SPIGOT-5336: Field name parity with Minecraft keys

By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
CraftBukkit/Spigot
2024-04-24 01:15:00 +10:00
parent d122883f57
commit 760899464e
26 changed files with 1306 additions and 156 deletions

View File

@@ -281,7 +281,7 @@ public final class CraftLegacy {
SPAWN_EGGS.put((byte) EntityType.HUSK.getTypeId(), Material.HUSK_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.LLAMA.getTypeId(), Material.LLAMA_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.MAGMA_CUBE.getTypeId(), Material.MAGMA_CUBE_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.MUSHROOM_COW.getTypeId(), Material.MOOSHROOM_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.MOOSHROOM.getTypeId(), Material.MOOSHROOM_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.MULE.getTypeId(), Material.MULE_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.OCELOT.getTypeId(), Material.OCELOT_SPAWN_EGG);
SPAWN_EGGS.put((byte) EntityType.PARROT.getTypeId(), Material.PARROT_SPAWN_EGG);

View File

@@ -0,0 +1,340 @@
package org.bukkit.craftbukkit.legacy;
import org.bukkit.Particle;
import org.bukkit.block.Biome;
import org.bukkit.block.banner.PatternType;
import org.bukkit.craftbukkit.legacy.fieldrename.FieldRenameData;
import org.bukkit.craftbukkit.legacy.reroute.DoNotReroute;
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.loot.LootTables;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionType;
public class FieldRename {
@DoNotReroute
public static String rename(ApiVersion apiVersion, String owner, String from) {
if (owner == null) {
return from;
}
return switch (owner) {
case "org/bukkit/block/banner/PatternType" -> convertPatternTypeName(apiVersion, from);
case "org/bukkit/enchantments/Enchantment" -> convertEnchantmentName(apiVersion, from);
case "org/bukkit/block/Biome" -> convertBiomeName(apiVersion, from);
case "org/bukkit/entity/EntityType" -> convertEntityTypeName(apiVersion, from);
case "org/bukkit/potion/PotionEffectType" -> convertPotionEffectTypeName(apiVersion, from);
case "org/bukkit/potion/PotionType" -> convertPotionTypeName(apiVersion, from);
case "org/bukkit/MusicInstrument" -> convertMusicInstrumentName(apiVersion, from);
case "org/bukkit/Particle" -> convertParticleName(apiVersion, from);
case "org/bukkit/loot/LootTables" -> convertLootTablesName(apiVersion, from);
case "org/bukkit/attribute/Attribute" -> convertAttributeName(apiVersion, from);
default -> from;
};
}
// PatternType
private static final FieldRenameData PATTERN_TYPE_DATA = FieldRenameData.Builder.newBuilder()
.forVersionsBefore(ApiVersion.FIELD_NAME_PARITY)
.change("DIAGONAL_RIGHT", "DIAGONAL_UP_RIGHT")
.forAllVersions()
.change("STRIPE_SMALL", "SMALL_STRIPES")
.change("DIAGONAL_LEFT_MIRROR", "DIAGONAL_UP_LEFT")
.change("DIAGONAL_RIGHT_MIRROR", "DIAGONAL_RIGHT")
.change("CIRCLE_MIDDLE", "CIRCLE")
.change("RHOMBUS_MIDDLE", "RHOMBUS")
.change("HALF_VERTICAL_MIRROR", "HALF_VERTICAL_RIGHT")
.change("HALF_HORIZONTAL_MIRROR", "HALF_HORIZONTAL_BOTTOM")
.build();
@DoNotReroute
public static String convertPatternTypeName(ApiVersion version, String from) {
return PATTERN_TYPE_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@RerouteStatic("org/bukkit/block/banner/PatternType")
public static PatternType valueOf_PatternType(String value, @InjectPluginVersion ApiVersion version) {
return PatternType.valueOf(convertPatternTypeName(version, value));
}
// Enchantment
private static final FieldRenameData ENCHANTMENT_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("PROTECTION_ENVIRONMENTAL", "PROTECTION")
.change("PROTECTION_FIRE", "FIRE_PROTECTION")
.change("PROTECTION_FALL", "FEATHER_FALLING")
.change("PROTECTION_EXPLOSIONS", "BLAST_PROTECTION")
.change("PROTECTION_PROJECTILE", "PROJECTILE_PROTECTION")
.change("OXYGEN", "RESPIRATION")
.change("WATER_WORKER", "AQUA_AFFINITY")
.change("DAMAGE_ALL", "SHARPNESS")
.change("DAMAGE_UNDEAD", "SMITE")
.change("DAMAGE_ARTHROPODS", "BANE_OF_ARTHROPODS")
.change("LOOT_BONUS_MOBS", "LOOTING")
.change("SWEEPING_EDGE", "SWEEPING")
.change("DIG_SPEED", "EFFICIENCY")
.change("DURABILITY", "UNBREAKING")
.change("LOOT_BONUS_BLOCKS", "FORTUNE")
.change("ARROW_DAMAGE", "POWER")
.change("ARROW_KNOCKBACK", "PUNCH")
.change("ARROW_FIRE", "FLAME")
.change("ARROW_INFINITY", "INFINITY")
.change("LUCK", "LUCK_OF_THE_SEA")
.build();
@DoNotReroute
public static String convertEnchantmentName(ApiVersion version, String from) {
return ENCHANTMENT_DATA.getReplacement(version, from);
}
@RerouteMethodName("getByName")
@RerouteStatic("org/bukkit/enchantments/Enchantment")
public static Enchantment getByName_Enchantment(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return Enchantment.getByName(convertEnchantmentName(ApiVersion.CURRENT, name));
}
// Biome
private static final FieldRenameData BIOME_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("NETHER", "NETHER_WASTES")
.change("TALL_BIRCH_FOREST", "OLD_GROWTH_BIRCH_FOREST")
.change("GIANT_TREE_TAIGA", "OLD_GROWTH_PINE_TAIGA")
.change("GIANT_SPRUCE_TAIGA", "OLD_GROWTH_SPRUCE_TAIGA")
.change("SNOWY_TUNDRA", "SNOWY_PLAINS")
.change("JUNGLE_EDGE", "SPARSE_JUNGLE")
.change("STONE_SHORE", "STONY_SHORE")
.change("MOUNTAINS", "WINDSWEPT_HILLS")
.change("WOODED_MOUNTAINS", "WINDSWEPT_FOREST")
.change("GRAVELLY_MOUNTAINS", "WINDSWEPT_GRAVELLY_HILLS")
.change("SHATTERED_SAVANNA", "WINDSWEPT_SAVANNA")
.change("WOODED_BADLANDS_PLATEAU", "WOODED_BADLANDS")
.build();
@DoNotReroute
public static String convertBiomeName(ApiVersion version, String from) {
return BIOME_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@RerouteStatic("org/bukkit/block/Biome")
public static Biome valueOf_Biome(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return Biome.valueOf(convertBiomeName(ApiVersion.CURRENT, name));
}
// EntityType
private static final FieldRenameData ENTITY_TYPE_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("XP_ORB", "EXPERIENCE_ORB")
.change("EYE_OF_ENDER_SIGNAL", "EYE_OF_ENDER")
.change("XP_BOTTLE", "EXPERIENCE_BOTTLE")
.change("FIREWORKS_ROCKET", "FIREWORK_ROCKET")
.change("EVOCATION_FANGS", "EVOKER_FANGS")
.change("EVOCATION_ILLAGER", "EVOKER")
.change("VINDICATION_ILLAGER", "VINDICATOR")
.change("ILLUSION_ILLAGER", "ILLUSIONER")
.change("COMMANDBLOCK_MINECART", "COMMAND_BLOCK_MINECART")
.change("SNOWMAN", "SNOW_GOLEM")
.change("VILLAGER_GOLEM", "IRON_GOLEM")
.change("ENDER_CRYSTAL", "END_CRYSTAL")
.change("ZOMBIE_PIGMAN", "ZOMBIFIED_PIGLIN")
.change("PIG_ZOMBIE", "ZOMBIFIED_PIGLIN")
.change("DROPPED_ITEM", "ITEM")
.change("LEASH_HITCH", "LEASH_KNOT")
.change("ENDER_SIGNAL", "EYE_OF_ENDER")
.change("SPLASH_POTION", "POTION")
.change("THROWN_EXP_BOTTLE", "EXPERIENCE_BOTTLE")
.change("PRIMED_TNT", "TNT")
.change("FIREWORK", "FIREWORK_ROCKET")
.change("MINECART_COMMAND", "COMMAND_BLOCK_MINECART")
.change("MINECART_CHEST", "CHEST_MINECART")
.change("MINECART_FURNACE", "FURNACE_MINECART")
.change("MINECART_TNT", "TNT_MINECART")
.change("MINECART_HOPPER", "HOPPER_MINECART")
.change("MINECART_MOB_SPAWNER", "SPAWNER_MINECART")
.change("MUSHROOM_COW", "MOOSHROOM")
.change("SNOWMAN", "SNOW_GOLEM")
.change("ENDER_CRYSTAL", "END_CRYSTAL")
.change("FISHING_HOOK", "FISHING_BOBBER")
.change("LIGHTNING", "LIGHTNING_BOLT")
.build();
@DoNotReroute
public static String convertEntityTypeName(ApiVersion version, String from) {
return ENTITY_TYPE_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@RerouteStatic("org/bukkit/entity/EntityType")
public static EntityType valueOf_EntityType(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return EntityType.valueOf(convertEntityTypeName(ApiVersion.CURRENT, name));
}
@RerouteMethodName("fromName")
@RerouteStatic("org/bukkit/entity/EntityType")
public static EntityType fromName_EntityType(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return EntityType.fromName(convertEntityTypeName(ApiVersion.CURRENT, name));
}
// PotionEffectType
private static final FieldRenameData POTION_EFFECT_TYPE_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("SLOW", "SLOWNESS")
.change("FAST_DIGGING", "HASTE")
.change("SLOW_DIGGING", "MINING_FATIGUE")
.change("INCREASE_DAMAGE", "STRENGTH")
.change("HEAL", "INSTANT_HEALTH")
.change("HARM", "INSTANT_DAMAGE")
.change("JUMP", "JUMP_BOOST")
.change("CONFUSION", "NAUSEA")
.change("DAMAGE_RESISTANCE", "RESISTANCE")
.build();
@DoNotReroute
public static String convertPotionEffectTypeName(ApiVersion version, String from) {
return POTION_EFFECT_TYPE_DATA.getReplacement(version, from);
}
@RerouteMethodName("getByName")
@RerouteStatic("org/bukkit/potion/PotionEffectType")
public static PotionEffectType getByName_PotionEffectType(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return PotionEffectType.getByName(convertPotionEffectTypeName(ApiVersion.CURRENT, name));
}
// PotionType
private static final FieldRenameData POTION_TYPE_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("UNCRAFTABLE", "EMPTY")
.change("JUMP", "LEAPING")
.change("SPEED", "SWIFTNESS")
.change("INSTANT_HEAL", "HEALING")
.change("INSTANT_DAMAGE", "HARMING")
.change("REGEN", "REGENERATION")
.build();
@DoNotReroute
public static String convertPotionTypeName(ApiVersion version, String from) {
return POTION_TYPE_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@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(convertPotionTypeName(ApiVersion.CURRENT, name));
}
// MusicInstrument
private static final FieldRenameData MUSIC_INSTRUMENT_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("PONDER", "PONDER_GOAT_HORN")
.change("SING", "SING_GOAT_HORN")
.change("SEEK", "SEEK_GOAT_HORN")
.change("ADMIRE", "ADMIRE_GOAT_HORN")
.change("CALL", "CALL_GOAT_HORN")
.change("YEARN", "YEARN_GOAT_HORN")
.change("DREAM", "DREAM_GOAT_HORN")
.build();
@DoNotReroute
public static String convertMusicInstrumentName(ApiVersion version, String from) {
return MUSIC_INSTRUMENT_DATA.getReplacement(version, from);
}
// Particle
private static final FieldRenameData PARTICLE_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("EXPLOSION_NORMAL", "POOF")
.change("EXPLOSION_LARGE", "EXPLOSION")
.change("EXPLOSION_HUGE", "EXPLOSION_EMITTER")
.change("FIREWORKS_SPARK", "FIREWORK")
.change("WATER_BUBBLE", "BUBBLE")
.change("WATER_SPLASH", "SPLASH")
.change("WATER_WAKE", "FISHING")
.change("SUSPENDED", "UNDERWATER")
.change("SUSPENDED_DEPTH", "UNDERWATER")
.change("CRIT_MAGIC", "ENCHANTED_HIT")
.change("SMOKE_NORMAL", "SMOKE")
.change("SMOKE_LARGE", "LARGE_SMOKE")
.change("SPELL", "EFFECT")
.change("SPELL_INSTANT", "INSTANT_EFFECT")
.change("SPELL_MOB", "ENTITY_EFFECT")
.change("SPELL_MOB_AMBIENT", "AMBIENT_ENTITY_EFFECT")
.change("SPELL_WITCH", "WITCH")
.change("DRIP_WATER", "DRIPPING_WATER")
.change("DRIP_LAVA", "DRIPPING_LAVA")
.change("VILLAGER_ANGRY", "ANGRY_VILLAGER")
.change("VILLAGER_HAPPY", "HAPPY_VILLAGER")
.change("TOWN_AURA", "MYCELIUM")
.change("ENCHANTMENT_TABLE", "ENCHANT")
.change("REDSTONE", "DUST")
.change("SNOWBALL", "ITEM_SNOWBALL")
.change("SNOW_SHOVEL", "ITEM_SNOWBALL")
.change("SLIME", "ITEM_SLIME")
.change("ITEM_CRACK", "ITEM")
.change("BLOCK_CRACK", "BLOCK")
.change("BLOCK_DUST", "BLOCK")
.change("WATER_DROP", "RAIN")
.change("MOB_APPEARANCE", "ELDER_GUARDIAN")
.change("TOTEM", "TOTEM_OF_UNDYING")
.build();
@DoNotReroute
public static String convertParticleName(ApiVersion version, String from) {
return PARTICLE_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@RerouteStatic("org/bukkit/Particle")
public static Particle valueOf_Particle(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return Particle.valueOf(convertParticleName(ApiVersion.CURRENT, name));
}
// LootTables
private static final FieldRenameData LOOT_TABLES_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("ZOMBIE_PIGMAN", "ZOMBIFIED_PIGLIN")
.build();
@DoNotReroute
public static String convertLootTablesName(ApiVersion version, String from) {
return LOOT_TABLES_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@RerouteStatic("org/bukkit/loot/LootTables")
public static LootTables valueOf_LootTables(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return LootTables.valueOf(convertLootTablesName(ApiVersion.CURRENT, name));
}
// LootTables
private static final FieldRenameData ATTRIBUTE_DATA = FieldRenameData.Builder.newBuilder()
.forAllVersions()
.change("HORSE_JUMP_STRENGTH", "GENERIC_JUMP_STRENGTH")
.build();
@DoNotReroute
public static String convertAttributeName(ApiVersion version, String from) {
return ATTRIBUTE_DATA.getReplacement(version, from);
}
@RerouteMethodName("valueOf")
@RerouteStatic("org/bukkit/attribute/Attribute")
public static LootTables valueOf_Attribute(String name) {
// We don't have version-specific changes, so just use current, and don't inject a version
return LootTables.valueOf(convertAttributeName(ApiVersion.CURRENT, name));
}
}

View File

@@ -0,0 +1,64 @@
package org.bukkit.craftbukkit.legacy.fieldrename;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import org.bukkit.craftbukkit.util.ApiVersion;
public record FieldRenameData(NavigableMap<ApiVersion, Map<String, String>> versionData, Map<String, String> data) {
public String getReplacement(ApiVersion apiVersion, String from) {
if (from == null) {
return null;
}
from = from.toUpperCase(Locale.ROOT);
from = data.getOrDefault(from, from);
for (Map.Entry<ApiVersion, Map<String, String>> entry : versionData.entrySet()) {
if (apiVersion.isNewerThanOrSameAs(entry.getKey())) {
continue;
}
from = entry.getValue().getOrDefault(from, from);
}
return from;
}
public static class Builder {
private final Map<String, String> data = new HashMap<>();
private final NavigableMap<ApiVersion, Map<String, String>> versionData = new TreeMap<>();
private ApiVersion currentVersion;
public static Builder newBuilder() {
return new Builder();
}
public Builder forVersionsBefore(ApiVersion apiVersion) {
this.currentVersion = apiVersion;
return this;
}
public Builder forAllVersions() {
this.currentVersion = null;
return this;
}
public Builder change(String from, String to) {
if (currentVersion != null) {
versionData.computeIfAbsent(currentVersion, d -> new HashMap<>()).put(from, to);
} else {
data.put(from, to);
}
return this;
}
public FieldRenameData build() {
return new FieldRenameData(versionData, data);
}
}
}

View File

@@ -0,0 +1,11 @@
package org.bukkit.craftbukkit.legacy.reroute;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoNotReroute {
}

View File

@@ -0,0 +1,11 @@
package org.bukkit.craftbukkit.legacy.reroute;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface InjectPluginName {
}

View File

@@ -0,0 +1,11 @@
package org.bukkit.craftbukkit.legacy.reroute;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface InjectPluginVersion {
}

View File

@@ -0,0 +1,39 @@
package org.bukkit.craftbukkit.legacy.reroute;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public record RerouteArgument(Type type, boolean injectPluginName, boolean injectPluginVersion) {
/**
* Converts the type string to the correct load opcode.
* <br>
* References:
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.3.2-200">Interpretation of field descriptors</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.iload">iload Opcode</a> /
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.iload_n">{@literal iload_<n> Opcode}</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.lload">lload Opcode</a> /
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.lload_n">{@literal lload_<n> Opcode}</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.fload">fload Opcode</a> /
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.fload">{@literal fload_<n> Opcode}</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.dload">dload Opcode</a> /
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.dload_n">{@literal dload_<n> Opcode}</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.aload">aload Opcode</a> /
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.aload_n">{@literal aload_<n> Opcode}</a>
*
* @return the opcode of the type
*/
public int instruction() {
if (injectPluginName() || injectPluginVersion()) {
throw new IllegalStateException(String.format("Cannot get instruction for plugin name / version argument: %s", this));
}
return type.getOpcode(Opcodes.ILOAD);
}
}

View File

@@ -0,0 +1,115 @@
package org.bukkit.craftbukkit.legacy.reroute;
import com.google.common.base.Preconditions;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.craftbukkit.util.ApiVersion;
import org.objectweb.asm.Type;
public class RerouteBuilder {
public static Map<String, RerouteMethodData> buildFromClass(Class<?> clazz) {
Preconditions.checkArgument(!clazz.isInterface(), "Interface Classes are currently not supported");
Map<String, RerouteMethodData> result = new HashMap<>();
for (Method method : clazz.getDeclaredMethods()) {
if (method.isBridge()) {
continue;
}
if (method.isSynthetic()) {
continue;
}
if (!Modifier.isPublic(method.getModifiers())) {
continue;
}
if (!Modifier.isStatic(method.getModifiers())) {
continue;
}
if (method.isAnnotationPresent(DoNotReroute.class)) {
continue;
}
RerouteMethodData rerouteMethodData = buildFromMethod(method);
result.put(rerouteMethodData.source(), rerouteMethodData);
}
return Collections.unmodifiableMap(result);
}
public static RerouteMethodData buildFromMethod(Method method) {
RerouteReturn rerouteReturn = new RerouteReturn(Type.getReturnType(method));
List<RerouteArgument> arguments = new ArrayList<>();
List<RerouteArgument> sourceArguments = new ArrayList<>();
for (Parameter parameter : method.getParameters()) {
Type type = Type.getType(parameter.getType());
boolean injectPluginName = false;
boolean injectPluginVersion = false;
if (parameter.isAnnotationPresent(InjectPluginName.class)) {
if (parameter.getType() != String.class) {
throw new RuntimeException("Plugin name argument must be of type name, but got " + parameter.getType());
}
injectPluginName = true;
}
if (parameter.isAnnotationPresent(InjectPluginVersion.class)) {
if (parameter.getType() != ApiVersion.class) {
throw new RuntimeException("Plugin version argument must be of type ApiVersion, but got " + parameter.getType());
}
injectPluginVersion = true;
}
if (injectPluginName && injectPluginVersion) {
// This should not happen, since we check types,
// and those two have different types -> it would already have failed
throw new RuntimeException("Wtf?");
}
RerouteArgument argument = new RerouteArgument(type, injectPluginName, injectPluginVersion);
arguments.add(argument);
if (!injectPluginName && !injectPluginVersion) {
sourceArguments.add(argument);
}
}
RerouteStatic rerouteStatic = method.getAnnotation(RerouteStatic.class);
Type sourceOwner;
if (rerouteStatic != null) {
sourceOwner = Type.getObjectType(rerouteStatic.value());
} else {
RerouteArgument argument = sourceArguments.get(0);
sourceOwner = argument.type();
sourceArguments.remove(argument);
}
Type sourceDesc = Type.getMethodType(rerouteReturn.type(), sourceArguments.stream().map(RerouteArgument::type).toArray(Type[]::new));
RerouteMethodName rerouteMethodName = method.getAnnotation(RerouteMethodName.class);
String methodName;
if (rerouteMethodName != null) {
methodName = rerouteMethodName.value();
} else {
methodName = method.getName();
}
String methodKey = sourceOwner.getInternalName()
+ " "
+ sourceDesc.getDescriptor()
+ " "
+ methodName;
Type targetType = Type.getType(method);
return new RerouteMethodData(methodKey, sourceDesc, sourceOwner, methodName, rerouteStatic != null, targetType, Type.getInternalName(method.getDeclaringClass()), method.getName(), arguments, rerouteReturn);
}
}

View File

@@ -0,0 +1,9 @@
package org.bukkit.craftbukkit.legacy.reroute;
import java.util.List;
import org.objectweb.asm.Type;
public record RerouteMethodData(String source, Type sourceDesc, Type sourceOwner, String sourceName,
boolean staticReroute, Type targetType, String targetOwner, String targetName,
List<RerouteArgument> arguments, RerouteReturn rerouteReturn) {
}

View File

@@ -0,0 +1,13 @@
package org.bukkit.craftbukkit.legacy.reroute;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RerouteMethodName {
String value();
}

View File

@@ -0,0 +1,32 @@
package org.bukkit.craftbukkit.legacy.reroute;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public record RerouteReturn(Type type) {
/**
* Converts the type string to the correct return opcode.
* <br>
* References:
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.3.2-200">Interpretation of field descriptors</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.return">return Opcode</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.ireturn">ireturn Opcode</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.lreturn">lreturn Opcode</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.freturn">freturn Opcode</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.dreturn">dreturn Opcode</a>
* <br>
* <a href="https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.5.areturn">areturn Opcode</a>
*
* @return the opcode of the type
*/
public int instruction() {
return type.getOpcode(Opcodes.IRETURN);
}
}

View File

@@ -0,0 +1,13 @@
package org.bukkit.craftbukkit.legacy.reroute;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RerouteStatic {
String value();
}