Skip to content

工具与盔甲

字数
3000 字
阅读时间
13 分钟

工具与盔甲

工具的主要用途是破坏方块。许多 Mod 添加了新的工具套装(例如铜制工具)或新的工具类型(例如锤子)。

自定义工具套装

一个工具套装通常由五个物品组成:镐、斧、铲、锄和剑。(剑在传统意义上不是工具,但为了保持一致性,这里也包括在内。)所有这些物品都有其对应的类:PickaxeItemAxeItemShovelItemHoeItemSwordItem。工具的类层次结构如下:

Item
- TieredItem
    - DiggerItem
        - AxeItem
        - HoeItem
        - PickaxeItem
        - ShovelItem
    - SwordItem

TieredItem 是一个包含用于具有特定 Tier(见下文)的物品的辅助工具的类。DiggerItem 包含用于设计用于破坏方块的物品的辅助工具。请注意,通常被认为是工具的其他物品(例如剪刀)不包含在此层次结构中。相反,它们直接扩展 Item 并自行持有破坏逻辑。

要创建一套标准工具,您必须首先定义一个 Tier。有关参考值,请参见 Minecraft 的 Tiers 枚举。此示例使用铜制工具,您可以在此处使用自己的材料并根据需要调整值。

java
// 我们将铜放在石头和铁之间。
public static final Tier COPPER_TIER = new SimpleTier(
    // 确定此工具无法破坏的方块的标签。有关更多信息,请参见下文。
    MyBlockTags.INCORRECT_FOR_COPPER_TOOL,
    // 确定此等级的耐久度。
    // 石头为 131,铁为 250。
    200,
    // 确定此等级的挖掘速度。剑不使用此值。
    // 石头使用 4,铁使用 6。
    5f,
    // 确定攻击伤害加成。不同的工具使用此值的方式不同。例如,剑造成 (getAttackDamageBonus() + 4) 伤害。
    // 石头使用 1,铁使用 2,分别对应剑的 5 和 6 攻击伤害;我们的剑现在造成 5.5 伤害。
    1.5f,
    // 确定此等级的可附魔性。这表示此工具上的附魔效果如何。
    // 金使用 22,我们将铜稍微低于此值。
    20,
    // 确定此等级的修复材料。使用 Supplier 进行延迟初始化。
    () -> Ingredient.of(Tags.Items.INGOTS_COPPER)
);

现在我们有了 Tier,我们可以将其用于注册工具。所有工具的构造函数都有相同的四个参数。

java
// ITEMS 是一个 DeferredRegister<Item>
public static final Supplier<SwordItem> COPPER_SWORD = ITEMS.register("copper_sword", () -> new SwordItem(
    // 要使用的等级。
    COPPER_TIER,
    // 物品属性。我们不需要在此处设置耐久度,因为 TieredItem 会为我们处理。
    new Item.Properties().attributes(
        // 每个 DiggerItem 的类或子类中都有 `createAttributes` 方法
        SwordItem.createAttributes(
            // 要使用的等级。
            COPPER_TIER,
            // 特定类型的攻击伤害加成。剑为 3,铲为 1.5,镐为 1,斧和锄的值不同。
            3,
            // 特定类型的攻击速度修饰符。玩家的默认攻击速度为 4,因此要达到所需的 1.6f 值,我们使用 -2.4f。剑为 -2.4f,铲为 -3f,镐为 -2.8f,斧和锄的值不同。
            -2.4f
        )
    )
));
public static final Supplier<AxeItem> COPPER_AXE = ITEMS.register("copper_axe", () -> new AxeItem(...));
public static final Supplier<PickaxeItem> COPPER_PICKAXE = ITEMS.register("copper_pickaxe", () -> new PickaxeItem(...));
public static final Supplier<ShovelItem> COPPER_SHOVEL = ITEMS.register("copper_shovel", () -> new ShovelItem(...));
public static final Supplier<HoeItem> COPPER_HOE = ITEMS.register("copper_hoe", () -> new HoeItem(...));

标签

在创建 Tier 时,会为其分配一个包含使用此工具破坏时不会掉落任何物品的方块的方块标签。例如,minecraft:incorrect_for_stone_tool 标签包含钻石矿石等方块,而 minecraft:incorrect_for_iron_tool 标签包含黑曜石和远古残骸等方块。为了更容易将方块分配给其错误的挖掘等级,还存在一个标签用于需要此工具挖掘的方块。例如,minecraft:needs_iron_tool 标签包含钻石矿石等方块,而 minecraft:needs_diamond_tool 标签包含黑曜石和远古残骸等方块。

如果您对此感到满意,可以为您工具重用其中一个错误标签。例如,如果我们希望我们的铜制工具只是更耐用的石制工具,我们可以传入 BlockTags#INCORRECT_FOR_STONE_TOOL

