物品
物品(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
即可。