Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Registry docs #423

Merged
merged 25 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
12c76e9
Registry docs
lynxplay Jun 17, 2024
3a4f74a
Fix build
lynxplay Jun 17, 2024
176d520
More comment
lynxplay Jun 17, 2024
f475232
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
bd9f5c3
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
c0da570
Add note about exceptions in bootstrap
lynxplay Jun 17, 2024
10de6a7
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
5ef8902
Vanilla
lynxplay Jun 17, 2024
a9a19e2
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
acaa65b
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
744bee0
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
c8b049e
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
4baa6cd
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
b2c5f52
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
f83727d
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
89346f1
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
b57f35d
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
492bae0
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
93bb85c
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
e50aea7
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
991d99c
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
c44dd5c
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
2f8ec94
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
6669c5c
Update docs/paper/dev/api/registries.mdx
lynxplay Jun 17, 2024
6480396
Javadoc Collection
lynxplay Jun 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/sidebar.paper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const paper: SidebarsConfig = {
"dev/api/plugin-messaging",
"dev/api/plugin-configs",
"dev/api/lifecycle",
"dev/api/registries",
"dev/api/recipes",
"dev/api/folia-support",
"dev/api/roadmap",
Expand Down
165 changes: 165 additions & 0 deletions docs/paper/dev/api/registries.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
slug: /dev/registries
description: A guide to registries and their modification on Paper.
---

# Registries

:::danger[Experimental]
The Registry API and anything that uses it is currently experimental and may change in the future.
:::

## 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 <Javadoc name={"org.bukkit.Registry#ITEM"}>ItemType registry</Javadoc> which holds all known item types.
Registries are available via the <Javadoc name={"io.papermc.paper.registry.RegistryAccess"}>RegistryAccess</Javadoc> 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

To retrieve elements from a registry, their respective keys can be used.
The API defines two types of keys.
<ol>
<li>
`net.kyori.adventure.key.Key` represents a namespace and a key.
</li>
<li>
<Javadoc name={"io.papermc.paper.registry.TypedKey"}>TypedKey</Javadoc> wraps an Adventure key,
but also includes the <Javadoc name={"io.papermc.paper.registry.TypedKey#registryKey()"}>key of
the registry</Javadoc> the
<Javadoc name={"io.papermc.paper.registry.TypedKey"}>TypedKey</Javadoc> belongs to.
</li>
</ol>
An example of retrieving the `Sharpness` enchantment using
<Javadoc name={"io.papermc.paper.registry.TypedKey"}>TypedKeys</Javadoc> looks as follows:

```java
// Fetch the enchantment registry from the registry access
final 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 value
final Enchantment enchantment = enchantmentRegistry.getOrThrow(TypedKey.create(
RegistryKey.ENCHANTMENT, Key.key("minecraft:sharpness"))
);

// Same as above, 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

Referencing entries in a registry is easier said then done.
While for most cases a plain <Javadoc project={"java"} name={"java.util.Collection"}>Collection</Javadoc> of the values might suffice, alternative approaches are
more often used by Minecraft and will hence be encountered.

A <Javadoc name={"io.papermc.paper.registry.set.RegistrySet"}>`RegistrySet`</Javadoc> defines a
collection of elements that *relate* to a registry.

Its most common subtype is the
<Javadoc name={"io.papermc.paper.registry.set.RegistryKeySet"}>`RegistryKeySet`</Javadoc> which
simply holds onto <Javadoc name={"io.papermc.paper.registry.TypedKey"}>TypedKey</Javadoc> instances.
An advantage of this data structure is its ability to remain valid even if the values of a
registry change.

A <Javadoc name={"io.papermc.paper.registry.set.RegistryKeySet"}>`RegistryKeySet`</Javadoc> can be
created via the factory methods on <Javadoc name={"io.papermc.paper.registry.set.RegistrySet"}>`RegistrySet`</Javadoc> like this:
```java
// Create a new registry key set that holds a collection enchantments
final RegistryKeySet<@NotNull Enchantment> bestEnchantments = RegistrySet.keySet(
RegistryKey.ENCHANTMENT,
// Arbitrary keys of enchantments to store in the key set.
EnchantmentKeys.CHANNELING,
TypedKey.create(RegistryKey.ENCHANTMENT, Key.key("papermc:softspoon"))
);
```

A <Javadoc name={"io.papermc.paper.registry.tag.Tag"}>`Tag`</Javadoc> follows up the concept
of a <Javadoc name={"io.papermc.paper.registry.set.RegistryKeySet"}>`RegistryKeySet`</Javadoc>
but is itself named and can hence be referenced.
A list of Vanilla tags can be found [on the Minecraft wiki](https://minecraft.wiki/w/Tag#Java_Edition_2).

## Mutating registries

Beyond plain reading access to registries, Paper also offers a way for plugins to modify registries.

:::warning
Mutating registries needs to be done during the server's bootstrap phase.
As such, this section is only applicable to [Paper plugins](../getting-started/paper-plugins.mdx).

**Exceptions** thrown by plugins during this phase will cause the server to shutdown before loading,
as missing values or modifications to the registries would otherwise cause data loss.
:::

:::note
Mutating registries is done via the
lynxplay marked this conversation as resolved.
Show resolved Hide resolved
<Javadoc
name={"io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager"}>LifecycleEventManager</Javadoc>.
See the [Lifecycle Events](./lifecycle.mdx) page for more information.
:::

The general entrypoint for mutating registries is
the <Javadoc name={"io.papermc.paper.registry.event.RegistryEvents"}>RegistryEvents</Javadoc> 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

Creating new entries is done via the <Javadoc name={"io.papermc.paper.registry.event.RegistryEventProvider#freeze()"}>`freeze` lifecycle event</Javadoc>
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:

```java
public class TestPluginBootstrap implements PluginBootstrap {

@Override
public void bootstrap(@NotNull BootstrapContext context) {
// Register a new handled 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
TypedKey.create(RegistryKey.ENCHANTMENT, Key.key("papermc:pointy")),
b -> b.description(Component.text("Pointy"))
.supportedItems(h.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

Modification of existing entries is useful for plugins that aim to change the way Vanilla entries
behave. For this, use the <Javadoc name={"io.papermc.paper.registry.event.RegistryEventProvider#entryAdd()"}>`entryAdd` lifecycle event</Javadoc>.
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.

```java
@Override
public void bootstrap(@NotNull BootstrapContext context) {
context.getLifecycleManager().registerEventHandler(RegistryEvents.ENCHANTMENT.entryAdd()
// Increase the max level to 20
.newHandler(event -> event.builder().maxLevel(20))
// Configure the handled to only be called for the Vanilla sharpness enchantment.
.filter(EnchantmentKeys.SHARPNESS)
);
}
```