或者,我们可以创建自己的标签,如下所示:

java
// 此标签将允许我们将这些方块添加到无法挖掘它们的错误标签中
public static final TagKey<Block> NEEDS_COPPER_TOOL = TagKey.create(BuiltInRegistries.BLOCK.key(), ResourceLocation.fromNamespaceAndPath(MOD_ID, "needs_copper_tool"));

// 此标签将传递到我们的等级中
public static final TagKey<Block> INCORRECT_FOR_COPPER_TOOL = TagKey.create(BuiltInRegistries.BLOCK.key(), ResourceLocation.fromNamespaceAndPath(MOD_ID, "incorrect_for_cooper_tool"));

然后,我们填充我们的标签。例如,让我们使铜能够挖掘金矿石、金块和红石矿石,但不能挖掘钻石或绿宝石。(红石块已经可以被石制工具挖掘。)标签文件位于 src/main/resources/data/mod_id/tags/block/needs_copper_tool.json(其中 mod_id 是您的 Mod ID):

json
{
    "values": [
        "minecraft:gold_block",
        "minecraft:raw_gold_block",
        "minecraft:gold_ore",
        "minecraft:deepslate_gold_ore",
        "minecraft:redstone_ore",
        "minecraft:deepslate_redstone_ore"
    ]
}

然后,为了将我们的标签传递到等级中,我们可以为任何对石制工具错误但在我们的铜制工具标签中的工具提供负约束。标签文件位于 src/main/resources/data/mod_id/tags/block/incorrect_for_cooper_tool.json

json
{
    "values": [
        "#minecraft:incorrect_for_stone_tool"
    ],
    "remove": [
        "#mod_id:needs_copper_tool"
    ]
}

最后,我们可以将我们的标签传递到我们的等级创建中,如上所示。

如果您想检查工具是否可以使方块状态掉落其方块,请调用 Tool#isCorrectForDrops。可以通过调用 ItemStack#get 并使用 DataComponents#TOOL 获取 Tool

自定义工具

