Skip to main content
Version: 1.21.4

盔甲(Armor)

盔甲(Armor)是一类物品(item),其主要用途是通过多种抗性和效果保护LivingEntity免受伤害。许多模组会添加新的盔甲套装(例如铜制盔甲)。

自定义盔甲套装(Custom Armor Sets)

对于类人生物,一个完整的盔甲套装通常包含四个物品:头部的头盔、胸部的胸甲、腿部的护腿和脚部的靴子。此外,还有专门为狼、马和羊驼设计的动物盔甲,这些盔甲会装备在动物专用的“身体”盔甲槽位上。所有这些物品通常分别通过 ArmorItemAnimalArmorItem 实现。

盔甲的绝大多数功能都是通过七个数据组件(data components)实现的:

  • DataComponents#MAX_DAMAGE#DAMAGE:用于耐久度
  • #MAX_STACK_SIZE:将堆叠数量设置为 1
  • #REPAIRABLE:允许在铁砧上修复盔甲
  • #ENCHANTABLE:设定最大附魔(enchanting)
  • #ATTRIBUTE_MODIFIERS:用于盔甲值、盔甲韧性和击退抗性
  • #EQUIPPABLE:定义实体如何装备该物品

ArmorItemAnimalArmorItem 分别结合 ArmorMaterialArmorTypeAnimalArmorItem.BodyType 来设置这些组件。参考数值可以在 ArmorMaterials 中找到。以下示例使用了铜制盔甲材质,你可以根据需要调整这些数值。

public static final ArmorMaterial COPPER_ARMOR_MATERIAL = new ArmorMaterial(
// 该护甲材质的耐久度倍率。
// 不同的 ArmorType(护甲类型)有不同的基础耐久度,该倍率会应用到这些基础值上:
// - HELMET(头盔):11
// - CHESTPLATE(胸甲):16
// - LEGGINGS(护腿):15
// - BOOTS(靴子):13
// - BODY(身体):16
15,
// 决定护甲的防御值(也就是护甲条上的半格数量)。
// 基于 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);
}),
// 决定护甲的可附魔性。这个值代表该护甲能获得多好的附魔效果。
// 金装的值是 25,这里我们把铜装设置得略低一些。
20,
// 决定穿上这件护甲时播放的音效。
// 这里使用了 Holder 包装。
SoundEvents.ARMOR_EQUIP_GENERIC,
// 返回护甲的韧性值。韧性值是参与伤害计算的额外参数,
// 详细信息可参考 Minecraft Wiki 上关于护甲机制的文章:
// https://minecraft.wiki/w/Armor#Armor_toughness
// 目前只有钻石和下界合金的值大于 0,这里我们直接返回 0。
0,
// 返回护甲的击退抗性值。穿戴该护甲时,玩家会获得一定程度的击退免疫。
// 如果玩家全身护甲的击退抗性总值达到 1 或更高,将完全不会被击退。
// 目前只有下界合金的值大于 0,这里我们直接返回 0。
0,
// 指定用于修复该护甲的物品标签。
Tags.Items.INGOTS_COPPER,
// EquipmentClientInfo JSON 的资源键,相关内容见下文
// 指向 assets/examplemod/equipment/copper.json
ResourceKey.create(EquipmentAssets.ROOT_ID, ResourceLocation.fromNamespaceAndPath("examplemod", "copper"))
);

现在我们已经有了自己的 ArmorMaterial(护甲材质),就可以用它来注册护甲了。ArmorItem(护甲物品)接收 ArmorMaterial 和代表装备部位的 ArmorType 作为参数。而 AnimalArmorItem 则接收 ArmorMaterialAnimalArmorItem.BodyType。此外,它还可以选择性地传入装备音效,以及是否应用耐久和可修复组件。

