物品
物品(Items)
与方块一样,物品是 Minecraft 的关键组成部分。方块构成了你周围的世界,而物品则存在于物品栏中。
什么是物品?
在进一步创建物品之前,了解什么是物品以及它与方块的区别非常重要。让我们通过一个例子来说明:
- 在世界中,你遇到一个泥土方块并想要挖掘它。这是一个方块,因为它被放置在世界中。(实际上,它是一个方块状态,而不是方块。更多详细信息请参阅方块状态文章。)
- 并非所有方块在破坏时都会掉落自身(例如树叶),更多信息请参阅战利品表文章。
- 一旦你挖掘了方块,它会被移除(即被替换为空气方块),并且泥土会掉落。掉落的泥土是一个物品实体。这意味着它像其他实体(猪、僵尸、箭等)一样,可以被水推动或被火和岩浆烧毁。
- 当你捡起泥土物品实体后,它会变成你物品栏中的一个物品堆叠。物品堆叠简单来说是一个物品实例,附带一些额外信息,例如堆叠数量。
- 物品堆叠由其对应的物品(即我们要创建的内容)支持。物品包含数据组件,这些组件存储了所有物品堆叠初始化的默认信息(例如,每把铁剑的最大耐久度为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>并提供了一些特定于物品的辅助方法:
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,可以完全省略工厂并使用简单的方法变体:
public static final Supplier<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem(
"example_item",
new Item.Properties() // 要使用的属性。
);这与前面的示例完全相同,但更简洁。当然,如果你想使用Item的子类而不是Item本身,则必须使用前面的方法。
这两种方法还有省略new Item.Properties()参数的重载:
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");最后,还有用于方块物品的快捷方式:
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由三个主要部分组成:
- 物品:它代表的物品,可通过
ItemStack#getItem获取。 - 堆叠数量:通常在1到64之间,可通过
getCount获取,并通过setCount或shrink更改。 - 数据组件映射:存储堆叠特定数据的地方。可通过
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 表示如下:
{
// 物品ID。必需。
"id": "minecraft:dirt",
// 物品堆叠数量。可选,默认为1。
"count": 4,
// 数据组件映射。可选,默认为空映射。
"components": {
"minecraft:enchantment_glint_override": true
}
}创造模式标签
默认情况下,你的物品只能通过/give获取,而不会出现在创造模式物品栏中。让我们改变这一点!
将物品添加到创造模式菜单的方式取决于你要将其添加到哪个标签。
现有的创造模式标签
注意:此方法用于将你的物品添加到 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以获取启用的特性标志列表,或hasPermissions以检查玩家是否有权限查看操作员物品标签。
自定义创造模式标签
CreativeModeTab是一个注册表,意味着自定义CreativeModeTab必须注册。创建创造模式标签使用构建器系统,构建器可通过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即可。