跳到主要内容

注册表参数

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

有两种类型的注册表参数:resourceresourceKey。 这两个参数的主要区别在于返回值: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.resourceArgumentTypes.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