Minecraft uses the registry system to handle almost everything in the game. When developing mods, you will need to register most content you add to the game. This helps with:
When registering any type of content, you pass in an Identifier
object, which speciied what things should be named for the game. Identifiers, often abbreviated as IDs, have a namespace and path. In most cases, the namespace is the ID of your mod (see terms), and the path is the name of the content you’re registering. The namespace and path cannot contain uppercases or characters in other languages. For example, the ID of vanilla dirt block has the ID of minecraft:dirt
.
Using custom content without registering it can lead to buggy behavior, such as missing textures, world save issues, and crashes. The game will usually let you know if you forget to register something.
When registering content, you need to specify which registry you are adding content to. The base game provides registries for all vanilla content, which can be found in Registries
(for 1.19.3 and above) or Registry
(for below 1.19.3).
Two examples of registries you may use include Registries.ITEM
(for 1.19.3 above)/Registry.ITEM
(for 1.19.2 below) for items and Registries.BLOCK
(for 1.19.3 above)/Registry.BLOCK
(for 1.19.2 below) for blocks.
For a deeper overview and description of all available registries, read the Registries
or Registry
class. A brief description for the registry types can be found in registry types page.
Use Registry.register
to register your contents into registries. Remember, each content can be registered no more than once. The basic syntax is:
Registry.register(registry, id, content);
For example:
Registry.register(Registries.ITEM, Identifier.of("tutorial", "example_item", EXAMPLE_ITEM));
Remember: registration should happen in mod initializers. Otherwise, you cannot register as they may have been frozen.
get
returns the content associated with an ID inside a registry. If the content doesn’t exist, SimpleDefaultedRegistry
returns the default registry value, and SimpleRegistry
returns null. You can use containsId
or getOrEmpty
method to test whether the id exists. For example:
Registries.ITEM.containsId(Identifier.ofVanilla("diamond")); // returns true Registries.ITEM.containsId(Identifier.ofVanilla("invalid_name")); // returns false Registries.ITEM.get(Identifier.ofVanilla("diamond")); // returns Items.DIAMOND Registries.ITEM.get(Identifier.ofVanilla("invalid_name")); // returns Items.AIR Registries.ITEM.getOrEmpty(Identifier.ofVanilla("diamond")); // returns Optional.of(Items.DIAMOND) Registries.ITEM.getOrEmpty(Identifier.ofVanilla("invalid_name")); // returns Optional.empty()
getId
returns the Identifier
associated with an entry inside a registry. If the entry doesn’t exist, SimpleDefaultedRegistry
returns the default registry ID, and SimpleRegistry
returns null. For example:
Registries.BLOCK.getId(Blocks.STONE); // returns Identifier.ofVanilla("stone"))
Some type of registries are not staticly stored in Registries
class. For example, you cannot find biome registries or loot table registries in Registries
class. But the registries do exist in Minecraft. That's because those registries are dynamic: they are loaded between different worlds as they are defined in data packs. In contrary, static registries, such as Registries.ITEM
and Registries.BLOCK
, are not defined in data packs yet, so they keep unchanged no matter which worlds you are in.
However, each registry has a registry key, which can be found in RegistryKeys
. You can get dynamic registries through registry keys with RegistryWrapper.WrapperLookup
objects (usually world.getRegistryManager()
when you have a World
object, or CommandRegistryAccess
when registering commands). See the example below, assume that you have a World
object:
final DynamicRegistryManager registryManager = world.getRegistryManager(); // both of the following two statements return the ''Biome'' object for desert in the world registryManager.get(RegistryKeys.BIOME).get(Identifier.ofVanilla("desert")); registryManager.getWrapperOrThrow(RegistryKeys.BIOME).getOrThrow(RegistryKey.of(RegistryKeys.BIOME, Identifier.ofVanilla("desert"))).value();
Not only registries have registry keys. All registry contents have registry keys (as registries themselves also belong to registry contents of Registries.REGISTRIES
). Registry contents may change between worlds, but registry keys always keep unchanged.
A registry entry (RegistryEntry
) is a wrapper of contents that belong to types that have registry. They have two types:
RegistryEntry.Reference
: things that are registered in the registry, and therefore have their IDs.RegistryEntry.Direct
: things not registered in the register. They may be anonymously specified in some ways.To explicitly show the differences between two, see the following two commands:
/loot give @s loot minecraft:blocks/stone
/loot give @s loot {pools:[{rolls:1, entries:[{type:"item", name:"minecraft:stone"}]}]}
Both the two commands give you a stone. The former one will get the loot table minecraft:blocks/stone
from the loot table registry of the world, so it is RegistryEntry.Reference
. The latter one will decode a loot table from a SNBT, which does not have an ID, so it is RegistryEntry.Direct
. Both the two type of registry entries can be fetched the actual content by calling value()
method.
Similar to registry entries, registry entry lists (RegistryEntryList
) are used in many cases and also have two types:
RegistryEntryList.Named
: The list defined by tags, which are defined in data packs.RegistryEntryList.Direct
: The list defirectly defined by listing all contents.