Skip to main content
Version: 1.21.4

物品(Items)

除了方块(blocks)之外,物品(items)也是 Minecraft 的核心组成部分。方块构成了你周围的世界,而物品则存在于各类物品栏中。

什么是物品?(What Even Is an Item?)​

在深入了解如何创建物品之前,首先要搞清楚物品到底是什么,以及它与比如 方块 有什么区别。我们用一个例子来说明:

  • 在世界中,你遇到一个泥土方块并想要挖掘它。这是一个方块,因为它被放置在世界中。(实际上,它不是一个方块,而是一个方块状态(blockstate)。详细信息请参阅 方块状态(Blockstates)文章。)
    • 不是所有方块在被破坏时都会掉落自身(比如树叶),更多内容请参考 掉落表(loot tables) 相关的文章。
  • 当你挖掘这个方块后,它会被移除(也就是被空气方块替代),同时掉落泥土。掉落的泥土是一个物品**实体(entity)**。这意味着,和其他实体(如猪、僵尸、箭等)一样,它可以被水流推动、被火或岩浆烧毁等。
  • 当你捡起这个泥土物品实体后,它会变成你物品栏中的一个物品堆(item stack)。简单来说,物品堆就是某个物品的一个实例,并带有一些额外信息,比如堆叠数量。
  • 物品堆背后对应着它的物品(item)(这也是我们要创建的东西)。物品包含了数据组件(data components),这些组件定义了所有物品堆初始化时的默认信息(例如,每把铁剑的最大耐久都是 250),而物品堆则可以修改这些数据组件,从而让同一种物品的不同堆叠拥有不同的信息(比如,一把铁剑剩余 100 次使用,另一把剩余 200 次)。想了解更多关于哪些操作通过物品完成、哪些通过物品堆完成,请继续阅读下文。
    • 物品和物品堆之间的关系,大致等同于 方块 和 方块状态(blockstates) 之间的关系,即方块状态总是由某个方块所支撑。这个类比并不完全严谨(比如物品堆不是单例),但可以帮助你理解这里的基本概念。

创建物品(Creating an Item)​

