ArmorMaterial is a data-driven record registered in the game's built-in registry. Each material declares per-slot defence values, enchantability, an equip sound, a repair ingredient, and one or more texture layers used for the 3D equipped rendering. The inventory icons are separate item textures, just like any other flat item.
ItemRegistry.Armour Material
Create a new class called ArmourMaterialRegistry in your common registry package. Declare a RegistrationProvider<ArmorMaterial> and register your material:
The seven arguments to ArmorMaterial are:
- defence map: damage reduction points per slot (iron totals 15: 2+6+5+2).
- enchantmentValue: enchantability (iron is 9, gold is 25, diamond is 10).
- equipSound: the
Holder<SoundEvent>played on equip. - repairIngredient: item accepted by an anvil to repair the armour.
- layers: list of texture layers shown on the player model when equipped.
- toughness: extra damage reduction for heavy armour (diamond: 2, netherite: 4, iron: 0).
- knockbackResistance: fraction of knockback absorbed (netherite: 0.1, others: 0).
Call ArmourMaterialRegistry.init() from CommonClass.init() before the item registry so the material is registered before the armour items that reference it:
Registering Armour Items
ArmorItem takes a Holder<ArmorMaterial>, not the material object directly. Retrieve it with Holder.direct() inside the item supplier, which is safe because the supplier is only evaluated after the material registry has been populated. Set the max stack size to 1 by calling .stacksTo(1) on getItemProperties():
Holder.direct() creates an unkeyed holder, which works at runtime but means the material cannot be referenced by data packs or other mods by its registry key. For full interoperability, retrieve the keyed holder after registration using BuiltInRegistries.ARMOR_MATERIAL.getHolder(ResourceKey...) and store it in a static Holder<ArmorMaterial> field initialised in a post-registration hook.Armour Textures
The 3D equipped model uses two texture files named after the layer identifier you declared. For the ArmorMaterial.Layer created with Identifier.fromNamespaceAndPath(MOD_ID, "example"), Minecraft looks for:
assets/examplemod/textures/models/armor/example_layer_1.png: worn on the helmet, chestplate, and boots model.assets/examplemod/textures/models/armor/example_layer_2.png: worn on the leggings model.
Both files follow the vanilla armour UV layout. The easiest starting point is to copy a vanilla armour texture from the Minecraft assets and recolour or redraw from there.
Creative Tab and Language File
Add all four pieces to your creative tab and add display names to ExampleLanguageProvider.addTranslations():
Datagen
Armour items use the standard flat 2D inventory model, so each piece needs registerSimpleFlatItemModel in ExampleModelProvider:
Create a 16x16 PNG inventory icon for each piece under common/src/main/resources/assets/examplemod/textures/item/ and run NeoForge Data to generate the model files.
Testing In-Game
Launch the client and equip each piece from your creative tab. Confirm:
- The inventory icon for each slot shows your item texture.
- The equipped 3D model on the player uses your layer textures.
- The armour bar fills according to your defence values.
- Placing the pieces in an anvil with Iron Sticks repairs their durability.
If the equipped model appears as the default leather armour texture or shows missing textures, double-check the layer texture file names. The number suffix (_layer_1, _layer_2) must be present and the folder must be textures/models/armor/ not textures/armor/.
You can find the source for this tutorial here:
View Source on GitHubBlock Entities (MultiLoader 26.1+)
Create a ticking BlockEntity that persists custom data to NBT, widen package-private access with an access transformer and access widener, implement client sync via getUpdateTag and getUpdatePacket, and wire up the ticker through BaseEntityBlock.
Continue →