From 956b5efa5f95a685a246b24cc14bdaea4f84bc41 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 25 Feb 2023 13:47:13 -0800 Subject: [PATCH] Registry Modification API --- .../paper/registry/keys/EnchantmentKeys.java | 308 ++++ .../paper/registry/keys/MobEffectKeys.java | 266 ++++ .../registry/keys/MusicInstrumentKeys.java | 91 ++ .../java/io/papermc/generator/Generators.java | 6 + patches/api/0004-Code-Generation.patch | 32 +- patches/api/0246-Add-PaperRegistry.patch | 92 -- .../api/0246-Registry-Modification-API.patch | 699 +++++++++ .../api/0247-Add-StructuresLocateEvent.patch | 11 +- patches/api/0282-Add-basic-Datapack-API.patch | 8 +- .../api/0342-More-PotionEffectType-API.patch | 6 +- patches/api/0349-Custom-Potion-Mixes.patch | 8 +- ...Folia-scheduler-and-owned-region-API.patch | 8 +- patches/api/0448-Improve-Registry.patch | 10 +- ...port-registry-mod-API-with-GameEvent.patch | 85 ++ patches/server/0013-Paper-Plugins.patch | 26 +- .../0497-Registry-Modification-API.patch | 1354 +++++++++++++++++ .../0497-TODO-Registry-Modification-API.patch | 18 - .../0498-Add-StructuresLocateEvent.patch | 48 +- patches/server/0979-Improve-Registry.patch | 20 +- ...0999-Flat-bedrock-generator-settings.patch | 6 +- ...port-registry-mod-API-with-GameEvent.patch | 80 + .../io/papermc/testplugin/TestPlugin.java | 10 + .../testplugin/TestPluginBootstrap.java | 24 +- 23 files changed, 3012 insertions(+), 204 deletions(-) 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/MobEffectKeys.java create mode 100644 paper-api-generator/generated/io/papermc/paper/registry/keys/MusicInstrumentKeys.java delete mode 100644 patches/api/0246-Add-PaperRegistry.patch create mode 100644 patches/api/0246-Registry-Modification-API.patch create mode 100644 patches/api/0460-Support-registry-mod-API-with-GameEvent.patch create mode 100644 patches/server/0497-Registry-Modification-API.patch delete mode 100644 patches/server/0497-TODO-Registry-Modification-API.patch create mode 100644 patches/server/1047-Support-registry-mod-API-with-GameEvent.patch 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..d5bee199d8 --- /dev/null +++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/EnchantmentKeys.java @@ -0,0 +1,308 @@ +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.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.4") +@ApiStatus.Experimental +public final class EnchantmentKeys { + /** + * {@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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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:sweeping} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SWEEPING = create(key("sweeping")); + + /** + * {@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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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")); + + 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/MobEffectKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java new file mode 100644 index 0000000000..4e11ecb245 --- /dev/null +++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/MobEffectKeys.java @@ -0,0 +1,266 @@ +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.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.4") +@ApiStatus.Experimental +public final class MobEffectKeys { + /** + * {@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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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:darkness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey DARKNESS = create(key("darkness")); + + 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/MusicInstrumentKeys.java b/paper-api-generator/generated/io/papermc/paper/registry/keys/MusicInstrumentKeys.java new file mode 100644 index 0000000000..11c4c10502 --- /dev/null +++ b/paper-api-generator/generated/io/papermc/paper/registry/keys/MusicInstrumentKeys.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.4") +@ApiStatus.Experimental +public final class MusicInstrumentKeys { + /** + * {@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: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: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: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: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: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")); + + /** + * {@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")); + + private MusicInstrumentKeys() { + } + + private static @NotNull TypedKey create(final @NotNull Key key) { + return TypedKey.create(RegistryKey.INSTRUMENT, 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..05b2142c3f 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,11 +8,14 @@ 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.enchantments.Enchantment; 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 { @@ -23,6 +26,9 @@ public interface Generators { 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("MusicInstrumentKeys", 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), new MobGoalGenerator("VanillaGoal", "com.destroystokyo.paper.entity.ai") }; diff --git a/patches/api/0004-Code-Generation.patch b/patches/api/0004-Code-Generation.patch index 294139088b..7acd7bdba4 100644 --- a/patches/api/0004-Code-Generation.patch +++ b/patches/api/0004-Code-Generation.patch @@ -7,7 +7,7 @@ Currently includes generated key holder classes for types used in the Registry Modification API diff --git a/build.gradle.kts b/build.gradle.kts -index 948bd84db9923ef43cf753b7b72bf4d0081ab43a..4ee1aed72727e911bff4ac91bcacfd8eee87ecfc 100644 +index 479865c7ae668b061a2e035de719a2ef98c5b0bf..b9bf992867115fe6e84091a1a0b1f220de751699 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ @@ -85,19 +85,22 @@ 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..5dde0eac9aa6354f71a910aff1d5e484deef0a5d --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java -@@ -0,0 +1,67 @@ +@@ -0,0 +1,85 @@ +package io.papermc.paper.registry; + +import net.kyori.adventure.key.Keyed; +import org.bukkit.GameEvent; ++import org.bukkit.MusicInstrument; +import org.bukkit.block.Biome; ++import org.bukkit.enchantments.Enchantment; +import org.bukkit.generator.structure.Structure; +import org.bukkit.generator.structure.StructureType; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.potion.PotionEffectType; +import org.jetbrains.annotations.ApiStatus; + +import static io.papermc.paper.registry.RegistryKeyImpl.create; @@ -131,6 +134,21 @@ 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.MusicInstrumentKeys ++ */ ++ 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 * @@ -183,7 +201,7 @@ index 0000000000000000000000000000000000000000..9ad300fa1668cb59bbd85ff8091591db +} 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 +245,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 +261,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 2365a8c620be709b280fb08855752bb0995838fc..b63e24b3c4d2f1a08e39434caa527bb2e0edea22 100644 diff --git a/patches/api/0246-Add-PaperRegistry.patch b/patches/api/0246-Add-PaperRegistry.patch deleted file mode 100644 index 8cc1e1b931..0000000000 --- a/patches/api/0246-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/0246-Registry-Modification-API.patch b/patches/api/0246-Registry-Modification-API.patch new file mode 100644 index 0000000000..6b6aa93fa9 --- /dev/null +++ b/patches/api/0246-Registry-Modification-API.patch @@ -0,0 +1,699 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Mar 2022 13:36:21 -0800 +Subject: [PATCH] Registry Modification API + + +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..93a036c6532cb132ce4207dee43197b1002a14f3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/Reference.java +@@ -0,0 +1,46 @@ ++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 or not exist. These are mainly useful for {@link io.papermc.paper.plugin.bootstrap.PluginBootstrap}s ++ * to have access to the vanilla keys of types without requiring the value to exist yet. ++ * ++ * @param type of the value ++ */ ++@Deprecated(forRemoval = true) ++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 ++ */ ++ @Deprecated(forRemoval = true) ++ 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..ddc0247b169d586da8dcc6a383cd9e3ee4bc7744 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/ReferenceImpl.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry; ++ ++import java.util.NoSuchElementException; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++@Deprecated(forRemoval = true) ++record ReferenceImpl(@NotNull Registry registry, @NotNull NamespacedKey key) implements Reference { ++ ++ @Override ++ public @NotNull T value() { ++ final @Nullable 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..f9d5f3ed36062bb8a592fa58c5135180b22e9d85 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccess.java +@@ -0,0 +1,51 @@ ++package io.papermc.paper.registry; ++ ++import java.util.ServiceLoader; ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * The {@link #registryAccess} methods provides access to registries given a {@link RegistryKey}. ++ *

++ * Replacement for {@link org.bukkit.Bukkit#getRegistry(Class)}. ++ */ ++@ApiStatus.NonExtendable ++@ApiStatus.Experimental ++public interface RegistryAccess { ++ ++ /** ++ * Get the RegistryAccess for the server. ++ * ++ * @return the registry access ++ */ ++ static @NotNull RegistryAccess registryAccess() { ++ return RegistryAccessHolder.INSTANCE; ++ } ++ ++ /** ++ * 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)} ++ */ ++ @Deprecated ++ @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..e1b28e22b754d875c83eaca10f5a9228c02259ab +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryAccessHolder.java +@@ -0,0 +1,7 @@ ++package io.papermc.paper.registry; ++ ++import java.util.ServiceLoader; ++ ++interface RegistryAccessHolder { ++ RegistryAccess INSTANCE = ServiceLoader.load(RegistryAccess.class).iterator().next(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryBuilder.java b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2bec1f1d750e796e1d26c3cd090d53de2672170f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java +@@ -0,0 +1,11 @@ ++package io.papermc.paper.registry; ++ ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * To be implemented by any type used for modifying registries. ++ */ ++@ApiStatus.NonExtendable ++@ApiStatus.Experimental ++public interface RegistryBuilder { ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryView.java b/src/main/java/io/papermc/paper/registry/RegistryView.java +new file mode 100644 +index 0000000000000000000000000000000000000000..768f4370fc622b7a6c783fdd67a222f1e0570e1a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryView.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry; ++ ++import net.kyori.adventure.key.Key; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Provides read-only access to a registry. ++ * ++ * @param registry object type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryView extends Iterable { ++ ++ @Nullable T get(final @NotNull Key key); ++ ++ @NotNull T getOrThrow(final @NotNull Key key); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e70e0b79f300f6453b8f5a76defdb2300360f688 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEvent.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.TypedKey; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Event object for {@link RegistryEvents.Provider#addition()}. This ++ * event is fired right before a specific object is added to a registry. ++ * It provides a way for plugins to modify parts of this object. ++ * ++ * @param object type ++ * @param object builder type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryAdditionEvent> extends RegistryEvent { ++ ++ /** ++ * Gets the builder for the object being added to the registry. ++ * ++ * @return the object builder ++ */ ++ @NotNull B builder(); ++ ++ /** ++ * Gets the key for this object in the registry. ++ * ++ * @return the key ++ */ ++ @NotNull TypedKey key(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c4841b63fa4b6bf49d1e04339561d48ba8ae562d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java +@@ -0,0 +1,41 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.RegistryView; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Base type for all registry events. ++ * ++ * @param object type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryEvent extends LifecycleEvent { ++ ++ /** ++ * Get the key for the registry this event pertains to. ++ * ++ * @return the registry key ++ */ ++ @NotNull RegistryKey registryKey(); ++ ++ /** ++ * Get a view of the registry which may or may not ++ * be complete based on the event. ++ * ++ * @return a registry view ++ */ ++ @NotNull RegistryView registry(); ++ ++ /** ++ * Get the name of the event. ++ * ++ * @return the event name ++ */ ++ default @NotNull String eventName() { ++ return this.getClass().getSimpleName(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0df562062e6468617597a49abf88e116dd693935 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.ApiStatus; ++ ++@ApiStatus.Internal ++@DefaultQualifier(NonNull.class) ++record RegistryEventProviderImpl>(RegistryKey registryKey) implements RegistryEvents.Provider { ++ ++ static > RegistryEvents.Provider create(final RegistryKey registryKey) { ++ return new RegistryEventProviderImpl<>(registryKey); ++ } ++ ++ @Override ++ public LifecycleEventType.Prioritizable> addition() { ++ return RegistryEventTypeProvider.PROVIDER.registryAddition(this); ++ } ++ ++ @Override ++ public PrioritizedLifecycleEventHandlerConfiguration newAdditionHandler(final LifecycleEventHandler> handler) { ++ return this.addition().newHandler(handler); ++ } ++ ++ @Override ++ public LifecycleEventType.Prioritizable> preFreeze() { ++ return RegistryEventTypeProvider.PROVIDER.registryPreFreeze(this); ++ } ++ ++ @Override ++ public PrioritizedLifecycleEventHandlerConfiguration newPreFreezeHandler(final LifecycleEventHandler> handler) { ++ return this.preFreeze().newHandler(handler); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java +new file mode 100644 +index 0000000000000000000000000000000000000000..118306c85e7c861a0c4010ba9e37f15ca49498a7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import java.util.ServiceLoader; ++import org.jetbrains.annotations.ApiStatus; ++ ++@ApiStatus.Internal ++interface RegistryEventTypeProvider { ++ ++ RegistryEventTypeProvider PROVIDER = ServiceLoader.load(RegistryEventTypeProvider.class) ++ .findFirst() ++ .orElseThrow(); ++ ++ ++ > LifecycleEventType.Prioritizable> registryAddition(RegistryEvents.Provider type); ++ ++ > LifecycleEventType.Prioritizable> registryPreFreeze(RegistryEvents.Provider type); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0df2045dab9b19f5456a8946e0b827cbdcf31159 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +@@ -0,0 +1,87 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++import static io.papermc.paper.registry.event.RegistryEventProviderImpl.create; ++ ++/** ++ * Holds providers for {@link RegistryAdditionEvent} and {@link RegistryPreFreezeEvent} ++ * handlers for each applicable registry. ++ */ ++@ApiStatus.Experimental ++public final class RegistryEvents { ++ ++ ++ /** ++ * Provider for each registry event type for a specific registry. ++ * ++ * @param object type ++ * @param object builder type ++ */ ++ @ApiStatus.Experimental ++ @ApiStatus.NonExtendable ++ public interface Provider> { ++ ++ /** ++ * Gets the event type for {@link RegistryAdditionEvent} which is fired just before ++ * an object is added to a registry. ++ *

++ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)} ++ * to register a handler for {@link RegistryAdditionEvent}. ++ * ++ * @return the addition event type ++ */ ++ LifecycleEventType.@NotNull Prioritizable> addition(); ++ ++ /** ++ * Shortcut for calling {@link #addition()} followed by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. ++ *

++ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration)} ++ * to register a handler for {@link RegistryAdditionEvent} ++ * ++ * @param handler the event handler for {@link RegistryAdditionEvent} ++ * @return the configuration for further use ++ */ ++ @NotNull PrioritizedLifecycleEventHandlerConfiguration newAdditionHandler(@NotNull LifecycleEventHandler> handler); ++ ++ /** ++ * Gets the event type for {@link RegistryPreFreezeEvent} which is fired just before ++ * a registry is frozen. It allows for the registration of new objects. ++ *

++ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)} ++ * to register a handler for {@link RegistryPreFreezeEvent}. ++ * ++ * @return the pre-freeze event type ++ */ ++ LifecycleEventType.@NotNull Prioritizable> preFreeze(); ++ ++ /** ++ * Shortcut for calling {@link #preFreeze()} followed by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. ++ *

++ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration)} ++ * to register a handler for {@link RegistryPreFreezeEvent} ++ * ++ * @param handler the event handler for {@link RegistryPreFreezeEvent} ++ * @return the configuration for further use ++ */ ++ @NotNull PrioritizedLifecycleEventHandlerConfiguration newPreFreezeHandler(@NotNull LifecycleEventHandler> handler); ++ ++ /** ++ * Gets the registry key associated with this event type provider. ++ * ++ * @return the registry key ++ */ ++ @NotNull RegistryKey registryKey(); ++ } ++ ++ private RegistryEvents() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8ca6cc14b544399e32477c5fbe8b58f3bb4f55c4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEvent.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.RegistryBuilder; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Event object for {@link RegistryEvents.Provider#preFreeze()}. This ++ * event is fired right before a registry is frozen disallowing further changes. ++ * It provides a way for plugins to add new objects to the registry. ++ * ++ * @param object type ++ * @param object builder type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryPreFreezeEvent> extends RegistryEvent { ++ ++ /** ++ * Get a view of the registry which supports ++ * the registering of new values. ++ * ++ * @return a writable registry view ++ */ ++ @Override ++ @NotNull WritableRegistry registry(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3cab150544f2bd7f8dd483f638817e5a36f462ed +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryView; ++import io.papermc.paper.registry.TypedKey; ++import java.util.function.Consumer; ++import org.jetbrains.annotations.ApiStatus; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * A registry view which supports registering new objects. ++ * ++ * @param object type ++ * @param object builder type ++ */ ++@ApiStatus.NonExtendable ++@ApiStatus.Experimental ++public interface WritableRegistry> extends RegistryView { ++ ++ /** ++ * Register a new value with the specified key. ++ * ++ * @param key the object's key (must be unique from others) ++ * @param value a consumer for the object's builder ++ */ ++ void register(@NotNull TypedKey key, @NotNull Consumer value); ++} +diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java +index dfe5055cefe6a110732e0fcc936dddb866cbd9e3..00142aeeb764fcaa242280d454f00873c842526c 100644 +--- a/src/main/java/org/bukkit/Bukkit.java ++++ b/src/main/java/org/bukkit/Bukkit.java +@@ -2349,8 +2349,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 // Paper + 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 613cd9c2e91a851c86e339d2be86981b57669311..932a721579dcbee7343910cc7b025c11019d22ea 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -126,7 +126,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. + * +@@ -138,7 +138,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. + * +@@ -156,7 +156,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. + * +@@ -179,14 +179,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 // Paper ++ Registry STRUCTURE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(Structure.class); // Paper + /** + * Server structure types. + * + * @see StructureType + */ +- Registry STRUCTURE_TYPE = Bukkit.getRegistry(StructureType.class); ++ Registry STRUCTURE_TYPE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.STRUCTURE_TYPE); // Paper + /** + * Sound keys. + * +@@ -197,16 +199,20 @@ 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}. + */ + //@ApiStatus.Experimental // Paper +- Registry TRIM_MATERIAL = Bukkit.getRegistry(TrimMaterial.class); ++ @Deprecated // Paper ++ Registry TRIM_MATERIAL = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL); // 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}. + */ + //@ApiStatus.Experimental // Paper +- Registry TRIM_PATTERN = Bukkit.getRegistry(TrimPattern.class); ++ @Deprecated // Paper ++ Registry TRIM_PATTERN = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.TRIM_PATTERN); // Paper + /** + * Villager profession. + * +@@ -261,7 +267,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. + * +@@ -270,6 +276,27 @@ public interface Registry extends Iterable { + */ + @Nullable + T get(@NotNull NamespacedKey key); ++ // Paper start ++ /** ++ * Get the object by its key. ++ * ++ * @param key non-null key ++ * @return item or null if it does not exist ++ */ ++ default @Nullable T get(final net.kyori.adventure.key.@NotNull Key key) { ++ return key instanceof final NamespacedKey nsKey ? this.get(nsKey) : this.get(new NamespacedKey(key.namespace(), key.value())); ++ } ++ ++ /** ++ * Get the object by its typed key. ++ * ++ * @param typedKey non-null typed key ++ * @return item or null if it does not exist ++ */ ++ default @Nullable T get(final io.papermc.paper.registry.@NotNull TypedKey typedKey) { ++ return this.get(typedKey.key()); ++ } ++ // Paper end + + /** + * Returns a new stream, which contains all registry items, which are registered to the registry. +diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java +index 7986d51083c2c27709032b06731621d2e89bec57..68fb12577a52f6ed162e5df27a7c27f93ec35bf3 100644 +--- a/src/main/java/org/bukkit/Server.java ++++ b/src/main/java/org/bukkit/Server.java +@@ -2005,8 +2005,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 // 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..312d44ab470220835cfc2bd6e9439fbaced7489f +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/TestRegistryAccess.java +@@ -0,0 +1,19 @@ ++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 ++ public @Nullable Registry getRegistry(@NotNull Class type) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public @NotNull Registry getRegistry(@NotNull RegistryKey registryKey) { ++ throw new UnsupportedOperationException(); ++ } ++} +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/0247-Add-StructuresLocateEvent.patch b/patches/api/0247-Add-StructuresLocateEvent.patch index f3cf01ce68..6d38437b62 100644 --- a/patches/api/0247-Add-StructuresLocateEvent.patch +++ b/patches/api/0247-Add-StructuresLocateEvent.patch @@ -513,22 +513,21 @@ index 0000000000000000000000000000000000000000..1e7b53f9bc13dcd5a0a4a40004591e4f + } +} diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index 613cd9c2e91a851c86e339d2be86981b57669311..4331acfc9efd08011e339a1bc0a5190abc197506 100644 +index 932a721579dcbee7343910cc7b025c11019d22ea..ce2f319b19daa5d5c176c3510bfc59b4baea5b88 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -262,6 +262,17 @@ public interface Registry extends Iterable { +@@ -268,6 +268,16 @@ public interface Registry extends Iterable { * @see GameEvent */ - Registry GAME_EVENT = Objects.requireNonNull(Bukkit.getRegistry(GameEvent.class), "No registry present for GameEvent. This is a bug."); -+ + Registry GAME_EVENT = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.registry.RegistryKey.GAME_EVENT); // Paper + // Paper start + /** + * Configured structures. + * @see io.papermc.paper.world.structure.ConfiguredStructure -+ * @deprecated use {@link #STRUCTURE} ++ * @deprecated use {@link io.papermc.paper.registry.RegistryAccess#getRegistry(io.papermc.paper.registry.RegistryKey)} with {@link io.papermc.paper.registry.RegistryKey#STRUCTURE}. + */ + @Deprecated(forRemoval = true) -+ Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); ++ Registry CONFIGURED_STRUCTURE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + // Paper end + /** diff --git a/patches/api/0282-Add-basic-Datapack-API.patch b/patches/api/0282-Add-basic-Datapack-API.patch index 497ce52ec6..7e3e6923a7 100644 --- a/patches/api/0282-Add-basic-Datapack-API.patch +++ b/patches/api/0282-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 c4a4a0b1295739070017e7d09dd5e04a798494e3..2e29da775e60c149d2c251d78ee7c60b494215a4 100644 +index 12343aa79df02bb662fb46360342c3c3cd6d1f00..29d1f4f0ac66bcc343bbd765c7a7e58726a8d1ba 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -318,9 +318,11 @@ public final class Bukkit { @@ -85,7 +85,7 @@ index c4a4a0b1295739070017e7d09dd5e04a798494e3..2e29da775e60c149d2c251d78ee7c60b public static DataPackManager getDataPackManager() { return server.getDataPackManager(); } -@@ -2536,6 +2538,14 @@ public final class Bukkit { +@@ -2539,6 +2541,14 @@ public final class Bukkit { public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() { return server.getMobGoals(); } @@ -101,7 +101,7 @@ index c4a4a0b1295739070017e7d09dd5e04a798494e3..2e29da775e60c149d2c251d78ee7c60b @NotNull diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 0e3e654fb0551c6f862ce14b75cf1186392b023f..61701b6e8291cb5816b0a7eb511152eed3db43e8 100644 +index 8139ac8f74ed6924cae42c94e881d8722ccbe922..f6b82192b0e5dff3b2b9c3ea54709601a2ccdffa 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -256,9 +256,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi @@ -116,7 +116,7 @@ index 0e3e654fb0551c6f862ce14b75cf1186392b023f..61701b6e8291cb5816b0a7eb511152ee public DataPackManager getDataPackManager(); /** -@@ -2210,5 +2212,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2213,5 +2215,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull com.destroystokyo.paper.entity.ai.MobGoals getMobGoals(); diff --git a/patches/api/0342-More-PotionEffectType-API.patch b/patches/api/0342-More-PotionEffectType-API.patch index 3ccfee4a9d..b3b7618869 100644 --- a/patches/api/0342-More-PotionEffectType-API.patch +++ b/patches/api/0342-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 4331acfc9efd08011e339a1bc0a5190abc197506..800d23bb249e19d5cf924e7ba36684068624da02 100644 +index ce2f319b19daa5d5c176c3510bfc59b4baea5b88..d5bef4af45d74848d6ff6530f9de516a1764934f 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -271,6 +271,31 @@ public interface Registry extends Iterable { +@@ -276,6 +276,31 @@ public interface Registry extends Iterable { */ @Deprecated(forRemoval = true) - Registry CONFIGURED_STRUCTURE = Bukkit.getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + Registry CONFIGURED_STRUCTURE = io.papermc.paper.registry.RegistryAccess.registryAccess().getRegistry(io.papermc.paper.world.structure.ConfiguredStructure.class); + + /** + * Potion effect types. diff --git a/patches/api/0349-Custom-Potion-Mixes.patch b/patches/api/0349-Custom-Potion-Mixes.patch index 57bce6f5d1..0f9b532b56 100644 --- a/patches/api/0349-Custom-Potion-Mixes.patch +++ b/patches/api/0349-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 d7a9b5f9aeececb4070264bba6d2240628cdca12..50d336fda7f549e50dc127767ca35107c99a3483 100644 +index 65010e9e6bbfbd6356cefa989a80ccb3764df2f6..482b3b7c610cea699fde1d43e7dc1da8f83083b3 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2578,6 +2578,15 @@ public final class Bukkit { +@@ -2581,6 +2581,15 @@ public final class Bukkit { public static io.papermc.paper.datapack.DatapackManager getDatapackManager() { return server.getDatapackManager(); } @@ -175,10 +175,10 @@ index d7a9b5f9aeececb4070264bba6d2240628cdca12..50d336fda7f549e50dc127767ca35107 @NotNull diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 1fbd8ce1b9fa60ba06512dfcbd025212bc6dedfc..eca2b37d2841f3d64b9c3134c6b40264ee49d255 100644 +index a03b81c75bec50faf3932cdd243e4180efa7b3c0..0578cdf4841245ab88e4737c681c16ff08faea3f 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -2246,5 +2246,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2249,5 +2249,12 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull io.papermc.paper.datapack.DatapackManager getDatapackManager(); diff --git a/patches/api/0413-Folia-scheduler-and-owned-region-API.patch b/patches/api/0413-Folia-scheduler-and-owned-region-API.patch index 5eb0946bc3..25a8273d3f 100644 --- a/patches/api/0413-Folia-scheduler-and-owned-region-API.patch +++ b/patches/api/0413-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 d71b30d574e5cf7273ff831edb7f3ef2359bbadc..f98c8c41ad9685af327db9c44db5fc9e37e00590 100644 +index 0bd05533b4d8150707265cb4063bd28300282305..06910d72640bf7a4c977f47d27afe9b1c11bf16a 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java -@@ -2609,6 +2609,141 @@ public final class Bukkit { +@@ -2612,6 +2612,141 @@ public final class Bukkit { } // Paper end @@ -645,10 +645,10 @@ index d71b30d574e5cf7273ff831edb7f3ef2359bbadc..f98c8c41ad9685af327db9c44db5fc9e 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 75f2b46c4fc1e12d1d02cd60865a5b76b1c2de49..f8f0a2b7fdd51c739c3f55801037a417872ce7d5 100644 +index 374bacc792bde7cbe51603d1c3c7630642e816a3..d13e7faee970e4f65b32f8fbfd0a8071f15ae7b9 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java -@@ -2275,4 +2275,119 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi +@@ -2278,4 +2278,119 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi */ @NotNull org.bukkit.potion.PotionBrewer getPotionBrewer(); // Paper end diff --git a/patches/api/0448-Improve-Registry.patch b/patches/api/0448-Improve-Registry.patch index 1082efe432..526249b5a0 100644 --- a/patches/api/0448-Improve-Registry.patch +++ b/patches/api/0448-Improve-Registry.patch @@ -10,12 +10,12 @@ getKey() methods on Keyed objects that have a registry are marked as Deprecated or Obsolete. diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index 800d23bb249e19d5cf924e7ba36684068624da02..57e97b424cebd205cb260556ab9fb9eb2ff1eebc 100644 +index d5bef4af45d74848d6ff6530f9de516a1764934f..74dbb4f80f9159c3e4ac0b04090f6fb4cf12b132 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java -@@ -307,6 +307,49 @@ public interface Registry extends Iterable { - @Nullable - T get(@NotNull NamespacedKey key); +@@ -333,6 +333,49 @@ public interface Registry extends Iterable { + } + // Paper end + // Paper start - improve Registry + /** @@ -63,7 +63,7 @@ index 800d23bb249e19d5cf924e7ba36684068624da02..57e97b424cebd205cb260556ab9fb9eb /** * Returns a new stream, which contains all registry items, which are registered to the registry. * -@@ -373,5 +416,12 @@ public interface Registry extends Iterable { +@@ -399,5 +442,12 @@ public interface Registry extends Iterable { public Iterator iterator() { return map.values().iterator(); } diff --git a/patches/api/0460-Support-registry-mod-API-with-GameEvent.patch b/patches/api/0460-Support-registry-mod-API-with-GameEvent.patch new file mode 100644 index 0000000000..e2c724fe98 --- /dev/null +++ b/patches/api/0460-Support-registry-mod-API-with-GameEvent.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 25 Feb 2023 21:26:44 -0800 +Subject: [PATCH] Support registry mod API with GameEvent + + +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +index 0df2045dab9b19f5456a8946e0b827cbdcf31159..b222103a73d388d5cf7eb088db1de06b582dea7d 100644 +--- a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +@@ -7,6 +7,7 @@ import io.papermc.paper.plugin.lifecycle.event.handler.configuration.Prioritized + import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; + import io.papermc.paper.registry.RegistryBuilder; + import io.papermc.paper.registry.RegistryKey; ++import org.bukkit.GameEvent; + import org.jetbrains.annotations.ApiStatus; + import org.jetbrains.annotations.NotNull; + +@@ -19,6 +20,7 @@ import static io.papermc.paper.registry.event.RegistryEventProviderImpl.create; + @ApiStatus.Experimental + public final class RegistryEvents { + ++ public static final Provider GAME_EVENT = create(RegistryKey.GAME_EVENT); + + /** + * Provider for each registry event type for a specific registry. +diff --git a/src/main/java/org/bukkit/GameEvent.java b/src/main/java/org/bukkit/GameEvent.java +index 6c9689baca1763e2ef79495d38618d587e792434..fd9ccb69f99ae77da66583770e994cd958fd4bf9 100644 +--- a/src/main/java/org/bukkit/GameEvent.java ++++ b/src/main/java/org/bukkit/GameEvent.java +@@ -10,6 +10,7 @@ import org.jetbrains.annotations.Nullable; + /** + * Represents a generic Mojang game event. + */ ++@org.checkerframework.framework.qual.DefaultQualifier(NotNull.class) // Paper + public abstract class GameEvent implements Keyed { + + public static final GameEvent BLOCK_ACTIVATE = getEvent("block_activate"); +@@ -147,4 +148,46 @@ public abstract class GameEvent implements Keyed { + + return gameEvent; + } ++ ++ // Paper start ++ /** ++ * Gets the range of the event which is used to ++ * notify listeners of the event. ++ * ++ * @return the range ++ */ ++ public abstract int getRange(); ++ ++ /** ++ * Gets the vibration level of the game event for vibration listeners. ++ * Not all events have vibration levels, and a level of 0 means ++ * it won't cause any vibrations. ++ * ++ * @return the vibration level ++ */ ++ public abstract int getVibrationLevel(); ++ ++ @org.jetbrains.annotations.ApiStatus.Experimental ++ @org.jetbrains.annotations.ApiStatus.NonExtendable ++ public interface Builder extends io.papermc.paper.registry.RegistryBuilder { ++ ++ /** ++ * Gets the range of the event which is used to ++ * notify listeners of the event. ++ * ++ * @return the range ++ */ ++ int range(); ++ ++ /** ++ * Sets the range of the event which is used to ++ * notify listeners of the event. ++ * ++ * @param range the range ++ * @return the builder ++ */ ++ @org.jetbrains.annotations.Contract("_ -> this") ++ @NotNull Builder range(int range); ++ } ++ // Paper end + } diff --git a/patches/server/0013-Paper-Plugins.patch b/patches/server/0013-Paper-Plugins.patch index 9d5b2ad42e..2d698cfbe2 100644 --- a/patches/server/0013-Paper-Plugins.patch +++ b/patches/server/0013-Paper-Plugins.patch @@ -759,16 +759,18 @@ index 0000000000000000000000000000000000000000..b38e1e0f3d3055086f51bb191fd4b60e +} diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java b/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java new file mode 100644 -index 0000000000000000000000000000000000000000..6c0f2c315387734f8dd4a7eca633aa0a9856dd17 +index 0000000000000000000000000000000000000000..48bc745ca9632fc46b5f786ff570434702eb47f2 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java -@@ -0,0 +1,65 @@ +@@ -0,0 +1,74 @@ +package io.papermc.paper.plugin.entrypoint; + +import io.papermc.paper.plugin.provider.PluginProvider; +import io.papermc.paper.plugin.storage.BootstrapProviderStorage; +import io.papermc.paper.plugin.storage.ProviderStorage; +import io.papermc.paper.plugin.storage.ServerPluginProviderStorage; ++import it.unimi.dsi.fastutil.objects.Object2BooleanMap; ++import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; +import org.jetbrains.annotations.ApiStatus; + +import java.util.HashMap; @@ -781,9 +783,11 @@ index 0000000000000000000000000000000000000000..6c0f2c315387734f8dd4a7eca633aa0a + + public static final LaunchEntryPointHandler INSTANCE = new LaunchEntryPointHandler(); + private final Map, ProviderStorage> storage = new HashMap<>(); ++ private final Object2BooleanMap> enteredMap = new Object2BooleanOpenHashMap<>(); + + LaunchEntryPointHandler() { + this.populateProviderStorage(); ++ this.enteredMap.defaultReturnValue(false); + } + + // Utility @@ -799,6 +803,7 @@ index 0000000000000000000000000000000000000000..6c0f2c315387734f8dd4a7eca633aa0a + } + + storage.enter(); ++ this.enteredMap.put(entrypoint, true); + } + + @Override @@ -822,6 +827,10 @@ index 0000000000000000000000000000000000000000..6c0f2c315387734f8dd4a7eca633aa0a + return storage; + } + ++ public boolean hasEntered(Entrypoint entrypoint) { ++ return this.enteredMap.getBoolean(entrypoint); ++ } ++ + // Reload only + public void populateProviderStorage() { + this.storage.put(Entrypoint.BOOTSTRAPPER, new BootstrapProviderStorage()); @@ -7126,17 +7135,24 @@ index ca70cd2e76c94f7a284c9af47c64252855f070a4..b366389fd1aed47e04884e9e495df83e validate(REGISTRY); } diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java -index 1eabd8b5a99850298838b11ba97e3d220f444378..8ff786c366332588a2df053438f23cc9fb7e2b84 100644 +index 1eabd8b5a99850298838b11ba97e3d220f444378..9e0f959b2966bf41463b4102664030fc0d4292e2 100644 --- a/src/main/java/net/minecraft/server/Bootstrap.java +++ b/src/main/java/net/minecraft/server/Bootstrap.java -@@ -76,7 +76,11 @@ public class Bootstrap { +@@ -67,6 +67,7 @@ public class Bootstrap { + if (BuiltInRegistries.REGISTRY.keySet().isEmpty()) { + throw new IllegalStateException("Unable to load registries"); + } else { ++ io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping (before any registry is populated) + FireBlock.bootStrap(); + ComposterBlock.bootStrap(); + if (EntityType.getKey(EntityType.PLAYER) == null) { +@@ -76,7 +77,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/0497-Registry-Modification-API.patch b/patches/server/0497-Registry-Modification-API.patch new file mode 100644 index 0000000000..e875ff096f --- /dev/null +++ b/patches/server/0497-Registry-Modification-API.patch @@ -0,0 +1,1354 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 27 Feb 2023 18:28:39 -0800 +Subject: [PATCH] Registry Modification API + +== AT == +public net.minecraft.server.RegistryLayer STATIC_ACCESS +public net.minecraft.core.MappedRegistry validateWrite(Lnet/minecraft/resources/ResourceKey;)V + +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..abecec33b6c0dba7183057efbc1425d94958b458 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -0,0 +1,85 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.collect.ImmutableList; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.world.structure.ConfiguredStructure; ++import io.papermc.paper.world.structure.PaperConfiguredStructure; ++import java.util.IdentityHashMap; ++import java.util.List; ++import java.util.Map; ++import java.util.function.Function; ++import java.util.stream.Collectors; ++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.enchantments.CraftEnchantment; ++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.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.Nullable; ++ ++import static io.papermc.paper.registry.entry.RegistryEntry.immutable; ++import static io.papermc.paper.registry.entry.RegistryEntry.immutableBuiltIn; ++import static io.papermc.paper.registry.entry.RegistryEntry.writableBuiltIn; ++ ++/** ++ * Note: Newly added registries should also be added to ++ * RegistriesArgumentProvider in the test package. ++ */ ++public final class PaperRegistries { ++ ++ @Deprecated(forRemoval = true) ++ private static final RegistryKey CONFIGURED_STRUCTURE = RegistryKeyImpl.create("worldgen/structure"); ++ @Deprecated(forRemoval = true) ++ static final RegistryEntry CONFIGURED_STRUCTURE_ENTRY = immutable(CONFIGURED_STRUCTURE, Registries.STRUCTURE, ConfiguredStructure.class, PaperConfiguredStructure::minecraftToBukkit).delay(); ++ ++ static final List> REGISTRY_ENTRIES; ++ static { ++ REGISTRY_ENTRIES = ImmutableList.>builder() ++ // built-ins ++ .add(immutableBuiltIn(RegistryKey.GAME_EVENT, Registries.GAME_EVENT, GameEvent.class, CraftGameEvent::new)) ++ .add(immutableBuiltIn(RegistryKey.STRUCTURE_TYPE, Registries.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new)) ++ .add(immutableBuiltIn(RegistryKey.INSTRUMENT, Registries.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new)) ++ .add(immutableBuiltIn(RegistryKey.ENCHANTMENT, Registries.ENCHANTMENT, Enchantment.class, CraftEnchantment::new)) ++ .add(immutableBuiltIn(RegistryKey.MOB_EFFECT, Registries.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new)) ++ ++ // data-drivens ++ .add(immutable(RegistryKey.STRUCTURE, Registries.STRUCTURE, org.bukkit.generator.structure.Structure.class, CraftStructure::new).delay()) ++ .add(immutable(RegistryKey.TRIM_MATERIAL, Registries.TRIM_MATERIAL, TrimMaterial.class, CraftTrimMaterial::new).delay()) ++ .add(immutable(RegistryKey.TRIM_PATTERN, Registries.TRIM_PATTERN, TrimPattern.class, CraftTrimPattern::new).delay()) ++ .build(); ++ } ++ ++ private static final Map, RegistryEntry> BY_REGISTRY_KEY = REGISTRY_ENTRIES.stream() ++ .collect(Collectors.toMap(RegistryEntry::key, Function.identity(), (e1, e2) -> {throw new IllegalArgumentException("duplicate keys");}, IdentityHashMap::new)); ++ ++ private static final Map, RegistryEntry> BY_RESOURCE_KEY = REGISTRY_ENTRIES.stream() ++ .collect(Collectors.toMap(RegistryEntry::resourceKey, Function.identity(), (e1, e2) -> {throw new IllegalArgumentException("duplicate keys");}, IdentityHashMap::new)); ++ ++ ++ @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..ac7b5af4d2fcb8519f6d5cb62022b2a2b12b0c8a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +@@ -0,0 +1,102 @@ ++package io.papermc.paper.registry; ++ ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import io.papermc.paper.registry.legacy.LegacyRegistryIdentifiers; ++import io.papermc.paper.world.structure.ConfiguredStructure; ++import java.util.IdentityHashMap; ++import java.util.Map; ++import java.util.Objects; ++import java.util.function.BooleanSupplier; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.Keyed; ++import org.bukkit.Registry; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.VisibleForTesting; ++ ++public class PaperRegistryAccess implements RegistryAccess { ++ ++ private final Map, Registry> registries = new IdentityHashMap<>(); ++ ++ public static PaperRegistryAccess instance() { ++ return (PaperRegistryAccess) RegistryAccess.registryAccess(); ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated ++ @Override ++ public @Nullable Registry getRegistry(final Class type) { ++ if (type == ConfiguredStructure.class) { // manually handle "duplicate" registries to avoid polluting maps in PaperRegistries ++ return (Registry) this.getRegistry0(PaperRegistries.CONFIGURED_STRUCTURE_ENTRY, true); ++ } ++ return this.getRegistry0(byType(type), true); ++ } ++ ++ @Override ++ public Registry getRegistry(final RegistryKey key) { ++ return Objects.requireNonNull(this.getRegistry0(key, false), "This shouldn't happen"); ++ } ++ ++ private @Nullable Registry getRegistry0(final @Nullable RegistryKey key, final boolean fromLegacy) { ++ if (key == null) { ++ return null; ++ } ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(key); ++ if (entry == null) { ++ if (!fromLegacy) throw new IllegalArgumentException(key + " is not a recognized key"); ++ return null; ++ } ++ return this.getRegistry0(entry, fromLegacy); ++ } ++ ++ @SuppressWarnings({"unchecked", "deprecation"}) ++ private @Nullable Registry getRegistry0(final RegistryEntry entry, final boolean fromLegacy) { ++ final @Nullable Registry registry = (Registry) this.registries.get(entry.key()); ++ if (registry != null) { ++ return registry; ++ } ++ if (entry instanceof final RegistryEntry.BuiltIn builtIn) { // provide built-ins as needed ++ return (Registry) this.registries.computeIfAbsent(entry.key(), ignored -> builtIn.createRegistry()); ++ } else if (entry instanceof DelayedRegistryEntry) { ++ // delayed registry entries are only for static final fields in org.bukkit.Registry for data-driven registries ++ return entry.createRegistry(null); ++ } ++ if (!fromLegacy) throw new IllegalArgumentException("You cannot access this registry: " + entry.key() + " yet!"); ++ return null; ++ } ++ ++ public > WritableCraftRegistry getWritableRegistry(final RegistryKey key) { ++ final Registry registry = this.getRegistry(key); ++ if (registry instanceof WritableCraftRegistry) { ++ return (WritableCraftRegistry) registry; ++ } ++ throw new IllegalArgumentException(key + " does not point to a writable registry"); ++ } ++ ++ public void createRegistry(final net.minecraft.core.Registry registry) { ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(registry.key()); ++ if (entry == null) { // not handled in API ++ return; ++ } ++ if (this.registries.containsKey(entry.key())) { ++ throw new IllegalArgumentException(registry.key() + " has already been created"); ++ } ++ this.registries.put(entry.key(), entry.createRegistry(registry)); ++ } ++ ++ public net.minecraft.core.RegistryAccess getDelayedRegistryAccess() { ++ return MinecraftServer.getServer().registryAccess(); ++ } ++ ++ public BooleanSupplier delayedValidCheck() { ++ //noinspection ConstantValue ++ return () -> MinecraftServer.getServer() != null; ++ } ++ ++ @SuppressWarnings("unchecked") ++ @Deprecated ++ @VisibleForTesting ++ 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/PaperRegistryBuilder.java b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3ddde5f0d8f60b83a002b415247e16f74d268e82 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java +@@ -0,0 +1,6 @@ ++package io.papermc.paper.registry; ++ ++public interface PaperRegistryBuilder extends RegistryBuilder { ++ ++ M build(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cbf8c7e1ef45a01ae9ee63d3b44be1b2d32b8d33 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java +@@ -0,0 +1,97 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Preconditions; ++import com.mojang.serialization.Lifecycle; ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.entrypoint.Entrypoint; ++import io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.event.RegistryAdditionEvent; ++import io.papermc.paper.registry.event.RegistryAdditionEventImpl; ++import io.papermc.paper.registry.event.RegistryEventMap; ++import io.papermc.paper.registry.event.RegistryEvents; ++import io.papermc.paper.registry.event.RegistryPreFreezeEvent; ++import io.papermc.paper.registry.event.RegistryPreFreezeEventImpl; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.intellij.lang.annotations.Subst; ++ ++public final class PaperRegistryListenerManager { ++ ++ public static final PaperRegistryListenerManager INSTANCE = new PaperRegistryListenerManager(); ++ ++ public final RegistryEventMap additionHooks = new RegistryEventMap("addition"); ++ public final RegistryEventMap preFreezeHooks = new RegistryEventMap("pre-freeze"); ++ ++ private PaperRegistryListenerManager() { ++ } ++ ++ public M registerWithListeners(final Registry registry, final String id, final M nms) { ++ return this.registerWithListeners(registry, new ResourceLocation(id), nms); ++ } ++ ++ public M registerWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { ++ return this.registerWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); ++ } ++ ++ public M registerWithListeners(final Registry registry, final ResourceKey key, final M nms) { ++ return this.registerWithListeners(registry, key, nms, Lifecycle.stable()); ++ } ++ ++ public > M registerWithListeners(final Registry registry, final ResourceKey key, final M nms, final Lifecycle lifecycle) { ++ Preconditions.checkState(LaunchEntryPointHandler.INSTANCE.hasEntered(Entrypoint.BOOTSTRAPPER), registry.key() + " tried to run modification listeners before bootstrappers have been called"); // verify that bootstrappers have been called ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(registry.key()); ++ if (!(entry instanceof RegistryEntry.Modifiable) || !this.additionHooks.hasHooks(entry.key())) { ++ ((net.minecraft.core.WritableRegistry) registry).register(key, nms, lifecycle); ++ return nms; ++ } ++ final CraftRegistry craftRegistry = (CraftRegistry) PaperRegistryAccess.instance().getRegistry(entry.key()); ++ final RegistryEntry.Modifiable modifiableEntry = (RegistryEntry.Modifiable) entry; ++ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.key(), Key.key(key.location().getNamespace(), key.location().getPath())); ++ final B builder = modifiableEntry.fillBuilder(typedKey, nms); ++ return this.registerWithListeners(registry, craftRegistry.view, modifiableEntry, key, nms, builder, lifecycle); ++ } ++ ++ public > M registerWithListeners(final Registry registry, final RegistryView registryView, final RegistryEntry.Modifiable entry, final ResourceKey key, final @Nullable M oldNms, final B builder, final Lifecycle lifecycle) { ++ @Subst("namespace:key") final ResourceLocation beingAdded = key.location(); ++ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.key(), Key.key(beingAdded.getNamespace(), beingAdded.getPath())); ++ final RegistryAdditionEventImpl event = entry.createAdditionEvent(typedKey, builder, registryView); ++ LifecycleEventRunner.INSTANCE.callEvent(this.additionHooks.getHook(entry.key(), RegistryEvents.Provider::addition), event); ++ if (oldNms != null) { ++ ((MappedRegistry) registry).clearIntrusiveHolder(oldNms); ++ } ++ final M newNms = event.builder().build(); ++ ((net.minecraft.core.WritableRegistry) registry).register(key, newNms, lifecycle); ++ return newNms; ++ } ++ ++ public > void runFreezeListeners(final ResourceKey> resourceKey) { ++ final @Nullable RegistryEntry entry = PaperRegistries.getEntry(resourceKey); ++ if (!(entry instanceof RegistryEntry.Writable) || !this.preFreezeHooks.hasHooks(entry.key())) { ++ return; ++ } ++ final RegistryPreFreezeEventImpl event = ((RegistryEntry.Writable) entry).createPreFreezeEvent(PaperRegistryAccess.instance().getWritableRegistry(entry.key())); ++ LifecycleEventRunner.INSTANCE.callEvent(this.preFreezeHooks.getHook(entry.key(), RegistryEvents.Provider::preFreeze), event); ++ } ++ ++ public > LifecycleEventType.Prioritizable> getRegistryAdditionEventType(final RegistryEvents.Provider type) { ++ if (!(PaperRegistries.getEntry(type.registryKey()) instanceof RegistryEntry.Modifiable)) { ++ throw new IllegalArgumentException(type.registryKey() + " does not support RegistryAdditionEvent"); ++ } ++ return this.additionHooks.getOrCreate(type, RegistryEvents.Provider::addition); ++ } ++ ++ public > LifecycleEventType.Prioritizable> getRegistryPreFreezeEventType(final RegistryEvents.Provider type) { ++ if (!(PaperRegistries.getEntry(type.registryKey()) instanceof RegistryEntry.Writable)) { ++ throw new IllegalArgumentException(type.registryKey() + " does not support RegistryPreFreezeEvent"); ++ } ++ return this.preFreezeHooks.getOrCreate(type, RegistryEvents.Provider::preFreeze); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/SimpleWritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/SimpleWritableCraftRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..437640b3cacc396297f2ac7c44bba0af734e69d0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/SimpleWritableCraftRegistry.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry; ++ ++import io.papermc.paper.registry.entry.RegistryEntry; ++import java.util.function.BiFunction; ++import java.util.function.Function; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.Registry; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++ ++public final class SimpleWritableCraftRegistry> extends WritableCraftRegistry { ++ ++ private final Function, ? extends B> newBuilder; ++ private final BiFunction minecraftToBukkit; ++ ++ public SimpleWritableCraftRegistry(final RegistryEntry.Writable entry, final Registry nmsRegistry, final Function, ? extends B> newBuilder, final BiFunction minecraftToBukkit) { ++ super(entry, (MappedRegistry) nmsRegistry); ++ this.newBuilder = newBuilder; ++ this.minecraftToBukkit = minecraftToBukkit; ++ } ++ ++ @Override ++ public T minecraftToBukkit(final NamespacedKey namespacedKey, final M minecraft) { ++ return this.minecraftToBukkit.apply(namespacedKey, minecraft); ++ } ++ ++ @Override ++ public B newBuilder(final TypedKey key) { ++ return this.newBuilder.apply(key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2bc44526556d83cd8e28c4e10ab034754b2016f3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java +@@ -0,0 +1,48 @@ ++package io.papermc.paper.registry; ++ ++import com.mojang.serialization.Lifecycle; ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.event.PaperWritableRegistry; ++import io.papermc.paper.registry.event.WritableRegistry; ++import java.util.function.Consumer; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public abstract class WritableCraftRegistry> extends CraftRegistry { ++ ++ private final RegistryEntry.Writable entry; ++ private final MappedRegistry registry; ++ public final WritableRegistry modifiableView; ++ ++ public WritableCraftRegistry(final RegistryEntry.Writable entry, final MappedRegistry registry) { ++ super(entry.preloadClass(), registry, null); ++ this.entry = entry; ++ this.registry = registry; ++ this.modifiableView = new PaperWritableRegistry<>(this.registry, this); ++ } ++ ++ public void register(final TypedKey key, final Consumer value) { ++ final ResourceKey resourceKey = ResourceKey.create(this.registry.key(), PaperAdventure.asVanilla(key.key())); ++ this.registry.validateWrite(resourceKey); ++ final B builder = this.newBuilder(key); ++ value.accept(builder); ++ PaperRegistryListenerManager.INSTANCE.registerWithListeners(this.registry, this.view, this.entry, resourceKey, null, builder, Lifecycle.experimental()); ++ } ++ ++ @Override ++ public final @Nullable T createBukkit(final NamespacedKey namespacedKey, final @Nullable M minecraft) { ++ if (minecraft == null) { ++ return null; ++ } ++ return this.minecraftToBukkit(namespacedKey, minecraft); ++ } ++ ++ public abstract T minecraftToBukkit(NamespacedKey namespacedKey, M minecraft); ++ ++ protected abstract B newBuilder(TypedKey key); ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/ImmutableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ImmutableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df8e6c2796301d08f5c8f99b030beb02eeb2bd94 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/ImmutableRegistryEntry.java +@@ -0,0 +1,54 @@ ++package io.papermc.paper.registry.entry; ++ ++import com.google.common.base.Preconditions; ++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.Nullable; ++ ++public class ImmutableRegistryEntry implements RegistryEntry { ++ ++ private final RegistryKey key; ++ private final Class preloadClass; ++ private final ResourceKey> resourceKey; ++ protected final BiFunction minecraftToBukkit; ++ ++ public ImmutableRegistryEntry(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit) { ++ this.key = key; ++ this.preloadClass = preloadClass; ++ this.resourceKey = resourceKey; ++ this.minecraftToBukkit = minecraftToBukkit; ++ } ++ ++ @Override ++ public RegistryKey key() { ++ return this.key; ++ } ++ ++ @Override ++ public ResourceKey> resourceKey() { ++ return this.resourceKey; ++ } ++ ++ @Override ++ public Class preloadClass() { ++ return this.preloadClass; ++ } ++ ++ @Override ++ public org.bukkit.Registry createRegistry(final @Nullable Registry registry) { ++ Preconditions.checkState(registry != null, "Cannot access " + this.resourceKey() + " yet"); ++ return new CraftRegistry<>(this.preloadClass, registry, this.minecraftToBukkit); ++ } ++ ++ public static class BuiltIn extends ImmutableRegistryEntry implements RegistryEntry.BuiltIn { ++ ++ public BuiltIn(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit) { ++ super(key, resourceKey, preloadClass, minecraftToBukkit); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4cc2ac1cf634b17e1b0c86f6ca61fc884b9719d1 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java +@@ -0,0 +1,40 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.RegistryView; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.event.RegistryAdditionEventImpl; ++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.checkerframework.checker.nullness.qual.Nullable; ++ ++public class ModifiableRegistryEntry> extends ImmutableRegistryEntry implements RegistryEntry.Modifiable { ++ ++ protected final BiFunction, ? super @Nullable M, ? extends B> newBuilder; ++ ++ ModifiableRegistryEntry(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ super(key, resourceKey, preloadClass, minecraftToBukkit); ++ this.newBuilder = newBuilder; ++ } ++ ++ @Override ++ public RegistryAdditionEventImpl createAdditionEvent(final TypedKey key, final B initialBuilder, final RegistryView view) { ++ return new RegistryAdditionEventImpl<>(key, initialBuilder, this.key(), view); ++ } ++ ++ @Override ++ public B fillBuilder(final TypedKey key, final M nms) { ++ return this.newBuilder.apply(key, nms); ++ } ++ ++ public static class BuiltIn> extends ModifiableRegistryEntry implements RegistryEntry.BuiltIn { ++ ++ public BuiltIn(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ super(key, resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++ } ++} +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..9d281558ac37c51df04bb1cdd143af5d26d0e037 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +@@ -0,0 +1,94 @@ ++package io.papermc.paper.registry.entry; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.RegistryView; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.WritableCraftRegistry; ++import io.papermc.paper.registry.event.RegistryAdditionEventImpl; ++import io.papermc.paper.registry.event.RegistryPreFreezeEventImpl; ++import io.papermc.paper.registry.legacy.DelayedRegistryEntry; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.server.RegistryLayer; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public interface RegistryEntry { ++ ++ ResourceKey> resourceKey(); ++ ++ RegistryKey key(); ++ ++ Class preloadClass(); ++ ++ org.bukkit.Registry createRegistry(@Nullable Registry registry); ++ ++ /** ++ * 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 a field, but instead be gotten via {@link io.papermc.paper.registry.RegistryAccess#getRegistry(RegistryKey)} ++ */ ++ @Deprecated ++ default RegistryEntry delay() { ++ Preconditions.checkState(!(this instanceof RegistryEntry.BuiltIn), "Cannot delay a built-in registry"); ++ return new DelayedRegistryEntry<>(this); ++ } ++ ++ interface BuiltIn extends RegistryEntry { ++ ++ default org.bukkit.Registry createRegistry() { ++ return this.createRegistry(RegistryLayer.STATIC_ACCESS.registryOrThrow(this.resourceKey())); ++ } ++ } ++ ++ interface Modifiable> extends RegistryEntry { ++ ++ RegistryAdditionEventImpl createAdditionEvent(TypedKey key, B initialBuilder, RegistryView view); ++ ++ B fillBuilder(TypedKey key, M nms); ++ } ++ ++ interface Writable> extends Modifiable { ++ ++ @Override ++ WritableCraftRegistry createRegistry(@Nullable Registry nmsRegistry); ++ ++ RegistryPreFreezeEventImpl createPreFreezeEvent(WritableCraftRegistry registry); ++ ++ interface BuiltIn> extends Writable, RegistryEntry.BuiltIn { ++ ++ @Override ++ default WritableCraftRegistry createRegistry() { ++ return this.createRegistry(RegistryLayer.STATIC_ACCESS.registryOrThrow(this.resourceKey())); ++ } ++ } ++ } ++ ++ static RegistryEntry immutable(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit) { ++ return new ImmutableRegistryEntry<>(key, resourceKey, preloadClass, minecraftToBukkit); ++ } ++ ++ static RegistryEntry immutableBuiltIn(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit) { ++ return new ImmutableRegistryEntry.BuiltIn<>(key, resourceKey, preloadClass, minecraftToBukkit); ++ } ++ ++ static > RegistryEntry modifiable(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ return new ModifiableRegistryEntry<>(key, resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++ ++ static > RegistryEntry modifiableBuiltIn(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ return new ModifiableRegistryEntry.BuiltIn<>(key, resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++ ++ static > RegistryEntry writable(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ return new WritableRegistryEntry<>(key,resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++ ++ static > RegistryEntry writableBuiltIn(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ return new WritableRegistryEntry.BuiltIn<>(key,resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..bf6747b4d9a34ddb53acdec0dabfc8dad8699e37 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java +@@ -0,0 +1,45 @@ ++package io.papermc.paper.registry.entry; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.SimpleWritableCraftRegistry; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.WritableCraftRegistry; ++import io.papermc.paper.registry.event.RegistryPreFreezeEventImpl; ++import java.util.function.BiFunction; ++import java.util.function.Function; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public class WritableRegistryEntry> extends ModifiableRegistryEntry implements RegistryEntry.Writable { ++ ++ protected WritableRegistryEntry(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ super(key, resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++ ++ @Override ++ public WritableCraftRegistry createRegistry(final @Nullable Registry registry) { ++ Preconditions.checkState(registry != null, "Cannot access " + this.resourceKey() + " yet"); ++ return new SimpleWritableCraftRegistry<>(this, registry, this.passNullNmsObject(this.newBuilder), this.minecraftToBukkit); ++ } ++ ++ @Override ++ public RegistryPreFreezeEventImpl createPreFreezeEvent(final WritableCraftRegistry registry) { ++ return new RegistryPreFreezeEventImpl<>(this.key(), registry.modifiableView); ++ } ++ ++ protected Function, ? extends B> passNullNmsObject(final BiFunction, ? super @Nullable M, ? extends B> biFunction) { ++ return t -> biFunction.apply(t, null); ++ } ++ ++ public static class BuiltIn> extends WritableRegistryEntry implements RegistryEntry.Writable.BuiltIn { ++ ++ public BuiltIn(final RegistryKey key, final ResourceKey> resourceKey, final Class preloadClass, final BiFunction minecraftToBukkit, final BiFunction, ? super @Nullable M, ? extends B> newBuilder) { ++ super(key, resourceKey, preloadClass, minecraftToBukkit, newBuilder); ++ } ++ } ++} +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/event/PaperRegistryView.java b/src/main/java/io/papermc/paper/registry/event/PaperRegistryView.java +new file mode 100644 +index 0000000000000000000000000000000000000000..468115c3695bb3bc1529560c624b93462fd02491 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/PaperRegistryView.java +@@ -0,0 +1,53 @@ ++package io.papermc.paper.registry.event; ++ ++import com.google.common.collect.Iterators; ++import io.papermc.paper.registry.RegistryView; ++import java.util.Iterator; ++import java.util.NoSuchElementException; ++import java.util.function.BiFunction; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceLocation; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public class PaperRegistryView implements RegistryView { ++ ++ protected final MappedRegistry registry; ++ private final BiFunction minecraftToBukkit; ++ ++ public PaperRegistryView(final Registry registry, final BiFunction minecraftToBukkit) { ++ this.registry = (MappedRegistry) registry; ++ this.minecraftToBukkit = convert(minecraftToBukkit); ++ } ++ ++ @Override ++ public T get(final Key key) { ++ final @Nullable M value = this.registry.beforeFrozenView().get(new ResourceLocation(key.namespace(), key.value())); ++ if (value == null) { ++ return null; ++ } ++ ++ return this.minecraftToBukkit.apply(key, value); ++ } ++ ++ @Override ++ public T getOrThrow(final Key key) { ++ final @Nullable T value = this.get(key); ++ if (value == null) { ++ throw new NoSuchElementException("No value found for key " + key); ++ } ++ return value; ++ } ++ ++ @Override ++ public Iterator iterator() { ++ return Iterators.transform(this.registry.beforeFrozenView().entrySet().iterator(), input -> this.minecraftToBukkit.apply(CraftNamespacedKey.fromMinecraft(input.getKey()), input.getValue())); ++ } ++ ++ private static BiFunction convert(final BiFunction original) { ++ return (key, m) -> original.apply(key instanceof final NamespacedKey ns ? ns : new NamespacedKey(key.namespace(), key.value()), m); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/PaperWritableRegistry.java b/src/main/java/io/papermc/paper/registry/event/PaperWritableRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..85296647e9a1bfcbaa9c94f1e7a47722727cd7c8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/PaperWritableRegistry.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.WritableCraftRegistry; ++import java.util.function.Consumer; ++import net.minecraft.core.Registry; ++import org.bukkit.Keyed; ++import org.jetbrains.annotations.NotNull; ++ ++public class PaperWritableRegistry> extends PaperRegistryView implements WritableRegistry { ++ ++ private final WritableCraftRegistry writableRegistry; ++ ++ public PaperWritableRegistry(final Registry registry, final WritableCraftRegistry writableRegistry) { ++ super(registry, writableRegistry::minecraftToBukkit); ++ this.writableRegistry = writableRegistry; ++ } ++ ++ @Override ++ public void register(final @NotNull TypedKey key, final Consumer value) { ++ this.writableRegistry.register(key, value); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEventImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fe2619b2e590cbd048a0bb9f06f82a3025d9dfaf +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEventImpl.java +@@ -0,0 +1,15 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.RegistryView; ++import io.papermc.paper.registry.TypedKey; ++ ++public record RegistryAdditionEventImpl>( ++ TypedKey key, ++ B builder, ++ RegistryKey registryKey, ++ RegistryView registry ++) implements RegistryAdditionEvent, PaperLifecycleEvent { ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f644f9db6cdef375aedb7aafc777c2204f3c1b73 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java +@@ -0,0 +1,43 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.function.Function; ++ ++public final class RegistryEventMap { ++ ++ private final Map, LifecycleEventType.Prioritizable>> hooks = new HashMap<>(); ++ private final String name; ++ ++ public RegistryEventMap(final String name) { ++ this.name = name; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public , E extends RegistryEvent> LifecycleEventType.Prioritizable getOrCreate(final RegistryEvents.Provider type, final Function, LifecycleEventType.Prioritizable> genericHelper) { ++ final RegistryLifecycleEventType registerHook; ++ if (this.hooks.containsKey(type.registryKey())) { ++ registerHook = (RegistryLifecycleEventType) this.hooks.get(type.registryKey()); ++ } else { ++ registerHook = new RegistryLifecycleEventType<>(type, this.name); ++ LifecycleEventRunner.INSTANCE.addEventType(registerHook); ++ this.hooks.put(type.registryKey(), registerHook); ++ } ++ return registerHook; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public , E extends RegistryEvent> LifecycleEventType.Prioritizable getHook(final RegistryKey registryKey, final Function, LifecycleEventType.Prioritizable> genericHelper) { ++ return (RegistryLifecycleEventType) this.hooks.get(registryKey); ++ } ++ ++ public boolean hasHooks(final RegistryKey registryKey) { ++ return this.hooks.containsKey(registryKey); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cf04f6426d56ee6ae4d23c47f458d1ecece6e834 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.PaperRegistryListenerManager; ++import io.papermc.paper.registry.RegistryBuilder; ++ ++public class RegistryEventTypeProviderImpl implements RegistryEventTypeProvider { ++ ++ public static RegistryEventTypeProviderImpl instance() { ++ return (RegistryEventTypeProviderImpl) RegistryEventTypeProvider.PROVIDER; ++ } ++ ++ @Override ++ public > LifecycleEventType.Prioritizable> registryAddition(final RegistryEvents.Provider type) { ++ return PaperRegistryListenerManager.INSTANCE.getRegistryAdditionEventType(type); ++ } ++ ++ @Override ++ public > LifecycleEventType.Prioritizable> registryPreFreeze(final RegistryEvents.Provider type) { ++ return PaperRegistryListenerManager.INSTANCE.getRegistryPreFreezeEventType(type); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryLifecycleEventType.java b/src/main/java/io/papermc/paper/registry/event/RegistryLifecycleEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..576b17846d6e7f7567fedc1ef98ff090126d04a8 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryLifecycleEventType.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++ ++public final class RegistryLifecycleEventType, E extends RegistryEvent> extends PrioritizableLifecycleEventType { ++ ++ RegistryLifecycleEventType(final RegistryEvents.Provider type, final String eventName) { ++ super(type.registryKey() + " / " + eventName, BootstrapContext.class); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEventImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b07cdd257e299205b695e0122a48c2f4225aef17 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEventImpl.java +@@ -0,0 +1,12 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import net.kyori.adventure.key.Keyed; ++ ++public record RegistryPreFreezeEventImpl>( ++ RegistryKey registryKey, ++ WritableRegistry registry ++) implements RegistryPreFreezeEvent, PaperLifecycleEvent { ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/package-info.java b/src/main/java/io/papermc/paper/registry/event/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..14d2d9766b8dee763f220c397aba3ad432d02aaa +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry.event; ++ ++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..9fdbb6ee847e2b041c86973229fbb89fe3f7719b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistry.java +@@ -0,0 +1,53 @@ ++package io.papermc.paper.registry.legacy; ++ ++import java.util.Iterator; ++import java.util.function.BooleanSupplier; ++import java.util.function.Supplier; ++import java.util.stream.Stream; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.jetbrains.annotations.NotNull; ++import oshi.util.Memoizer; ++ ++/** ++ * This is to support the now-deprecated fields in {@link Registry} for ++ * data-driven registries. ++ */ ++@Deprecated ++public final class DelayedRegistry implements Registry { ++ ++ private final Supplier> delegate; ++ private final BooleanSupplier validCheck; ++ ++ public DelayedRegistry(final Supplier> delegate, final BooleanSupplier validCheck) { ++ this.delegate = Memoizer.memoize(delegate); ++ this.validCheck = validCheck; ++ } ++ ++ private void checkValid() { ++ if (!this.validCheck.getAsBoolean()) { ++ throw new IllegalStateException("You are trying to access this registry too early!"); ++ } ++ } ++ ++ @Override ++ public @Nullable T get(final NamespacedKey key) { ++ this.checkValid(); ++ return this.delegate.get().get(key); ++ } ++ ++ ++ @Override ++ public Iterator iterator() { ++ this.checkValid(); ++ return this.delegate.get().iterator(); ++ } ++ ++ @Override ++ public @NotNull Stream stream() { ++ this.checkValid(); ++ return this.delegate.get().stream(); ++ } ++} +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..3ade945a6b8bfbc07595512847202d0086026ab3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/DelayedRegistryEntry.java +@@ -0,0 +1,42 @@ ++package io.papermc.paper.registry.legacy; ++ ++import io.papermc.paper.registry.PaperRegistryAccess; ++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; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++@Deprecated ++public class DelayedRegistryEntry implements RegistryEntry { ++ ++ private final RegistryEntry delegate; ++ ++ public DelayedRegistryEntry(final RegistryEntry delegate) { ++ this.delegate = delegate; ++ } ++ ++ @Override ++ public ResourceKey> resourceKey() { ++ return this.delegate.resourceKey(); ++ } ++ ++ @Override ++ public RegistryKey key() { ++ return this.delegate.key(); ++ } ++ ++ @Override ++ public Class preloadClass() { ++ return this.delegate.preloadClass(); ++ } ++ ++ @Override ++ public org.bukkit.Registry createRegistry(final @Nullable Registry registry) { ++ if (registry == null && !PaperRegistryAccess.instance().delayedValidCheck().getAsBoolean()) { ++ return new DelayedRegistry<>(() -> this.delegate.createRegistry(PaperRegistryAccess.instance().getDelayedRegistryAccess().registryOrThrow(this.resourceKey())), PaperRegistryAccess.instance().delayedValidCheck()); ++ } ++ return this.delegate.createRegistry(registry); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +new file mode 100644 +index 0000000000000000000000000000000000000000..18dab3d1a5c873cfef09a8eba69d1e6d228b62eb +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/LegacyRegistryIdentifiers.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.registry.legacy; ++ ++import com.google.common.collect.ImmutableMap; ++import io.papermc.paper.registry.RegistryKey; ++import java.lang.reflect.Field; ++import java.lang.reflect.ParameterizedType; ++import java.util.Map; ++ ++@Deprecated ++public final class LegacyRegistryIdentifiers { ++ ++ public static final Map, RegistryKey> CLASS_TO_KEY_MAP; ++ ++ static { ++ final ImmutableMap.Builder, RegistryKey> builder = ImmutableMap.builder(); ++ try { ++ for (final Field field : RegistryKey.class.getFields()) { ++ if (field.getType() == RegistryKey.class) { ++ // get the legacy type from the RegistryKey generic parameter on the field ++ final Class legacyType = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; ++ builder.put(legacyType, (RegistryKey) field.get(null)); ++ } ++ } ++ } catch (final ReflectiveOperationException ex) { ++ throw new RuntimeException(ex); ++ } ++ CLASS_TO_KEY_MAP = builder.build(); ++ } ++ ++ private LegacyRegistryIdentifiers() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/legacy/package-info.java b/src/main/java/io/papermc/paper/registry/legacy/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4396982af55872fafbfeaf8161ad6f392726c773 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/legacy/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry.legacy; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/io/papermc/paper/registry/package-info.java b/src/main/java/io/papermc/paper/registry/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b80179ff90e085568d7ceafd9b17511789dc99b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java +index 10e1ba2208a902951035574797073e57f67adad9..22d874234db391747d2bf7feed1a21a7275c6638 100644 +--- a/src/main/java/net/minecraft/core/MappedRegistry.java ++++ b/src/main/java/net/minecraft/core/MappedRegistry.java +@@ -81,6 +81,14 @@ public class MappedRegistry implements WritableRegistry { + return MappedRegistry.this.getTags().map(Pair::getSecond); + } + }; ++ // Paper start ++ @Nullable ++ private Map beforeFrozen = new HashMap<>(2048); ++ public Map beforeFrozenView() { ++ Validate.validState(this.beforeFrozen != null, "Cannot get this after the registry is frozen"); ++ return Collections.unmodifiableMap(this.beforeFrozen); ++ } ++ // Paper end + + public MappedRegistry(ResourceKey> key, Lifecycle lifecycle) { + this(key, lifecycle, false); +@@ -162,6 +170,7 @@ public class MappedRegistry implements WritableRegistry { + } + + this.lifecycles.put(value, lifecycle); ++ Objects.requireNonNull(this.beforeFrozen).put(key.location(), value); // Paper + this.registryLifecycle = this.registryLifecycle.add(lifecycle); + this.holdersInOrder = null; + return reference; +@@ -335,6 +344,7 @@ public class MappedRegistry implements WritableRegistry { + return this; + } else { + this.frozen = true; ++ this.beforeFrozen = null; // Paper + this.byValue.forEach((value, entry) -> { + entry.bindValue(value); + }); +@@ -457,4 +467,12 @@ public class MappedRegistry implements WritableRegistry { + public HolderLookup.RegistryLookup asLookup() { + return this.lookup; + } ++ // Paper start ++ // used to clear intrusive holders from GameEvent, Item, Block, EntityType, and Fluid from unused instances of those types ++ public void clearIntrusiveHolder(T instance) { ++ if (this.unregisteredIntrusiveHolders != null) { ++ this.unregisteredIntrusiveHolders.remove(instance); ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +index b366389fd1aed47e04884e9e495df83ec7398ca3..22e2c992387e4efb6ff2b18fa3b82a3686e3297e 100644 +--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java ++++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +@@ -343,6 +343,7 @@ public class BuiltInRegistries { + } + public static void bootStrap(Runnable runnable) { + // Paper end ++ REGISTRY.freeze(); // Paper - freeze main registry early + createContents(); + runnable.run(); // Paper + freeze(); +@@ -362,6 +363,7 @@ public class BuiltInRegistries { + REGISTRY.freeze(); + + for(Registry registry : REGISTRY) { ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key()); // Paper + registry.freeze(); + } + +diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +index e1bddbbdbeea79115d0f987065c34e0f7f04d377..fd6986e931099f7843bd6f4fc9c0ddc4806b500d 100644 +--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java ++++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +@@ -61,10 +61,12 @@ public class RegistryDataLoader { + }).toList(); + RegistryOps.RegistryInfoLookup registryInfoLookup = createContext(baseRegistryManager, list); + list.forEach((loader) -> { ++ io.papermc.paper.registry.PaperRegistryAccess.instance().createRegistry(loader.getFirst()); // Paper + loader.getSecond().load(resourceManager, registryInfoLookup); + }); + list.forEach((loader) -> { + Registry registry = loader.getFirst(); ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key()); // Paper + + try { + registry.freeze(); +@@ -143,7 +145,7 @@ public class RegistryDataLoader { + DataResult dataResult = decoder.parse(registryOps, jsonElement); + E object = dataResult.getOrThrow(false, (error) -> { + }); +- newRegistry.register(resourceKey, object, resource.isBuiltin() ? Lifecycle.stable() : dataResult.lifecycle()); ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(newRegistry, resourceKey, object, resource.isBuiltin() ? Lifecycle.stable() : dataResult.lifecycle()); // Paper + } catch (Exception var20) { + exceptions.put(resourceKey, new IllegalStateException(String.format(Locale.ROOT, "Failed to parse %s from pack %s", resourceLocation, resource.sourcePackId()), var20)); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index 72c2bc09ce6eefc63c3bab5a8f183e48316d0196..7de20b041a0ec88043275f59546a892f26bdaff1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -82,52 +82,20 @@ public class CraftRegistry implements Registry { + return ((Handleable) bukkit).getHandle(); + } + +- /** +- * 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); +- } +- +- return null; +- } ++ // Paper - replace with PaperRegistries + +- private final Class bukkitClass; ++ private final Class bukkitClass; // Paper - this is just the class that needs to load to its static fields are initialized first + private final Map cache = new HashMap<>(); + private final net.minecraft.core.Registry minecraftRegistry; +- private final BiFunction minecraftToBukkit; ++ private final BiFunction minecraftToBukkit; // Paper ++ public final io.papermc.paper.registry.RegistryView view; // Paper + 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 + this.bukkitClass = bukkitClass; + this.minecraftRegistry = minecraftRegistry; + this.minecraftToBukkit = minecraftToBukkit; ++ this.view = new io.papermc.paper.registry.event.PaperRegistryView<>(this.minecraftRegistry, this.minecraftToBukkit); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 24365002bde70f75116e220ba614d4b9db9b0134..2ee73132f4ceaf745908865e2f5bf00a6f28f813 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -279,7 +279,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 + private YamlConfiguration configuration; + private YamlConfiguration commandsConfiguration; + private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); +@@ -2663,7 +2663,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 + } + + @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/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider +new file mode 100644 +index 0000000000000000000000000000000000000000..8bee1a5ed877a04e4d027593df1f42cefdd824e7 +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider +@@ -0,0 +1 @@ ++io.papermc.paper.registry.event.RegistryEventTypeProviderImpl +diff --git a/src/test/java/io/papermc/paper/registry/DummyRegistryAccess.java b/src/test/java/io/papermc/paper/registry/DummyRegistryAccess.java +new file mode 100644 +index 0000000000000000000000000000000000000000..64fec4a1b81e51c790734c525fed886e31c30e67 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/DummyRegistryAccess.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.registry; ++ ++import java.util.function.BooleanSupplier; ++import net.minecraft.core.RegistryAccess; ++import org.bukkit.support.AbstractTestingBase; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++@DefaultQualifier(NonNull.class) ++public class DummyRegistryAccess extends PaperRegistryAccess { ++ ++ @Override ++ public RegistryAccess getDelayedRegistryAccess() { ++ return AbstractTestingBase.REGISTRY_CUSTOM; ++ } ++ ++ @Override ++ public BooleanSupplier delayedValidCheck() { ++ //noinspection ConstantValue ++ return () -> AbstractTestingBase.REGISTRY_CUSTOM != null; ++ } ++} +diff --git a/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b9d00e65639521eecd44bd2be3e012264c3785f5 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/registry/LegacyRegistryIdentifierTest.java +@@ -0,0 +1,20 @@ ++package io.papermc.paper.registry; ++ ++import org.bukkit.GameEvent; ++import org.bukkit.MusicInstrument; ++import org.bukkit.inventory.meta.trim.TrimPattern; ++import org.bukkit.support.AbstractTestingBase; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertSame; ++ ++@Deprecated ++class LegacyRegistryIdentifierTest extends AbstractTestingBase { ++ ++ @Test ++ void testSeveralConversions() { ++ assertSame(RegistryKey.GAME_EVENT, PaperRegistryAccess.byType(GameEvent.class)); ++ assertSame(RegistryKey.TRIM_PATTERN, PaperRegistryAccess.byType(TrimPattern.class)); ++ assertSame(RegistryKey.INSTRUMENT, PaperRegistryAccess.byType(MusicInstrument.class)); ++ } ++} +diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java +index 3b3e44c5ed24f653f7dc1e5d3d4f0ff76084f277..deec35b073365b0fce66914a92b36e633d345605 100644 +--- a/src/test/java/org/bukkit/support/DummyServer.java ++++ b/src/test/java/org/bukkit/support/DummyServer.java +@@ -43,11 +43,6 @@ public final class DummyServer { + when(instance.getLootTable(any())).then(mock -> new CraftLootTable(mock.getArgument(0), + AbstractTestingBase.DATA_PACK.getLootData().getLootTable(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 start - testing additions + final Thread currentThread = Thread.currentThread(); + when(instance.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread)); +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..6c7526bbc7318f510f81f4073a158f7136017a56 +--- /dev/null ++++ b/src/test/resources/META-INF/services/io.papermc.paper.registry.RegistryAccess +@@ -0,0 +1 @@ ++io.papermc.paper.registry.DummyRegistryAccess diff --git a/patches/server/0497-TODO-Registry-Modification-API.patch b/patches/server/0497-TODO-Registry-Modification-API.patch deleted file mode 100644 index 5a7f3ae78d..0000000000 --- a/patches/server/0497-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 72c2bc09ce6eefc63c3bab5a8f183e48316d0196..b84e984e53834ef338afd7b61a656eb82a14349a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -114,6 +114,7 @@ public class CraftRegistry implements Registry { - if (bukkitClass == TrimPattern.class) { - return new CraftRegistry<>(TrimPattern.class, registryHolder.registryOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::new); - } -+ // TODO registry modification API - - return null; - } diff --git a/patches/server/0498-Add-StructuresLocateEvent.patch b/patches/server/0498-Add-StructuresLocateEvent.patch index 34dd0f2443..53cd96cebd 100644 --- a/patches/server/0498-Add-StructuresLocateEvent.patch +++ b/patches/server/0498-Add-StructuresLocateEvent.patch @@ -7,10 +7,10 @@ Co-authored-by: Jake Potrebic 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 +32,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 +67,6 @@ index 3e57142dd9cb23d43857d5a4cb30962e4b696b74..a6d5b3fa7e3437e0aec54eec4079e9f3 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 b84e984e53834ef338afd7b61a656eb82a14349a..13270b2197c594dc03d089aea46aa410dd9efd13 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -115,6 +115,11 @@ public class CraftRegistry implements Registry { - return new CraftRegistry<>(TrimPattern.class, registryHolder.registryOrThrow(Registries.TRIM_PATTERN), CraftTrimPattern::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 @@ -193,18 +169,6 @@ index 0000000000000000000000000000000000000000..9178fe0d01b998ca1442bf2511f8fc00 + System.setOut(out); + } +} -diff --git a/src/test/java/org/bukkit/registry/PerRegistryTest.java b/src/test/java/org/bukkit/registry/PerRegistryTest.java -index 4e4ea083063daf22f1bb785ef212958ea889c43b..1c4966520b6401e6571aa44d5934dfa280bc80e3 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 - - 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 --- a/src/test/java/org/bukkit/registry/RegistryArgumentAddedTest.java diff --git a/patches/server/0979-Improve-Registry.patch b/patches/server/0979-Improve-Registry.patch index 58247ca580..6c1f3a47ea 100644 --- a/patches/server/0979-Improve-Registry.patch +++ b/patches/server/0979-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 13270b2197c594dc03d089aea46aa410dd9efd13..493d054cdda04bc08ab610a09c2a1d0290ae046c 100644 +index 7de20b041a0ec88043275f59546a892f26bdaff1..d6ae37baabf780abbd5d543b3c382237ac595360 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -126,6 +126,7 @@ public class CraftRegistry implements Registry { +@@ -86,6 +86,7 @@ public class CraftRegistry implements Registry { - private final Class bukkitClass; + private final Class bukkitClass; // Paper - this is just the class that needs to load to its static fields are initialized first 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; -@@ -170,6 +171,7 @@ public class CraftRegistry implements Registry { + private final BiFunction minecraftToBukkit; // Paper + public final io.papermc.paper.registry.RegistryView view; // Paper +@@ -132,6 +133,7 @@ public class CraftRegistry implements Registry { } this.cache.put(namespacedKey, bukkit); @@ -24,7 +24,7 @@ index 13270b2197c594dc03d089aea46aa410dd9efd13..493d054cdda04bc08ab610a09c2a1d02 return bukkit; } -@@ -192,4 +194,11 @@ public class CraftRegistry implements Registry { +@@ -154,4 +156,11 @@ public class CraftRegistry implements Registry { return this.minecraftToBukkit.apply(namespacedKey, minecraft); } @@ -61,10 +61,10 @@ index 5a570bae1262f768d86a6078bfded427294ed135..bf13fe2f858ee35c84c5a1f3fb2f7df6 } } 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 4e4ea083063daf22f1bb785ef212958ea889c43b..dad7935f9a4c7c8bb2a755cc0631330a59834233 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 { +@@ -48,19 +48,22 @@ public class PerRegistryTest extends AbstractTestingBase { @ParameterizedTest @MethodSource("data") @@ -91,7 +91,7 @@ index 1c4966520b6401e6571aa44d5934dfa280bc80e3..010de6fbb75eb5d51639695d260f9160 this.assertSameMatchWithKeyMessage(registry, element, key.toString()); // namespace:key this.assertSameMatchWithKeyMessage(registry, element, key.getKey()); // key -@@ -72,7 +75,7 @@ public class PerRegistryTest extends AbstractTestingBase { +@@ -71,7 +74,7 @@ public class PerRegistryTest extends AbstractTestingBase { }); } diff --git a/patches/server/0999-Flat-bedrock-generator-settings.patch b/patches/server/0999-Flat-bedrock-generator-settings.patch index 7e54f34f22..330d198435 100644 --- a/patches/server/0999-Flat-bedrock-generator-settings.patch +++ b/patches/server/0999-Flat-bedrock-generator-settings.patch @@ -101,17 +101,17 @@ index 0000000000000000000000000000000000000000..02d98ec591b676acf64460d14d608860 + } +} diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java -index c887d34171f89c731d76c4ca92c70be2b1edc1e6..438ae006a8e7da0e5124415b8350ebfd45ac6a10 100644 +index 19f50b788f922aa6bfedc4693b5cc5eda0b89cb6..4a469612e383d4a4c7e34261ba9edb8fdb9f136f 100644 --- a/src/main/java/net/minecraft/server/Bootstrap.java +++ b/src/main/java/net/minecraft/server/Bootstrap.java -@@ -78,6 +78,7 @@ public class Bootstrap { +@@ -79,6 +79,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 902156477bdfc9917105f1229f760c26e5af302a..98c7f695093acbcf9382a5f07a7a89e373709763 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java diff --git a/patches/server/1047-Support-registry-mod-API-with-GameEvent.patch b/patches/server/1047-Support-registry-mod-API-with-GameEvent.patch new file mode 100644 index 0000000000..12f0dac69f --- /dev/null +++ b/patches/server/1047-Support-registry-mod-API-with-GameEvent.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 25 Feb 2023 21:25:08 -0800 +Subject: [PATCH] Support registry mod API with GameEvent + + +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +index abecec33b6c0dba7183057efbc1425d94958b458..d75b27803c300deaec384bca3dc6dc58aaf05868 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -50,7 +50,7 @@ public final class PaperRegistries { + static { + REGISTRY_ENTRIES = ImmutableList.>builder() + // built-ins +- .add(immutableBuiltIn(RegistryKey.GAME_EVENT, Registries.GAME_EVENT, GameEvent.class, CraftGameEvent::new)) ++ .add(writableBuiltIn(RegistryKey.GAME_EVENT, Registries.GAME_EVENT, GameEvent.class, CraftGameEvent::new, CraftGameEvent.Builder::new)) + .add(immutableBuiltIn(RegistryKey.STRUCTURE_TYPE, Registries.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new)) + .add(immutableBuiltIn(RegistryKey.INSTRUMENT, Registries.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new)) + .add(immutableBuiltIn(RegistryKey.ENCHANTMENT, Registries.ENCHANTMENT, Enchantment.class, CraftEnchantment::new)) +diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java +index f943a0342ab34f10284c1daa84ff7424541221c4..66f0791cba4be6e11feebf288707c9d865ae66a0 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java +@@ -87,7 +87,7 @@ public class GameEvent { + } + + private static GameEvent register(String id, int range) { +- return Registry.register(BuiltInRegistries.GAME_EVENT, id, new GameEvent(range)); ++ return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(BuiltInRegistries.GAME_EVENT, id, new GameEvent(range)); // Paper + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java +index ac9b4328cd55a68664a3f71186bc9a7be7cd9658..acb1f4c95226b0603ddae4ead9fcb5704b33ec98 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java +@@ -58,4 +58,43 @@ public class CraftGameEvent extends GameEvent implements Handleable { ++ ++ private int range = 16; ++ ++ public Builder(final io.papermc.paper.registry.TypedKey $, final net.minecraft.world.level.gameevent.@org.checkerframework.checker.nullness.qual.Nullable GameEvent nms) { ++ if (nms != null) { ++ this.range = nms.getNotificationRadius(); ++ } ++ } ++ ++ @Override ++ public int range() { ++ return this.range; ++ } ++ ++ @Override ++ public Builder range(final int range) { ++ this.range = range; ++ return this; ++ } ++ ++ @Override ++ public net.minecraft.world.level.gameevent.GameEvent build() { ++ return new net.minecraft.world.level.gameevent.GameEvent(this.range); ++ } ++ } ++ // Paper end + } diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java index 4e68423bb7..eedd4c0fe4 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java @@ -1,5 +1,7 @@ package io.papermc.testplugin; +import org.bukkit.GameEvent; +import org.bukkit.Registry; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; @@ -8,5 +10,13 @@ public final class TestPlugin extends JavaPlugin implements Listener { @Override public void onEnable() { this.getServer().getPluginManager().registerEvents(this, this); + + + final GameEvent newEvent = Registry.GAME_EVENT.get(TestPluginBootstrap.NEW_EVENT); + if (newEvent == null) { + throw new RuntimeException("could not find new event"); + } else { + System.out.println("New event: " + newEvent.getKey() + " " + newEvent.getRange()); + } } } diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java index e978b15f97..c18792b157 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java @@ -2,12 +2,34 @@ package io.papermc.testplugin; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import io.papermc.paper.plugin.bootstrap.PluginBootstrap; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.event.RegistryEvents; +import io.papermc.paper.registry.keys.GameEventKeys; +import net.kyori.adventure.key.Key; +import org.bukkit.GameEvent; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.framework.qual.DefaultQualifier; import org.jetbrains.annotations.NotNull; +@DefaultQualifier(NonNull.class) public class TestPluginBootstrap implements PluginBootstrap { + static final TypedKey NEW_EVENT = TypedKey.create(RegistryKey.GAME_EVENT, Key.key("machine_maker", "best_event")); + @Override public void bootstrap(@NotNull BootstrapContext context) { + final LifecycleEventManager lifecycleManager = context.getLifecycleManager(); + lifecycleManager.registerEventHandler(RegistryEvents.GAME_EVENT.newAdditionHandler(event -> { + if (event.key().equals(GameEventKeys.BLOCK_OPEN)) { + event.builder().range(event.builder().range() * 2); + } + }).priority(10)); + lifecycleManager.registerEventHandler(RegistryEvents.GAME_EVENT.preFreeze(), event -> { + event.registry().register(NEW_EVENT, builder -> { + builder.range(2); + }); + }); } - }