From 00b711dc5bbfbd47770768ef2e54485f529e32fc Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 28 Feb 2026 13:53:35 -0800 Subject: [PATCH] Bytecode Modification Framework --- paper-server/build.gradle.kts | 3 +- .../io/papermc/paper/plugin/ApiVersion.java | 181 +++++++++ .../PaperClassloaderBytecodeModifier.java | 12 - .../PaperClassloaderBytecodeModifier.java | 60 +++ .../VersionedClassloaderBytecodeModifier.java | 32 ++ .../classloader/bytecode/package-info.java | 4 + .../configuration/PaperPluginMeta.java | 28 +- .../registry/entry/RegistryEntryBuilder.java | 2 +- .../registry/entry/RegistryEntryMeta.java | 2 +- .../org/bukkit/craftbukkit/CraftRegistry.java | 3 +- .../org/bukkit/craftbukkit/CraftServer.java | 2 +- .../craftbukkit/attribute/CraftAttribute.java | 2 +- .../enchantments/CraftEnchantment.java | 2 +- .../craftbukkit/entity/CraftEntityType.java | 2 +- .../craftbukkit/inventory/CraftItemFlag.java | 2 +- .../craftbukkit/legacy/FieldRename.java | 2 +- .../craftbukkit/legacy/MaterialRerouting.java | 2 +- .../craftbukkit/legacy/enums/DummyEnum.java | 7 - .../craftbukkit/legacy/enums/EnumEvil.java | 288 --------------- .../legacy/enums/ImposterEnumMap.java | 137 ------- .../legacy/enums/ImposterEnumSet.java | 346 ------------------ .../legacy/fieldrename/FieldRenameData.java | 2 +- .../reroute/RequirePluginVersionData.java | 3 +- .../craftbukkit/legacy/reroute/Reroute.java | 2 +- .../legacy/reroute/RerouteBuilder.java | 2 +- .../craftbukkit/potion/CraftPotionType.java | 2 +- .../bukkit/craftbukkit/util/ApiVersion.java | 130 ------- .../bukkit/craftbukkit/util/Commodore.java | 12 +- .../craftbukkit/util/CraftMagicNumbers.java | 3 + ...nt.classloader.ClassloaderBytecodeModifier | 2 +- .../legacy/MaterialReroutingTest.java | 2 +- .../reroute/InjectPluginVersionTest.java | 2 +- .../reroute/RequirePluginVersionDataTest.java | 3 +- .../reroute/RequirePluginVersionTest.java | 2 +- .../craftbukkit/util/ApiVersionTest.java | 16 +- 35 files changed, 319 insertions(+), 983 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/ApiVersion.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java create mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java create mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/VersionedClassloaderBytecodeModifier.java create mode 100644 paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/package-info.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/DummyEnum.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/EnumEvil.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumMap.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumSet.java delete mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/util/ApiVersion.java diff --git a/paper-server/build.gradle.kts b/paper-server/build.gradle.kts index 4b842350add1..42c6bfcb70fa 100644 --- a/paper-server/build.gradle.kts +++ b/paper-server/build.gradle.kts @@ -176,10 +176,11 @@ dependencies { implementation("net.neoforged:AutoRenamingTool:2.0.3") // Remap plugins // Remap reflection - val reflectionRewriterVersion = "0.0.3" + val reflectionRewriterVersion = "0.0.4-SNAPSHOT" implementation("io.papermc:reflection-rewriter:$reflectionRewriterVersion") implementation("io.papermc:reflection-rewriter-runtime:$reflectionRewriterVersion") implementation("io.papermc:reflection-rewriter-proxy-generator:$reflectionRewriterVersion") + implementation("io.papermc:asm-utils:$reflectionRewriterVersion") // Spark implementation("me.lucko:spark-api:0.1-20240720.200737-2") diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/ApiVersion.java b/paper-server/src/main/java/io/papermc/paper/plugin/ApiVersion.java new file mode 100644 index 000000000000..3b0492816968 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/plugin/ApiVersion.java @@ -0,0 +1,181 @@ +package io.papermc.paper.plugin; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedType; +import java.util.Comparator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; +import org.bukkit.craftbukkit.util.Versioning; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import org.spongepowered.configurate.serialize.ScalarSerializer; +import org.spongepowered.configurate.serialize.SerializationException; + +@NullMarked +public sealed interface ApiVersion extends io.papermc.asm.versioned.ApiVersion permits ApiVersion.Legacy, ApiVersion.Modern, ApiVersion.None { + + Serializer SERIALIZER = new Serializer(); + + ApiVersion CURRENT = getOrCreateVersion(Versioning.getCurrentApiVersion()); + ApiVersion FLATTENING = getOrCreateVersion("1.13"); + ApiVersion FIELD_NAME_PARITY = getOrCreateVersion("1.20.5"); + ApiVersion ABSTRACT_COW = getOrCreateVersion("1.21.5"); + ApiVersion NONE = getOrCreateVersion("none"); + + String getVersionString(); + + @Override + default int compareTo(final ApiVersion o) { + return switch (o) { + case final Legacy oLegacy -> switch (this) { + case final Legacy thisLegacy -> thisLegacy.compareSameType(oLegacy); + case final Modern ignored -> 1; + case final None ignored -> -1; + }; + case final Modern oModern -> switch (this) { + case final Legacy ignored -> -1; + case final Modern thisModern -> thisModern.compareSameType(oModern); + case final None ignored -> -1; + }; + case final None ignored -> switch (this) { + case final Legacy ignored2 -> 1; + case final Modern ignored2 -> 1; + case final None ignored2 -> 0; + }; + }; + } + + record Legacy(int major, int minor, int patch) implements ApiVersion { + + private static final Comparator COMPARATOR = Comparator + .comparingInt(Legacy::major) + .thenComparingInt(Legacy::minor) + .thenComparingInt(Legacy::patch); + + int compareSameType(final Legacy other) { + return COMPARATOR.compare(this, other); + } + + @Override + public String getVersionString() { + return this.major() + "." + this.minor() + '.' + this.patch(); + } + + @Override + public String toString() { + return this.getVersionString(); + } + } + + record Modern(int year, int major, int minor) implements ApiVersion { + + private static final Comparator COMPARATOR = Comparator + .comparingInt(Modern::year) + .thenComparingInt(Modern::major) + .thenComparingInt(Modern::minor); + + int compareSameType(final Modern other) { + return COMPARATOR.compare(this, other); + } + + @Override + public String getVersionString() { + return this.year() + "." + this.major() + '.' + this.minor(); + } + + @Override + public String toString() { + return this.getVersionString(); + } + } + + record None() implements ApiVersion { + + private static final None INSTANCE = new None(); + + @Override + public String getVersionString() { + return "none"; + } + + @Override + public String toString() { + return this.getVersionString(); + } + } + + final class Serializer extends ScalarSerializer.Annotated { + + Serializer() { + super(ApiVersion.class); + } + + @Override + public ApiVersion deserialize(final AnnotatedType type, final Object obj) throws SerializationException { + try { + final ApiVersion version = getOrCreateVersion(obj.toString()); + final Minimum min = type.getAnnotation(Minimum.class); + if (min != null) { + final ApiVersion minVersion = getOrCreateVersion(min.value()); + if (version.isOlderThan(minVersion)) { + throw new SerializationException(ApiVersion.class, version + " is too old for a paper plugin!"); + } + } + return version; + } catch (final IllegalArgumentException ex) { + throw new SerializationException(ApiVersion.class, "Could not parse version string", ex); + } + } + + @Override + protected Object serialize(final AnnotatedType type, final ApiVersion item, final Predicate> typeSupported) { + return item.getVersionString(); + } + } + + static ApiVersion getOrCreateVersion(final @Nullable String versionString) { + class Holder { + private static final Map cache = new ConcurrentHashMap<>(); + } + if (versionString == null || versionString.isBlank() || versionString.equalsIgnoreCase("none")) { + return None.INSTANCE; + } + final ApiVersion parsed = parse(versionString); + Holder.cache.putIfAbsent(parsed.getVersionString(), parsed); + return Holder.cache.get(parsed.getVersionString()); + } + + private static ApiVersion parse(final String versionString) { + final String[] parts = versionString.split("\\."); + + if (parts.length < 2 || parts.length > 3) { + throw new IllegalArgumentException("Version string must have 2 or 3 numbers"); + } + + final int first = Integer.parseInt(parts[0]); + final int second = Integer.parseInt(parts[1]); + final int third = parts.length == 3 ? Integer.parseInt(parts[2]) : 0; + + if (first == 1) { + if (second > 21) { + throw new IllegalArgumentException("Legacy version string must be 1.21.xx or lower"); + } + return new Legacy(first, second, third); + } else { + if (first < 26) { + throw new IllegalArgumentException("Modern version string must be 26.xx.xx or higher"); + } + return new Modern(first, second, third); + } + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + @interface Minimum { + String value(); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java deleted file mode 100644 index 0e734c07dbe8..000000000000 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperClassloaderBytecodeModifier.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.papermc.paper.plugin.entrypoint.classloader; - -import io.papermc.paper.plugin.configuration.PluginMeta; - -// Stub, implement in future. -public class PaperClassloaderBytecodeModifier implements ClassloaderBytecodeModifier { - - @Override - public byte[] modify(PluginMeta configuration, byte[] bytecode) { - return io.papermc.paper.pluginremap.reflect.ReflectionRemapper.processClass(bytecode); - } -} 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 new file mode 100644 index 000000000000..ac6ad60900b1 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/PaperClassloaderBytecodeModifier.java @@ -0,0 +1,60 @@ +package io.papermc.paper.plugin.entrypoint.classloader.bytecode; + +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; +import java.util.Map; +import java.util.stream.Collectors; +import net.minecraft.util.Util; +import org.objectweb.asm.Opcodes; + +public class PaperClassloaderBytecodeModifier implements ClassloaderBytecodeModifier { + + private static final Map> MODIFIERS = Util.make(new LinkedHashMap<>(), map -> { + }); + + private final Map> constructedModifiers = MODIFIERS.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> { + return entry.getValue().stream().map(factory -> factory.create(Opcodes.ASM9)).toList(); + })); + + @Override + public byte[] modify(final PluginMeta configuration, byte[] bytecode) { + int start = -1; + if (configuration.getAPIVersion() != null) { + int i = 0; + for (final Map.Entry> entry : this.constructedModifiers.entrySet()) { + final ApiVersion apiVersion = ApiVersion.getOrCreateVersion(configuration.getAPIVersion()); + final ApiVersion modifierApiVersion = entry.getKey(); + if (apiVersion.isOlderThanOrSameAs(modifierApiVersion)) { + start = i; + break; + } + i++; + } + } else { + start = 0; + } + if (start == -1) { + return bytecode; // no modification needed. The plugin version is newer than all versioned modifiers + } + + final Iterator>> iter = this.constructedModifiers.entrySet().iterator(); + Iterators.advance(iter, start); + while (iter.hasNext()) { + for (final VersionedClassloaderBytecodeModifier modifier : iter.next().getValue()) { + bytecode = modifier.modify(configuration, bytecode); + } + } + return bytecode; + } + + private interface ModifierFactory { + + VersionedClassloaderBytecodeModifier create(int api); + } +} 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 new file mode 100644 index 000000000000..acdd6e99b125 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/VersionedClassloaderBytecodeModifier.java @@ -0,0 +1,32 @@ +package io.papermc.paper.plugin.entrypoint.classloader.bytecode; + +import io.papermc.asm.AbstractRewriteRuleVisitorFactory; +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; + +import static io.papermc.asm.util.DescriptorUtils.desc; + +public abstract class VersionedClassloaderBytecodeModifier extends AbstractRewriteRuleVisitorFactory implements ClassloaderBytecodeModifier, RuleFactoryConfiguration.Holder { + + protected VersionedClassloaderBytecodeModifier(final int api) { + super(api, ClassInfoProvider.basic()); + } + + @Override + public final byte[] modify(final PluginMeta config, final byte[] bytecode) { + final ClassReader cr = new ClassReader(bytecode); + final ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); // need to compute frames because of instruction removal in ctor rewriting + + cr.accept(this.createVisitor(cw), 0); + return cw.toByteArray(); + } + + @Override + public final RuleFactoryConfiguration configuration() { + return RuleFactoryConfiguration.create(desc(this.getClass())); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/package-info.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/package-info.java new file mode 100644 index 000000000000..57ecac8a2bd7 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/bytecode/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.plugin.entrypoint.classloader.bytecode; + +import org.jspecify.annotations.NullMarked; 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 d3b3a8baca01..b6209dc6c4a3 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 @@ -5,15 +5,13 @@ import io.papermc.paper.configuration.constraint.Constraint; import io.papermc.paper.configuration.serializer.ComponentSerializer; import io.papermc.paper.configuration.serializer.EnumValueSerializer; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.plugin.configuration.PluginMeta; import io.papermc.paper.plugin.provider.configuration.serializer.PermissionConfigurationSerializer; import io.papermc.paper.plugin.provider.configuration.serializer.constraints.PluginConfigConstraints; import io.papermc.paper.plugin.provider.configuration.type.DependencyConfiguration; import io.papermc.paper.plugin.provider.configuration.type.PermissionConfiguration; import io.papermc.paper.plugin.provider.configuration.type.PluginDependencyLifeCycle; -import java.lang.reflect.Type; -import java.util.function.Predicate; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginLoadOrder; @@ -26,8 +24,6 @@ import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.ObjectMapper; import org.spongepowered.configurate.objectmapping.meta.Required; -import org.spongepowered.configurate.serialize.ScalarSerializer; -import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.yaml.NodeStyle; import org.spongepowered.configurate.yaml.YamlConfigurationLoader; @@ -63,6 +59,7 @@ public class PaperPluginMeta implements PluginMeta { @FlattenedResolver private PermissionConfiguration permissionConfiguration = new PermissionConfiguration(PermissionDefault.OP, List.of()); @Required + @ApiVersion.Minimum("1.19") private ApiVersion apiVersion; private Map> dependencies = new EnumMap<>(PluginDependencyLifeCycle.class); @@ -70,7 +67,6 @@ public class PaperPluginMeta implements PluginMeta { public PaperPluginMeta() { } - static final ApiVersion MINIMUM = ApiVersion.getOrCreateVersion("1.19"); public static PaperPluginMeta create(BufferedReader reader) throws ConfigurateException { YamlConfigurationLoader loader = YamlConfigurationLoader.builder() .indent(2) @@ -78,28 +74,8 @@ public static PaperPluginMeta create(BufferedReader reader) throws ConfigurateEx .headerMode(HeaderMode.NONE) .source(() -> reader) .defaultOptions((options) -> { - return options.serializers((serializers) -> { serializers - .register(new ScalarSerializer<>(ApiVersion.class) { - @Override - public ApiVersion deserialize(final Type type, final Object obj) throws SerializationException { - try { - final ApiVersion version = ApiVersion.getOrCreateVersion(obj.toString()); - if (version.isOlderThan(MINIMUM)) { - throw new SerializationException(version + " is too old for a paper plugin!"); - } - return version; - } catch (final IllegalArgumentException e) { - throw new SerializationException(e); - } - } - - @Override - protected Object serialize(final ApiVersion item, final Predicate> typeSupported) { - return item.getVersionString(); - } - }) .register(new EnumValueSerializer()) .register(PermissionConfiguration.class, PermissionConfigurationSerializer.SERIALIZER) .register(new ComponentSerializer()) diff --git a/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java b/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java index 51c91cf018ec..0cc921002fb9 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryBuilder.java @@ -1,5 +1,6 @@ package io.papermc.paper.registry.entry; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.PaperRegistryBuilder; import io.papermc.paper.registry.RegistryKey; import java.util.function.BiFunction; @@ -10,7 +11,6 @@ import net.minecraft.resources.ResourceKey; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.util.ApiVersion; import static io.papermc.paper.registry.entry.RegistryEntryMeta.RegistryModificationApiSupport.ADDABLE; import static io.papermc.paper.registry.entry.RegistryEntryMeta.RegistryModificationApiSupport.MODIFIABLE; diff --git a/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryMeta.java b/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryMeta.java index f606c523f680..1207a5cf4125 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryMeta.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/entry/RegistryEntryMeta.java @@ -1,6 +1,7 @@ package io.papermc.paper.registry.entry; import com.google.common.base.Preconditions; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.PaperRegistryBuilder; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.TypedKey; @@ -16,7 +17,6 @@ import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.CraftRegistry; -import org.bukkit.craftbukkit.util.ApiVersion; public sealed interface RegistryEntryMeta permits RegistryEntryMeta.ApiOnly, RegistryEntryMeta.ServerSide { // TODO remove Keyed diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java index 0d343556fbb6..b278a390b6ca 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit; import com.google.common.base.Preconditions; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; @@ -8,7 +9,6 @@ import io.papermc.paper.registry.set.NamedRegistryKeySetImpl; import io.papermc.paper.registry.tag.Tag; import io.papermc.paper.util.Holderable; -import io.papermc.paper.util.MCUtil; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -24,7 +24,6 @@ import org.bukkit.Particle; import org.bukkit.Registry; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.entity.EntityType; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index da49c8005592..cb9692670737 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -15,6 +15,7 @@ import io.papermc.paper.configuration.GlobalConfiguration; import io.papermc.paper.configuration.PaperServerConfiguration; import io.papermc.paper.configuration.ServerConfiguration; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.world.PaperWorldLoader; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.awt.image.BufferedImage; @@ -196,7 +197,6 @@ import org.bukkit.craftbukkit.tag.CraftFluidTag; import org.bukkit.craftbukkit.tag.CraftGameEventTag; import org.bukkit.craftbukkit.tag.CraftItemTag; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftIconCache; import org.bukkit.craftbukkit.util.CraftLocation; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java b/paper-server/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java index c1987c186928..07cb51fedd1f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.attribute; 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 java.util.Locale; @@ -10,7 +11,6 @@ import org.bukkit.attribute.Attribute; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.ApiVersion; public class CraftAttribute extends OldEnumHolderable implements Attribute { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java index 45b70a28e0c3..8dc7e99baedc 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.enchantments; import com.google.common.base.Preconditions; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.util.Holderable; import java.util.Locale; @@ -12,7 +13,6 @@ import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.enchantments.EnchantmentWrapper; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java index d842c2c21570..026abc1b10c5 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.entity; import com.google.common.base.Preconditions; +import io.papermc.paper.plugin.ApiVersion; import io.papermc.paper.registry.RegistryKey; import java.util.Locale; import net.minecraft.core.Holder; @@ -9,7 +10,6 @@ import org.bukkit.Registry; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.EntityType; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFlag.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFlag.java index 902fb5f222ed..3238b6fc4f16 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFlag.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFlag.java @@ -1,8 +1,8 @@ package org.bukkit.craftbukkit.inventory; import com.google.common.base.Preconditions; +import io.papermc.paper.plugin.ApiVersion; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.inventory.ItemFlag; public class CraftItemFlag { 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 42dfc8f15ae1..23354fc0d5ca 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 @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.legacy; +import io.papermc.paper.plugin.ApiVersion; import java.util.function.BiFunction; import org.bukkit.NamespacedKey; import org.bukkit.Particle; @@ -12,7 +13,6 @@ 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.util.ApiVersion; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemFlag; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java index 9bc8055c3632..51e07815884f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.legacy; +import io.papermc.paper.plugin.ApiVersion; import java.util.Collection; import java.util.EnumMap; import java.util.HashMap; @@ -30,7 +31,6 @@ import org.bukkit.craftbukkit.legacy.reroute.RerouteStatic; import org.bukkit.craftbukkit.tag.CraftBlockTag; import org.bukkit.craftbukkit.tag.CraftItemTag; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.Animals; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/DummyEnum.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/DummyEnum.java deleted file mode 100644 index dd50792cd7b7..000000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/DummyEnum.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bukkit.craftbukkit.legacy.enums; - -/** - * A crash dummy to use, instead of the old enums which matured to Abstracthood or Interfacehood and the baby enums which are still growing. - */ -public enum DummyEnum { -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/EnumEvil.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/EnumEvil.java deleted file mode 100644 index 1376703cde16..000000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/EnumEvil.java +++ /dev/null @@ -1,288 +0,0 @@ -package org.bukkit.craftbukkit.legacy.enums; - -import com.google.common.base.Converter; -import com.google.common.base.Enums; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import java.io.Serializable; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collector; -import java.util.stream.Collectors; -import org.bukkit.Art; -import org.bukkit.Fluid; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; -import org.bukkit.Sound; -import org.bukkit.attribute.Attribute; -import org.bukkit.block.Biome; -import org.bukkit.block.banner.PatternType; -import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.legacy.reroute.DoNotReroute; -import org.bukkit.craftbukkit.legacy.reroute.InjectPluginVersion; -import org.bukkit.craftbukkit.legacy.reroute.NotInBukkit; -import org.bukkit.craftbukkit.legacy.reroute.RequireCompatibility; -import org.bukkit.craftbukkit.legacy.reroute.RequirePluginVersion; -import org.bukkit.craftbukkit.legacy.reroute.RerouteArgumentType; -import org.bukkit.craftbukkit.legacy.reroute.RerouteReturnType; -import org.bukkit.craftbukkit.legacy.reroute.RerouteStatic; -import org.bukkit.craftbukkit.util.ApiVersion; -import org.bukkit.craftbukkit.util.ClassTraverser; -import org.bukkit.entity.Cat; -import org.bukkit.entity.Frog; -import org.bukkit.entity.Villager; -import org.bukkit.map.MapCursor; -import org.bukkit.util.OldEnum; - -@Deprecated -@NotInBukkit -@RequireCompatibility("enum-compatibility-mode") -@RequirePluginVersion(maxInclusive = "1.20.6") -public class EnumEvil { - - private static final Map, LegacyRegistryData> REGISTRIES = new HashMap<>(); - - static { - // Add Classes which got changed here - REGISTRIES.put(Art.class, new LegacyRegistryData(Registry.ART, Art::valueOf)); - REGISTRIES.put(Attribute.class, new LegacyRegistryData(Registry.ATTRIBUTE, Attribute::valueOf)); - REGISTRIES.put(Biome.class, new LegacyRegistryData(Registry.BIOME, Biome::valueOf)); - REGISTRIES.put(Fluid.class, new LegacyRegistryData(Registry.FLUID, Fluid::valueOf)); - REGISTRIES.put(Villager.Type.class, new LegacyRegistryData(Registry.VILLAGER_TYPE, Villager.Type::valueOf)); - REGISTRIES.put(Villager.Profession.class, new LegacyRegistryData(Registry.VILLAGER_PROFESSION, Villager.Profession::valueOf)); - REGISTRIES.put(Sound.class, new LegacyRegistryData(Registry.SOUNDS, Sound::valueOf)); - REGISTRIES.put(Frog.Variant.class, new LegacyRegistryData(Registry.FROG_VARIANT, Frog.Variant::valueOf)); - REGISTRIES.put(Cat.Type.class, new LegacyRegistryData(Registry.CAT_VARIANT, Cat.Type::valueOf)); - REGISTRIES.put(MapCursor.Type.class, new LegacyRegistryData(Registry.MAP_DECORATION_TYPE, MapCursor.Type::valueOf)); - REGISTRIES.put(PatternType.class, new LegacyRegistryData(Registry.BANNER_PATTERN, PatternType::valueOf)); - } - - public static LegacyRegistryData getRegistryData(Class clazz) { - ClassTraverser it = new ClassTraverser(clazz); - LegacyRegistryData registryData; - while (it.hasNext()) { - registryData = EnumEvil.REGISTRIES.get(it.next()); - if (registryData != null) { - return registryData; - } - } - - return null; - } - - @DoNotReroute - public static Registry getRegistry(Class clazz) { - LegacyRegistryData registryData = EnumEvil.getRegistryData(clazz); - - if (registryData != null) { - return registryData.registry(); - } - - return null; - } - - @RerouteStatic("com/google/common/collect/Maps") - @RerouteReturnType("java/util/EnumSet") - public static ImposterEnumMap newEnumMap(Class objectClass) { - return new ImposterEnumMap(objectClass); - } - - @RerouteStatic("com/google/common/collect/Maps") - @RerouteReturnType("java/util/EnumSet") - public static ImposterEnumMap newEnumMap(Map map) { - return new ImposterEnumMap(map); - } - - @RerouteStatic("com/google/common/collect/Sets") - public static Collector toImmutableEnumSet() { - return Collectors.toUnmodifiableSet(); - } - - @RerouteStatic("com/google/common/collect/Sets") - @RerouteReturnType("java/util/EnumSet") - public static ImposterEnumSet newEnumSet(Iterable iterable, Class clazz) { - ImposterEnumSet set = ImposterEnumSet.noneOf(clazz); - - for (Object some : iterable) { - set.add(some); - } - - return set; - } - - @RerouteStatic("com/google/common/collect/Sets") - public static ImmutableSet immutableEnumSet(Iterable iterable) { - return ImmutableSet.of(iterable); - } - - @RerouteStatic("com/google/common/collect/Sets") - public static ImmutableSet immutableEnumSet(@RerouteArgumentType("java/lang/Enum") Object first, @RerouteArgumentType("[java/lang/Enum") Object... rest) { - return ImmutableSet.of(first, rest); - } - - @RerouteStatic("com/google/common/base/Enums") - public static Field getField(@RerouteArgumentType("java/lang/Enum") Object value) { - if (value instanceof Enum eValue) { - return Enums.getField(eValue); - } - - try { - return value.getClass().getField(((OldEnum) value).name()); - } catch (NoSuchFieldException impossible) { - throw new AssertionError(impossible); - } - } - - @RerouteStatic("com/google/common/base/Enums") - public static com.google.common.base.Optional getIfPresent(Class clazz, String name, @InjectPluginVersion ApiVersion apiVersion) { - if (clazz.isEnum()) { - return Enums.getIfPresent(clazz, name); - } - - Registry registry = EnumEvil.getRegistry(clazz); - if (registry == null) { - return com.google.common.base.Optional.absent(); - } - - name = FieldRename.rename(apiVersion, clazz.getName().replace('.', '/'), name); - return com.google.common.base.Optional.fromNullable(registry.get(NamespacedKey.fromString(name.toLowerCase(Locale.ROOT)))); - } - - @RerouteStatic("com/google/common/base/Enums") - public static Converter stringConverter(Class clazz, @InjectPluginVersion ApiVersion apiVersion) { - if (clazz.isEnum()) { - return Enums.stringConverter(clazz); - } - - return new StringConverter(apiVersion, clazz); - } - - public static Object[] getEnumConstants(Class clazz) { - if (clazz.isEnum()) { - return clazz.getEnumConstants(); - } - - Registry registry = EnumEvil.getRegistry(clazz); - - if (registry == null) { - return clazz.getEnumConstants(); - } - - // Need to do this in such away to avoid ClassCastException - List values = Lists.newArrayList(registry); - Object array = Array.newInstance(clazz, values.size()); - - for (int i = 0; i < values.size(); i++) { - Array.set(array, i, values.get(i)); - } - - return (Object[]) array; - } - - public static String name(@RerouteArgumentType("java/lang/Enum") Object object) { - if (object instanceof OldEnum) { - return ((OldEnum) object).name(); - } - - return ((Enum) object).name(); - } - - public static int compareTo(@RerouteArgumentType("java/lang/Enum") Object object, @RerouteArgumentType("java/lang/Enum") Object other) { - if (object instanceof OldEnum) { - return ((OldEnum) object).compareTo((OldEnum) other); - } - - return ((Enum) object).compareTo((Enum) other); - } - - public static Class getDeclaringClass(@RerouteArgumentType("java/lang/Enum") Object object) { - Class clazz = object.getClass(); - Class zuper = clazz.getSuperclass(); - return (zuper == Enum.class) ? clazz : zuper; - } - - public static Optional describeConstable(@RerouteArgumentType("java/lang/Enum") Object object) { - return EnumEvil.getDeclaringClass(object) - .describeConstable() - .map(c -> Enum.EnumDesc.of(c, EnumEvil.name(object))); - } - - @RerouteStatic("java/lang/Enum") - @RerouteReturnType("java/lang/Enum") - public static Object valueOf(Class enumClass, String name, @InjectPluginVersion ApiVersion apiVersion) { - name = FieldRename.rename(apiVersion, enumClass.getName().replace('.', '/'), name); - LegacyRegistryData registryData = EnumEvil.getRegistryData(enumClass); - if (registryData != null) { - return registryData.function().apply(name); - } - - return Enum.valueOf(enumClass, name); - } - - public static String toString(@RerouteArgumentType("java/lang/Enum") Object object) { - return object.toString(); - } - - public static int ordinal(@RerouteArgumentType("java/lang/Enum") Object object) { - if (object instanceof OldEnum) { - return ((OldEnum) object).ordinal(); - } - - return ((Enum) object).ordinal(); - } - - public record LegacyRegistryData(Registry registry, Function function) { - } - - private static final class StringConverter> extends Converter implements Serializable { - - private final ApiVersion apiVersion; - private final Class clazz; - private transient LegacyRegistryData registryData; - - StringConverter(ApiVersion apiVersion, Class clazz) { - this.apiVersion = apiVersion; - this.clazz = clazz; - } - - @Override - protected T doForward(String value) { - if (this.registryData == null) { - this.registryData = EnumEvil.getRegistryData(this.clazz); - } - value = FieldRename.rename(this.apiVersion, this.clazz.getName().replace('.', '/'), value); - return (T) this.registryData.function().apply(value); - } - - @Override - protected String doBackward(T enumValue) { - return enumValue.name(); - } - - @Override - public boolean equals(Object object) { - if (object instanceof StringConverter that) { - return this.clazz.equals(that.clazz); - } - return false; - } - - @Override - public int hashCode() { - return this.clazz.hashCode(); - } - - @Override - public String toString() { - return "Enums.stringConverter(" + this.clazz.getName() + ".class)"; - } - - private static final long serialVersionUID = 0L; - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumMap.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumMap.java deleted file mode 100644 index b3e2367a0c14..000000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumMap.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.bukkit.craftbukkit.legacy.enums; - -import java.util.AbstractMap; -import java.util.Collection; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -/** - * The "I can't believe it works" map. - * It replaces every EnumMap with the ImposterEnumMap and uses a HashMap instead of an object array. - * Used so that plugins which use an EnumMap still work. - */ -public class ImposterEnumMap extends AbstractMap { - - private final Class objectClass; - private final Map map; - - public ImposterEnumMap(Class objectClass) { - this.objectClass = objectClass; - this.map = ImposterEnumMap.getMap(objectClass); - } - - public ImposterEnumMap(EnumMap enumMap) { - this.objectClass = DummyEnum.class; - this.map = enumMap.clone(); - } - - public ImposterEnumMap(Map map) { - if (map instanceof ImposterEnumMap) { - this.objectClass = ((ImposterEnumMap) map).objectClass; - this.map = ImposterEnumMap.getMap(this.objectClass); - } else { - this.objectClass = DummyEnum.class; - this.map = new TreeMap(); - } - - this.map.putAll(map); - } - - private static Map getMap(Class objectClass) { - // Since we replace every enum map we might also replace some maps which are for real enums. - // If this is the case use a EnumMap instead of a HashMap - if (objectClass.isEnum()) { - return new EnumMap(objectClass); - } else { - return new HashMap(); - } - } - - @Override - public int size() { - return this.map.size(); - } - - @Override - public boolean containsValue(Object value) { - return this.map.containsValue(value); - } - - @Override - public boolean containsKey(Object key) { - return this.map.containsKey(key); - } - - @Override - public Object get(Object key) { - return this.map.get(key); - } - - @Override - public Object put(Object key, Object value) { - this.typeCheck(key); - return this.map.put(key, value); - } - - @Override - public Object remove(Object key) { - return this.map.remove(key); - } - - @Override - public void putAll(Map m) { - if (this.map instanceof EnumMap) { - this.map.putAll(m); - } - - super.putAll(m); - } - - @Override - public void clear() { - this.map.clear(); - } - - @Override - public Set keySet() { - return this.map.keySet(); - } - - @Override - public Collection values() { - return this.map.values(); - } - - @Override - public Set> entrySet() { - return this.map.entrySet(); - } - - @Override - public boolean equals(Object o) { - return this.map.equals(o); - } - - @Override - public int hashCode() { - return this.map.hashCode(); - } - - @Override - public ImposterEnumMap clone() { - ImposterEnumMap enumMap = new ImposterEnumMap(this.objectClass); - enumMap.putAll(this.map); - return enumMap; - } - - private void typeCheck(Object object) { - if (this.objectClass != DummyEnum.class) { - if (!this.objectClass.isAssignableFrom(object.getClass())) { - throw new ClassCastException(object.getClass() + " != " + this.objectClass); - } - } - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumSet.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumSet.java deleted file mode 100644 index e5afc060cca9..000000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/enums/ImposterEnumSet.java +++ /dev/null @@ -1,346 +0,0 @@ -package org.bukkit.craftbukkit.legacy.enums; - -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; -import org.bukkit.Registry; -import org.bukkit.util.OldEnum; -import org.jetbrains.annotations.NotNull; - -public class ImposterEnumSet extends AbstractSet { - - private final Class objectClass; - private final Set set; - - private static Set createSet(Class clazz) { - if (clazz.isEnum()) { - return EnumSet.noneOf((Class) clazz); - } else { - return new TreeSet(); - } - } - - public static ImposterEnumSet noneOf(Class clazz) { - Set set = ImposterEnumSet.createSet(clazz); - return new ImposterEnumSet(set, clazz); - } - - public static ImposterEnumSet allOf(Class clazz) { - Set set; - if (clazz.isEnum()) { - set = EnumSet.allOf((Class) clazz); - } else { - set = new HashSet(); - Registry registry = EnumEvil.getRegistry(clazz); - if (registry == null) { - throw new IllegalArgumentException("Class " + clazz + " is not an Enum nor an OldEnum"); - } - - for (Object object : registry) { - set.add(object); - } - } - return new ImposterEnumSet(set, clazz); - } - - public static ImposterEnumSet copyOf(Set set) { - Class clazz; - if (set instanceof ImposterEnumSet imposter) { - set = imposter.set; - clazz = imposter.objectClass; - } else { - if (!set.isEmpty()) { - clazz = (Class) set.stream() - .filter(val -> val != null) - .map(val -> val.getClass()) - .findAny() - .orElse(Object.class); - } else { - clazz = Object.class; - } - } - - Set newSet = ImposterEnumSet.createSet(clazz); - newSet.addAll(set); - - return new ImposterEnumSet(newSet, clazz); - } - - public static ImposterEnumSet copyOf(Collection collection) { - Class clazz; - if (collection instanceof ImposterEnumSet imposter) { - collection = imposter.set; - clazz = imposter.objectClass; - } else { - if (!collection.isEmpty()) { - clazz = (Class) collection.stream() - .filter(val -> val != null) - .map(val -> val.getClass()) - .findAny() - .orElse(Object.class); - } else { - clazz = Object.class; - } - } - - Set newSet = ImposterEnumSet.createSet(clazz); - newSet.addAll(collection); - - return new ImposterEnumSet(newSet, clazz); - } - - public static ImposterEnumSet complementOf(Set set) { - Class clazz = null; - if (set instanceof ImposterEnumSet imposter) { - set = imposter.set; - clazz = imposter.objectClass; - } - - if (set instanceof EnumSet enumSet) { - enumSet = EnumSet.complementOf(enumSet); - - if (clazz != null) { - return new ImposterEnumSet(enumSet, clazz); - } - - if (!set.isEmpty()) { - clazz = (Class) set.stream() - .filter(val -> val != null) - .map(val -> val.getClass()) - .findAny() - .orElse(Object.class); - } else { - clazz = (Class) enumSet.stream() - .filter(val -> val != null) - .map(val -> val.getClass()) - .map(val -> (Class) val) - .findAny() - .orElse(Object.class); - } - - return new ImposterEnumSet(enumSet, clazz); - } - - if (set.isEmpty() && clazz == null) { - throw new IllegalStateException("Class is null and set is empty, cannot get class!"); - } - - if (clazz == null) { - clazz = (Class) set.stream() - .filter(val -> val != null) - .map(val -> val.getClass()) - .findAny() - .orElse(Object.class); - } - - Registry registry = EnumEvil.getRegistry(clazz); - Set newSet = new HashSet(); - - for (Object value : registry) { - if (set.contains(value)) { - continue; - } - - newSet.add(value); - } - - return new ImposterEnumSet(newSet, clazz); - } - - public static ImposterEnumSet of(Object e) { - Set set = ImposterEnumSet.createSet(e.getClass()); - set.add(e); - - return new ImposterEnumSet(set, e.getClass()); - } - - public static ImposterEnumSet of(Object e1, Object e2) { - Set set = ImposterEnumSet.createSet(e1.getClass()); - set.add(e1); - set.add(e2); - - return new ImposterEnumSet(set, e1.getClass()); - } - - public static ImposterEnumSet of(Object e1, Object e2, Object e3) { - Set set = ImposterEnumSet.createSet(e1.getClass()); - set.add(e1); - set.add(e2); - set.add(e3); - - return new ImposterEnumSet(set, e1.getClass()); - } - - - public static ImposterEnumSet of(Object e1, Object e2, Object e3, Object e4) { - Set set = ImposterEnumSet.createSet(e1.getClass()); - set.add(e1); - set.add(e2); - set.add(e3); - set.add(e4); - - return new ImposterEnumSet(set, e1.getClass()); - } - - - public static ImposterEnumSet of(Object e1, Object e2, Object e3, Object e4, Object e5) { - Set set = ImposterEnumSet.createSet(e1.getClass()); - set.add(e1); - set.add(e2); - set.add(e3); - set.add(e4); - set.add(e5); - - return new ImposterEnumSet(set, e1.getClass()); - } - - - public static ImposterEnumSet of(Object e, Object... rest) { - Set set = ImposterEnumSet.createSet(e.getClass()); - set.add(e); - - Collections.addAll(set, rest); - - return new ImposterEnumSet(set, e.getClass()); - } - - public static ImposterEnumSet range(Object from, Object to) { - Set set; - if (from.getClass().isEnum()) { - set = EnumSet.range((Enum) from, (Enum) to); - } else { - set = new HashSet(); - Registry registry = EnumEvil.getRegistry(from.getClass()); - for (Object o : registry) { - if (((OldEnum) o).ordinal() < ((OldEnum) from).ordinal()) { - continue; - } - - if (((OldEnum) o).ordinal() > ((OldEnum) to).ordinal()) { - continue; - } - - set.add(o); - } - } - - return new ImposterEnumSet(set, from.getClass()); - } - - private ImposterEnumSet(Set set, Class objectClass) { - this.set = set; - this.objectClass = objectClass; - } - - @Override - public Iterator iterator() { - return this.set.iterator(); - } - - @Override - public int size() { - return this.set.size(); - } - - @Override - public boolean equals(Object o) { - return this.set.equals(o); - } - - @Override - public int hashCode() { - return this.set.hashCode(); - } - - @Override - public boolean removeAll(Collection c) { - return this.set.removeAll(c); - } - - @Override - public boolean isEmpty() { - return this.set.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return this.set.contains(o); - } - - @NotNull - @Override - public Object[] toArray() { - return this.set.toArray(); - } - - @NotNull - @Override - public T[] toArray(@NotNull T[] a) { - return (T[]) this.set.toArray(a); - } - - @Override - public boolean add(Object o) { - this.typeCheck(o); - return this.set.add(o); - } - - @Override - public boolean remove(Object o) { - return this.set.remove(o); - } - - @Override - public boolean containsAll(@NotNull Collection c) { - return this.set.containsAll(c); - } - - @Override - public boolean addAll(@NotNull Collection c) { - if (this.set instanceof EnumSet) { - this.set.addAll(c); - } - - return super.addAll(c); - } - - @Override - public boolean retainAll(@NotNull Collection c) { - return this.set.retainAll(c); - } - - @Override - public void clear() { - this.set.clear(); - } - - @Override - public String toString() { - return this.set.toString(); - } - - public ImposterEnumSet clone() { - Set newSet; - if (this.set instanceof EnumSet enumSet) { - newSet = enumSet.clone(); - } else { - newSet = new HashSet(); - newSet.addAll(this.set); - } - - return new ImposterEnumSet(newSet, this.objectClass); - } - - private void typeCheck(Object object) { - if (this.objectClass != DummyEnum.class) { - if (!this.objectClass.isAssignableFrom(object.getClass())) { - throw new ClassCastException(object.getClass() + " != " + this.objectClass); - } - } - } -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/fieldrename/FieldRenameData.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/fieldrename/FieldRenameData.java index 3e9b03b5ca37..e3ed2ed8cd3f 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/fieldrename/FieldRenameData.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/fieldrename/FieldRenameData.java @@ -1,12 +1,12 @@ package org.bukkit.craftbukkit.legacy.fieldrename; +import io.papermc.paper.plugin.ApiVersion; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.NavigableMap; import java.util.TreeMap; import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.util.ApiVersion; public record FieldRenameData(RenameData renameData, RenameData keyRenameData) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionData.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionData.java index bb85c0688014..1f6e45c236bb 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionData.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionData.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.legacy.reroute; -import org.bukkit.craftbukkit.util.ApiVersion; + +import io.papermc.paper.plugin.ApiVersion; public record RequirePluginVersionData(ApiVersion minInclusive, ApiVersion maxInclusive) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/Reroute.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/Reroute.java index 1b8749998e1a..691c4da044ef 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/Reroute.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/Reroute.java @@ -1,9 +1,9 @@ package org.bukkit.craftbukkit.legacy.reroute; +import io.papermc.paper.plugin.ApiVersion; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.ClassTraverser; import org.jetbrains.annotations.VisibleForTesting; import org.objectweb.asm.Type; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RerouteBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RerouteBuilder.java index ca02b6b937a4..cbf554e914cf 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RerouteBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/reroute/RerouteBuilder.java @@ -1,6 +1,7 @@ package org.bukkit.craftbukkit.legacy.reroute; import com.google.common.base.Preconditions; +import io.papermc.paper.plugin.ApiVersion; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -10,7 +11,6 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; -import org.bukkit.craftbukkit.util.ApiVersion; import org.objectweb.asm.Type; public class RerouteBuilder { 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 a304fafd78f6..4bf9b8aebc80 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 @@ -2,6 +2,7 @@ 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 java.util.List; import java.util.Locale; @@ -13,7 +14,6 @@ import org.bukkit.Registry; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/ApiVersion.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/ApiVersion.java deleted file mode 100644 index 4a1b8038a144..000000000000 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/ApiVersion.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.bukkit.craftbukkit.util; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import org.jetbrains.annotations.NotNull; - -public final class ApiVersion implements Comparable, Serializable { - - public static final ApiVersion CURRENT; - public static final ApiVersion FLATTENING; - public static final ApiVersion FIELD_NAME_PARITY; - public static final ApiVersion ABSTRACT_COW; - public static final ApiVersion NONE; - - private static final Map versions; - - static { - versions = new HashMap<>(); - CURRENT = getOrCreateVersion(Versioning.getCurrentApiVersion()); - FLATTENING = getOrCreateVersion("1.13"); - FIELD_NAME_PARITY = getOrCreateVersion("1.20.5"); - ABSTRACT_COW = getOrCreateVersion("1.21.5"); - NONE = getOrCreateVersion("none"); - } - - private final boolean none; - private final int major; - private final int minor; - private final int patch; - - private ApiVersion() { - this.none = true; - this.major = Integer.MIN_VALUE; - this.minor = Integer.MIN_VALUE; - this.patch = Integer.MIN_VALUE; - } - - private ApiVersion(int major, int minor, int patch) { - this.none = false; - this.major = major; - this.minor = minor; - this.patch = patch; - } - - public static ApiVersion getOrCreateVersion(String versionString) { - if (versionString == null || versionString.trim().isEmpty() || versionString.equalsIgnoreCase("none")) { - return ApiVersion.versions.computeIfAbsent("none", s -> new ApiVersion()); - } - - ApiVersion version = ApiVersion.versions.get(versionString); - - if (version != null) { - return version; - } - - String[] versionParts = versionString.split("\\."); - - if (versionParts.length != 2 && versionParts.length != 3) { - throw new IllegalArgumentException(String.format("API version string should be of format \"major.minor.patch\" or \"major.minor\", where \"major\", \"minor\" and \"patch\" are numbers. For example \"1.18.2\" or \"1.13\", but got '%s' instead.", versionString)); - } - - int major = ApiVersion.parseNumber(versionParts[0]); - int minor = ApiVersion.parseNumber(versionParts[1]); - - int patch; - if (versionParts.length == 3) { - patch = ApiVersion.parseNumber(versionParts[2]); - } else { - patch = 0; - } - - versionString = ApiVersion.toVersionString(major, minor, patch); - return ApiVersion.versions.computeIfAbsent(versionString, s -> new ApiVersion(major, minor, patch)); - } - - private static int parseNumber(String number) { - return Integer.parseInt(number); - } - - private static String toVersionString(int major, int minor, int patch) { - return major + "." + minor + "." + patch; - } - - @Override - public int compareTo(@NotNull ApiVersion other) { - int result = Integer.compare(this.major, other.major); - - if (result == 0) { - result = Integer.compare(this.minor, other.minor); - } - - if (result == 0) { - result = Integer.compare(this.patch, other.patch); - } - - return result; - } - - public String getVersionString() { - if (this.none) { - return "none"; - } - - return ApiVersion.toVersionString(this.major, this.minor, this.patch); - } - - public boolean isNewerThan(ApiVersion apiVersion) { - return this.compareTo(apiVersion) > 0; - } - - public boolean isOlderThan(ApiVersion apiVersion) { - return this.compareTo(apiVersion) < 0; - } - - public boolean isNewerThanOrSameAs(ApiVersion apiVersion) { - return this.compareTo(apiVersion) >= 0; - } - - public boolean isOlderThanOrSameAs(ApiVersion apiVersion) { - return this.compareTo(apiVersion) <= 0; - } - - @Override - public String toString() { - return this.getVersionString(); - } - - private static final long serialVersionUID = 0L; -} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java index cfba954cc65c..43b64734d3cc 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/Commodore.java @@ -1,15 +1,13 @@ package org.bukkit.craftbukkit.util; import com.google.common.base.Predicates; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; import com.google.common.io.ByteStreams; +import io.papermc.paper.plugin.ApiVersion; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; @@ -31,7 +29,6 @@ import org.bukkit.craftbukkit.legacy.FieldRename; import org.bukkit.craftbukkit.legacy.MaterialRerouting; import org.bukkit.craftbukkit.legacy.MethodRerouting; -import org.bukkit.craftbukkit.legacy.enums.EnumEvil; import org.bukkit.craftbukkit.legacy.reroute.Reroute; import org.bukkit.craftbukkit.legacy.reroute.RerouteArgument; import org.bukkit.craftbukkit.legacy.reroute.RerouteBuilder; @@ -70,12 +67,6 @@ public class Commodore { "org/bukkit/inventory/ItemStack (S)V setDurability" )); - private static final Map ENUM_RENAMES = Map.of( - "java/lang/Enum", "java/lang/Object", - "java/util/EnumSet", "org/bukkit/craftbukkit/legacy/enums/ImposterEnumSet", - "java/util/EnumMap", "org/bukkit/craftbukkit/legacy/enums/ImposterEnumMap" - ); - private static final Map RENAMES = Map.of( "org/bukkit/entity/TextDisplay$TextAligment", "org/bukkit/entity/TextDisplay$TextAlignment", // SPIGOT-7335 "org/spigotmc/event/entity/EntityMountEvent", "org/bukkit/event/entity/EntityMountEvent", @@ -120,7 +111,6 @@ public void updateReroute(Predicate compatibilityPresent) { .create(compatibilityPresent) .forClass(FieldRename.class) .forClass(MethodRerouting.class) - .forClass(EnumEvil.class) .build(); this.reroutes.clear(); 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 9323383f7d12..fc52e06d52a6 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 @@ -15,6 +15,8 @@ import com.mojang.serialization.JsonOps; 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.registry.RegistryKey; import java.io.File; import java.io.IOException; @@ -398,6 +400,7 @@ public byte[] processClass(PluginDescriptionFile pdf, String path, byte[] clazz) // Paper end try { clazz = this.commodore.convert(clazz, pdf.getName(), ApiVersion.getOrCreateVersion(pdf.getAPIVersion()), ((CraftServer) Bukkit.getServer()).activeCompatibilities); + clazz = ClassloaderBytecodeModifier.bytecodeModifier().modify(pdf, clazz); } catch (Exception ex) { Bukkit.getLogger().log(Level.SEVERE, "Fatal error trying to convert " + pdf.getFullName() + ":" + path, ex); } 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.ClassloaderBytecodeModifier index 20dbe2775951..4a5548399719 100644 --- 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.ClassloaderBytecodeModifier @@ -1 +1 @@ -io.papermc.paper.plugin.entrypoint.classloader.PaperClassloaderBytecodeModifier +io.papermc.paper.plugin.entrypoint.classloader.bytecode.PaperClassloaderBytecodeModifier diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/MaterialReroutingTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/MaterialReroutingTest.java index f6b04513355c..d2dc53cb7f71 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/MaterialReroutingTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/MaterialReroutingTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.*; import com.google.common.base.Joiner; import com.google.common.base.Predicates; +import io.papermc.paper.plugin.ApiVersion; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -15,7 +16,6 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.legacy.reroute.Reroute; import org.bukkit.craftbukkit.legacy.reroute.RerouteBuilder; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.Commodore; import org.bukkit.support.environment.Normal; import org.junit.jupiter.api.AfterAll; diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/InjectPluginVersionTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/InjectPluginVersionTest.java index 1612d66ac326..f4c67fc9b5b5 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/InjectPluginVersionTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/InjectPluginVersionTest.java @@ -2,9 +2,9 @@ import static org.junit.jupiter.api.Assertions.*; import com.google.common.base.Predicates; +import io.papermc.paper.plugin.ApiVersion; import java.util.List; import java.util.Map; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.support.environment.Normal; import org.junit.jupiter.api.Test; diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionDataTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionDataTest.java index c7c9ab3e6960..827ae538cbc6 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionDataTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionDataTest.java @@ -1,8 +1,9 @@ package org.bukkit.craftbukkit.legacy.reroute; import static org.junit.jupiter.api.Assertions.*; + +import io.papermc.paper.plugin.ApiVersion; import java.lang.annotation.Annotation; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.support.environment.Normal; import org.junit.jupiter.api.Test; diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionTest.java index 840073648a95..4dd09a4ed192 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/legacy/reroute/RequirePluginVersionTest.java @@ -1,8 +1,8 @@ package org.bukkit.craftbukkit.legacy.reroute; +import io.papermc.paper.plugin.ApiVersion; import java.util.List; import java.util.Map; -import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.support.environment.Normal; import org.junit.jupiter.api.Test; diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/util/ApiVersionTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/util/ApiVersionTest.java index 99a60be33772..7d8db55d08b3 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/util/ApiVersionTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/util/ApiVersionTest.java @@ -1,6 +1,8 @@ package org.bukkit.craftbukkit.util; import static org.junit.jupiter.api.Assertions.*; + +import io.papermc.paper.plugin.ApiVersion; import java.util.stream.Stream; import net.minecraft.SharedConstants; import org.bukkit.support.environment.VanillaFeature; @@ -19,7 +21,9 @@ public static Stream parseData() { Arguments.of("none", "none"), Arguments.of("1.12", "1.12.0"), Arguments.of("1.13.3", "1.13.3"), - Arguments.of("1.+20.3", "1.20.3") + Arguments.of("1.+20.3", "1.20.3"), + Arguments.of("26.1", "26.1.0"), + Arguments.of("28.2.3", "28.2.3") ); } @@ -27,7 +31,11 @@ public static Stream compareData() { return Stream.of( Arguments.of("none", "none", CompareResult.SAME), Arguments.of("none", "1.20", CompareResult.SMALLER), - Arguments.of("2.20.3", "1.30.4", CompareResult.BIGGER), + Arguments.of("1.20.3", "1.19.4", CompareResult.BIGGER), + Arguments.of("26.1", "1.21.4", CompareResult.BIGGER), + Arguments.of("26.3.2", "1.21.11", CompareResult.BIGGER), + Arguments.of("none", "26.1.2", CompareResult.SMALLER), + Arguments.of("1.8.9", "26.1.2", CompareResult.SMALLER), Arguments.of("1.13", "1.12", CompareResult.BIGGER), Arguments.of("1.13.2", "1.13.3", CompareResult.SMALLER) ); @@ -90,8 +98,8 @@ public void testParsing(String parse, String expected) { @Test public void testSameInstance() { - ApiVersion one = ApiVersion.getOrCreateVersion("1.23.3"); - ApiVersion second = ApiVersion.getOrCreateVersion("1.+23.3"); + ApiVersion one = ApiVersion.getOrCreateVersion("1.20.3"); + ApiVersion second = ApiVersion.getOrCreateVersion("1.+20.3"); assertSame(one, second); }