From 5632210f10e520ce70a647b2b2bd45efde4d039b Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 4 May 2024 11:22:35 -0700 Subject: [PATCH] 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 --- .../paper/registry/keys/DamageTypeKeys.java | 367 ++++++ .../paper/registry/keys/EnchantmentKeys.java | 336 ++++++ .../paper/registry/keys/GameEventKeys.java | 9 +- .../paper/registry/keys/InstrumentKeys.java | 91 ++ .../paper/registry/keys/MobEffectKeys.java | 321 ++++++ .../paper/registry/keys/WolfVariantKeys.java | 105 ++ .../java/io/papermc/generator/Generators.java | 12 +- .../generator/types/GeneratedKeyType.java | 20 +- patches/api/0004-Code-Generation.patch | 88 +- patches/api/0243-Add-PaperRegistry.patch | 92 -- ...gistryAccess-for-managing-registries.patch | 394 +++++++ .../api/0244-Add-StructuresLocateEvent.patch | 12 +- patches/api/0278-Add-basic-Datapack-API.patch | 8 +- .../api/0338-More-PotionEffectType-API.patch | 8 +- patches/api/0345-Custom-Potion-Mixes.patch | 8 +- ...Folia-scheduler-and-owned-region-API.patch | 8 +- patches/api/0444-Improve-Registry.patch | 6 +- patches/server/0019-Paper-Plugins.patch | 13 +- ...gistryAccess-for-managing-Registries.patch | 1026 +++++++++++++++++ .../0485-TODO-Registry-Modification-API.patch | 18 - .../0486-Add-StructuresLocateEvent.patch | 89 +- patches/server/0940-Improve-Registry.patch | 12 +- ...0989-Flat-bedrock-generator-settings.patch | 6 +- 23 files changed, 2842 insertions(+), 207 deletions(-) create mode 100644 paper-api-generator/generated/io/papermc/paper/registry/keys/DamageTypeKeys.java create mode 100644 paper-api-generator/generated/io/papermc/paper/registry/keys/EnchantmentKeys.java create mode 100644 paper-api-generator/generated/io/papermc/paper/registry/keys/InstrumentKeys.java create mode 100644 paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java create mode 100644 paper-api-generator/generated/io/papermc/paper/registry/keys/WolfVariantKeys.java delete mode 100644 patches/api/0243-Add-PaperRegistry.patch create mode 100644 patches/api/0243-Add-RegistryAccess-for-managing-registries.patch create mode 100644 patches/server/0485-Add-RegistryAccess-for-managing-Registries.patch delete mode 100644 patches/server/0485-TODO-Registry-Modification-API.patch diff --git a/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") +@ApiStatus.Experimental +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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") +@ApiStatus.Experimental +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 WIND_BURST = create(key("wind_burst")); + + private EnchantmentKeys() { + } + + private static @NotNull TypedKey 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 create(final @NotNull Key key) { + private static @NotNull TypedKey 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") +@ApiStatus.Experimental +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 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 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 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 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 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 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 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 YEARN_GOAT_HORN = create(key("yearn_goat_horn")); + + private InstrumentKeys() { + } + + private static @NotNull TypedKey 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") +@ApiStatus.Experimental +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 WITHER = create(key("wither")); + + private MobEffectKeys() { + } + + private static @NotNull TypedKey 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") +@ApiStatus.Experimental +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 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 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 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 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 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 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 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 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 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 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 extends SimpleGenerator { return typeBuilder.addMethod(createMethod.build()).build(); } - @SuppressWarnings("unchecked") private Set> collectExperimentalKeys(final Registry registry) { + if (FeatureElement.FILTERED_REGISTRIES.contains(registry.key())) { + return this.collectExperimentalKeysBuiltIn(registry); + } else { + return this.collectExperimentalKeysDataDriven(registry); + } + } + + private Set> collectExperimentalKeysBuiltIn(final Registry registry) { + final HolderLookup.RegistryLookup filteredLookup = registry.asLookup().filterElements(v -> { + return ((FeatureElement) v).requiredFeatures().contains(FeatureFlags.UPDATE_1_21); + }); + return filteredLookup.listElementIds().collect(Collectors.toUnmodifiableSet()); + } + + @SuppressWarnings("unchecked") + private Set> collectExperimentalKeysDataDriven(final Registry registry) { final RegistrySetBuilder.@Nullable RegistryBootstrap experimentalBootstrap = (RegistrySetBuilder.RegistryBootstrap) 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 the value type + */ +@SuppressWarnings("unused") -+@ApiStatus.Experimental +public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { + + /* ******************* * @@ -131,6 +147,22 @@ index 0000000000000000000000000000000000000000..c4b30b16ce4db754b958c493ad86d086 + * @see io.papermc.paper.registry.keys.StructureTypeKeys + */ + RegistryKey STRUCTURE_TYPE = create("worldgen/structure_type"); ++ /** ++ * Built-in registry for instruments. ++ * @see io.papermc.paper.registry.keys.InstrumentKeys ++ */ ++ RegistryKey INSTRUMENT = create("instrument"); ++ /** ++ * Built-in registry for enchantments. ++ * @see io.papermc.paper.registry.keys.EnchantmentKeys ++ */ ++ RegistryKey ENCHANTMENT = create("enchantment"); ++ /** ++ * Built-in registry for potion effect types (mob effects). ++ * @see io.papermc.paper.registry.keys.MobEffectKeys ++ */ ++ RegistryKey MOB_EFFECT = create("mob_effect"); ++ + + /* ********************** * + * Data-driven Registries * @@ -155,13 +187,42 @@ index 0000000000000000000000000000000000000000..c4b30b16ce4db754b958c493ad86d086 + * @see io.papermc.paper.registry.keys.TrimPatternKeys + */ + RegistryKey TRIM_PATTERN = create("trim_pattern"); ++ /** ++ * Data-driven registry for damage types. ++ * @see io.papermc.paper.registry.keys.DamageTypeKeys ++ */ ++ RegistryKey DAMAGE_TYPE = create("damage_type"); ++ /** ++ * Data-driven registry for wolf variants ++ * @see io.papermc.paper.registry.keys.WolfVariantKeys ++ */ ++ RegistryKey WOLF_VARIANT = create("wolf_variant"); ++ ++ ++ /* ******************* * ++ * API-only Registries * ++ * ******************* */ ++ RegistryKey PAINTING_VARIANT = create("painting_variant"); ++ RegistryKey ATTRIBUTE = create("attribute"); ++ RegistryKey BANNER_PATTERN = create("banner_pattern"); ++ RegistryKey CAT_VARIANT = create("cat_variant"); ++ RegistryKey ENTITY_TYPE = create("entity_type"); ++ RegistryKey PARTICLE_TYPE = create("particle_type"); ++ RegistryKey POTION = create("potion"); ++ RegistryKey SOUND_EVENT = create("sound_event"); ++ RegistryKey VILLAGER_PROFESSION = create("villager_profession"); ++ RegistryKey VILLAGER_TYPE = create("villager_type"); ++ RegistryKey> MEMORY_MODULE_TYPE = create("memory_module_type"); ++ RegistryKey FLUID = create("fluid"); ++ RegistryKey FROG_VARIANT = create("frog_variant"); ++ RegistryKey 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> REGISTRY_KEYS = Sets.newIdentityHashSet(); + + static RegistryKey create(@Subst("some_key") final String key) { -+ final RegistryKey registryKey = new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key)); ++ final RegistryKey registryKey = createInternal(key); + REGISTRY_KEYS.add(registryKey); + return registryKey; + } + ++ // creates the key without adding to the internal set of keys ++ static RegistryKey createInternal(@Subst("some_key") final String key) { ++ return new RegistryKeyImpl<>(Key.key(Key.MINECRAFT_NAMESPACE, key)); ++ } ++ +} diff --git a/src/main/java/io/papermc/paper/registry/TypedKey.java b/src/main/java/io/papermc/paper/registry/TypedKey.java 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 @NotNull TypedKey create(final @NotNull RegistryKey registryKey, final @NotNull Key key) { ++ static @NotNull TypedKey create(final @NotNull RegistryKey registryKey, final @NotNull Key key) { + return new TypedKeyImpl<>(key, registryKey); + } +} diff --git a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java 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(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { ++record TypedKeyImpl(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { +} diff --git a/src/main/java/org/bukkit/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 -Date: Wed, 2 Mar 2022 13:36:21 -0800 -Subject: [PATCH] Add PaperRegistry - - -diff --git a/src/main/java/io/papermc/paper/registry/Reference.java b/src/main/java/io/papermc/paper/registry/Reference.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d880810cbf05bc45051fe29515054211572e33b4 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/Reference.java -@@ -0,0 +1,43 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Represents a reference to a server-backed registry value that may -+ * change. -+ * -+ * @param type of the value -+ */ -+public interface Reference extends Keyed { -+ -+ /** -+ * Gets the value from the registry with the key. -+ * -+ * @return the value -+ * @throws java.util.NoSuchElementException if there is no value with this key -+ */ -+ @NotNull T value(); -+ -+ /** -+ * Gets the value from the registry with the key. -+ * -+ * @return the value or null if it doesn't exist -+ */ -+ @Nullable T valueOrNull(); -+ -+ /** -+ * Creates a reference to a registered value. -+ * -+ * @param registry the registry the value is located in -+ * @param key the key to the value -+ * @param the type of the value -+ * @return a reference -+ */ -+ static @NotNull Reference create(@NotNull Registry registry, @NotNull NamespacedKey key) { -+ return new ReferenceImpl<>(registry, key); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/ReferenceImpl.java b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6083b5982 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java -@@ -0,0 +1,31 @@ -+package io.papermc.paper.registry; -+ -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.Registry; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.NoSuchElementException; -+ -+record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { -+ -+ @Override -+ public @NotNull T value() { -+ final T value = this.registry.get(this.key); -+ if (value == null) { -+ throw new NoSuchElementException("No such value with key " + this.key); -+ } -+ return value; -+ } -+ -+ @Override -+ public @Nullable T valueOrNull() { -+ return this.registry.get(this.key); -+ } -+ -+ @Override -+ public @NotNull NamespacedKey getKey() { -+ return this.key; -+ } -+} diff --git a/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch b/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch new file mode 100644 index 0000000000..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 +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 type of the value ++ */ ++@Deprecated(forRemoval = true, since = "1.20.6") ++public interface Reference extends Keyed { ++ ++ /** ++ * Gets the value from the registry with the key. ++ * ++ * @return the value ++ * @throws java.util.NoSuchElementException if there is no value with this key ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.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 the type of the value ++ * @return a reference ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ static @NotNull Reference create(@NotNull Registry registry, @NotNull NamespacedKey key) { ++ return new ReferenceImpl<>(registry, key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/ReferenceImpl.java b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f29e76a6b66ddfec12ddf8db6dcb2df6083b5982 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.NoSuchElementException; ++ ++record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { ++ ++ @Override ++ public @NotNull T value() { ++ final T value = this.registry.get(this.key); ++ if (value == null) { ++ throw new NoSuchElementException("No such value with key " + this.key); ++ } ++ return value; ++ } ++ ++ @Override ++ public @Nullable T valueOrNull() { ++ return this.registry.get(this.key); ++ } ++ ++ @Override ++ public @NotNull NamespacedKey getKey() { ++ return this.key; ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccess.java b/src/main/java/io/papermc/paper/registry/RegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..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()}. ++ */ ++@ApiStatus.NonExtendable ++public interface RegistryAccess { ++ ++ /** ++ * Get the {@link RegistryAccess} instance for the server. ++ * ++ * @return the RegistryAccess instance ++ */ ++ static @NotNull RegistryAccess registryAccess() { ++ return RegistryAccessHolder.INSTANCE.orElseThrow(() -> new IllegalStateException("No RegistryAccess implementation found")); ++ } ++ ++ /** ++ * Gets the registry based on the type. ++ * ++ * @param type the type ++ * @return the registry or null if none found ++ * @param the type ++ * @deprecated use {@link #getRegistry(RegistryKey)} with keys from {@link RegistryKey} ++ */ ++ @Deprecated(since = "1.20.6", forRemoval = true) ++ @Nullable Registry getRegistry(@NotNull Class type); ++ ++ /** ++ * Gets the registry with the specified key. ++ * ++ * @param registryKey the key ++ * @return the registry ++ * @param the type ++ * @throws java.util.NoSuchElementException if no registry with the key is found ++ * @throws IllegalArgumentException if the registry is not available yet ++ */ ++ // Future note: We should have no trouble removing this generic qualifier when ++ // registry types no longer have to be "keyed" as it shouldn't break ABI or API. ++ @NotNull Registry getRegistry(@NotNull RegistryKey registryKey); ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b89e19c070f97c9662f1e16309446494b30aa7c9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.registry; ++ ++import java.util.Optional; ++import java.util.ServiceLoader; ++ ++final class RegistryAccessHolder { ++ ++ static final Optional INSTANCE = ServiceLoader.load(RegistryAccess.class).findFirst(); ++ ++ private RegistryAccessHolder() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/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(@NotNull Key key) implements RegistryKey { + + static final Set> 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 RegistryKey create(@Subst("some_key") final String key) { + final RegistryKey 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 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 Registry getRegistry(@NotNull Class tClass) { + return server.getRegistry(tClass); + } +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index a04d279561676e825905f5512c399d14a3d8f828..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 extends Iterable { + * + * @see Enchantment + */ +- Registry ENCHANTMENT = Objects.requireNonNull(Bukkit.getRegistry(Enchantment.class), "No registry present for Enchantment. This is a bug."); ++ Registry ENCHANTMENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.ENCHANTMENT); // Paper + /** + * Server entity types. + * +@@ -141,7 +141,7 @@ public interface Registry extends Iterable { + * + * @see MusicInstrument + */ +- Registry INSTRUMENT = Objects.requireNonNull(Bukkit.getRegistry(MusicInstrument.class), "No registry present for MusicInstrument. This is a bug."); ++ Registry INSTRUMENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.INSTRUMENT); // Paper + /** + * Default server loot tables. + * +@@ -159,7 +159,7 @@ public interface Registry extends Iterable { + * + * @see PotionEffectType + */ +- Registry EFFECT = Objects.requireNonNull(Bukkit.getRegistry(PotionEffectType.class), "No registry present for PotionEffectType. This is a bug."); ++ Registry EFFECT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.MOB_EFFECT); // Paper + /** + * Server particles. + * +@@ -182,14 +182,16 @@ public interface Registry extends Iterable { + * Server structures. + * + * @see Structure ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#STRUCTURE} + */ +- Registry STRUCTURE = Bukkit.getRegistry(Structure.class); ++ @Deprecated(since = "1.20.6") // Paper ++ Registry 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 STRUCTURE_TYPE = Bukkit.getRegistry(StructureType.class); ++ Registry STRUCTURE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.STRUCTURE_TYPE); // Paper + /** + * Sound keys. + * +@@ -200,21 +202,26 @@ public interface Registry extends Iterable { + * Trim materials. + * + * @see TrimMaterial ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#TRIM_MATERIAL} + */ +- Registry TRIM_MATERIAL = Bukkit.getRegistry(TrimMaterial.class); ++ @Deprecated(since = "1.20.6") // Paper ++ Registry 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 TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class); ++ @Deprecated(since = "1.20.6") ++ Registry 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 DAMAGE_TYPE = Objects.requireNonNull(Bukkit.getRegistry(DamageType.class), "No registry present for DamageType. This is a bug."); ++ @Deprecated(since = "1.20.6") ++ Registry 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 extends Iterable { + * 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 = 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 = 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 extends Iterable { + * + * @see GameEvent + */ +- Registry GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug."); ++ Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper + /** + * Get the object by its key. + * +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 395f7910f535bfd33a5676b011ab62a53e30e140..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 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 + Registry getRegistry(@NotNull Class tClass); + + /** +diff --git a/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java b/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..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 Registry getRegistry(final @NotNull Class type) { ++ throw new UnsupportedOperationException("Not supported"); ++ } ++ ++ @Override ++ public @NotNull Registry getRegistry(final @NotNull RegistryKey registryKey) { ++ throw new UnsupportedOperationException("Not supported"); ++ } ++} +diff --git a/src/test/java/org/bukkit/support/TestServer.java b/src/test/java/org/bukkit/support/TestServer.java +index b208150297a23c0b4acb79135416809718f5650e..f11c639f1dc3c5034678d80bde3127a2e81a4a93 100644 +--- a/src/test/java/org/bukkit/support/TestServer.java ++++ b/src/test/java/org/bukkit/support/TestServer.java +@@ -36,26 +36,11 @@ public final class TestServer { + + when(instance.getBukkitVersion()).thenReturn("BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion()); + +- Map, Registry> registers = new HashMap<>(); +- when(instance.getRegistry(any())).then(invocationOnMock -> registers.computeIfAbsent(invocationOnMock.getArgument(0), aClass -> new Registry() { +- private final Map cache = new HashMap<>(); +- +- @Override +- public Keyed get(NamespacedKey key) { +- return cache.computeIfAbsent(key, key2 -> mock(aClass, withSettings().stubOnly())); +- } +- +- @NotNull +- @Override +- public Stream stream() { +- throw new UnsupportedOperationException("Not supported"); +- } +- +- @Override +- public Iterator iterator() { +- throw new UnsupportedOperationException("Not supported"); +- } +- })); ++ // Paper start - RegistryAccess ++ when(instance.getRegistry(any())).then(invocationOnMock -> { ++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(((Class)invocationOnMock.getArgument(0))); ++ }); ++ // Paper end - RegistryAccess + + UnsafeValues unsafeValues = mock(withSettings().stubOnly()); + when(instance.getUnsafe()).thenReturn(unsafeValues); +diff --git a/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +new file mode 100644 +index 0000000000000000000000000000000000000000..f0a5e6d6b99aeef349fe465080ef2ff7b58617a6 +--- /dev/null ++++ b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.TestRegistryAccess diff --git a/patches/api/0244-Add-StructuresLocateEvent.patch b/patches/api/0244-Add-StructuresLocateEvent.patch index a07fa632f7..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 extends Iterable { +@@ -292,6 +292,15 @@ public interface Registry extends Iterable { * @see GameEvent */ - Registry GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug."); -+ + Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper + // Paper start + /** + * Configured structures. + * @see io.papermc.paper.world.structure.ConfiguredStructure -+ * @deprecated use {@link #STRUCTURE} ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#STRUCTURE} + */ + @Deprecated(forRemoval = true) -+ Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); ++ Registry CONFIGURED_STRUCTURE = 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 extends Iterable { +@@ -300,6 +300,31 @@ public interface Registry extends Iterable { */ @Deprecated(forRemoval = true) - Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + Registry 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 extends Iterable { +@@ -335,6 +335,49 @@ public interface Registry extends Iterable { @Nullable T get(@NotNull NamespacedKey key); @@ -84,7 +84,7 @@ index 76b1d08d9ae2c2cf5c6d88934929695d438b3284..542c0516e19b6177ff8007ca6f8955dc /** * Returns a new stream, which contains all registry items, which are registered to the registry. * -@@ -394,5 +437,12 @@ public interface Registry extends Iterable { +@@ -401,5 +444,12 @@ public interface Registry extends Iterable { public Iterator 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 +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> REGISTRY_ENTRIES; ++ private static final Map, RegistryEntry> BY_REGISTRY_KEY; ++ private static final Map, RegistryEntry> BY_RESOURCE_KEY; ++ static { ++ REGISTRY_ENTRIES = List.of( ++ // built-ins ++ entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new), ++ entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new), ++ entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new), ++ entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new), ++ entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new), ++ ++ // data-drivens ++ entry(Registries.STRUCTURE, RegistryKey.STRUCTURE, Structure.class, CraftStructure::new).delayed(), ++ entry(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL, TrimMaterial.class, CraftTrimMaterial::new).delayed(), ++ entry(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delayed(), ++ entry(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE, DamageType.class, CraftDamageType::new).delayed(), ++ entry(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT, Wolf.Variant.class, CraftWolf.CraftVariant::new).delayed(), ++ ++ // 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>) (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, RegistryEntry> byRegistryKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); ++ final Map, RegistryEntry> byResourceKey = new IdentityHashMap<>(REGISTRY_ENTRIES.size()); ++ for (final RegistryEntry entry : REGISTRY_ENTRIES) { ++ byRegistryKey.put(entry.apiKey(), entry); ++ byResourceKey.put(entry.mcKey(), entry); ++ } ++ BY_REGISTRY_KEY = Collections.unmodifiableMap(byRegistryKey); ++ BY_RESOURCE_KEY = Collections.unmodifiableMap(byResourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static > @Nullable RegistryEntry getEntry(final ResourceKey> resourceKey) { ++ return (RegistryEntry) BY_RESOURCE_KEY.get(resourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static > @Nullable RegistryEntry getEntry(final RegistryKey registryKey) { ++ return (RegistryEntry) BY_REGISTRY_KEY.get(registryKey); ++ } ++ ++ private PaperRegistries() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..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, 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> getLoadedServerBackedRegistries() { ++ return this.registries.keySet().stream().filter(registryHolder -> !(PaperRegistries.getEntry(registryHolder) instanceof ApiRegistryEntry)).collect(Collectors.toUnmodifiableSet()); ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated(forRemoval = true) ++ @Override ++ public @Nullable Registry getRegistry(final Class type) { ++ final RegistryKey registryKey; ++ final @Nullable RegistryEntry entry; ++ registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type"); ++ entry = PaperRegistries.getEntry(registryKey); ++ final @Nullable RegistryHolder registry = (RegistryHolder) this.registries.get(registryKey); ++ if (registry != null) { ++ // if the registry exists, return right away. Since this is the "legacy" method, we return DelayedRegistry ++ // for the non-builtin Registry instances stored as fields in Registry. ++ return registry.get(); ++ } else if (entry instanceof DelayedRegistryEntry) { ++ // if the registry doesn't exist and the entry is marked as "delayed", we create a registry holder that is empty ++ // which will later be filled with the actual registry. This is so the fields on org.bukkit.Registry can be populated with ++ // registries that don't exist at the time org.bukkit.Registry is statically initialized. ++ final RegistryHolder delayedHolder = new RegistryHolder.Delayed<>(); ++ this.registries.put(registryKey, delayedHolder); ++ return delayedHolder.get(); ++ } else { ++ // if the registry doesn't exist yet or doesn't have a delayed entry, just return null ++ return null; ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Override ++ public Registry getRegistry(final RegistryKey key) { ++ if (PaperRegistries.getEntry(key) == null) { ++ throw new NoSuchElementException(key + " is not a valid registry key"); ++ } ++ final @Nullable RegistryHolder registryHolder = (RegistryHolder) 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 Registry possiblyUnwrap(final Registry registry) { ++ if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry ++ return delayedRegistry.delegate(); ++ } ++ return registry; ++ } ++ ++ public void registerReloadableRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { ++ this.registerRegistry(resourceKey, registry, true); ++ } ++ ++ public void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry) { ++ this.registerRegistry(resourceKey, registry, false); ++ } ++ ++ @SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server. ++ private > void registerRegistry(final ResourceKey> resourceKey, final net.minecraft.core.Registry registry, final boolean replace) { ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(resourceKey); ++ if (entry == null) { // skip registries that don't have API entries ++ return; ++ } ++ final @Nullable RegistryHolder registryHolder = (RegistryHolder) this.registries.get(entry.apiKey()); ++ if (registryHolder == null || replace) { ++ // if the holder doesn't exist yet, or is marked as "replaceable", put it in the map. ++ this.registries.put(entry.apiKey(), entry.createRegistryHolder(registry)); ++ } else { ++ if (registryHolder instanceof RegistryHolder.Delayed && entry instanceof final DelayedRegistryEntry delayedEntry) { ++ // if the registry holder is delayed, and the entry is marked as "delayed", then load the holder with the CraftRegistry instance that wraps the actual nms Registry. ++ ((RegistryHolder.Delayed) registryHolder).loadFrom(delayedEntry, registry); ++ } else { ++ throw new IllegalArgumentException(resourceKey + " has already been created"); ++ } ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated ++ @VisibleForTesting ++ public static @Nullable RegistryKey byType(final Class type) { ++ return (RegistryKey) LegacyRegistryIdentifiers.CLASS_TO_KEY_MAP.get(type); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryHolder.java b/src/main/java/io/papermc/paper/registry/RegistryHolder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..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 { ++ ++ Registry get(); ++ ++ final class Memoized> implements RegistryHolder { ++ ++ private final Supplier memoizedSupplier; ++ ++ public Memoized(final Supplier supplier) { ++ this.memoizedSupplier = Suppliers.memoize(supplier::get); ++ } ++ ++ public Registry get() { ++ return this.memoizedSupplier.get(); ++ } ++ } ++ ++ final class Delayed> implements RegistryHolder { ++ ++ private final DelayedRegistry delayedRegistry = new DelayedRegistry<>(); ++ ++ @Override ++ public DelayedRegistry get() { ++ return this.delayedRegistry; ++ } ++ ++ void loadFrom(final DelayedRegistryEntry delayedEntry, final net.minecraft.core.Registry registry) { ++ final RegistryHolder delegateHolder = delayedEntry.delegate().createRegistryHolder(registry); ++ if (!(delegateHolder instanceof RegistryHolder.Memoized)) { ++ throw new IllegalArgumentException(delegateHolder + " must be a memoized holder"); ++ } ++ this.delayedRegistry.load(((Memoized) 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 extends BaseRegistryEntry> { ++ ++ private final Supplier> registrySupplier; ++ ++ protected ApiRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Supplier> registrySupplier ++ ) { ++ super(mcKey, apiKey); ++ this.registrySupplier = registrySupplier; ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry 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> implements RegistryEntry { // TODO remove Keyed ++ ++ private final ResourceKey> minecraftRegistryKey; ++ private final RegistryKey apiRegistryKey; ++ ++ protected BaseRegistryEntry(final ResourceKey> minecraftRegistryKey, final RegistryKey apiRegistryKey) { ++ this.minecraftRegistryKey = minecraftRegistryKey; ++ this.apiRegistryKey = apiRegistryKey; ++ } ++ ++ @Override ++ public final ResourceKey> mcKey() { ++ return this.minecraftRegistryKey; ++ } ++ ++ @Override ++ public final RegistryKey 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 extends BaseRegistryEntry> { // TODO remove Keyed ++ ++ protected final Class classToPreload; ++ protected final BiFunction minecraftToBukkit; ++ ++ protected CraftRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class classToPreload, ++ final BiFunction minecraftToBukkit ++ ) { ++ super(mcKey, apiKey); ++ this.classToPreload = classToPreload; ++ this.minecraftToBukkit = minecraftToBukkit; ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return new RegistryHolder.Memoized<>(() -> this.createApiRegistry(nmsRegistry)); ++ } ++ ++ private CraftRegistry createApiRegistry(final Registry 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> extends RegistryEntryInfo { // TODO remove Keyed ++ ++ RegistryHolder createRegistryHolder(Registry nmsRegistry); ++ ++ /** ++ * This should only be used if the registry instance needs to exist early due to the need ++ * to populate a field in {@link org.bukkit.Registry}. Data-driven registries shouldn't exist ++ * as fields, but instead be obtained via {@link io.papermc.paper.registry.RegistryAccess#getRegistry(RegistryKey)} ++ */ ++ @Deprecated ++ default RegistryEntry delayed() { ++ return new DelayedRegistryEntry<>(this); ++ } ++ ++ static RegistryEntry> entry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class classToPreload, ++ final BiFunction minecraftToBukkit ++ ) { ++ return new CraftRegistryEntry<>(mcKey, apiKey, classToPreload, minecraftToBukkit); ++ } ++ ++ static RegistryEntry> apiOnly( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Supplier> 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 { ++ ++ ResourceKey> mcKey(); ++ ++ RegistryKey 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> implements Registry { ++ ++ private @MonotonicNonNull Supplier delegate; ++ ++ public void load(final Supplier registry) { ++ if (this.delegate != null) { ++ throw new IllegalStateException("Registry already loaded!"); ++ } ++ this.delegate = registry; ++ } ++ ++ public Registry delegate() { ++ if (this.delegate == null) { ++ throw new IllegalStateException("You are trying to access this registry too early!"); ++ } ++ return this.delegate.get(); ++ } ++ ++ @Override ++ public @Nullable T get(final NamespacedKey key) { ++ return this.delegate().get(key); ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return this.delegate().iterator(); ++ } ++ ++ @Override ++ public Stream stream() { ++ return this.delegate().stream(); ++ } ++ ++ @Override ++ public NamespacedKey getKey(final T value) { ++ return this.delegate().getKey(value); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..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>(RegistryEntry delegate) implements RegistryEntry { ++ ++ @Override ++ public ResourceKey> mcKey() { ++ return this.delegate.mcKey(); ++ } ++ ++ @Override ++ public RegistryKey apiKey() { ++ return this.delegate.apiKey(); ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return this.delegate.createRegistryHolder(nmsRegistry); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +new file mode 100644 +index 0000000000000000000000000000000000000000..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, RegistryKey> CLASS_TO_KEY_MAP; ++ ++ static { ++ final ImmutableMap.Builder, RegistryKey> builder = ImmutableMap.builder(); ++ try { ++ for (final Field field : RegistryKey.class.getFields()) { ++ if (field.getType() == RegistryKey.class) { ++ // get the legacy type from the RegistryKey generic parameter on the field ++ final Class legacyType = 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> key, R registry, BuiltInRegistries.RegistryBootstrap initializer + ) { + Bootstrap.checkBootstrapCalled(() -> "registry " + key); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(registry.key(), registry); // Paper - initialize API registry + ResourceLocation resourceLocation = key.location(); + LOADERS.put(resourceLocation, () -> initializer.run(registry)); + WRITABLE_REGISTRY.register((ResourceKey)key, registry, RegistrationInfo.BUILT_IN); // Paper - decompile fix +diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +index 1a40a600b8a9716ef26f3143f361a47b76ec2510..d59356df2d98de873fc5accc749f87fa3d685267 100644 +--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java ++++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +@@ -284,6 +284,7 @@ public class RegistryDataLoader { + public static record RegistryData(ResourceKey> key, Codec elementCodec) { + RegistryDataLoader.Loader create(Lifecycle lifecycle, Map, Exception> errors) { + WritableRegistry writableRegistry = new MappedRegistry<>(this.key, lifecycle); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerRegistry(this.key, writableRegistry); // Paper - initialize API registry + return new RegistryDataLoader.Loader<>(this, writableRegistry, errors); + } + +diff --git a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +index cf08819dd7ef6db807053a52aaf66a7fdea18ab6..69682d7be64a2163d574de939f5146f5a7a642ef 100644 +--- a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java ++++ b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +@@ -60,6 +60,7 @@ public class ReloadableServerRegistries { + return CompletableFuture.supplyAsync( + () -> { + WritableRegistry writableRegistry = new MappedRegistry<>(type.registryKey(), Lifecycle.experimental()); ++ io.papermc.paper.registry.PaperRegistryAccess.instance().registerReloadableRegistry(type.registryKey(), writableRegistry); // Paper - register reloadable registry + Map map = new HashMap<>(); + SimpleJsonResourceReloadListener.scanDirectory(resourceManager, type.directory(), GSON, map); + map.forEach( +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index 4209a45af2bfe772f678b07b49070522de4195a8..e2fcbeb8635280fcd2aeedff9803386c9bcabb0c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -100,55 +100,15 @@ public class CraftRegistry implements Registry { + + ", this can happen if a plugin creates its own registry entry with out properly registering it."); + } + +- /** +- * Note: Newly added registries should also be added to RegistriesArgumentProvider in the test package +- * +- * @param bukkitClass the bukkit class of the registry +- * @param registryHolder the minecraft registry holder +- * @return the bukkit registry of the provided class +- */ +- public static Registry createRegistry(Class bukkitClass, RegistryAccess registryHolder) { +- if (bukkitClass == Enchantment.class) { +- return new CraftRegistry<>(Enchantment.class, registryHolder.registryOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new); +- } +- if (bukkitClass == GameEvent.class) { +- return new CraftRegistry<>(GameEvent.class, registryHolder.registryOrThrow(Registries.GAME_EVENT), CraftGameEvent::new); +- } +- if (bukkitClass == MusicInstrument.class) { +- return new CraftRegistry<>(MusicInstrument.class, registryHolder.registryOrThrow(Registries.INSTRUMENT), CraftMusicInstrument::new); +- } +- if (bukkitClass == PotionEffectType.class) { +- return new CraftRegistry<>(PotionEffectType.class, registryHolder.registryOrThrow(Registries.MOB_EFFECT), CraftPotionEffectType::new); +- } +- if (bukkitClass == Structure.class) { +- return new CraftRegistry<>(Structure.class, registryHolder.registryOrThrow(Registries.STRUCTURE), CraftStructure::new); +- } +- if (bukkitClass == StructureType.class) { +- return new CraftRegistry<>(StructureType.class, BuiltInRegistries.STRUCTURE_TYPE, CraftStructureType::new); +- } +- if (bukkitClass == TrimMaterial.class) { +- return new CraftRegistry<>(TrimMaterial.class, registryHolder.registryOrThrow(Registries.TRIM_MATERIAL), CraftTrimMaterial::new); +- } +- if (bukkitClass == TrimPattern.class) { +- return new CraftRegistry<>(TrimPattern.class, registryHolder.registryOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new); +- } +- if (bukkitClass == DamageType.class) { +- return new CraftRegistry<>(DamageType.class, registryHolder.registryOrThrow(Registries.DAMAGE_TYPE), CraftDamageType::new); +- } +- if (bukkitClass == Wolf.Variant.class) { +- return new CraftRegistry<>(Wolf.Variant.class, registryHolder.registryOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new); +- } +- +- return null; +- } ++ // Paper - move to PaperRegistries + +- private final Class bukkitClass; ++ private final Class bukkitClass; // Paper - relax preload class + private final Map cache = new HashMap<>(); + private final net.minecraft.core.Registry minecraftRegistry; + private final BiFunction minecraftToBukkit; + private boolean init; + +- public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit) { ++ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit) { // Paper - relax preload class + this.bukkitClass = bukkitClass; + this.minecraftRegistry = minecraftRegistry; + this.minecraftToBukkit = minecraftToBukkit; +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 1460060f2ff42ebaa7b2418b375ce661c73bd17f..2c89ba2b518618640064ebea22d3d9595407bad7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -283,7 +283,7 @@ public final class CraftServer implements Server { + protected final DedicatedServer console; + protected final DedicatedPlayerList playerList; + private final Map worlds = new LinkedHashMap(); +- private final Map, Registry> registries = new HashMap<>(); ++ // private final Map, Registry> registries = new HashMap<>(); // Paper - replace with RegistryAccess + private YamlConfiguration configuration; + private YamlConfiguration commandsConfiguration; + private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); +@@ -2693,7 +2693,7 @@ public final class CraftServer implements Server { + + @Override + public Registry getRegistry(Class aClass) { +- return (Registry) this.registries.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, this.console.registryAccess())); ++ return io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(aClass); // Paper - replace with RegistryAccess + } + + @Deprecated +diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +new file mode 100644 +index 0000000000000000000000000000000000000000..8a083d45004f82fc9c51c219fb20f34624adb501 +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.PaperRegistryAccess +diff --git a/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b9d00e65639521eecd44bd2be3e012264c3785f5 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.GameEvent; ++import org.bukkit.MusicInstrument; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertSame; ++ ++@Deprecated ++class LegacyRegistryIdentifierTest extends AbstractTestingBase { ++ ++ @Test ++ void testSeveralConversions() { ++ assertSame(RegistryKey.GAME_EVENT, PaperRegistryAccess.byType(GameEvent.class)); ++ assertSame(RegistryKey.TRIM_PATTERN, PaperRegistryAccess.byType(TrimPattern.class)); ++ assertSame(RegistryKey.INSTRUMENT, PaperRegistryAccess.byType(MusicInstrument.class)); ++ } ++} +diff --git a/src/test/java/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 = 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> loadedRegistries = new HashSet<>(DummyServer.registers.keySet()); +- Set> notFound = new HashSet<>(); ++ // Paper start ++ Set> loadedRegistries = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap<>()); ++ loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().getLoadedServerBackedRegistries()); ++ // Paper end ++ Set> notFound = new HashSet<>(); // Paper + + RegistriesArgumentProvider + .getData() + .map(Arguments::get) + .map(array -> array[0]) +- .map(clazz -> (Class) clazz) ++ .map(clazz -> (io.papermc.paper.registry.RegistryKey) clazz) // Paper + .forEach(clazz -> { + if (!loadedRegistries.remove(clazz)) { + notFound.add(clazz); +diff --git a/src/test/java/org/bukkit/registry/RegistryConversionTest.java b/src/test/java/org/bukkit/registry/RegistryConversionTest.java +index 8c6b7f9804cf56269cc5a1b5924db2d2bf556f88..782c2ce424fc124e18145615187dc1e9d33f80ae 100644 +--- a/src/test/java/org/bukkit/registry/RegistryConversionTest.java ++++ b/src/test/java/org/bukkit/registry/RegistryConversionTest.java +@@ -37,9 +37,9 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(1) + @RegistriesTest +- public void testHandleableImplementation(Class clazz) { ++ public void testHandleableImplementation(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + Set> notImplemented = new HashSet<>(); +- Registry registry = Bukkit.getRegistry(clazz); ++ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(type); // Paper + + for (Keyed item : registry) { + if (!(item instanceof Handleable)) { +@@ -59,7 +59,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(2) + @RegistriesTest +- public void testMinecraftToBukkitPresent(Class clazz, ResourceKey> registryKey, ++ public void testMinecraftToBukkitPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) { + Method method = null; + try { +@@ -107,7 +107,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(2) + @RegistriesTest +- public void testBukkitToMinecraftPresent(Class clazz, ResourceKey> registryKey, ++ public void testBukkitToMinecraftPresent(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) { + Method method = null; + try { +@@ -153,9 +153,9 @@ public class RegistryConversionTest extends AbstractTestingBase { + """, minecraftClazz.getName(), clazz.getSimpleName()); + } + +- @Order(2) ++ @Order(3) + @RegistriesTest +- public void testMinecraftToBukkitNullValue(Class clazz) throws IllegalAccessException { ++ public void testMinecraftToBukkitNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper + this.checkValidMinecraftToBukkit(clazz); + + try { +@@ -174,7 +174,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(3) + @RegistriesTest +- public void testBukkitToMinecraftNullValue(Class clazz) throws IllegalAccessException { ++ public void testBukkitToMinecraftNullValue(io.papermc.paper.registry.RegistryKey type, Class clazz) throws IllegalAccessException { // Paper + this.checkValidBukkitToMinecraft(clazz); + + try { +@@ -193,14 +193,14 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(3) + @RegistriesTest +- public void testMinecraftToBukkit(Class clazz) { ++ public void testMinecraftToBukkit(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + this.checkValidMinecraftToBukkit(clazz); + this.checkValidHandle(clazz); + + Map notMatching = new HashMap<>(); + Method method = RegistryConversionTest.MINECRAFT_TO_BUKKIT_METHODS.get(clazz); + +- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { ++ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper + Keyed bukkit = (Keyed) arguments[0]; + Object minecraft = arguments[1]; + +@@ -224,14 +224,14 @@ public class RegistryConversionTest extends AbstractTestingBase { + + @Order(3) + @RegistriesTest +- public void testBukkitToMinecraft(Class clazz) { ++ public void testBukkitToMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz) { // Paper + this.checkValidBukkitToMinecraft(clazz); + this.checkValidHandle(clazz); + + Map notMatching = new HashMap<>(); + Method method = RegistryConversionTest.BUKKIT_TO_MINECRAFT_METHODS.get(clazz); + +- RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> { ++ RegistryArgumentProvider.getValues(type).map(Arguments::get).forEach(arguments -> { // Paper + Keyed bukkit = (Keyed) arguments[0]; + Object minecraft = arguments[1]; + +@@ -259,7 +259,7 @@ public class RegistryConversionTest extends AbstractTestingBase { + */ + @Order(3) + @RegistriesTest +- public void testMinecraftToBukkitNoValidMinecraft(Class clazz, ResourceKey> registryKey, ++ public void testMinecraftToBukkitNoValidMinecraft(io.papermc.paper.registry.RegistryKey type, Class clazz, ResourceKey> registryKey, // Paper + Class craftClazz, Class minecraftClazz) throws IllegalAccessException { + this.checkValidMinecraftToBukkit(clazz); + +diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java +index 7a4681155f740a98ecafa0b992eae1fb5524551f..bd56792fc674c4e3606a3179ebf5a84ef0a4e35c 100644 +--- a/src/test/java/org/bukkit/support/DummyServer.java ++++ b/src/test/java/org/bukkit/support/DummyServer.java +@@ -45,10 +45,7 @@ public final class DummyServer { + when(instance.getLootTable(any())).then(mock -> new CraftLootTable(mock.getArgument(0), + AbstractTestingBase.DATA_PACK.fullRegistries().getLootTable(ResourceKey.create(Registries.LOOT_TABLE, CraftNamespacedKey.toMinecraft(mock.getArgument(0)))))); + +- when(instance.getRegistry(any())).then((Answer>) mock -> { +- Class aClass = mock.getArgument(0); +- return registers.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, AbstractTestingBase.REGISTRY_CUSTOM)); +- }); ++ // Paper - RegistryAccess + + // Paper start - testing additions + final Thread currentThread = Thread.currentThread(); +diff --git a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +index 342ea2914b361f39708bf0d8a39385c62d340c30..69a6a8419947a0617405e8931193f88d0dc5c3c4 100644 +--- a/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java ++++ b/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +@@ -1,6 +1,7 @@ + package org.bukkit.support.provider; + + import com.google.common.collect.Lists; ++import io.papermc.paper.registry.RegistryKey; + import java.util.List; + import java.util.stream.Stream; + import net.minecraft.core.registries.Registries; +@@ -37,16 +38,17 @@ public class RegistriesArgumentProvider implements ArgumentsProvider { + + static { + // Order: Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class +- DATA.add(Arguments.of(Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class)); +- DATA.add(Arguments.of(GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class)); +- DATA.add(Arguments.of(MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class)); +- DATA.add(Arguments.of(PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class)); +- DATA.add(Arguments.of(Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class)); +- DATA.add(Arguments.of(StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class)); +- DATA.add(Arguments.of(TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.armortrim.TrimMaterial.class)); +- DATA.add(Arguments.of(TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.armortrim.TrimPattern.class)); +- DATA.add(Arguments.of(DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class)); +- DATA.add(Arguments.of(Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, WolfVariant.class)); ++ // Order: RegistryKey, Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class ++ DATA.add(Arguments.of(RegistryKey.ENCHANTMENT, Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class)); ++ DATA.add(Arguments.of(RegistryKey.GAME_EVENT, GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class)); ++ DATA.add(Arguments.of(RegistryKey.INSTRUMENT, MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class)); ++ DATA.add(Arguments.of(RegistryKey.MOB_EFFECT, PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffect.class)); ++ DATA.add(Arguments.of(RegistryKey.STRUCTURE, Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class)); ++ DATA.add(Arguments.of(RegistryKey.STRUCTURE_TYPE, StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class)); ++ DATA.add(Arguments.of(RegistryKey.TRIM_MATERIAL, TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.armortrim.TrimMaterial.class)); ++ DATA.add(Arguments.of(RegistryKey.TRIM_PATTERN, TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.armortrim.TrimPattern.class)); ++ DATA.add(Arguments.of(RegistryKey.DAMAGE_TYPE, DamageType.class, Registries.DAMAGE_TYPE, CraftDamageType.class, net.minecraft.world.damagesource.DamageType.class)); ++ DATA.add(Arguments.of(RegistryKey.WOLF_VARIANT, Wolf.Variant.class, Registries.WOLF_VARIANT, CraftWolf.CraftVariant.class, net.minecraft.world.entity.animal.WolfVariant.class)); + } + + @Override +diff --git a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java +index f2ceb5e67536dfa5de792dc64a7898fd2e8aa810..beb5fc9e721f5de54064c3d241df9ca9f4cd4f65 100644 +--- a/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java ++++ b/src/test/java/org/bukkit/support/provider/RegistryArgumentProvider.java +@@ -22,11 +22,11 @@ public class RegistryArgumentProvider implements ArgumentsProvider, AnnotationCo + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { +- return RegistryArgumentProvider.getValues(this.registryType); ++ return RegistryArgumentProvider.getValues(io.papermc.paper.registry.PaperRegistryAccess.byType(this.registryType)); // Paper + } + +- public static Stream getValues(Class registryType) { +- Registry registry = Bukkit.getRegistry(registryType); ++ public static Stream getValues(io.papermc.paper.registry.RegistryKey registryType) { // Paper ++ Registry registry = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(registryType); // Paper + return registry.stream().map(keyed -> (Handleable) keyed) + .map(handleAble -> Arguments.of(handleAble, handleAble.getHandle())); + } diff --git a/patches/server/0485-TODO-Registry-Modification-API.patch b/patches/server/0485-TODO-Registry-Modification-API.patch deleted file mode 100644 index d624aad69b..0000000000 --- a/patches/server/0485-TODO-Registry-Modification-API.patch +++ /dev/null @@ -1,18 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 27 Feb 2023 18:28:39 -0800 -Subject: [PATCH] TODO Registry Modification API - - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 4209a45af2bfe772f678b07b49070522de4195a8..480313506bf41410de090c59e047323345ea78da 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -138,6 +138,7 @@ public class CraftRegistry implements Registry { - if (bukkitClass == Wolf.Variant.class) { - return new CraftRegistry<>(Wolf.Variant.class, registryHolder.registryOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new); - } -+ // TODO registry modification API - - return null; - } diff --git a/patches/server/0486-Add-StructuresLocateEvent.patch b/patches/server/0486-Add-StructuresLocateEvent.patch index 4e44861dd1..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 +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 CONFIGURED_STRUCTURE_REGISTRY_KEY = RegistryKeyImpl.createInternal("worldgen/structure"); ++ @Deprecated(forRemoval = true) ++ static final RegistryEntry CONFIGURED_STRUCTURE_REGISTRY_ENTRY = entry(Registries.STRUCTURE, CONFIGURED_STRUCTURE_REGISTRY_KEY, io.papermc.paper.world.structure.ConfiguredStructure.class, io.papermc.paper.world.structure.PaperConfiguredStructure::minecraftToBukkit).delayed(); ++ + static final List> REGISTRY_ENTRIES; + private static final Map, RegistryEntry> BY_REGISTRY_KEY; + private static final Map, RegistryEntry> BY_RESOURCE_KEY; +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +index 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 @Nullable Registry getRegistry(final Class type) { + final RegistryKey registryKey; + final @Nullable RegistryEntry entry; +- registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type"); +- entry = PaperRegistries.getEntry(registryKey); ++ if (type == io.papermc.paper.world.structure.ConfiguredStructure.class) { // manually handle "duplicate" registries to avoid polluting maps in PaperRegistries ++ registryKey = (RegistryKey) PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_KEY; ++ entry = (RegistryEntry) PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_ENTRY; ++ } else { ++ registryKey = requireNonNull(byType(type), () -> type + " is not a valid registry type"); ++ entry = PaperRegistries.getEntry(registryKey); ++ } + final @Nullable RegistryHolder registry = (RegistryHolder) this.registries.get(registryKey); + if (registry != null) { + // if the registry exists, return right away. Since this is the "legacy" method, we return DelayedRegistry diff --git a/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java new file mode 100644 -index 0000000000000000000000000000000000000000..2667067fd13f61e0464ba88ae4e4a7078351d1a8 +index 0000000000000000000000000000000000000000..013d614a1cf1ab2b5a6ec190c2b4ba7753268731 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/structure/PaperConfiguredStructure.java -@@ -0,0 +1,35 @@ +@@ -0,0 +1,27 @@ +package io.papermc.paper.world.structure; + +import java.util.Objects; @@ -32,18 +69,10 @@ index 0000000000000000000000000000000000000000..2667067fd13f61e0464ba88ae4e4a707 + private PaperConfiguredStructure() { + } + -+ @Deprecated(forRemoval = true) -+ public static final class LegacyRegistry extends CraftRegistry { -+ -+ public LegacyRegistry(final Registry minecraftRegistry) { -+ super(ConfiguredStructure.class, minecraftRegistry, LegacyRegistry::minecraftToBukkit); -+ } -+ -+ private static @Nullable ConfiguredStructure minecraftToBukkit(NamespacedKey key, Structure nms) { -+ final ResourceLocation structureTypeLoc = Objects.requireNonNull(BuiltInRegistries.STRUCTURE_TYPE.getKey(nms.type()), "unexpected structure type " + nms.type()); -+ final @Nullable StructureType structureType = StructureType.getStructureTypes().get(structureTypeLoc.getPath()); -+ return structureType == null ? null : new ConfiguredStructure(key, structureType); -+ } ++ public static @Nullable ConfiguredStructure minecraftToBukkit(NamespacedKey key, Structure nms) { ++ final ResourceLocation structureTypeLoc = Objects.requireNonNull(BuiltInRegistries.STRUCTURE_TYPE.getKey(nms.type()), "unexpected structure type " + nms.type()); ++ final @Nullable StructureType structureType = StructureType.getStructureTypes().get(structureTypeLoc.getPath()); ++ return structureType == null ? null : new ConfiguredStructure(key, structureType); + } +} diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -75,22 +104,6 @@ index 7cdb59cd2f2ffe1195d21519ef97dae0e430285b..a8768f1925d5824ca985be1b53694ee2 ChunkGeneratorStructureState chunkgeneratorstructurestate = world.getChunkSource().getGeneratorState(); Map>> map = new Object2ObjectArrayMap(); Iterator iterator = structures.iterator(); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 480313506bf41410de090c59e047323345ea78da..c7d377dbb53cdc1f823a839e3a113136efc16349 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -139,6 +139,11 @@ public class CraftRegistry implements Registry { - return new CraftRegistry<>(Wolf.Variant.class, registryHolder.registryOrThrow(Registries.WOLF_VARIANT), CraftWolf.CraftVariant::new); - } - // TODO registry modification API -+ // Paper start - remove this after a while along with all ConfiguredStructure stuff -+ if (bukkitClass == io.papermc.paper.world.structure.ConfiguredStructure.class) { -+ return new io.papermc.paper.world.structure.PaperConfiguredStructure.LegacyRegistry(registryHolder.registryOrThrow(Registries.STRUCTURE)); -+ } -+ // Paper end - - return null; - } diff --git a/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java b/src/test/java/io/papermc/paper/world/structure/ConfiguredStructureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9178fe0d01b998ca1442bf2511f8fc00db9388ba @@ -194,26 +207,26 @@ index 0000000000000000000000000000000000000000..9178fe0d01b998ca1442bf2511f8fc00 + } +} diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java -index 4e4ea083063daf22f1bb785ef212958ea889c43b..1c4966520b6401e6571aa44d5934dfa280bc80e3 100644 +index 4e4ea083063daf22f1bb785ef212958ea889c43b..523b4b208e05c6b70014440200e3196cc84f36cc 100644 --- a/src/test/java/org/bukkit/registry/PerRegistryTest.java +++ b/src/test/java/org/bukkit/registry/PerRegistryTest.java @@ -36,6 +36,7 @@ public class PerRegistryTest extends AbstractTestingBase { if (!(object instanceof CraftRegistry registry)) { continue; } -+ if (object instanceof io.papermc.paper.world.structure.PaperConfiguredStructure.LegacyRegistry) continue; // Paper - skip ++ if (object == Registry.CONFIGURED_STRUCTURE) continue; // Paper - skip data.add(Arguments.of(registry)); } catch (ReflectiveOperationException e) { diff --git a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java b/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java -index 4adaafafb7140e983a4e90f0ff0deaaf0887a9a5..65cc33c45553e755371ec4313dd38bb61eb7d61c 100644 +index 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> loadedRegistries = new HashSet<>(DummyServer.registers.keySet()); - Set> notFound = new HashSet<>(); -+ loadedRegistries.remove(io.papermc.paper.world.structure.ConfiguredStructure.class); // Paper - ignore +@@ -26,6 +26,7 @@ public class RegistryArgumentAddedTest extends AbstractTestingBase { + loadedRegistries.addAll(io.papermc.paper.registry.PaperRegistryAccess.instance().getLoadedServerBackedRegistries()); + // Paper end + Set> notFound = new HashSet<>(); // Paper ++ loadedRegistries.remove(io.papermc.paper.registry.PaperRegistries.CONFIGURED_STRUCTURE_REGISTRY_KEY); // Paper - ignore RegistriesArgumentProvider .getData() diff --git a/patches/server/0940-Improve-Registry.patch b/patches/server/0940-Improve-Registry.patch index 0d7c6b94e6..2f8634794b 100644 --- a/patches/server/0940-Improve-Registry.patch +++ b/patches/server/0940-Improve-Registry.patch @@ -5,18 +5,18 @@ Subject: [PATCH] Improve Registry diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index c7d377dbb53cdc1f823a839e3a113136efc16349..73472890e30180dc3cb6aa1bd9c5815087334682 100644 +index e2fcbeb8635280fcd2aeedff9803386c9bcabb0c..a3a00778a8fdbc13f8adbf4e4fbc4f1303d22789 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -150,6 +150,7 @@ public class CraftRegistry implements Registry { +@@ -104,6 +104,7 @@ public class CraftRegistry implements Registry { - private final Class bukkitClass; + private final Class bukkitClass; // Paper - relax preload class private final Map cache = new HashMap<>(); + private final Map byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry private final net.minecraft.core.Registry minecraftRegistry; private final BiFunction minecraftToBukkit; private boolean init; -@@ -194,6 +195,7 @@ public class CraftRegistry implements Registry { +@@ -148,6 +149,7 @@ public class CraftRegistry implements Registry { } this.cache.put(namespacedKey, bukkit); @@ -24,7 +24,7 @@ index c7d377dbb53cdc1f823a839e3a113136efc16349..73472890e30180dc3cb6aa1bd9c58150 return bukkit; } -@@ -216,4 +218,11 @@ public class CraftRegistry implements Registry { +@@ -170,4 +172,11 @@ public class CraftRegistry implements Registry { return this.minecraftToBukkit.apply(namespacedKey, minecraft); } @@ -61,7 +61,7 @@ index 364f8d7a7106259401154d91b1b79869d014a469..f336bf98574e4fdeabc3b21062983439 } diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java -index 1c4966520b6401e6571aa44d5934dfa280bc80e3..010de6fbb75eb5d51639695d260f916072fdb22d 100644 +index 523b4b208e05c6b70014440200e3196cc84f36cc..12b93a6e091de47522d060fa0cd84fe41318c46a 100644 --- a/src/test/java/org/bukkit/registry/PerRegistryTest.java +++ b/src/test/java/org/bukkit/registry/PerRegistryTest.java @@ -49,19 +49,22 @@ public class PerRegistryTest extends AbstractTestingBase { 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