- Minecraft Modding: Fabric + Kotlin – Introduction and Setup
- Minecraft Modding: Fabric + Kotlin – Items
- Minecraft Modding: Fabric + Kotlin – Strings and Refactoring
Layout and Structure
Now that we have the mod set up, it’s time to actually start adding items! You’ll see that in our src
folder, we have two sub-folders: client
and main
. These folders both have three sub-folders each: java
, kotlin
, and resources
.
The java
folder contains mixins, which you can read more about here (currently, mixins do not support Kotlin). We don’t need that folder right now.
The kotlin
folder contains our mod’s Kotlin code. This is the folder most of our mod’s code will go in.
The last folder is resources
. The content of the resources folder will change depending on if it’s in the client
or main
folder. In both folders, it contains a JSON file for the mixins (either modid.client.mixins.json
or modid.mixins.json
). The client
folder has only that one file inside resources
. However, the main
folder will also have fabric.mod.json
and assets/modid/icon.png
. The file fabric.mod.json
describes the metadata of the mod, and reading through it, you will see that it references files in other folders, including mod entrypoints. I recommend reading through it, as we will be editing it later. icon.png
, on the other hand, is the icon of our mod. The default is a drawing of “Mod ID”. You can change the icon if you want to.
You can collapse client
, as we won’t be doing anything with it right now. Now, let’s take a look through main/kotlin
. You can see that there are two files: ExampleMod.kt
and ExampleModDataGenerator.kt
. The first is our mod’s entrypoint, and the second is where our datagen code will live.
Go ahead and rename both files to whatever you want. I’ll be using Stuff.kt
and StuffDataGenerator.kt
, since my mod is called Stuff (in practice, you’ll obviously want to choose a better mod name, but this is just a tutorial, so I went with that). Now, you’ll need to edit fabric.mod.json
. Change entrypoints.main[0].value
to the mod entrypoint file (again, Stuff
in my case) and entrypoints.fabric-datagen[0].value
to the datagen entrypoint file (for me, StuffDataGenerator
).
Now run the Minecraft client (remember, using the runClient
Gradle task) to make sure you did everything correct. If you did, it should launch successfully. If it did, great! You can stop the client, and we can get to actually making our mod.
Adding the Item
Now, create a new package named items
in the same directory as the entrypoints. Right click on it and go to New > Minecraft Class, and click Item. Give it the name IceCube
. A new Java class should be generated at items.IceCube
:
public class IceCube extends Item {
public IceCube(Settings settings) {
super(settings);
}
}
We’re using Kotlin, so right-click on the file in IntelliJ and select Convert Java File to Kotlin File.
Now, go back to the mod entrypoint file. We need to register this item so that Minecraft can see it. Add the following property to the class:
val ICE_CUBE = Registry.register(
Registries.ITEM,
Identifier("modid", "ice_cube"),
IceCube(FabricItemSettings()),
)
Make sure you have the right imports, namely net.minecraft.util.Identifier
and net.minecraft.registry.Registry
, since the Java standard library exports classes with the same name.
The code is registering the IceCube
item with the identifier modid:ice_cube
. As always, remember to replace modid
with your mod ID.
Now, run the Minecraft client. If you haven’t already, create a Creative mode world with cheats enabled. Use the command /give @s modid:ice_cube
to give yourself the item. If you did everything correctly, you should have the item. However, it’s show the default no-texture texture, since we never gave it a texture. Let’s fix that.
Textures
Download ice_cube.png
from here. In assets/modid
, create the folders textures/item
, and copy ice_cube.png
into item
. Now, in assets/modid
, create the folders models/item
, and create a file called ice_cube.json
. This file will contain the model for the item. Add this:
{
"parent": "item/generated",
"textures": {
"layer0": "modid:item/ice_cube"
}
}
Notice that it references the ice cube texture you copied earlier, through modid:item/ice_cube
. Now, run the client. The modid:ice_cube
item should have the new texture!
If we want our item to have a certain stack size, like 16, we can use the methods on FabricItemSettings
. Go to the mod entrypoint file, and where you registered the ice cube as an item, you’ll see that you passed an instance of that class with FabricItemSettings()
. Replace FabricItemSettings()
with FabricItemSettings().maxCount(16)
. You can use methods to add properties like this. In addition to the stack size, let’s try making it fireproof with the fireproof()
method.
Run the client again, and use the command /give @s modid:ice_cube 64
. You should have 4 stacks of ice cubes, 16 ice cubes in each stack. Now, place down some lava. Throwing most vanilla items in should cause them to burn and be destroyed. But if you throw an ice cube in, nothing will happen, and you can pick it back up again!
Creating an ItemGroup
As we add more items to our mod, especially those that don’t fit into any of the creative tabs in the inventory, we’ll want to create a creative tab for our mod. As the Fabric tutorial says: “Before you create an item group, determine whether it would have enough content to warrant its own group. Your item group will be placed on a separate page of tabs, impacting its discoverability, and users may be confused if the item is not where similar items are in the creative inventory.” Since this is a tutorial mod, we’ll go ahead and add it regardless, but you should consider this before adding it in your own mods.
Add the follow property to your mod entrypoint class:
private val MODID_GROUP = RegistryKey.of(RegistryKeys.ITEM_GROUP, Identifier("modid", "modid_group"))
Then, add this to the end of the onInitialize
method:
Registry.register(
Registries.ITEM_GROUP,
MODID_GROUP,
FabricItemGroup.builder().icon { ItemStack(ICE_CUBE) }
.displayName(
Text.translatable("itemGroup.modid.modid_group")
)
.build(),
)
As always, remember to substitute modid
for your mod ID. This code is registering an item group, and setting the ice cube we created earlier as its tab icon. However, this item group doesn’t have any items yet. To do that, we need to add items in the onInitialize
method. At the end of the method, add this:
ItemGroupEvents.modifyEntriesEvent(MODID_GROUP).register(ModifyEntries { content ->
content.add(ICE_CUBE)
})
This code is taking the group we just created and adding the ice cube item to it. Now, run the client. In your creative inventory, you should be able to see a tab with the ice cube icon (you might need to click arrows to show overflowed tabs in other pages).
That’s it for this post! In the next post, we’ll look at internationalization/strings and do some basic refactoring.
Leave a Reply