More ReflectionManager stuff
This commit is contained in:
		| @@ -7,15 +7,14 @@ import java.io.InputStreamReader; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| import com.google.common.collect.ImmutableMap; | ||||
| import me.libraryaddict.disguise.disguisetypes.DisguiseType; | ||||
| import org.bukkit.Art; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.Location; | ||||
| @@ -76,36 +75,31 @@ public class ReflectionManager { | ||||
|      */ | ||||
|     private static Map<String, Map<String, String>> ForgeFieldMappings; | ||||
|     /** | ||||
|      * Map of Forge fully qualified class names to a map from mc-dev method names to Forge method names. | ||||
|      * | ||||
|      * There may be a mapping from null in the innermost map, which may be ignored. | ||||
|      * Map of Forge fully qualified class names to a map from mc-dev method names to a map from method signatures to Forge method names. | ||||
|      */ | ||||
|     private static Map<String, Map<String, Map<Class<?>[], String>>> ForgeMethodMappings; | ||||
|     private static Map<String, Class<?>> primitiveTypes; | ||||
|     private static Pattern signatureSegment; | ||||
|     private static Map<String, Map<String, Map<String, String>>> ForgeMethodMappings; | ||||
|     private static Map<Class<?>, String> primitiveTypes; | ||||
|  | ||||
|     static { | ||||
|         final String nameseg_class = "a-zA-Z0-9$_"; | ||||
|         final String fqn_class = "a-zA-Z0-9$_/"; | ||||
|         final String fqn_component = "L[" + fqn_class + "]+;"; | ||||
|         final String fqn_class = nameseg_class + "/"; | ||||
|  | ||||
|         signatureSegment = Pattern.compile("\\[*(?:Z|B|C|S|I|J|F|D|V|" + fqn_component + ")"); | ||||
|         primitiveTypes = ImmutableMap.<String, Class<?>>builder() | ||||
|                 .put("Z", boolean.class) | ||||
|                 .put("B", byte.class) | ||||
|                 .put("C", char.class) | ||||
|                 .put("S", short.class) | ||||
|                 .put("I", int.class) | ||||
|                 .put("J", long.class) | ||||
|                 .put("F", float.class) | ||||
|                 .put("D", double.class) | ||||
|                 .put("V", void.class).build(); | ||||
|         primitiveTypes = ImmutableMap.<Class<?>, String>builder() | ||||
|                 .put(boolean.class,"Z") | ||||
|                 .put(byte.class,   "B") | ||||
|                 .put(char.class,   "C") | ||||
|                 .put(short.class,  "S") | ||||
|                 .put(int.class,    "I") | ||||
|                 .put(long.class,   "J") | ||||
|                 .put(float.class,  "F") | ||||
|                 .put(double.class, "D") | ||||
|                 .put(void.class,   "V").build(); | ||||
|  | ||||
|         if (isForge) { | ||||
|             // Initialize the maps by reading the srg file | ||||
|             ForgeClassMappings = new HashMap<String, String>(); | ||||
|             ForgeFieldMappings = new HashMap<String, Map<String, String>>(); | ||||
|             ForgeMethodMappings = new HashMap<String, Map<String, Map<Class<?>[], String>>>(); | ||||
|             ForgeMethodMappings = new HashMap<String, Map<String, Map<String, String>>>(); | ||||
|             try { | ||||
|                 InputStream stream = Class.forName("net.minecraftforge.common.MinecraftForge").getClassLoader() | ||||
|                         .getResourceAsStream("mappings/" + getBukkitVersion() + "/cb2numpkg.srg"); | ||||
| @@ -153,49 +147,37 @@ public class ReflectionManager { | ||||
|                     Matcher methodMatcher = methodPattern.matcher(line); | ||||
|                     if (methodMatcher.matches()) { | ||||
|                         // get by CB class name | ||||
|                         Map<String, Map<Class<?>[], String>> middleMap = ForgeMethodMappings.get(dir2fqn(methodMatcher.group(5))); | ||||
|                         Map<String, Map<String, String>> middleMap = ForgeMethodMappings.get(dir2fqn(methodMatcher.group(5))); | ||||
|                         if (middleMap == null) { | ||||
|                             middleMap = new HashMap<String, Map<Class<?>[], String>>(); | ||||
|                             middleMap = new HashMap<String, Map<String, String>>(); | ||||
|                             ForgeMethodMappings.put(dir2fqn(methodMatcher.group(5)), middleMap); | ||||
|                         } | ||||
|                         // get by CB method name | ||||
|                         Map<Class<?>[], String> innerMap = middleMap.get(methodMatcher.group(2)); | ||||
|                         Map<String, String> innerMap = middleMap.get(methodMatcher.group(2)); | ||||
|                         if (innerMap == null) { | ||||
|                             innerMap = new HashMap<Class<?>[], String>(); | ||||
|                             innerMap = new HashMap<String, String>(); | ||||
|                             middleMap.put(methodMatcher.group(2), innerMap); | ||||
|                         } | ||||
|                         // parse the class array | ||||
|                         Class<?>[] argsCb = null, argsForge = null; | ||||
|                         try { | ||||
|                             argsCb = parseSignatureArguments(methodMatcher.group(3)); | ||||
|                         } catch (Throwable ignored) { | ||||
|                         } | ||||
|                         try { | ||||
|                             argsForge = parseSignatureArguments(methodMatcher.group(7)); | ||||
|                         } catch (Throwable ignored) { | ||||
|                         } | ||||
|  | ||||
|                         innerMap.put(argsCb, methodMatcher.group(6)); | ||||
|                         innerMap.put(argsForge, methodMatcher.group(6)); | ||||
|                         System.out.println(methodMatcher.group(5) + "/" + methodMatcher.group(2) + "(" + argsForge + ") -> " + methodMatcher.group(6)); | ||||
|                         continue; | ||||
|                         // store the parameter strings | ||||
|                         innerMap.put(methodMatcher.group(3), methodMatcher.group(6)); | ||||
|                         innerMap.put(methodMatcher.group(7), methodMatcher.group(6)); | ||||
|                     } | ||||
|                 } | ||||
|                 System.out.println("[LibsDisguises] Loaded in Cauldron/Forge mode"); | ||||
|                 System.out.println("[LibsDisguises]" + ForgeClassMappings.size() + " Cauldron class mappings loaded"); | ||||
|                 System.out.println("[LibsDisguises]" + ForgeFieldMappings.size() + " Cauldron field mappings loaded"); | ||||
|                 System.out.println("[LibsDisguises]" + ForgeMethodMappings.size() + " Cauldron method mappings loaded"); | ||||
|                 System.out.println("[LibsDisguises] Loaded " + ForgeClassMappings.size() + " Cauldron class mappings"); | ||||
|                 System.out.println("[LibsDisguises] Loaded " + ForgeFieldMappings.size() + " Cauldron field mappings"); | ||||
|                 System.out.println("[LibsDisguises] Loaded " + ForgeMethodMappings.size() + " Cauldron method mappings"); | ||||
|             } catch (ClassNotFoundException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 System.err.println("Warning: Running on Cauldron server, but couldn't load mappings file"); | ||||
|                 System.err.println("Warning: Running on Cauldron server, but couldn't load mappings file. LibsDisguises will likely crash!"); | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 System.err.println("Warning: Running on Cauldron server, but couldn't load mappings file"); | ||||
|                 System.err.println("Warning: Running on Cauldron server, but couldn't load mappings file. LibsDisguises will likely crash!"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static final Class craftItemClass; | ||||
|     private static final Class<?> craftItemClass; | ||||
|     private static final Field pingField; | ||||
|     private static final Field trackerField; | ||||
|     private static final Field entitiesField; | ||||
| @@ -224,36 +206,17 @@ public class ReflectionManager { | ||||
|         trackerField = getNmsField("WorldServer", "tracker"); | ||||
|         entitiesField = getNmsField("EntityTracker", "trackedEntities"); | ||||
|         ihmGet = getNmsMethod("IntHashMap", "get", int.class); | ||||
|  | ||||
|         Method m = getNmsMethod("Item", "getItemOf", getNmsClass("Block")); | ||||
|         System.out.println(m); | ||||
|  | ||||
|         DisguiseType.ARROW.isMisc(); | ||||
|     } | ||||
|  | ||||
|     private static String dir2fqn(String s) { | ||||
|         return s.replaceAll("/", "."); | ||||
|     } | ||||
|  | ||||
|     public static Class<?>[] parseSignatureArguments(String args) throws ClassNotFoundException { | ||||
|         List<Class<?>> classes = new ArrayList<Class<?>>(); | ||||
|         Matcher matcher = signatureSegment.matcher(args); | ||||
|         while (matcher.find()) { | ||||
|             classes.add(parseClass(matcher.group())); | ||||
|         } | ||||
|         return classes.toArray(new Class<?>[classes.size()]); | ||||
|     } | ||||
|  | ||||
|     private static Class<?> parseClass(String str) throws ClassNotFoundException { | ||||
|         if (str.startsWith("[")) { | ||||
|             // Array | ||||
|             // http://stackoverflow.com/a/4901192/1210278 | ||||
|             return java.lang.reflect.Array.newInstance(parseClass(str.substring(1)), 0).getClass(); | ||||
|         } else if (str.length() == 1) { | ||||
|             return primitiveTypes.get(str); | ||||
|         } else if (str.startsWith("L")) { | ||||
|             // Chop off L and ; | ||||
|             return Class.forName(str.substring(1, str.length() - 1)); | ||||
|         } else { | ||||
|             throw new ClassNotFoundException("Malformed method signature fragment? Argument: " + str); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // === | ||||
|  | ||||
|     public static Object createEntityInstance(String entityName) { | ||||
| @@ -327,7 +290,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static Entity getBukkitEntity(Object nmsEntity) { | ||||
|         try { | ||||
|             return (Entity) ReflectionManager.getNmsClass("Entity").getMethod("getBukkitEntity").invoke(nmsEntity); | ||||
|             return (Entity) getNmsMethod("Entity", "getBukkitEntity").invoke(nmsEntity); | ||||
|         } catch (Exception ex) { | ||||
|             ex.printStackTrace(); | ||||
|         } | ||||
| @@ -347,7 +310,7 @@ public class ReflectionManager { | ||||
|         return bukkitVersion; | ||||
|     } | ||||
|  | ||||
|     public static Class getCraftClass(String className) { | ||||
|     public static Class<?> getCraftClass(String className) { | ||||
|         try { | ||||
|             return Class.forName("org.bukkit.craftbukkit." + getBukkitVersion() + "." + className); | ||||
|         } catch (Exception e) { | ||||
| @@ -358,8 +321,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static String getCraftSound(Sound sound) { | ||||
|         try { | ||||
|             Class c = getCraftClass("CraftSound"); | ||||
|             return (String) c.getMethod("getSound", Sound.class).invoke(null, sound); | ||||
|             return (String) getCraftClass("CraftSound").getMethod("getSound", Sound.class).invoke(null, sound); | ||||
|         } catch (Exception ex) { | ||||
|             ex.printStackTrace(); | ||||
|         } | ||||
| @@ -368,8 +330,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static String getEnumArt(Art art) { | ||||
|         try { | ||||
|             Class craftArt = Class.forName("org.bukkit.craftbukkit." + getBukkitVersion() + ".CraftArt"); | ||||
|             Object enumArt = craftArt.getMethod("BukkitToNotch", Art.class).invoke(null, art); | ||||
|             Object enumArt = getCraftClass("CraftArt").getMethod("BukkitToNotch", Art.class).invoke(null, art); | ||||
|             for (Field field : enumArt.getClass().getFields()) { | ||||
|                 if (field.getType() == String.class) { | ||||
|                     return (String) field.get(enumArt); | ||||
| @@ -416,15 +377,17 @@ public class ReflectionManager { | ||||
|     } | ||||
|  | ||||
|     public static Class getNmsClass(String className) { | ||||
|         try { | ||||
|             if (isForge) { | ||||
|                 String forgeName = ForgeClassMappings.get(className); | ||||
|                 if (forgeName == null) { | ||||
|                     throw new RuntimeException("Missing Forge mapping for " + className); | ||||
|         if (isForge) { | ||||
|             String forgeName = ForgeClassMappings.get(className); | ||||
|             if (forgeName != null) { | ||||
|                 try { | ||||
|                     return Class.forName(forgeName); | ||||
|                 } catch (ClassNotFoundException ignored) { | ||||
|                 } | ||||
|                 return Class.forName(forgeName); | ||||
|             } | ||||
|  | ||||
|             } else | ||||
|                 throw new RuntimeException("Missing Forge mapping for " + className); | ||||
|         } | ||||
|         try { | ||||
|             return Class.forName("net.minecraft.server." + getBukkitVersion() + "." + className); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
| @@ -455,14 +418,21 @@ public class ReflectionManager { | ||||
|     } | ||||
|  | ||||
|     public static Field getNmsField(Class clazz, String fieldName) { | ||||
|         try { | ||||
|             if (isForge) { | ||||
|                 Map<String, String> fieldMap = ForgeFieldMappings.get(clazz.getName()); | ||||
|                 if (fieldMap == null) { throw new RuntimeException("No field mappings for " + clazz.getName()); } | ||||
|         if (isForge) { | ||||
|             Map<String, String> fieldMap = ForgeFieldMappings.get(clazz.getName()); | ||||
|             if (fieldMap != null) { | ||||
|                 String forgeName = fieldMap.get(fieldName); | ||||
|                 if (forgeName == null) { throw new RuntimeException("No field mapping for " + clazz.getName() + "." + fieldName); } | ||||
|                 return clazz.getField(forgeName); | ||||
|             } | ||||
|                 if (forgeName != null) { | ||||
|                     try { | ||||
|                         return clazz.getField(forgeName); | ||||
|                     } catch (NoSuchFieldException ignored) { | ||||
|                     } | ||||
|                 } else | ||||
|                     throw new RuntimeException("No field mapping for " + clazz.getName() + "." + fieldName); | ||||
|             } else | ||||
|                 throw new RuntimeException("No field mappings for " + clazz.getName()); | ||||
|         } | ||||
|         try { | ||||
|             return clazz.getField(fieldName); | ||||
|         } catch (NoSuchFieldException e) { | ||||
|             e.printStackTrace(); | ||||
| @@ -474,17 +444,40 @@ public class ReflectionManager { | ||||
|         return getNmsMethod(getNmsClass(className), methodName, parameters); | ||||
|     } | ||||
|  | ||||
|     private static String methodSignaturePart(Class<?> param) { | ||||
|         if (param.isArray()) { | ||||
|             return "[" + methodSignaturePart(param.getComponentType()); | ||||
|         } else if (param.isPrimitive()) { | ||||
|             return primitiveTypes.get(param); | ||||
|         } else { | ||||
|             return "L" + param.getName().replaceAll("\\.", "/") + ";"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static Method getNmsMethod(Class<?> clazz, String methodName, Class<?>... parameters) { | ||||
|         if (isForge) { | ||||
|             Map<String, Map<String, String>> middleMap = ForgeMethodMappings.get(clazz.getName()); | ||||
|             if (middleMap != null) { | ||||
|                 Map<String, String> innerMap = middleMap.get(methodName); | ||||
|                 if (innerMap != null) { | ||||
|                     StringBuilder sb = new StringBuilder(); | ||||
|                     for (Class<?> cl : parameters) { | ||||
|                         sb.append(methodSignaturePart(cl)); | ||||
|                     } | ||||
|                     String trName = innerMap.get(sb.toString()); | ||||
|                     if (trName != null) { | ||||
|                         try { | ||||
|                             return clazz.getMethod(trName, parameters); | ||||
|                         } catch (NoSuchMethodException ignored) { | ||||
|                         } | ||||
|                     } else | ||||
|                         throw new RuntimeException("No method mapping for " + clazz.getName() + "." + methodName + "(" + sb.toString() + ")"); | ||||
|                 } else | ||||
|                     throw new RuntimeException("No method mapping for " + clazz.getName() + "." + methodName); | ||||
|             } else | ||||
|                 throw new RuntimeException("No method mappings for " + clazz.getName()); | ||||
|         } | ||||
|         try { | ||||
|             if (isForge) { | ||||
|                 Map<String, Map<Class<?>[], String>> middleMap = ForgeMethodMappings.get(clazz.getName()); | ||||
|                 if (middleMap == null) { throw new RuntimeException("No method mappings for " + clazz.getName()); } | ||||
|                 Map<Class<?>[], String> innerMap = middleMap.get(methodName); | ||||
|                 if (innerMap == null) { throw new RuntimeException("No method mapping for " + clazz.getName() + "." + methodName); } | ||||
|                 String trName = innerMap.get(parameters); | ||||
|                 if (trName == null) { throw new RuntimeException("No method mapping for " + clazz.getName() + "." + methodName + "(" + parameters + ")"); } | ||||
|                 return clazz.getMethod(trName, parameters); | ||||
|             } | ||||
|             return clazz.getMethod(methodName, parameters); | ||||
|         } catch (NoSuchMethodException e) { | ||||
|             e.printStackTrace(); | ||||
| @@ -550,7 +543,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static WrappedGameProfile grabProfileAddUUID(String playername) { | ||||
|         try { | ||||
|             Object minecraftServer = getNmsClass("MinecraftServer").getMethod("getServer").invoke(null); | ||||
|             Object minecraftServer = getNmsMethod("MinecraftServer", "getServer").invoke(null); | ||||
|             for (Method method : getNmsClass("MinecraftServer").getMethods()) { | ||||
|                 if (method.getReturnType().getSimpleName().equals("GameProfileRepository")) { | ||||
|                     Object profileRepo = method.invoke(minecraftServer); | ||||
|   | ||||
| @@ -1,29 +0,0 @@ | ||||
| package me.libraryaddict.disguise.utilities; | ||||
|  | ||||
| import org.junit.Test; | ||||
|  | ||||
| import static org.junit.Assert.assertEquals; | ||||
|  | ||||
| public class ReflectionManagerTests { | ||||
|  | ||||
|     @Test | ||||
|     public void testParseSignatureArguments() throws Exception { | ||||
|         Class<?>[] expect, actual; | ||||
|  | ||||
|         expect = new Class<?>[] {boolean.class, byte.class, char.class, short.class, int.class, long.class, float.class, double.class}; | ||||
|         actual = ReflectionManager.parseSignatureArguments("ZBCSIJFD"); | ||||
|         assertEquals(expect, actual); | ||||
|  | ||||
|         expect = new Class<?>[] {int.class, String[].class, int.class, String.class}; | ||||
|         actual = ReflectionManager.parseSignatureArguments("I[Ljava/lang/String;ILjava/lang/String;"); | ||||
|         assertEquals(expect, actual); | ||||
|  | ||||
|         expect = new Class<?>[] {}; | ||||
|         actual = ReflectionManager.parseSignatureArguments(""); | ||||
|         assertEquals(expect, actual); | ||||
|  | ||||
|         expect = new Class<?>[] {boolean[][][][][][].class}; | ||||
|         actual = ReflectionManager.parseSignatureArguments("[[[[[[Z"); | ||||
|         assertEquals(expect, actual); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user