Registry Arguments
Registries in Minecraft hold all sort of information - possible item materials, block materials, enchantments, potion effects, ... and more! These arguments are particularly useful for retrieving type values.
There are two types of registry arguments: resource
and resourceKey
.
The main difference between those arguments is the return value: The resource
argument returns the parsed value, whilst the resourceKey
only returns a TypedKey
, which
you can use to retrieve the value yourself.
For more information on the resourceKey
argument, check out its dedicated segment.
Resource Argument
Just like any other argument, you can get a ArgumentType<T>
reference to it using ArgumentTypes.resource(RegistryKey<T>)
. A selection of possible registry keys can be
found below. They are accessed in a static context using the ResourceKeys
interface.
Each entry in the ResourceKeys
returns a RegistryKey<T>
. The <T>
generic parameter here describes the return type. This means that if we were to retrieve
RegistryKeys.ITEM
, since it is defined as follows:
public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
// ...
RegistryKey<ItemType> ITEM = RegistryKeyImpl.create("item");
// ...
}
The return type of the retrieved value using ctx.getArgument(...)
would be an ItemType
.
And really, there isn't much more to it. For that exact reason, here is an example on the implementation of such an argument:
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("Enchanted <player>'s <item> with <enchantment>!",
Placeholder.component("player", player.name()),
Placeholder.component("item", Component.translatable(stack.translationKey())),
Placeholder.component("enchantment", enchantment.displayName(10))
);
}
else {
ctx.getSource().getSender().sendRichMessage("<red>This command requires a player!");
}
return Command.SINGLE_SUCCESS;
}))
.build();
}
We define an enchantment
argument using a enchantment registry key resource and retrieve the value of that using ctx.getArgument("enchantment", Enchantment.class)
.
Finally, we enchant the item of the executing player's hand with whatever enchantment the sender chose at level 10 and send a success message.
Here is how it looks in-game:
There are certain edge-cases, where this argument will cause a Network Protocol Error on the client, due to missing registries on the client.
Basically, the only argument where this is the case right now is with the STRUCTURE
registry key.
// Registering this command will cause client to not be able to connect to the server.
final LiteralCommandNode<CommandSourceStack> invalidRegistryArgument = Commands.literal("registry-structure")
.then(Commands.argument("value", ArgumentTypes.resource(RegistryKey.STRUCTURE)))
.build();
Due to this fact, it is advised to only use the STRUCTURE
registry key argument with a resourceKey(...)
argument type and parse the values yourself.
More information on resource key arguments can be found by clicking here..
Resource Key Argument
For the client, there is barely any difference between the using ArgumentTypes.resource
or ArgumentTypes.resourceKey
. The only difference is that
using ArgumentTypes.resourceKey
does not provide error checking. We can visualize this using RegistryKey.ITEM
.
Here is the tab completion for when using ArgumentTypes.resource(RegistryKey.ITEM)
:
And here is the tab completion for when using ArgumenTypes.resourceKey(RegistryKey.ITEM)
:
The resource argument provides a much cleaner user experience, whilst the resourceKey argument has one very important usecase: You get the raw
TypedKey<T>
returned as an argument result. This object is particularly useful, as it provides all information required to be able to retrieve
a value from a registry yourself.
Unless you have a specific reason for using the resourceKey
argument over the resource
one, the resource
argument is preferred due to the error checking
and simple usability.
Direct code comparison
Here is a simple code snipped on how one could use the RegistryKey.ITEM
registry with a resource
argument type:
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;
});
Here is the same code, using a resourceKey
argument type:
Commands.argument("item", ArgumentTypes.resourceKey(RegistryKey.ITEM))
.executes(ctx -> {
final TypedKey<ItemType> itemKey = ctx.getArgument("value", TypedKey.class);
ItemType item = RegistryAccess.registryAccess().getRegistry(itemKey.registryKey()).get(itemKey.key());
if (item == null) {
ctx.getSource().getSender().sendRichMessage("<red>Please provide a valid item!");
return -1;
}
if (ctx.getSource().getExecutor() instanceof Player player) {
player.getInventory().addItem(item.createItemStack());
}
return Command.SINGLE_SUCCESS;
});
Using a TypedKey
First, in order to get the correct registry, you can run RegistryAccess#getregistry(RegistryKey)
. In order to get a RegistryAccess
, you can just use the static
RegistryAccess.registryAccess()
method. The RegistryKey
is retrieved using TypedKey#registryKey
.
Now, in order to get the final value T
, you can run Registry#get(Key)
, where the key can be retrieved using TypedKey#key
. This will return the backing instance
from that resource key or null, if no value has been found.
Usecase over resource argument
The main usecase for this argument type is the ability to store the key (the value returned to you by TypedKey#key
). If you want to be able to store the exact user
input and be able to retrieve the backed instance without much throuble, that is the way to do it.
Registry Key Previews
At the time of writing, the following RegistryKeys exist:
RegistryKeys Field | Return Value | Preview Video |
---|---|---|
ATTRIBUTE | Attribute | Attribute |
BANNER_PATTERN | PatternType | Pattern Type |
BIOME | Biome | Biome |
BLOCK | BlockType | Block Type |
CAT_VARIANT | Cat.Type | Cat Type |
DAMAGE_TYPE | DamageType | Damage Type |
DATA_COMPONENT_TYPE | DataComponentType | Data Component Type |
FLUID | Fluid | Fluid |
FROG_VARIANT | Frog.Variant | Frog Variant |
GAME_EVENT | GameEvent | Game Event |
INSTRUMENT | MusicInstrument | Music Instrument |
ITEM | ItemType | Item Type |
JUKEBOX_SONG | JukeboxSong | Jukebox Song |
MAP_DECORATION_TYPE | MapCursor.Type | Map Cursor Type |
MENU | MenuType | Menu Type |
MOB_EFFECT | PotionEffectType | Potion Effect Type |
PAINTING_VARIANT | Art | Art |
SOUND_EVENT | Sound | Sound |
STRUCTURE | Structure | Structure |
STRUCTURE_TYPE | StructureType | Structure Type |
VILLAGER_PROFESSION | Villager.Profession | Villager Profession |
VILLAGER_TYPE | Villager.Type | Villager Type |
WOLF_VARIANT | Wolf.Variant | Wolf Variant |
Attribute
Pattern Type
Biome
Block Type
Cat Type
Damage Type
Data Component Type
Fluid
Frog Variant
Game Event
Music Instrument
Item Type
Jukebox Song
Map Cursor Type
Menu Type
Potion Effect Type
Art
Sound
Structure
This argument kicks the client, so no preview for this one ¯\_(ツ)_/¯