Skip to main content
Version: 1.21.x

Armor

Armors are items whose primary use is to protect an entity from damage using a variety of resistances and effects. Many mods add new armor sets (for example copper armor).

Custom Armor Sets

An armor set for a humanoid entity typically consists of four items: a helmet for the head, a chestplate for the chest, leggings for the legs, and boots for the feet. There is also armor for wolves, horses, and llamas that are applied to a 'body' armor slot specifically for animals. All of these items are generally implemented through ArmorItem and AnimalArmorItem, respectively.

Armors are almost completely implemented through seven data components:

  • DataComponents#MAX_DAMAGE and #DAMAGE for durability
  • #MAX_STACK_SIZE to set the stack size to 1
  • #REPAIRABLE for repairing an armor piece in an anvil
  • #ENCHANTABLE for the maximum enchanting value
  • #ATTRIBUTE_MODIFIERS for armor, armor toughness, and knockback resistance
  • #EQUIPPABLE for how the entity can equip the item.

ArmorItem and AnimalArmorItem use ArmorMaterial combined with ArmorType or AnimalArmorItem.BodyType respectively to set up the components. Reference values can be found within ArmorMaterials. This example uses a copper armor material, which you can adjust the values as needed.

public static final ArmorMaterial COPPER_ARMOR_MATERIAL = new ArmorMaterial(
// The durability multiplier of the armor material.
// ArmorType have different unit durabilities that the multiplier is applied to:
// - HELMET: 11
// - CHESTPLATE: 16
// - LEGGINGS: 15
// - BOOTS: 13
// - BODY: 16
15,
// Determines the defense value (or the number of half-armors on the bar).
// Based on ArmorType.
Util.make(new EnumMap<>(ArmorType.class), map -> {
map.put(ArmorItem.Type.BOOTS, 2);
map.put(ArmorItem.Type.LEGGINGS, 4);
map.put(ArmorItem.Type.CHESTPLATE, 6);
map.put(ArmorItem.Type.HELMET, 2);
map.put(ArmorItem.Type.BODY, 4);
}),
// Determines the enchantability of the armor. This represents how good the enchantments on this armor will be.
// Gold uses 25; we put copper slightly below that.
20,
// Determines the sound played when equipping this armor.
// This is wrapped with a Holder.
SoundEvents.ARMOR_EQUIP_GENERIC,
// Returns the toughness value of the armor. The toughness value is an additional value included in
// damage calculation, for more information, refer to the Minecraft Wiki's article on armor mechanics:
// https://minecraft.wiki/w/Armor#Armor_toughness
// Only diamond and netherite have values greater than 0 here, so we just return 0.
0,
// Returns the knockback resistance value of the armor. While wearing this armor, the player is
// immune to knockback to some degree. If the player has a total knockback resistance value of 1 or greater
// from all armor pieces combined, they will not take any knockback at all.
// Only netherite has values greater than 0 here, so we just return 0.
0,
// The tag that determines what items can repair this armor.
Tags.Items.INGOTS_COPPER,
// The relative location of the EquipmentModel JSON discussed below
// Points to assets/examplemod/models/equipment/copper.json
ResourceLocation.fromNamespaceAndPath("examplemod", "copper")
);

Now that we have our ArmorMaterial, we can use it for registering armor. ArmorItem takes in the ArmorMaterial and the ArmorType representing where the item can be equipped. AnimalArmorItem, on the other hand takes in the ArmorMaterial and the AnimalArmorItem.BodyType. It also can optionally take in the an equip sound and whether to apply the durability and repairable components.

// ITEMS is a DeferredRegister.Items
public static final DeferredItem<ArmorItem> COPPER_HELMET = ITEMS.registerItem(
"copper_helmet",
props -> new ArmorItem(
// The material to use.
COPPER_ARMOR_MATERIAL,
// The type of armor to create.
ArmorType.HELMET,
// The item properties.
props
)
);

public static final DeferredItem<ArmorItem> COPPER_CHESTPLATE =
ITEMS.registerItem("copper_chestplate", props -> new ArmorItem(...));
public static final DeferredItem<ArmorItem> COPPER_LEGGINGS =
ITEMS.registerItem("copper_chestplate", props -> new ArmorItem(...));
public static final DeferredItem<ArmorItem> COPPER_BOOTS =
ITEMS.registerItem("copper_chestplate", props -> new ArmorItem(...));

