盔甲
盔甲是主要通过各种抗性和效果,保护 LivingEntity 免受伤害的物品。许多 Mod 会添加新的盔甲套装,例如铜盔甲。
自定义盔甲套装
人形实体的一套盔甲通常包含四件物品:头部的头盔、胸部的胸甲、腿部的护腿和脚部的靴子。狼、马和羊驼也有盔甲,装备在动物专用的“身体”盔甲槽。这些物品通常通过七类数据组件实现:
DataComponents#MAX_DAMAGE和#DAMAGE:耐久度。#MAX_STACK_SIZE:将堆叠上限设为1。#REPAIRABLE:铁砧修复。#ENCHANTABLE:最大附魔能力值。#ATTRIBUTE_MODIFIERS:盔甲值、盔甲韧性和击退抗性。#EQUIPPABLE:实体如何装备此物品。
通常,人形实体盔甲通过 Item.Properties#humanoidArmor 设置,狼铠使用 wolfArmor,马铠使用 horseArmor,鹦鹉螺盔甲使用 nautilusArmor。它们都使用 ArmorMaterial 设置组件;人形盔甲还需要结合 ArmorType。参考数值可在 ArmorMaterials 中找到。下面以铜盔甲材质为例,可以按需调整数值。
// The resource key of the equipment asset used to link
// the `EquipmentClientInfo` JSON discussed below.
// Points to assets/examplemod/equipment/copper.json
public static final ResourceKey<EquipmentAsset> COPPER_ASSET = ResourceKey.create(EquipmentAssets.ROOT_ID, Identifier.fromNamespaceAndPath("examplemod", "copper"));
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 resource key of the EquipmentClientInfo JSON discussed below.
COPPER_ASSET
);
有了 ArmorMaterial,便可以用它注册盔甲:
// ITEMS is a DeferredRegister.Items
public static final DeferredItem<Item> COPPER_HELMET = ITEMS.registerItem(
"copper_helmet",
props -> new Item(
props.humanoidArmor(
// The material to use.
COPPER_ARMOR_MATERIAL,
// The type of armor to create.
ArmorType.HELMET
)
)
);
public static final DeferredItem<Item> COPPER_CHESTPLATE =
ITEMS.registerItem("copper_chestplate", props -> new Item(props.humanoidArmor(...)));
public static final DeferredItem<Item> COPPER_LEGGINGS =
ITEMS.registerItem("copper_chestplate", props -> new Item(props.humanoidArmor(...)));
public static final DeferredItem<Item> COPPER_BOOTS =
ITEMS.registerItem("copper_chestplate", props -> new Item(props.humanoidArmor(...)));
public static final DeferredItem<Item> COPPER_WOLF_ARMOR = ITEMS.registerItem(
"copper_wolf_armor",
props -> new Item(
// The material to use.
props.wolfArmor(COPPER_ARMOR_MATERIAL)
)
);
public static final DeferredItem<Item> COPPER_HORSE_ARMOR =
ITEMS.registerItem("copper_horse_armor", props -> new Item(props.horseArmor(...)));
public static final DeferredItem<Item> COPPER_NAUTILUS_ARMOR =
ITEMS.registerItem("copper_nautilus_armor", props -> new Item(props.nautilusArmor(...)));
若要从零创建盔甲或类似盔甲的物品,可以组合以下部分实现:
- 通过
Item.Properties#component设置DataComponents#EQUIPPABLE,添加符合自己需求的Equippable。 - 通过
Item.Properties#attributes添加盔甲值、韧性和击退抗性等属性。 - 通过
Item.Properties#durability添加耐久度。 - 通过
Item.Properties#repariable允许修复。 - 通过
Item.Properties#enchantable允许附魔。 - 将盔甲加入某些
minecraft:enchantable/*物品标签,允许应用相应附魔。
Equippable
Equippable 数据组件描述实体如何装备物品,以及游戏中由什么负责渲染。任何具有此组件的物品都可装备,不论它是否被视为盔甲,例如鞍和羊驼身上的地毯。每个具有此组件的物品只能装备到一个 EquipmentSlot。
可以直接调用记录类构造函数创建 Equippable,也可使用 Equippable#builder,先为各字段设置默认值,配置完成后调用 build:
// The resource key of the equipment asset used to link
// the `EquipmentClientInfo` JSON discussed below.
// Points to assets/examplemod/equipment/equippable.json
public static final ResourceKey<EquipmentAsset> EXAMPLE_EQUIPABBLE = ResourceKey.create(EquipmentAssets.ROOT_ID, Identifier.fromNamespaceAndPath("examplemod", "equippable"));
// Assume there is some DeferredRegister.Items ITEMS
public static final DeferredItem<Item> EQUIPPABLE = ITEMS.registerSimpleItem(
"equippable",
props -> props.component(
DataComponents.EQUIPPABLE,
// Sets the slot that this item can be equipped to.
Equippable.builder(EquipmentSlot.HELMET)
// Determines the sound played when equipping this item.
// This is wrapped with a Holder.
// Defaults to SoundEvents#ARMOR_EQUIP_GENERIC.
.setEquipSound(SoundEvents.ARMOR_EQUIP_GENERIC)
// The resource key of the EquipmentClientInfo JSON discussed below.
// When not set, does not render the equipment.
.setAsset(ResourceKey.create(EXAMPLE_EQUIPABBLE))
// 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(Identifier.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)
// Whether the item can be equipped onto another entity on interaction (e.g., right click).
// Defaults to false.
.setEquipOnInteract(true)
// When true, an item with the SHEAR_REMOVE_ARMOR item ability can remove the equipped item.
// Defaults to false.
.setCanBeSheared(true)
// The sound to play when shearing this equipped item.
// This is wrapped with a holder.
// Defaults to SoundEvents#SHEARS_SNIP.
.setShearingSound(SoundEvents.SADDLE_UNEQUIP)
.build()
)
);
装备资源
现在游戏中已有盔甲,但穿上后仍不会显示,因为还没有指定装备的渲染方式。需要在 Equippable#assetId 指定的位置创建 EquipmentClientInfo JSON,路径相对于资源包(assets 目录)中的 equipment 文件夹。EquipmentClientInfo 指定各渲染层所使用的纹理。
EquipmentClientInfo 本质上是从 EquipmentClientInfo.LayerType 到一组 EquipmentClientInfo.Layer 的映射。
可以将 LayerType 理解为某类对象需要渲染的一组纹理。例如,LayerType#HUMANOID 由 HumanoidArmorLayer 用于渲染人形实体的头部、胸部和脚部;LayerType#WOLF_BODY 由 WolfArmorLayer 用于渲染身体盔甲。如果这些层用于同一类可装备物品(例如铜盔甲),便可以合并到一个装备信息 JSON 中。
LayerType 映射到需要应用的一组 Layer,并按给定顺序渲染纹理。每个 Layer 实际上表示一张待渲染纹理。第一个参数是纹理位置,相对于 textures/entity/equipment。
第二个参数是可选值,通过 EquipmentClientInfo.Dyeable 表示纹理能否着色。Dyeable 保存一个整数;若提供此值,就以其作为默认 RGB 着色颜色。未提供时使用纯白色。
警告 要应用不同于未染色颜色的色调,物品必须位于
ItemTags#DYEABLE中,并将DataComponents#DYED_COLOR设为相应 RGB 值。
第三个参数为布尔值,表示是否以渲染时提供的纹理替代 Layer 内定义的纹理,例如玩家的自定义披风或鞘翅纹理。
下面为铜盔甲材质创建设备信息。假设每层都有两张纹理:实际盔甲纹理,以及叠加在其上并着色的纹理。对于动物盔甲,假设还可以传入一张动态纹理。
JSON
// In assets/examplemod/equipment/copper.json
{
// The layer map
"layers": {
// The serialized name of the EquipmentClientInfo.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/humanoid/copper/outer.png
"texture": "examplemod:copper/outer"
},
{
// The overlay texture
// Points to assets/examplemod/textures/entity/equipment/humanoid/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/humanoid_leggings/copper/inner.png
"texture": "examplemod:copper/inner"
},
{
// Points to assets/examplemod/textures/entity/equipment/humanoid_leggings/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/wolf_body/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/horse_body/copper/horse.png
"texture": "examplemod:copper/horse",
"use_player_texture": true
}
],
// For nautilus armor
"nautilus_body": [
{
// Points to assets/examplemod/textures/entity/equipment/nautilus_body/copper/nautilus.png
"texture": "examplemod:copper/nautilus",
"use_player_texture": true
}
]
}
}
数据生成
public class MyEquipmentInfoProvider extends EquipmentAssetProvider {
public MyEquipmentInfoProvider(PackOutput output) {
super(output);
}
@Override
protected void registerModels(BiConsumer<ResourceKey<EquipmentAsset>, EquipmentClientInfo> output) {
output.accept(
// Must match Equippable#assetId
COPPER_ASSET,
EquipmentClientInfo.builder()
// For humanoid head, chest, and feet
.addLayers(
EquipmentClientInfo.LayerType.HUMANOID,
// Base texture
new EquipmentClientInfo.Layer(
// The relative texture of the armor
// Points to assets/examplemod/textures/entity/equipment/humanoid/copper/outer.png
Identifier.fromNamespaceAndPath("examplemod", "copper/outer"),
Optional.empty(),
false
),
// Overlay texture
new EquipmentClientInfo.Layer(
// The overlay texture
// Points to assets/examplemod/textures/entity/equipment/humanoid/copper/outer_overlay.png
Identifier.fromNamespaceAndPath("examplemod", "copper/outer_overlay"),
// An RGB value (always opaque color)
// When not specified, set to 0 (meaning transparent or invisible)
Optional.of(new EquipmentClientInfo.Dyeable(Optional.of(0x7683DE))),
false
)
)
// For humanoid legs
.addLayers(
EquipmentClientInfo.LayerType.HUMANOID_LEGGINGS,
new EquipmentClientInfo.Layer(
// Points to assets/examplemod/textures/entity/equipment/humanoid_leggings/copper/inner.png
Identifier.fromNamespaceAndPath("examplemod", "copper/inner"),
Optional.empty(),
false
),
new EquipmentClientInfo.Layer(
// Points to assets/examplemod/textures/entity/equipment/humanoid_leggings/copper/inner_overlay.png
Identifier.fromNamespaceAndPath("examplemod", "copper/inner_overlay"),
Optional.of(new EquipmentClientInfo.Dyeable(Optional.of(0x7683DE))),
false
)
)
// For wolf armor
.addLayers(
EquipmentClientInfo.LayerType.WOLF_BODY,
// Base texture
new EquipmentClientInfo.Layer(
// Points to assets/examplemod/textures/entity/equipment/wolf_body/copper/wolf.png
Identifier.fromNamespaceAndPath("examplemod", "copper/wolf"),
Optional.empty(),
// When true, uses the texture passed into the layer renderer instead
true
)
)
// For horse armor
.addLayers(
EquipmentClientInfo.LayerType.HORSE_BODY,
// Base texture
new EquipmentClientInfo.Layer(
// Points to assets/examplemod/textures/entity/equipment/horse_body/copper/horse.png
Identifier.fromNamespaceAndPath("examplemod", "copper/horse"),
Optional.empty(),
true
)
)
// For nautilus armor
.addLayers(
EquipmentClientInfo.LayerType.NAUTILUS_BODY,
// Base texture
new EquipmentClientInfo.Layer(
// Points to assets/examplemod/textures/entity/equipment/nautilus_body/copper/nautilus.png
Identifier.fromNamespaceAndPath("examplemod", "copper/nautilus"),
Optional.empty(),
true
)
)
.build()
);
}
}
@SubscribeEvent // on the mod event bus
public static void gatherData(GatherDataEvent.Client event) {
event.createProvider(MyEquipmentInfoProvider::new);
}
装备渲染
装备信息通过 EquipmentLayerRenderer,在 EntityRenderer 或其某个 RenderLayer 的渲染函数中绘制。它作为渲染上下文的一部分,通过 EntityRendererProvider.Context#getEquipmentRenderer 获取。如果需要 EquipmentClientInfo,也可通过 EntityRendererProvider.Context#getEquipmentAssets 获取。
默认情况下,以下渲染层负责对应的 EquipmentClientInfo.LayerType:
LayerType |
RenderLayer |
使用者 |
|---|---|---|
HUMANOID |
HumanoidArmorLayer |
玩家、人形生物(如僵尸、骷髅)、盔甲架 |
HUMANOID_LEGGINGS |
HumanoidArmorLayer |
玩家、人形生物(如僵尸、骷髅)、盔甲架 |
HUMANOID_BABY |
HumanoidArmorLayer |
玩家、幼年人形生物(如幼年僵尸) |
WINGS |
WingsLayer |
玩家、人形生物(如僵尸、骷髅)、盔甲架 |
WOLF_BODY |
WolfArmorLayer |
狼 |
HORSE_BODY |
HorseArmorLayer |
马 |
LLAMA_BODY |
LlamaDecorLayer |
羊驼、行商羊驼 |
PIG_SADDLE |
SimpleEquipmentLayer |
猪 |
STRIDER_SADDLE |
SimpleEquipmentLayer |
炽足兽 |
CAMEL_SADDLE |
SimpleEquipmentLayer |
骆驼 |
CAMEL_HUSK_SADDLE |
SimpleEquipmentLayer |
尸壳骆驼 |
HORSE_SADDLE |
SimpleEquipmentLayer |
马 |
DONKEY_SADDLE |
SimpleEquipmentLayer |
驴 |
MULE_SADDLE |
SimpleEquipmentLayer |
骡 |
ZOMBIE_HORSE_SADDLE |
SimpleEquipmentLayer |
僵尸马 |
SKELETON_HORSE_SADDLE |
SimpleEquipmentLayer |
骷髅马 |
HAPPY_GHAST_BODY |
SimpleEquipmentLayer |
快乐恶魂 |
NAUTILUS_SADDLE |
SimpleEquipmentLayer |
鹦鹉螺 |
NAUTILUS_BODY |
SimpleEquipmentLayer |
鹦鹉螺 |
EquipmentLayerRenderer 只有一个用于提交装备层渲染的方法:renderLayers。
// In some render method where EquipmentLayerRenderer equipmentLayerRenderer is available
this.equipmentLayerRenderer.renderLayers(
// The layer type to render
EquipmentClientInfo.LayerType.HUMANOID,
// The resource key representing the EquipmentClientInfo JSON
// This would be set in the `EQUIPPABLE` data component via `assetId`
stack.get(DataComponents.EQUIPPABLE).assetId().orElseThrow(),
// The model to apply the equipment info 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 collector to submit the model data to
collector,
// The packed light coordinates
lightCoords,
// 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
Identifier.fromNamespaceAndPath("examplemod", "textures/other_texture.png"),
// The color of the model outline
// Only used if the outline color is not 0 and the `RenderType` has or is an outline type
outlineColor,
// The starting order priority to submit the layers and trims, ticking up with each model submitted
// By default, this is 1
order
);
来源: NeoForged/Documentation(26.1)。中文翻译依据提交
4a680cdd4d15。