// ITEMS 是一个 DeferredRegister.Items
public static final DeferredItem<ArmorItem> COPPER_HELMET = ITEMS.registerItem(
"copper_helmet",
props -> new ArmorItem(
// 要使用的材料。
COPPER_ARMOR_MATERIAL,
// 要创建的护甲类型。
ArmorType.HELMET,
// 物品属性。
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(
// 要使用的材料。
COPPER_ARMOR_MATERIAL,
// 该护甲可以被哪种身体类型穿戴。
AnimalArmorItem.BodyType.CANINE,
// 物品属性。
props
)
);

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

现在,创建护甲或类似护甲的物品,不再需要继承 ArmorItemAnimalArmorItem。你只需结合以下几个部分即可实现:

  • 通过设置 Item.Properties#componentDataComponents#EQUIPPABLE,为你的物品添加自定义需求的 Equippable 组件(可装备组件)。
  • 通过 Item.Properties#attributes 为物品添加属性(例如护甲值、韧性、击退抗性等)。
  • 通过 Item.Properties#durability 添加物品耐久度。
  • 通过 Item.Properties#repariable 允许物品被修复。
  • 通过 Item.Properties#enchantable 允许物品被附魔。
  • 将你的护甲加入某些 minecraft:enchantable/* ItemTags(物品标签),以便该物品可以获得特定的附魔。

Equippable

Equippable 是一个数据组件(data component),它定义了一个实体如何装备该物品,以及游戏内如何渲染该物品。只要物品包含了这个组件,无论它是否被视为“护甲”,都可以被装备(例如羊驼身上的地毯)。每个带有此组件的物品只能装备到一个 EquipmentSlot(装备槽)上。

你可以直接调用 record 构造函数,或者通过 Equippable#builder 创建一个 Equippable,该 builder 会为每个字段设置默认值,最后通过 build 方法完成创建:

// 假设存在一个 DeferredRegister.Items ITEMS
public static final DeferredItem<Item> EQUIPPABLE = ITEMS.registerSimpleItem(
"equippable",
new Item.Properties().copmonent(
DataComponents.EQUIPPABLE,
// 设置该物品可以装备到的槽位。
Equippable.builder(EquipmentSlot.HELMET)
// 设置装备该护甲时播放的音效。
// 这里使用 Holder 进行包装。
// 默认为 SoundEvents#ARMOR_EQUIP_GENERIC。
.setEquipSound(SoundEvents.ARMOR_EQUIP_GENERIC)
// EquipmentClientInfo JSON 的资源键,详见下文。
// 指向 assets/examplemod/equipment/equippable.json
// 如果未设置,则不会渲染该装备。
.setAsset(ResourceKey.create(EquipmentAssets.ROOT_ID, ResourceLocation.fromNamespaceAndPath("examplemod", "equippable")))
// 穿戴时在玩家屏幕上覆盖的贴图的相对路径(如南瓜模糊效果)。
// 指向 assets/examplemod/textures/equippable.png
// 如果未设置,则不会渲染覆盖层。
.setCameraOverlay(ResourceLocation.withDefaultNamespace("examplemod", "equippable"))
// 可以装备此物品的实体类型集合(直接指定或通过标签)。
// 如果未设置,则任何实体都可以装备此物品。
.setAllowedEntities(EntityType.ZOMBIE)
// 该物品能否通过发射器装备。
// 默认为 true。
.setDispensable(true),
// 在快速装备时,该物品是否可以被替换下。
// 默认为 true。
.setSwappable(false),
// 装备被攻击时是否应该受到损坏(通常用于装备)。
// 物品本身也必须是可损坏的。
// 默认为 true。
.setDamageOnHurt(false)
.build()
)
);

装备资源(Equipment Assets)

现在我们已经在游戏中添加了一些护甲,但如果尝试穿戴它,会发现没有任何渲染效果,因为我们还没有指定如何渲染该装备。为此,需要在 资源包assets 文件夹)下的 equipment 文件夹中,按照 Equippable#assetId 指定的位置创建一个 EquipmentClientInfo JSON 文件。EquipmentClientInfo 用于指定每一层渲染时所用的贴图。

EquipmentClientInfo 实际上是一个将 EquipmentClientInfo.LayerType 映射到 EquipmentClientInfo.Layer 列表的映射表。

LayerType 可以理解为某一实例下需要渲染的贴图分组。例如,LayerType#HUMANOIDHumanoidArmorLayer 用于在人形实体上渲染头部、胸部与脚部;LayerType#WOLF_BODYWolfArmorLayer 用于渲染狼的护甲。这些类型可以组合在一个装备信息 JSON 文件中,如果它们属于同一种可装备物品(比如铜制护甲)。 LayerType 会映射到一组有序的 Layer(层),这些 Layer 会依次应用并渲染贴图。每个 Layer 实际上代表一张需要渲染的贴图。第一个参数表示贴图的位置,路径是相对于 textures/entity/equipment 的。

第二个参数是一个可选项,用于指示该贴图是否可以染色,即是否作为 EquipmentClientInfo.DyeableDyeable 对象内部保存了一个整数,如果存在,则表示默认用于给贴图染色的 RGB 颜色。如果该可选项不存在,则默认使用纯白色。

warning

如果想让物品应用非未染色(undyed)的颜色,物品必须在 ItemTags#DYEABLE 标签中,并且需要设置 DataComponents#DYED_COLOR 组件为某个 RGB 值。

第三个参数是一个布尔值,表示在渲染时是否使用传入的贴图来替代 Layer 中定义的贴图。例如,玩家的自定义披风(cape)或鞘翅(elytra)贴图就属于这种情况。

接下来,我们为铜质护甲材质创建一个装备信息。我们假设每个层级都有两张贴图:一张用于实际护甲,另一张是叠加并可染色的贴图。对于动物护甲,我们假设会有一个可动态传入的贴图。

// 在 assets/examplemod/equipment/copper.json 中
{
// 图层映射(layer map)
"layers": {
// 要应用的 EquipmentClientInfo.LayerType 的序列化名称
// 用于类人生物的头部、胸部和脚部
"humanoid": [
// 按照提供顺序渲染的图层列表
{
// 盔甲的相对材质路径
// 指向 assets/examplemod/textures/entity/equipment/copper/outer.png
"texture": "examplemod:copper/outer"
},
{
// 覆盖材质(overlay texture)
// 指向 assets/examplemod/textures/entity/equipment/copper/outer_overlay.png
"texture": "examplemod:copper/outer_overlay",
// 如果指定该项,则允许该材质根据 DataComponents#DYED_COLOR 进行染色
// 否则,无法染色
"dyeable": {
// RGB 值(始终为不透明色)
// 0x7683DE 的十进制表示
// 如果未指定,则设为 0(表示透明或不可见)
"color_when_undyed": 7767006
}
}
],
// 用于类人生物的腿部
"humanoid_leggings": [
{
// 指向 assets/examplemod/textures/entity/equipment/copper/inner.png
"texture": "examplemod:copper/inner"
},
{
// 指向 assets/examplemod/textures/entity/equipment/copper/inner_overlay.png
"texture": "examplemod:copper/inner_overlay",
"dyeable": {
"color_when_undyed": 7767006
}
}
],
// 用于狼盔甲
"wolf_body": [
{
// 指向 assets/examplemod/textures/entity/equipment/copper/wolf.png
"texture": "examplemod:copper/wolf",
// 如果为 true,则改为使用传递给图层渲染器的材质
"use_player_texture": true
}
],
// 用于马盔甲
"horse_body": [
{
// 指向 assets/examplemod/textures/entity/equipment/copper/horse.png
"texture": "examplemod:copper/horse",
"use_player_texture": true
}
]
}
}

装备渲染(Equipment Rendering)

装备信息(equipment infos)是通过 EquipmentLayerRendererEntityRenderer 或其某个 RenderLayer 的渲染函数中进行渲染的。EquipmentLayerRenderer 可以通过渲染上下文中的 EntityRendererProvider.Context#getEquipmentRenderer 获取。如果你需要 EquipmentClientInfo,也可以通过 EntityRendererProvider.Context#getEquipmentAssets 获得。

默认情况下,以下渲染层会渲染对应的 EquipmentClientInfo.LayerType

LayerTypeRenderLayer使用对象
HUMANOIDHumanoidArmorLayer玩家、类人生物(如僵尸、骷髅)、盔甲架
HUMANOID_LEGGINGSHumanoidArmorLayer玩家、类人生物(如僵尸、骷髅)、盔甲架
WINGSWingsLayer玩家、类人生物(如僵尸、骷髅)、盔甲架
WOLF_BODYWolfArmorLayer
HORSE_BODYHorseArmorLayer
LLAMA_BODYLlamaDecorLayer羊驼、商人羊驼

EquipmentLayerRenderer 只有一个用于渲染装备层的方法,名称也很直观,叫做 renderLayers

// 在某个渲染方法中,EquipmentLayerRenderer equipmentLayerRenderer 是一个字段
this.equipmentLayerRenderer.renderLayers(
// 要渲染的层类型
EquipmentClientInfo.LayerType.HUMANOID,
// 表示 EquipmentClientInfo JSON 的资源键
// 这个值会在 `EQUIPPABLE` 数据组件中通过 `assetId` 设置
stack.get(DataComponents.EQUIPPABLE).assetId().orElseThrow(),
// 要应用装备信息的模型
// 这些模型通常与实体模型分离
// 并且是独立的 ModelLayers,关联到 LayerDefinition
model,
// 表示作为模型渲染的物品堆叠
// 仅用于获取可染色、特效和盔甲装饰的信息
stack,
// 用于将模型渲染到正确位置的姿态堆栈
poseStack,
// 获取渲染类型顶点消费者所需的缓冲区来源
bufferSource,
// 打包的光照纹理
lighting,
// 当某一层的 use_player_texture 为 true 且不为 null 时,要渲染的绝对纹理路径
// 代表 assets 文件夹下的绝对位置
ResourceLocation.fromNamespaceAndPath("examplemod", "textures/other_texture.png")
);