public static final DeferredItem<AnimalArmorItem> COPPER_WOLF_ARMOR = ITEMS.registerItem(
"copper_wolf_armor",
props -> new AnimalArmorItem(
// The material to use.
COPPER_ARMOR_MATERIAL,
// The body type the armor can be worn by.
AnimalArmorItem.BodyType.CANINE,
// The item properties.
props
)
);

public static final DeferredItem<AnimalArmorItem> COPPER_HORSE_ARMOR =
ITEMS.registerItem("copper_horse_armor", props -> new AnimalArmorItem(...));

Now, creating armor or an armor-like item does not need to extend ArmorItem or AnimalArmorItem. It simply can be implemented using a combination of the following parts:

  • Adding a Equippable with your own requirements by setting DataComponents#EQUIPPABLE via Item.Properties#component.
  • Adding attributes to the item (e.g. armor, toughness, knockback) via Item.Properties#attributes.
  • Adding item durability via Item.Properties#durability.
  • Allowing the item to be repaired via Item.Properties#repariable.
  • Allowing the item to be enchanted via Item.Properties#enchantable.
  • Adding your armor to some of the minecraft:enchantable/* ItemTags so that your item can have certain enchantments applied to it.
note

The only logic that has no alternative to using an ArmorItem base is when mobs replace their current held item via Mob#canReplaceCurrentItem. Mobs will always check for an instance of SwordItem, followed by BowItem, CrossbowItem, ArmorItem, and DiggerItem, with all other items not considered for specialized logic.

Equippable

Equippable is a data component that contains how an entity can equip this item and what handles the rendering in game. This allows any item, regardless of whether it is considered 'armor', to be equipped if this component is available (for example carpets on llamas). Each item with this component can only be equipped to a single EquipmentSlot.

An Equippable can be created either by directly calling the record constructor or via Equippable#builder, which sets the defaults for each field, folowed by build once finished:

// Assume there is some DeferredRegister.Items ITEMS
public static final DeferredItem<Item> EQUIPPABLE = ITEMS.registerSimpleItem(
"equippable",
new Item.Properties().copmonent(
DataComponents.EQUIPPABLE,
// Sets the slot that this item can be equipped to.
Equippable.builder(EquipmentSlot.HELMET)
// Determines the sound played when equipping this armor.
// This is wrapped with a Holder.
// Defaults to SoundEvents#ARMOR_EQUIP_GENERIC.
.setEquipSound(SoundEvents.ARMOR_EQUIP_GENERIC)
// The relative location of the EquipmentModel JSON discussed below.
// Points to assets/examplemod/models/equipment/equippable.json
// When not set, does not render the equipment.
.setModel(ResourceLocation.fromNamespaceAndPath("examplemod", "equippable"))
// The relative location of the texture to overlay on the player screen when wearing (e.g., pumpkin blur).
// Points to assets/examplemod/textures/equippable.png
// When not set, does not render an overlay.
.setCameraOverlay(ResourceLocation.withDefaultNamespace("examplemod", "equippable"))
// A HolderSet of entity types (direct or tag) that can equip this item.
// When not set, any entity can equip this item.
.setAllowedEntities(EntityType.ZOMBIE)
// Whether the item can be equipped when dispensed from a dispenser.
// Defaults to true.
.setDispensable(true),
// Whether the item can be swapped off the player during a quick equip.
// Defaults to true.
.setSwappable(false),
// Whether the item should be damaged when attacked (for equipment typically).
// Must also be a damageable item.
// Defaults to true.
.setDamageOnHurt(false)
.build()
)
);

Equipment Models

Now we have some armor in game, but if we try to wear it, nothing will render since we never specified how to render the equipment. To do so, we need to create an EquipmentModel JSON at the location specified by Equippable#model, relative to the models/equipment folder of the resource pack (assets folder). The EquipmentModel specifies the associated textures to use for each layer to render.

note

EquipmentModel is a bit of a misnomer as it does not specify the model to use when rendering, only the textures. The model used is the one passed in during equipment rendering.

An EquipmentModel is functionally a map of EquipmentModel.LayerTypes to a list of EquipmentModel.Layers to apply.

The LayerType can be thought of as a group of textures to render for some instance. For example, LayerType#HUMANOID is used by the HumanoidArmorLayer to render the head, chest, and feet on humanoid entities; LayerType#WOLF_BODY is used by WolfArmorLayer to render the body armor. These can be combined into one equipment model JSON if they are for the same type of equippable, like copper armor.

The LayerType maps to some list of Layers to apply and render the model in the order provided. A Layer effectively represents a single texture to render. The first parameter represents the location of the texture, relative to textures/entity/equipment.

The second parameter is an optional that indicates whether the texture can be tinted as a EquipmentModel.Dyeable. The Dyeable object holds an integer that, when present, indicates the default RGB color to tint the texture with. If this optional is not present, then pure white is used.

warning

For a tint other than the undyed color to be applied to the item, the item must be in the ItemTags#DYEABLE and have the DataComponents#DYED_COLOR component set to some RGB value.

The third parameter is a boolean that indicates whether the texture provided during rendering should be used instead of the one defined within the Layer. An example of this is a custom cape or custom elytra texture for the player.

Let's create a equipment model for the copper armor material. We'll also assume that for each layer there are two textures: one for the actual armor and one that is overlayed and tinted. For the animal armor, we'll say that there is some dynamic texture to be used that can be passed in.

// In assets/examplemod/models/equipment/copper.json
{
// The layer map
"layers": {
// The serialized name of the EquipmentModel.LayerType to apply.
// For humanoid head, chest, and feet
"humanoid": [
// A list of layers to render in the order provided
{
// The relative texture of the armor
// Points to assets/examplemod/textures/entity/equipment/copper/outer.png
"texture": "examplemod:copper/outer"
},
{
// The overlay texture
// Points to assets/examplemod/textures/entity/equipment/copper/outer_overlay.png
"texture": "examplemod:copper/outer_overlay",
// When specified, allows the texture to be tinted the color in DataComponents#DYED_COLOR
// Otherwise, cannot be tinted
"dyeable": {
// An RGB value (always opaque color)
// 0x7683DE as decimal
// When not specified, set to 0 (meaning transparent or invisible)
"color_when_undyed": 7767006
}
}
],
// For humanoid legs
"humanoid_leggings": [
{
// Points to assets/examplemod/textures/entity/equipment/copper/inner.png
"texture": "examplemod:copper/inner"
},
{
// Points to assets/examplemod/textures/entity/equipment/copper/inner_overlay.png
"texture": "examplemod:copper/inner_overlay",
"dyeable": {
"color_when_undyed": 7767006
}
}
],
// For wolf armor
"wolf_body": [
{
// Points to assets/examplemod/textures/entity/equipment/copper/wolf.png
"texture": "examplemod:copper/wolf",
// When true, uses the texture passed into the layer renderer instead
"use_player_texture": true
}
],
// For horse armor
"horse_body": [
{
// Points to assets/examplemod/textures/entity/equipment/copper/horse.png
"texture": "examplemod:copper/horse",
"use_player_texture": true
}
]
}
}

Equipment Rendering

The equipment models are rendered via the EquipmentLayerRenderer in the render function of an EntityRenderer or one of its RenderLayers. EquipmentLayerRenderer is obtained as part of the render context via EntityRendererProvider.Context#getEquipmentRenderer. If the EquipmentModels are required, they are also available via EntityRendererProvider.Context#getEquipmentModels.

By default, the following layers render the associated EquipmentModel.LayerType:

LayerTypeRenderLayerUsed by
HUMANOIDHumanoidArmorLayerPlayer, humanoid mobs (e.g., zombies, skeletons), armor stands
HUMANOID_LEGGINGSHumanoidArmorLayerPlayer, humanoid mobs (e.g., zombies, skeletons), armor stands
WINGSWingsLayerPlayer, humanoid mobs (e.g., zombies, skeletons), armor stands
WOLF_BODYWolfArmorLayerWolf
HORSE_BODYHorseArmorLayerHorse
LLAMA_BODYLlamaDecorLayerLlama, trader llama

EquipmentLayerRenderer has only one method to render the equipment layers, aptly named renderLayers:

// In some render method where EquipmentLayerRenderer equipmentLayerRenderer is a field
this.equipmentLayerRenderer.renderLayers(
// The layer type to render
EquipmentModel.LayerType.HUMANOID,
// The model id representing the EquipmentModel JSON
// This would be set in the `EQUIPPABLE` data component via `model`
stack.get(DataComponents.EQUIPPABLE).model().orElseThrow(),
// The model to apply the textures to
// These are usually separate models from the entity model
// and are separate ModelLayers linking to a LayerDefinition
model,
// The item stack representing the item being rendered as a model
// This is only used to get the dyeable, foil, and armor trim information
stack,
// The pose stack used to render the model in the correct location
poseStack,
// The source of the buffers to get the vertex consumer of the render type
bufferSource,
// The packed light texture
lighting,
// An absolute path of the texture to render when use_player_texture is true for one of the layer if not null
// Represents an absolute location within the assets folder
ResourceLocation.fromNamespaceAndPath("examplemod", "textures/other_texture.png")
);