Skip to content

物品

字数
3663 字
阅读时间
15 分钟

物品(Items)

与方块一样,物品是 Minecraft 的关键组成部分。方块构成了你周围的世界,而物品则存在于物品栏中。


什么是物品?

在进一步创建物品之前,了解什么是物品以及它与方块的区别非常重要。让我们通过一个例子来说明:

  1. 在世界中,你遇到一个泥土方块并想要挖掘它。这是一个方块,因为它被放置在世界中。(实际上,它是一个方块状态,而不是方块。更多详细信息请参阅方块状态文章。)
  2. 并非所有方块在破坏时都会掉落自身(例如树叶),更多信息请参阅战利品表文章。
  3. 一旦你挖掘了方块,它会被移除(即被替换为空气方块),并且泥土会掉落。掉落的泥土是一个物品实体。这意味着它像其他实体(猪、僵尸、箭等)一样,可以被水推动或被火和岩浆烧毁。
  4. 当你捡起泥土物品实体后,它会变成你物品栏中的一个物品堆叠。物品堆叠简单来说是一个物品实例,附带一些额外信息,例如堆叠数量。
  5. 物品堆叠由其对应的物品(即我们要创建的内容)支持。物品包含数据组件,这些组件存储了所有物品堆叠初始化的默认信息(例如,每把铁剑的最大耐久度为250),而物品堆叠可以修改这些数据组件,允许同一物品的两个不同堆叠具有不同的信息(例如,一把铁剑剩余100次使用,另一把剩余200次使用)。有关哪些功能通过物品实现,哪些通过物品堆叠实现,请继续阅读。

物品和物品堆叠之间的关系与方块和方块状态之间的关系大致相同,即方块状态总是由方块支持。这并不是一个非常准确的比较(例如,物品堆叠不是单例),但它很好地解释了这一概念。


创建物品

现在我们已经了解了什么是物品,让我们来创建一个!

