跳到主要内容

注册表参数

Minecraft 中的注册表保存了各种信息 - 可能的物品或方块类型、附魔、药水效果等等!

有两种类型的注册表参数:resource 和 resourceKey。 这两个参数的主要区别在于返回值:resource 参数返回解析后的值,而 resourceKey 只返回一个 TypedKey,你可以用它 来自己检索值。

Resource 参数​

就像任何其他参数一样,你可以使用 ArgumentTypes.resource(RegistryKey<T>) 获取对它的 ArgumentType<T> 引用。可以在下面找到可能的注册表键的选择。 它们通过使用 RegistryKey 接口在静态上下文中访问。

RegistryKey 中的每个条目都返回一个 RegistryKey<T>。这里的 <T> 泛型参数描述了返回类型。这意味着如果我们要检索 RegistryKey.ITEM,返回类型将是 ItemType,因为它的定义如下:

RegistryKey.java
public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
// ...
RegistryKey<ItemType> ITEM = RegistryKeyImpl.create("item");
// ...
}

实际上,就是这么简单。正是因为这个原因,这里有一个这样参数的实现示例:

public static LiteralCommandNode<CommandSourceStack> enchantmentRegistry() {
return Commands.literal("enchants-registry")
.then(Commands.argument("enchantment", ArgumentTypes.resource(RegistryKey.ENCHANTMENT))
.executes(ctx -> {
final Enchantment enchantment = ctx.getArgument("enchantment", Enchantment.class);

if (ctx.getSource().getExecutor() instanceof Player player) {
final ItemStack stack = player.getInventory().getItemInMainHand();
stack.addUnsafeEnchantment(enchantment, 10);
ctx.getSource().getSender().sendRichMessage("已为 <player> 的 <item> 添加 <enchantment>!",
Placeholder.component("player", player.name()),
Placeholder.component("item", Component.translatable(stack)),
Placeholder.component("enchantment", enchantment.displayName(10))
);
return Command.SINGLE_SUCCESS;
}

ctx.getSource().getSender().sendRichMessage("<red>此命令需要一个玩家!");
return Command.SINGLE_SUCCESS;
}))
.build();
}

我们使用附魔注册表键资源定义一个 enchantment 参数,并使用 ctx.getArgument("enchantment", Enchantment.class) 检索该值。 最后,我们用发送者选择的任何附魔为玩家手中的物品附魔,等级为 10,并发送一条成功消息。

它在游戏中的效果如下:

注意

在某些边缘情况下,由于客户端缺少注册表,此参数会导致网络协议错误。 基本上,目前唯一出现这种情况的参数是 STRUCTURE 注册表键。

// 注册此命令将导致客户端无法连接到服务器。
final LiteralCommandNode<CommandSourceStack> invalidRegistryArgument = Commands.literal("registry-structure")
.then(Commands.argument("value", ArgumentTypes.resource(RegistryKey.STRUCTURE)))
.build();

由于这个事实,建议只使用带有 resourceKey(...) 参数类型的 STRUCTURE 注册表键,并自己解析值。

Resource key 参数​

对于客户端来说,使用 ArgumentTypes.resource 或 ArgumentTypes.resourceKey 几乎没有区别。唯一的区别是 使用 ArgumentTypes.resourceKey 不提供错误检查。我们可以使用 RegistryKey.ITEM 来可视化这一点。

这是使用 ArgumentTypes.resource(RegistryKey.ITEM) 时的 tab 补全:


这是使用 ArgumentTypes.resourceKey(RegistryKey.ITEM) 时的 tab 补全:


备注

在上面给出的示例中,由于未处理的空指针异常,命令没有成功运行。该命令的代码直接尝试使用注册表访问检索的值 通过执行 ItemType item = RegistryAccess.registryAccess().getRegistry(itemKey.registryKey()).get(itemKey.key())。如果你尝试对结果进行任何 操作,它可能为空并出错。

你应该始终检查注册表检索操作的结果。下面的直接代码比较中给出了一个示例。

resource 参数提供了更好的用户体验,而 resourceKey 参数有一个非常重要的用例:你得到原始的 TypedKey<T> 作为参数结果返回。这个对象特别有用,因为它提供了从注册表中检索 值所需的所有信息。

提示

除非你有特定的理由使用 resourceKey 参数而不是 resource 参数,否则由于客户端错误检查和简单的可用性,推荐使用 resource 参数。

