aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJake Potrebic <[email protected]>2024-05-04 11:22:35 -0700
committerGitHub <[email protected]>2024-05-04 11:22:35 -0700
commit5632210f10e520ce70a647b2b2bd45efde4d039b (patch)
tree1581f21c73e1129dda4ac14d96c0e6dc2a460ab2
parent156675c773bf09679ed7b163b6c9b46f0ccb8070 (diff)
downloadPaper-5632210f10e520ce70a647b2b2bd45efde4d039b.tar.gz
Paper-5632210f10e520ce70a647b2b2bd45efde4d039b.zip
add RegistryAccess for managing registries (#10154)
* add RegistryAccess for managing registries * add missing types to key data generator * fix some stuff * Add RegistryKeys for all other non-server-backed registries * fix tests * remove Experimental annotations
-rw-r--r--paper-api-generator/generated/io/papermc/paper/registry/keys/DamageTypeKeys.java367
-rw-r--r--paper-api-generator/generated/io/papermc/paper/registry/keys/EnchantmentKeys.java336
-rw-r--r--paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java9
-rw-r--r--paper-api-generator/generated/io/papermc/paper/registry/keys/InstrumentKeys.java91
-rw-r--r--paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java321
-rw-r--r--paper-api-generator/generated/io/papermc/paper/registry/keys/WolfVariantKeys.java105
-rw-r--r--paper-api-generator/src/main/java/io/papermc/generator/Generators.java12
-rw-r--r--paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java20
-rw-r--r--patches/api/0004-Code-Generation.patch88
-rw-r--r--patches/api/0243-Add-PaperRegistry.patch92
-rw-r--r--patches/api/0243-Add-RegistryAccess-for-managing-registries.patch394
-rw-r--r--patches/api/0244-Add-StructuresLocateEvent.patch12
-rw-r--r--patches/api/0278-Add-basic-Datapack-API.patch8
-rw-r--r--patches/api/0338-More-PotionEffectType-API.patch8
-rw-r--r--patches/api/0345-Custom-Potion-Mixes.patch8
-rw-r--r--patches/api/0409-Folia-scheduler-and-owned-region-API.patch8
-rw-r--r--patches/api/0444-Improve-Registry.patch6
-rw-r--r--patches/server/0019-Paper-Plugins.patch13
-rw-r--r--patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch1026
-rw-r--r--patches/server/0485-TODO-Registry-Modification-API.patch18
-rw-r--r--patches/server/0486-Add-StructuresLocateEvent.patch89
-rw-r--r--patches/server/0940-Improve-Registry.patch12
-rw-r--r--patches/server/0989-Flat-bedrock-generator-settings.patch6
23 files changed, 2842 insertions, 207 deletions
diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/DamageTypeKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/DamageTypeKeys.java
new file mode 100644
index 0000000000..ed52d2393e
--- /dev/null
+++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/DamageTypeKeys.java
@@ -0,0 +1,367 @@
+package io.papermc.paper.registry.keys;
+
+import static net.kyori.adventure.key.Key.key;
+
+import io.papermc.paper.generated.GeneratedFrom;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import net.kyori.adventure.key.Key;
+import org.bukkit.MinecraftExperimental;
+import org.bukkit.damage.DamageType;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Vanilla keys for {@link RegistryKey#DAMAGE_TYPE}.
+ *
+ * @apiNote The fields provided here are a direct representation of
+ * what is available from the vanilla game source. They may be
+ * changed (including removals) on any Minecraft version
+ * bump, so cross-version compatibility is not provided on the
+ * same level as it is on most of the other API.
+ */
+@SuppressWarnings({
+ "unused",
+ "SpellCheckingInspection"
+})
+@GeneratedFrom("1.20.6")
+public final class DamageTypeKeys {
+ /**
+ * {@code minecraft:arrow}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> ARROW = create(key("arrow"));
+
+ /**
+ * {@code minecraft:bad_respawn_point}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> BAD_RESPAWN_POINT = create(key("bad_respawn_point"));
+
+ /**
+ * {@code minecraft:cactus}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> CACTUS = create(key("cactus"));
+
+ /**
+ * {@code minecraft:cramming}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> CRAMMING = create(key("cramming"));
+
+ /**
+ * {@code minecraft:dragon_breath}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> DRAGON_BREATH = create(key("dragon_breath"));
+
+ /**
+ * {@code minecraft:drown}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> DROWN = create(key("drown"));
+
+ /**
+ * {@code minecraft:dry_out}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> DRY_OUT = create(key("dry_out"));
+
+ /**
+ * {@code minecraft:explosion}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> EXPLOSION = create(key("explosion"));
+
+ /**
+ * {@code minecraft:fall}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FALL = create(key("fall"));
+
+ /**
+ * {@code minecraft:falling_anvil}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FALLING_ANVIL = create(key("falling_anvil"));
+
+ /**
+ * {@code minecraft:falling_block}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FALLING_BLOCK = create(key("falling_block"));
+
+ /**
+ * {@code minecraft:falling_stalactite}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FALLING_STALACTITE = create(key("falling_stalactite"));
+
+ /**
+ * {@code minecraft:fireball}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FIREBALL = create(key("fireball"));
+
+ /**
+ * {@code minecraft:fireworks}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FIREWORKS = create(key("fireworks"));
+
+ /**
+ * {@code minecraft:fly_into_wall}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FLY_INTO_WALL = create(key("fly_into_wall"));
+
+ /**
+ * {@code minecraft:freeze}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> FREEZE = create(key("freeze"));
+
+ /**
+ * {@code minecraft:generic}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> GENERIC = create(key("generic"));
+
+ /**
+ * {@code minecraft:generic_kill}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> GENERIC_KILL = create(key("generic_kill"));
+
+ /**
+ * {@code minecraft:hot_floor}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> HOT_FLOOR = create(key("hot_floor"));
+
+ /**
+ * {@code minecraft:in_fire}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> IN_FIRE = create(key("in_fire"));
+
+ /**
+ * {@code minecraft:in_wall}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> IN_WALL = create(key("in_wall"));
+
+ /**
+ * {@code minecraft:indirect_magic}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> INDIRECT_MAGIC = create(key("indirect_magic"));
+
+ /**
+ * {@code minecraft:lava}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> LAVA = create(key("lava"));
+
+ /**
+ * {@code minecraft:lightning_bolt}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> LIGHTNING_BOLT = create(key("lightning_bolt"));
+
+ /**
+ * {@code minecraft:magic}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> MAGIC = create(key("magic"));
+
+ /**
+ * {@code minecraft:mob_attack}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> MOB_ATTACK = create(key("mob_attack"));
+
+ /**
+ * {@code minecraft:mob_attack_no_aggro}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> MOB_ATTACK_NO_AGGRO = create(key("mob_attack_no_aggro"));
+
+ /**
+ * {@code minecraft:mob_projectile}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> MOB_PROJECTILE = create(key("mob_projectile"));
+
+ /**
+ * {@code minecraft:on_fire}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> ON_FIRE = create(key("on_fire"));
+
+ /**
+ * {@code minecraft:out_of_world}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> OUT_OF_WORLD = create(key("out_of_world"));
+
+ /**
+ * {@code minecraft:outside_border}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> OUTSIDE_BORDER = create(key("outside_border"));
+
+ /**
+ * {@code minecraft:player_attack}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> PLAYER_ATTACK = create(key("player_attack"));
+
+ /**
+ * {@code minecraft:player_explosion}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> PLAYER_EXPLOSION = create(key("player_explosion"));
+
+ /**
+ * {@code minecraft:sonic_boom}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> SONIC_BOOM = create(key("sonic_boom"));
+
+ /**
+ * {@code minecraft:spit}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> SPIT = create(key("spit"));
+
+ /**
+ * {@code minecraft:stalagmite}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> STALAGMITE = create(key("stalagmite"));
+
+ /**
+ * {@code minecraft:starve}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> STARVE = create(key("starve"));
+
+ /**
+ * {@code minecraft:sting}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> STING = create(key("sting"));
+
+ /**
+ * {@code minecraft:sweet_berry_bush}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> SWEET_BERRY_BUSH = create(key("sweet_berry_bush"));
+
+ /**
+ * {@code minecraft:thorns}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> THORNS = create(key("thorns"));
+
+ /**
+ * {@code minecraft:thrown}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> THROWN = create(key("thrown"));
+
+ /**
+ * {@code minecraft:trident}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> TRIDENT = create(key("trident"));
+
+ /**
+ * {@code minecraft:unattributed_fireball}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> UNATTRIBUTED_FIREBALL = create(key("unattributed_fireball"));
+
+ /**
+ * {@code minecraft:wind_charge}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<DamageType> WIND_CHARGE = create(key("wind_charge"));
+
+ /**
+ * {@code minecraft:wither}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> WITHER = create(key("wither"));
+
+ /**
+ * {@code minecraft:wither_skull}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<DamageType> WITHER_SKULL = create(key("wither_skull"));
+
+ private DamageTypeKeys() {
+ }
+
+ /**
+ * Creates a key for {@link DamageType} in a registry.
+ *
+ * @param key the value's key in the registry
+ * @return a new typed key
+ */
+ @ApiStatus.Experimental
+ public static @NotNull TypedKey<DamageType> create(final @NotNull Key key) {
+ return TypedKey.create(RegistryKey.DAMAGE_TYPE, key);
+ }
+}
diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/EnchantmentKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/EnchantmentKeys.java
new file mode 100644
index 0000000000..3c64bc0790
--- /dev/null
+++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/EnchantmentKeys.java
@@ -0,0 +1,336 @@
+package io.papermc.paper.registry.keys;
+
+import static net.kyori.adventure.key.Key.key;
+
+import io.papermc.paper.generated.GeneratedFrom;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import net.kyori.adventure.key.Key;
+import org.bukkit.MinecraftExperimental;
+import org.bukkit.enchantments.Enchantment;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Vanilla keys for {@link RegistryKey#ENCHANTMENT}.
+ *
+ * @apiNote The fields provided here are a direct representation of
+ * what is available from the vanilla game source. They may be
+ * changed (including removals) on any Minecraft version
+ * bump, so cross-version compatibility is not provided on the
+ * same level as it is on most of the other API.
+ */
+@SuppressWarnings({
+ "unused",
+ "SpellCheckingInspection"
+})
+@GeneratedFrom("1.20.6")
+public final class EnchantmentKeys {
+ /**
+ * {@code minecraft:aqua_affinity}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> AQUA_AFFINITY = create(key("aqua_affinity"));
+
+ /**
+ * {@code minecraft:bane_of_arthropods}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> BANE_OF_ARTHROPODS = create(key("bane_of_arthropods"));
+
+ /**
+ * {@code minecraft:binding_curse}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> BINDING_CURSE = create(key("binding_curse"));
+
+ /**
+ * {@code minecraft:blast_protection}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> BLAST_PROTECTION = create(key("blast_protection"));
+
+ /**
+ * {@code minecraft:breach}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<Enchantment> BREACH = create(key("breach"));
+
+ /**
+ * {@code minecraft:channeling}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> CHANNELING = create(key("channeling"));
+
+ /**
+ * {@code minecraft:density}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<Enchantment> DENSITY = create(key("density"));
+
+ /**
+ * {@code minecraft:depth_strider}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> DEPTH_STRIDER = create(key("depth_strider"));
+
+ /**
+ * {@code minecraft:efficiency}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> EFFICIENCY = create(key("efficiency"));
+
+ /**
+ * {@code minecraft:feather_falling}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> FEATHER_FALLING = create(key("feather_falling"));
+
+ /**
+ * {@code minecraft:fire_aspect}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> FIRE_ASPECT = create(key("fire_aspect"));
+
+ /**
+ * {@code minecraft:fire_protection}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> FIRE_PROTECTION = create(key("fire_protection"));
+
+ /**
+ * {@code minecraft:flame}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> FLAME = create(key("flame"));
+
+ /**
+ * {@code minecraft:fortune}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> FORTUNE = create(key("fortune"));
+
+ /**
+ * {@code minecraft:frost_walker}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> FROST_WALKER = create(key("frost_walker"));
+
+ /**
+ * {@code minecraft:impaling}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> IMPALING = create(key("impaling"));
+
+ /**
+ * {@code minecraft:infinity}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> INFINITY = create(key("infinity"));
+
+ /**
+ * {@code minecraft:knockback}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> KNOCKBACK = create(key("knockback"));
+
+ /**
+ * {@code minecraft:looting}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> LOOTING = create(key("looting"));
+
+ /**
+ * {@code minecraft:loyalty}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> LOYALTY = create(key("loyalty"));
+
+ /**
+ * {@code minecraft:luck_of_the_sea}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> LUCK_OF_THE_SEA = create(key("luck_of_the_sea"));
+
+ /**
+ * {@code minecraft:lure}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> LURE = create(key("lure"));
+
+ /**
+ * {@code minecraft:mending}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> MENDING = create(key("mending"));
+
+ /**
+ * {@code minecraft:multishot}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> MULTISHOT = create(key("multishot"));
+
+ /**
+ * {@code minecraft:piercing}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> PIERCING = create(key("piercing"));
+
+ /**
+ * {@code minecraft:power}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> POWER = create(key("power"));
+
+ /**
+ * {@code minecraft:projectile_protection}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> PROJECTILE_PROTECTION = create(key("projectile_protection"));
+
+ /**
+ * {@code minecraft:protection}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> PROTECTION = create(key("protection"));
+
+ /**
+ * {@code minecraft:punch}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> PUNCH = create(key("punch"));
+
+ /**
+ * {@code minecraft:quick_charge}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> QUICK_CHARGE = create(key("quick_charge"));
+
+ /**
+ * {@code minecraft:respiration}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> RESPIRATION = create(key("respiration"));
+
+ /**
+ * {@code minecraft:riptide}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> RIPTIDE = create(key("riptide"));
+
+ /**
+ * {@code minecraft:sharpness}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> SHARPNESS = create(key("sharpness"));
+
+ /**
+ * {@code minecraft:silk_touch}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> SILK_TOUCH = create(key("silk_touch"));
+
+ /**
+ * {@code minecraft:smite}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> SMITE = create(key("smite"));
+
+ /**
+ * {@code minecraft:soul_speed}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> SOUL_SPEED = create(key("soul_speed"));
+
+ /**
+ * {@code minecraft:sweeping_edge}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> SWEEPING_EDGE = create(key("sweeping_edge"));
+
+ /**
+ * {@code minecraft:swift_sneak}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> SWIFT_SNEAK = create(key("swift_sneak"));
+
+ /**
+ * {@code minecraft:thorns}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> THORNS = create(key("thorns"));
+
+ /**
+ * {@code minecraft:unbreaking}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> UNBREAKING = create(key("unbreaking"));
+
+ /**
+ * {@code minecraft:vanishing_curse}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Enchantment> VANISHING_CURSE = create(key("vanishing_curse"));
+
+ /**
+ * {@code minecraft:wind_burst}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<Enchantment> WIND_BURST = create(key("wind_burst"));
+
+ private EnchantmentKeys() {
+ }
+
+ private static @NotNull TypedKey<Enchantment> create(final @NotNull Key key) {
+ return TypedKey.create(RegistryKey.ENCHANTMENT, key);
+ }
+}
diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java
index f220c63b8a..6d228f2f02 100644
--- a/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java
+++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/GameEventKeys.java
@@ -449,14 +449,7 @@ public final class GameEventKeys {
private GameEventKeys() {
}
- /**
- * Creates a key for {@link GameEvent} in a registry.
- *
- * @param key the value's key in the registry
- * @return a new typed key
- */
- @ApiStatus.Experimental
- public static @NotNull TypedKey<GameEvent> create(final @NotNull Key key) {
+ private static @NotNull TypedKey<GameEvent> create(final @NotNull Key key) {
return TypedKey.create(RegistryKey.GAME_EVENT, key);
}
}
diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/InstrumentKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/InstrumentKeys.java
new file mode 100644
index 0000000000..0cddaa1936
--- /dev/null
+++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/InstrumentKeys.java
@@ -0,0 +1,91 @@
+package io.papermc.paper.registry.keys;
+
+import static net.kyori.adventure.key.Key.key;
+
+import io.papermc.paper.generated.GeneratedFrom;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import net.kyori.adventure.key.Key;
+import org.bukkit.MusicInstrument;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Vanilla keys for {@link RegistryKey#INSTRUMENT}.
+ *
+ * @apiNote The fields provided here are a direct representation of
+ * what is available from the vanilla game source. They may be
+ * changed (including removals) on any Minecraft version
+ * bump, so cross-version compatibility is not provided on the
+ * same level as it is on most of the other API.
+ */
+@SuppressWarnings({
+ "unused",
+ "SpellCheckingInspection"
+})
+@GeneratedFrom("1.20.6")
+public final class InstrumentKeys {
+ /**
+ * {@code minecraft:admire_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> ADMIRE_GOAT_HORN = create(key("admire_goat_horn"));
+
+ /**
+ * {@code minecraft:call_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> CALL_GOAT_HORN = create(key("call_goat_horn"));
+
+ /**
+ * {@code minecraft:dream_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> DREAM_GOAT_HORN = create(key("dream_goat_horn"));
+
+ /**
+ * {@code minecraft:feel_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> FEEL_GOAT_HORN = create(key("feel_goat_horn"));
+
+ /**
+ * {@code minecraft:ponder_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> PONDER_GOAT_HORN = create(key("ponder_goat_horn"));
+
+ /**
+ * {@code minecraft:seek_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> SEEK_GOAT_HORN = create(key("seek_goat_horn"));
+
+ /**
+ * {@code minecraft:sing_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> SING_GOAT_HORN = create(key("sing_goat_horn"));
+
+ /**
+ * {@code minecraft:yearn_goat_horn}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<MusicInstrument> YEARN_GOAT_HORN = create(key("yearn_goat_horn"));
+
+ private InstrumentKeys() {
+ }
+
+ private static @NotNull TypedKey<MusicInstrument> create(final @NotNull Key key) {
+ return TypedKey.create(RegistryKey.INSTRUMENT, key);
+ }
+}
diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java
new file mode 100644
index 0000000000..83835bd7ff
--- /dev/null
+++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java
@@ -0,0 +1,321 @@
+package io.papermc.paper.registry.keys;
+
+import static net.kyori.adventure.key.Key.key;
+
+import io.papermc.paper.generated.GeneratedFrom;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import net.kyori.adventure.key.Key;
+import org.bukkit.MinecraftExperimental;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Vanilla keys for {@link RegistryKey#MOB_EFFECT}.
+ *
+ * @apiNote The fields provided here are a direct representation of
+ * what is available from the vanilla game source. They may be
+ * changed (including removals) on any Minecraft version
+ * bump, so cross-version compatibility is not provided on the
+ * same level as it is on most of the other API.
+ */
+@SuppressWarnings({
+ "unused",
+ "SpellCheckingInspection"
+})
+@GeneratedFrom("1.20.6")
+public final class MobEffectKeys {
+ /**
+ * {@code minecraft:absorption}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> ABSORPTION = create(key("absorption"));
+
+ /**
+ * {@code minecraft:bad_omen}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> BAD_OMEN = create(key("bad_omen"));
+
+ /**
+ * {@code minecraft:blindness}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> BLINDNESS = create(key("blindness"));
+
+ /**
+ * {@code minecraft:conduit_power}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> CONDUIT_POWER = create(key("conduit_power"));
+
+ /**
+ * {@code minecraft:darkness}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> DARKNESS = create(key("darkness"));
+
+ /**
+ * {@code minecraft:dolphins_grace}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> DOLPHINS_GRACE = create(key("dolphins_grace"));
+
+ /**
+ * {@code minecraft:fire_resistance}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> FIRE_RESISTANCE = create(key("fire_resistance"));
+
+ /**
+ * {@code minecraft:glowing}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> GLOWING = create(key("glowing"));
+
+ /**
+ * {@code minecraft:haste}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> HASTE = create(key("haste"));
+
+ /**
+ * {@code minecraft:health_boost}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> HEALTH_BOOST = create(key("health_boost"));
+
+ /**
+ * {@code minecraft:hero_of_the_village}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> HERO_OF_THE_VILLAGE = create(key("hero_of_the_village"));
+
+ /**
+ * {@code minecraft:hunger}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> HUNGER = create(key("hunger"));
+
+ /**
+ * {@code minecraft:infested}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<PotionEffectType> INFESTED = create(key("infested"));
+
+ /**
+ * {@code minecraft:instant_damage}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> INSTANT_DAMAGE = create(key("instant_damage"));
+
+ /**
+ * {@code minecraft:instant_health}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> INSTANT_HEALTH = create(key("instant_health"));
+
+ /**
+ * {@code minecraft:invisibility}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> INVISIBILITY = create(key("invisibility"));
+
+ /**
+ * {@code minecraft:jump_boost}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> JUMP_BOOST = create(key("jump_boost"));
+
+ /**
+ * {@code minecraft:levitation}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> LEVITATION = create(key("levitation"));
+
+ /**
+ * {@code minecraft:luck}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> LUCK = create(key("luck"));
+
+ /**
+ * {@code minecraft:mining_fatigue}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> MINING_FATIGUE = create(key("mining_fatigue"));
+
+ /**
+ * {@code minecraft:nausea}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> NAUSEA = create(key("nausea"));
+
+ /**
+ * {@code minecraft:night_vision}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> NIGHT_VISION = create(key("night_vision"));
+
+ /**
+ * {@code minecraft:oozing}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<PotionEffectType> OOZING = create(key("oozing"));
+
+ /**
+ * {@code minecraft:poison}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> POISON = create(key("poison"));
+
+ /**
+ * {@code minecraft:raid_omen}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<PotionEffectType> RAID_OMEN = create(key("raid_omen"));
+
+ /**
+ * {@code minecraft:regeneration}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> REGENERATION = create(key("regeneration"));
+
+ /**
+ * {@code minecraft:resistance}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> RESISTANCE = create(key("resistance"));
+
+ /**
+ * {@code minecraft:saturation}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> SATURATION = create(key("saturation"));
+
+ /**
+ * {@code minecraft:slow_falling}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> SLOW_FALLING = create(key("slow_falling"));
+
+ /**
+ * {@code minecraft:slowness}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> SLOWNESS = create(key("slowness"));
+
+ /**
+ * {@code minecraft:speed}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> SPEED = create(key("speed"));
+
+ /**
+ * {@code minecraft:strength}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> STRENGTH = create(key("strength"));
+
+ /**
+ * {@code minecraft:trial_omen}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<PotionEffectType> TRIAL_OMEN = create(key("trial_omen"));
+
+ /**
+ * {@code minecraft:unluck}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> UNLUCK = create(key("unluck"));
+
+ /**
+ * {@code minecraft:water_breathing}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> WATER_BREATHING = create(key("water_breathing"));
+
+ /**
+ * {@code minecraft:weakness}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> WEAKNESS = create(key("weakness"));
+
+ /**
+ * {@code minecraft:weaving}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<PotionEffectType> WEAVING = create(key("weaving"));
+
+ /**
+ * {@code minecraft:wind_charged}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ @ApiStatus.Experimental
+ @MinecraftExperimental(MinecraftExperimental.Requires.UPDATE_1_21)
+ public static final TypedKey<PotionEffectType> WIND_CHARGED = create(key("wind_charged"));
+
+ /**
+ * {@code minecraft:wither}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<PotionEffectType> WITHER = create(key("wither"));
+
+ private MobEffectKeys() {
+ }
+
+ private static @NotNull TypedKey<PotionEffectType> create(final @NotNull Key key) {
+ return TypedKey.create(RegistryKey.MOB_EFFECT, key);
+ }
+}
diff --git a/paper-api-generator/generated/io/papermc/paper/registry/keys/WolfVariantKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/WolfVariantKeys.java
new file mode 100644
index 0000000000..5ae854aba8
--- /dev/null
+++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/WolfVariantKeys.java
@@ -0,0 +1,105 @@
+package io.papermc.paper.registry.keys;
+
+import static net.kyori.adventure.key.Key.key;
+
+import io.papermc.paper.generated.GeneratedFrom;
+import io.papermc.paper.registry.RegistryKey;
+import io.papermc.paper.registry.TypedKey;
+import net.kyori.adventure.key.Key;
+import org.bukkit.entity.Wolf;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Vanilla keys for {@link RegistryKey#WOLF_VARIANT}.
+ *
+ * @apiNote The fields provided here are a direct representation of
+ * what is available from the vanilla game source. They may be
+ * changed (including removals) on any Minecraft version
+ * bump, so cross-version compatibility is not provided on the
+ * same level as it is on most of the other API.
+ */
+@SuppressWarnings({
+ "unused",
+ "SpellCheckingInspection"
+})
+@GeneratedFrom("1.20.6")
+public final class WolfVariantKeys {
+ /**
+ * {@code minecraft:ashen}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> ASHEN = create(key("ashen"));
+
+ /**
+ * {@code minecraft:black}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> BLACK = create(key("black"));
+
+ /**
+ * {@code minecraft:chestnut}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> CHESTNUT = create(key("chestnut"));
+
+ /**
+ * {@code minecraft:pale}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> PALE = create(key("pale"));
+
+ /**
+ * {@code minecraft:rusty}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> RUSTY = create(key("rusty"));
+
+ /**
+ * {@code minecraft:snowy}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> SNOWY = create(key("snowy"));
+
+ /**
+ * {@code minecraft:spotted}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> SPOTTED = create(key("spotted"));
+
+ /**
+ * {@code minecraft:striped}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> STRIPED = create(key("striped"));
+
+ /**
+ * {@code minecraft:woods}
+ *
+ * @apiNote This field is version-dependant and may be removed in future Minecraft versions
+ */
+ public static final TypedKey<Wolf.Variant> WOODS = create(key("woods"));
+
+ private WolfVariantKeys() {
+ }
+
+ /**
+ * Creates a key for {@link Wolf.Variant} in a registry.
+ *
+ * @param key the value's key in the registry
+ * @return a new typed key
+ */
+ @ApiStatus.Experimental
+ public static @NotNull TypedKey<Wolf.Variant> create(final @NotNull Key key) {
+ return TypedKey.create(RegistryKey.WOLF_VARIANT, key);
+ }
+}
diff --git a/paper-api-generator/src/main/java/io/papermc/generator/Generators.java b/paper-api-generator/src/main/java/io/papermc/generator/Generators.java
index ac62e26e93..4afed26dd5 100644
--- a/paper-api-generator/src/main/java/io/papermc/generator/Generators.java
+++ b/paper-api-generator/src/main/java/io/papermc/generator/Generators.java
@@ -8,21 +8,31 @@ import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
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;
public interface Generators {
SourceGenerator[] API = {
- simpleKey("GameEventKeys", GameEvent.class, Registries.GAME_EVENT, RegistryKey.GAME_EVENT, true),
+ simpleKey("GameEventKeys", GameEvent.class, Registries.GAME_EVENT, RegistryKey.GAME_EVENT, false),
simpleKey("BiomeKeys", Biome.class, Registries.BIOME, RegistryKey.BIOME, true),
simpleKey("TrimMaterialKeys", TrimMaterial.class, Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL, true),
simpleKey("TrimPatternKeys", TrimPattern.class, Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, true),
simpleKey("StructureKeys", Structure.class, Registries.STRUCTURE, RegistryKey.STRUCTURE, true),
simpleKey("StructureTypeKeys", StructureType.class, Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, false),
+ simpleKey("InstrumentKeys", MusicInstrument.class, Registries.INSTRUMENT, RegistryKey.INSTRUMENT, false),
+ simpleKey("EnchantmentKeys", Enchantment.class, Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, false),
+ simpleKey("MobEffectKeys", PotionEffectType.class, Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, false),
+ simpleKey("DamageTypeKeys", DamageType.class, Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, true),
+ simpleKey("WolfVariantKeys", Wolf.Variant.class, Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, true),
new MobGoalGenerator("VanillaGoal", "com.destroystokyo.paper.entity.ai")
};
diff --git a/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java b/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java
index 66c4a4b14f..8307fcad4c 100644
--- a/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java
+++ b/paper-api-generator/src/main/java/io/papermc/generator/types/GeneratedKeyType.java
@@ -25,11 +25,14 @@ import java.util.Set;
import java.util.stream.Collectors;
import net.kyori.adventure.key.Key;
import net.minecraft.core.Holder;
+import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.data.registries.UpdateOneTwentyOneRegistries;
import net.minecraft.data.registries.VanillaRegistries;
import net.minecraft.resources.ResourceKey;
+import net.minecraft.world.flag.FeatureElement;
+import net.minecraft.world.flag.FeatureFlags;
import org.bukkit.MinecraftExperimental;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -151,8 +154,23 @@ public class GeneratedKeyType<T, A> extends SimpleGenerator {
return typeBuilder.addMethod(createMethod.build()).build();
}
- @SuppressWarnings("unchecked")
private Set<ResourceKey<T>> collectExperimentalKeys(final Registry<T> registry) {
+ if (FeatureElement.FILTERED_REGISTRIES.contains(registry.key())) {
+ return this.collectExperimentalKeysBuiltIn(registry);
+ } else {
+ return this.collectExperimentalKeysDataDriven(registry);
+ }
+ }
+
+ private Set<ResourceKey<T>> collectExperimentalKeysBuiltIn(final Registry<T> registry) {
+ final HolderLookup.RegistryLookup<T> filteredLookup = registry.asLookup().filterElements(v -> {
+ return ((FeatureElement) v).requiredFeatures().contains(FeatureFlags.UPDATE_1_21);
+ });
+ return filteredLookup.listElementIds().collect(Collectors.toUnmodifiableSet());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Set<ResourceKey<T>> collectExperimentalKeysDataDriven(final Registry<T> registry) {
final RegistrySetBuilder.@Nullable RegistryBootstrap<T> experimentalBootstrap = (RegistrySetBuilder.RegistryBootstrap<T>) EXPERIMENTAL_REGISTRY_ENTRIES.get(this.registryKey);
if (experimentalBootstrap == null) {
return Collections.emptySet();
diff --git a/patches/api/0004-Code-Generation.patch b/patches/api/0004-Code-Generation.patch
index edbc6ff3ef..718ff4eb87 100644
--- a/patches/api/0004-Code-Generation.patch
+++ b/patches/api/0004-Code-Generation.patch
@@ -85,20 +85,37 @@ index 0000000000000000000000000000000000000000..2512dba27edfdccbc4430815b6cba048
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java
new file mode 100644
-index 0000000000000000000000000000000000000000..c4b30b16ce4db754b958c493ad86d0863592c263
+index 0000000000000000000000000000000000000000..a505064565f7f029be8727b1951d9ef67c3acf2c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java
-@@ -0,0 +1,67 @@
+@@ -0,0 +1,128 @@
+package io.papermc.paper.registry;
+
+import net.kyori.adventure.key.Keyed;
++import org.bukkit.Art;
++import org.bukkit.Fluid;
+import org.bukkit.GameEvent;
++import org.bukkit.MusicInstrument;
++import org.bukkit.Particle;
++import org.bukkit.Sound;
++import org.bukkit.attribute.Attribute;
+import org.bukkit.block.Biome;
++import org.bukkit.block.banner.PatternType;
++import org.bukkit.damage.DamageType;
++import org.bukkit.enchantments.Enchantment;
++import org.bukkit.entity.Cat;
++import org.bukkit.entity.EntityType;
++import org.bukkit.entity.Frog;
++import org.bukkit.entity.Villager;
++import org.bukkit.entity.Wolf;
++import org.bukkit.entity.memory.MemoryKey;
+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.jetbrains.annotations.ApiStatus;
++import org.bukkit.map.MapCursor;
++import org.bukkit.potion.PotionEffectType;
++import org.bukkit.potion.PotionType;
+
+import static io.papermc.paper.registry.RegistryKeyImpl.create;
+
@@ -115,7 +132,6 @@ index 0000000000000000000000000000000000000000..c4b30b16ce4db754b958c493ad86d086
+ * @param <T> the value type
+ */
+@SuppressWarnings("unused")
+public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
+
+ /* ******************* *
@@ -131,6 +147,22 @@ index 0000000000000000000000000000000000000000..c4b30b16ce4db754b958c493ad86d086
+ * @see io.papermc.paper.registry.keys.StructureTypeKeys
+ */
+ RegistryKey<StructureType> STRUCTURE_TYPE = create("worldgen/structure_type");
++ /**
++ * Built-in registry for instruments.
++ * @see io.papermc.paper.registry.keys.InstrumentKeys
++ */
++ RegistryKey<MusicInstrument> INSTRUMENT = create("instrument");
++ /**
++ * Built-in registry for enchantments.
++ * @see io.papermc.paper.registry.keys.EnchantmentKeys
++ */
++ RegistryKey<Enchantment> ENCHANTMENT = create("enchantment");
++ /**
++ * Built-in registry for potion effect types (mob effects).
++ * @see io.papermc.paper.registry.keys.MobEffectKeys
++ */
++ RegistryKey<PotionEffectType> MOB_EFFECT = create("mob_effect");
++
+
+ /* ********************** *
+ * Data-driven Registries *
@@ -155,13 +187,42 @@ index 0000000000000000000000000000000000000000..c4b30b16ce4db754b958c493ad86d086
+ * @see io.papermc.paper.registry.keys.TrimPatternKeys
+ */
+ RegistryKey<TrimPattern> TRIM_PATTERN = create("trim_pattern");
++ /**
++ * Data-driven registry for damage types.
++ * @see io.papermc.paper.registry.keys.DamageTypeKeys
++ */
++ RegistryKey<DamageType> DAMAGE_TYPE = create("damage_type");
++ /**
++ * Data-driven registry for wolf variants
++ * @see io.papermc.paper.registry.keys.WolfVariantKeys
++ */
++ RegistryKey<Wolf.Variant> WOLF_VARIANT = create("wolf_variant");
++
++
++ /* ******************* *
++ * API-only Registries *
++ * ******************* */
++ RegistryKey<Art> PAINTING_VARIANT = create("painting_variant");
++ RegistryKey<Attribute> ATTRIBUTE = create("attribute");
++ RegistryKey<PatternType> BANNER_PATTERN = create("banner_pattern");
++ RegistryKey<Cat.Type> CAT_VARIANT = create("cat_variant");
++ RegistryKey<EntityType> ENTITY_TYPE = create("entity_type");
++ RegistryKey<Particle> PARTICLE_TYPE = create("particle_type");
++ RegistryKey<PotionType> POTION = create("potion");
++ RegistryKey<Sound> SOUND_EVENT = create("sound_event");
++ RegistryKey<Villager.Profession> VILLAGER_PROFESSION = create("villager_profession");
++ RegistryKey<Villager.Type> VILLAGER_TYPE = create("villager_type");
++ RegistryKey<MemoryKey<?>> MEMORY_MODULE_TYPE = create("memory_module_type");
++ RegistryKey<Fluid> FLUID = create("fluid");
++ RegistryKey<Frog.Variant> FROG_VARIANT = create("frog_variant");
++ RegistryKey<MapCursor.Type> MAP_DECORATION_TYPE = create("map_decoration_type");
+}
diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
new file mode 100644
-index 0000000000000000000000000000000000000000..9ad300fa1668cb59bbd85ff8091591db69b8c9dc
+index 0000000000000000000000000000000000000000..791813220b2504214b1adecc69093cd600fb0f8c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
-@@ -0,0 +1,19 @@
+@@ -0,0 +1,24 @@
+package io.papermc.paper.registry;
+
+import com.google.common.collect.Sets;
@@ -175,15 +236,20 @@ index 0000000000000000000000000000000000000000..9ad300fa1668cb59bbd85ff8091591db
+ static final Set<RegistryKey<?>> REGISTRY_KEYS = Sets.newIdentityHashSet();
+
+ static <T> RegistryKey<T> create(@Subst("some_key") final String key) {
-+ final RegistryKey<T> registryKey = new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key));
++ final RegistryKey<T> registryKey = createInternal(key);
+ REGISTRY_KEYS.add(registryKey);
+ return registryKey;
+ }
+
++ // creates the key without adding to the internal set of keys
++ static <T> RegistryKey<T> 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
new file mode 100644
-index 0000000000000000000000000000000000000000..271454cd1b92ada4301025b57348ea77da9116a1
+index 0000000000000000000000000000000000000000..6f5a062ba7ee7173468ecea3c1855a233bf3855e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKey.java
@@ -0,0 +1,44 @@
@@ -227,13 +293,13 @@ index 0000000000000000000000000000000000000000..271454cd1b92ada4301025b57348ea77
+ * @return a new key for the value key and registry key
+ */
+ @ApiStatus.Experimental
-+ static <T extends Keyed> @NotNull TypedKey<T> create(final @NotNull RegistryKey<T> registryKey, final @NotNull Key key) {
++ static <T> @NotNull TypedKey<T> create(final @NotNull RegistryKey<T> 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
new file mode 100644
-index 0000000000000000000000000000000000000000..3c3fd73f7742bb8602e2f9164dd4c1208a412255
+index 0000000000000000000000000000000000000000..1a97b3359c4ece5c29131da7c3f208aaa8fab66e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java
@@ -0,0 +1,8 @@
@@ -243,7 +309,7 @@ index 0000000000000000000000000000000000000000..3c3fd73f7742bb8602e2f9164dd4c120
+import net.kyori.adventure.key.Keyed;
+import org.jetbrains.annotations.NotNull;
+
-+record TypedKeyImpl<T extends Keyed>(@NotNull Key key, @NotNull RegistryKey<T> registryKey) implements TypedKey<T> {
++record TypedKeyImpl<T>(@NotNull Key key, @NotNull RegistryKey<T> registryKey) implements TypedKey<T> {
+}
diff --git a/src/main/java/org/bukkit/MinecraftExperimental.java b/src/main/java/org/bukkit/MinecraftExperimental.java
index b6f4810e387c22c4a70609ea1d605130245689a5..03824ae54e1bdb8b14f79b3c5e0294ae725e43f8 100644
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 <[email protected]>
-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 <T> type of the value
-+ */
-+public interface Reference<T extends Keyed> 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 <T> the type of the value
-+ * @return a reference
-+ */
-+ static <T extends Keyed> @NotNull Reference<T> create(@NotNull Registry<T> 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<T extends Keyed>(@NotNull Registry<T> registry, @NotNull NamespacedKey key) implements Reference<T> {
-+
-+ @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..17ce5cc911
--- /dev/null
+++ b/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch
@@ -0,0 +1,394 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+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..d8656772e0c983df7c40ddc367a73ce473348339
+--- /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 <T> type of the value
++ */
++@Deprecated(forRemoval = true, since = "1.20.6")
++public interface Reference<T extends Keyed> 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.6")
++ @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.6")
++ @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 <T> the type of the value
++ * @return a reference
++ */
++ @Deprecated(forRemoval = true, since = "1.20.6")
++ static <T extends Keyed> @NotNull Reference<T> create(@NotNull Registry<T> 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<T extends Keyed>(@NotNull Registry<T> registry, @NotNull NamespacedKey key) implements Reference<T> {
++
++ @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..86ab67ff5023bf6adea80b02648b6f67476e30e5
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/RegistryAccess.java
+@@ -0,0 +1,49 @@
++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;
++
++/**
++ * Used for accessing different {@link Registry} instances
++ * by a {@link RegistryKey}. Get the main instance of {@link RegistryAccess}
++ * with {@link RegistryAccess#registryAccess()}.
++ */
++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 <T> the type
++ * @deprecated use {@link #getRegistry(RegistryKey)} with keys from {@link RegistryKey}
++ */
++ @Deprecated(since = "1.20.6", forRemoval = true)
++ <T extends Keyed> @Nullable Registry<T> getRegistry(@NotNull Class<T> type);
++
++ /**
++ * Gets the registry with the specified key.
++ *
++ * @param registryKey the key
++ * @return the registry
++ * @param <T> 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.
++ <T extends Keyed> @NotNull Registry<T> getRegistry(@NotNull RegistryKey<T> 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<RegistryAccess> INSTANCE = ServiceLoader.load(RegistryAccess.class).findFirst();
++
++ private RegistryAccessHolder() {
++ }
++}
+diff --git a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
+index 791813220b2504214b1adecc69093cd600fb0f8c..47fe5b0d5d031110c27210a0a256c260b35d9ba1 100644
+--- a/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
++++ b/src/main/java/io/papermc/paper/registry/RegistryKeyImpl.java
+@@ -10,6 +10,17 @@ record RegistryKeyImpl<T>(@NotNull Key key) implements RegistryKey<T> {
+
+ static final Set<RegistryKey<?>> REGISTRY_KEYS = Sets.newIdentityHashSet();
+
++ // override equals and hashCode to this can be used to simulate an "identity" hashmap
++ @Override
++ public boolean equals(final Object obj) {
++ return obj == this;
++ }
++
++ @Override
++ public int hashCode() {
++ return System.identityHashCode(this);
++ }
++
+ static <T> RegistryKey<T> create(@Subst("some_key") final String key) {
+ final RegistryKey<T> registryKey = createInternal(key);
+ REGISTRY_KEYS.add(registryKey);
+diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
+index 732ed3724e784ad659cb4411dbd73b42a8330a2c..7be6710d28dea19bd0f9054c1c2e32dacd355c45 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 <T> 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.6")
+ public static <T extends Keyed> Registry<T> getRegistry(@NotNull Class<T> 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..91117cad12eee0bdaac8e0398a0f7f288ba27a40 100644
+--- a/src/main/java/org/bukkit/Registry.java
++++ b/src/main/java/org/bukkit/Registry.java
+@@ -129,7 +129,7 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+ *
+ * @see Enchantment
+ */
+- Registry<Enchantment> ENCHANTMENT = Objects.requireNonNull(Bukkit.getRegistry(Enchantment.class), "No registry present for Enchantment. This is a bug.");
++ Registry<Enchantment> 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<T extends Keyed> extends Iterable<T> {
+ *
+ * @see MusicInstrument
+ */
+- Registry<MusicInstrument> INSTRUMENT = Objects.requireNonNull(Bukkit.getRegistry(MusicInstrument.class), "No registry present for MusicInstrument. This is a bug.");
++ Registry<MusicInstrument> 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<T extends Keyed> extends Iterable<T> {
+ *
+ * @see PotionEffectType
+ */
+- Registry<PotionEffectType> EFFECT = Objects.requireNonNull(Bukkit.getRegistry(PotionEffectType.class), "No registry present for PotionEffectType. This is a bug.");
++ Registry<PotionEffectType> 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<T extends Keyed> extends Iterable<T> {
+ * 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> STRUCTURE = Bukkit.getRegistry(Structure.class);
++ @Deprecated(since = "1.20.6") // Paper
++ Registry<Structure> STRUCTURE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Structure.class), "No registry present for Structure. This is a bug."); // Paper
+ /**
+ * Server structure types.
+ *
+ * @see StructureType
+ */
+- Registry<StructureType> STRUCTURE_TYPE = Bukkit.getRegistry(StructureType.class);
++ Registry<StructureType> STRUCTURE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.STRUCTURE_TYPE); // Paper
+ /**
+ * Sound keys.
+ *
+@@ -200,21 +202,26 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+ * 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<TrimMaterial> TRIM_MATERIAL = Bukkit.getRegistry(TrimMaterial.class);
++ @Deprecated(since = "1.20.6") // Paper
++ Registry<TrimMaterial> TRIM_MATERIAL = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(TrimMaterial.class), "No registry present for TrimMaterial. This is a bug."); // 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<TrimPattern> TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class);
++ @Deprecated(since = "1.20.6")
++ Registry<TrimPattern> TRIM_PATTERN = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(TrimPattern.class), "No registry present for TrimPattern. This is a bug."); // Paper
+ /**
+ * Damage types.
+ *
+ * @see DamageType
++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#DAMAGE_TYPE}
+ */
+- @ApiStatus.Experimental
+- Registry<DamageType> DAMAGE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(DamageType.class), "No registry present for DamageType. This is a bug.");
++ @Deprecated(since = "1.20.6")
++ Registry<DamageType> DAMAGE_TYPE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(DamageType.class), "No registry present for DamageType. This is a bug."); // Paper
+ /**
+ * Villager profession.
+ *
+@@ -268,8 +275,10 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+ * Wolf variants.
+ *
+ * @see Wolf.Variant
++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#WOLF_VARIANT}
+ */
+- Registry<Wolf.Variant> WOLF_VARIANT = Objects.requireNonNull(Bukkit.getRegistry(Wolf.Variant.class), "No registry present for Wolf Variant. This is a bug.");
++ @Deprecated(since = "1.20.6")
++ Registry<Wolf.Variant> WOLF_VARIANT = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Wolf.Variant.class), "No registry present for Wolf$Variant. This is a bug."); // Paper
+ /**
+ * Map cursor types.
+ *
+@@ -282,7 +291,7 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+ *
+ * @see GameEvent
+ */
+- Registry<GameEvent> GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug.");
++ Registry<GameEvent> 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..5644af8154373923791e3ed5f8b01c3f5d357b9c 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 <T> 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.6") // Paper
+ <T extends Keyed> Registry<T> getRegistry(@NotNull Class<T> 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..f5ece852f97017f71bc129e194cb212979b2537b
+--- /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.6", forRemoval = true)
++ public @Nullable <T extends Keyed> Registry<T> getRegistry(final @NotNull Class<T> type) {
++ throw new UnsupportedOperationException("Not supported");
++ }
++
++ @Override
++ public @NotNull <T extends Keyed> Registry<T> getRegistry(final @NotNull RegistryKey<T> 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<Class<? extends Keyed>, Registry<?>> registers = new HashMap<>();
+- when(instance.getRegistry(any())).then(invocationOnMock -> registers.computeIfAbsent(invocationOnMock.getArgument(0), aClass -> new Registry<Keyed>() {
+- private final Map<NamespacedKey, Keyed> cache = new HashMap<>();
+-
+- @Override
+- public Keyed get(NamespacedKey key) {
+- return cache.computeIfAbsent(key, key2 -> mock(aClass, withSettings().stubOnly()));
+- }
+-
+- @NotNull
+- @Override
+- public Stream<Keyed> stream() {
+- throw new UnsupportedOperationException("Not supported");
+- }
+-
+- @Override
+- public Iterator<Keyed> iterator() {
+- throw new UnsupportedOperationException("Not supported");
+- }
+- }));
++ // Paper start - RegistryAccess
++ when(instance.getRegistry(any())).then(invocationOnMock -> {
++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(((Class<Keyed>)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..10ef586cce 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 91117cad12eee0bdaac8e0398a0f7f288ba27a40..43f410326d6d68242113e2fefe31af256889ed9c 100644
--- a/src/main/java/org/bukkit/Registry.java
+++ b/src/main/java/org/bukkit/Registry.java
-@@ -283,6 +283,17 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+@@ -292,6 +292,15 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
* @see GameEvent
*/
- Registry<GameEvent> GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug.");
-+
+ Registry<GameEvent> 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<io.papermc.paper.world.structure.ConfiguredStructure> CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class);
++ Registry<io.papermc.paper.world.structure.ConfiguredStructure> CONFIGURED_STRUCTURE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class), "No registry present for ConfiguredStructure. This is a bug.");
+ // 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..cad46c8765 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 43f410326d6d68242113e2fefe31af256889ed9c..90ab3bef4c5b6b6e215e9c759c886ed6d0f3302b 100644
--- a/src/main/java/org/bukkit/Registry.java
+++ b/src/main/java/org/bukkit/Registry.java
-@@ -292,6 +292,31 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+@@ -300,6 +300,31 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
*/
@Deprecated(forRemoval = true)
- Registry<io.papermc.paper.world.structure.ConfiguredStructure> CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class);
+ Registry<io.papermc.paper.world.structure.ConfiguredStructure> CONFIGURED_STRUCTURE = Objects.requireNonNull(io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class), "No registry present for ConfiguredStructure. This is a bug.");
+
+ /**
+ * 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..9ae821e422 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 9a8be5c730802e5750de1fc31e65f254f5894e63..0f7f23738c57ebe37846714159bb49e5b61e9f3d 100644
--- a/src/main/java/org/bukkit/Registry.java
+++ b/src/main/java/org/bukkit/Registry.java
-@@ -328,6 +328,49 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
+@@ -335,6 +335,49 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
@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<T extends Keyed> extends Iterable<T> {
+@@ -401,5 +444,12 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
public Iterator<T> iterator() {
return map.values().iterator();
}
diff --git a/patches/server/0019-Paper-Plugins.patch b/patches/server/0019-Paper-Plugins.patch
index 7a19309b99..b3ef03dd63 100644
--- a/patches/server/0019-Paper-Plugins.patch
+++ b/patches/server/0019-Paper-Plugins.patch
@@ -7208,17 +7208,24 @@ index bc91370654f5da33cbfe7d42431568915c1159d6..b43af53960978ac04bccde08544a5628
validate(REGISTRY);
}
diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java
-index 15ee2f2a83bfef2f6891d9bfb2d3a8c14b24ffb1..d0d95d729853fc296c4931a2f73a3fc5f94302c9 100644
+index 15ee2f2a83bfef2f6891d9bfb2d3a8c14b24ffb1..26892378d27dadce25c178333188ba093dc1617b 100644
--- a/src/main/java/net/minecraft/server/Bootstrap.java
+++ b/src/main/java/net/minecraft/server/Bootstrap.java
-@@ -74,7 +74,11 @@ public class Bootstrap {
+@@ -63,6 +63,7 @@ public class Bootstrap {
+ Bootstrap.isBootstrapped = true;
+ Instant instant = Instant.now();
+
++ io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping
+ if (BuiltInRegistries.REGISTRY.keySet().isEmpty()) {
+ throw new IllegalStateException("Unable to load registries");
+ } else {
+@@ -74,7 +75,10 @@ public class Bootstrap {
EntitySelectorOptions.bootStrap();
DispenseItemBehavior.bootStrap();
CauldronInteraction.bootStrap();
- BuiltInRegistries.bootStrap();
+ // Paper start
+ BuiltInRegistries.bootStrap(() -> {
-+ io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping
+ });
+ // Paper end
CreativeModeTabs.validate();
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..04ed9f2f0e
--- /dev/null
+++ b/patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch
@@ -0,0 +1,1026 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+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..cc7d4924098eab9663cc52917e4b30d6ef4b02c7
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+@@ -0,0 +1,101 @@
++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.entity.memory.MemoryKey;
++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.apiOnly;
++import static io.papermc.paper.registry.entry.RegistryEntry.entry;
++
++@DefaultQualifier(NonNull.class)
++public final class PaperRegistries {
++
++ static final List<RegistryEntry<?, ?, ?>> REGISTRY_ENTRIES;
++ private static final Map<RegistryKey<?>, RegistryEntry<?, ?, ?>> BY_REGISTRY_KEY;
++ private static final Map<ResourceKey<?>, 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(),
++
++ // api-only
++ apiOnly(Registries.BIOME, RegistryKey.BIOME, () -> org.bukkit.Registry.BIOME),
++ apiOnly(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT, () -> org.bukkit.Registry.ART),
++ apiOnly(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE, () -> org.bukkit.Registry.ATTRIBUTE),
++ apiOnly(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN, () -> org.bukkit.Registry.BANNER_PATTERN),
++ apiOnly(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT, () -> org.bukkit.Registry.CAT_VARIANT),
++ apiOnly(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE, () -> org.bukkit.Registry.ENTITY_TYPE),
++ apiOnly(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE, () -> org.bukkit.Registry.PARTICLE_TYPE),
++ apiOnly(Registries.POTION, RegistryKey.POTION, () -> org.bukkit.Registry.POTION),
++ apiOnly(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT, () -> org.bukkit.Registry.SOUNDS),
++ apiOnly(Registries.VILLAGER_PROFESSION, RegistryKey.VILLAGER_PROFESSION, () -> org.bukkit.Registry.VILLAGER_PROFESSION),
++ apiOnly(Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE, () -> org.bukkit.Registry.VILLAGER_TYPE),
++ apiOnly(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE, () -> (org.bukkit.Registry<MemoryKey<?>>) (org.bukkit.Registry) org.bukkit.Registry.MEMORY_MODULE_TYPE),
++ apiOnly(Registries.FLUID, RegistryKey.FLUID, () -> org.bukkit.Registry.FLUID),
++ apiOnly(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT, () -> org.bukkit.Registry.FROG_VARIANT),
++ apiOnly(Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE, () -> org.bukkit.Registry.MAP_DECORATION_TYPE)
++ );
++ final Map<RegistryKey<?>, RegistryEntry<?, ?, ?>> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size());
++ final Map<ResourceKey<?>, 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 <M, T extends Keyed, R extends org.bukkit.Registry<T>> @Nullable RegistryEntry<M, T, R> getEntry(final ResourceKey<? extends Registry<M>> resourceKey) {
++ return (RegistryEntry<M, T, R>) BY_RESOURCE_KEY.get(resourceKey);
++ }
++
++ @SuppressWarnings("unchecked")
++ public static <M, T extends Keyed, R extends org.bukkit.Registry<T>> @Nullable RegistryEntry<M, T, R> getEntry(final RegistryKey<? super T> registryKey) {
++ return (RegistryEntry<M, T, R>) 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..9f2bcfe0d9e479466a1e46e503071d1151310e6a
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java
+@@ -0,0 +1,124 @@
++package io.papermc.paper.registry;
++
++import io.papermc.paper.registry.entry.ApiRegistryEntry;
++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.Map;
++import java.util.NoSuchElementException;
++import java.util.Set;
++import java.util.concurrent.ConcurrentHashMap;
++import java.util.stream.Collectors;
++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<RegistryKey<?>, RegistryHolder<?>> registries = new ConcurrentHashMap<>(); // is "identity" because RegistryKey overrides equals and hashCode
++
++ public static PaperRegistryAccess instance() {
++ return (PaperRegistryAccess) RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found"));
++ }
++
++ @VisibleForTesting
++ public Set<RegistryKey<?>> getLoadedServerBackedRegistries() {
++ return this.registries.keySet().stream().filter(registryHolder -> !(PaperRegistries.getEntry(registryHolder) instanceof ApiRegistryEntry)).collect(Collectors.toUnmodifiableSet());
++ }
++
++ @SuppressWarnings("unchecked")
++ @Deprecated(forRemoval = true)
++ @Override
++ public <T extends Keyed> @Nullable Registry<T> getRegistry(final Class<T> type) {
++ final RegistryKey<T> registryKey;
++ final @Nullable RegistryEntry<?, T, ?> entry;
++ registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type");
++ entry = PaperRegistries.getEntry(registryKey);
++ final @Nullable RegistryHolder<T> registry = (RegistryHolder<T>) 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<?, T, ?>) {
++ // 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<T> 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 <T extends Keyed> Registry<T> getRegistry(final RegistryKey<T> key) {
++ if (PaperRegistries.getEntry(key) == null) {
++ throw new NoSuchElementException(key + " is not a valid registry key");
++ }
++ final @Nullable RegistryHolder<T> registryHolder = (RegistryHolder<T>) this.registries.get(key);
++ if (registryHolder == null) {
++ throw new IllegalArgumentException(key + " points to a registry that 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 <T extends Keyed> Registry<T> possiblyUnwrap(final Registry<T> registry) {
++ if (registry instanceof final DelayedRegistry<T, ?> delayedRegistry) { // if not coming from legacy, unwrap the delayed registry
++ return delayedRegistry.delegate();
++ }
++ return registry;
++ }
++
++ public <M> void registerReloadableRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry) {
++ this.registerRegistry(resourceKey, registry, true);
++ }
++
++ public <M> void registerRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> 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 <M, B extends Keyed, R extends Registry<B>> void registerRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry, final boolean replace) {
++ final @Nullable RegistryEntry<M, B, R> entry = PaperRegistries.getEntry(resourceKey);
++ if (entry == null) { // skip registries that don't have API entries
++ return;
++ }
++ final @Nullable RegistryHolder<B> registryHolder = (RegistryHolder<B>) 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 RegistryHolder.Delayed<?, ?> && entry instanceof final DelayedRegistryEntry<M, B, R> 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.
++ ((RegistryHolder.Delayed<B, R>) registryHolder).loadFrom(delayedEntry, registry);
++ } else {
++ throw new IllegalArgumentException(resourceKey + " has already been created");
++ }
++ }
++ }
++
++ @SuppressWarnings("unchecked")
++ @Deprecated
++ @VisibleForTesting
++ public static <T extends Keyed> @Nullable RegistryKey<T> byType(final Class<T> type) {
++ return (RegistryKey<T>) 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..02402ef647c3e78ed56fd6b2687bf7c67448f891
+--- /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.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.framework.qual.DefaultQualifier;
++
++@DefaultQualifier(NonNull.class)
++public interface RegistryHolder<B extends Keyed> {
++
++ Registry<B> get();
++
++ final class Memoized<B extends Keyed, R extends Registry<B>> implements RegistryHolder<B> {
++
++ private final Supplier<R> memoizedSupplier;
++
++ public Memoized(final Supplier<? extends R> supplier) {
++ this.memoizedSupplier = Suppliers.memoize(supplier::get);
++ }
++
++ public Registry<B> get() {
++ return this.memoizedSupplier.get();
++ }
++ }
++
++ final class Delayed<B extends Keyed, R extends Registry<B>> implements RegistryHolder<B> {
++
++ private final DelayedRegistry<B, R> delayedRegistry = new DelayedRegistry<>();
++
++ @Override
++ public DelayedRegistry<B, R> get() {
++ return this.delayedRegistry;
++ }
++
++ <M> void loadFrom(final DelayedRegistryEntry<M, B, R> delayedEntry, final net.minecraft.core.Registry<M> registry) {
++ final RegistryHolder<B> delegateHolder = delayedEntry.delegate().createRegistryHolder(registry);
++ if (!(delegateHolder instanceof RegistryHolder.Memoized<B, ?>)) {
++ throw new IllegalArgumentException(delegateHolder + " must be a memoized holder");
++ }
++ this.delayedRegistry.load(((Memoized<B, R>) delegateHolder).memoizedSupplier);
++ }
++ }
++}
+diff --git a/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..b2281a21eafd1f22f0ce261787e29af8a8637147
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/entry/ApiRegistryEntry.java
+@@ -0,0 +1,27 @@
++package io.papermc.paper.registry.entry;
++
++import io.papermc.paper.registry.RegistryHolder;
++import io.papermc.paper.registry.RegistryKey;
++import java.util.function.Supplier;
++import net.minecraft.core.Registry;
++import net.minecraft.resources.ResourceKey;
++import org.bukkit.Keyed;
++
++public class ApiRegistryEntry<M, B extends Keyed> extends BaseRegistryEntry<M, B, org.bukkit.Registry<B>> {
++
++ private final Supplier<org.bukkit.Registry<B>> registrySupplier;
++
++ protected ApiRegistryEntry(
++ final ResourceKey<? extends Registry<M>> mcKey,
++ final RegistryKey<B> apiKey,
++ final Supplier<org.bukkit.Registry<B>> registrySupplier
++ ) {
++ super(mcKey, apiKey);
++ this.registrySupplier = registrySupplier;
++ }
++
++ @Override
++ public RegistryHolder<B> createRegistryHolder(final Registry<M> nmsRegistry) {
++ return new RegistryHolder.Memoized<>(this.registrySupplier);
++ }
++}
+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..1be8a5feccd27779fcd8ebb2c362f17d78d307da
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/entry/BaseRegistryEntry.java
+@@ -0,0 +1,27 @@
++package io.papermc.paper.registry.entry;
++
++import io.papermc.paper.registry.RegistryKey;
++import net.minecraft.core.Registry;
++import net.minecraft.resources.ResourceKey;
++import org.bukkit.Keyed;
++
++public abstract class BaseRegistryEntry<M, B extends Keyed, R extends org.bukkit.Registry<B>> implements RegistryEntry<M, B, R> { // TODO remove Keyed
++
++ private final ResourceKey<? extends Registry<M>> minecraftRegistryKey;
++ private final RegistryKey<B> apiRegistryKey;
++
++ protected BaseRegistryEntry(final ResourceKey<? extends Registry<M>> minecraftRegistryKey, final RegistryKey<B> apiRegistryKey) {
++ this.minecraftRegistryKey = minecraftRegistryKey;
++ this.apiRegistryKey = apiRegistryKey;
++ }
++
++ @Override
++ public final ResourceKey<? extends Registry<M>> mcKey() {
++ return this.minecraftRegistryKey;
++ }
++
++ @Override
++ public final RegistryKey<B> apiKey() {
++ return this.apiRegistryKey;
++ }
++}
+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..d0023caafdb33d2f76bdd7bf6dfb3204069f52a0
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/entry/CraftRegistryEntry.java
+@@ -0,0 +1,39 @@
++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<M, B extends Keyed> extends BaseRegistryEntry<M, B, CraftRegistry<B, M>> { // TODO remove Keyed
++
++ protected final Class<?> classToPreload;
++ protected final BiFunction<NamespacedKey, M, B> minecraftToBukkit;
++
++ protected CraftRegistryEntry(
++ final ResourceKey<? extends Registry<M>> mcKey,
++ final RegistryKey<B> apiKey,
++ final Class<?> classToPreload,
++ final BiFunction<NamespacedKey, M, B> minecraftToBukkit
++ ) {
++ super(mcKey, apiKey);
++ this.classToPreload = classToPreload;
++ this.minecraftToBukkit = minecraftToBukkit;
++ }
++
++ @Override
++ public RegistryHolder<B> createRegistryHolder(final Registry<M> nmsRegistry) {
++ return new RegistryHolder.Memoized<>(() -> this.createApiRegistry(nmsRegistry));
++ }
++
++ private CraftRegistry<B, M> createApiRegistry(final Registry<M> nmsRegistry) {
++ return new CraftRegistry<>(this.classToPreload, 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..3ca3938267bea86df1077c0ebeb8859a634cd042
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java
+@@ -0,0 +1,47 @@
++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 java.util.function.Supplier;
++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<M, B extends Keyed, R extends org.bukkit.Registry<B>> extends RegistryEntryInfo<M, B> { // TODO remove Keyed
++
++ RegistryHolder<B> createRegistryHolder(Registry<M> 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<M, B, R> delayed() {
++ return new DelayedRegistryEntry<>(this);
++ }
++
++ static <M, B extends Keyed> RegistryEntry<M, B, CraftRegistry<B, M>> entry(
++ final ResourceKey<? extends Registry<M>> mcKey,
++ final RegistryKey<B> apiKey,
++ final Class<?> classToPreload,
++ final BiFunction<NamespacedKey, M, B> minecraftToBukkit
++ ) {
++ return new CraftRegistryEntry<>(mcKey, apiKey, classToPreload, minecraftToBukkit);
++ }
++
++ static <M, B extends Keyed> RegistryEntry<M, B, org.bukkit.Registry<B>> apiOnly(
++ final ResourceKey<? extends Registry<M>> mcKey,
++ final RegistryKey<B> apiKey,
++ final Supplier<org.bukkit.Registry<B>> apiRegistrySupplier
++ ) {
++ return new ApiRegistryEntry<>(mcKey, apiKey, apiRegistrySupplier);
++ }
++}
+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..0ae855e80fc9fddfc1feb33c7a9748204828b7cc
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntryInfo.java
+@@ -0,0 +1,12 @@
++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<M, B> {
++
++ ResourceKey<? extends Registry<M>> mcKey();
++
++ RegistryKey<B> apiKey();
++}
+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<T extends Keyed, R extends Registry<T>> implements Registry<T> {
++
++ private @MonotonicNonNull Supplier<? extends R> delegate;
++
++ public void load(final Supplier<? extends R> registry) {
++ if (this.delegate != null) {
++ throw new IllegalStateException("Registry already loaded!");
++ }
++ this.delegate = registry;
++ }
++
++ public Registry<T> 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<T> iterator() {
++ return this.delegate().iterator();
++ }
++
++ @Override
++ public Stream<T> 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..5f615f50ac0cdbc47cf7a39b630b653e0d30cdf5
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java
+@@ -0,0 +1,26 @@
++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<M, T extends Keyed, R extends org.bukkit.Registry<T>>(RegistryEntry<M, T, R> delegate) implements RegistryEntry<M, T, R> {
++
++ @Override
++ public ResourceKey<? extends Registry<M>> mcKey() {
++ return this.delegate.mcKey();
++ }
++
++ @Override
++ public RegistryKey<T> apiKey() {
++ return this.delegate.apiKey();
++ }
++
++ @Override
++ public RegistryHolder<T> createRegistryHolder(final Registry<M> 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..83870816cd4c54f94a3c603ffe41c11e457f3dec
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java
+@@ -0,0 +1,33 @@
++package io.papermc.paper.registry.legacy;
++
++import com.google.common.collect.ImmutableMap;
++import io.leangen.geantyref.GenericTypeReflector;
++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<Class<?>, RegistryKey<?>> CLASS_TO_KEY_MAP;
++
++ static {
++ final ImmutableMap.Builder<Class<?>, 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 = GenericTypeReflector.erase(((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<? extends Registry<T>> key, R registry, BuiltInRegistries.RegistryBootstrap<T> 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<T>(ResourceKey<? extends Registry<T>> key, Codec<T> elementCodec) {
+ RegistryDataLoader.Loader<T> create(Lifecycle lifecycle, Map<ResourceKey<?>, Exception> errors) {
+ WritableRegistry<T> 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<T> writableRegistry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental());
++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(type.registryKey(), writableRegistry); // Paper - register reloadable registry
+ Map<ResourceLocation, JsonElement> 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<B extends Keyed, M> implements Registry<B> {
+ + ", 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 <B extends Keyed> Registry<?> createRegistry(Class<B> 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<? super B> bukkitClass;
++ private final Class<?> bukkitClass; // Paper - relax preload class
+ private final Map<NamespacedKey, B> cache = new HashMap<>();
+ private final net.minecraft.core.Registry<M> minecraftRegistry;
+ private final BiFunction<NamespacedKey, M, B> minecraftToBukkit;
+ private boolean init;
+
+- public CraftRegistry(Class<? super B> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, BiFunction<NamespacedKey, M, B> minecraftToBukkit) {
++ public CraftRegistry(Class<?> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, BiFunction<NamespacedKey, M, B> 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<String, World> worlds = new LinkedHashMap<String, World>();
+- private final Map<Class<?>, Registry<?>> registries = new HashMap<>();
++ // private final Map<Class<?>, 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 <T extends Keyed> Registry<T> getRegistry(Class<T> aClass) {
+- return (Registry<T>) 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/io/papermc/paper/registry/RegistryKeyTest.java b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java
+index e070aa1bb69859224493d958621389ee757f8752..311837ac7cea6b75eedee01bf893317a8763cdf9 100644
+--- a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java
++++ b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java
+@@ -1,15 +1,18 @@
+ package io.papermc.paper.registry;
+
++import io.papermc.paper.registry.entry.RegistryEntry;
+ import java.util.Optional;
+ import java.util.stream.Stream;
+ import net.minecraft.core.Registry;
+ import net.minecraft.resources.ResourceKey;
+ import net.minecraft.resources.ResourceLocation;
++import org.bukkit.Keyed;
+ import org.bukkit.support.AbstractTestingBase;
+ import org.junit.jupiter.api.BeforeAll;
+ import org.junit.jupiter.params.ParameterizedTest;
+ import org.junit.jupiter.params.provider.MethodSource;
+
++import static org.junit.jupiter.api.Assertions.assertNotNull;
+ import static org.junit.jupiter.api.Assertions.assertTrue;
+
+ class RegistryKeyTest extends AbstractTestingBase {
+@@ -28,6 +31,12 @@ class RegistryKeyTest extends AbstractTestingBase {
+ void testApiRegistryKeysExist(final RegistryKey<?> key) {
+ final Optional<Registry<Object>> registry = AbstractTestingBase.REGISTRY_CUSTOM.registry(ResourceKey.createRegistryKey(new ResourceLocation(key.key().asString())));
+ assertTrue(registry.isPresent(), "Missing vanilla registry for " + key.key().asString());
++ }
+
++ @ParameterizedTest
++ @MethodSource("data")
++ void testRegistryEntryExists(final RegistryKey<?> key) {
++ final RegistryEntry<?, ?, ?> entry = PaperRegistries.getEntry(key);
++ assertNotNull(entry, "Missing PaperRegistries entry for " + key);
+ }
+ }
+diff --git a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java
+index 4adaafafb7140e983a4e90f0ff0deaaf0887a9a5..0dd775ad1bd0bf9ba7ea05255d543a9df8b5fcfd 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<Class<?>> loadedRegistries = new HashSet<>(DummyServer.registers.keySet());
+- Set<Class<?>> notFound = new HashSet<>();
++ // Paper start
++ Set<io.papermc.paper.registry.RegistryKey<?>> loadedRegistries = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>());
++ loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().getLoadedServerBackedRegistries());
++ // Paper end
++ Set<io.papermc.paper.registry.RegistryKey<?>> 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<? extends Keyed> clazz) {
++ public void testHandleableImplementation(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz) { // Paper
+ Set<Class<? extends Keyed>> notImplemented = new HashSet<>();
+- Registry<? extends Keyed> registry = Bukkit.getRegistry(clazz);
++ Registry<? extends Keyed> 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<? extends Keyed> clazz, ResourceKey<net.minecraft.core.Registry<?>> registryKey,
++ public void testMinecraftToBukkitPresent(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz, ResourceKey<net.minecraft.core.Registry<?>> registryKey, // Paper
+ Class<? extends Keyed> craftClazz, Class<?> minecraftClazz) {
+ Method method = null;
+ try {
+@@ -107,7 +107,7 @@ public class RegistryConversionTest extends AbstractTestingBase {
+
+ @Order(2)
+ @RegistriesTest
+- public void testBukkitToMinecraftPresent(Class<? extends Keyed> clazz, ResourceKey<net.minecraft.core.Registry<?>> registryKey,
++ public void testBukkitToMinecraftPresent(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz, ResourceKey<net.minecraft.core.Registry<?>> registryKey, // Paper
+ Class<? extends Keyed> 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<? extends Keyed> clazz) throws IllegalAccessException {
++ public void testMinecraftToBukkitNullValue(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz) throws IllegalAccessException { // Paper
+ this.checkValidMinecraftToBukkit(clazz);
+
+ try {
+@@ -174,7 +174,7 @@ public class RegistryConversionTest extends AbstractTestingBase {
+
+ @Order(3)
+ @RegistriesTest
+- public void testBukkitToMinecraftNullValue(Class<? extends Keyed> clazz) throws IllegalAccessException {
++ public void testBukkitToMinecraftNullValue(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz) throws IllegalAccessException { // Paper
+ this.checkValidBukkitToMinecraft(clazz);
+
+ try {
+@@ -193,14 +193,14 @@ public class RegistryConversionTest extends AbstractTestingBase {
+
+ @Order(3)
+ @RegistriesTest
+- public void testMinecraftToBukkit(Class<? extends Keyed> clazz) {
++ public void testMinecraftToBukkit(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz) { // Paper
+ this.checkValidMinecraftToBukkit(clazz);
+ this.checkValidHandle(clazz);
+
+ Map<Object, Object> 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<? extends Keyed> clazz) {
++ public void testBukkitToMinecraft(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz) { // Paper
+ this.checkValidBukkitToMinecraft(clazz);
+ this.checkValidHandle(clazz);
+
+ Map<Object, Object> 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<? extends Keyed> clazz, ResourceKey<net.minecraft.core.Registry<?>> registryKey,
++ public void testMinecraftToBukkitNoValidMinecraft(io.papermc.paper.registry.RegistryKey<? extends Keyed> type, Class<? extends Keyed> clazz, ResourceKey<net.minecraft.core.Registry<?>> registryKey, // Paper
+ Class<? extends Keyed> 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<Registry<?>>) mock -> {
+- Class<? extends Keyed> 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<? extends Arguments> 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<? extends Arguments> getValues(Class<? extends Keyed> registryType) {
+- Registry<?> registry = Bukkit.getRegistry(registryType);
++ public static Stream<? extends Arguments> getValues(io.papermc.paper.registry.RegistryKey<? extends Keyed> 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 <[email protected]>
-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<B extends Keyed, M> implements Registry<B> {
- 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..23f1bd4d51 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 <[email protected]>
+diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+index cc7d4924098eab9663cc52917e4b30d6ef4b02c7..183e168afcc4302bc1e3274a89835f1f60e4bbd6 100644
+--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java
++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java
+@@ -40,6 +40,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<io.papermc.paper.world.structure.ConfiguredStructure> CONFIGURED_STRUCTURE_REGISTRY_KEY = RegistryKeyImpl.createInternal("worldgen/structure");
++ @Deprecated(forRemoval = true)
++ static final RegistryEntry<Structure, io.papermc.paper.world.structure.ConfiguredStructure, ?> 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<RegistryEntry<?, ?, ?>> REGISTRY_ENTRIES;
+ private static final Map<RegistryKey<?>, RegistryEntry<?, ?, ?>> BY_REGISTRY_KEY;
+ private static final Map<ResourceKey<?>, 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 9f2bcfe0d9e479466a1e46e503071d1151310e6a..7aa1a29e93b787e1167169bc7d6e9563daf6241e 100644
+--- a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java
++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java
+@@ -45,8 +45,13 @@ public class PaperRegistryAccess implements RegistryAccess {
+ public <T extends Keyed> @Nullable Registry<T> getRegistry(final Class<T> type) {
+ final RegistryKey<T> registryKey;
+ final @Nullable RegistryEntry<?, T, ?> 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<T>) PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_KEY;
++ entry = (RegistryEntry<?, T, ?>) PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_ENTRY;
++ } else {
++ registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type");
++ entry = PaperRegistries.getEntry(registryKey);
++ }
+ final @Nullable RegistryHolder<T> registry = (RegistryHolder<T>) 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<ConfiguredStructure, Structure> {
-+
-+ public LegacyRegistry(final Registry<Structure> 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<StructurePlacement, Set<Holder<Structure>>> 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<B extends Keyed, M> implements Registry<B> {
- 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 0dd775ad1bd0bf9ba7ea05255d543a9df8b5fcfd..c1e51d104c52dd3f3e48d651b0ff1f00ae9bf96d 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<Class<?>> loadedRegistries = new HashSet<>(DummyServer.registers.keySet());
- Set<Class<?>> 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().getLoadedServerBackedRegistries());
+ // Paper end
+ Set<io.papermc.paper.registry.RegistryKey<?>> 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<B extends Keyed, M> implements Registry<B> {
+@@ -104,6 +104,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
- private final Class<? super B> bukkitClass;
+ private final Class<?> bukkitClass; // Paper - relax preload class
private final Map<NamespacedKey, B> cache = new HashMap<>();
+ private final Map<B, NamespacedKey> byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry
private final net.minecraft.core.Registry<M> minecraftRegistry;
private final BiFunction<NamespacedKey, M, B> minecraftToBukkit;
private boolean init;
-@@ -194,6 +195,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
+@@ -148,6 +149,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
}
this.cache.put(namespacedKey, bukkit);
@@ -24,7 +24,7 @@ index c7d377dbb53cdc1f823a839e3a113136efc16349..73472890e30180dc3cb6aa1bd9c58150
return bukkit;
}
-@@ -216,4 +218,11 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
+@@ -170,4 +172,11 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
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 {
diff --git a/patches/server/0989-Flat-bedrock-generator-settings.patch b/patches/server/0989-Flat-bedrock-generator-settings.patch
index 7103386726..b973a4d233 100644
--- a/patches/server/0989-Flat-bedrock-generator-settings.patch
+++ b/patches/server/0989-Flat-bedrock-generator-settings.patch
@@ -105,17 +105,17 @@ index 0000000000000000000000000000000000000000..e0d73113c937ddbcf8144f88b15a8d3d
+ }
+}
diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java
-index 05f4be8dfff37ab6804a2d990b1f8c430d42dc7c..2a49a6a6bccabf588ba67b565d8f16fda04ba0b0 100644
+index a3a2097716430b30c9bac2581b9f67fe0c595bd2..6885a653bfe629c46bface19ff1eb666d74d4f1b 100644
--- a/src/main/java/net/minecraft/server/Bootstrap.java
+++ b/src/main/java/net/minecraft/server/Bootstrap.java
-@@ -76,6 +76,7 @@ public class Bootstrap {
+@@ -77,6 +77,7 @@ public class Bootstrap {
CauldronInteraction.bootStrap();
// Paper start
BuiltInRegistries.bootStrap(() -> {
+ io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings
- io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping
});
// Paper end
+ CreativeModeTabs.validate();
diff --git a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
index dc765b92cc90f5f370254e68bbbdfa5add7935ce..8ce870a5341a61fbbaf42021ef7f7f615a6a3e09 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java