与基础方块类似,对于不需要特殊功能的基础物品(例如木棍、糖等),可以直接使用Item​类。为此,在注册时,使用Item.Properties​参数实例化Item​。可以通过Item.Properties#of​创建Item.Properties​参数,并通过调用其方法进行自定义:

  • stacksTo​ - 设置物品的最大堆叠数量(通过DataComponents#MAX_STACK_SIZE​)。默认为64。例如,末影珍珠等物品的堆叠数量为16。
  • durability​ - 设置物品的耐久度(通过DataComponents#MAX_DAMAGE​)并将初始伤害设置为0(通过DataComponents#DAMAGE​)。默认为0,表示“无耐久度”。例如,铁工具使用250。注意,设置耐久度会自动将最大堆叠数量锁定为1。
  • craftRemainder​ - 设置物品的合成剩余物。原版使用此功能来处理合成后留下空桶的装满的桶。
  • fireResistant​ - 使使用此物品的物品实体免疫火和岩浆(通过DataComponents#FIRE_RESISTANT​)。用于各种下界合金物品。
  • setNoRepair​ - 禁用此物品的合成台和铁砧修复。原版未使用。
  • rarity​ - 设置物品的稀有度(通过DataComponents#RARITY​)。目前,这只会改变物品的颜色。稀有度是一个枚举,包含四个值:COMMON​(白色,默认)、UNCOMMON​(黄色)、RARE​(水绿色)和EPIC​(浅紫色)。请注意,模组可能会添加更多稀有度类型。
  • requiredFeatures​ - 设置此物品所需的特性标志。这主要用于原版在次要版本中的特性锁定系统。除非你正在集成一个被原版特性标志锁定的系统,否则不建议使用此功能。
  • food​ - 设置物品的FoodProperties​(通过DataComponents#FOOD​)。

有关示例或查看 Minecraft 使用的各种值,请参阅Items​类。


食物

Item​类为食物物品提供了默认功能,这意味着你不需要为此单独创建一个类。要使你的物品可食用,只需通过Item.Properties​中的food​方法设置FoodProperties​即可。

FoodProperties​使用FoodProperties.Builder​创建。然后你可以设置各种属性:

  • nutrition​ - 设置恢复的饥饿值。以半饥饿点计数,例如 Minecraft 的牛排恢复8点饥饿值。
  • saturationMod​ - 用于计算食用此食物时恢复的饱和值的饱和度修饰符。计算公式为min(2 * nutrition * saturationMod, playerNutrition)​,这意味着使用0.5将使有效饱和值与饥饿值相同。
  • alwaysEdible​ - 此物品是否始终可食用,即使饥饿条已满。默认为false​,金苹果等物品为true​,因为它们提供的不仅仅是填充饥饿条。
  • fast​ - 是否为此食物启用快速食用。默认为false​,原版中的干海带为true​。
  • effect​ - 添加食用此物品时应用的MobEffectInstance​。第二个参数表示应用效果的概率;例如,腐肉有80%的概率(即0.8)在食用时应用饥饿效果。此方法有两个变体;你应该使用接受Supplier​的变体(另一个直接接受MobEffectInstance​,由于类加载问题,已被 NeoForge 弃用)。
  • usingConvertsTo​ - 设置使用后转换成的物品。
  • build​ - 设置完所有内容后,调用build​以获取FoodProperties​对象以供进一步使用。

有关示例或查看 Minecraft 使用的各种值,请参阅Foods​类。

要获取物品的FoodProperties​,调用Item#getFoodProperties(ItemStack, LivingEntity)​。这可能返回null​,因为并非所有物品都可食用。要确定物品是否可食用,请检查getFoodProperties​调用的结果是否为null​。


更多功能

直接使用Item​只允许创建非常基础的物品。如果你想添加功能,例如右键点击交互,则需要一个扩展Item​的自定义类。Item​类有许多可以重写的方法,用于实现不同的功能;有关更多信息,请参阅Item​和IItemExtension​类。

物品的两个最常见用例是左键点击和右键点击。有关左键点击,请参阅破坏方块攻击实体(待完成)。有关右键点击,请参阅交互管道


DeferredRegister.Items

所有注册表都使用DeferredRegister​来注册其内容,物品也不例外。然而,由于添加新物品是绝大多数模组的基本功能,NeoForge 提供了DeferredRegister.Items​辅助类,它扩展了DeferredRegister<Item>​并提供了一些特定于物品的辅助方法:

java
public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(ExampleMod.MOD_ID);

public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerItem(
    "example_item",
    Item::new, // 将属性传递给的工厂。
    new Item.Properties() // 要使用的属性。
);

在内部,这将简单地调用ITEMS.register("example_item", () -> new Item(new Item.Properties()))​,将属性参数应用于提供的物品工厂(通常是构造函数)。

如果你想使用Item::new​,可以完全省略工厂并使用简单的方法变体:

java
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem(
    "example_item",
    new Item.Properties() // 要使用的属性。
);

这与前面的示例完全相同,但更简洁。当然,如果你想使用Item​的子类而不是Item​本身,则必须使用前面的方法。

这两种方法还有省略new Item.Properties()​参数的重载:

java
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerItem("example_item", Item::new);
// 省略Item::new参数的变体
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item");

最后,还有用于方块物品的快捷方式:

java
public static final Supplier<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
    "example_block",
    ExampleBlocksClass.EXAMPLE_BLOCK, new Item.Properties()
);
// 省略属性参数的变体:
public static final Supplier<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
    "example_block",
    ExampleBlocksClass.EXAMPLE_BLOCK
);
// 省略名称参数,使用方块的注册名称的变体:
public static final Supplier<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
    ExampleBlocksClass.EXAMPLE_BLOCK,
    new Item.Properties()
);
// 省略名称和属性的变体:
public static final Supplier<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
    ExampleBlocksClass.EXAMPLE_BLOCK
);

注意:如果你将注册的方块放在单独的类中,你应该在加载物品类之前加载方块类。


资源

如果你注册了物品并通过/give​或创造模式标签获取它,你会发现它缺少正确的模型和纹理。这是因为纹理和模型由 Minecraft 的资源系统处理。

要为物品应用简单的纹理,你必须添加物品模型 JSON 和纹理 PNG。有关更多信息,请参阅资源部分。


物品堆叠(ItemStacks)

与方块和方块状态一样,大多数你期望使用Item​的地方实际上使用的是ItemStack​。ItemStack​表示容器中的一个或多个物品的堆叠,例如物品栏。同样,与方块和方块状态一样,方法应由Item​重写并由ItemStack​调用,Item​中的许多方法会传入ItemStack​实例。

ItemStack​由三个主要部分组成:

  1. 物品:它代表的物品,可通过ItemStack#getItem​获取。
  2. 堆叠数量:通常在1到64之间,可通过getCount​获取,并通过setCount​或shrink​更改。
  3. 数据组件映射:存储堆叠特定数据的地方。可通过getComponents​获取。通常通过has​、get​、set​、update​和remove​访问和修改组件值。

要创建新的ItemStack​,调用new ItemStack(Item)​,传入支持的物品。默认情况下,这使用数量为1且没有NBT数据;如果需要,还有接受数量和NBT数据的构造函数重载。

ItemStack​是可变对象(见下文),但有时需要将它们视为不可变对象。如果你需要修改被视为不可变的ItemStack​,可以使用#copy​或#copyWithCount​克隆堆叠(如果需要特定堆叠数量)。

如果你想表示堆叠没有物品,请使用ItemStack.EMPTY​。如果你想检查ItemStack​是否为空,请调用#isEmpty​。


物品堆叠的可变性

ItemStack​是可变对象。这意味着如果你调用例如#setCount​或任何数据组件映射方法,ItemStack​本身将被修改。原版广泛使用ItemStack​的可变性,许多方法依赖于它。例如,#split​从调用它的堆叠中拆分出给定数量,同时修改调用者并返回一个新的ItemStack​。

然而,在处理多个ItemStack​时,这有时会导致问题。最常见的实例是处理物品栏槽位时,因为你必须同时考虑光标当前选择的ItemStack​以及你试图插入/提取的ItemStack​。

提示:如果有疑问,最好安全起见,使用#copy​复制堆叠。


JSON 表示

在许多情况下,例如配方中,物品堆叠需要表示为 JSON 对象。物品堆叠的 JSON 表示如下:

json
{
    // 物品ID。必需。
    "id": "minecraft:dirt",
    // 物品堆叠数量。可选,默认为1。
    "count": 4,
    // 数据组件映射。可选,默认为空映射。
    "components": {
        "minecraft:enchantment_glint_override": true
    }
}

创造模式标签

默认情况下,你的物品只能通过/give​获取,而不会出现在创造模式物品栏中。让我们改变这一点!

将物品添加到创造模式菜单的方式取决于你要将其添加到哪个标签。

现有的创造模式标签

注意:此方法用于将你的物品添加到 Minecraft 的标签或其他模组的标签中。要将物品添加到自己的标签中,请参阅下文。

可以通过BuildCreativeModeTabContentsEvent​将物品添加到现有的CreativeModeTab​中,该事件在模组事件总线上触发,仅在逻辑客户端上触发。通过调用event#accept​添加物品。

java
// MyItemsClass.MY_ITEM 是 Supplier<? extends Item>,MyBlocksClass.MY_BLOCK 是 Supplier<? extends Block>
@SubscribeEvent
public static void buildContents(BuildCreativeModeTabContentsEvent event) {
    // 这是我们要添加到的标签吗?
    if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
        event.accept(MyItemsClass.MY_ITEM.get());
        // 接受 ItemLike。假设 MY_BLOCK 有对应的物品。
        event.accept(MyBlocksClass.MY_BLOCK.get());
    }
}

