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 edbc6ff3ef..4815570cd6 100644 --- a/patches/api/0004-Code-Generation.patch +++ b/patches/api/0004-Code-Generation.patch @@ -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 b6f4810e387c22c4a70609ea1d605130245689a5..03824ae54e1bdb8b14f79b3c5e0294ae725e43f8 100644 diff --git a/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch b/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch index dee50d07c0..f89b9a6d45 100644 --- a/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch +++ b/patches/api/0243-Add-RegistryAccess-for-managing-registries.patch @@ -164,47 +164,20 @@ index 0000000000000000000000000000000000000000..b89e19c070f97c9662f1e16309446494 + } +} diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java -index c4b30b16ce4db754b958c493ad86d0863592c263..e376c95ac4db43a1c5233287f01b20b9c8b614bc 100644 +index 5dde0eac9aa6354f71a910aff1d5e484deef0a5d..9908ab753e983fba6e827980de68e7cf6f6feb13 100644 --- a/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java -@@ -2,11 +2,16 @@ package io.papermc.paper.registry; - - import net.kyori.adventure.key.Keyed; +@@ -4,7 +4,9 @@ import net.kyori.adventure.key.Keyed; import org.bukkit.GameEvent; -+import org.bukkit.MusicInstrument; + import org.bukkit.MusicInstrument; import org.bukkit.block.Biome; +import org.bukkit.damage.DamageType; -+import org.bukkit.enchantments.Enchantment; + import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Wolf; import org.bukkit.generator.structure.Structure; import org.bukkit.generator.structure.StructureType; import org.bukkit.inventory.meta.trim.TrimMaterial; - import org.bukkit.inventory.meta.trim.TrimPattern; -+import org.bukkit.potion.PotionEffectType; - import org.jetbrains.annotations.ApiStatus; - - import static io.papermc.paper.registry.RegistryKeyImpl.create; -@@ -40,6 +45,19 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { - * @see io.papermc.paper.registry.keys.StructureTypeKeys - */ - RegistryKey STRUCTURE_TYPE = create("worldgen/structure_type"); -+ /** -+ * Built-in registry for instruments. -+ */ -+ RegistryKey INSTRUMENT = create("instrument"); -+ /** -+ * Built-in registry for enchantments. -+ */ -+ RegistryKey ENCHANTMENT = create("enchantment"); -+ /** -+ * Built-in registry for potion effect types (mob effects). -+ */ -+ RegistryKey MOB_EFFECT = create("mob_effect"); -+ - - /* ********************** * - * Data-driven Registries * -@@ -64,4 +82,12 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { +@@ -82,4 +84,12 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * @see io.papermc.paper.registry.keys.TrimPatternKeys */ RegistryKey TRIM_PATTERN = create("trim_pattern"); @@ -237,30 +210,6 @@ index 9ad300fa1668cb59bbd85ff8091591db69b8c9dc..791813220b2504214b1adecc69093cd6 + } + } -diff --git a/src/main/java/io/papermc/paper/registry/TypedKey.java b/src/main/java/io/papermc/paper/registry/TypedKey.java -index 271454cd1b92ada4301025b57348ea77da9116a1..6f5a062ba7ee7173468ecea3c1855a233bf3855e 100644 ---- a/src/main/java/io/papermc/paper/registry/TypedKey.java -+++ b/src/main/java/io/papermc/paper/registry/TypedKey.java -@@ -38,7 +38,7 @@ public sealed interface TypedKey extends Keyed permits TypedKeyImpl { - * @return a new key for the value key and registry key - */ - @ApiStatus.Experimental -- static @NotNull TypedKey create(final @NotNull RegistryKey registryKey, final @NotNull Key key) { -+ static @NotNull TypedKey create(final @NotNull RegistryKey registryKey, final @NotNull Key key) { - return new TypedKeyImpl<>(key, registryKey); - } - } -diff --git a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java -index 3c3fd73f7742bb8602e2f9164dd4c1208a412255..1a97b3359c4ece5c29131da7c3f208aaa8fab66e 100644 ---- a/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java -+++ b/src/main/java/io/papermc/paper/registry/TypedKeyImpl.java -@@ -4,5 +4,5 @@ import net.kyori.adventure.key.Key; - import net.kyori.adventure.key.Keyed; - import org.jetbrains.annotations.NotNull; - --record TypedKeyImpl(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { -+record TypedKeyImpl(@NotNull Key key, @NotNull RegistryKey registryKey) implements TypedKey { - } diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index 732ed3724e784ad659cb4411dbd73b42a8330a2c..cbf660db860e73df21be426e63928f8aeec0ac90 100644 --- a/src/main/java/org/bukkit/Bukkit.java diff --git a/patches/api/0477-Registry-Modification-API.patch b/patches/api/0477-Registry-Modification-API.patch new file mode 100644 index 0000000000..ad28f0c763 --- /dev/null +++ b/patches/api/0477-Registry-Modification-API.patch @@ -0,0 +1,398 @@ +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/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/Registry.java b/src/main/java/org/bukkit/Registry.java +index c63a2d5d21eb599939ec7ae5e57506ff746e4174..6aecb2d04479439d9d133f723ef160a693f699c6 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -331,6 +331,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 + + // Paper start - improve Registry + /** diff --git a/patches/api/0478-Support-registry-mod-API-with-GameEvent.patch b/patches/api/0478-Support-registry-mod-API-with-GameEvent.patch new file mode 100644 index 0000000000..e2c724fe98 --- /dev/null +++ b/patches/api/0478-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/0019-Paper-Plugins.patch b/patches/server/0019-Paper-Plugins.patch index 7a19309b99..b2fbc0027f 100644 --- a/patches/server/0019-Paper-Plugins.patch +++ b/patches/server/0019-Paper-Plugins.patch @@ -760,16 +760,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; @@ -782,9 +784,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 @@ -800,6 +804,7 @@ index 0000000000000000000000000000000000000000..6c0f2c315387734f8dd4a7eca633aa0a + } + + storage.enter(); ++ this.enteredMap.put(entrypoint, true); + } + + @Override @@ -823,6 +828,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()); @@ -7208,17 +7217,24 @@ index bc91370654f5da33cbfe7d42431568915c1159d6..b43af53960978ac04bccde08544a5628 validate(REGISTRY); } diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java -index 15ee2f2a83bfef2f6891d9bfb2d3a8c14b24ffb1..d0d95d729853fc296c4931a2f73a3fc5f94302c9 100644 +index 15ee2f2a83bfef2f6891d9bfb2d3a8c14b24ffb1..bae46c0c18d4394849ac8e68e59a6cdd6ebfb4cc 100644 --- a/src/main/java/net/minecraft/server/Bootstrap.java +++ b/src/main/java/net/minecraft/server/Bootstrap.java -@@ -74,7 +74,11 @@ public class Bootstrap { +@@ -66,6 +66,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) { +@@ -74,7 +75,10 @@ public class Bootstrap { EntitySelectorOptions.bootStrap(); DispenseItemBehavior.bootStrap(); CauldronInteraction.bootStrap(); - BuiltInRegistries.bootStrap(); + // Paper start + BuiltInRegistries.bootStrap(() -> { -+ io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping + }); + // Paper end CreativeModeTabs.validate(); diff --git a/patches/server/0989-Flat-bedrock-generator-settings.patch b/patches/server/0989-Flat-bedrock-generator-settings.patch index 7103386726..477da3df0a 100644 --- a/patches/server/0989-Flat-bedrock-generator-settings.patch +++ b/patches/server/0989-Flat-bedrock-generator-settings.patch @@ -105,17 +105,17 @@ index 0000000000000000000000000000000000000000..e0d73113c937ddbcf8144f88b15a8d3d + } +} diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java -index 05f4be8dfff37ab6804a2d990b1f8c430d42dc7c..2a49a6a6bccabf588ba67b565d8f16fda04ba0b0 100644 +index 8ffc3b27b98de3a73bccdb9bb4fe5a47d2781d4e..c66afe7c6734756b00265599bf17ad29203996db 100644 --- a/src/main/java/net/minecraft/server/Bootstrap.java +++ b/src/main/java/net/minecraft/server/Bootstrap.java -@@ -76,6 +76,7 @@ public class Bootstrap { +@@ -77,6 +77,7 @@ public class Bootstrap { CauldronInteraction.bootStrap(); // Paper start BuiltInRegistries.bootStrap(() -> { + io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings - io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping }); // Paper end + CreativeModeTabs.validate(); diff --git a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java index dc765b92cc90f5f370254e68bbbdfa5add7935ce..8ce870a5341a61fbbaf42021ef7f7f615a6a3e09 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java diff --git a/patches/server/1046-Registry-Modification-API.patch b/patches/server/1046-Registry-Modification-API.patch new file mode 100644 index 0000000000..4085770792 --- /dev/null +++ b/patches/server/1046-Registry-Modification-API.patch @@ -0,0 +1,913 @@ +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 +index e3c16b2aee3da74c43c52a20f52fcde066f0d90d..5c246637630b9e85b710b41a522ba2de2aad5475 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -34,6 +34,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; + import org.checkerframework.framework.qual.DefaultQualifier; + + import static io.papermc.paper.registry.entry.RegistryEntry.entry; ++import static io.papermc.paper.registry.entry.RegistryEntry.writable; + + @DefaultQualifier(NonNull.class) + public final class PaperRegistries { +@@ -51,7 +52,7 @@ public final class PaperRegistries { + REGISTRY_ENTRIES = List.of( + // built-ins + entry(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT, Enchantment.class, CraftEnchantment::new), +- entry(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new), ++ writable(Registries.GAME_EVENT, RegistryKey.GAME_EVENT, GameEvent.class, CraftGameEvent::new, CraftGameEvent.Builder::new), + entry(Registries.INSTRUMENT, RegistryKey.INSTRUMENT, MusicInstrument.class, CraftMusicInstrument::new), + entry(Registries.MOB_EFFECT, RegistryKey.MOB_EFFECT, PotionEffectType.class, CraftPotionEffectType::new), + entry(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE, StructureType.class, CraftStructureType::new), +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +index db6aa01babce66cbfe95b0f758d2bcec4d7351dc..9cecc6a9ed2a660c8967786ac0a31118349095e1 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +@@ -80,6 +80,14 @@ public class PaperRegistryAccess implements RegistryAccess { + return possiblyUnwrap(registryHolder.get()); + } + ++ 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"); ++ } ++ + private static Registry possiblyUnwrap(final Registry registry) { + if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry + return delayedRegistry.delegate(); +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..4cf32102a134ebef67d3893cfd24bf0add321eb9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.registry; ++ ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public interface PaperRegistryBuilder extends RegistryBuilder { ++ ++ M build(); ++ ++ @FunctionalInterface ++ interface Filler> { ++ ++ B fill(final TypedKey key, final @Nullable M nms); ++ ++ default Factory asFactory() { ++ return key -> this.fill(key, null); ++ } ++ } ++ ++ @FunctionalInterface ++ interface Factory> { ++ ++ B create(final TypedKey key); ++ } ++} +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..4291d875a2df5c75d648c02e7607b3fab82f8c63 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java +@@ -0,0 +1,169 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Preconditions; ++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.entry.RegistryEntryInfo; ++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.Holder; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.RegistrationInfo; ++import net.minecraft.core.Registry; ++import net.minecraft.core.WritableRegistry; ++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() { ++ } ++ ++ /** ++ * For {@link Registry#register(Registry, String, Object)} ++ */ ++ public M registerWithListeners(final Registry registry, final String id, final M nms) { ++ return this.registerWithListeners(registry, new ResourceLocation(id), nms); ++ } ++ ++ /** ++ * For {@link Registry#register(Registry, ResourceLocation, Object)} ++ */ ++ public M registerWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { ++ return this.registerWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); ++ } ++ ++ /** ++ * For {@link Registry#register(Registry, ResourceKey, Object)} ++ */ ++ public M registerWithListeners(final Registry registry, final ResourceKey key, final M nms) { ++ return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, PaperRegistryListenerManager::registerWithInstance); ++ } ++ ++ /** ++ * For {@link Registry#registerForHolder(Registry, ResourceLocation, Object)} ++ */ ++ public Holder.Reference registerForHolderWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { ++ return this.registerForHolderWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); ++ } ++ ++ /** ++ * For {@link Registry#registerForHolder(Registry, ResourceKey, Object)} ++ */ ++ public Holder.Reference registerForHolderWithListeners(final Registry registry, final ResourceKey key, final M nms) { ++ return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, WritableRegistry::register); ++ } ++ ++ public > void registerWithListeners( ++ final Registry registry, ++ final ResourceKey key, ++ final M nms, ++ final RegistrationInfo registrationInfo ++ ) { ++ this.registerWithListeners(registry, key, nms, registrationInfo, WritableRegistry::register); ++ } ++ ++ public , R> R registerWithListeners( ++ final Registry registry, ++ final ResourceKey key, ++ final M nms, ++ final RegistrationInfo registrationInfo, ++ final RegisterMethod registerMethod ++ ) { ++ 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 RegistryEntryInfo entry = PaperRegistries.getEntry(registry.key()); ++ if (!(entry instanceof RegistryEntry.Modifiable) || !this.additionHooks.hasHooks(entry.apiKey())) { ++ return registerMethod.register((WritableRegistry) registry, key, nms, registrationInfo); ++ } ++ final RegistryEntry.Modifiable modifiableEntry = (RegistryEntry.Modifiable) entry; ++ final CraftRegistry craftRegistry = (CraftRegistry) PaperRegistryAccess.instance().getRegistry(entry.apiKey()); ++ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.apiKey(), 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, registrationInfo, registerMethod); ++ } ++ ++ public > void registerWithListeners( ++ final Registry registry, ++ final RegistryView registryView, ++ final RegistryEntry.Modifiable entry, ++ final ResourceKey key, ++ final @Nullable M oldNms, ++ final B builder, ++ final RegistrationInfo registrationInfo ++ ) { ++ this.registerWithListeners(registry, registryView, entry, key, oldNms, builder, registrationInfo, WritableRegistry::register); ++ } ++ ++ public , R> R registerWithListeners( ++ final Registry registry, ++ final RegistryView registryView, ++ final RegistryEntry.Modifiable entry, ++ final ResourceKey key, ++ final @Nullable M oldNms, ++ final B builder, ++ final RegistrationInfo registrationInfo, ++ final RegisterMethod registerMethod ++ ) { ++ @Subst("namespace:key") final ResourceLocation beingAdded = key.location(); ++ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.apiKey(), Key.key(beingAdded.getNamespace(), beingAdded.getPath())); ++ final RegistryAdditionEventImpl event = entry.createAdditionEvent(typedKey, builder, registryView); ++ LifecycleEventRunner.INSTANCE.callEvent(this.additionHooks.getHook(entry.apiKey()), event); ++ if (oldNms != null) { ++ ((MappedRegistry) registry).clearIntrusiveHolder(oldNms); ++ } ++ final M newNms = event.builder().build(); ++ return registerMethod.register((WritableRegistry) registry, key, newNms, registrationInfo); ++ } ++ ++ private static M registerWithInstance(final WritableRegistry writableRegistry, final ResourceKey key, final M value, final RegistrationInfo registrationInfo) { ++ writableRegistry.register(key, value, registrationInfo); ++ return value; ++ } ++ ++ @FunctionalInterface ++ public interface RegisterMethod { ++ ++ R register(WritableRegistry writableRegistry, ResourceKey key, M value, RegistrationInfo registrationInfo); ++ } ++ ++ public > void runFreezeListeners(final ResourceKey> resourceKey) { ++ final @Nullable RegistryEntryInfo entry = PaperRegistries.getEntry(resourceKey); ++ if (!(entry instanceof RegistryEntry.Writable) || !this.preFreezeHooks.hasHooks(entry.apiKey())) { ++ return; ++ } ++ final RegistryEntry.Writable writableEntry = (RegistryEntry.Writable) entry; ++ final RegistryPreFreezeEventImpl event = writableEntry.createPreFreezeEvent(PaperRegistryAccess.instance().getWritableRegistry(entry.apiKey())); ++ LifecycleEventRunner.INSTANCE.callEvent(this.preFreezeHooks.getHook(entry.apiKey()), 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); ++ } ++ ++ 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); ++ } ++} +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..9c18f50e5599d12cdec5e978020eb5ad53892b90 +--- /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 io.papermc.paper.registry.entry.WritableRegistryEntry; ++import java.util.function.BiFunction; ++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 PaperRegistryBuilder.Factory builderFactory; ++ private final BiFunction minecraftToBukkit; ++ ++ public SimpleWritableCraftRegistry(final WritableRegistryEntry entry, final Registry nmsRegistry, final PaperRegistryBuilder.Factory builderFactory, final BiFunction minecraftToBukkit) { ++ super(entry, (MappedRegistry) nmsRegistry); ++ this.builderFactory = builderFactory; ++ 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.builderFactory.create(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..89594ca9a2e955785e8a4dfd66dc1f45d9efe065 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java +@@ -0,0 +1,59 @@ ++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.Optional; ++import java.util.function.Consumer; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.RegistrationInfo; ++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 static final RegistrationInfo FROM_PLUGIN = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); ++ ++ private final RegistryEntry.Writable entry; ++ private final MappedRegistry registry; ++ public final WritableRegistry modifiableView; ++ ++ public WritableCraftRegistry(final RegistryEntry.Writable entry, final MappedRegistry registry) { ++ super(entry.toPreload(), 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, ++ FROM_PLUGIN ++ ); ++ } ++ ++ @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/ModifiableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fd130cc1e0d36196b98f4949aaa966bcaec9c953 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java +@@ -0,0 +1,38 @@ ++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; ++ ++public class ModifiableRegistryEntry> extends CraftRegistryEntry implements RegistryEntry.Modifiable { ++ ++ protected final PaperRegistryBuilder.Filler builderFiller; ++ ++ protected ModifiableRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler builderFiller ++ ) { ++ super(mcKey, apiKey, toPreload, minecraftToBukkit); ++ this.builderFiller = builderFiller; ++ } ++ ++ @Override ++ public RegistryAdditionEventImpl createAdditionEvent(final TypedKey key, final B initialBuilder, final RegistryView view) { ++ return new RegistryAdditionEventImpl<>(key, initialBuilder, this.apiKey(), view); ++ } ++ ++ @Override ++ public B fillBuilder(final TypedKey key, final M nms) { ++ return this.builderFiller.fill(key, nms); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +index 9cda87cd03a04998cb527a4be9d3950523646cd3..5a108fd327c7cb223627e0e44791f0cf0392fd3b 100644 +--- a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +@@ -1,7 +1,14 @@ + package io.papermc.paper.registry.entry; + ++import io.papermc.paper.registry.PaperRegistryBuilder; + import io.papermc.paper.registry.RegistryHolder; + 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.event.WritableRegistry; + import io.papermc.paper.registry.legacy.DelayedRegistryEntry; + import java.util.function.BiFunction; + import net.minecraft.core.Registry; +@@ -27,7 +34,38 @@ public interface RegistryEntry(this); + } + +- static RegistryEntry> entry(final ResourceKey> minecraftRegistryKey, final RegistryKey apiRegistryKey, final Class classToPreload, final BiFunction minecraftToBukkit) { +- return new CraftRegistryEntry<>(minecraftRegistryKey, apiRegistryKey, classToPreload, minecraftToBukkit); ++ interface Modifiable> extends RegistryEntryInfo { ++ ++ RegistryAdditionEventImpl createAdditionEvent(TypedKey key, B initialBuilder, RegistryView view); ++ ++ B fillBuilder(TypedKey key, M nms); ++ } ++ ++ interface Writable> extends Modifiable { // TODO remove Keyed ++ ++ RegistryPreFreezeEventImpl createPreFreezeEvent(WritableCraftRegistry writableRegistry); ++ } ++ ++ static RegistryEntry entry(final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit) { ++ return new CraftRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit); ++ } ++ ++ static > RegistryEntry modifiable(final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler filler) { ++ return new ModifiableRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit, filler); ++ } ++ ++ static > RegistryEntry writable(final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler filler) { ++ return new WritableRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit, filler); + } + } +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..57bae24373f3af6a37decf8a656317d68daaa21a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java +@@ -0,0 +1,56 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.RegistryView; ++import io.papermc.paper.registry.SimpleWritableCraftRegistry; ++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 java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++ ++public class WritableRegistryEntry> extends BaseRegistryEntry> implements RegistryEntry.Writable { ++ ++ private final PaperRegistryBuilder.Filler builderFiller; ++ ++ protected WritableRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler builderFiller ++ ) { ++ super(mcKey, apiKey, toPreload, minecraftToBukkit); ++ this.builderFiller = builderFiller; ++ } ++ ++ private WritableCraftRegistry createRegistry(final Registry registry) { ++ return new SimpleWritableCraftRegistry<>(this, registry, this.builderFiller.asFactory(), this.minecraftToBukkit); ++ } ++ ++ @Override ++ public RegistryHolder> createRegistryHolder(final Registry nmsRegistry) { ++ return new RegistryHolder<>(() -> this.createRegistry(nmsRegistry)); ++ } ++ ++ @Override ++ public RegistryAdditionEventImpl createAdditionEvent(final TypedKey key, final B initialBuilder, final RegistryView view) { ++ return new RegistryAdditionEventImpl<>(key, initialBuilder, this.apiKey(), view); ++ } ++ ++ @Override ++ public B fillBuilder(final TypedKey key, final M nms) { ++ return this.builderFiller.fill(key, nms); ++ } ++ ++ @Override ++ public RegistryPreFreezeEventImpl createPreFreezeEvent(final WritableCraftRegistry registry) { ++ return new RegistryPreFreezeEventImpl<>(this.apiKey(), registry.modifiableView); ++ } ++} +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..d68698725f6e90fa05db3668ea559c25a559cd25 +--- /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 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) { ++ 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..a318fa8cd83d44546412462e80df38624ea04954 +--- /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..4ffb90d495dbe45e2fa6df9e61f13eee7c77f5a8 +--- /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/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 72c0c4a12aea39fa1c1967fa0277ed117471107e..7af48c1cb6985769cea840a01f8290b73380be29 100644 +--- a/src/main/java/net/minecraft/core/MappedRegistry.java ++++ b/src/main/java/net/minecraft/core/MappedRegistry.java +@@ -77,6 +77,14 @@ public class MappedRegistry implements WritableRegistry { + } + }; + private final Object tagAdditionLock = new Object(); ++ // Paper start ++ @Nullable ++ private Map beforeFrozen = new HashMap<>(2048); ++ public Map beforeFrozenView() { ++ com.google.common.base.Preconditions.checkState(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); +@@ -144,6 +152,7 @@ public class MappedRegistry implements WritableRegistry { + this.byId.add(reference); + this.toId.put(value, i); + this.registrationInfos.put(key, info); ++ Objects.requireNonNull(this.beforeFrozen).put(key.location(), value); // Paper + this.registryLifecycle = this.registryLifecycle.add(info.lifecycle()); + return reference; + } +@@ -323,6 +332,7 @@ public class MappedRegistry implements WritableRegistry { + } else { + this.frozen = true; + this.byValue.forEach((value, entry) -> entry.bindValue((T)value)); ++ this.beforeFrozen = null; // Paper + List list = this.byKey + .entrySet() + .stream() +@@ -436,4 +446,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(final 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 8daee5a7935e3253834c4cbe81d5e8886f776dad..d7da62360d48d8c12c489296b4ee2ee44c0c2d93 100644 +--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java ++++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +@@ -310,6 +310,7 @@ public class BuiltInRegistries { + } + public static void bootStrap(Runnable runnable) { + // Paper end ++ REGISTRY.freeze(); // Paper - freeze main registry early + createContents(); + runnable.run(); // Paper + freeze(); +@@ -328,6 +329,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 d59356df2d98de873fc5accc749f87fa3d685267..cf3f3a737c4efe832bea8797d0c9af18f87d932f 100644 +--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java ++++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +@@ -188,7 +188,7 @@ public class RegistryDataLoader { + JsonElement jsonElement = JsonParser.parseReader(reader); + DataResult dataResult = decoder.parse(ops, jsonElement); + E object = dataResult.getOrThrow(); +- registry.register(key, object, entryInfo); ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(registry, key, object, entryInfo); // Paper + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index a3a00778a8fdbc13f8adbf4e4fbc4f1303d22789..0ec0b8f1d2a9b601194fe07c511dc7ce1abdaea1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -106,13 +106,15 @@ public class CraftRegistry implements Registry { + 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 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) { // Paper - relax preload class ++ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit) { // Paper - relax preload class + 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/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/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/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..61c7779fbb --- /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/net/minecraft/world/level/gameevent/GameEvent.java b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java +index ef0eecd4404fcce4046b53ff9e176ea59978d1ac..c4f8a03aac42507df2d9a84b3acf53887d2eed86 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/GameEvent.java +@@ -81,7 +81,7 @@ public record GameEvent(int notificationRadius) { + } + + private static Holder.Reference register(String id, int range) { +- return Registry.registerForHolder(BuiltInRegistries.GAME_EVENT, new ResourceLocation(id), new GameEvent(range)); ++ return io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerForHolderWithListeners(BuiltInRegistries.GAME_EVENT, new ResourceLocation(id), new GameEvent(range)); // Paper + } + + public static record Context(@Nullable Entity sourceEntity, @Nullable BlockState affectedState) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java +index ac9b4328cd55a68664a3f71186bc9a7be7cd9658..34c63a685606a55936f27dfe4393d23e46d8d20d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftGameEvent.java +@@ -19,10 +19,12 @@ public class CraftGameEvent extends GameEvent implements Handleable handleKey; // Paper + + public CraftGameEvent(NamespacedKey key, net.minecraft.world.level.gameevent.GameEvent handle) { + this.key = key; + this.handle = handle; ++ this.handleKey = net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(this.key)); // Paper + } + + @Override +@@ -58,4 +60,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.notificationRadius(); ++ } ++ } ++ ++ @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); + }); + }); } - }