物品
物品与方块都是 Minecraft 的核心组成部分。方块构成周围的世界,物品则存在于物品栏中。
什么是物品
创建物品之前,需要先理解物品究竟是什么,以及它与方块等对象的区别。以下用泥土说明:
- 你在世界中遇到一个泥土方块并准备挖掘。它是方块,因为它放置在世界中。更准确地说,它是方块状态,详见方块状态。
- 并非所有方块被破坏后都会掉落自身,例如树叶。详情见战利品表。
- 挖掉方块后,它会被移除(替换为空气),并掉落泥土。掉落的泥土是一个物品**实体**,因此与猪、僵尸、箭等其他实体一样,可以被水推动,也会被火和熔岩烧毁。
- 捡起泥土物品实体后,它会成为物品栏中的物品堆叠。物品堆叠可以简单理解为带有额外信息的物品实例,例如堆叠数量。
- 物品堆叠以对应的物品为基础,这也是我们要创建的对象。物品持有数据组件,为所有堆叠提供初始化时的默认信息,例如铁剑的最大耐久度为 250。物品堆叠可以修改这些组件,因此同一种物品的不同堆叠可以具有不同信息,例如一把铁剑剩余 100 次使用次数,另一把剩余 200 次。下文会进一步说明物品与物品堆叠各自负责的内容。
创建物品
理解物品后,就可以创建它了。
与基础方块类似,不需要特殊功能的物品,例如木棍、糖等,可以直接使用 Item 类。注册时传入 Item.Properties 参数来实例化 Item。该参数可以用 Item.Properties#of 创建,再调用以下方法进行配置:
setId:设置物品的资源键。- 每个物品都必须设置,否则会抛出异常。
overrideDescription:设置物品的翻译键。创建的Component存储于DataComponents#ITEM_NAME。useBlockDescriptionPrefix:便捷方法,以block.<modid>.<registry_name>为翻译键调用overrideDescription。所有BlockItem都应调用它。requiredFeatures:设置物品所需的特性标志。主要用于原版在小版本中锁定特性的系统。除非与原版受特性标志限制的系统集成,否则不建议使用。stacksTo:通过DataComponents#MAX_STACK_SIZE设置最大堆叠数量,默认 64。例如末影珍珠等物品只能堆叠到 16。durability:通过DataComponents#MAX_DAMAGE设置耐久度,同时通过DataComponents#DAMAGE将初始损伤设为 0。默认值为 0,表示没有耐久度,例如铁制工具的值为 250。设置耐久度会自动将最大堆叠数量限制为 1。fireResistant:通过DataComponents#FIRE_RESISTANT让该物品对应的物品实体免疫火和熔岩伤害,用于各种下界合金物品。rarity:通过DataComponents#RARITY设置稀有度,目前只是改变物品名称颜色。Rarity枚举有COMMON(白色,默认)、UNCOMMON(黄色)、RARE(青色)和EPIC(淡紫色)四个值。Mod 可能添加更多稀有度类型。setNoCombineRepair:禁用砂轮及合成栏修复,原版未使用。jukeboxPlayable:设置物品放入唱片机后播放的数据包JukeboxSong的资源键。food:通过DataComponents#FOOD设置物品的FoodProperties。
若要查看示例或原版使用的具体数值,可查阅 Items 类。
剩余物与冷却
物品还可以设置使用时应用的属性,或在一段时间内阻止再次使用:
craftRemainder:设置合成剩余物,原版用于装满液体的桶,合成后留下空桶。usingConvertsTo:设置通过Item#use、IItemExtension#finishUsingItem或Item#releaseUsing完成使用后返回的物品,其ItemStack存储于DataComponents#USE_REMAINDER。useCooldown:通过DataComponents#USE_COOLDOWN设置再次使用前需要等待的秒数。
工具与盔甲
一些物品作为工具或盔甲使用。它们通过一系列物品属性构建,只有部分行为交由对应类处理:
enchantable:通过DataComponents#ENCHANTABLE设置堆叠的最大附魔值,使物品可以附魔。repairable:通过DataComponents#REPAIRABLE设置可用于修复耐久度的物品或标签。物品必须具有耐久度组件,且不能含DataComponents#UNBREAKABLE。equippable:通过DataComponents#EQUIPPABLE设置物品可装备的槽位。equippableUnswappable:与equippable相同,但禁用通过使用物品按钮(默认右键)快速替换装备。
更多信息见对应页面。
添加更多功能
直接使用 Item 只能创建很基础的物品。若要添加右键交互等功能,需要创建继承 Item 的自定义类。Item 提供了许多可重写的方法,详见 Item 和 IItemExtension。
物品最常见的两类操作是左键和右键。由于它们比较复杂,而且涉及其他系统,因此在独立的交互文档中说明。
DeferredRegister.Items
注册表都使用 DeferredRegister 注册内容,物品也不例外。由于添加物品是绝大多数 Mod 的核心功能,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, // The factory that the properties will be passed into.
props -> props // A unary operator of the properties to use.
);
它在内部把属性传给指定的物品工厂(通常是构造函数),实际相当于调用 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",
props -> props // A unary operator of the properties to use.
);
这与前一示例完全等价,只是更简短。如果使用的是 Item 的子类,则仍需使用前一个方法。
这两个方法也都有省略 new Item.Properties() 参数的重载:
public static final DeferredItem<Item> EXAMPLE_ITEM = ITEMS.registerItem("example_item", Item::new);
// Variant that also omits the Item::new parameter
public static final DeferredItem<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item");
最后还有方块物品的便捷方法。除 setId 外,它们还会调用 useBlockDescriptionPrefix,使翻译键与方块一致:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
"example_block",
ExampleBlocksClass.EXAMPLE_BLOCK,
props -> props
);
// Variant that omits the properties parameter:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
"example_block",
ExampleBlocksClass.EXAMPLE_BLOCK
);
// Variant that omits the name parameter, instead using the block's registry name:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
// Must be an instance of `Holder<Block>`
// DeferredBlock<T> also works
ExampleBlocksClass.EXAMPLE_BLOCK,
props -> props
);
// Variant that omits both the name and the properties:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
// Must be an instance of `Holder<Block>`
// DeferredBlock<T> also works
ExampleBlocksClass.EXAMPLE_BLOCK
);
提示 如果已注册的方块位于独立类中,应先加载方块类,再加载物品类。
资源
注册并通过 /give 或创造模式物品栏获得物品后,会发现它缺少正确的模型和纹理,因为模型和纹理由 Minecraft 的资源系统处理。
每个物品都应添加或生成以下 JSON 文件:
编写这些内容时,可以参考类似原版方块的文件和数据生成器。
ItemStack
与方块和方块状态类似,许多看似需要 Item 的地方实际上使用 ItemStack。它表示容器(例如物品栏)中一个或多个物品组成的堆叠。方法通常在 Item 中重写,通过 ItemStack 调用,且许多 Item 方法会收到一个 ItemStack 参数。
一个 ItemStack 主要由三部分组成:
- 对应的
Item,可通过ItemStack#getItem取得,也可通过getItemHolder取得Holder<Item>。 - 堆叠数量,通常在 1 到 64 之间,可通过
getCount读取,通过setCount或shrink修改。 - 存储堆叠专用数据的数据组件映射,可通过
getComponents读取,通常用has、get、set、update和remove访问或修改组件值。
调用 new ItemStack(Item) 并传入对应物品即可创建堆叠,默认数量为 1,且没有 NBT 数据;需要时也可使用接受数量和 NBT 数据的构造函数重载。注意,在组件绑定或世界存在之前,不能创建 ItemStack;此时应使用下文的 ItemStackTemplate。
ItemStack 是可变对象,但有时需要按不可变对象处理。若要修改这种堆叠,可先用 #copy 复制,或用 #copyWithCount 指定新数量并复制。
用 ItemStack.EMPTY 表示没有物品的堆叠,用 #isEmpty 检查堆叠是否为空。
ItemStack 的可变性
ItemStack 是可变对象。调用 #setCount 或数据组件映射的修改方法会直接改变该对象。原版大量利用这一点,某些方法也依赖这种行为。例如,#split 会从当前堆叠分离指定数量,既修改调用方,又返回新的 ItemStack。
同时处理多个 ItemStack 时,这有时会造成问题。常见情况是操作物品栏槽位:既要考虑鼠标光标选中的堆叠,也要考虑正在插入或取出的堆叠。
建议 不能确定时,先调用
#copy复制堆叠更稳妥。
ItemStackTemplate
ItemStackTemplate 是 ItemStack 的不可变形式,通常用于配方等不可变上下文。模板包含构成堆叠的基本元素:持有的 Item holder、数量,以及以补丁形式存储的数据组件。
通过 new ItemStackTemplate(...) 构造函数传入 Item 和其他所需元素即可创建模板;实际需要堆叠时,再调用 ItemStackTemplate#create 创建 ItemStack。
JSON 表示
在配方等场景中,需要把 ItemStackTemplate 表示为 JSON 对象,格式如下:
{
// The item ID. Required.
"id": "minecraft:dirt",
// The item stack count [1, 99]. Optional, defaults to 1.
"count": 4,
// A map of data components. Optional, defaults to an empty map.
"components": {
"minecraft:enchantment_glint_override": true
}
}
ItemInstance
ItemInstance 是 ItemStack 和 ItemStackTemplate 共同实现的父接口。堆叠和模板一般用于各自独立的上下文,但某些操作可以同时接受两者,例如读取物品数量。这时使用 ItemInstance,而不是某一种具体类型。
它提供检查物品的 #is、获取数量的 count,以及通过 DataComponentGetter 读取组件的方法。
创造模式物品栏标签页
默认情况下,物品只能通过 /give 获得,不会出现在创造模式物品栏中。
添加方式取决于目标标签页。
已有标签页
提示 此方法用于向 Minecraft 或其他 Mod 的标签页添加物品。添加到自己的标签页,见下文。
可通过 BuildCreativeModeTabContentsEvent 向已有 CreativeModeTab 添加物品。该事件在 Mod 事件总线上触发,且仅在逻辑客户端触发。调用 event#accept 添加物品。
//MyItemsClass.MY_ITEM is a Supplier<? extends Item>, MyBlocksClass.MY_BLOCK is a Supplier<? extends Block>
@SubscribeEvent // on the mod event bus
public static void buildContents(BuildCreativeModeTabContentsEvent event) {
// Is this the tab we want to add to?
if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
event.accept(MyItemsClass.MY_ITEM.get());
// Accepts an ItemLike. This assumes that MY_BLOCK has a corresponding item.
event.accept(MyBlocksClass.MY_BLOCK.get());
}
}
事件还提供额外信息,例如 getFlags 可读取启用的特性标志,hasPermissions 可检查玩家是否有权查看管理员物品标签页。
自定义标签页
CreativeModeTab 属于注册表对象,因此自定义标签页必须注册。通过 CreativeModeTab#builder 获取构建器,设置标题、图标、默认物品等属性。NeoForge 还提供了自定义图片、标签与槽位颜色、排序位置等方法。
//CREATIVE_MODE_TABS is a DeferredRegister<CreativeModeTab>
public static final Supplier<CreativeModeTab> EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example", () -> CreativeModeTab.builder()
//Set the title of the tab. Don't forget to add a translation!
.title(Component.translatable("itemGroup." + MOD_ID + ".example"))
//Set the icon of the tab.
.icon(() -> new ItemStack(MyItemsClass.EXAMPLE_ITEM.get()))
//Add your items to the tab.
.displayItems((params, output) -> {
output.accept(MyItemsClass.MY_ITEM.get());
// Accepts an ItemLike. This assumes that MY_BLOCK has a corresponding item.
output.accept(MyBlocksClass.MY_BLOCK.get());
})
.build()
);
ItemLike
原版的 Item 和 Block 都实现了 ItemLike 接口。该接口定义 #asItem 方法,用于返回对象对应的物品表示:Item 返回自身;Block 返回关联的 BlockItem,若不存在则返回 Blocks.AIR。当物品的“来源”并不重要时,通常会使用 ItemLike,例如许多数据生成器。
自定义对象也可以实现 ItemLike,只需重写 #asItem。
来源: NeoForged/Documentation(26.1)。中文翻译依据提交
4a680cdd4d15。