跳到主要内容
版本:1.21.4

物品(Items)

与方块一起,物品是Minecraft的关键组成部分。虽然方块构成了您周围的世界,但物品存在于物品栏中。

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

在我们进一步创建物品之前,重要的是要理解物品实际上是什么,以及它与方块(block)的区别。让我们用一个例子来说明:

  • 在世界中,您遇到一个泥土方块并想要挖掘它。这是一个方块(block),因为它被放置在世界中。(实际上,它不是方块,而是方块状态。有关更详细的信息,请参阅方块状态文章(Blockstates article)。)
  • 一旦您挖掘了方块,它被移除(=被空气方块替换)并且泥土掉落。掉落的泥土是一个物品**实体(entity)**。这意味着像其他实体(猪、僵尸、箭等)一样,它本质上可以被水推动或被火和熔岩燃烧。
  • 一旦您捡起泥土物品实体,它就成为您物品栏中的物品堆叠(item stack)。简单来说,物品堆叠是带有一些额外信息(如堆叠大小)的物品实例。
  • 物品堆叠由它们对应的物品(item)(这就是我们正在创建的)支持。物品保存数据组件(data components),其中包含所有物品堆叠初始化的默认信息(例如,每把铁剑的最大耐久度为250),而物品堆叠可以修改这些数据组件,允许同一物品的两个不同堆叠具有不同的信息(例如,一把铁剑剩余100次使用,而另一把铁剑剩余200次使用)。有关通过物品完成什么和通过物品堆叠完成什么的更多信息,请继续阅读。
    • 物品和物品堆叠之间的关系大致与方块(blocks)方块状态(blockstates)之间的关系相同,即方块状态总是由方块支持。这不是一个非常准确的比较(例如,物品堆叠不是单例),但它很好地基本概念。

创建物品(Creating an Item)

现在我们已经理解了物品是什么,让我们创建一个!

