From eb11b190bf4a5ba53546f5b92cecfed14b93ce6c Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Thu, 26 Feb 2026 16:26:49 +0100 Subject: [PATCH 1/8] Implement potion registry --- .../paper/registry/keys/PotionTypeKeys.java | 356 ++++++++++++++++++ .../papermc/paper/registry/RegistryKey.java | 6 +- .../src/main/java/org/bukkit/Registry.java | 2 +- .../main/java/org/bukkit/UnsafeValues.java | 13 +- .../java/org/bukkit/potion/PotionType.java | 241 +++++++----- .../java/io/papermc/generator/Rewriters.java | 3 +- .../generator/registry/RegistryEntries.java | 7 +- .../paper/registry/PaperRegistries.java | 4 +- .../paper/registry/PaperSimpleRegistry.java | 5 - .../flag/PaperFeatureFlagProviderImpl.java | 2 - .../craftbukkit/potion/CraftPotionType.java | 66 +--- .../craftbukkit/util/CraftMagicNumbers.java | 8 - .../provider/RegistriesArgumentProvider.java | 10 +- 13 files changed, 530 insertions(+), 193 deletions(-) create mode 100644 paper-api/src/generated/java/io/papermc/paper/registry/keys/PotionTypeKeys.java diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/PotionTypeKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/PotionTypeKeys.java new file mode 100644 index 000000000000..bf3b7252f219 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/PotionTypeKeys.java @@ -0,0 +1,356 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.bukkit.potion.PotionType; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#POTION}. + * + * @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" +}) +@NullMarked +@GeneratedClass +public final class PotionTypeKeys { + /** + * {@code minecraft:awkward} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey AWKWARD = create(key("awkward")); + + /** + * {@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:harming} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HARMING = create(key("harming")); + + /** + * {@code minecraft:healing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HEALING = create(key("healing")); + + /** + * {@code minecraft:infested} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey INFESTED = create(key("infested")); + + /** + * {@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:leaping} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LEAPING = create(key("leaping")); + + /** + * {@code minecraft:long_fire_resistance} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_FIRE_RESISTANCE = create(key("long_fire_resistance")); + + /** + * {@code minecraft:long_invisibility} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_INVISIBILITY = create(key("long_invisibility")); + + /** + * {@code minecraft:long_leaping} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_LEAPING = create(key("long_leaping")); + + /** + * {@code minecraft:long_night_vision} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_NIGHT_VISION = create(key("long_night_vision")); + + /** + * {@code minecraft:long_poison} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_POISON = create(key("long_poison")); + + /** + * {@code minecraft:long_regeneration} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_REGENERATION = create(key("long_regeneration")); + + /** + * {@code minecraft:long_slow_falling} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_SLOW_FALLING = create(key("long_slow_falling")); + + /** + * {@code minecraft:long_slowness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_SLOWNESS = create(key("long_slowness")); + + /** + * {@code minecraft:long_strength} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_STRENGTH = create(key("long_strength")); + + /** + * {@code minecraft:long_swiftness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_SWIFTNESS = create(key("long_swiftness")); + + /** + * {@code minecraft:long_turtle_master} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_TURTLE_MASTER = create(key("long_turtle_master")); + + /** + * {@code minecraft:long_water_breathing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_WATER_BREATHING = create(key("long_water_breathing")); + + /** + * {@code minecraft:long_weakness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey LONG_WEAKNESS = create(key("long_weakness")); + + /** + * {@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:mundane} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey MUNDANE = create(key("mundane")); + + /** + * {@code minecraft:night_vision} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey NIGHT_VISION = create(key("night_vision")); + + /** + * {@code minecraft:oozing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey OOZING = create(key("oozing")); + + /** + * {@code minecraft:poison} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey POISON = create(key("poison")); + + /** + * {@code minecraft: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:slow_falling} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SLOW_FALLING = create(key("slow_falling")); + + /** + * {@code minecraft:slowness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SLOWNESS = create(key("slowness")); + + /** + * {@code minecraft: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:strong_harming} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_HARMING = create(key("strong_harming")); + + /** + * {@code minecraft:strong_healing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_HEALING = create(key("strong_healing")); + + /** + * {@code minecraft:strong_leaping} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_LEAPING = create(key("strong_leaping")); + + /** + * {@code minecraft:strong_poison} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_POISON = create(key("strong_poison")); + + /** + * {@code minecraft:strong_regeneration} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_REGENERATION = create(key("strong_regeneration")); + + /** + * {@code minecraft:strong_slowness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_SLOWNESS = create(key("strong_slowness")); + + /** + * {@code minecraft:strong_strength} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_STRENGTH = create(key("strong_strength")); + + /** + * {@code minecraft:strong_swiftness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_SWIFTNESS = create(key("strong_swiftness")); + + /** + * {@code minecraft:strong_turtle_master} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey STRONG_TURTLE_MASTER = create(key("strong_turtle_master")); + + /** + * {@code minecraft:swiftness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SWIFTNESS = create(key("swiftness")); + + /** + * {@code minecraft:thick} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey THICK = create(key("thick")); + + /** + * {@code minecraft:turtle_master} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey TURTLE_MASTER = create(key("turtle_master")); + + /** + * {@code minecraft:water} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WATER = create(key("water")); + + /** + * {@code minecraft:water_breathing} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WATER_BREATHING = create(key("water_breathing")); + + /** + * {@code minecraft:weakness} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WEAKNESS = create(key("weakness")); + + /** + * {@code minecraft:weaving} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WEAVING = create(key("weaving")); + + /** + * {@code minecraft:wind_charged} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey WIND_CHARGED = create(key("wind_charged")); + + private PotionTypeKeys() { + } + + private static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.POTION, key); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index dcee3d88f5b7..238a238a6216 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -132,6 +132,11 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * @see io.papermc.paper.registry.keys.GameRuleKeys */ RegistryKey> GAME_RULE = create("game_rule"); + /** + * Built-in registry for potions. + * + */ + RegistryKey POTION = create("potion"); /* ********************** * * Data-driven Registries * @@ -238,7 +243,6 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * ******************* */ RegistryKey ENTITY_TYPE = create("entity_type"); RegistryKey PARTICLE_TYPE = create("particle_type"); - RegistryKey POTION = create("potion"); RegistryKey> MEMORY_MODULE_TYPE = create("memory_module_type"); /** diff --git a/paper-api/src/main/java/org/bukkit/Registry.java b/paper-api/src/main/java/org/bukkit/Registry.java index 0859653089ac..398a0ad1ab18 100644 --- a/paper-api/src/main/java/org/bukkit/Registry.java +++ b/paper-api/src/main/java/org/bukkit/Registry.java @@ -215,7 +215,7 @@ public Iterator iterator() { * * @see PotionType */ - Registry POTION = registryFor(RegistryKey.POTION); // Paper + Registry POTION = registryFor(RegistryKey.POTION); /** * Server statistics. * diff --git a/paper-api/src/main/java/org/bukkit/UnsafeValues.java b/paper-api/src/main/java/org/bukkit/UnsafeValues.java index 020ee30c0a7d..d582aff73afb 100644 --- a/paper-api/src/main/java/org/bukkit/UnsafeValues.java +++ b/paper-api/src/main/java/org/bukkit/UnsafeValues.java @@ -3,6 +3,7 @@ import com.google.common.collect.Multimap; import io.papermc.paper.entity.EntitySerializationFlag; import io.papermc.paper.registry.RegistryKey; +import java.util.Map; import net.kyori.adventure.text.event.HoverEvent; import org.bukkit.advancement.Advancement; import org.bukkit.attribute.Attribute; @@ -19,11 +20,9 @@ import org.bukkit.material.MaterialData; import org.bukkit.plugin.InvalidPluginException; import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.potion.PotionType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; /** * This interface provides value conversions that may be specific to a @@ -117,16 +116,6 @@ public interface UnsafeValues { // Paper - replace with better system - /** - * Do not use, method will get removed, and the plugin won't run - * - * @param key of the potion type - * @return an internal potion data - */ - @ApiStatus.Internal - @Deprecated(since = "1.20.2", forRemoval = true) - PotionType.InternalPotionData getInternalPotionData(NamespacedKey key); - /** * Create a new {@link DamageSource.Builder}. * diff --git a/paper-api/src/main/java/org/bukkit/potion/PotionType.java b/paper-api/src/main/java/org/bukkit/potion/PotionType.java index f7bac2d6a27e..ffefb31fb15e 100644 --- a/paper-api/src/main/java/org/bukkit/potion/PotionType.java +++ b/paper-api/src/main/java/org/bukkit/potion/PotionType.java @@ -1,94 +1,140 @@ package org.bukkit.potion; -import com.google.common.base.Suppliers; +import com.google.common.base.Preconditions; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.world.flag.FeatureDependant; import java.util.List; -import java.util.function.Supplier; +import java.util.Locale; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; import org.bukkit.Bukkit; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.util.OldEnum; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** - * This enum reflects and matches each potion state that can be obtained from - * the Creative mode inventory + * This list reflects and matches each potion state that can be obtained from + * the creative mode inventory */ -public enum PotionType implements Keyed, io.papermc.paper.world.flag.FeatureDependant { // Paper - feature flag API +@NullMarked +public interface PotionType extends OldEnum, Keyed, FeatureDependant { + // Start generate - PotionType - AWKWARD("awkward"), - FIRE_RESISTANCE("fire_resistance"), - HARMING("harming"), - HEALING("healing"), - INFESTED("infested"), - INVISIBILITY("invisibility"), - LEAPING("leaping"), - LONG_FIRE_RESISTANCE("long_fire_resistance"), - LONG_INVISIBILITY("long_invisibility"), - LONG_LEAPING("long_leaping"), - LONG_NIGHT_VISION("long_night_vision"), - LONG_POISON("long_poison"), - LONG_REGENERATION("long_regeneration"), - LONG_SLOW_FALLING("long_slow_falling"), - LONG_SLOWNESS("long_slowness"), - LONG_STRENGTH("long_strength"), - LONG_SWIFTNESS("long_swiftness"), - LONG_TURTLE_MASTER("long_turtle_master"), - LONG_WATER_BREATHING("long_water_breathing"), - LONG_WEAKNESS("long_weakness"), - LUCK("luck"), - MUNDANE("mundane"), - NIGHT_VISION("night_vision"), - OOZING("oozing"), - POISON("poison"), - REGENERATION("regeneration"), - SLOW_FALLING("slow_falling"), - SLOWNESS("slowness"), - STRENGTH("strength"), - STRONG_HARMING("strong_harming"), - STRONG_HEALING("strong_healing"), - STRONG_LEAPING("strong_leaping"), - STRONG_POISON("strong_poison"), - STRONG_REGENERATION("strong_regeneration"), - STRONG_SLOWNESS("strong_slowness"), - STRONG_STRENGTH("strong_strength"), - STRONG_SWIFTNESS("strong_swiftness"), - STRONG_TURTLE_MASTER("strong_turtle_master"), - SWIFTNESS("swiftness"), - THICK("thick"), - TURTLE_MASTER("turtle_master"), - WATER("water"), - WATER_BREATHING("water_breathing"), - WEAKNESS("weakness"), - WEAVING("weaving"), - WIND_CHARGED("wind_charged"); - // End generate - PotionType + PotionType AWKWARD = getType("awkward"); + + PotionType FIRE_RESISTANCE = getType("fire_resistance"); + + PotionType HARMING = getType("harming"); + + PotionType HEALING = getType("healing"); + + PotionType INFESTED = getType("infested"); + + PotionType INVISIBILITY = getType("invisibility"); + + PotionType LEAPING = getType("leaping"); + + PotionType LONG_FIRE_RESISTANCE = getType("long_fire_resistance"); + + PotionType LONG_INVISIBILITY = getType("long_invisibility"); + + PotionType LONG_LEAPING = getType("long_leaping"); + + PotionType LONG_NIGHT_VISION = getType("long_night_vision"); + + PotionType LONG_POISON = getType("long_poison"); + + PotionType LONG_REGENERATION = getType("long_regeneration"); + + PotionType LONG_SLOW_FALLING = getType("long_slow_falling"); + + PotionType LONG_SLOWNESS = getType("long_slowness"); + + PotionType LONG_STRENGTH = getType("long_strength"); + + PotionType LONG_SWIFTNESS = getType("long_swiftness"); + + PotionType LONG_TURTLE_MASTER = getType("long_turtle_master"); + + PotionType LONG_WATER_BREATHING = getType("long_water_breathing"); + + PotionType LONG_WEAKNESS = getType("long_weakness"); + + PotionType LUCK = getType("luck"); + + PotionType MUNDANE = getType("mundane"); + + PotionType NIGHT_VISION = getType("night_vision"); + + PotionType OOZING = getType("oozing"); + + PotionType POISON = getType("poison"); + + PotionType REGENERATION = getType("regeneration"); + + PotionType SLOW_FALLING = getType("slow_falling"); + + PotionType SLOWNESS = getType("slowness"); + + PotionType STRENGTH = getType("strength"); - private final NamespacedKey key; - private final Supplier internalPotionDataSupplier; + PotionType STRONG_HARMING = getType("strong_harming"); - PotionType(String key) { - this.key = NamespacedKey.minecraft(key); - this.internalPotionDataSupplier = Suppliers.memoize(() -> Bukkit.getUnsafe().getInternalPotionData(this.key)); + PotionType STRONG_HEALING = getType("strong_healing"); + + PotionType STRONG_LEAPING = getType("strong_leaping"); + + PotionType STRONG_POISON = getType("strong_poison"); + + PotionType STRONG_REGENERATION = getType("strong_regeneration"); + + PotionType STRONG_SLOWNESS = getType("strong_slowness"); + + PotionType STRONG_STRENGTH = getType("strong_strength"); + + PotionType STRONG_SWIFTNESS = getType("strong_swiftness"); + + PotionType STRONG_TURTLE_MASTER = getType("strong_turtle_master"); + + PotionType SWIFTNESS = getType("swiftness"); + + PotionType THICK = getType("thick"); + + PotionType TURTLE_MASTER = getType("turtle_master"); + + PotionType WATER = getType("water"); + + PotionType WATER_BREATHING = getType("water_breathing"); + + PotionType WEAKNESS = getType("weakness"); + + PotionType WEAVING = getType("weaving"); + + PotionType WIND_CHARGED = getType("wind_charged"); + // End generate - PotionType + + private static PotionType getType(final @KeyPattern.Value String key) { + return Registry.POTION.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); } /** * @return the potion effect type of this potion type * @deprecated Potions can have multiple effects use {@link #getPotionEffects()} */ - @Nullable @Deprecated(since = "1.20.2") - public PotionEffectType getEffectType() { - return internalPotionDataSupplier.get().getEffectType(); + default @Nullable PotionEffectType getEffectType() { + final List effects = this.getPotionEffects(); + return effects.isEmpty() ? null : effects.getFirst().getType(); } /** * @return a list of all effects this potion type has */ - @NotNull - public List getPotionEffects() { - return internalPotionDataSupplier.get().getPotionEffects(); - } + List getPotionEffects(); /** * @return if this potion type is instant @@ -96,9 +142,7 @@ public List getPotionEffects() { * Use {@link PotionEffectType#isInstant()} in combination with {@link #getPotionEffects()} and {@link PotionEffect#getType()} */ @Deprecated(since = "1.20.2") - public boolean isInstant() { - return internalPotionDataSupplier.get().isInstant(); - } + boolean isInstant(); /** * Checks if the potion type has an upgraded state. @@ -107,9 +151,7 @@ public boolean isInstant() { * * @return true if the potion type can be upgraded; */ - public boolean isUpgradeable() { - return internalPotionDataSupplier.get().isUpgradeable(); - } + boolean isUpgradeable(); /** * Checks if the potion type has an extended state. @@ -117,13 +159,9 @@ public boolean isUpgradeable() { * * @return true if the potion type can be extended */ - public boolean isExtendable() { - return internalPotionDataSupplier.get().isExtendable(); - } + boolean isExtendable(); - public int getMaxLevel() { - return internalPotionDataSupplier.get().getMaxLevel(); - } + int getMaxLevel(); /** * @param effectType the effect to get by @@ -131,40 +169,35 @@ public int getMaxLevel() { * @deprecated Misleading */ @Deprecated(since = "1.9") - @Nullable - public static PotionType getByEffect(@Nullable PotionEffectType effectType) { - if (effectType == null) - return WATER; - for (PotionType type : PotionType.values()) { - if (effectType.equals(type.getEffectType())) + static @Nullable PotionType getByEffect(@Nullable PotionEffectType effectType) { + if (effectType == null) return WATER; + for (PotionType type : Registry.POTION) { + if (effectType.equals(type.getEffectType())) { return type; + } } return null; } - @NotNull - @Override - public NamespacedKey getKey() { - return key; + /** + * @param name of the potion type. + * @return the potion type with the given name. + * @deprecated only for backwards compatibility, use {@link Registry#get(NamespacedKey)} instead. + */ + @Deprecated(since = "1.21.11", forRemoval = true) @ApiStatus.ScheduledForRemoval(inVersion = "1.22") // Paper - will be removed via asm-utils + static PotionType valueOf(String name) { + NamespacedKey key = NamespacedKey.fromString(name.toLowerCase(Locale.ROOT)); + PotionType potionType = key == null ? null : Bukkit.getUnsafe().get(RegistryKey.POTION, key); + Preconditions.checkArgument(potionType != null, "No potion type found with the name %s", name); + return potionType; } /** - * @deprecated Do not use, interface will get removed, and the plugin won't run + * @return an array of all known potion types. + * @deprecated use {@link Registry#iterator()}. */ - @Deprecated(since = "1.20.2", forRemoval = true) - @ApiStatus.Internal - public interface InternalPotionData { - - PotionEffectType getEffectType(); - - List getPotionEffects(); - - boolean isInstant(); - - boolean isUpgradeable(); - - boolean isExtendable(); - - int getMaxLevel(); + @Deprecated(since = "1.21.11", forRemoval = true) @ApiStatus.ScheduledForRemoval(inVersion = "1.22") // Paper - will be removed via asm-utils + static PotionType[] values() { + return Registry.POTION.stream().toArray(PotionType[]::new); } } diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index dee77d43ba9a..fe7bda0786b9 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -5,7 +5,6 @@ import io.papermc.generator.registry.RegistryEntries; import io.papermc.generator.rewriter.registration.PatternSourceSetRewriter; import io.papermc.generator.rewriter.types.Types; -import io.papermc.generator.rewriter.types.registry.EnumRegistryRewriter; import io.papermc.generator.rewriter.types.registry.FeatureFlagRewriter; import io.papermc.generator.rewriter.types.registry.PaperFeatureFlagMapping; import io.papermc.generator.rewriter.types.registry.RegistryFieldRewriter; @@ -111,7 +110,6 @@ public static void bootstrap(PatternSourceSetRewriter apiSourceSet, PatternSourc private static void bootstrapApi(PatternSourceSetRewriter sourceSet) { sourceSet - .register("PotionType", PotionType.class, new EnumRegistryRewriter<>(Registries.POTION)) .register("EntityType", EntityType.class, new EntityTypeRewriter()) .register("DisplaySlot", DisplaySlot.class, new EnumCloneRewriter<>(net.minecraft.world.scores.DisplaySlot.class) { @Override @@ -225,6 +223,7 @@ protected String rewriteFieldType(Holder.Reference(Registries.PIG_VARIANT, "getVariant")) .register("ZombieNautilusVariant", ZombieNautilus.Variant.class, new RegistryFieldRewriter<>(Registries.ZOMBIE_NAUTILUS_VARIANT, "getVariant")) .register("Dialog", Dialog.class, new RegistryFieldRewriter<>(Registries.DIALOG, "getDialog")) + .register("PotionType", PotionType.class, new RegistryFieldRewriter<>(Registries.POTION, "getType")) .register("MemoryKey", MemoryKey.class, new MemoryKeyRewriter()) // .register("ItemType", org.bukkit.inventory.ItemType.class, new io.papermc.generator.rewriter.types.simple.ItemTypeRewriter()) - disable for now, lynx want the generic type .register("BlockType", BlockType.class, new BlockTypeRewriter()) diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 0a9f1e9a68f7..63a1f25c87bd 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -153,7 +153,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> REGISTRY_CLASS_NAME_BASED_ON_API = Set.of( BlockType.class, - ItemType.class + ItemType.class, + PotionType.class ); public static final List> BUILT_IN = List.of( @@ -170,7 +171,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> DATA_DRIVEN = List.of( @@ -198,7 +200,6 @@ private static RegistryEntry inconsistentEntry(ResourceKey> API_ONLY = List.of( entry(Registries.ENTITY_TYPE, net.minecraft.world.entity.EntityType.class, EntityType.class), entry(Registries.PARTICLE_TYPE, ParticleTypes.class, Particle.class), - entry(Registries.POTION, Potions.class, PotionType.class), entry(Registries.MEMORY_MODULE_TYPE, MemoryModuleType.class, MemoryKey.class) ); diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index 121babcfdda5..c61d1be2a3ee 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -75,6 +75,7 @@ import org.bukkit.craftbukkit.legacy.FieldRename; import org.bukkit.craftbukkit.map.CraftMapCursor; import org.bukkit.craftbukkit.potion.CraftPotionEffectType; +import org.bukkit.craftbukkit.potion.CraftPotionType; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.damage.DamageType; import org.bukkit.enchantments.Enchantment; @@ -94,6 +95,7 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.map.MapCursor; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; import org.jspecify.annotations.Nullable; import static io.papermc.paper.registry.entry.RegistryEntryBuilder.start; @@ -121,6 +123,7 @@ public final class PaperRegistries { start(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT).craft(Sound.class, CraftSound::new, true).create(PaperSoundEventRegistryEntry.PaperBuilder::new, RegistryEntryMeta.RegistryModificationApiSupport.NONE), start(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE).craft(DataComponentTypes.class, PaperDataComponentType::of).build(), start(Registries.GAME_RULE, RegistryKey.GAME_RULE).craft(GameRule.class, CraftGameRule::new).build(), + start(Registries.POTION, RegistryKey.POTION).craft(PotionType.class, CraftPotionType::new).build(), // data-driven start(Registries.BIOME, RegistryKey.BIOME).craft(Biome.class, CraftBiome::new).build().delayed(), @@ -146,7 +149,6 @@ public final class PaperRegistries { // api-only start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType), start(Registries.PARTICLE_TYPE, RegistryKey.PARTICLE_TYPE).apiOnly(PaperSimpleRegistry::particleType), - start(Registries.POTION, RegistryKey.POTION).apiOnly(PaperSimpleRegistry::potion), start(Registries.MEMORY_MODULE_TYPE, RegistryKey.MEMORY_MODULE_TYPE).apiOnly(() -> org.bukkit.Registry.MEMORY_MODULE_TYPE) // End generate - RegistryDefinitions ); diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java index 7c3fdfb46efb..6f078f66f549 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperSimpleRegistry.java @@ -11,7 +11,6 @@ import org.bukkit.Particle; import org.bukkit.Registry; import org.bukkit.entity.EntityType; -import org.bukkit.potion.PotionType; import org.jspecify.annotations.NullMarked; @NullMarked @@ -25,10 +24,6 @@ static Registry particleType() { return new PaperSimpleRegistry<>(Particle.class, BuiltInRegistries.PARTICLE_TYPE); } - static Registry potion() { - return new PaperSimpleRegistry<>(PotionType.class, BuiltInRegistries.POTION); - } - private final net.minecraft.core.Registry nmsRegistry; protected PaperSimpleRegistry(final Class type, final net.minecraft.core.Registry nmsRegistry) { diff --git a/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java b/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java index c0953bb67dcf..55e8b2d9f46a 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java +++ b/paper-server/src/main/java/io/papermc/paper/world/flag/PaperFeatureFlagProviderImpl.java @@ -47,8 +47,6 @@ static FeatureElement getFeatureElement(final FeatureDependant dependant) { if (dependant instanceof final EntityType entityType) { // TODO remove when EntityType is server-backed return CraftEntityType.bukkitToMinecraft(entityType); - } else if (dependant instanceof final PotionType potionType) { - return CraftPotionType.bukkitToMinecraft(potionType); } else if (dependant instanceof final GameRule gameRule) { return () -> CraftGameRule.bukkitToMinecraft(gameRule).requiredFeatures(); } else { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java index 4bf9b8aebc80..5852c8cf91ba 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java @@ -1,59 +1,38 @@ package org.bukkit.craftbukkit.potion; import com.google.common.base.Preconditions; -import com.google.common.base.Suppliers; import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.util.OldEnumHolderable; +import io.papermc.paper.world.flag.PaperFeatureDependent; import java.util.List; import java.util.Locale; -import java.util.function.Supplier; import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.alchemy.Potion; import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; -public class CraftPotionType implements PotionType.InternalPotionData { +public class CraftPotionType extends OldEnumHolderable implements PotionType, PaperFeatureDependent { public static PotionType minecraftHolderToBukkit(Holder minecraft) { return CraftPotionType.minecraftToBukkit(minecraft.value()); } public static PotionType minecraftToBukkit(Potion minecraft) { - Preconditions.checkArgument(minecraft != null); - - net.minecraft.core.Registry registry = CraftRegistry.getMinecraftRegistry(Registries.POTION); - PotionType bukkit = Registry.POTION.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().identifier())); - - Preconditions.checkArgument(bukkit != null); - - return bukkit; + return CraftRegistry.minecraftToBukkit(minecraft, Registries.POTION); } public static Potion bukkitToMinecraft(PotionType bukkit) { - Preconditions.checkArgument(bukkit != null); - - return CraftRegistry.getMinecraftRegistry(Registries.POTION) - .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow(); + return CraftRegistry.bukkitToMinecraft(bukkit); } public static Holder bukkitToMinecraftHolder(PotionType bukkit) { - Preconditions.checkArgument(bukkit != null); - - net.minecraft.core.Registry registry = CraftRegistry.getMinecraftRegistry(Registries.POTION); - - if (registry.wrapAsHolder(CraftPotionType.bukkitToMinecraft(bukkit)) instanceof Holder.Reference holder) { - return holder; - } - - throw new IllegalArgumentException("No Reference holder found for " + bukkit - + ", this can happen if a plugin creates its own sound effect with out properly registering it."); + return CraftRegistry.bukkitToMinecraftHolder(bukkit); } public static String bukkitToString(PotionType bukkit) { @@ -76,49 +55,34 @@ public static PotionType stringToBukkit(String string) { return CraftRegistry.get(RegistryKey.POTION, key, ApiVersion.CURRENT); } - private final NamespacedKey key; - private final Potion potion; - private final Supplier> potionEffects; - private final Supplier upgradeable; - private final Supplier extendable; - private final Supplier maxLevel; - - public CraftPotionType(NamespacedKey key, Potion potion) { - this.key = key; - this.potion = potion; - this.potionEffects = Suppliers.memoize(() -> potion.getEffects().stream().map(CraftPotionUtil::toBukkit).toList()); - this.upgradeable = Suppliers.memoize(() -> Registry.POTION.get(new NamespacedKey(key.getNamespace(), "strong_" + key.getKey())) != null); - this.extendable = Suppliers.memoize(() -> Registry.POTION.get(new NamespacedKey(key.getNamespace(), "long_" + key.getKey())) != null); - this.maxLevel = Suppliers.memoize(() -> this.isUpgradeable() ? 2 : 1); - } + private static int count = 0; - @Override - public PotionEffectType getEffectType() { - return this.getPotionEffects().isEmpty() ? null : this.getPotionEffects().get(0).getType(); + public CraftPotionType(final Holder holder) { + super(holder, count++); } @Override public List getPotionEffects() { - return this.potionEffects.get(); + return this.getHandle().getEffects().stream().map(CraftPotionUtil::toBukkit).toList(); } @Override public boolean isInstant() { - return this.potion.hasInstantEffects(); + return this.getHandle().hasInstantEffects(); } @Override public boolean isUpgradeable() { - return this.upgradeable.get(); + return BuiltInRegistries.POTION.containsKey(this.getHolder().unwrapKey().orElseThrow().identifier().withPrefix("strong_")); } @Override public boolean isExtendable() { - return this.extendable.get(); + return BuiltInRegistries.POTION.containsKey(this.getHolder().unwrapKey().orElseThrow().identifier().withPrefix("long_")); } @Override public int getMaxLevel() { - return this.maxLevel.get(); + return this.isUpgradeable() ? 2 : 1; } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index fc52e06d52a6..51128928a845 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -458,14 +458,6 @@ public String getTranslationKey(final Attribute attribute) { return attribute.getTranslationKey(); } - @Override - public PotionType.InternalPotionData getInternalPotionData(NamespacedKey namespacedKey) { - Potion potionRegistry = CraftRegistry.getMinecraftRegistry(Registries.POTION) - .getOptional(CraftNamespacedKey.toMinecraft(namespacedKey)).orElseThrow(); - - return new CraftPotionType(namespacedKey, potionRegistry); - } - @Override public DamageSource.Builder createDamageSourceBuilder(DamageType damageType) { return new CraftDamageSourceBuilder(damageType); diff --git a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java index 00b949fc0982..251bd35ff556 100644 --- a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +++ b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java @@ -13,18 +13,19 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.effect.MobEffect; -import net.minecraft.world.entity.animal.feline.CatVariant; import net.minecraft.world.entity.animal.chicken.ChickenVariant; import net.minecraft.world.entity.animal.cow.CowVariant; -import net.minecraft.world.entity.animal.pig.PigVariant; -import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariant; +import net.minecraft.world.entity.animal.feline.CatVariant; import net.minecraft.world.entity.animal.frog.FrogVariant; +import net.minecraft.world.entity.animal.nautilus.ZombieNautilusVariant; +import net.minecraft.world.entity.animal.pig.PigVariant; import net.minecraft.world.entity.animal.wolf.WolfSoundVariant; import net.minecraft.world.entity.animal.wolf.WolfVariant; import net.minecraft.world.entity.decoration.painting.PaintingVariant; import net.minecraft.world.entity.npc.villager.VillagerProfession; import net.minecraft.world.entity.npc.villager.VillagerType; import net.minecraft.world.item.Instrument; +import net.minecraft.world.item.alchemy.Potion; import net.minecraft.world.level.block.entity.BannerPattern; import net.minecraft.world.level.saveddata.maps.MapDecorationType; import org.bukkit.Art; @@ -69,6 +70,7 @@ import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern; import org.bukkit.craftbukkit.map.CraftMapCursor; import org.bukkit.craftbukkit.potion.CraftPotionEffectType; +import org.bukkit.craftbukkit.potion.CraftPotionType; import org.bukkit.damage.DamageType; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Cat; @@ -87,6 +89,7 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.map.MapCursor; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.Arguments; @@ -149,6 +152,7 @@ public Object[] get() { register(Registries.ZOMBIE_NAUTILUS_VARIANT, ZombieNautilus.Variant.class, CraftZombieNautilus.CraftVariant.class, ZombieNautilusVariant.class); register(Registries.DIALOG, Dialog.class, PaperDialog.class, net.minecraft.server.dialog.Dialog.class); register(Registries.GAME_RULE, GameRule.class, GameRules.class, CraftGameRule.class, net.minecraft.world.level.gamerules.GameRule.class); + register(Registries.POTION, PotionType.class, CraftPotionType.class, Potion.class); } private static void register(ResourceKey> registryKey, Class api, Class impl, Class internal) { From 9a6f5eb291026624957baf348a96434a68c767d9 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:25:11 +0100 Subject: [PATCH 2/8] bytecode rewriting --- .../papermc/paper/registry/RegistryKey.java | 2 +- .../PaperSimplePluginClassLoader.java | 4 +- .../bytecode/ClassToInterfaceRules.java | 63 +++++++++++++++++++ .../ClassloaderBytecodeModifier.java | 2 +- .../PaperClassloaderBytecodeModifier.java | 1 - ...ader.bytecode.ClassloaderBytecodeModifier} | 0 6 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java rename paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/{ => bytecode}/ClassloaderBytecodeModifier.java (89%) rename paper-server/src/main/resources/META-INF/services/{io.papermc.paper.plugin.entrypoint.classloader.ClassloaderBytecodeModifier => io.papermc.paper.plugin.entrypoint.classloader.bytecode.ClassloaderBytecodeModifier} (100%) diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index 238a238a6216..d73cc7e97c29 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -134,7 +134,7 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { RegistryKey> GAME_RULE = create("game_rule"); /** * Built-in registry for potions. - * + * @see io.papermc.paper.registry.keys.PotionTypeKeys */ RegistryKey POTION = create("potion"); diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java index d97f63347cda..2eba88f1c7df 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java @@ -1,9 +1,8 @@ package io.papermc.paper.plugin.entrypoint.classloader; import io.papermc.paper.plugin.configuration.PluginMeta; +import io.papermc.paper.plugin.entrypoint.classloader.bytecode.ClassloaderBytecodeModifier; import io.papermc.paper.plugin.util.NamespaceChecker; -import org.jetbrains.annotations.ApiStatus; - import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -16,6 +15,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; +import org.jetbrains.annotations.ApiStatus; /** * Represents a simple classloader used for paper plugin bootstrappers. diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java new file mode 100644 index 000000000000..fb4384603ffe --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java @@ -0,0 +1,63 @@ +package io.papermc.paper.plugin.entrypoint.classloader.bytecode; + +import io.papermc.asm.ClassInfoProvider; +import io.papermc.asm.RewriteRuleVisitorFactory; +import io.papermc.asm.rules.classes.ClassToInterfaceRule; +import io.papermc.paper.util.OldEnumHolderable; +import java.util.Map; +import java.util.Set; +import org.bukkit.craftbukkit.potion.CraftPotionType; +import org.bukkit.potion.PotionType; +import org.bukkit.util.OldEnum; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; + +public final class ClassToInterfaceRules { + + private static final RewriteRuleVisitorFactory VISITOR_FACTORY = RewriteRuleVisitorFactory.create( + Opcodes.ASM9, + chain -> { + for (final Class klass : classes()) { + chain.then(new ClassToInterfaceRule(klass.describeConstable().orElseThrow(), null)); + } + + for (final Map.Entry>, Class>> entry : enums()) { + chain.then(new ClassToInterfaceRule(entry.getKey().describeConstable().orElseThrow(), null)); + } + // todo later bump asm-utils and move static methods out + /* + chain.then(new EnumToInterfaceRule(enums().stream().collect(Collectors.toMap(entry -> { + return entry.getKey().describeConstable().orElseThrow(); + }, entry -> { + return entry.getValue().describeConstable().orElseThrow(); + }))));*/ + }, + ClassInfoProvider.basic() + ); + + private ClassToInterfaceRules() { + } + + public static ClassVisitor visitor(final ClassVisitor parent) { + return VISITOR_FACTORY.createVisitor(parent); + } + + public static byte[] processClass(final byte[] bytes) { + final ClassReader classReader = new ClassReader(bytes); + final ClassWriter classWriter = new ClassWriter(classReader, 0); + classReader.accept(visitor(classWriter), 0); + return classWriter.toByteArray(); + } + + private static Set>, Class>>> enums() { + return Set.of( + Map.entry(PotionType.class, CraftPotionType.class) + ); + } + + private static Set> classes() { + return Set.of(); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/ClassloaderBytecodeModifier.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassloaderBytecodeModifier.java similarity index 89% rename from paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/ClassloaderBytecodeModifier.java rename to paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassloaderBytecodeModifier.java index 93b5196a960f..fcbc60462b71 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/ClassloaderBytecodeModifier.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassloaderBytecodeModifier.java @@ -1,4 +1,4 @@ -package io.papermc.paper.plugin.entrypoint.classloader; +package io.papermc.paper.plugin.entrypoint.classloader.bytecode; import io.papermc.paper.plugin.configuration.PluginMeta; import net.kyori.adventure.util.Services; diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java index ac6ad60900b1..11e8452ce535 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java @@ -3,7 +3,6 @@ import com.google.common.collect.Iterators; import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.plugin.configuration.PluginMeta; -import io.papermc.paper.plugin.entrypoint.classloader.ClassloaderBytecodeModifier; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; diff --git a/paper-server/src/main/resources/META-INF/services/io.papermc.paper.plugin.entrypoint.classloader.ClassloaderBytecodeModifier b/paper-server/src/main/resources/META-INF/services/io.papermc.paper.plugin.entrypoint.classloader.bytecode.ClassloaderBytecodeModifier similarity index 100% rename from paper-server/src/main/resources/META-INF/services/io.papermc.paper.plugin.entrypoint.classloader.ClassloaderBytecodeModifier rename to paper-server/src/main/resources/META-INF/services/io.papermc.paper.plugin.entrypoint.classloader.bytecode.ClassloaderBytecodeModifier From 194ccf1df65ed7adb9d5273dd6256238612ef8c7 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Thu, 26 Feb 2026 17:52:47 +0100 Subject: [PATCH 3/8] better holder --- .../java/org/bukkit/craftbukkit/potion/CraftPotionType.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java index 5852c8cf91ba..b1dc1136042f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java @@ -16,11 +16,13 @@ import org.bukkit.craftbukkit.legacy.FieldRename; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionType; +import org.jspecify.annotations.NullMarked; +@NullMarked public class CraftPotionType extends OldEnumHolderable implements PotionType, PaperFeatureDependent { public static PotionType minecraftHolderToBukkit(Holder minecraft) { - return CraftPotionType.minecraftToBukkit(minecraft.value()); + return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.POTION); } public static PotionType minecraftToBukkit(Potion minecraft) { From ab7eae594b342092c7ed58f83efa3d1c4497cb0f Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 28 Feb 2026 02:17:55 -0800 Subject: [PATCH 4/8] Some fixes --- .../java/org/bukkit/potion/PotionType.java | 23 +------ .../bytecode/ClassToInterfaceRules.java | 35 +++------- .../io/papermc/paper/util/Holderable.java | 1 + .../paper/util/LegacyEnumHolderable.java | 66 +++++++++++++++++++ .../craftbukkit/legacy/FieldRename.java | 3 +- .../craftbukkit/potion/CraftPotionType.java | 19 +++++- settings.gradle.kts | 1 + test-plugin/build.gradle.kts | 3 +- .../io/papermc/testplugin/TestPlugin.java | 6 ++ 9 files changed, 105 insertions(+), 52 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java diff --git a/paper-api/src/main/java/org/bukkit/potion/PotionType.java b/paper-api/src/main/java/org/bukkit/potion/PotionType.java index ffefb31fb15e..d840f5d5efc5 100644 --- a/paper-api/src/main/java/org/bukkit/potion/PotionType.java +++ b/paper-api/src/main/java/org/bukkit/potion/PotionType.java @@ -21,7 +21,7 @@ * the creative mode inventory */ @NullMarked -public interface PotionType extends OldEnum, Keyed, FeatureDependant { +public interface PotionType extends Keyed, FeatureDependant { // Start generate - PotionType PotionType AWKWARD = getType("awkward"); @@ -179,25 +179,4 @@ private static PotionType getType(final @KeyPattern.Value String key) { return null; } - /** - * @param name of the potion type. - * @return the potion type with the given name. - * @deprecated only for backwards compatibility, use {@link Registry#get(NamespacedKey)} instead. - */ - @Deprecated(since = "1.21.11", forRemoval = true) @ApiStatus.ScheduledForRemoval(inVersion = "1.22") // Paper - will be removed via asm-utils - static PotionType valueOf(String name) { - NamespacedKey key = NamespacedKey.fromString(name.toLowerCase(Locale.ROOT)); - PotionType potionType = key == null ? null : Bukkit.getUnsafe().get(RegistryKey.POTION, key); - Preconditions.checkArgument(potionType != null, "No potion type found with the name %s", name); - return potionType; - } - - /** - * @return an array of all known potion types. - * @deprecated use {@link Registry#iterator()}. - */ - @Deprecated(since = "1.21.11", forRemoval = true) @ApiStatus.ScheduledForRemoval(inVersion = "1.22") // Paper - will be removed via asm-utils - static PotionType[] values() { - return Registry.POTION.stream().toArray(PotionType[]::new); - } } diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java index fb4384603ffe..50ccb4dd808c 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java @@ -2,13 +2,12 @@ import io.papermc.asm.ClassInfoProvider; import io.papermc.asm.RewriteRuleVisitorFactory; -import io.papermc.asm.rules.classes.ClassToInterfaceRule; -import io.papermc.paper.util.OldEnumHolderable; +import io.papermc.asm.rules.classes.EnumToInterfaceRule; +import java.lang.constant.ClassDesc; import java.util.Map; -import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.craftbukkit.potion.CraftPotionType; import org.bukkit.potion.PotionType; -import org.bukkit.util.OldEnum; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; @@ -19,20 +18,8 @@ public final class ClassToInterfaceRules { private static final RewriteRuleVisitorFactory VISITOR_FACTORY = RewriteRuleVisitorFactory.create( Opcodes.ASM9, chain -> { - for (final Class klass : classes()) { - chain.then(new ClassToInterfaceRule(klass.describeConstable().orElseThrow(), null)); - } - - for (final Map.Entry>, Class>> entry : enums()) { - chain.then(new ClassToInterfaceRule(entry.getKey().describeConstable().orElseThrow(), null)); - } - // todo later bump asm-utils and move static methods out - /* - chain.then(new EnumToInterfaceRule(enums().stream().collect(Collectors.toMap(entry -> { - return entry.getKey().describeConstable().orElseThrow(); - }, entry -> { - return entry.getValue().describeConstable().orElseThrow(); - }))));*/ + Map descs = classes().entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().describeConstable().orElseThrow(), entry -> entry.getValue().describeConstable().orElseThrow())); + chain.then(new EnumToInterfaceRule(descs)); }, ClassInfoProvider.basic() ); @@ -46,18 +33,14 @@ public static ClassVisitor visitor(final ClassVisitor parent) { public static byte[] processClass(final byte[] bytes) { final ClassReader classReader = new ClassReader(bytes); - final ClassWriter classWriter = new ClassWriter(classReader, 0); + final ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); classReader.accept(visitor(classWriter), 0); return classWriter.toByteArray(); } - private static Set>, Class>>> enums() { - return Set.of( - Map.entry(PotionType.class, CraftPotionType.class) + private static Map, Class> classes() { + return Map.of( + PotionType.class, CraftPotionType.class ); } - - private static Set> classes() { - return Set.of(); - } } diff --git a/paper-server/src/main/java/io/papermc/paper/util/Holderable.java b/paper-server/src/main/java/io/papermc/paper/util/Holderable.java index a1927b6bcea6..2bdfa8c7733b 100644 --- a/paper-server/src/main/java/io/papermc/paper/util/Holderable.java +++ b/paper-server/src/main/java/io/papermc/paper/util/Holderable.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; +import io.papermc.asm.rules.classes.LegacyEnum; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; import net.kyori.adventure.key.Key; diff --git a/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java b/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java new file mode 100644 index 000000000000..cf4b5845ab1c --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java @@ -0,0 +1,66 @@ +package io.papermc.paper.util; + +import com.google.common.base.Preconditions; +import io.papermc.asm.rules.classes.LegacyEnum; +import io.papermc.paper.registry.HolderableBase; +import java.util.Locale; +import net.minecraft.core.Holder; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public abstract class LegacyEnumHolderable> extends HolderableBase implements Holderable, LegacyEnum, Keyed { + + private final int ordinal; + private final @Nullable String name; + + protected LegacyEnumHolderable(final Holder holder, final int ordinal) { + super(holder); + this.ordinal = ordinal; + if (holder instanceof final Holder.Reference reference) { + // For backwards compatibility, minecraft values will still return the uppercase name without the namespace, + // in case plugins use, for example, the name as a key in a config file to receive registry item specific values. + // Custom registry items will return the key with namespace. For a plugin this should look like a new registry item + // (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly). + if (NamespacedKey.MINECRAFT.equals(reference.key().identifier().getNamespace())) { + this.name = reference.key().identifier().getPath().toUpperCase(Locale.ROOT); + } else { + this.name = reference.key().identifier().toString(); + } + } else { + this.name = null; + } + } + + @Override + @Deprecated + public int compareTo(final I other) { + this.checkIsReference(); + return this.ordinal - other.ordinal(); + } + + @Override + @Deprecated + public String name() { + this.checkIsReference(); + return this.name; + } + + @Override + @Deprecated + public int ordinal() { + this.checkIsReference(); + return this.ordinal; + } + + private void checkIsReference() { + Preconditions.checkState(this.holder.kind() == Holder.Kind.REFERENCE, "Cannot call method for this registry item, because it is not registered."); + } + + @Override + public String toString() { + return this.implToString(); + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java index 23354fc0d5ca..bd9babd470ff 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/FieldRename.java @@ -13,6 +13,7 @@ import org.bukkit.craftbukkit.legacy.reroute.InjectPluginVersion; import org.bukkit.craftbukkit.legacy.reroute.RerouteMethodName; import org.bukkit.craftbukkit.legacy.reroute.RerouteStatic; +import org.bukkit.craftbukkit.potion.CraftPotionType; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemFlag; @@ -271,7 +272,7 @@ public static String convertPotionTypeName(ApiVersion version, String from) { @RerouteStatic("org/bukkit/potion/PotionType") public static PotionType valueOf_PotionType(String name) { // We don't have version-specific changes, so just use current, and don't inject a version - return PotionType.valueOf(FieldRename.convertPotionTypeName(ApiVersion.CURRENT, name)); + return CraftPotionType.valueOf(FieldRename.convertPotionTypeName(ApiVersion.CURRENT, name)); } // MusicInstrument diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java index b1dc1136042f..7dd7f8323078 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java @@ -3,7 +3,7 @@ import com.google.common.base.Preconditions; import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.RegistryKey; -import io.papermc.paper.util.OldEnumHolderable; +import io.papermc.paper.util.LegacyEnumHolderable; import io.papermc.paper.world.flag.PaperFeatureDependent; import java.util.List; import java.util.Locale; @@ -11,7 +11,9 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.world.item.alchemy.Potion; +import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.legacy.FieldRename; import org.bukkit.potion.PotionEffect; @@ -19,7 +21,7 @@ import org.jspecify.annotations.NullMarked; @NullMarked -public class CraftPotionType extends OldEnumHolderable implements PotionType, PaperFeatureDependent { +public class CraftPotionType extends LegacyEnumHolderable implements PotionType, PaperFeatureDependent { public static PotionType minecraftHolderToBukkit(Holder minecraft) { return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.POTION); @@ -87,4 +89,17 @@ public boolean isExtendable() { public int getMaxLevel() { return this.isUpgradeable() ? 2 : 1; } + + @Deprecated // bytecode rewrites target this + public static PotionType valueOf(final String name) { + final NamespacedKey key = NamespacedKey.fromString(name.toLowerCase(Locale.ROOT)); + final PotionType potionType = key == null ? null : Bukkit.getUnsafe().get(RegistryKey.POTION, key); + Preconditions.checkArgument(potionType != null, "No potion type found with the name %s", name); + return potionType; + } + + @Deprecated // bytecode rewrites target this + public static PotionType[] values() { + return Registry.POTION.stream().toArray(PotionType[]::new); + } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 9289c95a7301..bd3e72bac7bc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,6 +9,7 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } +includeBuild("../asm-utils") if (!file(".git").exists()) { val errorText = """ diff --git a/test-plugin/build.gradle.kts b/test-plugin/build.gradle.kts index 3dd4b5f5cad5..8d1e71986cb1 100644 --- a/test-plugin/build.gradle.kts +++ b/test-plugin/build.gradle.kts @@ -1,7 +1,8 @@ version = "1.0.0-SNAPSHOT" dependencies { - compileOnly(project(":paper-api")) + // compileOnly(project(":paper-api")) + compileOnly("io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT") } tasks.processResources { 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 fd891f5b1fad..fccea4053175 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java @@ -2,6 +2,7 @@ import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.potion.PotionType; public final class TestPlugin extends JavaPlugin implements Listener { @@ -9,6 +10,11 @@ public final class TestPlugin extends JavaPlugin implements Listener { public void onEnable() { this.getServer().getPluginManager().registerEvents(this, this); + System.out.println(PotionType.AWKWARD.ordinal()); + System.out.println(PotionType.LONG_FIRE_RESISTANCE.ordinal()); + System.out.println(PotionType.LONG_FIRE_RESISTANCE.compareTo(PotionType.FIRE_RESISTANCE)); + System.out.println(PotionType.values()); + System.out.println(PotionType.valueOf("AWKWARD")); // io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this); } } From e9392860a4beae947a69a3729692f50e88838f07 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Sat, 28 Feb 2026 21:09:32 +0100 Subject: [PATCH 5/8] skip rewriting for future versions --- .../src/main/java/org/bukkit/potion/PotionType.java | 7 ------- .../classloader/bytecode/ClassToInterfaceRules.java | 9 ++++++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/potion/PotionType.java b/paper-api/src/main/java/org/bukkit/potion/PotionType.java index d840f5d5efc5..4fc0b0d7b952 100644 --- a/paper-api/src/main/java/org/bukkit/potion/PotionType.java +++ b/paper-api/src/main/java/org/bukkit/potion/PotionType.java @@ -1,18 +1,11 @@ package org.bukkit.potion; -import com.google.common.base.Preconditions; -import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.world.flag.FeatureDependant; import java.util.List; -import java.util.Locale; import net.kyori.adventure.key.Key; import net.kyori.adventure.key.KeyPattern; -import org.bukkit.Bukkit; import org.bukkit.Keyed; -import org.bukkit.NamespacedKey; import org.bukkit.Registry; -import org.bukkit.util.OldEnum; -import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java index 50ccb4dd808c..21e4df0189ad 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java @@ -18,8 +18,11 @@ public final class ClassToInterfaceRules { private static final RewriteRuleVisitorFactory VISITOR_FACTORY = RewriteRuleVisitorFactory.create( Opcodes.ASM9, chain -> { - Map descs = classes().entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().describeConstable().orElseThrow(), entry -> entry.getValue().describeConstable().orElseThrow())); - chain.then(new EnumToInterfaceRule(descs)); + Map enums = enums().entrySet().stream().collect(Collectors.toMap( + entry -> entry.getKey().describeConstable().orElseThrow(), + entry -> entry.getValue().describeConstable().orElseThrow() + )); + chain.then(new EnumToInterfaceRule(enums)); }, ClassInfoProvider.basic() ); @@ -38,7 +41,7 @@ public static byte[] processClass(final byte[] bytes) { return classWriter.toByteArray(); } - private static Map, Class> classes() { + private static Map, Class> enums() { return Map.of( PotionType.class, CraftPotionType.class ); From 39c8197295a5b76f83db4230db6efe3267d2443e Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 28 Feb 2026 12:28:17 -0800 Subject: [PATCH 6/8] only need to compute frames --- .../entrypoint/classloader/bytecode/ClassToInterfaceRules.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java index 21e4df0189ad..8c47c85522e7 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/ClassToInterfaceRules.java @@ -36,7 +36,7 @@ public static ClassVisitor visitor(final ClassVisitor parent) { public static byte[] processClass(final byte[] bytes) { final ClassReader classReader = new ClassReader(bytes); - final ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + final ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES); classReader.accept(visitor(classWriter), 0); return classWriter.toByteArray(); } From 64824452af619203ea9225adbc724b11eada7a24 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Thu, 5 Mar 2026 13:12:32 +0100 Subject: [PATCH 7/8] port on top of bytecode framework --- .../PaperClassloaderBytecodeModifier.java | 2 ++ .../VersionedClassloaderBytecodeModifier.java | 1 - .../bytecode/version/V1_21_11.java | 31 +++++++++++++++++++ .../paper/util/LegacyEnumHolderable.java | 10 +++--- .../craftbukkit/util/CraftMagicNumbers.java | 2 +- 5 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/version/V1_21_11.java diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java index 11e8452ce535..d56004b9beec 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java @@ -3,6 +3,7 @@ import com.google.common.collect.Iterators; import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.plugin.configuration.PluginMeta; +import io.papermc.paper.plugin.entrypoint.classloader.bytecode.version.V1_21_11; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -14,6 +15,7 @@ public class PaperClassloaderBytecodeModifier implements ClassloaderBytecodeModifier { private static final Map> MODIFIERS = Util.make(new LinkedHashMap<>(), map -> { + map.put(V1_21_11.VERSION, List.of(V1_21_11::new)); }); private final Map> constructedModifiers = MODIFIERS.entrySet().stream() diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/VersionedClassloaderBytecodeModifier.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/VersionedClassloaderBytecodeModifier.java index acdd6e99b125..c2fe7d7cf9c2 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/VersionedClassloaderBytecodeModifier.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/VersionedClassloaderBytecodeModifier.java @@ -4,7 +4,6 @@ import io.papermc.asm.ClassInfoProvider; import io.papermc.asm.rules.builder.RuleFactoryConfiguration; import io.papermc.paper.plugin.configuration.PluginMeta; -import io.papermc.paper.plugin.entrypoint.classloader.ClassloaderBytecodeModifier; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/version/V1_21_11.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/version/V1_21_11.java new file mode 100644 index 000000000000..28de3769b505 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/version/V1_21_11.java @@ -0,0 +1,31 @@ +package io.papermc.paper.plugin.entrypoint.classloader.bytecode.version; + +import io.papermc.asm.rules.RewriteRule; +import io.papermc.asm.rules.classes.EnumToInterfaceRule; +import io.papermc.paper.plugin.ApiVersion; +import io.papermc.paper.plugin.entrypoint.classloader.bytecode.VersionedClassloaderBytecodeModifier; +import java.util.Map; +import java.util.stream.Collectors; +import org.bukkit.craftbukkit.potion.CraftPotionType; +import org.bukkit.potion.PotionType; + +public class V1_21_11 extends VersionedClassloaderBytecodeModifier { + + public static final ApiVersion VERSION = ApiVersion.getOrCreateVersion("1.21.11"); + + public V1_21_11(final int api) { + super(api); + } + + private static final Map, Class> REGISTRY_TYPES_TO_INTERFACES = Map.of( + PotionType.class, CraftPotionType.class + ); + + @Override + protected RewriteRule createRule() { + return new EnumToInterfaceRule(REGISTRY_TYPES_TO_INTERFACES.entrySet().stream().collect(Collectors.toMap( + entry -> entry.getKey().describeConstable().orElseThrow(), + entry -> entry.getValue().describeConstable().orElseThrow() + ))); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java b/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java index cf4b5845ab1c..a3c99c86e1a2 100644 --- a/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java +++ b/paper-server/src/main/java/io/papermc/paper/util/LegacyEnumHolderable.java @@ -4,6 +4,7 @@ import io.papermc.asm.rules.classes.LegacyEnum; import io.papermc.paper.registry.HolderableBase; import java.util.Locale; +import java.util.regex.Pattern; import net.minecraft.core.Holder; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; @@ -25,7 +26,7 @@ protected LegacyEnumHolderable(final Holder holder, final int ordinal) { // Custom registry items will return the key with namespace. For a plugin this should look like a new registry item // (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly). if (NamespacedKey.MINECRAFT.equals(reference.key().identifier().getNamespace())) { - this.name = reference.key().identifier().getPath().toUpperCase(Locale.ROOT); + this.name = formatKeyAsField(reference.key().identifier().getPath()); } else { this.name = reference.key().identifier().toString(); } @@ -59,8 +60,9 @@ private void checkIsReference() { Preconditions.checkState(this.holder.kind() == Holder.Kind.REFERENCE, "Cannot call method for this registry item, because it is not registered."); } - @Override - public String toString() { - return this.implToString(); + private static final Pattern ILLEGAL_FIELD_CHARACTERS = Pattern.compile("[.-/]"); + + public static String formatKeyAsField(String path) { + return ILLEGAL_FIELD_CHARACTERS.matcher(path.toUpperCase(Locale.ENGLISH)).replaceAll("_"); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java index 51128928a845..0e1771146655 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java @@ -16,7 +16,7 @@ import io.papermc.paper.adventure.AdventureCodecs; import io.papermc.paper.entity.EntitySerializationFlag; import io.papermc.paper.plugin.ApiVersion; -import io.papermc.paper.plugin.entrypoint.classloader.ClassloaderBytecodeModifier; +import io.papermc.paper.plugin.entrypoint.classloader.bytecode.ClassloaderBytecodeModifier; import io.papermc.paper.registry.RegistryKey; import java.io.File; import java.io.IOException; From 90174546d4a8792297c9f5e1791c994759e7890a Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Thu, 5 Mar 2026 13:14:16 +0100 Subject: [PATCH 8/8] register api version serializer --- .../paper/plugin/provider/configuration/PaperPluginMeta.java | 1 + 1 file changed, 1 insertion(+) diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/provider/configuration/PaperPluginMeta.java b/paper-server/src/main/java/io/papermc/paper/plugin/provider/configuration/PaperPluginMeta.java index b6209dc6c4a3..43e90ef8424f 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/provider/configuration/PaperPluginMeta.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/provider/configuration/PaperPluginMeta.java @@ -79,6 +79,7 @@ public static PaperPluginMeta create(BufferedReader reader) throws ConfigurateEx .register(new EnumValueSerializer()) .register(PermissionConfiguration.class, PermissionConfigurationSerializer.SERIALIZER) .register(new ComponentSerializer()) + .register(ApiVersion.SERIALIZER) .registerAnnotatedObjects( ObjectMapper.factoryBuilder() .addConstraint(Constraint.class, new Constraint.Factory())