From 9548d25824273f9731b3befba0dc5ececd2f18fd Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Wed, 10 Jan 2024 17:40:34 -0800 Subject: [PATCH] add RegistryAccess for managing registries --- patches/api/0243-Add-PaperRegistry.patch | 92 -- ...gistryAccess-for-managing-registries.patch | 461 +++++++++ .../api/0244-Add-StructuresLocateEvent.patch | 12 +- patches/api/0278-Add-basic-Datapack-API.patch | 8 +- .../api/0338-More-PotionEffectType-API.patch | 8 +- patches/api/0345-Custom-Potion-Mixes.patch | 8 +- ...Folia-scheduler-and-owned-region-API.patch | 8 +- patches/api/0444-Improve-Registry.patch | 6 +- ...gistryAccess-for-managing-Registries.patch | 931 ++++++++++++++++++ .../0485-TODO-Registry-Modification-API.patch | 18 - .../0486-Add-StructuresLocateEvent.patch | 89 +- patches/server/0940-Improve-Registry.patch | 12 +- 12 files changed, 1473 insertions(+), 180 deletions(-) delete mode 100644 patches/api/0243-Add-PaperRegistry.patch create mode 100644 patches/api/0243-Add-RegistryAccess-for-managing-registries.patch create mode 100644 patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch delete mode 100644 patches/server/0485-TODO-Registry-Modification-API.patch diff --git a/patches/api/0243-Add-PaperRegistry.patch b/patches/api/0243-Add-PaperRegistry.patch deleted file mode 100644 index 8cc1e1b931..0000000000 --- a/patches/api/0243-Add-PaperRegistry.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Mar 2022 13:36:21 -0800 -Subject: [PATCH] Add PaperRegistry - - -diff --git a/src/main/java/io/papermc/paper/registry/Reference.java b/src/main/java/io/papermc/paper/registry/Reference.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d880810cbf05bc45051fe29515054211572e33b4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/Reference.java -@@ -0,0 +1,43 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents a reference to a server-backed registry value that may -+ * change. -+ * -+ * @param type of the value -+ */ -+public interface Reference extends Keyed { -+ -+ /** -+ * Gets the value from the registry with the key. -+ * -+ * @return the value -+ * @throws java.util.NoSuchElementException if there is no value with this key -+ */ -+ @NotNull T value(); -+ -+ /** -+ * Gets the value from the registry with the key. -+ * -+ * @return the value or null if it doesn't exist -+ */ -+ @Nullable T valueOrNull(); -+ -+ /** -+ * Creates a reference to a registered value. -+ * -+ * @param registry the registry the value is located in -+ * @param key the key to the value -+ * @param the type of the value -+ * @return a reference -+ */ -+ static @NotNull Reference create(@NotNull Registry registry, @NotNull NamespacedKey key) { -+ return new ReferenceImpl<>(registry, key); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/ReferenceImpl.java b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6083b5982 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java -@@ -0,0 +1,31 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.NoSuchElementException; -+ -+record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { -+ -+ @Override -+ public @NotNull T value() { -+ final T value = this.registry.get(this.key); -+ if (value == null) { -+ throw new NoSuchElementException("No such value with key " + this.key); -+ } -+ return value; -+ } -+ -+ @Override -+ public @Nullable T valueOrNull() { -+ return this.registry.get(this.key); -+ } -+ -+ @Override -+ public @NotNull NamespacedKey getKey() { -+ return this.key; -+ } -+} diff --git a/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch b/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch new file mode 100644 index 0000000000..dee50d07c0 --- /dev/null +++ b/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch @@ -0,0 +1,461 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Mar 2022 13:36:21 -0800 +Subject: [PATCH] Add RegistryAccess for managing registries + + +diff --git a/src/main/java/io/papermc/paper/registry/Reference.java b/src/main/java/io/papermc/paper/registry/Reference.java +new file mode 100644 +index 0000000000000000000000000000000000000000..92ec13c2bd515fedfd5057201ae4ba15c184bacd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/Reference.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Represents a reference to a server-backed registry value that may ++ * change. ++ * ++ * @param type of the value ++ */ ++@Deprecated(forRemoval = true, since = "1.20.4") ++public interface Reference extends Keyed { ++ ++ /** ++ * Gets the value from the registry with the key. ++ * ++ * @return the value ++ * @throws java.util.NoSuchElementException if there is no value with this key ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ @NotNull T value(); ++ ++ /** ++ * Gets the value from the registry with the key. ++ * ++ * @return the value or null if it doesn't exist ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ @Nullable T valueOrNull(); ++ ++ /** ++ * Creates a reference to a registered value. ++ * ++ * @param registry the registry the value is located in ++ * @param key the key to the value ++ * @param the type of the value ++ * @return a reference ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.4") ++ static @NotNull Reference create(@NotNull Registry registry, @NotNull NamespacedKey key) { ++ return new ReferenceImpl<>(registry, key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/ReferenceImpl.java b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6083b5982 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.NoSuchElementException; ++ ++record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { ++ ++ @Override ++ public @NotNull T value() { ++ final T value = this.registry.get(this.key); ++ if (value == null) { ++ throw new NoSuchElementException("No such value with key " + this.key); ++ } ++ return value; ++ } ++ ++ @Override ++ public @Nullable T valueOrNull() { ++ return this.registry.get(this.key); ++ } ++ ++ @Override ++ public @NotNull NamespacedKey getKey() { ++ return this.key; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccess.java b/src/main/java/io/papermc/paper/registry/RegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e3034bd90443f355201d72c2fc9a2960c98d2649 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccess.java +@@ -0,0 +1,45 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++@ApiStatus.NonExtendable ++@ApiStatus.Experimental ++public interface RegistryAccess { ++ ++ /** ++ * Get the {@link RegistryAccess} instance for the server. ++ * ++ * @return the RegistryAccess instance ++ */ ++ static @NotNull RegistryAccess registryAccess() { ++ return RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found")); ++ } ++ ++ /** ++ * Gets the registry based on the type. ++ * ++ * @param type the type ++ * @return the registry or null if none found ++ * @param the type ++ * @deprecated use {@link #getRegistry(RegistryKey)} with keys from {@link RegistryKey} ++ */ ++ @Deprecated(since = "1.20.4", forRemoval = true) ++ @Nullable Registry getRegistry(@NotNull Class type); ++ ++ /** ++ * Gets the registry with the specified key. ++ * ++ * @param registryKey the key ++ * @return the registry ++ * @param the type ++ * @throws java.util.NoSuchElementException if no registry with the key is found ++ * @throws IllegalArgumentException if the registry is not available yet ++ */ ++ // Future note: We should have no trouble removing this generic qualifier when ++ // registry types no longer have to be "keyed" as it shouldn't break ABI or API. ++ @NotNull Registry getRegistry(@NotNull RegistryKey registryKey); ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b89e19c070f97c9662f1e16309446494b30aa7c9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.registry; ++ ++import java.util.Optional; ++import java.util.ServiceLoader; ++ ++final class RegistryAccessHolder { ++ ++ static final Optional INSTANCE = ServiceLoader.load(RegistryAccess.class).findFirst(); ++ ++ private RegistryAccessHolder() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java +index c4b30b16ce4db754b958c493ad86d0863592c263..e376c95ac4db43a1c5233287f01b20b9c8b614bc 100644 +--- a/src/main/java/io/papermc/paper/registry/RegistryKey.java ++++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java +@@ -2,11 +2,16 @@ package io.papermc.paper.registry; + + import net.kyori.adventure.key.Keyed; + import org.bukkit.GameEvent; ++import org.bukkit.MusicInstrument; + import org.bukkit.block.Biome; ++import org.bukkit.damage.DamageType; ++import org.bukkit.enchantments.Enchantment; ++import org.bukkit.entity.Wolf; + import org.bukkit.generator.structure.Structure; + import org.bukkit.generator.structure.StructureType; + import org.bukkit.inventory.meta.trim.TrimMaterial; + import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.potion.PotionEffectType; + import org.jetbrains.annotations.ApiStatus; + + import static io.papermc.paper.registry.RegistryKeyImpl.create; +@@ -40,6 +45,19 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { + * @see io.papermc.paper.registry.keys.StructureTypeKeys + */ + RegistryKey STRUCTURE_TYPE = create("worldgen/structure_type"); ++ /** ++ * Built-in registry for instruments. ++ */ ++ RegistryKey INSTRUMENT = create("instrument"); ++ /** ++ * Built-in registry for enchantments. ++ */ ++ RegistryKey ENCHANTMENT = create("enchantment"); ++ /** ++ * Built-in registry for potion effect types (mob effects). ++ */ ++ RegistryKey MOB_EFFECT = create("mob_effect"); ++ + + /* ********************** * + * Data-driven Registries * +@@ -64,4 +82,12 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { + * @see io.papermc.paper.registry.keys.TrimPatternKeys + */ + RegistryKey TRIM_PATTERN = create("trim_pattern"); ++ /** ++ * Data-driven registry for damage types. ++ */ ++ RegistryKey DAMAGE_TYPE = create("damage_type"); ++ /** ++ * Data-driven registry for wolf variants ++ */ ++ RegistryKey WOLF_VARIANT = create("wolf_variant"); + } +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java +index 9ad300fa1668cb59bbd85ff8091591db69b8c9dc..791813220b2504214b1adecc69093cd600fb0f8c 100644 +--- a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java ++++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java +@@ -11,9 +11,14 @@ record RegistryKeyImpl(@NotNull Key key) implements RegistryKey { + static final Set> REGISTRY_KEYS = Sets.newIdentityHashSet(); + + static RegistryKey create(@Subst("some_key") final String key) { +- final RegistryKey registryKey = new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key)); ++ final RegistryKey registryKey = createInternal(key); + REGISTRY_KEYS.add(registryKey); + return registryKey; + } + ++ // creates the key without adding to the internal set of keys ++ static RegistryKey createInternal(@Subst("some_key") final String key) { ++ return new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key)); ++ } ++ + } +diff --git a/src/main/java/io/papermc/paper/registry/TypedKey.java b/src/main/java/io/papermc/paper/registry/TypedKey.java +index 271454cd1b92ada4301025b57348ea77da9116a1..6f5a062ba7ee7173468ecea3c1855a233bf3855e 100644 +--- a/src/main/java/io/papermc/paper/registry/TypedKey.java ++++ b/src/main/java/io/papermc/paper/registry/TypedKey.java +@@ -38,7 +38,7 @@ public sealed interface TypedKey extends Keyed permits TypedKeyImpl { + * @return a new key for the value key and registry key + */ + @ApiStatus.Experimental +- static @NotNull TypedKey create(final @NotNull RegistryKey registryKey, final @NotNull Key key) { ++ static @NotNull TypedKey create(final @NotNull RegistryKey registryKey, final @NotNull Key key) { + return new TypedKeyImpl<>(key, registryKey); + } + } +diff --git a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java +index 3c3fd73f7742bb8602e2f9164dd4c1208a412255..1a97b3359c4ece5c29131da7c3f208aaa8fab66e 100644 +--- a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java ++++ b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java +@@ -4,5 +4,5 @@ import net.kyori.adventure.key.Key; + import net.kyori.adventure.key.Keyed; + import org.jetbrains.annotations.NotNull; + +-record TypedKeyImpl(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { ++record TypedKeyImpl(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { + } +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index 732ed3724e784ad659cb4411dbd73b42a8330a2c..cbf660db860e73df21be426e63928f8aeec0ac90 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2398,8 +2398,11 @@ public final class Bukkit { + * @param tClass of the registry to get + * @param type of the registry + * @return the corresponding registry or null if not present ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} ++ * with keys from {@link io.papermc.paper.registry.RegistryKey} + */ + @Nullable ++ @Deprecated(since = "1.20.4") + public static Registry getRegistry(@NotNull Class tClass) { + return server.getRegistry(tClass); + } +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index a04d279561676e825905f5512c399d14a3d8f828..e2aea210de4f37f6ca1afe3e6fdbc790410539ac 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -129,7 +129,7 @@ public interface Registry extends Iterable { + * + * @see Enchantment + */ +- Registry ENCHANTMENT = Objects.requireNonNull(Bukkit.getRegistry(Enchantment.class), "No registry present for Enchantment. This is a bug."); ++ Registry ENCHANTMENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.ENCHANTMENT); // Paper + /** + * Server entity types. + * +@@ -141,7 +141,7 @@ public interface Registry extends Iterable { + * + * @see MusicInstrument + */ +- Registry INSTRUMENT = Objects.requireNonNull(Bukkit.getRegistry(MusicInstrument.class), "No registry present for MusicInstrument. This is a bug."); ++ Registry INSTRUMENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.INSTRUMENT); // Paper + /** + * Default server loot tables. + * +@@ -159,7 +159,7 @@ public interface Registry extends Iterable { + * + * @see PotionEffectType + */ +- Registry EFFECT = Objects.requireNonNull(Bukkit.getRegistry(PotionEffectType.class), "No registry present for PotionEffectType. This is a bug."); ++ Registry EFFECT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.MOB_EFFECT); // Paper + /** + * Server particles. + * +@@ -182,14 +182,16 @@ public interface Registry extends Iterable { + * Server structures. + * + * @see Structure ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#STRUCTURE} + */ +- Registry STRUCTURE = Bukkit.getRegistry(Structure.class); ++ @Deprecated(since = "1.20.4") // Paper ++ Registry STRUCTURE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Structure.class); // Paper + /** + * Server structure types. + * + * @see StructureType + */ +- Registry STRUCTURE_TYPE = Bukkit.getRegistry(StructureType.class); ++ Registry STRUCTURE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.STRUCTURE_TYPE); // Paper + /** + * Sound keys. + * +@@ -200,21 +202,25 @@ public interface Registry extends Iterable { + * Trim materials. + * + * @see TrimMaterial ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#TRIM_MATERIAL} + */ +- Registry TRIM_MATERIAL = Bukkit.getRegistry(TrimMaterial.class); ++ @Deprecated(since = "1.20.4") // Paper ++ Registry TRIM_MATERIAL = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(TrimMaterial.class); // Paper + /** + * Trim patterns. + * + * @see TrimPattern ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#TRIM_PATTERN} + */ +- Registry TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class); ++ @Deprecated(since = "1.20.4") ++ Registry TRIM_PATTERN = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(TrimPattern.class); // Paper + /** + * Damage types. + * + * @see DamageType + */ + @ApiStatus.Experimental +- Registry DAMAGE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(DamageType.class), "No registry present for DamageType. This is a bug."); ++ Registry DAMAGE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(DamageType.class); // Paper + /** + * Villager profession. + * +@@ -269,7 +275,7 @@ public interface Registry extends Iterable { + * + * @see Wolf.Variant + */ +- Registry WOLF_VARIANT = Objects.requireNonNull(Bukkit.getRegistry(Wolf.Variant.class), "No registry present for Wolf Variant. This is a bug."); ++ Registry WOLF_VARIANT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Wolf.Variant.class); // Paper + /** + * Map cursor types. + * +@@ -282,7 +288,7 @@ public interface Registry extends Iterable { + * + * @see GameEvent + */ +- Registry GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug."); ++ Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper + /** + * Get the object by its key. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 395f7910f535bfd33a5676b011ab62a53e30e140..84397dd36027fffcb3e7216c877be29c31da560f 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2046,8 +2046,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi + * @param tClass of the registry to get + * @param type of the registry + * @return the corresponding registry or null if not present ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} ++ * with keys from {@link io.papermc.paper.registry.RegistryKey} + */ + @Nullable ++ @Deprecated(since = "1.20.4") // Paper + Registry getRegistry(@NotNull Class tClass); + + /** +diff --git a/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java b/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5e99d7d84150664f16cbbd6f58eb3a316017fe5f +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class TestRegistryAccess implements RegistryAccess { ++ ++ @Override ++ @Deprecated(since = "1.20.4", forRemoval = true) ++ public @Nullable Registry getRegistry(final @NotNull Class type) { ++ throw new UnsupportedOperationException("Not supported"); ++ } ++ ++ @Override ++ public @NotNull Registry getRegistry(final @NotNull RegistryKey registryKey) { ++ throw new UnsupportedOperationException("Not supported"); ++ } ++} +diff --git a/src/test/java/org/bukkit/support/TestServer.java b/src/test/java/org/bukkit/support/TestServer.java +index b208150297a23c0b4acb79135416809718f5650e..f11c639f1dc3c5034678d80bde3127a2e81a4a93 100644 +--- a/src/test/java/org/bukkit/support/TestServer.java ++++ b/src/test/java/org/bukkit/support/TestServer.java +@@ -36,26 +36,11 @@ public final class TestServer { + + when(instance.getBukkitVersion()).thenReturn("BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion()); + +- Map, Registry> registers = new HashMap<>(); +- when(instance.getRegistry(any())).then(invocationOnMock -> registers.computeIfAbsent(invocationOnMock.getArgument(0), aClass -> new Registry() { +- private final Map cache = new HashMap<>(); +- +- @Override +- public Keyed get(NamespacedKey key) { +- return cache.computeIfAbsent(key, key2 -> mock(aClass, withSettings().stubOnly())); +- } +- +- @NotNull +- @Override +- public Stream stream() { +- throw new UnsupportedOperationException("Not supported"); +- } +- +- @Override +- public Iterator iterator() { +- throw new UnsupportedOperationException("Not supported"); +- } +- })); ++ // Paper start - RegistryAccess ++ when(instance.getRegistry(any())).then(invocationOnMock -> { ++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(((Class)invocationOnMock.getArgument(0))); ++ }); ++ // Paper end - RegistryAccess + + UnsafeValues unsafeValues = mock(withSettings().stubOnly()); + when(instance.getUnsafe()).thenReturn(unsafeValues); +diff --git a/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +new file mode 100644 +index 0000000000000000000000000000000000000000..f0a5e6d6b99aeef349fe465080ef2ff7b58617a6 +--- /dev/null ++++ b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.TestRegistryAccess diff --git a/patches/api/0244-Add-StructuresLocateEvent.patch b/patches/api/0244-Add-StructuresLocateEvent.patch index a07fa632f7..7f05fa3b18 100644 --- a/patches/api/0244-Add-StructuresLocateEvent.patch +++ b/patches/api/0244-Add-StructuresLocateEvent.patch @@ -513,24 +513,22 @@ index 0000000000000000000000000000000000000000..1e7b53f9bc13dcd5a0a4a40004591e4f + } +} diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index a04d279561676e825905f5512c399d14a3d8f828..ac8fe849dfd407bb2beeca16aeda3ebbe5c7a874 100644 +index e2aea210de4f37f6ca1afe3e6fdbc790410539ac..29f21ac76fc5226e03ef0a01985718a8a9b72460 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -283,6 +283,17 @@ public interface Registry extends Iterable { +@@ -289,6 +289,15 @@ public interface Registry extends Iterable { * @see GameEvent */ - Registry GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug."); -+ + Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper + // Paper start + /** + * Configured structures. + * @see io.papermc.paper.world.structure.ConfiguredStructure -+ * @deprecated use {@link #STRUCTURE} ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#STRUCTURE} + */ + @Deprecated(forRemoval = true) -+ Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); ++ Registry CONFIGURED_STRUCTURE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + // Paper end -+ /** * Get the object by its key. * diff --git a/patches/api/0278-Add-basic-Datapack-API.patch b/patches/api/0278-Add-basic-Datapack-API.patch index 6d8473b377..eef13380f6 100644 --- a/patches/api/0278-Add-basic-Datapack-API.patch +++ b/patches/api/0278-Add-basic-Datapack-API.patch @@ -70,7 +70,7 @@ index 0000000000000000000000000000000000000000..58f78d5e91beacaf710f62461cf869f7 + +} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index d078ea797cf4c6ab291aec3ad7fbd4740017286c..c3d3c7d05a03658157d49c6ff1ea1d7d085a6fd4 100644 +index 652932fa3ae5360802335803b4108b65019b6922..237bdd97203dbc80c010ae57735bc45e36c78fc5 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -330,9 +330,11 @@ public final class Bukkit { @@ -85,7 +85,7 @@ index d078ea797cf4c6ab291aec3ad7fbd4740017286c..c3d3c7d05a03658157d49c6ff1ea1d7d public static DataPackManager getDataPackManager() { return server.getDataPackManager(); } -@@ -2585,6 +2587,14 @@ public final class Bukkit { +@@ -2588,6 +2590,14 @@ public final class Bukkit { public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { return server.getMobGoals(); } @@ -101,7 +101,7 @@ index d078ea797cf4c6ab291aec3ad7fbd4740017286c..c3d3c7d05a03658157d49c6ff1ea1d7d @NotNull diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index e6598c36cfc98282f30a57105986a295f1c94676..61ee087ec4a75ee8b10e204b4cdd1bab5f066819 100644 +index d28b3ad2e9979127051e8062122572bc3d2cb0b5..d3631288ec03c5ca04221c20ecee745f7e9fa71a 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -266,9 +266,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi @@ -116,7 +116,7 @@ index e6598c36cfc98282f30a57105986a295f1c94676..61ee087ec4a75ee8b10e204b4cdd1bab public DataPackManager getDataPackManager(); /** -@@ -2251,5 +2253,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2254,5 +2256,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull com.destroystokyo.paper.entity.ai.MobGoals getMobGoals(); diff --git a/patches/api/0338-More-PotionEffectType-API.patch b/patches/api/0338-More-PotionEffectType-API.patch index a0419b1cc2..ec42b4c6e0 100644 --- a/patches/api/0338-More-PotionEffectType-API.patch +++ b/patches/api/0338-More-PotionEffectType-API.patch @@ -5,13 +5,13 @@ Subject: [PATCH] More PotionEffectType API diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index ac8fe849dfd407bb2beeca16aeda3ebbe5c7a874..76b1d08d9ae2c2cf5c6d88934929695d438b3284 100644 +index 29f21ac76fc5226e03ef0a01985718a8a9b72460..7fdce09618505fad9b6f4781ac81b1e373bc1114 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -292,6 +292,31 @@ public interface Registry extends Iterable { +@@ -297,6 +297,31 @@ public interface Registry extends Iterable { */ @Deprecated(forRemoval = true) - Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + Registry CONFIGURED_STRUCTURE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + + /** + * Potion effect types. @@ -38,8 +38,8 @@ index ac8fe849dfd407bb2beeca16aeda3ebbe5c7a874..76b1d08d9ae2c2cf5c6d88934929695d + } + }; // Paper end - /** + * Get the object by its key. diff --git a/src/main/java/org/bukkit/potion/PotionEffectType.java b/src/main/java/org/bukkit/potion/PotionEffectType.java index e045e6a74821f291938cc6af86e313c1f1c4626c..e77cf365cefafbeba09123187e70fd5274f10d53 100644 --- a/src/main/java/org/bukkit/potion/PotionEffectType.java diff --git a/patches/api/0345-Custom-Potion-Mixes.patch b/patches/api/0345-Custom-Potion-Mixes.patch index b6a28f8917..7987206bf8 100644 --- a/patches/api/0345-Custom-Potion-Mixes.patch +++ b/patches/api/0345-Custom-Potion-Mixes.patch @@ -155,10 +155,10 @@ index 0000000000000000000000000000000000000000..3ede1e8f7bf0436fdc5bf395c0f9eaf1 + } +} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index fb6a3b71cf3c304c5d0177747bc098e134b22d58..eb6d59bad1e4f0b394290d683f5dfed6ba6dd75b 100644 +index 1bbf2306fd6fdb3ead79fc770434541c2e054875..88223f062665c2c738e73a725d292b868e5372af 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2627,6 +2627,15 @@ public final class Bukkit { +@@ -2630,6 +2630,15 @@ public final class Bukkit { public static io.papermc.paper.datapack.DatapackManager getDatapackManager() { return server.getDatapackManager(); } @@ -175,10 +175,10 @@ index fb6a3b71cf3c304c5d0177747bc098e134b22d58..eb6d59bad1e4f0b394290d683f5dfed6 @NotNull diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 43b049b68a8af548cd05c67dafc23dabd07bab27..6da6c20b684eba64b85d67db2482b4a968749070 100644 +index 5b13d84b39a006f84c74008d3141b1a2ac954b7d..0c2906de839fe8211ed431df2e5e94740f04b94a 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -2287,5 +2287,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2290,5 +2290,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull io.papermc.paper.datapack.DatapackManager getDatapackManager(); diff --git a/patches/api/0409-Folia-scheduler-and-owned-region-API.patch b/patches/api/0409-Folia-scheduler-and-owned-region-API.patch index 05f2626953..0cb828dfbf 100644 --- a/patches/api/0409-Folia-scheduler-and-owned-region-API.patch +++ b/patches/api/0409-Folia-scheduler-and-owned-region-API.patch @@ -499,10 +499,10 @@ index 0000000000000000000000000000000000000000..a6b50c9d8af589cc4747e14d343d2045 + } +} diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index a2e5e917a7a0f6763f2ac13583dc28d9ea35ca64..e4f3f621c4c6d2653770c149db71587fc04e0991 100644 +index 00b855a22b5b838db46126ff5bd6797ffff97da2..6545c5879706f4e527e4f742cc553c6e852cd6f8 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2658,6 +2658,141 @@ public final class Bukkit { +@@ -2661,6 +2661,141 @@ public final class Bukkit { } // Paper end @@ -645,10 +645,10 @@ index a2e5e917a7a0f6763f2ac13583dc28d9ea35ca64..e4f3f621c4c6d2653770c149db71587f public static Server.Spigot spigot() { return server.spigot(); diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 708ea9556510b2e9de2f7f1c381572e3bde540d1..63cbc38217865be8f79890a0d8d6143461d344f3 100644 +index b3b82405440c236f035e49d0edf6fda12e2db4bb..fb31f2a668b2d6a1115123e34adea67ed4dbfd22 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -2316,4 +2316,119 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2319,4 +2319,119 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer(); // Paper end diff --git a/patches/api/0444-Improve-Registry.patch b/patches/api/0444-Improve-Registry.patch index 2124cf7153..858b177b9b 100644 --- a/patches/api/0444-Improve-Registry.patch +++ b/patches/api/0444-Improve-Registry.patch @@ -31,10 +31,10 @@ index 62d2b3f950860dee0898d77b0a29635c3f9a7e23..704dba92f9246ef398ed8d162ebee3cf @Override public @NotNull String translationKey() { diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index 76b1d08d9ae2c2cf5c6d88934929695d438b3284..542c0516e19b6177ff8007ca6f8955dc9082da95 100644 +index 7fdce09618505fad9b6f4781ac81b1e373bc1114..c63a2d5d21eb599939ec7ae5e57506ff746e4174 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -328,6 +328,49 @@ public interface Registry extends Iterable { +@@ -332,6 +332,49 @@ public interface Registry extends Iterable { @Nullable T get(@NotNull NamespacedKey key); @@ -84,7 +84,7 @@ index 76b1d08d9ae2c2cf5c6d88934929695d438b3284..542c0516e19b6177ff8007ca6f8955dc /** * Returns a new stream, which contains all registry items, which are registered to the registry. * -@@ -394,5 +437,12 @@ public interface Registry extends Iterable { +@@ -398,5 +441,12 @@ public interface Registry extends Iterable { public Iterator iterator() { return map.values().iterator(); } diff --git a/patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch b/patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch new file mode 100644 index 0000000000..989e6099ae --- /dev/null +++ b/patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch @@ -0,0 +1,931 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 27 Feb 2023 18:28:39 -0800 +Subject: [PATCH] Add RegistryAccess for managing Registries + +RegistryAccess is independant from CraftServer and +doesn't require one to be created allowing the +org.bukkit.Registry class to be loaded earlier. + +== AT == +public net.minecraft.server.RegistryLayer STATIC_ACCESS + +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5fc4c41ec2089d4f69861c5da17e0bef8a203401 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -0,0 +1,82 @@ ++package io.papermc.paper.registry; ++ ++import io.papermc.paper.registry.entry.RegistryEntry; ++import java.util.Collections; ++import java.util.IdentityHashMap; ++import java.util.List; ++import java.util.Map; ++import net.minecraft.core.Registry; ++import net.minecraft.core.registries.Registries; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.world.item.enchantment.Enchantment; ++import net.minecraft.world.level.levelgen.structure.Structure; ++import org.bukkit.GameEvent; ++import org.bukkit.Keyed; ++import org.bukkit.MusicInstrument; ++import org.bukkit.craftbukkit.CraftGameEvent; ++import org.bukkit.craftbukkit.CraftMusicInstrument; ++import org.bukkit.craftbukkit.damage.CraftDamageType; ++import org.bukkit.craftbukkit.enchantments.CraftEnchantment; ++import org.bukkit.craftbukkit.entity.CraftWolf; ++import org.bukkit.craftbukkit.generator.structure.CraftStructure; ++import org.bukkit.craftbukkit.generator.structure.CraftStructureType; ++import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; ++import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern; ++import org.bukkit.craftbukkit.potion.CraftPotionEffectType; ++import org.bukkit.damage.DamageType; ++import org.bukkit.entity.Wolf; ++import org.bukkit.generator.structure.StructureType; ++import org.bukkit.inventory.meta.trim.TrimMaterial; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.potion.PotionEffectType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import static io.papermc.paper.registry.entry.RegistryEntry.entry; ++ ++@DefaultQualifier(NonNull.class) ++public final class PaperRegistries { ++ ++ static final List> REGISTRY_ENTRIES; ++ private static final Map, RegistryEntry> BY_REGISTRY_KEY; ++ private static final Map, RegistryEntry> BY_RESOURCE_KEY; ++ static { ++ REGISTRY_ENTRIES = List.of( ++ // built-ins ++ entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new), ++ entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new), ++ entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new), ++ entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new), ++ entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new), ++ ++ // data-drivens ++ entry(Registries.STRUCTURE, RegistryKey.STRUCTURE, Structure.class, CraftStructure::new).delayed(), ++ entry(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL, TrimMaterial.class, CraftTrimMaterial::new).delayed(), ++ entry(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delayed(), ++ entry(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, DamageType.class, CraftDamageType::new).delayed(), ++ entry(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, Wolf.Variant.class, CraftWolf.CraftVariant::new).delayed() ++ ); ++ final Map, RegistryEntry> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); ++ final Map, RegistryEntry> byResourceKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); ++ for (final RegistryEntry entry : REGISTRY_ENTRIES) { ++ byRegistryKey.put(entry.apiKey(), entry); ++ byResourceKey.put(entry.mcKey(), entry); ++ } ++ BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey); ++ BY_RESOURCE_KEY = Collections.unmodifiableMap(byResourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static > @Nullable RegistryEntry getEntry(final ResourceKey> resourceKey) { ++ return (RegistryEntry) BY_RESOURCE_KEY.get(resourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static > @Nullable RegistryEntry getEntry(final RegistryKey registryKey) { ++ return (RegistryEntry) BY_REGISTRY_KEY.get(registryKey); ++ } ++ ++ private PaperRegistries() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9480dafb2de09ac883e997c41e8a16b77f5f7082 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +@@ -0,0 +1,119 @@ ++package io.papermc.paper.registry; ++ ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.legacy.DelayedRegistry; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import io.papermc.paper.registry.legacy.LegacyRegistryIdentifiers; ++import java.util.Collections; ++import java.util.IdentityHashMap; ++import java.util.Map; ++import java.util.Set; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.VisibleForTesting; ++ ++import static java.util.Objects.requireNonNull; ++ ++@DefaultQualifier(NonNull.class) ++public class PaperRegistryAccess implements RegistryAccess { ++ ++ // We store the API registries in a memoized supplier, so they can be created on-demand. ++ // These suppliers are added to this map right after the instance of nms.Registry is created before it is loaded. ++ // We want to do registration there, so we have access to the nms.Registry instance in order to wrap it in a CraftRegistry instance. ++ // The memoized Supplier is needed because we *can't* instantiate any CraftRegistry class until **all** the BuiltInRegistries have been added ++ // to this map because that would class-load org.bukkit.Registry which would query this map. ++ private final Map, RegistryHolder> registries = Collections.synchronizedMap(new IdentityHashMap<>()); ++ ++ public static PaperRegistryAccess instance() { ++ return (PaperRegistryAccess) RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found")); ++ } ++ ++ @VisibleForTesting ++ public Set> loadedRegistryKeys() { ++ return Collections.unmodifiableSet(this.registries.keySet()); ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated(forRemoval = true) ++ @Override ++ public @Nullable Registry getRegistry(final Class type) { ++ final RegistryKey registryKey; ++ final @Nullable RegistryEntry entry; ++ registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type"); ++ entry = PaperRegistries.getEntry(registryKey); ++ final @Nullable RegistryHolder registry = (RegistryHolder) this.registries.get(registryKey); ++ if (registry != null) { ++ // if the registry exists, return right away. Since this is the "legacy" method, we return DelayedRegistry ++ // for the non-builtin Registry instances stored as fields in Registry. ++ return registry.get(); ++ } else if (entry instanceof DelayedRegistryEntry) { ++ // if the registry doesn't exist and the entry is marked as "delayed", we create a registry holder that is empty ++ // which will later be filled with the actual registry. This is so the fields on org.bukkit.Registry can be populated with ++ // registries that don't exist at the time org.bukkit.Registry is statically initialized. ++ final RegistryHolder delayedHolder = new RegistryHolder.Delayed<>(); ++ this.registries.put(registryKey, delayedHolder); ++ return delayedHolder.get(); ++ } else { ++ // if the registry doesn't exist yet or doesn't have a delayed entry, just return null ++ return null; ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Override ++ public Registry getRegistry(final RegistryKey key) { ++ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(key); ++ if (registryHolder == null) { ++ throw new IllegalArgumentException(key + " is not a valid registry key or that registry is not available yet"); ++ } ++ // since this is the getRegistry method that uses the modern RegistryKey, we unwrap any DelayedRegistry instances ++ // that might be returned here. I don't think reference equality is required when doing getRegistry(RegistryKey.WOLF_VARIANT) == Registry.WOLF_VARIANT ++ return possiblyUnwrap(registryHolder.get()); ++ } ++ ++ private static Registry possiblyUnwrap(final Registry registry) { ++ if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry ++ return delayedRegistry.delegate(); ++ } ++ return registry; ++ } ++ ++ public void registerReloadableRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { ++ this.registerRegistry(resourceKey, registry, true); ++ } ++ ++ public void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { ++ this.registerRegistry(resourceKey, registry, false); ++ } ++ ++ @SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server. ++ private > void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry, final boolean replace) { ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(resourceKey); ++ if (entry == null) { // skip registries that don't have API entries ++ return; ++ } ++ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(entry.apiKey()); ++ if (registryHolder == null || replace) { ++ // if the holder doesn't exist yet, or is marked as "replaceable", put it in the map. ++ this.registries.put(entry.apiKey(), entry.createRegistryHolder(registry)); ++ } else { ++ if (registryHolder instanceof final RegistryHolder.Delayed delayedHolder && entry instanceof final DelayedRegistryEntry delayedEntry) { ++ // if the registry holder is delayed, and the entry is marked as "delayed", then load the holder with the CraftRegistry instance that wraps the actual nms Registry. ++ delayedHolder.loadFrom(delayedEntry, registry); ++ } else { ++ throw new IllegalArgumentException(resourceKey + " has already been created"); ++ } ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated ++ @VisibleForTesting ++ public static @Nullable RegistryKey byType(final Class type) { ++ return (RegistryKey) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryHolder.java b/src/main/java/io/papermc/paper/registry/RegistryHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f750325fa980d4c49b92573ac4650f2b53c26e7b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryHolder.java +@@ -0,0 +1,47 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.base.Suppliers; ++import io.papermc.paper.registry.legacy.DelayedRegistry; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import java.util.function.Supplier; ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class RegistryHolder> { ++ ++ private final @Nullable Supplier memoizedSupplier; ++ ++ public RegistryHolder(final Supplier supplier) { ++ this.memoizedSupplier = Suppliers.memoize(supplier::get); ++ } ++ ++ protected RegistryHolder() { ++ this.memoizedSupplier = null; ++ } ++ ++ public Registry get() { ++ Preconditions.checkState(this.memoizedSupplier != null, "Must provide a supplier or override this method!"); ++ return this.memoizedSupplier.get(); ++ } ++ ++ public static final class Delayed> extends RegistryHolder { ++ ++ private final DelayedRegistry delayedRegistry = new DelayedRegistry<>(); ++ ++ @Override ++ public Registry get() { ++ return this.delayedRegistry; ++ } ++ ++ void loadFrom(final DelayedRegistryEntry delayedEntry, final net.minecraft.core.Registry registry) { ++ final RegistryHolder delegateHolder = delayedEntry.delegate().createRegistryHolder(registry); ++ Preconditions.checkState(delegateHolder.memoizedSupplier != null, "delegateHolder must have a memoized supplier!"); ++ this.delayedRegistry.load(delegateHolder.memoizedSupplier); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6ce94c2399817a74771ade0bb82905763a8e9df2 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java +@@ -0,0 +1,38 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryKey; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.CraftRegistry; ++ ++public abstract class BaseRegistryEntry> implements RegistryEntry { // TODO remove Keyed ++ private final ResourceKey> minecraftRegistryKey; ++ private final RegistryKey apiRegistryKey; ++ private final Class classToPreload; ++ protected final BiFunction minecraftToBukkit; ++ ++ protected BaseRegistryEntry(final ResourceKey> minecraftRegistryKey, final RegistryKey apiRegistryKey, final Class classToPreload, final BiFunction minecraftToBukkit) { ++ this.minecraftRegistryKey = minecraftRegistryKey; ++ this.apiRegistryKey = apiRegistryKey; ++ this.classToPreload = classToPreload; ++ this.minecraftToBukkit = minecraftToBukkit; ++ } ++ ++ @Override ++ public final ResourceKey> mcKey() { ++ return this.minecraftRegistryKey; ++ } ++ ++ @Override ++ public final RegistryKey apiKey() { ++ return this.apiRegistryKey; ++ } ++ ++ @Override ++ public final Class toPreload() { ++ return this.classToPreload; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1639380c9db4249f9e49b23588720d5cec2d63fd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java +@@ -0,0 +1,34 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class CraftRegistryEntry extends BaseRegistryEntry> { // TODO remove Keyed ++ ++ protected CraftRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit ++ ) { ++ super(mcKey, apiKey, toPreload, minecraftToBukkit); ++ } ++ ++ @Override ++ public RegistryHolder> createRegistryHolder(final Registry nmsRegistry) { ++ return new RegistryHolder<>(() -> this.createApiRegistry(nmsRegistry)); ++ } ++ ++ private CraftRegistry createApiRegistry(final Registry nmsRegistry) { ++ return new CraftRegistry<>(this.toPreload(), nmsRegistry, this.minecraftToBukkit); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9cda87cd03a04998cb527a4be9d3950523646cd3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public interface RegistryEntry> extends RegistryEntryInfo { // TODO remove Keyed ++ ++ RegistryHolder createRegistryHolder(Registry nmsRegistry); ++ ++ /** ++ * This should only be used if the registry instance needs to exist early due to the need ++ * to populate a field in {@link org.bukkit.Registry}. Data-driven registries shouldn't exist ++ * as fields, but instead be obtained via {@link io.papermc.paper.registry.RegistryAccess#getRegistry(RegistryKey)} ++ */ ++ @Deprecated ++ default RegistryEntry delayed() { ++ return new DelayedRegistryEntry<>(this); ++ } ++ ++ static RegistryEntry> entry(final ResourceKey> minecraftRegistryKey, final RegistryKey apiRegistryKey, final Class classToPreload, final BiFunction minecraftToBukkit) { ++ return new CraftRegistryEntry<>(minecraftRegistryKey, apiRegistryKey, classToPreload, minecraftToBukkit); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..abb24093dc81c0ba8a761700be59d4c9a67f4b00 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.RegistryKey; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++ ++public interface RegistryEntryInfo { ++ ++ ResourceKey> mcKey(); ++ ++ RegistryKey apiKey(); ++ ++ Class toPreload(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/package-info.java b/src/main/java/io/papermc/paper/registry/entry/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e4c94d6860e0f5b643cde1ded20b5503c02a4866 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry.entry; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5562e8da5ebaef2a3add46e88d64358b7737b59e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java +@@ -0,0 +1,55 @@ ++package io.papermc.paper.registry.legacy; ++ ++import java.util.Iterator; ++import java.util.function.Supplier; ++import java.util.stream.Stream; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * This is to support the now-deprecated fields in {@link Registry} for ++ * data-driven registries. ++ */ ++public final class DelayedRegistry> implements Registry { ++ ++ private @MonotonicNonNull Supplier delegate; ++ ++ public void load(final Supplier registry) { ++ if (this.delegate != null) { ++ throw new IllegalStateException("Registry already loaded!"); ++ } ++ this.delegate = registry; ++ } ++ ++ public Registry delegate() { ++ if (this.delegate == null) { ++ throw new IllegalStateException("You are trying to access this registry too early!"); ++ } ++ return this.delegate.get(); ++ } ++ ++ @Override ++ public @Nullable T get(final NamespacedKey key) { ++ return this.delegate().get(key); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return this.delegate().iterator(); ++ } ++ ++ @Override ++ public Stream stream() { ++ return this.delegate().stream(); ++ } ++ ++ @Override ++ public NamespacedKey getKey(final T value) { ++ return this.delegate().getKey(value); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0ca04fac46b2ec6aa8481ad867264050bfda630c +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry.legacy; ++ ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++ ++public record DelayedRegistryEntry>(RegistryEntry delegate) implements RegistryEntry { ++ ++ @Override ++ public ResourceKey> mcKey() { ++ return this.delegate.mcKey(); ++ } ++ ++ @Override ++ public RegistryKey apiKey() { ++ return this.delegate.apiKey(); ++ } ++ ++ @Override ++ public Class toPreload() { ++ return this.delegate.toPreload(); ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return this.delegate.createRegistryHolder(nmsRegistry); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +new file mode 100644 +index 0000000000000000000000000000000000000000..18dab3d1a5c873cfef09a8eba69d1e6d228b62eb +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.registry.legacy; ++ ++import com.google.common.collect.ImmutableMap; ++import io.papermc.paper.registry.RegistryKey; ++import java.lang.reflect.Field; ++import java.lang.reflect.ParameterizedType; ++import java.util.Map; ++ ++@Deprecated ++public final class LegacyRegistryIdentifiers { ++ ++ public static final Map, RegistryKey> CLASS_TO_KEY_MAP; ++ ++ static { ++ final ImmutableMap.Builder, RegistryKey> builder = ImmutableMap.builder(); ++ try { ++ for (final Field field : RegistryKey.class.getFields()) { ++ if (field.getType() == RegistryKey.class) { ++ // get the legacy type from the RegistryKey generic parameter on the field ++ final Class legacyType = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; ++ builder.put(legacyType, (RegistryKey) field.get(null)); ++ } ++ } ++ } catch (final ReflectiveOperationException ex) { ++ throw new RuntimeException(ex); ++ } ++ CLASS_TO_KEY_MAP = builder.build(); ++ } ++ ++ private LegacyRegistryIdentifiers() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/package-info.java b/src/main/java/io/papermc/paper/registry/legacy/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4396982af55872fafbfeaf8161ad6f392726c773 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry.legacy; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +index b43af53960978ac04bccde08544a562841492791..8daee5a7935e3253834c4cbe81d5e8886f776dad 100644 +--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java ++++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +@@ -297,6 +297,7 @@ public class BuiltInRegistries { + ResourceKey> key, R registry, BuiltInRegistries.RegistryBootstrap initializer + ) { + Bootstrap.checkBootstrapCalled(() -> "registry " + key); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(registry.key(), registry); // Paper - initialize API registry + ResourceLocation resourceLocation = key.location(); + LOADERS.put(resourceLocation, () -> initializer.run(registry)); + WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN); // Paper - decompile fix +diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +index 1a40a600b8a9716ef26f3143f361a47b76ec2510..d59356df2d98de873fc5accc749f87fa3d685267 100644 +--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java ++++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +@@ -284,6 +284,7 @@ public class RegistryDataLoader { + public static record RegistryData(ResourceKey> key, Codec elementCodec) { + RegistryDataLoader.Loader create(Lifecycle lifecycle, Map, Exception> errors) { + WritableRegistry writableRegistry = new MappedRegistry<>(this.key, lifecycle); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(this.key, writableRegistry); // Paper - initialize API registry + return new RegistryDataLoader.Loader<>(this, writableRegistry, errors); + } + +diff --git a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +index cf08819dd7ef6db807053a52aaf66a7fdea18ab6..69682d7be64a2163d574de939f5146f5a7a642ef 100644 +--- a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java ++++ b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +@@ -60,6 +60,7 @@ public class ReloadableServerRegistries { + return CompletableFuture.supplyAsync( + () -> { + WritableRegistry writableRegistry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental()); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(type.registryKey(), writableRegistry); // Paper - register reloadable registry + Map map = new HashMap<>(); + SimpleJsonResourceReloadListener.scanDirectory(resourceManager, type.directory(), GSON, map); + map.forEach( +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index 4209a45af2bfe772f678b07b49070522de4195a8..e2fcbeb8635280fcd2aeedff9803386c9bcabb0c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -100,55 +100,15 @@ public class CraftRegistry implements Registry { + + ", this can happen if a plugin creates its own registry entry with out properly registering it."); + } + +- /** +- * Note: Newly added registries should also be added to RegistriesArgumentProvider in the test package +- * +- * @param bukkitClass the bukkit class of the registry +- * @param registryHolder the minecraft registry holder +- * @return the bukkit registry of the provided class +- */ +- public static Registry createRegistry(Class bukkitClass, RegistryAccess registryHolder) { +- if (bukkitClass == Enchantment.class) { +- return new CraftRegistry<>(Enchantment.class, registryHolder.registryOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new); +- } +- if (bukkitClass == GameEvent.class) { +- return new CraftRegistry<>(GameEvent.class, registryHolder.registryOrThrow(Registries.GAME_EVENT), CraftGameEvent::new); +- } +- if (bukkitClass == MusicInstrument.class) { +- return new CraftRegistry<>(MusicInstrument.class, registryHolder.registryOrThrow(Registries.INSTRUMENT), CraftMusicInstrument::new); +- } +- if (bukkitClass == PotionEffectType.class) { +- return new CraftRegistry<>(PotionEffectType.class, registryHolder.registryOrThrow(Registries.MOB_EFFECT), CraftPotionEffectType::new); +- } +- if (bukkitClass == Structure.class) { +- return new CraftRegistry<>(Structure.class, registryHolder.registryOrThrow(Registries.STRUCTURE), CraftStructure::new); +- } +- if (bukkitClass == StructureType.class) { +- return new CraftRegistry<>(StructureType.class, BuiltInRegistries.STRUCTURE_TYPE, CraftStructureType::new); +- } +- if (bukkitClass == TrimMaterial.class) { +- return new CraftRegistry<>(TrimMaterial.class, registryHolder.registryOrThrow(Registries.TRIM_MATERIAL), CraftTrimMaterial::new); +- } +- if (bukkitClass == TrimPattern.class) { +- return new CraftRegistry<>(TrimPattern.class, registryHolder.registryOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new); +- } +- if (bukkitClass == DamageType.class) { +- return new CraftRegistry<>(DamageType.class, registryHolder.registryOrThrow(Registries.DAMAGE_TYPE), CraftDamageType::new); +- } +- if (bukkitClass == Wolf.Variant.class) { +- return new CraftRegistry<>(Wolf.Variant.class, registryHolder.registryOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new); +- } +- +- return null; +- } ++ // Paper - move to PaperRegistries + +- private final Class bukkitClass; ++ private final Class bukkitClass; // Paper - relax preload class + private final Map cache = new HashMap<>(); + private final net.minecraft.core.Registry minecraftRegistry; + private final BiFunction minecraftToBukkit; + private boolean init; + +- public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit) { ++ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit) { // Paper - relax preload class + this.bukkitClass = bukkitClass; + this.minecraftRegistry = minecraftRegistry; + this.minecraftToBukkit = minecraftToBukkit; +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 1460060f2ff42ebaa7b2418b375ce661c73bd17f..2c89ba2b518618640064ebea22d3d9595407bad7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -283,7 +283,7 @@ public final class CraftServer implements Server { + protected final DedicatedServer console; + protected final DedicatedPlayerList playerList; + private final Map worlds = new LinkedHashMap(); +- private final Map, Registry> registries = new HashMap<>(); ++ // private final Map, Registry> registries = new HashMap<>(); // Paper - replace with RegistryAccess + private YamlConfiguration configuration; + private YamlConfiguration commandsConfiguration; + private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); +@@ -2693,7 +2693,7 @@ public final class CraftServer implements Server { + + @Override + public Registry getRegistry(Class aClass) { +- return (Registry) this.registries.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, this.console.registryAccess())); ++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(aClass); // Paper - replace with RegistryAccess + } + + @Deprecated +diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +new file mode 100644 +index 0000000000000000000000000000000000000000..8a083d45004f82fc9c51c219fb20f34624adb501 +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.PaperRegistryAccess +diff --git a/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b9d00e65639521eecd44bd2be3e012264c3785f5 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.GameEvent; ++import org.bukkit.MusicInstrument; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertSame; ++ ++@Deprecated ++class LegacyRegistryIdentifierTest extends AbstractTestingBase { ++ ++ @Test ++ void testSeveralConversions() { ++ assertSame(RegistryKey.GAME_EVENT, PaperRegistryAccess.byType(GameEvent.class)); ++ assertSame(RegistryKey.TRIM_PATTERN, PaperRegistryAccess.byType(TrimPattern.class)); ++ assertSame(RegistryKey.INSTRUMENT, PaperRegistryAccess.byType(MusicInstrument.class)); ++ } ++} +diff --git a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java +index 4adaafafb7140e983a4e90f0ff0deaaf0887a9a5..848ad252c06031d33e659f6116e911f966810442 100644 +--- a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java ++++ b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java +@@ -21,14 +21,17 @@ public class RegistryArgumentAddedTest extends AbstractTestingBase { + // Make sure every registry is created + Class.forName(Registry.class.getName()); + +- Set> loadedRegistries = new HashSet<>(DummyServer.registers.keySet()); +- Set> notFound = new HashSet<>(); ++ // Paper start ++ Set> loadedRegistries = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>()); ++ loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().loadedRegistryKeys()); ++ // Paper end ++ Set> notFound = new HashSet<>(); // Paper + + RegistriesArgumentProvider + .getData() + .map(Arguments::get) + .map(array -> array[0]) +- .map(clazz -> (Class) clazz) ++ .map(clazz -> (io.papermc.paper.registry.RegistryKey) clazz) // Paper + .forEach(clazz -> { + if (!loadedRegistries.remove(clazz)) { + notFound.add(clazz); +diff --git a/src/test/java/org/bukkit/registry/RegistryConversionTest.java b/src/test/java/org/bukkit/registry/RegistryConversionTest.java +index 8c6b7f9804cf56269cc5a1b5924db2d2bf556f88..782c2ce424fc124e18145615187dc1e9d33f80ae 100644 +--- a/src/test/java/org/bukkit/registry/RegistryConversionTest.java ++++ b/src/test/java/org/bukkit/registry/RegistryConversionTest.java +@@ -37,9 +37,9 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(1) + @RegistriesTest +- public void testHandleableImplementation(Class clazz) { ++ public void testHandleableImplementation(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + Set> notImplemented = new HashSet<>(); +- Registry registry = Bukkit.getRegistry(clazz); ++ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(type); // Paper + + for (Keyed item : registry) { + if (!(item instanceof Handleable)) { +@@ -59,7 +59,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(2) + @RegistriesTest +- public void testMinecraftToBukkitPresent(Class clazz, ResourceKey> registryKey, ++ public void testMinecraftToBukkitPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) { + Method method = null; + try { +@@ -107,7 +107,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(2) + @RegistriesTest +- public void testBukkitToMinecraftPresent(Class clazz, ResourceKey> registryKey, ++ public void testBukkitToMinecraftPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) { + Method method = null; + try { +@@ -153,9 +153,9 @@ public class RegistryConversionTest extends AbstractTestingBase { + """, minecraftClazz.getName(), clazz.getSimpleName()); + } + +- @Order(2) ++ @Order(3) + @RegistriesTest +- public void testMinecraftToBukkitNullValue(Class clazz) throws IllegalAccessException { ++ public void testMinecraftToBukkitNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper + this.checkValidMinecraftToBukkit(clazz); + + try { +@@ -174,7 +174,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(3) + @RegistriesTest +- public void testBukkitToMinecraftNullValue(Class clazz) throws IllegalAccessException { ++ public void testBukkitToMinecraftNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper + this.checkValidBukkitToMinecraft(clazz); + + try { +@@ -193,14 +193,14 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(3) + @RegistriesTest +- public void testMinecraftToBukkit(Class clazz) { ++ public void testMinecraftToBukkit(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + this.checkValidMinecraftToBukkit(clazz); + this.checkValidHandle(clazz); + + Map notMatching = new HashMap<>(); + Method method = RegistryConversionTest.MINECRAFT_TO_BUKKIT_METHODS.get(clazz); + +- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { ++ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper + Keyed bukkit = (Keyed) arguments[0]; + Object minecraft = arguments[1]; + +@@ -224,14 +224,14 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(3) + @RegistriesTest +- public void testBukkitToMinecraft(Class clazz) { ++ public void testBukkitToMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + this.checkValidBukkitToMinecraft(clazz); + this.checkValidHandle(clazz); + + Map notMatching = new HashMap<>(); + Method method = RegistryConversionTest.BUKKIT_TO_MINECRAFT_METHODS.get(clazz); + +- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { ++ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper + Keyed bukkit = (Keyed) arguments[0]; + Object minecraft = arguments[1]; + +@@ -259,7 +259,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + */ + @Order(3) + @RegistriesTest +- public void testMinecraftToBukkitNoValidMinecraft(Class clazz, ResourceKey> registryKey, ++ public void testMinecraftToBukkitNoValidMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) throws IllegalAccessException { + this.checkValidMinecraftToBukkit(clazz); + +diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java +index 7a4681155f740a98ecafa0b992eae1fb5524551f..bd56792fc674c4e3606a3179ebf5a84ef0a4e35c 100644 +--- a/src/test/java/org/bukkit/support/DummyServer.java ++++ b/src/test/java/org/bukkit/support/DummyServer.java +@@ -45,10 +45,7 @@ public final class DummyServer { + when(instance.getLootTable(any())).then(mock -> new CraftLootTable(mock.getArgument(0), + AbstractTestingBase.DATA_PACK.fullRegistries().getLootTable(ResourceKey.create(Registries.LOOT_TABLE, CraftNamespacedKey.toMinecraft(mock.getArgument(0)))))); + +- when(instance.getRegistry(any())).then((Answer>) mock -> { +- Class aClass = mock.getArgument(0); +- return registers.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, AbstractTestingBase.REGISTRY_CUSTOM)); +- }); ++ // Paper - RegistryAccess + + // Paper start - testing additions + final Thread currentThread = Thread.currentThread(); +diff --git a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +index 342ea2914b361f39708bf0d8a39385c62d340c30..69a6a8419947a0617405e8931193f88d0dc5c3c4 100644 +--- a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java ++++ b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +@@ -1,6 +1,7 @@ + package org.bukkit.support.provider; + + import com.google.common.collect.Lists; ++import io.papermc.paper.registry.RegistryKey; + import java.util.List; + import java.util.stream.Stream; + import net.minecraft.core.registries.Registries; +@@ -37,16 +38,17 @@ public class RegistriesArgumentProvider implements ArgumentsProvider { + + static { + // Order: Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class +- DATA.add(Arguments.of(Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class)); +- DATA.add(Arguments.of(GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class)); +- DATA.add(Arguments.of(MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class)); +- DATA.add(Arguments.of(PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class)); +- DATA.add(Arguments.of(Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class)); +- DATA.add(Arguments.of(StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class)); +- DATA.add(Arguments.of(TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.armortrim.TrimMaterial.class)); +- DATA.add(Arguments.of(TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.armortrim.TrimPattern.class)); +- DATA.add(Arguments.of(DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class)); +- DATA.add(Arguments.of(Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, WolfVariant.class)); ++ // Order: RegistryKey, Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class ++ DATA.add(Arguments.of(RegistryKey.ENCHANTMENT, Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class)); ++ DATA.add(Arguments.of(RegistryKey.GAME_EVENT, GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class)); ++ DATA.add(Arguments.of(RegistryKey.INSTRUMENT, MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class)); ++ DATA.add(Arguments.of(RegistryKey.MOB_EFFECT, PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class)); ++ DATA.add(Arguments.of(RegistryKey.STRUCTURE, Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class)); ++ DATA.add(Arguments.of(RegistryKey.STRUCTURE_TYPE, StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class)); ++ DATA.add(Arguments.of(RegistryKey.TRIM_MATERIAL, TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.armortrim.TrimMaterial.class)); ++ DATA.add(Arguments.of(RegistryKey.TRIM_PATTERN, TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.armortrim.TrimPattern.class)); ++ DATA.add(Arguments.of(RegistryKey.DAMAGE_TYPE, DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class)); ++ DATA.add(Arguments.of(RegistryKey.WOLF_VARIANT, Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, net.minecraft.world.entity.animal.WolfVariant.class)); + } + + @Override +diff --git a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java +index f2ceb5e67536dfa5de792dc64a7898fd2e8aa810..beb5fc9e721f5de54064c3d241df9ca9f4cd4f65 100644 +--- a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java ++++ b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java +@@ -22,11 +22,11 @@ public class RegistryArgumentProvider implements ArgumentsProvider, AnnotationCo + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { +- return RegistryArgumentProvider.getValues(this.registryType); ++ return RegistryArgumentProvider.getValues(io.papermc.paper.registry.PaperRegistryAccess.byType(this.registryType)); // Paper + } + +- public static Stream getValues(Class registryType) { +- Registry registry = Bukkit.getRegistry(registryType); ++ public static Stream getValues(io.papermc.paper.registry.RegistryKey registryType) { // Paper ++ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(registryType); // Paper + return registry.stream().map(keyed -> (Handleable) keyed) + .map(handleAble -> Arguments.of(handleAble, handleAble.getHandle())); + } diff --git a/patches/server/0485-TODO-Registry-Modification-API.patch b/patches/server/0485-TODO-Registry-Modification-API.patch deleted file mode 100644 index d624aad69b..0000000000 --- a/patches/server/0485-TODO-Registry-Modification-API.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 27 Feb 2023 18:28:39 -0800 -Subject: [PATCH] TODO Registry Modification API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 4209a45af2bfe772f678b07b49070522de4195a8..480313506bf41410de090c59e047323345ea78da 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -138,6 +138,7 @@ public class CraftRegistry implements Registry { - if (bukkitClass == Wolf.Variant.class) { - return new CraftRegistry<>(Wolf.Variant.class, registryHolder.registryOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new); - } -+ // TODO registry modification API - - return null; - } diff --git a/patches/server/0486-Add-StructuresLocateEvent.patch b/patches/server/0486-Add-StructuresLocateEvent.patch index 4e44861dd1..da94da4dad 100644 --- a/patches/server/0486-Add-StructuresLocateEvent.patch +++ b/patches/server/0486-Add-StructuresLocateEvent.patch @@ -5,12 +5,49 @@ Subject: [PATCH] Add StructuresLocateEvent Co-authored-by: Jake Potrebic +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +index d45e2855f137d8708139281e8598ed34cc07ddd2..3a2b7f6f2dad856bc1499472970ba8b579df2e33 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -38,6 +38,12 @@ import static io.papermc.paper.registry.entry.RegistryEntry.entry; + @DefaultQualifier(NonNull.class) + public final class PaperRegistries { + ++ @Deprecated(forRemoval = true) ++ @org.jetbrains.annotations.VisibleForTesting ++ public static final RegistryKey CONFIGURED_STRUCTURE_REGISTRY_KEY = RegistryKeyImpl.createInternal("worldgen/structure"); ++ @Deprecated(forRemoval = true) ++ static final RegistryEntry CONFIGURED_STRUCTURE_REGISTRY_ENTRY = entry(Registries.STRUCTURE, CONFIGURED_STRUCTURE_REGISTRY_KEY, io.papermc.paper.world.structure.ConfiguredStructure.class, io.papermc.paper.world.structure.PaperConfiguredStructure::minecraftToBukkit).delayed(); ++ + static final List> REGISTRY_ENTRIES; + private static final Map, RegistryEntry> BY_REGISTRY_KEY; + private static final Map, RegistryEntry> BY_RESOURCE_KEY; +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +index 958e37a80ea486f460f495a4a6f6a55aa5f1c7ee..0de4a2cf8527a0cbdc7de4c9bdba4230047a1252 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +@@ -43,8 +43,13 @@ public class PaperRegistryAccess implements RegistryAccess { + public @Nullable Registry getRegistry(final Class type) { + final RegistryKey registryKey; + final @Nullable RegistryEntry entry; +- registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type"); +- entry = PaperRegistries.getEntry(registryKey); ++ if (type == io.papermc.paper.world.structure.ConfiguredStructure.class) { // manually handle "duplicate" registries to avoid polluting maps in PaperRegistries ++ registryKey = (RegistryKey) PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_KEY; ++ entry = (RegistryEntry) PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_ENTRY; ++ } else { ++ registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type"); ++ entry = PaperRegistries.getEntry(registryKey); ++ } + final @Nullable RegistryHolder registry = (RegistryHolder) this.registries.get(registryKey); + if (registry != null) { + // if the registry exists, return right away. Since this is the "legacy" method, we return DelayedRegistry diff --git a/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java new file mode 100644 -index 0000000000000000000000000000000000000000..2667067fd13f61e0464ba88ae4e4a7078351d1a8 +index 0000000000000000000000000000000000000000..013d614a1cf1ab2b5a6ec190c2b4ba7753268731 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java -@@ -0,0 +1,35 @@ +@@ -0,0 +1,27 @@ +package io.papermc.paper.world.structure; + +import java.util.Objects; @@ -32,18 +69,10 @@ index 0000000000000000000000000000000000000000..2667067fd13f61e0464ba88ae4e4a707 + private PaperConfiguredStructure() { + } + -+ @Deprecated(forRemoval = true) -+ public static final class LegacyRegistry extends CraftRegistry { -+ -+ public LegacyRegistry(final Registry minecraftRegistry) { -+ super(ConfiguredStructure.class, minecraftRegistry, LegacyRegistry::minecraftToBukkit); -+ } -+ -+ private static @Nullable ConfiguredStructure minecraftToBukkit(NamespacedKey key, Structure nms) { -+ final ResourceLocation structureTypeLoc = Objects.requireNonNull(BuiltInRegistries.STRUCTURE_TYPE.getKey(nms.type()), "unexpected structure type " + nms.type()); -+ final @Nullable StructureType structureType = StructureType.getStructureTypes().get(structureTypeLoc.getPath()); -+ return structureType == null ? null : new ConfiguredStructure(key, structureType); -+ } ++ public static @Nullable ConfiguredStructure minecraftToBukkit(NamespacedKey key, Structure nms) { ++ final ResourceLocation structureTypeLoc = Objects.requireNonNull(BuiltInRegistries.STRUCTURE_TYPE.getKey(nms.type()), "unexpected structure type " + nms.type()); ++ final @Nullable StructureType structureType = StructureType.getStructureTypes().get(structureTypeLoc.getPath()); ++ return structureType == null ? null : new ConfiguredStructure(key, structureType); + } +} diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -75,22 +104,6 @@ index 7cdb59cd2f2ffe1195d21519ef97dae0e430285b..a8768f1925d5824ca985be1b53694ee2 ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState(); Map>> map = new Object2ObjectArrayMap(); Iterator iterator = structures.iterator(); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 480313506bf41410de090c59e047323345ea78da..c7d377dbb53cdc1f823a839e3a113136efc16349 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -139,6 +139,11 @@ public class CraftRegistry implements Registry { - return new CraftRegistry<>(Wolf.Variant.class, registryHolder.registryOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new); - } - // TODO registry modification API -+ // Paper start - remove this after a while along with all ConfiguredStructure stuff -+ if (bukkitClass == io.papermc.paper.world.structure.ConfiguredStructure.class) { -+ return new io.papermc.paper.world.structure.PaperConfiguredStructure.LegacyRegistry(registryHolder.registryOrThrow(Registries.STRUCTURE)); -+ } -+ // Paper end - - return null; - } diff --git a/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java b/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9178fe0d01b998ca1442bf2511f8fc00db9388ba @@ -194,26 +207,26 @@ index 0000000000000000000000000000000000000000..9178fe0d01b998ca1442bf2511f8fc00 + } +} diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java -index 4e4ea083063daf22f1bb785ef212958ea889c43b..1c4966520b6401e6571aa44d5934dfa280bc80e3 100644 +index 4e4ea083063daf22f1bb785ef212958ea889c43b..523b4b208e05c6b70014440200e3196cc84f36cc 100644 --- a/src/test/java/org/bukkit/registry/PerRegistryTest.java +++ b/src/test/java/org/bukkit/registry/PerRegistryTest.java @@ -36,6 +36,7 @@ public class PerRegistryTest extends AbstractTestingBase { if (!(object instanceof CraftRegistry registry)) { continue; } -+ if (object instanceof io.papermc.paper.world.structure.PaperConfiguredStructure.LegacyRegistry) continue; // Paper - skip ++ if (object == Registry.CONFIGURED_STRUCTURE) continue; // Paper - skip data.add(Arguments.of(registry)); } catch (ReflectiveOperationException e) { diff --git a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java -index 4adaafafb7140e983a4e90f0ff0deaaf0887a9a5..65cc33c45553e755371ec4313dd38bb61eb7d61c 100644 +index 848ad252c06031d33e659f6116e911f966810442..f538a209af064c1f1333d30f90bfc21523b2f4cd 100644 --- a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java +++ b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java -@@ -23,6 +23,7 @@ public class RegistryArgumentAddedTest extends AbstractTestingBase { - - Set> loadedRegistries = new HashSet<>(DummyServer.registers.keySet()); - Set> notFound = new HashSet<>(); -+ loadedRegistries.remove(io.papermc.paper.world.structure.ConfiguredStructure.class); // Paper - ignore +@@ -26,6 +26,7 @@ public class RegistryArgumentAddedTest extends AbstractTestingBase { + loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().loadedRegistryKeys()); + // Paper end + Set> notFound = new HashSet<>(); // Paper ++ loadedRegistries.remove(io.papermc.paper.registry.PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_KEY); // Paper - ignore RegistriesArgumentProvider .getData() diff --git a/patches/server/0940-Improve-Registry.patch b/patches/server/0940-Improve-Registry.patch index 0d7c6b94e6..2f8634794b 100644 --- a/patches/server/0940-Improve-Registry.patch +++ b/patches/server/0940-Improve-Registry.patch @@ -5,18 +5,18 @@ Subject: [PATCH] Improve Registry diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index c7d377dbb53cdc1f823a839e3a113136efc16349..73472890e30180dc3cb6aa1bd9c5815087334682 100644 +index e2fcbeb8635280fcd2aeedff9803386c9bcabb0c..a3a00778a8fdbc13f8adbf4e4fbc4f1303d22789 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -150,6 +150,7 @@ public class CraftRegistry implements Registry { +@@ -104,6 +104,7 @@ public class CraftRegistry implements Registry { - private final Class bukkitClass; + private final Class bukkitClass; // Paper - relax preload class private final Map cache = new HashMap<>(); + private final Map byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry private final net.minecraft.core.Registry minecraftRegistry; private final BiFunction minecraftToBukkit; private boolean init; -@@ -194,6 +195,7 @@ public class CraftRegistry implements Registry { +@@ -148,6 +149,7 @@ public class CraftRegistry implements Registry { } this.cache.put(namespacedKey, bukkit); @@ -24,7 +24,7 @@ index c7d377dbb53cdc1f823a839e3a113136efc16349..73472890e30180dc3cb6aa1bd9c58150 return bukkit; } -@@ -216,4 +218,11 @@ public class CraftRegistry implements Registry { +@@ -170,4 +172,11 @@ public class CraftRegistry implements Registry { return this.minecraftToBukkit.apply(namespacedKey, minecraft); } @@ -61,7 +61,7 @@ index 364f8d7a7106259401154d91b1b79869d014a469..f336bf98574e4fdeabc3b21062983439 } diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java -index 1c4966520b6401e6571aa44d5934dfa280bc80e3..010de6fbb75eb5d51639695d260f916072fdb22d 100644 +index 523b4b208e05c6b70014440200e3196cc84f36cc..12b93a6e091de47522d060fa0cd84fe41318c46a 100644 --- a/src/test/java/org/bukkit/registry/PerRegistryTest.java +++ b/src/test/java/org/bukkit/registry/PerRegistryTest.java @@ -49,19 +49,22 @@ public class PerRegistryTest extends AbstractTestingBase {