MultiLoader 26.1+ · Part 15

Custom Tools (MultiLoader 26.1+)

INTERMEDIATE MULTILOADER 26.1-26.1.2 18 min read · Jun 12, 2026
MultiLoader 26.1+ · 17 parts
1 Getting Started with MultiLoader 26.1+ 2 Setting Up RegistrationUtils (MultiLoader 26.1+) 3 Creating Items (MultiLoader 26.1+) 4 Creating Blocks (MultiLoader 26.1+) 5 Data Generation: Block & Item Models (MultiLoader 26.1+) 6 Data Generation: Block Loot Tables (MultiLoader 26.1+) 7 Data Generation: Crafting Recipes (MultiLoader 26.1+) 8 Data Generation: Block & Item Tags (MultiLoader 26.1+) 9 Data Generation: Language Files (MultiLoader 26.1+) 10 Data Generation: Advancements (MultiLoader 26.1+) 11 Data Generation: Sound Definitions (MultiLoader 26.1+) 12 Data Generation: Particle Descriptions (MultiLoader 26.1+) 13 Data Generation: Enchantments (MultiLoader 26.1+) 14 Custom Food Items (MultiLoader 26.1+) 15 Custom Tools (MultiLoader 26.1+) 16 Custom Armour (MultiLoader 26.1+) 17 Block Entities (MultiLoader 26.1+)

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.

Tool Tier

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:

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

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

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:

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

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());
java
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:

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

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

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 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 →