可以通过将 Tool 数据组件(通过 DataComponents#TOOL)添加到您的物品的默认组件列表中(通过 Item.Properties#component)来创建自定义工具。DiggerItem 是一个实现,它接受一个 Tier,如上所述,以构建 ToolDiggerItem 还提供了一个方便的方法 #createAttributes,用于为您的工具提供 Item.Properties#attributes,例如修改后的攻击伤害和攻击速度。

Tool 包含一个 Tool.Rules 列表,持有工具时的默认挖掘速度(默认为 1),以及挖掘方块时工具应受到的伤害量(默认为 1)。Tool.Rule 包含三条信息:要应用规则的方块的 HolderSet,挖掘集合中方块的可选速度,以及确定这些方块是否可以从此工具掉落的可选布尔值。如果未设置可选值,则将检查其他规则。如果所有规则都失败,则默认行为是默认挖掘速度并且方块无法掉落。

注意:可以通过 Registry#getOrCreateTagTagKey 创建 HolderSet

创建多功能工具类物品(即结合两个或多个工具的物品,例如将斧和镐合二为一)或任何类似工具的物品不需要扩展任何现有的 TieredItems。它可以通过以下部分的组合来实现:

  • 通过 Item.Properties#component 设置 DataComponents#TOOL 来添加带有您自己规则的 Tool
  • 通过 Item.Properties#attributes 向物品添加属性(例如攻击伤害、攻击速度)。
  • 重写 IItemExtension#canPerformAction 以确定物品可以执行哪些 ItemAbility
  • 如果您希望您的物品根据 ItemAbility 在右键点击时修改方块状态,请调用 IBlockExtension#getToolModifiedState
  • 将您的工具添加到一些 minecraft:enchantable/* 标签中,以便您的物品可以应用某些附魔。

ItemAbility

ItemAbility 是对物品可以执行和不能执行的操作的抽象。这包括左键点击和右键点击行为。NeoForge 在 ItemAbilities 类中提供了默认的 ItemAbility

  • 挖掘能力。这些能力存在于上述所有四种 DiggerItem 类型中,以及剑和剪刀的挖掘。
  • 斧的右键点击能力,用于剥离(原木)、刮削(氧化的铜)和去蜡(涂蜡的铜)。
  • 剪刀的能力,用于收获(蜂巢)、雕刻(南瓜)和解除(绊线)。
  • 铲的平整(土路)、剑的横扫、锄的耕作、盾牌的格挡和钓鱼竿的抛掷能力。

要创建您自己的 ItemAbility,请使用 ItemAbility#get —— 如果需要,它将创建一个新的 ItemAbility。然后,在自定义工具类型中根据需要重写 IItemExtension#canPerformAction

要查询 ItemStack 是否可以执行某个 ItemAbility,请调用 IItemStackExtension#canPerformAction。请注意,这适用于任何 Item,而不仅仅是工具。

盔甲

与工具类似,盔甲使用等级系统(尽管是不同的系统)。工具的 Tier 被称为盔甲的 ArmorMaterial。与上面一样,此示例展示了如何添加铜制盔甲;可以根据需要进行调整。然而,与 Tier 不同,ArmorMaterial 需要注册。有关原版值,请参见 ArmorMaterials 类。

java
// ARMOR_MATERIALS 是一个 DeferredRegister<ArmorMaterial>

// 我们将铜放在锁链甲和铁之间。
public static final Holder<ArmorMaterial> COPPER_ARMOR_MATERIAL =
    ARMOR_MATERIALS.register("copper", () -> new ArmorMaterial(
        // 确定此盔甲材料的防御值,取决于它是哪种盔甲部件。
        Util.make(new EnumMap<>(ArmorItem.Type.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,
        // 确定此盔甲的修复物品。
        () -> Ingredient.of(Tags.Items.INGOTS_COPPER),
        // 确定渲染时要应用的盔甲纹理位置
        // 如果盔甲纹理需要更动态,也可以通过重写物品上的 'IItemExtension#getArmorTexture' 来指定
        List.of(
            // 创建一个新的盔甲纹理,它将位于:
            // - 'assets/mod_id/textures/models/armor/copper_layer_1.png' 用于外部纹理
            // - 'assets/mod_id/textures/models/armor/copper_layer_2.png' 用于内部纹理(仅裤子)
            new ArmorMaterial.Layer(
                ResourceLocation.fromNamespaceAndPath(MOD_ID, "copper")
            ),
            // 创建一个新的盔甲纹理,它将渲染在前一个纹理之上,位于:
            // - 'assets/mod_id/textures/models/armor/copper_layer_1_overlay.png' 用于外部纹理
            // - 'assets/mod_id/textures/models/armor/copper_layer_2_overlay.png' 用于内部纹理(仅裤子)
            // 'true' 表示盔甲材料可染色;但是,物品还必须添加到 'minecraft:dyeable' 标签中
            new ArmorMaterial.Layer(
                ResourceLocation.fromNamespaceAndPath(MOD_ID, "copper"), "_overlay", true
            )
        ),
        // 返回盔甲的韧性值。韧性值是包含在伤害计算中的附加值,有关更多信息,请参阅 Minecraft Wiki 的盔甲机制文章:
        // https://minecraft.wiki/w/Armor#Armor_toughness
        // 只有钻石和下界合金的值大于 0,所以我们只返回 0。
        0,
        // 返回盔甲的击退抗性值。穿着此盔甲时,玩家在一定程度上免疫击退。如果玩家从所有盔甲部件中获得的总击退抗性值为 1 或更高,则玩家将不会受到任何击退。
        // 只有下界合金的值大于 0,所以我们只返回 0。
        0
    ));

然后,我们在物品注册中使用该盔甲材料。

java
// ITEMS 是一个 DeferredRegister<Item>
public static final Supplier<ArmorItem> COPPER_HELMET = ITEMS.register("copper_helmet", () -> new ArmorItem(
    // 要使用的盔甲材料。
    COPPER_ARMOR_MATERIAL,
    // 要使用的盔甲类型。
    ArmorItem.Type.HELMET,
    // 物品属性,我们在其中设置耐久度。
    // ArmorItem.Type 是一个包含五个值的枚举:HELMET、CHESTPLATE、LEGGINGS、BOOTS 和 BODY。
    // BODY 用于非玩家实体,如狼或马。
    // 原版盔甲材料通过使用基值并将其乘以类型特定的常数来确定此值。
    // 常数为 BOOTS 为 13,LEGGINGS 为 15,CHESTPLATE 为 16,HELMET 为 11,BODY 为 16。
    // 如果我们不想使用这些比率,我们可以正常设置耐久度。
    new Item.Properties().durability(ArmorItem.Type.HELMET.getDurability(15))
));
public static final Supplier<ArmorItem> COPPER_CHESTPLATE = ITEMS.register("copper_chestplate", () -> new ArmorItem(...));
public static final Supplier<ArmorItem> COPPER_LEGGINGS = ITEMS.register("copper_leggings", () -> new ArmorItem(...));
public static final Supplier<ArmorItem> COPPER_BOOTS = ITEMS.register("copper_boots", () -> new ArmorItem(...));

在创建您的盔甲纹理时,最好在原版盔甲纹理的基础上工作,以查看哪些部分位于何处。

贡献者

The avatar of contributor named as 小飘 小飘

文件历史