工具

工具

工具是主要用于破坏方块的物品。许多 Mod 会添加新材质的工具套装(例如铜工具),或新的工具类型(例如锤子)。

自定义工具套装

一套工具通常包含镐、斧、锹、锄、剑和矛六种物品。剑和矛并非传统意义上的工具,但为保持一致也在此介绍。这些物品通过组合以下十四类数据组件实现:

  • DataComponents#MAX_DAMAGE 和 #DAMAGE:耐久度。
  • #MAX_STACK_SIZE:将堆叠上限设为 1。
  • #REPAIRABLE:铁砧修复。
  • #ENCHANTABLE:最大附魔能力值。
  • #ATTRIBUTE_MODIFIERS:攻击伤害和攻击速度。
  • #TOOL:挖掘信息。
  • #WEAPON:物品受到的耐久损耗及禁用盾牌。
  • #ATTACK_RANGE:挥动武器时的攻击范围。
  • #DAMAGE_TYPE:造成的伤害类型。
  • #MINIMUM_ATTACK_CHARGE:使用此武器发动攻击前,至少需要经过的刻数。
  • #SWING_ANIMATION:挥动物品时播放的动画。
  • #PIERCING_WEAPON:可同时攻击多个实体的刺击。
  • #KINETIC_WEAPON:根据动量、通过使用物品对多个实体发动的攻击。
  • #USE_EFFECTS:使用物品时对实体应用的效果。

通常通过 Item.Properties#tool、#sword、#spear,或 tool 的便捷方法(pickaxe、axe、hoe、shovel)设置工具。这些方法一般接收辅助记录类 ToolMaterial。剪刀等其他通常被视为工具的物品,并未通过数据组件实现通用挖掘逻辑,而是直接继承 Item 并重写相关方法。交互行为(默认右键)也没有对应数据组件,因此锹、斧和锄分别有自己的工具类 ShovelItem、AxeItem 和 HoeItem。

要创建标准工具套装,先定义 ToolMaterial。可参考 ToolMaterial 中的常量取值。此处以铜工具为例;可以替换材质并按需调整数值。

// We place copper somewhere between stone and iron.
public static final ToolMaterial COPPER_MATERIAL = new ToolMaterial(
        // The tag that determines what blocks this material cannot break. See below for more information.
        MyBlockTags.INCORRECT_FOR_COPPER_TOOL,
        // Determines the durability of the material.
        // Stone is 131, iron is 250.
        200,
        // Determines the mining speed of the material. Unused by swords.
        // Stone uses 4, iron uses 6.
        5f,
        // Determines the attack damage bonus. Different tools use this differently. For example, swords do (getAttackDamageBonus() + 4) damage.
        // Stone uses 1, iron uses 2, corresponding to 5 and 6 attack damage for swords, respectively; our sword does 5.5 damage now.
        1.5f,
        // Determines the enchantability of the material. This represents how good the enchantments on this tool will be.
        // Gold uses 22, we put copper slightly below that.
        20,
        // The tag that determines what items can repair this material.
        Tags.Items.INGOTS_COPPER
);

有了 ToolMaterial,便可以用它注册工具。所有 tool 便捷方法都接收相同的三个参数:

// ITEMS is a DeferredRegister.Items
public static final DeferredItem<Item> COPPER_SWORD = ITEMS.registerItem(
    "copper_sword",
    props -> new Item(
        // The item properties.
        props.sword(
            // The material to use.
            COPPER_MATERIAL,
            // The type-specific attack damage bonus. 3 for swords, 1.5 for shovels, 1 for pickaxes, varying for axes and hoes.
            3,
            // The type-specific attack speed modifier. The player has a default attack speed of 4, so to get to the desired
            // value of 1.6f, we use -2.4f. -2.4f for swords, -3f for shovels, -2.8f for pickaxes, varying for axes and hoes.
            -2.4f,
        )
    )
);

public static final DeferredItem<Item> COPPER_AXE = ITEMS.registerItem("copper_axe", props -> new Item(props.axe(...)));
public static final DeferredItem<Item> COPPER_PICKAXE = ITEMS.registerItem("copper_pickaxe", props -> new Item(props.pickaxe(...)));
public static final DeferredItem<Item> COPPER_SHOVEL = ITEMS.registerItem("copper_shovel", props -> new Item(props.shovel(...)));
public static final DeferredItem<Item> COPPER_HOE = ITEMS.registerItem("copper_hoe", props -> new Item(props.hoe(...)));

public static final DeferredItem<Item> COPPER_SPEAR = ITEMS.registerItem(
    "copper_spear",
    props -> new Item(
        props.spear(
            // The material to use.
            COPPER_MATERIAL,
            // The type-specific attack speed modifier. This value is scaled by performing the reciprocal of this value, then
            // subtracting 4.
            0.85f,
            // The damage multiplier applied when using the spear as a kinetic weapon, assuming one of the conditions are met.
            0.82f,
            // The number of seconds that must pass before the spear can be used as a kinetic weapon.
            0.65f,
            // The maximum number of seconds that can pass while using the kinetic weapon to dismount a hit entity.
            4.0f,
            // The minimum speed, in blocks, of the attacker using the kinetic weapon to dismount a hit entity.
            9.0f,
            // The maximum number of seconds that can pass while using the kinetic weapon to knockback a hit entity.
            8.25f,
            // The minimum speed, in blocks, of the attacker using the kinetic weapon to knockack a hit entity.
            5.1f,
            // The maximum number of seconds that can pass while using the kinetic weapon to damage a hit entity.
            12.5f,
            // The minimum speed, in blocks, of the attacker using the kinetic weapon to damage a hit entity. This is relative
            // to the attacked entity's speed.
            4.6f
        )
    )
);