与基本方块一样,对于不需要特殊功能的基本物品(想想木棍、糖等),可以直接使用Item类。为此,在注册期间,使用Item.Properties参数实例化Item。此Item.Properties参数可以使用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)并将初始伤害设置为0(通过DataComponents#DAMAGE)。默认为0,表示"无耐久度"。例如,铁工具在此处使用250。请注意,设置耐久度会自动将最大堆叠大小锁定为1。
  • fireResistant - 使使用此物品的物品实体免疫火和熔岩(通过DataComponents#FIRE_RESISTANT)。各种下界合金物品使用此功能。
  • rarity - 设置此物品的稀有度(通过DataComponents#RARITY)。目前,这仅更改物品的颜色。Rarity是一个枚举,由四个值组成:COMMON(白色,默认)、UNCOMMON(黄色)、RARE(水色)和EPIC(浅紫色)。请注意,模组可能会添加更多稀有度类型。
  • setNoRepair - 禁用此物品的铁砧和合成网格修复。在原版中未使用。
  • jukeboxPlayable - 设置插入唱片机时播放的数据包JukeboxSong的资源键。
  • food - 设置此物品的FoodProperties(通过DataComponents#FOOD)。

有关示例,或查看Minecraft使用的各种值,请查看Items类。

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

物品可能具有在使用时应用或防止物品在一段时间内使用的附加属性:

  • craftRemainder - 设置此物品的合成剩余物。原版使用此功能处理合成后留下空桶的装满的桶。
  • usingConvertsTo - 设置通过Item#useIItemExtension#finishUsingItemItem#releaseUsing使用物品完成后返回的物品。ItemStack存储在DataComponents#USE_REMAINDER上。
  • useCooldown - 设置物品可以再次使用之前的秒数(通过DataComponents#USE_COOLDOWN)。

工具和盔甲(Tools and Armor)

一些物品像工具(tools)盔甲(armor)一样工作。这些通过一系列物品属性构建,只有一些使用委托给它们的关联类:

  • enchantable - 设置堆叠的最大附魔(enchantment)值,允许物品被附魔(通过DataComponents#ENCHANTABLE)。
  • repairable - 设置可用于修复此物品耐久度的物品或标签(通过DataComponents#REPAIRABLE)。必须具有耐久度组件且不是DataComponents#UNBREAKABLE
  • equippable - 设置物品可以装备到的槽位(通过DataComponents#EQUIPPABLE)。
  • equippableUnswappable - 与equippable相同,但禁用通过使用物品按钮(默认右键单击)的快速交换。

更多信息可以在它们相关的页面上找到。

更多功能(More Functionality)

直接使用Item只允许非常基本的物品。如果您想添加功能,例如右键单击交互,需要一个扩展Item的自定义类。Item类有许多可以重写以执行不同操作的方法;有关更多信息,请参阅类ItemIItemExtension

物品的两个最常见用例是左键单击和右键单击。由于它们的复杂性以及它们涉及其他系统,它们在单独的交互文章(Interaction article)中进行了解释。

DeferredRegister.Items

所有注册表都使用DeferredRegister来注册其内容,物品也不例外。然而,由于添加新物品是绝大多数模组的基本功能,NeoForge提供了DeferredRegister.Items辅助类,它扩展了DeferredRegister<Item>并提供了一些特定于物品的辅助功能:

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");

最后,还有方块物品的快捷方式。除了setId,这些还调用useBlockDescriptionPrefix将翻译键设置为用于方块的翻译键:

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

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

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

// 省略名称和属性的变体:
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(
// 必须是`Holder<Block>`的实例
// DeferredBlock<T>也可以工作
ExampleBlocksClass.EXAMPLE_BLOCK
);
备注

如果您将注册的方块保存在单独的类中,应在物品类之前类加载您的方块类。

资源(Resources)

如果您注册了您的物品并获取您的物品(通过/give或通过创造标签页(creative tab)),您会发现它缺少适当的模型和纹理。这是因为纹理和模型由Minecraft的资源系统处理。

对于每个物品,您将希望添加 - 或生成(generate) - 以下JSON文件:

对于以上所有内容,还请参考类似原版方块的文件和数据生成器。

ItemStacks

与方块和方块状态一样,大多数您期望使用Item的地方实际上使用ItemStackItemStack表示容器中的一个或多个物品的堆叠,例如物品栏。再次与方块和方块状态一样,方法应由Item重写并在ItemStack上调用,并且Item中的许多方法都传递了ItemStack实例。

ItemStack由三个主要部分组成:

  • 它代表的Item,可通过ItemStack#getItem获取,或getItemHolder用于Holder<Item>
  • 堆叠大小,通常在1到64之间,可通过getCount获取并通过setCountshrink更改。
  • 数据组件(data components)映射,其中存储堆叠特定数据。可通过getComponents获取。组件值通常通过hasgetsetupdateremove访问和修改。

要创建新的ItemStack,请调用new ItemStack(Item),传入支持物品。默认情况下,这使用计数1且无NBT数据;如果需要,也有接受计数和NBT数据的构造函数重载。

ItemStack是可变对象(见下文),但有时需要将它们视为不可变对象。如果您需要修改要视为不可变的ItemStack,可以使用#copy克隆堆叠,或者如果应使用特定堆叠大小,则使用#copyWithCount

如果要表示堆叠没有物品,请使用ItemStack.EMPTY。如果要检查ItemStack是否为空,请调用#isEmpty

ItemStack的可变性(Mutability of ItemStacks)

ItemStack是可变对象。这意味着如果您调用例如#setCount或任何数据组件映射方法,ItemStack本身将被修改。原版广泛使用ItemStack的可变性,并且几种方法依赖于此。例如,#split从调用它的堆叠中分割给定数量,既修改调用者又在此过程中返回新的ItemStack

然而,这有时在处理多个ItemStack时会导致问题。最常见的情况是在处理物品栏槽位时,因为您必须考虑光标当前选择的ItemStack以及您尝试插入/提取的ItemStack

提示

如有疑问,最好安全起见并#copy堆叠。

JSON表示(JSON Representation)

在许多情况下,例如配方(recipes),物品堆叠需要表示为JSON对象。物品堆叠的JSON表示如下所示:

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

创造标签页(Creative Tabs)

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

您将物品放入创造菜单的方式取决于您想要将其添加到哪个标签页。

现有创造标签页(Existing Creative Tabs)

备注

此方法用于将您的物品添加到Minecraft的标签页或其他模组的标签页。要将物品添加到您自己的标签页,请参见下文。

可以通过BuildCreativeModeTabContentsEvent将物品添加到现有的CreativeModeTab,该事件在模组事件总线(mod event bus)上触发,仅在逻辑客户端(logical client)上。通过调用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以检查玩家是否有权限查看操作员物品标签页。

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

CreativeModeTab是一个注册表,意味着自定义CreativeModeTab必须注册(registered)。创建创造标签页使用构建器系统,构建器可通过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是原版中由ItemBlocks实现的接口。它定义了方法#asItem,该方法返回对象实际是什么的物品表示:Item只返回自身,而Block返回其关联的BlockItem(如果可用),否则返回Blocks.AIRItemLike用于物品"来源"不重要的各种上下文,例如在许多数据生成器(data generators)中。

也可以在您的自定义对象上实现ItemLike。只需重写#asItem即可。