盔甲

盔甲

盔甲是主要通过各种抗性和效果,保护 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。