直接代码比较​

这是一个使用 RegistryKey.ITEM 注册表和 resource 参数类型的简单代码片段:

Commands.argument("item", ArgumentTypes.resource(RegistryKey.ITEM))
.executes(ctx -> {
final ItemType item = ctx.getArgument("item", ItemType.class);

if (ctx.getSource().getExecutor() instanceof Player player) {
player.getInventory().addItem(item.createItemStack());
}

return Command.SINGLE_SUCCESS;
});

这是相同的代码,使用 resourceKey 参数类型。我们不直接使用 ctx.getArgument("item", TypedKey.class) 检索参数,而是使用 RegistryArgumentExtractor 来检索我们的 TypedKey<ItemType>。

Commands.argument("item", ArgumentTypes.resourceKey(RegistryKey.ITEM))
.executes(ctx -> {
final TypedKey<ItemType> itemKey = RegistryArgumentExtractor.getTypedKey(ctx, RegistryKey.ITEM, "item");
ItemType item = RegistryAccess.registryAccess().getRegistry(itemKey.registryKey()).get(itemKey.key());

if (item == null) {
ctx.getSource().getSender().sendRichMessage("<red>请提供一个有效的物品!");
return Command.SINGLE_SUCCESS;
}

if (ctx.getSource().getExecutor() instanceof Player player) {
player.getInventory().addItem(item.createItemStack());
}

return Command.SINGLE_SUCCESS;
})

使用 TypedKey​

首先,为了获取正确的注册表,你可以运行 RegistryAccess#getRegistry(RegistryKey)。要获取 RegistryAccess,你可以直接使用静态的 RegistryAccess.registryAccess() 方法。RegistryKey 可以使用 TypedKey#registryKey() 检索。 现在,要获取最终的值 T,你可以运行 Registry#get(Key),其中的键可以使用 TypedKey#key() 检索。这将返回该资源键的后备实例 或 null(如果未找到值)。

相对于 resource 参数的用例​

此参数类型的主要用例是能够存储键(由 TypedKey#key 返回给你的值)。如果你想能够存储确切的用户 输入并且能够在不费太多力气的情况下检索后备实例,那就是这样做的方法。

注册表键预览​

在编写时,存在以下 RegistryKeys:

RegistryKeys 字段返回值预览视频
ATTRIBUTEAttributeAttribute
BANNER_PATTERNPatternTypeBanner Pattern
BIOMEBiomeBiome
BLOCKBlockTypeBlock
CAT_VARIANTCat.TypeCat Variant
DAMAGE_TYPEDamageTypeDamage Type
DATA_COMPONENT_TYPEDataComponentTypeData Component Type
ENCHANTMENTEnchantmentEnchantment
ENTITY_TYPEEntityTypeEntity Type
FLUIDFluidFluid
FROG_VARIANTFrog.VariantFrog Variant
GAME_EVENTGameEventGame Event
INSTRUMENTMusicInstrumentInstrument
ITEMItemTypeItem
JUKEBOX_SONGJukeboxSongJukebox Song
MAP_DECORATION_TYPEMapCursor.TypeMap Decoration Type
MEMORY_MODULE_TYPEMemoryKey<?>Memory Module Type
MENUMenuTypeMenu
MOB_EFFECTPotionEffectTypeMob effect
PAINTING_VARIANTArtPainting variant
PARTICLE_TYPEParticleParticle
POTIONPotionTypePotion
SOUND_EVENTSoundSound
STRUCTUREStructureStructure
STRUCTURE_TYPEStructureTypeStructure Type
TRIM_MATERIALTrimMaterialTrim Material
TRIM_PATTERNTrimPatternTrim Pattern
VILLAGER_PROFESSIONVillager.ProfessionVillager Profession
VILLAGER_TYPEVillager.TypeVillager Type
WOLF_VARIANTWolf.VariantWolf Variant

Attribute​

Biome​

Block​

Cat variant​

Damage type​

Enchantment​

Entity type​

Data component type​

Fluid​

Frog variant​

Game event​

Instrument​

Item​

Jukebox Song​

Map decoration type​

Memory module type​

Mob effect​

Painting variant​

Particle​

Potion​

Sound​

Structure​

这个参数会踢出客户端,所以没有预览 ¯\_(ツ)_/¯

Structure type​

Trim material​

Trim pattern​

Villager profession​

Villager type​

Wolf variant​