-
-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
26,402 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
35 changes: 35 additions & 0 deletions
35
src/main/java/com/maxqia/remapper/ClassInheritanceProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.maxqia.remapper; | ||
|
||
import net.md_5.specialsource.provider.InheritanceProvider; | ||
|
||
import java.util.Collection; | ||
import java.util.HashSet; | ||
|
||
public class ClassInheritanceProvider implements InheritanceProvider { | ||
|
||
@Override | ||
public Collection<String> getParents(String className) { | ||
className = Transformer.remapper.map(className); | ||
|
||
try { | ||
Collection<String> parents = new HashSet<>(); | ||
Class<?> reference = Class.forName(className.replace('/', '.').replace('$', '.'), false, this.getClass().getClassLoader()/*RemappedMethods.loader*/); | ||
Class<?> extend = reference.getSuperclass(); | ||
if (extend != null) { | ||
parents.add(Utils.reverseMap(extend)); | ||
} | ||
|
||
for (Class<?> inter : reference.getInterfaces()) { | ||
if (inter != null) { | ||
parents.add(Utils.reverseMap(inter)); | ||
} | ||
} | ||
|
||
return parents; | ||
} catch (Exception e) { | ||
// Empty catch block | ||
} | ||
return null; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.maxqia.remapper; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
/** | ||
* Based on Apache's ReflectionUtil | ||
* | ||
* @author Maxqia | ||
*/ | ||
public class RemapUtils { | ||
|
||
private static final Method GET_CALLER_CLASS; | ||
|
||
static { | ||
try { | ||
final Class<?> reflection = Class.forName("sun.reflect.Reflection"); | ||
GET_CALLER_CLASS = reflection.getMethod("getCallerClass", int.class); | ||
} catch (ReflectiveOperationException e) { | ||
throw new RuntimeException("getCallerClass doesn't exist!"); | ||
} | ||
} | ||
|
||
public static Class<?> getCallerClass(int skip) { | ||
if (GET_CALLER_CLASS != null) { | ||
try { | ||
return (Class<?>) GET_CALLER_CLASS.invoke(null, skip + 1); | ||
} catch (ReflectiveOperationException e) { | ||
throw new AssertionError(e.getMessage()); | ||
} | ||
} | ||
throw new RuntimeException("getCallerClass doesn't exist!"); | ||
} | ||
|
||
public static ClassLoader getCallerClassloader() { | ||
return getCallerClass(3).getClassLoader(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package com.maxqia.remapper; | ||
|
||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.util.Map; | ||
|
||
import static com.maxqia.remapper.Utils.*; | ||
|
||
public class RemappedMethods { | ||
|
||
// Classes | ||
public static Class<?> forName(String className) throws ClassNotFoundException { | ||
return forName(className, true, RemapUtils.getCallerClassloader()); | ||
} // Class.forName(String) grabs the caller's classloader, we replicate that | ||
|
||
public static Class<?> forName(String className, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException { | ||
if (!className.startsWith("net.minecraft.server.v1_12_R1")) { | ||
return Class.forName(className, initialize, classLoader); | ||
} | ||
className = Transformer.jarMapping.classes.getOrDefault(className.replace('.', '/'), className).replace('/', '.'); | ||
return Class.forName(className, initialize, classLoader); | ||
} | ||
|
||
// Get Fields | ||
public static Field getField(Class<?> inst, String name) throws NoSuchFieldException, SecurityException { | ||
if (!inst.getName().startsWith("net.minecraft.")) { | ||
return inst.getField(name); | ||
} | ||
return inst.getField(Transformer.remapper.mapFieldName(reverseMap(inst), name, null)); | ||
} | ||
|
||
public static Field getDeclaredField(Class<?> inst, String name) throws NoSuchFieldException, SecurityException { | ||
if (!inst.getName().startsWith("net.minecraft.")) { | ||
return inst.getDeclaredField(name); | ||
} | ||
return inst.getDeclaredField(Transformer.remapper.mapFieldName(reverseMap(inst), name, null)); | ||
} | ||
|
||
// Get Methods | ||
public static Method getMethod(Class<?> inst, String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { | ||
if (!inst.getName().startsWith("net.minecraft.")) { | ||
return inst.getMethod(name, parameterTypes); | ||
} | ||
return inst.getMethod(mapMethod(inst, name, parameterTypes), parameterTypes); | ||
} | ||
|
||
public static Method getDeclaredMethod(Class<?> inst, String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { | ||
if (!inst.getName().startsWith("net.minecraft.")) { | ||
return inst.getDeclaredMethod(name, parameterTypes); | ||
} | ||
return inst.getDeclaredMethod(mapMethod(inst, name, parameterTypes), parameterTypes); | ||
} | ||
|
||
// getName | ||
public static String getName(Field field) { | ||
if (!field.getDeclaringClass().getName().startsWith("net.minecraft.")) { | ||
return field.getName(); | ||
} | ||
String name = field.getName(); | ||
String match = reverseMap(field.getDeclaringClass()); | ||
Map<String, String> map = Transformer.jarMapping.fields; | ||
for (String value : map.keySet()) { | ||
if (map.get(name).startsWith(match)) { | ||
String[] matched = value.split("/"); | ||
return matched[matched.length - 1]; | ||
} | ||
} | ||
|
||
return name; | ||
} | ||
|
||
public static String getName(Method method) { | ||
if (!method.getDeclaringClass().getName().startsWith("net.minecraft.")) { | ||
return method.getName(); | ||
} | ||
String name = method.getName(); | ||
String match = reverseMap(method.getDeclaringClass()); | ||
Map<String, String> map = Transformer.jarMapping.methods; | ||
for (String value : map.keySet()) { | ||
if (map.get(name).startsWith(match)) { | ||
String[] matched = value.split("\\s+")[0].split("/"); | ||
String rtr = matched[matched.length - 1]; | ||
return rtr; | ||
} | ||
} | ||
|
||
return name; | ||
} | ||
|
||
// getSimpleName | ||
public static String getSimpleName(Class<?> inst) { | ||
if (!inst.getName().startsWith("net.minecraft.")) { | ||
return inst.getSimpleName(); | ||
} | ||
String[] name = getName(inst).split("\\."); | ||
return name[name.length - 1]; | ||
} | ||
|
||
public static String getName(Class<?> inst) { | ||
if (!inst.getName().startsWith("net.minecraft.")) { | ||
return inst.getName(); | ||
} | ||
return reverseMapExternal(inst); | ||
} | ||
|
||
public static Class<?> loadClass(ClassLoader inst, String className) throws ClassNotFoundException { | ||
if (className.startsWith("net.minecraft.")) { | ||
className = Transformer.mapClass(className.replace('.', '/')).replace('/', '.'); | ||
} | ||
return inst.loadClass(className); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.maxqia.remapper; | ||
|
||
import net.md_5.specialsource.JarMapping; | ||
import net.md_5.specialsource.JarRemapper; | ||
import org.objectweb.asm.ClassReader; | ||
import org.objectweb.asm.ClassWriter; | ||
import org.objectweb.asm.Opcodes; | ||
import org.objectweb.asm.Type; | ||
import org.objectweb.asm.tree.AbstractInsnNode; | ||
import org.objectweb.asm.tree.ClassNode; | ||
import org.objectweb.asm.tree.MethodInsnNode; | ||
import org.objectweb.asm.tree.MethodNode; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.ListIterator; | ||
|
||
public class Transformer { | ||
|
||
public static JarMapping jarMapping; | ||
public static JarRemapper remapper; | ||
|
||
public static void init(JarMapping mapping, JarRemapper remapper) { | ||
if (Transformer.jarMapping == null) { | ||
Transformer.jarMapping = mapping; | ||
} | ||
if (Transformer.remapper == null) { | ||
Transformer.remapper = remapper; | ||
} | ||
} | ||
|
||
/** | ||
* Convert code from using Class.X methods to our remapped versions | ||
*/ | ||
public static byte[] transform(byte[] code) { | ||
ClassReader reader = new ClassReader(code); // Turn from bytes into visitor | ||
ClassNode node = new ClassNode(); | ||
reader.accept(node, 0); // Visit using ClassNode | ||
|
||
for (MethodNode method : node.methods) { // Taken from SpecialSource | ||
ListIterator<AbstractInsnNode> insnIterator = method.instructions.iterator(); | ||
while (insnIterator.hasNext()) { | ||
AbstractInsnNode insn = insnIterator.next(); | ||
if (!(insn instanceof MethodInsnNode)) { | ||
continue; | ||
} | ||
MethodInsnNode mi = (MethodInsnNode) insn; | ||
switch (mi.getOpcode()) { | ||
case Opcodes.INVOKEVIRTUAL: | ||
remapVirtual(mi); | ||
break; | ||
case Opcodes.INVOKESTATIC: | ||
remapForName(mi); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
ClassWriter writer = new ClassWriter(0); | ||
node.accept(writer); | ||
return writer.toByteArray(); | ||
} | ||
|
||
public static String mapClass(String className) { | ||
String tRemapped = JarRemapper.mapTypeName(className, jarMapping.packages, jarMapping.classes, className); | ||
if (tRemapped.equals(className) && className.startsWith("net/minecraft/server/") && !className.contains("v1_12_R1")) { | ||
String tNewClassStr = "net/minecraft/server/v1_12_R1" + "/" + className.substring("v1_12_R1".length()); | ||
return JarRemapper.mapTypeName(tNewClassStr, jarMapping.packages, jarMapping.classes, className); | ||
} | ||
return tRemapped; | ||
} | ||
|
||
private static void remapForName(AbstractInsnNode insn) { | ||
MethodInsnNode method = (MethodInsnNode) insn; | ||
if (!"java/lang/Class".equals(method.owner) || !"forName".equals(method.name)) { | ||
return; | ||
} | ||
method.owner = "com/maxqia/remapper/RemappedMethods"; | ||
} | ||
|
||
private static void remapVirtual(AbstractInsnNode insn) { | ||
MethodInsnNode method = (MethodInsnNode) insn; | ||
|
||
if (!(("java/lang/Class".equals(method.owner) && ("getField".equals(method.name) | ||
|| "getDeclaredField".equals(method.name) | ||
|| "getMethod".equals(method.name) | ||
|| "getDeclaredMethod".equals(method.name) | ||
|| "getSimpleName".equals(method.name)) | ||
) | ||
|| ("getName".equals(method.name) && ("java/lang/reflect/Field".equals(method.owner) | ||
|| "java/lang/reflect/Method".equals(method.owner))) | ||
|| ("java/lang/ClassLoader".equals(method.owner) && "loadClass".equals(method.name)))) { | ||
return; | ||
} | ||
|
||
Type returnType = Type.getReturnType(method.desc); | ||
|
||
ArrayList<Type> args = new ArrayList<>(); | ||
args.add(Type.getObjectType(method.owner)); | ||
args.addAll(Arrays.asList(Type.getArgumentTypes(method.desc))); | ||
|
||
method.setOpcode(Opcodes.INVOKESTATIC); | ||
method.owner = "com/maxqia/remapper/RemappedMethods"; | ||
method.desc = Type.getMethodDescriptor(returnType, args.toArray(new Type[args.size()])); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package com.maxqia.remapper; | ||
|
||
import org.objectweb.asm.Type; | ||
|
||
import java.util.Map; | ||
|
||
public class Utils { | ||
|
||
public static String reverseMapExternal(Class<?> name) { | ||
return reverseMap(name).replace('$', '.').replace('/', '.'); | ||
} | ||
|
||
public static String reverseMap(Class<?> name) { | ||
return reverseMap(Type.getInternalName(name)); | ||
} | ||
|
||
public static String reverseMap(String check) { | ||
return Transformer.jarMapping.classes.getOrDefault(check, check); | ||
} | ||
|
||
public static String mapMethod(Class<?> inst, String name, Class<?>... parameterTypes) { | ||
String result = mapMethodInternal(inst, name, parameterTypes); | ||
if (result != null) { | ||
return result; | ||
} | ||
return name; | ||
} | ||
|
||
public static String mapMethodInternal(Class<?> inst, String name, Class<?>... parameterTypes) { | ||
String match = reverseMap(inst) + "/" + name; | ||
|
||
Map<String, String> map = Transformer.jarMapping.methods; | ||
for (String value : map.keySet()) { | ||
String[] str = value.split("\\s+"); | ||
int i = 0; | ||
for (Type type : Type.getArgumentTypes(str[1])) { | ||
if (i >= parameterTypes.length || !type.getClassName().equals(reverseMapExternal(parameterTypes[i]))) { | ||
i = -1; | ||
break; | ||
} | ||
i++; | ||
} | ||
|
||
if (i >= parameterTypes.length) { | ||
return map.get(value); | ||
} | ||
} | ||
|
||
// return superMethodName | ||
Class interfaces = inst.getSuperclass(); | ||
if (interfaces != null) { | ||
String superMethodName = mapMethodInternal(interfaces, name, parameterTypes); | ||
return String.valueOf(superMethodName); | ||
} | ||
return null; | ||
} | ||
} |
Oops, something went wrong.