SPIGOT-5336: Field name parity with Minecraft keys
By: DerFrZocker <derrieple@gmail.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user