Table of Contents
Adding an Item
Introduction
Adding a basic item is one of the first steps in modding. You're going to need to create an Item
object, register it, and give it a texture. To add additional behavior to the item you will need a custom Item class. In this tutorial and all future ones, the “tutorial
” namespace is used as a placeholder. If you have a separate mod id, feel free to use it instead.
Create an Item instance
If you're in version 1.21.2 or above, please directly read Creating Items in 1.21.2+.
First, create an instance of Item
. The constructor takes in an Item.Settings
(or a FabricItemSettings
unless versions since 1.20.5) instance, which is used to set item properties such as the durability, and stack count. For simplicity, we just do it in ExampleMod
class, and store them in static fields.
public class ExampleMod implements ModInitializer { // an instance of our new item // for versions below 1.20.4 public static final Item CUSTOM_ITEM = new Item(new FabricItemSettings()); // for versions since 1.20.5, below 1.21.2 public static final Item CUSTOM_ITEM = new Item(new Item.Settings()); [...] }
Register the item
We've create a basic item, but it still does not exist in Minecraft, because it has not been registered. In Minecraft, almost everything has an registry, and items are no exceptions.
You'll use the vanilla registry system for registering new content. The basic syntax is Registry.register(Registry Type, Identifier, Content)
. Registry types are stored as static fields in the Registries
or Registry
class, and the identifier is what labels your content. Content is an instance of whatever you're adding. Specifically for item, the syntax is Registry#register(Registries.ITEM, Identifier, Item)
. This can be called anywhere as long as it occurs during initialization. The method itself also returns the registered content itself.
For versions since 1.21, an Identifier
is created through Identifier.of("namespace", "path")
. For versions below 1.21, it is created through new Identifier("namespace", "path")
or new Identifier("namespace:path")
. It will fail if the namespace or path contains illegal characters.
Your new item has now been added to Minecraft. Run the run config
public class ExampleMod implements ModInitializer { // an instance of our new item public static final Item CUSTOM_ITEM = new Item(new Item.Settings()); @Override public void onInitialize() { // For versions below 1.21, please replace ''Identifier.of'' with ''new Identifier'' } }
Minecraft Client
or runClient
Gradle task to see it in action, execute the command /give @s tutorial:custom_item
in game.
For more simplicity, you can simplify your code by directly registering them when assigning the fields, as Register.register
will also return the registered object:
public class ExampleMod implements ModInitializer { // an instance of our new item public static final Item CUSTOM_ITEM = // For versions below 1.21, use ''new Identifier("tutorial", "custom_item")''. new Item(new Item.Settings())); @Override public void onInitialize() { } }
Best practice of registering items
In the code above, you simply created one item. However, it is not convenient if you have many items in your mod, as you need to register and create an Identifier
instance each time. Therefore, we can create a specific class to store item objects, such as ModItems
or TutorialItems
, and write a simple register
method to conveniently register items. This is quite common in actual mod development. You may also check vanilla Items
class to see how Minecraft completes it in a similar way.
In this example, create a TutorialItems
class and refer to the class in the ModInitializer
.
public final class TutorialItems { private TutorialItems() {} // an instance of our new item public static final Item CUSTOM_ITEM = register("custom_item", new Item(new Item.Settings())); // For versions below 1.21, please replace ''Identifier.of'' with ''new Identifier'' } public static void initialize() { } }
Remember to refer to some methods or fields in the mods initializer so as to statically load the class TutorialItems
.
public class ExampleMod implements ModInitializer { @Override public void onInitialize() { TutorialItems.initialize(); } }
Note: Some experienced users may decide to use reflection to automatically register all static fields of a class. This is also a preferable way, but should be used with caution.
Creating Items in 1.21.2+
Since 1.21.2, the item registration is tutally rewrited. You have to store a RegistryKey
in your Item.Settings
, so the models and translation keys will be correctly stored in item components. Otherwise, you may see the following exceptions and Minecraft does not run:
java.lang.NullPointerException: Item id not set
To make it run correctly, you should write like below:
public final class TutorialItems { private TutorialItems() { } public static final Item CUSTOM_ITEM = register("custom_item", Item::new, new Item.Settings()); public static Item register(String path, Function<Item.Settings, Item> factory, Item.Settings settings) { final RegistryKey<Item> registryKey = RegistryKey.of(RegistryKeys.ITEM, Identifier.of("tutorial", path)); return Items.register(registryKey, factory, settings); } public static void initialize() { } }
In the method Items.register
, the registry key will be written in the settings
first, and then use that settings
to create the item.
Adding model and textures
If you registered your item properly in the first step, you can successfully get your item by typing command /give @s tutorial:custom_item
. You will find it has missing texture, and Minecraft will complain about a missing texture file in a fashion similar to this:
[Server-Worker-1/WARN]: Unable to load model: 'tutorial:custom_item#inventory' referenced from: tutorial:custom_item#inventory: java.io.FileNotFoundException: tutorial:models/item/custom_item.json
That's because we haven't provided the item with textures and models. Therefore, you need to define the item model json and provide a texture image. You're going to need to add these to your resource directory. The direct path of each is:
- Item model:
…/resources/assets/tutorial/models/item/custom_item.json
- Item texture:
…/resources/assets/tutorial/textures/item/custom_item.png
Our example texture can be found here.
A basic item model template is:
{ "parent": "item/generated", "textures": { "layer0": "tutorial:item/custom_item" } }
The parent
of your item model changes how it's rendered in the hand and comes in useful for things like block items in the inventory. item/generated
is used for many simple items. item/handheld
is used for tools that are held from the bottom left of the texture. In the json, textures/layer0
is the location of your image file.
Creating an Item class
You have created a simple item, and learned how to change some basic properties. But maybe you want it to have more behaviors. Therefore, you will need to create an item class. The default constructor requires an Item.Settings
object.
public class CustomItem extends Item { public CustomItem(Settings settings) { super(settings); } }
A practical use-case for a custom item class would be making the item play a sound when you use it:
public class CustomItem extends Item { public CustomItem(Settings settings) { super(settings); } // write this if the version is below 1.21.2: @Override public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) { user.playSound(SoundEvents.BLOCK_WOOL_BREAK, 1.0F, 1.0F); return TypedActionResult.success(user.getStackInHand(hand)); } // write this if the version is 1.21.2 or higher: @Override public ActionResult use(World world, PlayerEntity user, Hand hand) { user.playSound(SoundEvents.BLOCK_WOOL_BREAK, 1.0F, 1.0F); return ActionResult.SUCCESS; } }
Replace the old Item object with an instance of your new item class:
If you did everything correctly, using the item should now play a sound. You can also add some tooltips for the item based on your item class.
public final class TutorialItems { [...] // an instance of our new item // For versions below 1.21.2: public static final CustomItem CUSTOM_ITEM = register("custom_item", new CustomItem(new Item.Settings())); // For versions since 1.21.2: public static final CustomItem CUSTOM_ITEM = register("custom_item", CustomItem::new, new Item.Settings()); [...] }
Item components
Sometimes you may need to add some default components for the item, such as max stack size or fire durability. This can be done by calling component
method in Item.Settings
. Detailed information about item components can be found in the tutorial in Fabric docs.
In this example, the item will be unbreakable by default, while hiding tooltips about it.
// For versions below 1.21.2: public static final CustomItem CUSTOM_ITEM = register("custom_item", new CustomItem(new Item.Settings() .component(DataComponentTypes.UNBREAKABLE, new UnbreakableComponent(true)))); // For versions since 1.21.2: public static final Item CUSTOM_ITEM = register("custom_item", CustomItem::new, new Item.Settings() .component(DataComponentTypes.UNBREAKABLE, new UnbreakableComponent(true)));
Specifically, max stack size can be simply set by calling maxCount
method (which is valid also before 1.20.5). Note that if your item is damageable you cannot specify a maximum stack size or the game will throw a RuntimeException
.
public class ExampleMod implements ModInitializer { // An instance of our new item, where the maximum stack size is 16 // For versions below 1.21.2: public static final CustomItem CUSTOM_ITEM = register("custom_item", new CustomItem(new Item.Settings().maxCount(16))); // For versions since 1.21.2: public static final Item CUSTOM_ITEM = register("custom_item", CustomItem::new, new Item.Settings().maxCount(16)); [...] }
Make your item become fuel, or compostable
If you want to make it a fuel so that it can be used in a furnace, you can register in FuelRegistry
when initializing the mod, for example:
public class ExampleMod implements ModInitializer { [...] // For versions below 1.21.2 @Override public void onInitialize() { [...] FuelRegistry.INSTANCE.add(TutorialItems.CUSTOM_ITEM, 300); } }
However, in practice, when you have many items to register, as registering quantities of items may be effort-consuming and messy, you can consider placing the codes in a separate method, instead of writing like above.
In versions below 1.21.2, you need to use Fabric API's FuelRegistry.INSTANCE
.
public final class TutorialItems { [...] // For versions below 1.21.2 public static void registerFuels() { FuelRegistry.INSTANCE.add(CUSTOM_ITEM, 300); } }
In versions since 1.21.2, use Fabric API's FuelRegistryEvents
:
public final class TutorialItems { [...] // For versions since 1.21.2 public static void registerFuels() { FuelRegistryEvents.BUILD.register((builder, context) -> { // You can add multiple items at once in this lambda. builder.add(CUSTOM_ITEM, 300); }); } }
And then refer to this method in your ModInitializer
:
public class ExampleMod implements ModInitializer { [...] @Override public void onInitialize() { [...] TutorialItems.registerFuels(); } }
Similarly, you can use a CompostingChanceRegistry
to make it compostable in a composter.