MultiLoader 1.21+ · Part 10

Custom Tools (MultiLoader 1.21+)

INTERMEDIATE MULTILOADER 1.21-1.21.1 20 min read · Jul 13, 2026
MultiLoader 1.21+ · 28 parts
1 Getting Started with MultiLoader 1.21+ 2 Setting Up RegistrationUtils 3 Creating Items (MultiLoader 1.21+) 4 Creating Blocks (MultiLoader 1.21+) 5 Data Generation: Block & Item Models (MultiLoader 1.21+) 6 Data Generation: Block Loot Tables (MultiLoader 1.21+) 7 Data Generation: Crafting Recipes (MultiLoader 1.21+) 8 Data Generation: Block & Item Tags (MultiLoader 1.21+) 9 Custom Food Items (MultiLoader 1.21+) 10 Custom Tools (MultiLoader 1.21+) 11 Custom Armour (MultiLoader 1.21+) 12 Block Entities (MultiLoader 1.21+) 13 Config Files (MultiLoader 1.21+) 14 Custom Sounds (MultiLoader 1.21+) 15 Events and Listeners (MultiLoader 1.21+) 16 Networking and Custom Packets (MultiLoader 1.21+) 17 Data Generation: Advancements (MultiLoader 1.21+) 18 Data Generation: Language Files (MultiLoader 1.21+) 19 Custom Entities (MultiLoader 1.21+) 20 Ore Generation (MultiLoader 1.21+) 21 Introduction to Mixins (MultiLoader 1.21+) 22 Custom Particles (MultiLoader 1.21+) 23 Menus & Screens (MultiLoader 1.21+) 24 Key Bindings (MultiLoader 1.21+) 25 Custom Potion Effects (MultiLoader 1.21+) 26 Custom Enchantments (MultiLoader 1.21+) 27 Custom Commands (MultiLoader 1.21+) 28 Custom Biomes (MultiLoader 1.21+)

Custom tools require two things: a Tier that defines durability, mining speed, and enchantability, and the actual item registrations for each tool type. In 1.21 the tier system was reworked so that instead of 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.

Tool Tier

Create an enum called ExampleToolTier in your common project that implements the Tier interface. I created a separate util package to store this in. 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):

java
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:

java
public class ExampleTags {
public static final TagKey<Block> INCORRECT_FOR_EXAMPLE_TOOL =
TagKey.create(Registries.BLOCK, ResourceLocation.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 plus the blocks that specifically need your new tier:

java
@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.

Registering Tool Items

In 1.21, the tool item constructors were simplified to 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:

java
public static final RegistryObject<Item, SwordItem> EXAMPLE_SWORD = ITEMS.register("example_sword",
() -> new SwordItem(ExampleToolTier.EXAMPLE, getItemProperties()));
public static final RegistryObject<Item, PickaxeItem> EXAMPLE_PICKAXE = ITEMS.register("example_pickaxe",
() -> new PickaxeItem(ExampleToolTier.EXAMPLE, getItemProperties()));
public static final RegistryObject<Item, AxeItem> EXAMPLE_AXE = ITEMS.register("example_axe",
() -> new AxeItem(ExampleToolTier.EXAMPLE, getItemProperties()));

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 translation keys to en_us.json:

java
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());
json
"item.examplemod.example_sword": "Example Sword",
"item.examplemod.example_pickaxe": "Example Pickaxe",
"item.examplemod.example_axe": "Example Axe",
"item.examplemod.example_shovel": "Example Shovel",
"item.examplemod.example_hoe": "Example Hoe"

Datagen

Tools and weapons need the minecraft:item/handheld parent model so they rotate correctly when held. the basicItem has the minecraft:item/generatedparent model, and so does not apply the transformations to how it is held like a tool or weapon. To do this, let's make a new function in our ExampleItemModelProvider:

java
public ItemModelBuilder handheldItem(Item item) {
ResourceLocation itemRL = Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item));
return this.getBuilder(itemRL.toString()).parent(new ModelFile.UncheckedModelFile("item/handheld")).texture("layer0", ResourceLocation.fromNamespaceAndPath(itemRL.getNamespace(), "item/" + itemRL.getPath()));
}

This creates a new item model file for our item, but sets the .parent() of theItemModelBuilder to use minecraft:item/handheld instead of minecraft:item/generated. We can now register our handheld models using the new method we just created:

java
@Override
protected void registerModels() {
basicItem(ItemRegistry.IRON_STICK.get());
basicItem(ItemRegistry.EXAMPLE_FOOD.get());
handheldItem(ItemRegistry.EXAMPLE_SWORD.get());
handheldItem(ItemRegistry.EXAMPLE_PICKAXE.get());
handheldItem(ItemRegistry.EXAMPLE_AXE.get());
handheldItem(ItemRegistry.EXAMPLE_SHOVEL.get());
handheldItem(ItemRegistry.EXAMPLE_HOE.get());
}

Create 16×16 PNG textures for each tool under src/main/resources/assets/examplemod/textures/item/ and run NeoForge Data. The generated model JSON will look like this for the sword, for example:

json
{
"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 1.21+)

Register an ArmorMaterial record with per-slot defence values and texture layers, create all four armour item types, set up the equipped layer textures, and generate inventory models through datagen.

Continue →