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#useIItemExtension#finishUsingItemItem#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 类有许多可被重写的方法,用于实现不同的行为;详细信息请参阅 ItemIItemExtension 这两个类。

物品最常见的两种用例是左键点击和右键点击。由于它们涉及的系统较为复杂,这部分内容会在单独的 交互(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 的地方,实际上使用的是 ItemStackItemStack 表示一个容器(例如背包)中一组(一个或多个)物品。同样地,方法应由 Item 重写,并在 ItemStack 上调用,且 Item 中的许多方法都会接收一个 ItemStack 实例作为参数。

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

  • 它所代表的 Item,可通过 ItemStack#getItem 获取,或通过 getItemHolder 获取 Holder<Item>
  • 堆叠数量(stack size),通常在 1 到 64 之间,可通过 getCount 获取,并可通过 setCountshrink 修改。
  • 数据组件(data components)映射,存储了堆叠中特有的数据。可通过 getComponents 获取。组件的值通常通过 hasgetsetupdateremove 进行访问和修改。 要创建一个新的 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 是一个接口,由原版中的 ItemBlock 实现。它定义了 #asItem 方法,该方法会返回当前对象对应的物品表示:Item 会直接返回自身,而 Block 会返回其关联的 BlockItem(如果有),否则返回 Blocks.AIR。在许多场景下,例如在很多数据生成器中,当物品的“来源”并不重要时,会使用 ItemLike

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

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