Registries
What is a registry?
Section titled “What is a registry?”In the context of Minecraft, a registry holds onto a set of values of the same type, identifying each by a key. An example of such a registry would be the ItemType registry which holds all known item types. Registries are available via the RegistryAccess class.
While a large portion of registries are defined by the server and client independently, more and more are defined by the server and sent to the client while joining the server. This enables the server, and to that extent plugins, to define custom content for both itself and clients playing on it. Notable examples include enchantments and biomes.
Retrieving values from a registry
Section titled “Retrieving values from a registry”To retrieve elements from a registry, their respective keys can be used. The API defines two types of keys.
net.kyori.adventure.key.Key
represents a namespace and a key.- TypedKey wraps an Adventure key, but also includes the key of the registry the TypedKey belongs to.
An example of retrieving the Sharpness
enchantment using
TypedKeys looks as follows:
// Fetch the enchantment registry from the registry accessfinal Registry<Enchantment> enchantmentRegistry = RegistryAccess .registryAccess() .getRegistry(RegistryKey.ENCHANTMENT);
// Get the sharpness enchantment using its key.// getOrThrow may be replaced with get if the registry may not contain said valuefinal Enchantment enchantment = enchantmentRegistry.getOrThrow(TypedKey.create( RegistryKey.ENCHANTMENT, Key.key("minecraft:sharpness")));
// Same as above, but using the instance's methodfinal Enchantment enchantment = enchantmentRegistry.getOrThrow( RegistryKey.ENCHANTMENT.typedKey(Key.key("minecraft:sharpness")));
// Same as above, but using generated create method// available for data-driven registries or "writable" ones// (those bound to a lifecycle event in RegistryEvents).final Enchantment enchantment = enchantmentRegistry.getOrThrow( EnchantmentKeys.create(Key.key("minecraft:sharpness")));
// Same as above too, but using generated typed keys.// Only Vanilla entries have generated keys, for custom entries, the above method must be used.final Enchantment enchantment = enchantmentRegistry.getOrThrow(EnchantmentKeys.SHARPNESS);
Referencing registry values
Section titled “Referencing registry values”Referencing entries in a registry is easier said then done. While for most cases a plain Collection of the values might suffice, alternative approaches are more often used by Minecraft and will hence be encountered.
A RegistrySet
defines a
collection of elements that relate to a registry.
Its most common subtype is the
RegistryKeySet
which
simply holds onto TypedKey instances.
An advantage of this data structure is its ability to remain valid even if the values of a
registry change.
A RegistryKeySet
can be
created via the factory methods on RegistrySet
like this:
// Create a new registry key set that holds a collection enchantmentsfinal RegistryKeySet<Enchantment> bestEnchantments = RegistrySet.keySet( RegistryKey.ENCHANTMENT, // Arbitrary keys of enchantments to store in the key set. EnchantmentKeys.CHANNELING, EnchantmentKeys.create(Key.key("papermc:softspoon")));
A Tag
follows up the concept
of a RegistryKeySet
but is itself named and can hence be referenced.
A list of Vanilla tags can be found on the Minecraft wiki.
Mutating registries
Section titled “Mutating registries”Beyond plain reading access to registries, Paper also offers a way for plugins to modify registries.
The general entrypoint for mutating registries is the RegistryEvents type, which provides an entry point for each registry that can be modified. Modification of a registry can take two different forms.
Create new entries
Section titled “Create new entries”Creating new entries is done via the freeze
lifecycle event
on the respective registries.
The freeze event is called right before a registry’s content is frozen in-place, meaning all Vanilla entries are registered.
Plugins can hence register their own entries at this point.
The following example shows how to create a new enchantment:
public class TestPluginBootstrap implements PluginBootstrap {
@Override public void bootstrap(BootstrapContext context) { // Register a new handler for the freeze lifecycle event on the enchantment registry context.getLifecycleManager().registerEventHandler(RegistryEvents.ENCHANTMENT.freeze().newHandler(event -> { event.registry().register( // The key of the registry // Plugins should use their own namespace instead of minecraft or papermc EnchantmentKeys.create(Key.key("papermc:pointy")), b -> b.description(Component.text("Pointy")) .supportedItems(event.getOrCreateTag(ItemTypeTagKeys.SWORDS)) .anvilCost(1) .maxLevel(25) .weight(10) .minimumCost(EnchantmentRegistryEntry.EnchantmentCost.of(1, 1)) .maximumCost(EnchantmentRegistryEntry.EnchantmentCost.of(3, 1)) .activeSlots(EquipmentSlotGroup.ANY) ); })); }}
Modifying existing entries
Section titled “Modifying existing entries”Modification of existing entries is useful for plugins that aim to change the way Vanilla entries
behave. For this, use the entryAdd
lifecycle event.
The event is called for *any* entry added to a registry, however the API provides an easy way to target a specific entry for modification.
The following example shows how to increase the maximum level of the Sharpness
enchantment.
@Overridepublic void bootstrap(BootstrapContext context) { context.getLifecycleManager().registerEventHandler(RegistryEvents.ENCHANTMENT.entryAdd() // Increase the max level to 20 .newHandler(event -> event.builder().maxLevel(20)) // Configure the handler to only be called for the Vanilla sharpness enchantment. .filter(EnchantmentKeys.SHARPNESS) );}