该事件还提供了一些额外信息,例如getFlags​以获取启用的特性标志列表,或hasPermissions​以检查玩家是否有权限查看操作员物品标签。

自定义创造模式标签

CreativeModeTab​是一个注册表,意味着自定义CreativeModeTab​必须注册。创建创造模式标签使用构建器系统,构建器可通过CreativeModeTab#builder​获取。构建器提供了设置标题、图标、默认物品和许多其他属性的选项。此外,NeoForge 提供了额外的方法来自定义标签的图像、标签和槽位颜色、标签的排序位置等。

java
// CREATIVE_MODE_TABS 是 DeferredRegister<CreativeModeTab>
public static final Supplier<CreativeModeTab> EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example", () -> CreativeModeTab.builder()
    // 设置标签的标题。别忘了添加翻译!
    .title(Component.translatable("itemGroup." + MOD_ID + ".example"))
    // 设置标签的图标。
    .icon(() -> new ItemStack(MyItemsClass.EXAMPLE_ITEM.get()))
    // 将你的物品添加到标签中。
    .displayItems((params, output) -> {
        output.accept(MyItemsClass.MY_ITEM.get());
        // 接受 ItemLike。假设 MY_BLOCK 有对应的物品。
        output.accept(MyBlocksClass.MY_BLOCK.get());
    })
    .build()
);

ItemLike

ItemLike​是一个接口,由原版中的Item​和Block​实现。它定义了#asItem​方法,该方法返回对象的物品表示:Item​只返回自身,而Block​返回其关联的BlockItem​(如果可用),否则返回Blocks.AIR​。ItemLike​用于许多不关心物品“来源”的上下文中,例如在许多数据生成器中。

你也可以在自定义对象上实现ItemLike​。只需重写#asItem​即可。

贡献者

The avatar of contributor named as 小飘 小飘

文件历史