Custom tools require two things: a Tier that defines durability, mining speed, and enchantability, and the actual item registrations for each tool type. Rather than a numeric harvest level, a tier declares a tag of blocks it cannot harvest correctly, which keeps cross-mod compatibility flexible.
NOTE
Complete the Data Generation: Block and Item Tags tutorial before continuing. We add a new block tag in this tutorial that the tier references.
Create an enum called ExampleToolTier in your common project that implements the Tier interface. A separate util package is a good home for this. An enum is the cleanest way to define one or more tiers while keeping the repair ingredient supplier lazy so the item registry has finished populating before it is accessed:
public enum ExampleToolTier implements Tier {
EXAMPLE(
ExampleTags.INCORRECT_FOR_EXAMPLE_TOOL,
500,
6.5f,
2.0f,
14,
() -> Ingredient.of(ItemRegistry.IRON_STICK.get())
);
private final TagKey<Block> incorrectBlocksForDrops;
private final int uses;
private final float speed;
private final float attackDamageBonus;
private final int enchantmentValue;
private final Supplier<Ingredient> repairIngredient;
ExampleToolTier(TagKey<Block> incorrectBlocksForDrops, int uses, float speed,
float attackDamageBonus, int enchantmentValue,
Supplier<Ingredient> repairIngredient) {
this.incorrectBlocksForDrops = incorrectBlocksForDrops;
this.uses = uses;
this.speed = speed;
this.attackDamageBonus = attackDamageBonus;
this.enchantmentValue = enchantmentValue;
this.repairIngredient = Suppliers.memoize(repairIngredient::get);
}
@Override public int getUses() { return uses; }
@Override public float getSpeed() { return speed; }
@Override public float getAttackDamageBonus() { return attackDamageBonus; }
@Override public TagKey<Block> getIncorrectBlocksForDrops() { return incorrectBlocksForDrops; }
@Override public int getEnchantmentValue() { return enchantmentValue; }
@Override public Ingredient getRepairIngredient() { return repairIngredient.get(); }
}
The six constructor parameters are:
- incorrectBlocksForDrops: the tag of blocks this tier cannot harvest (see next section).
- uses: total durability before the tool breaks.
- speed: mining speed multiplier (iron is 6.0, diamond is 8.0).
- attackDamageBonus: base bonus damage added on top of each tool type's own offset.
- enchantmentValue: enchantability (iron is 14, gold is 22, diamond is 10).
- repairIngredient: item or tag accepted by an anvil to repair the tool.
Suppliers.memoize wraps the supplier so the ingredient is only built once and cached thereafter. Add the com.google.common.base.Suppliers import from Guava, which is already on the classpath via Minecraft.
Incorrect Blocks Tag
Rather than reusing a vanilla incorrect-blocks tag such as BlockTags.INCORRECT_FOR_IRON_TOOL, create a dedicated tag for your tier so other mods and data packs can specify exactly which blocks require it. Create a tag constants class in your common project:
public class ExampleTags {
public static final TagKey<Block> INCORRECT_FOR_EXAMPLE_TOOL =
TagKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath(Constants.MOD_ID, "incorrect_for_example_tool"));
}
Then open ExampleBlockTagsProvider and populate the tag. We mark it as needing at least an example-tier tool to drop by listing all blocks that are too hard for lower tiers. A common convention is to extend the next tier down's incorrect set and add any blocks that specifically need your new tier:
@Override
protected void addTags(HolderLookup.Provider provider) {
tag(BlockTags.MINEABLE_WITH_PICKAXE)
.add(BlockRegistry.NEW_DIRT.get());
// Blocks that cannot be harvested below iron tier
tag(BlockTags.NEEDS_IRON_TOOL)
.add(BlockRegistry.NEW_DIRT.get());
// Custom tier tag: extends the iron incorrect set so example-tier
// tools can harvest iron-tier blocks, plus any blocks specific to
// your tier that stone-tier tools cannot harvest
tag(ExampleTags.INCORRECT_FOR_EXAMPLE_TOOL)
.addTag(BlockTags.INCORRECT_FOR_IRON_TOOL);
}
TIP
If your tier sits between two vanilla tiers (e.g. between iron and diamond), extend the lower one's incorrect tag and add only the blocks that specifically require your tier or higher. This ensures proper ordering in the tool tier hierarchy.
The tool item constructors accept only the tier and item properties. The per-type attack damage offsets are baked into each class (sword: +3, pickaxe: +1, axe: +5, shovel: +1.5). Add the following fields to ItemRegistry:
public static final RegistryObject<Item, SwordItem> EXAMPLE_SWORD = ITEMS.register("example_sword",
() -> new SwordItem(ExampleToolTier.EXAMPLE, getItemProperties("example_sword")));
public static final RegistryObject<Item, PickaxeItem> EXAMPLE_PICKAXE = ITEMS.register("example_pickaxe",
() -> new PickaxeItem(ExampleToolTier.EXAMPLE, getItemProperties("example_pickaxe")));
public static final RegistryObject<Item, AxeItem> EXAMPLE_AXE = ITEMS.register("example_axe",
() -> new AxeItem(ExampleToolTier.EXAMPLE, getItemProperties("example_axe")));
You can add ShovelItem and HoeItem the same way if you want a complete tool set.
Creative Tab and Language File
Add the tools to your creative tab's displayItems lambda and add display names to ExampleLanguageProvider.addTranslations():
output.accept(ItemRegistry.EXAMPLE_SWORD.get());
output.accept(ItemRegistry.EXAMPLE_PICKAXE.get());
output.accept(ItemRegistry.EXAMPLE_AXE.get());
output.accept(ItemRegistry.EXAMPLE_SHOVEL.get());
output.accept(ItemRegistry.EXAMPLE_HOE.get());
add(ItemRegistry.EXAMPLE_SWORD.get(), "Example Sword");
add(ItemRegistry.EXAMPLE_PICKAXE.get(), "Example Pickaxe");
add(ItemRegistry.EXAMPLE_AXE.get(), "Example Axe");
add(ItemRegistry.EXAMPLE_SHOVEL.get(), "Example Shovel");
add(ItemRegistry.EXAMPLE_HOE.get(), "Example Hoe");
Datagen
Tools and weapons need the minecraft:item/handheld parent model so they rotate correctly when held. registerSimpleFlatItemModel uses minecraft:item/generated and does not apply the held-item transformations, so a small helper method is needed. Add it to ExampleModelProvider:
private void registerHandheldItem(BlockModelGenerators blockModels, Item item) {
Identifier model = ModelTemplates.FLAT_HANDHELD.create(
ModelLocationUtils.getModelLocation(item),
TextureMapping.layer0(item),
blockModels.modelOutput);
blockModels.registerSimpleItemModel(item, model);
}
ModelTemplates.FLAT_HANDHELD writes a JSON model that sets parent to minecraft:item/handheld and wires layer0 to the item's texture path. Then registerSimpleItemModel writes the corresponding items/ definition that points to that model. Update registerModels to use the helper for all tool types:
@Override
protected void registerModels(BlockModelGenerators blockModels, ItemModelGenerators itemModels) {
blockModels.createTrivialCube(BlockRegistry.NEW_DIRT.get());
blockModels.registerSimpleItemModel(
BlockRegistry.NEW_DIRT.get(),
ModelLocationUtils.getModelLocation(BlockRegistry.NEW_DIRT.get()));
blockModels.registerSimpleFlatItemModel(ItemRegistry.IRON_STICK.get());
blockModels.registerSimpleFlatItemModel(ItemRegistry.TOMATO.get());
registerHandheldItem(blockModels, ItemRegistry.EXAMPLE_SWORD.get());
registerHandheldItem(blockModels, ItemRegistry.EXAMPLE_PICKAXE.get());
registerHandheldItem(blockModels, ItemRegistry.EXAMPLE_AXE.get());
registerHandheldItem(blockModels, ItemRegistry.EXAMPLE_SHOVEL.get());
registerHandheldItem(blockModels, ItemRegistry.EXAMPLE_HOE.get());
}
Create 16x16 PNG textures for each tool under common/src/main/resources/assets/examplemod/textures/item/ and run NeoForge Data. The generated model JSON for the sword will look like this:
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "examplemod:item/example_sword"
}
}
Testing In-Game
Launch the client and find your tools in the creative tab. Switch to survival, place a New Dirt block, and try breaking it with different tools:
- Your fist and a wooden pickaxe should mine slowly and drop nothing.
- An iron pickaxe should mine it and drop it (from the loot table and tool tag).
- Your custom example pickaxe should also mine and drop it correctly.
Check the tool's durability by mining blocks in survival until it breaks, and verify the repair ingredient (Iron Stick) works in an anvil.
You can find the source for this tutorial here:
View Source on GitHub NEXT IN SERIES
Custom Armour (MultiLoader 26.1+)
Register an ArmorMaterial with per-slot defence values, create helmet, chestplate, leggings, and boots items, supply layer textures for the 3D equipped model, and generate flat inventory item models.
Continue →