提示 tool 本身还接收两个额外参数:表示可挖掘方块的 TagKey,以及被击中后格挡物(例如盾牌)被禁用的秒数。

标签

创建 ToolMaterial 时,需要指定一个方块标签,包含使用此工具破坏时不会掉落物品的方块。例如,minecraft:incorrect_for_stone_tool 包含钻石矿石等方块,minecraft:incorrect_for_iron_tool 则包含黑曜石和远古残骸等。为了便于将方块分配到不适用的挖掘等级,还存在表示所需工具等级的标签。例如,minecraft:needs_iron_tool 包含钻石矿石等方块,minecraft:needs_diamond_tool 包含黑曜石和远古残骸等。

如果符合需求,可以复用已有的不适用工具标签。例如,若铜工具只是更耐用的石工具,可以传入 BlockTags#INCORRECT_FOR_STONE_TOOL。

也可以创建自己的标签:

// This tag will allow us to add these blocks to the incorrect tags that cannot mine them
public static final TagKey<Block> NEEDS_COPPER_TOOL = TagKey.create(BuiltInRegistries.BLOCK.key(), Identifier.fromNamespaceAndPath(MOD_ID, "needs_copper_tool"));

// This tag will be passed into our material
public static final TagKey<Block> INCORRECT_FOR_COPPER_TOOL = TagKey.create(BuiltInRegistries.BLOCK.key(), Identifier.fromNamespaceAndPath(MOD_ID, "incorrect_for_cooper_tool"));

接下来填充标签。例如,让铜工具能够挖掘金矿石、金块和红石矿石,但不能挖掘钻石或绿宝石(石工具本来就能挖掘红石块)。标签文件位于 src/main/resources/data/mod_id/tags/block/needs_copper_tool.json,其中 mod_id 为你的 Mod ID:

{
    "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:

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

最后,按前文示例将标签传入材质实例。

要判断工具是否能让某个方块状态产生掉落物,调用 Tool#isCorrectForDrops。可以用 DataComponents#TOOL 调用 ItemStack#get 获取 Tool。

自定义工具

可以通过 Item.Properties#component,向物品的默认组件列表添加 Tool 数据组件(DataComponents#TOOL),创建自定义工具。

Tool 包含一组 Tool.Rule、持有工具时的默认挖掘速度(默认为 1),以及每次挖掘方块造成的耐久损耗(默认为 1)。每个 Tool.Rule 包含三项信息:适用方块的 HolderSet、可选的挖掘速度,以及可选的布尔值,表示工具能否让这些方块产生掉落物。未设置可选值时,会继续检查其他规则。如果所有规则都不匹配,则使用默认挖掘速度,且方块不会产生掉落物。

提示 可以通过 Registry#getOrThrow,从 TagKey 创建 HolderSet。

不使用现有 ToolMaterial 常量,也可以创建任何工具或多功能工具(将两种以上工具合为一件物品,例如斧镐)。可组合以下部分实现:

  • 通过 Item.Properties#component 设置 DataComponents#TOOL,添加自定义规则的 Tool。
  • 通过 Item.Properties#attributes 添加攻击伤害、攻击速度等属性修饰符。
  • 通过 Item.Properties#durability 添加耐久度。
  • 通过 Item.Properties#repariable 允许修复。
  • 通过 Item.Properties#enchantable 允许附魔。
  • 通过 Item.Properties#component 设置 DataComponents#WEAPON,使物品能作为武器使用,并可禁用格挡物。
  • 重写 IItemExtension#canPerformAction,指定物品能执行的 ItemAbility。
  • 如果希望右键时根据 ItemAbility 修改方块状态,调用 IBlockExtension#getToolModifiedState。
  • 将工具加入某些 minecraft:enchantable/* 物品标签,允许应用相应附魔。
  • 将工具加入某些 minecraft:*_preferred_weapons 标签,让生物优先拾取并使用此武器。

对于盾牌,可为副手应用 DataComponents#EQUIPPABLE 数据组件,并使用 DataComponents#BLOCKS_ATTACKS 在激活时减少持有者受到的伤害。

ItemAbility

ItemAbility 抽象描述物品能执行和不能执行的行为,包括左键和右键行为。NeoForge 在 ItemAbilities 类中提供了默认能力:

  • 斧的右键能力:原木去皮、氧化铜除锈、涂蜡铜除蜡。
  • 锹的右键能力:铲出土径、熄灭营火。
  • 剪刀能力:挖掘方块、采集蜜脾、移除狼铠、雕刻南瓜、解除绊线、修剪植物以停止生长。
  • 剑横扫、锄耕地、钓鱼竿抛投、三叉戟投掷、刷子刷扫、点火工具点火及望远镜观察等能力。

使用 ItemAbility#get 创建自己的能力;如果尚不存在,该方法会创建新 ItemAbility。然后在自定义工具类型中按需重写 IItemExtension#canPerformAction。

要查询 ItemStack 能否执行某个 ItemAbility,调用 IItemStackExtension#canPerformAction。这适用于任何 Item,并不限于工具。


来源: NeoForged/Documentation(26.1)。中文翻译依据提交 4a680cdd4d15。