现在我们已经理解了物品的概念,接下来就来创建一个物品吧!

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

  • setId - 设置该物品的资源键(resource key)。
    • 这一项必须为每个物品设置,否则会抛出异常。
  • overrideDescription - 设置该物品的翻译键(translation key)。生成的 Component 会存储在 DataComponents#ITEM_NAME 中。
  • useBlockDescriptionPrefix - 便捷方法,会调用 overrideDescription,并使用 block.<modid>.<registry_name> 作为翻译键。对于所有 BlockItem,都应调用此方法。
  • requiredFeatures - 设置该物品所需的功能标志(feature flags)。主要用于原版的功能锁定系统(feature locking system),通常只在你需要与原版通过功能标志锁定的系统集成时才建议使用。
  • stacksTo - 设置该物品的最大堆叠数量(max stack size,通过 DataComponents#MAX_STACK_SIZE)。默认值为 64。例如末影珍珠或其他只能堆叠到 16 的物品会使用该属性。
  • durability - 设置该物品的耐久度(durability,通过 DataComponents#MAX_DAMAGE),并将初始损耗值设为 0(通过 DataComponents#DAMAGE)。默认值为 0,表示“无耐久度”。比如铁制工具在这里的值为 250。注意,设置耐久度后,最大堆叠数量会自动锁定为 1。
  • fireResistant - 让使用该物品的物品实体免疫火焰和岩浆(通过 DataComponents#FIRE_RESISTANT)。常用于各种下界合金(netherite)物品。
  • rarity - 设置该物品的稀有度(rarity,通过 DataComponents#RARITY)。目前,这仅会改变物品名称的颜色。Rarity 是一个枚举(enum),包含四个值:COMMON(白色,默认)、UNCOMMON(黄色)、RARE(青色)、EPIC(浅紫色)。注意,模组可能会添加更多稀有度类型。
  • setNoRepair - 禁用该物品在铁砧和合成栏中的修复功能。原版未使用该属性。
  • jukeboxPlayable - 设置插入唱片机(jukebox)时要播放的 datapack JukeboxSong 的资源键(resource key)。
  • food - 设置该物品的 FoodProperties(通过 DataComponents#FOOD)。

如需查看示例,或想了解 Minecraft 中使用的各种值,可以参考 Items 类。

剩余物与冷却时间(Remainders and Cooldowns)​

物品在被使用时,可能具有额外属性,例如使用后产生剩余物,或在一定时间内无法再次使用:

  • craftRemainder - 设置该物品的合成剩余物(crafting remainder)。原版用在如装满的水桶,合成后会留下空桶。
  • usingConvertsTo - 设置该物品在使用结束后(通过 Item#use、IItemExtension#finishUsingItem 或 Item#releaseUsing)返回的物品。对应的 ItemStack 会存储在 DataComponents#USE_REMAINDER 上。
  • useCooldown - 设置该物品再次可用前需要等待的秒数(通过 DataComponents#USE_COOLDOWN)。

工具与护甲(Tools and Armor)​

有些物品的行为类似于工具和护甲。这些物品通过一系列的物品属性进行构建,部分功能会委托给它们关联的类。

  • enchantable - 设置物品堆叠的最大 附魔 值,使该物品可以被附魔(通过 DataComponents#ENCHANTABLE 实现)。
  • repairable - 设置可用于修复该物品耐久度的物品或标签(通过 DataComponents#REPAIRABLE 实现)。必须具有耐久度组件,并且不能为 DataComponents#UNBREAKABLE。
  • equippable - 设置该物品可以装备到的槽位(通过 DataComponents#EQUIPPABLE 实现)。
  • equippableUnswappable - 与 equippable 类似,但禁用通过使用物品按钮(默认右键)进行的快速切换。

更多信息可在相关页面找到。

更多功能(More Functionality)​

直接使用 Item 只允许创建非常基础的物品。如果你想为物品添加更多功能,例如右键交互,则需要创建一个继承自 Item 的自定义类。Item 类有许多可被重写的方法,用于实现不同的行为;详细信息请参阅 Item 和 IItemExtension 这两个类。

物品最常见的两种用例是左键点击和右键点击。由于它们涉及的系统较为复杂,这部分内容会在单独的 交互(Interaction)文章 中详细说明。

DeferredRegister.Items​

所有注册表(Registry)都使用 DeferredRegister 来注册其内容,物品也不例外。不过,由于添加新物品是绝大多数模组的核心功能,NeoForge 提供了一个扩展自 DeferredRegister<Item> 的辅助类 DeferredRegister.Items,它还提供了一些专用于物品的辅助方法:

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

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

在内部,这实际上会通过将属性参数应用到提供的物品工厂(通常为构造函数),调用 ITEMS.register("example_item", registryName -> new Item(new Item.Properties().setId(ResourceKey.create(Registries.ITEM, registryName))))。物品的 id 会被设置到属性上。

如果你想直接使用 Item::new,可以完全省略工厂方法,直接使用 simple 方法变体:

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

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

这两种方法都提供了重载版本,可以省略 new Item.Properties() 参数:

public static final DeferredItem<Item> EXAMPLE_ITEM = ITEMS.registerItem("example_item", Item::new);

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

最后,还有用于方块物品(block item)的简化注册方法。除了调用 setId 外,这些方法还会调用 useBlockDescriptionPrefix,将翻译键(translation key)设置为与方块一致:

public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
"example_block",
ExampleBlocksClass.EXAMPLE_BLOCK,
new Item.Properties()
);

// 省略 properties 参数的变体:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
"example_block",
ExampleBlocksClass.EXAMPLE_BLOCK
);

// 省略 name 参数的变体,此时会直接使用方块的注册名:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
// 必须是 `Holder<Block>` 的实例
// `DeferredBlock<T>` 也可以
ExampleBlocksClass.EXAMPLE_BLOCK,
new Item.Properties()
);

// 同时省略 name 和 properties 参数的变体:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
// 必须是 `Holder<Block>` 的实例
// `DeferredBlock<T>` 也可以
ExampleBlocksClass.EXAMPLE_BLOCK
);
note

如果你将已注册的方块(block)放在单独的类中,你应该在 items 类加载前先加载 blocks 类。

资源(Resources)​

如果你注册了自己的物品(item),并通过 /give 命令或 创造模式标签 获取该物品,你会发现它缺少正确的模型和贴图。这是因为贴图和模型是由 Minecraft 的资源系统管理的。

要为物品应用一个简单的贴图,你需要创建客户端物品(client item)、模型 JSON 文件和贴图 PNG 文件。更多信息请参考 客户端物品 章节。

ItemStack​

与方块(block)和方块状态(blockstate)类似,大多数你以为会用到 Item 的地方,实际上使用的是 ItemStack。ItemStack 表示一个容器(例如背包)中一组(一个或多个)物品。同样地,方法应由 Item 重写,并在 ItemStack 上调用,且 Item 中的许多方法都会接收一个 ItemStack 实例作为参数。

一个 ItemStack 包含三个主要部分:

  • 它所代表的 Item,可通过 ItemStack#getItem 获取,或通过 getItemHolder 获取 Holder<Item>。
  • 堆叠数量(stack size),通常在 1 到 64 之间,可通过 getCount 获取,并可通过 setCount 或 shrink 修改。
  • 数据组件(data components)映射,存储了堆叠中特有的数据。可通过 getComponents 获取。组件的值通常通过 has、get、set、update 和 remove 进行访问和修改。 要创建一个新的 ItemStack,可以调用 new ItemStack(Item),并传入其所依赖的物品(item)。默认情况下,这会创建一个数量为 1、没有 NBT 数据的物品堆叠(item stack);如果需要,也有接受数量和 NBT 数据的构造函数重载可用。

ItemStack 是可变对象(mutable object,见下文),但有时需要将其视为不可变对象(immutable)。如果你需要修改一个本应视为不可变的 ItemStack,可以使用 #copy 方法进行克隆,或者如果需要指定堆叠数量,则可使用 #copyWithCount。

如果你想表示某个堆叠没有物品,可以使用 ItemStack.EMPTY。如果你想检查一个 ItemStack 是否为空,可以调用 #isEmpty 方法。

ItemStack 的可变性(Mutability of ItemStacks`)​

ItemStack 是可变对象。这意味着,例如调用 #setCount 或任何数据组件映射(data component map)相关方法时,ItemStack 本身会被修改。原版(Vanilla)大量利用了 ItemStack 的可变性,并且有许多方法依赖于此。例如,#split 方法会从当前堆叠中拆分出指定数量,既修改了调用者本身,同时返回一个新的 ItemStack。

然而,在同时处理多个 ItemStack 时,这种可变性有时会导致问题。最常见的情况是在处理物品栏(inventory)槽位时,因为你需要同时考虑当前光标选中的 ItemStack,以及你尝试插入或提取的 ItemStack。

tip

如果不确定,宁可保险一点,使用 #copy 方法复制堆叠。

JSON 表示(JSON Representation)​

在许多场景下,例如 配方,物品堆叠需要以 JSON 对象的形式表示。一个物品堆叠的 JSON 表示如下:

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

创造模式标签页(Creative Tabs)​

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

将物品添加到创造模式菜单的方式,取决于你想将其加入哪个标签页(tab)。

已有的创造模式标签页(Existing Creative Tabs)​

note

本方法用于将你的物品添加到 Minecraft 原版标签页,或其他模组的标签页。如果你想添加到你自己的标签页,请见下文。

可以通过 BuildCreativeModeTabContentsEvent 事件将物品添加到已有的 CreativeModeTab 中。该事件会在 模组事件总线 上触发,并且只会在 逻辑客户端 触发。通过调用 event#accept 方法添加物品。

//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 获取已启用的功能标志(feature flags)列表,或者通过 hasPermissions 检查玩家是否有权限查看管理员物品标签页。

自定义创造模式标签页(Custom Creative Tabs)​

CreativeModeTab 是一种注册表(Registry),这意味着自定义的 CreativeModeTab 必须进行注册。创建一个创造模式标签页采用构建器(builder)模式,可以通过 CreativeModeTab#builder 获取构建器。该构建器允许你设置标签页标题、图标、默认物品以及其他多种属性。此外,NeoForge 还提供了额外的方法,用于自定义标签页的图片、标签和槽位颜色、排列顺序等。

//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 方法即可。

护甲
方块
方块状态
破坏方块
客户端物品模型
创造模式标签页
数据组件
数据生成
附魔
实体
食物
饥饿机制
交互
战利品表
事件总线
配方
注册方法
客户端/服务端区分
工具