Refactor redirect logic, should break nothing
This commit is contained in:
parent
ac27079e3f
commit
d5f39d57cc
|
@ -47,6 +47,7 @@ repositories {
|
||||||
maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
||||||
maven { url = 'https://files.minecraftforge.net/maven/' }
|
maven { url = 'https://files.minecraftforge.net/maven/' }
|
||||||
maven { url = 'https://jitpack.io/' }
|
maven { url = 'https://jitpack.io/' }
|
||||||
|
maven { url = 'https://maven.izzel.io/releases' }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -66,6 +67,7 @@ dependencies {
|
||||||
implementation 'net.md-5:bungeecord-chat:1.16-R0.4'
|
implementation 'net.md-5:bungeecord-chat:1.16-R0.4'
|
||||||
implementation 'mysql:mysql-connector-java:5.1.49'
|
implementation 'mysql:mysql-connector-java:5.1.49'
|
||||||
implementation 'org.yaml:snakeyaml:1.27'
|
implementation 'org.yaml:snakeyaml:1.27'
|
||||||
|
implementation 'io.izzel:tools:1.0.+'
|
||||||
implementation project(':arclight-api')
|
implementation project(':arclight-api')
|
||||||
implementation project(':i18n-config')
|
implementation project(':i18n-config')
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import org.objectweb.asm.tree.FieldInsnNode;
|
||||||
import org.objectweb.asm.tree.FieldNode;
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
import org.objectweb.asm.tree.InsnList;
|
import org.objectweb.asm.tree.InsnList;
|
||||||
import org.objectweb.asm.tree.InsnNode;
|
import org.objectweb.asm.tree.InsnNode;
|
||||||
import org.objectweb.asm.tree.IntInsnNode;
|
|
||||||
import org.objectweb.asm.tree.LdcInsnNode;
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
@ -25,6 +24,8 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static io.izzel.arclight.common.mod.util.remapper.ArclightRedirectAdapter.loadInt;
|
||||||
|
|
||||||
// 你好
|
// 你好
|
||||||
// 不要抄(笑)
|
// 不要抄(笑)
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -89,18 +90,6 @@ public class ArclightEnumExtender {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AbstractInsnNode loadInt(int i) {
|
|
||||||
if (i >= -1 && i < 6) {
|
|
||||||
return new InsnNode(Opcodes.ICONST_0 + i);
|
|
||||||
} else if (i >= -128 && i < 128) {
|
|
||||||
return new IntInsnNode(Opcodes.BIPUSH, i);
|
|
||||||
} else if (i >= -32768 && i < 32768) {
|
|
||||||
return new IntInsnNode(Opcodes.SIPUSH, i);
|
|
||||||
} else {
|
|
||||||
return new LdcInsnNode(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void tryCreateCtor(ClassNode node) {
|
private static void tryCreateCtor(ClassNode node) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (MethodNode method : node.methods) {
|
for (MethodNode method : node.methods) {
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package io.izzel.arclight.common.mod.util.remapper;
|
package io.izzel.arclight.common.mod.util.remapper;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import io.izzel.arclight.common.mod.ArclightMod;
|
import com.google.common.collect.Multimap;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
|
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
|
||||||
|
import io.izzel.arclight.common.util.ArrayUtil;
|
||||||
|
import io.izzel.tools.product.Product;
|
||||||
|
import io.izzel.tools.product.Product2;
|
||||||
|
import io.izzel.tools.product.Product4;
|
||||||
import org.apache.logging.log4j.Marker;
|
import org.apache.logging.log4j.Marker;
|
||||||
import org.apache.logging.log4j.MarkerManager;
|
import org.apache.logging.log4j.MarkerManager;
|
||||||
import org.objectweb.asm.Handle;
|
import org.objectweb.asm.Handle;
|
||||||
|
@ -10,131 +15,75 @@ import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.InsnList;
|
||||||
|
import org.objectweb.asm.tree.InsnNode;
|
||||||
|
import org.objectweb.asm.tree.IntInsnNode;
|
||||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||||
import org.objectweb.asm.tree.LdcInsnNode;
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
import org.objectweb.asm.tree.TypeInsnNode;
|
||||||
|
import org.spongepowered.asm.util.Bytecode;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ListIterator;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class ArclightRedirectAdapter implements PluginTransformer {
|
public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
|
|
||||||
public static final ArclightRedirectAdapter INSTANCE = new ArclightRedirectAdapter();
|
public static final ArclightRedirectAdapter INSTANCE = new ArclightRedirectAdapter();
|
||||||
private static final Marker MARKER = MarkerManager.getMarker("REDIRECT");
|
private static final Marker MARKER = MarkerManager.getMarker("REDIRECT");
|
||||||
private static final String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
|
private static final String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
|
||||||
private static final Map<MethodInsnNode, MethodInsnNode> METHOD_REDIRECTS = ImmutableMap
|
private static final Multimap<String, Product2<String, MethodInsnNode>> METHOD_MODIFY = HashMultimap.create();
|
||||||
.<MethodInsnNode, MethodInsnNode>builder()
|
private static final Multimap<String, Product2<String, MethodInsnNode>> METHOD_REDIRECT = HashMultimap.create();
|
||||||
.put(
|
private static final Map<Method, Product4<String, Class<?>[], String, Class<?>[]>> METHOD_TO_HANDLER = new HashMap<>();
|
||||||
method(Opcodes.INVOKEVIRTUAL, Field.class, "getName"),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFieldGetName", Field.class)
|
static {
|
||||||
)
|
redirect(Field.class, "getName", "fieldGetName");
|
||||||
.put(
|
redirect(Method.class, "getName", "methodGetName");
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getField", String.class),
|
redirect(Class.class, "getCanonicalName", "classGetCanonicalName");
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectGetField", Class.class, String.class)
|
redirect(Class.class, "getSimpleName", "classGetSimpleName");
|
||||||
)
|
modify(Class.class, "getName", "classGetName");
|
||||||
.put(
|
modify(Package.class, "getName", "packageGetName");
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getDeclaredField", String.class),
|
modify(Class.class, "forName", "classForName", String.class);
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectGetDeclaredField", Class.class, String.class)
|
modify(Class.class, "forName", "classForName", String.class, boolean.class, ClassLoader.class);
|
||||||
)
|
modify(Class.class, "getField", "classGetField", String.class);
|
||||||
.put(
|
modify(Class.class, "getDeclaredField", "classGetDeclaredField", String.class);
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getName"),
|
modify(Class.class, "getMethod", "classGetMethod", String.class, Class[].class);
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectClassGetName", Class.class)
|
modify(Class.class, "getDeclaredMethod", "classGetDeclaredMethod", String.class, Class[].class);
|
||||||
)
|
modify(MethodType.class, "fromMethodDescriptorString", "fromDescStr", String.class, ClassLoader.class);
|
||||||
.put(
|
modify(MethodHandles.Lookup.class, "findStatic", "lookupFindStatic", Class.class, String.class, MethodType.class);
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getCanonicalName"),
|
modify(MethodHandles.Lookup.class, "findVirtual", "lookupFindVirtual", Class.class, String.class, MethodType.class);
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectClassGetCanonicalName", Class.class)
|
modify(MethodHandles.Lookup.class, "findSpecial", "lookupFindSpecial", Class.class, String.class, MethodType.class, Class.class);
|
||||||
)
|
modify(MethodHandles.Lookup.class, "findGetter", "lookupFindGetter", Class.class, String.class, Class.class);
|
||||||
.put(
|
modify(MethodHandles.Lookup.class, "findSetter", "lookupFindSetter", Class.class, String.class, Class.class);
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getSimpleName"),
|
modify(MethodHandles.Lookup.class, "findStaticGetter", "lookupFindStaticGetter", Class.class, String.class, Class.class);
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectClassGetSimpleName", Class.class)
|
modify(MethodHandles.Lookup.class, "findStaticSetter", "lookupFindStaticSetter", Class.class, String.class, Class.class);
|
||||||
)
|
modify(ClassLoader.class, "loadClass", "classLoaderLoadClass", String.class);
|
||||||
.put(
|
// todo not enable this yet
|
||||||
method(Opcodes.INVOKEVIRTUAL, Method.class, "getName"),
|
// modify(Method.class, "invoke", "methodInvoke", Object.class, Object[].class);
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectMethodGetName", Method.class)
|
}
|
||||||
)
|
|
||||||
.put(
|
public static Product4<String, Class<?>[], String, Class<?>[]> getInvokeRule(Method method) {
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getMethod", String.class, Class[].class),
|
return METHOD_TO_HANDLER.get(method);
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectGetMethod", Class.class, String.class, Class[].class)
|
}
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, Class.class, "getDeclaredMethod", String.class, Class[].class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectGetDeclaredMethod", Class.class, String.class, Class[].class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKESTATIC, Class.class, "forName", String.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectForName", String.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKESTATIC, Class.class, "forName", String.class, boolean.class, ClassLoader.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectForName", String.class, boolean.class, ClassLoader.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, Package.class, "getName"),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectPackageGetName", Package.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKESTATIC, MethodType.class, "fromMethodDescriptorString", String.class, ClassLoader.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFromDescStr", String.class, ClassLoader.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findStatic", Class.class, String.class, MethodType.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindStatic", MethodHandles.Lookup.class, Class.class, String.class, MethodType.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findVirtual", Class.class, String.class, MethodType.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindVirtual", MethodHandles.Lookup.class, Class.class, String.class, MethodType.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findSpecial", Class.class, String.class, MethodType.class, Class.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindSpecial", MethodHandles.Lookup.class, Class.class, String.class, MethodType.class, Class.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findGetter", Class.class, String.class, Class.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindGetter", MethodHandles.Lookup.class, Class.class, String.class, Class.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findSetter", Class.class, String.class, Class.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindSetter", MethodHandles.Lookup.class, Class.class, String.class, Class.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findStaticGetter", Class.class, String.class, Class.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindStaticGetter", MethodHandles.Lookup.class, Class.class, String.class, Class.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, MethodHandles.Lookup.class, "findStaticSetter", Class.class, String.class, Class.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectFindStaticSetter", MethodHandles.Lookup.class, Class.class, String.class, Class.class)
|
|
||||||
)
|
|
||||||
.put(
|
|
||||||
method(Opcodes.INVOKEVIRTUAL, ClassLoader.class, "loadClass", String.class),
|
|
||||||
method(Opcodes.INVOKESTATIC, ArclightReflectionHandler.class, "redirectClassLoaderLoadClass", ClassLoader.class, String.class)
|
|
||||||
)
|
|
||||||
.build();
|
|
||||||
private static final String METHOD_SIG = Type.getInternalName(Method.class);
|
|
||||||
private static final String INVOKE_SIG = Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class), Type.getType(Object[].class));
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleClass(ClassNode node, ClassLoaderRemapper remapper) {
|
public void handleClass(ClassNode node, ClassLoaderRemapper remapper) {
|
||||||
redirect(node, remapper.getGeneratedHandler());
|
redirect(node, remapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void redirect(ClassNode classNode, String generatedOwner) {
|
private static void redirect(ClassNode classNode, ClassLoaderRemapper remapper) {
|
||||||
boolean defineClassFound = false;
|
|
||||||
for (MethodNode methodNode : classNode.methods) {
|
for (MethodNode methodNode : classNode.methods) {
|
||||||
ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
|
for (AbstractInsnNode insnNode : methodNode.instructions) {
|
||||||
while (iterator.hasNext()) {
|
|
||||||
AbstractInsnNode insnNode = iterator.next();
|
|
||||||
if (insnNode instanceof MethodInsnNode) {
|
if (insnNode instanceof MethodInsnNode) {
|
||||||
MethodInsnNode from = (MethodInsnNode) insnNode;
|
MethodInsnNode from = (MethodInsnNode) insnNode;
|
||||||
MethodInsnNode newNode = find(from, generatedOwner);
|
process(from, methodNode.instructions, remapper);
|
||||||
if (newNode != null) {
|
|
||||||
iterator.set(newNode);
|
|
||||||
}
|
|
||||||
} else if (insnNode.getOpcode() == Opcodes.INVOKEDYNAMIC) {
|
} else if (insnNode.getOpcode() == Opcodes.INVOKEDYNAMIC) {
|
||||||
InvokeDynamicInsnNode invokeDynamic = (InvokeDynamicInsnNode) insnNode;
|
InvokeDynamicInsnNode invokeDynamic = (InvokeDynamicInsnNode) insnNode;
|
||||||
Object[] bsmArgs = invokeDynamic.bsmArgs;
|
Object[] bsmArgs = invokeDynamic.bsmArgs;
|
||||||
|
@ -143,96 +92,185 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
if (bsmArg instanceof Handle) {
|
if (bsmArg instanceof Handle) {
|
||||||
Handle handle = (Handle) bsmArg;
|
Handle handle = (Handle) bsmArg;
|
||||||
if (toOpcode(handle.getTag()) != -1) {
|
if (toOpcode(handle.getTag()) != -1) {
|
||||||
MethodInsnNode node = find(handle, generatedOwner);
|
bsmArgs[i] = processHandle(handle, remapper);
|
||||||
if (node != null) {
|
|
||||||
bsmArgs[i] = new Handle(toHandle(node.getOpcode()), node.owner, node.name, node.desc, node.itf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (insnNode.getOpcode() == Opcodes.LDC) {
|
|
||||||
defineClassFound |= "defineClass".equals(((LdcInsnNode) insnNode).cst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (defineClassFound) {
|
|
||||||
for (MethodNode methodNode : classNode.methods) {
|
|
||||||
for (AbstractInsnNode insnNode : methodNode.instructions) {
|
|
||||||
if (insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
|
|
||||||
MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
|
|
||||||
if (methodInsnNode.owner.equals(METHOD_SIG) && methodInsnNode.name.equals("invoke") && methodInsnNode.desc.equals(INVOKE_SIG)) {
|
|
||||||
methodInsnNode.setOpcode(Opcodes.INVOKESTATIC);
|
|
||||||
methodInsnNode.owner = generatedOwner;
|
|
||||||
methodInsnNode.name = "redirectDefineClassInvoke";
|
|
||||||
methodInsnNode.desc = "(L" + METHOD_SIG + ";" + methodInsnNode.desc.substring(1);
|
|
||||||
ArclightMod.LOGGER.debug(MARKER, "Redirect candidate defineClass method invoke in {}/{} {}"
|
|
||||||
, classNode.name, methodNode.name, methodNode.desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodInsnNode find(Handle handle, String generatedOwner) {
|
private static Handle processHandle(Handle handle, ClassLoaderRemapper remapper) {
|
||||||
for (Map.Entry<MethodInsnNode, MethodInsnNode> entry : METHOD_REDIRECTS.entrySet()) {
|
String key = handle.getName() + handle.getDesc();
|
||||||
MethodInsnNode key = entry.getKey();
|
Collection<Product2<String, MethodInsnNode>> col = METHOD_REDIRECT.get(key);
|
||||||
if (
|
for (Product2<String, MethodInsnNode> methodRedirect : col) {
|
||||||
key.getOpcode() == toOpcode(handle.getTag()) &&
|
if (isSuperType(handle.getOwner(), methodRedirect._1)) {
|
||||||
Objects.equals(key.owner, handle.getOwner()) &&
|
MethodInsnNode node = methodRedirect._2;
|
||||||
Objects.equals(key.name, handle.getName()) &&
|
String owner = REPLACED_NAME.equals(node.owner) ? remapper.getGeneratedHandler() : node.owner;
|
||||||
Objects.equals(key.desc, handle.getDesc())) {
|
return new Handle(toHandle(node.getOpcode()), owner, node.name, node.desc, node.itf);
|
||||||
MethodInsnNode to = entry.getValue();
|
}
|
||||||
if (REPLACED_NAME.equals(to.owner)) {
|
}
|
||||||
MethodInsnNode clone = (MethodInsnNode) to.clone(ImmutableMap.of());
|
return handle;
|
||||||
clone.owner = generatedOwner;
|
}
|
||||||
return clone;
|
|
||||||
|
private static void process(MethodInsnNode node, InsnList insnList, ClassLoaderRemapper remapper) {
|
||||||
|
String key = node.name + node.desc;
|
||||||
|
Collection<Product2<String, MethodInsnNode>> modifyArgsCol = METHOD_MODIFY.get(key);
|
||||||
|
for (Product2<String, MethodInsnNode> modifyArgs : modifyArgsCol) {
|
||||||
|
if (isSuperType(node.owner, modifyArgs._1)) {
|
||||||
|
MethodInsnNode handlerNode;
|
||||||
|
if (REPLACED_NAME.equals(modifyArgs._2.owner)) {
|
||||||
|
handlerNode = (MethodInsnNode) modifyArgs._2.clone(ImmutableMap.of());
|
||||||
|
handlerNode.owner = remapper.getGeneratedHandler();
|
||||||
} else {
|
} else {
|
||||||
return to;
|
handlerNode = modifyArgs._2;
|
||||||
}
|
}
|
||||||
|
processModify(node, insnList, handlerNode);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
Collection<Product2<String, MethodInsnNode>> methodRedirectCol = METHOD_REDIRECT.get(key);
|
||||||
}
|
for (Product2<String, MethodInsnNode> methodRedirect : methodRedirectCol) {
|
||||||
|
if (isSuperType(node.owner, methodRedirect._1)) {
|
||||||
private static MethodInsnNode find(MethodInsnNode from, String generatedOwner) {
|
MethodInsnNode handlerNode;
|
||||||
for (Map.Entry<MethodInsnNode, MethodInsnNode> entry : METHOD_REDIRECTS.entrySet()) {
|
if (REPLACED_NAME.equals(methodRedirect._2.owner)) {
|
||||||
MethodInsnNode key = entry.getKey();
|
handlerNode = (MethodInsnNode) methodRedirect._2.clone(ImmutableMap.of());
|
||||||
if (
|
handlerNode.owner = remapper.getGeneratedHandler();
|
||||||
key.getOpcode() == from.getOpcode() &&
|
|
||||||
Objects.equals(key.owner, from.owner) &&
|
|
||||||
Objects.equals(key.name, from.name) &&
|
|
||||||
Objects.equals(key.desc, from.desc)) {
|
|
||||||
MethodInsnNode to = entry.getValue();
|
|
||||||
if (REPLACED_NAME.equals(to.owner)) {
|
|
||||||
MethodInsnNode clone = (MethodInsnNode) to.clone(ImmutableMap.of());
|
|
||||||
clone.owner = generatedOwner;
|
|
||||||
return clone;
|
|
||||||
} else {
|
} else {
|
||||||
return to;
|
handlerNode = methodRedirect._2;
|
||||||
|
}
|
||||||
|
processMethodRedirect(node, insnList, handlerNode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isSuperType(String sub, String sup) {
|
||||||
|
return sub.equals(sup) || GlobalClassRepo.inheritanceProvider().getAll(sub).contains(sup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processMethodRedirect(MethodInsnNode node, InsnList insnList, MethodInsnNode handlerNode) {
|
||||||
|
insnList.set(node, handlerNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processModify(MethodInsnNode node, InsnList insnList, MethodInsnNode handlerNode) {
|
||||||
|
InsnList list = new InsnList();
|
||||||
|
list.add(handlerNode);
|
||||||
|
Type methodType = Type.getMethodType(node.desc);
|
||||||
|
Type[] types = methodType.getArgumentTypes();
|
||||||
|
if (node.getOpcode() != Opcodes.INVOKESTATIC) {
|
||||||
|
types = ArrayUtil.prepend(types, Type.getObjectType(node.owner), Type[]::new);
|
||||||
|
}
|
||||||
|
if (types.length == 1) {
|
||||||
|
if (node.desc.startsWith("()")) {
|
||||||
|
String retDesc = methodType.getReturnType().getDescriptor();
|
||||||
|
if (handlerNode.desc.equals("(" + retDesc + ")" + retDesc)) { // handle(obj.method())
|
||||||
|
insnList.insert(node, handlerNode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String desc = types[0].getDescriptor();
|
||||||
|
if (handlerNode.desc.equals("(" + desc + ")" + desc)) { // object.call(handle(arg0))
|
||||||
|
insnList.insertBefore(node, handlerNode);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
for (int i = 0, argumentTypesLength = types.length; i < argumentTypesLength; i++) {
|
||||||
|
Type type = types[i];
|
||||||
|
if (i > 0) {
|
||||||
|
swap(list, types[i - 1]);
|
||||||
|
}
|
||||||
|
if (argumentTypesLength > 1 && i != argumentTypesLength - 1) {
|
||||||
|
list.add(new InsnNode(Opcodes.DUP));
|
||||||
|
}
|
||||||
|
list.add(loadInt(i));
|
||||||
|
list.add(new InsnNode(Opcodes.AALOAD));
|
||||||
|
cast(list, type);
|
||||||
|
}
|
||||||
|
insnList.insertBefore(node, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodInsnNode method(int opcode, Class<?> cl, String name, Class<?>... pTypes) {
|
private static void swap(InsnList list, Type top) {
|
||||||
|
if (top.getSize() == 1) {
|
||||||
|
list.add(new InsnNode(Opcodes.SWAP));
|
||||||
|
} else {
|
||||||
|
list.add(new InsnNode(Opcodes.DUP2_X1));
|
||||||
|
list.add(new InsnNode(Opcodes.POP2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cast(InsnList list, Type type) {
|
||||||
|
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||||
|
String internalName = type.getInternalName();
|
||||||
|
if (!"java/lang/Object".equals(internalName)) {
|
||||||
|
list.add(new TypeInsnNode(Opcodes.CHECKCAST, internalName));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String boxingType = Bytecode.getBoxingType(type);
|
||||||
|
String unboxingMethod = Bytecode.getUnboxingMethod(type);
|
||||||
|
list.add(new TypeInsnNode(Opcodes.CHECKCAST, boxingType));
|
||||||
|
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + type.getDescriptor(), false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void modify(Class<?> owner, String name, String handlerName, Class<?>... args) {
|
||||||
|
addRule(true, owner, name, handlerName, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void redirect(Class<?> owner, String name, String handlerName, Class<?>... args) {
|
||||||
|
addRule(false, owner, name, handlerName, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addRule(boolean modifyArgs, Class<?> owner, String name, String handlerName, Class<?>... args) {
|
||||||
|
Method original = methodOf(owner, name, args);
|
||||||
|
Class<?>[] handlerArgs;
|
||||||
|
if (!Modifier.isStatic(original.getModifiers())) {
|
||||||
|
handlerArgs = ArrayUtil.prepend(args, owner, Class[]::new);
|
||||||
|
} else {
|
||||||
|
handlerArgs = args;
|
||||||
|
}
|
||||||
|
Method handler = methodOf(ArclightReflectionHandler.class, "redirect" + capitalize(handlerName), handlerArgs);
|
||||||
|
METHOD_REDIRECT.put(name + Type.getMethodDescriptor(original), Product.of(Type.getInternalName(owner), methodNodeOf(handler)));
|
||||||
|
Product2<String, Class<?>[]> handleProd;
|
||||||
|
if (modifyArgs) {
|
||||||
|
Method modifyHandler;
|
||||||
|
try {
|
||||||
|
modifyHandler = methodOf(ArclightReflectionHandler.class, "handle" + capitalize(handlerName), handlerArgs);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
handlerArgs[0] = original.getReturnType();
|
||||||
|
modifyHandler = methodOf(ArclightReflectionHandler.class, "handle" + capitalize(handlerName), handlerArgs);
|
||||||
|
}
|
||||||
|
METHOD_MODIFY.put(name + Type.getMethodDescriptor(original), Product.of(Type.getInternalName(owner), methodNodeOf(modifyHandler)));
|
||||||
|
handleProd = Product.of("handle" + capitalize(handlerName), handlerArgs);
|
||||||
|
} else {
|
||||||
|
handleProd = Product.of(null, null);
|
||||||
|
}
|
||||||
|
METHOD_TO_HANDLER.put(original, Product.of("redirect" + capitalize(handlerName), handlerArgs, handleProd._1, handleProd._2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String capitalize(String name) {
|
||||||
|
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Method methodOf(Class<?> owner, String name, Class<?>... args) {
|
||||||
try {
|
try {
|
||||||
return method(opcode, cl.getMethod(name, pTypes));
|
return owner.getMethod(name, args);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
try {
|
try {
|
||||||
return method(opcode, cl.getDeclaredMethod(name, pTypes));
|
return owner.getDeclaredMethod(name, args);
|
||||||
} catch (NoSuchMethodException ex) {
|
} catch (NoSuchMethodException e2) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(e2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodInsnNode method(int opcode, Method method) {
|
private static MethodInsnNode methodNodeOf(Method method) {
|
||||||
String owner = Type.getInternalName(method.getDeclaringClass());
|
String owner = Type.getInternalName(method.getDeclaringClass());
|
||||||
String name = method.getName();
|
String name = method.getName();
|
||||||
String desc = Type.getMethodDescriptor(method);
|
String desc = Type.getMethodDescriptor(method);
|
||||||
return new MethodInsnNode(opcode, owner, name, desc);
|
return new MethodInsnNode(Opcodes.INVOKESTATIC, owner, name, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int toOpcode(int handleType) {
|
private static int toOpcode(int handleType) {
|
||||||
|
@ -260,4 +298,16 @@ public class ArclightRedirectAdapter implements PluginTransformer {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AbstractInsnNode loadInt(int i) {
|
||||||
|
if (i >= -1 && i < 6) {
|
||||||
|
return new InsnNode(Opcodes.ICONST_0 + i);
|
||||||
|
} else if (i >= -128 && i < 128) {
|
||||||
|
return new IntInsnNode(Opcodes.BIPUSH, i);
|
||||||
|
} else if (i >= -32768 && i < 32768) {
|
||||||
|
return new IntInsnNode(Opcodes.SIPUSH, i);
|
||||||
|
} else {
|
||||||
|
return new LdcInsnNode(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,10 @@ import net.md_5.specialsource.InheritanceMap;
|
||||||
import net.md_5.specialsource.JarMapping;
|
import net.md_5.specialsource.JarMapping;
|
||||||
import net.md_5.specialsource.provider.ClassLoaderProvider;
|
import net.md_5.specialsource.provider.ClassLoaderProvider;
|
||||||
import net.md_5.specialsource.provider.JointProvider;
|
import net.md_5.specialsource.provider.JointProvider;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -18,11 +20,22 @@ import java.util.List;
|
||||||
public class ArclightRemapper {
|
public class ArclightRemapper {
|
||||||
|
|
||||||
public static final ArclightRemapper INSTANCE;
|
public static final ArclightRemapper INSTANCE;
|
||||||
|
public static final File DUMP;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
|
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
|
||||||
try {
|
try {
|
||||||
INSTANCE = new ArclightRemapper();
|
INSTANCE = new ArclightRemapper();
|
||||||
|
String property = System.getProperty("arclight.remapper.dump");
|
||||||
|
if (property != null) {
|
||||||
|
DUMP = new File(property);
|
||||||
|
if (!DUMP.exists()) {
|
||||||
|
DUMP.mkdirs();
|
||||||
|
}
|
||||||
|
FileUtils.forceDelete(DUMP);
|
||||||
|
} else {
|
||||||
|
DUMP = null;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,11 @@ import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
import org.spongepowered.asm.service.MixinService;
|
import org.spongepowered.asm.service.MixinService;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -43,6 +45,7 @@ public class ClassLoaderRemapper extends LenientJarRemapper {
|
||||||
private final JarRemapper toBukkitRemapper;
|
private final JarRemapper toBukkitRemapper;
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
private final String generatedHandler;
|
private final String generatedHandler;
|
||||||
|
private final Class<?> generatedHandlerClass;
|
||||||
|
|
||||||
public ClassLoaderRemapper(JarMapping jarMapping, JarMapping toBukkitMapping, ClassLoader classLoader) {
|
public ClassLoaderRemapper(JarMapping jarMapping, JarMapping toBukkitMapping, ClassLoader classLoader) {
|
||||||
super(jarMapping);
|
super(jarMapping);
|
||||||
|
@ -52,7 +55,8 @@ public class ClassLoaderRemapper extends LenientJarRemapper {
|
||||||
this.jarMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
this.jarMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
||||||
this.toBukkitMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
this.toBukkitMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
||||||
this.toBukkitRemapper = new LenientJarRemapper(this.toBukkitMapping);
|
this.toBukkitRemapper = new LenientJarRemapper(this.toBukkitMapping);
|
||||||
this.generatedHandler = generateReflectionHandler();
|
this.generatedHandlerClass = generateReflectionHandler();
|
||||||
|
this.generatedHandler = Type.getInternalName(generatedHandlerClass);
|
||||||
GlobalClassRepo.INSTANCE.addRepo(new ClassLoaderRepo(this.classLoader));
|
GlobalClassRepo.INSTANCE.addRepo(new ClassLoaderRepo(this.classLoader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +80,10 @@ public class ClassLoaderRemapper extends LenientJarRemapper {
|
||||||
return generatedHandler;
|
return generatedHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<?> getGeneratedHandlerClass() {
|
||||||
|
return generatedHandlerClass;
|
||||||
|
}
|
||||||
|
|
||||||
// BiMap: srg -> bukkit
|
// BiMap: srg -> bukkit
|
||||||
private final Map<String, BiMap<Field, String>> cacheFields = new ConcurrentHashMap<>();
|
private final Map<String, BiMap<Field, String>> cacheFields = new ConcurrentHashMap<>();
|
||||||
private final Map<String, Map.Entry<Map<Method, String>, Map<WrappedMethod, Method>>> cacheMethods = new ConcurrentHashMap<>();
|
private final Map<String, Map.Entry<Map<Method, String>, Map<WrappedMethod, Method>>> cacheMethods = new ConcurrentHashMap<>();
|
||||||
|
@ -286,12 +294,12 @@ public class ClassLoaderRemapper extends LenientJarRemapper {
|
||||||
ClassWriter wr = new PluginClassWriter(ClassWriter.COMPUTE_FRAMES);
|
ClassWriter wr = new PluginClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||||
node.accept(wr);
|
node.accept(wr);
|
||||||
|
|
||||||
return wr.toByteArray();
|
return dump(wr.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final AtomicInteger COUNTER = new AtomicInteger();
|
private static final AtomicInteger COUNTER = new AtomicInteger();
|
||||||
|
|
||||||
private String generateReflectionHandler() {
|
private Class<?> generateReflectionHandler() {
|
||||||
try {
|
try {
|
||||||
ClassNode node = MixinService.getService().getBytecodeProvider().getClassNode(Type.getInternalName(ArclightReflectionHandler.class));
|
ClassNode node = MixinService.getService().getBytecodeProvider().getClassNode(Type.getInternalName(ArclightReflectionHandler.class));
|
||||||
Preconditions.checkNotNull(node, "node");
|
Preconditions.checkNotNull(node, "node");
|
||||||
|
@ -300,12 +308,13 @@ public class ClassLoaderRemapper extends LenientJarRemapper {
|
||||||
ClassVisitor visitor = new ClassRemapper(writer, new NameRemapper(name));
|
ClassVisitor visitor = new ClassRemapper(writer, new NameRemapper(name));
|
||||||
node.accept(visitor);
|
node.accept(visitor);
|
||||||
byte[] bytes = writer.toByteArray();
|
byte[] bytes = writer.toByteArray();
|
||||||
|
dump(bytes);
|
||||||
Class<?> cl = Unsafe.defineClass(name.replace('/', '.'), bytes, 0, bytes.length, getClass().getClassLoader(), getClass().getProtectionDomain());
|
Class<?> cl = Unsafe.defineClass(name.replace('/', '.'), bytes, 0, bytes.length, getClass().getClassLoader(), getClass().getProtectionDomain());
|
||||||
Unsafe.ensureClassInitialized(cl);
|
Unsafe.ensureClassInitialized(cl);
|
||||||
|
|
||||||
Field remapper = cl.getField("remapper");
|
Field remapper = cl.getField("remapper");
|
||||||
remapper.set(null, this);
|
remapper.set(null, this);
|
||||||
return name;
|
return cl;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -385,4 +394,23 @@ public class ClassLoaderRemapper extends LenientJarRemapper {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] dump(byte[] bytes) {
|
||||||
|
try {
|
||||||
|
if (ArclightRemapper.DUMP != null) {
|
||||||
|
String className = new ClassReader(bytes).getClassName() + ".class";
|
||||||
|
int index = className.lastIndexOf('/');
|
||||||
|
if (index != -1) {
|
||||||
|
File file = new File(ArclightRemapper.DUMP, className.substring(0, index));
|
||||||
|
file.mkdirs();
|
||||||
|
Files.write(file.toPath().resolve(className.substring(index + 1)), bytes);
|
||||||
|
} else {
|
||||||
|
Files.write(ArclightRemapper.DUMP.toPath().resolve(className), bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Failed to dump class " + new ClassReader(bytes).getClassName(), e);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@ package io.izzel.arclight.common.mod.util.remapper.generated;
|
||||||
|
|
||||||
import io.izzel.arclight.api.ArclightVersion;
|
import io.izzel.arclight.api.ArclightVersion;
|
||||||
import io.izzel.arclight.api.Unsafe;
|
import io.izzel.arclight.api.Unsafe;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderAdapter;
|
import io.izzel.arclight.common.mod.util.remapper.ArclightRedirectAdapter;
|
||||||
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
||||||
|
import io.izzel.arclight.common.util.ArrayUtil;
|
||||||
|
import io.izzel.tools.product.Product4;
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
@ -11,11 +13,13 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.CodeSource;
|
import java.security.CodeSource;
|
||||||
import java.security.Permissions;
|
import java.security.Permissions;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class ArclightReflectionHandler extends ClassLoader {
|
public class ArclightReflectionHandler extends ClassLoader {
|
||||||
|
@ -24,27 +28,9 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
|
|
||||||
public static ClassLoaderRemapper remapper;
|
public static ClassLoaderRemapper remapper;
|
||||||
|
|
||||||
// bukkit -> srg
|
// srg -> bukkit
|
||||||
public static Class<?> redirectForName(String cl) throws ClassNotFoundException {
|
public static String redirectFieldGetName(Field field) {
|
||||||
return redirectForName(cl, true, Unsafe.getCallerClass().getClassLoader());
|
return remapper.tryMapFieldToBukkit(field.getDeclaringClass(), field.getName(), field);
|
||||||
}
|
|
||||||
|
|
||||||
// bukkit -> srg
|
|
||||||
public static Class<?> redirectForName(String cl, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException {
|
|
||||||
if (!cl.startsWith(PREFIX)) {
|
|
||||||
return Class.forName(cl, initialize, classLoader);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
String replace = remapper.mapType(cl.replace('.', '/')).replace('/', '.');
|
|
||||||
return Class.forName(replace, initialize, classLoader);
|
|
||||||
} catch (ClassNotFoundException e) { // nested/inner class
|
|
||||||
int i = cl.lastIndexOf('.');
|
|
||||||
if (i > 0) {
|
|
||||||
String replace = cl.substring(0, i).replace('.', '/') + "$" + cl.substring(i + 1);
|
|
||||||
replace = remapper.mapType(replace).replace('/', '.').replace('$', '.');
|
|
||||||
return Class.forName(replace, initialize, classLoader);
|
|
||||||
} else throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// srg -> bukkit
|
// srg -> bukkit
|
||||||
|
@ -52,61 +38,20 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
return remapper.tryMapMethodToBukkit(method.getDeclaringClass(), method);
|
return remapper.tryMapMethodToBukkit(method.getDeclaringClass(), method);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
|
||||||
public static Method redirectGetMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) throws NoSuchMethodException {
|
|
||||||
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
|
|
||||||
if (method != null) {
|
|
||||||
return method;
|
|
||||||
} else {
|
|
||||||
return cl.getMethod(bukkitName, pTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bukkit -> srg
|
|
||||||
public static Method redirectGetDeclaredMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) throws NoSuchMethodException {
|
|
||||||
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
|
|
||||||
if (method != null) {
|
|
||||||
return method;
|
|
||||||
} else {
|
|
||||||
return cl.getDeclaredMethod(bukkitName, pTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// srg -> bukkit
|
|
||||||
public static String redirectFieldGetName(Field field) {
|
|
||||||
return remapper.tryMapFieldToBukkit(field.getDeclaringClass(), field.getName(), field);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bukkit -> srg
|
|
||||||
public static Field redirectGetField(Class<?> cl, String bukkitName) throws NoSuchFieldException {
|
|
||||||
String field = remapper.tryMapFieldToSrg(cl, bukkitName);
|
|
||||||
return cl.getField(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bukkit -> srg
|
|
||||||
public static Field redirectGetDeclaredField(Class<?> cl, String bukkitName) throws NoSuchFieldException {
|
|
||||||
String field = remapper.tryMapDecFieldToSrg(cl, bukkitName);
|
|
||||||
return cl.getDeclaredField(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
// srg -> bukkit
|
|
||||||
public static String redirectClassGetName(Class<?> cl) {
|
|
||||||
String internalName = Type.getInternalName(cl);
|
|
||||||
Type type = Type.getObjectType(remapper.toBukkitRemapper().mapType(internalName));
|
|
||||||
return type.getInternalName().replace('/', '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// srg -> bukkit
|
// srg -> bukkit
|
||||||
public static String redirectClassGetCanonicalName(Class<?> cl) {
|
public static String redirectClassGetCanonicalName(Class<?> cl) {
|
||||||
String canonicalName = cl.getCanonicalName();
|
|
||||||
if (canonicalName == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (cl.isArray()) {
|
if (cl.isArray()) {
|
||||||
String name = redirectClassGetCanonicalName(cl.getComponentType());
|
String name = redirectClassGetCanonicalName(cl.getComponentType());
|
||||||
if (name == null) return null;
|
if (name == null) return null;
|
||||||
return name + "[]";
|
return name + "[]";
|
||||||
}
|
}
|
||||||
|
if (cl.isLocalClass() || cl.isAnonymousClass()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String canonicalName = cl.getCanonicalName();
|
||||||
|
if (canonicalName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
Class<?> enclosingClass = cl.getEnclosingClass();
|
Class<?> enclosingClass = cl.getEnclosingClass();
|
||||||
if (enclosingClass == null) {
|
if (enclosingClass == null) {
|
||||||
return redirectClassGetName(cl);
|
return redirectClassGetName(cl);
|
||||||
|
@ -138,8 +83,19 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// srg -> bukkit
|
// srg -> bukkit
|
||||||
public static String redirectPackageGetName(Package pkg) {
|
public static String handleClassGetName(String cl) {
|
||||||
String name = pkg.getName();
|
return remapper.toBukkitRemapper().mapType(cl.replace('.', '/')).replace('/', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// srg -> bukkit
|
||||||
|
public static String redirectClassGetName(Class<?> cl) {
|
||||||
|
String internalName = Type.getInternalName(cl);
|
||||||
|
Type type = Type.getObjectType(remapper.toBukkitRemapper().mapType(internalName));
|
||||||
|
return type.getInternalName().replace('/', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// srg -> bukkit
|
||||||
|
public static String handlePackageGetName(String name) {
|
||||||
if (name.startsWith(PREFIX)) {
|
if (name.startsWith(PREFIX)) {
|
||||||
return PREFIX + "server." + ArclightVersion.current().packageName();
|
return PREFIX + "server." + ArclightVersion.current().packageName();
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,6 +103,111 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// srg -> bukkit
|
||||||
|
public static String redirectPackageGetName(Package pkg) {
|
||||||
|
return handlePackageGetName(pkg.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static String handleClassForName(String cl) {
|
||||||
|
String mapped = remapper.map(cl.replace('.', '/')).replace('/', '.');
|
||||||
|
if (mapped.equals(cl) && cl.startsWith(PREFIX)) {
|
||||||
|
int i = cl.lastIndexOf('.');
|
||||||
|
if (i > 0) {
|
||||||
|
String nest = cl.substring(0, i).replace('.', '/') + "$" + cl.substring(i + 1);
|
||||||
|
String replace = remapper.map(nest).replace('/', '.');
|
||||||
|
return replace.equals(nest) ? mapped : replace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Class<?> redirectClassForName(String cl) throws ClassNotFoundException {
|
||||||
|
return redirectClassForName(cl, true, Unsafe.getCallerClass().getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Object[] handleClassForName(String cl, boolean initialize, ClassLoader classLoader) {
|
||||||
|
return new Object[]{handleClassForName(cl), initialize, classLoader};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Class<?> redirectClassForName(String cl, boolean initialize, ClassLoader classLoader) throws ClassNotFoundException {
|
||||||
|
if (!cl.startsWith(PREFIX)) {
|
||||||
|
return Class.forName(cl, initialize, classLoader);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String replace = remapper.mapType(cl.replace('.', '/')).replace('/', '.');
|
||||||
|
return Class.forName(replace, initialize, classLoader);
|
||||||
|
} catch (ClassNotFoundException e) { // nested/inner class
|
||||||
|
int i = cl.lastIndexOf('.');
|
||||||
|
if (i > 0) {
|
||||||
|
String replace = cl.substring(0, i).replace('.', '/') + "$" + cl.substring(i + 1);
|
||||||
|
replace = remapper.mapType(replace).replace('/', '.').replace('$', '.');
|
||||||
|
return Class.forName(replace, initialize, classLoader);
|
||||||
|
} else throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Object[] handleClassGetField(Class<?> cl, String bukkitName) {
|
||||||
|
return new Object[]{cl, remapper.tryMapFieldToSrg(cl, bukkitName)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Field redirectClassGetField(Class<?> cl, String bukkitName) throws NoSuchFieldException {
|
||||||
|
String field = remapper.tryMapFieldToSrg(cl, bukkitName);
|
||||||
|
return cl.getField(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Object[] handleClassGetDeclaredField(Class<?> cl, String bukkitName) {
|
||||||
|
return handleClassGetField(cl, bukkitName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Field redirectClassGetDeclaredField(Class<?> cl, String bukkitName) throws NoSuchFieldException {
|
||||||
|
String field = remapper.tryMapDecFieldToSrg(cl, bukkitName);
|
||||||
|
return cl.getDeclaredField(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Object[] handleClassGetMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) {
|
||||||
|
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
|
||||||
|
return new Object[]{cl, method == null ? bukkitName : method.getName(), pTypes};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Method redirectClassGetMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) throws NoSuchMethodException {
|
||||||
|
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
|
||||||
|
if (method != null) {
|
||||||
|
return method;
|
||||||
|
} else {
|
||||||
|
return cl.getMethod(bukkitName, pTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Object[] handleClassGetDeclaredMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) {
|
||||||
|
return handleClassGetMethod(cl, bukkitName, pTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Method redirectClassGetDeclaredMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) throws NoSuchMethodException {
|
||||||
|
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
|
||||||
|
if (method != null) {
|
||||||
|
return method;
|
||||||
|
} else {
|
||||||
|
return cl.getDeclaredMethod(bukkitName, pTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static Object[] handleFromDescStr(String desc, ClassLoader classLoader) {
|
||||||
|
return new Object[]{remapper.mapMethodDesc(desc), classLoader};
|
||||||
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodType redirectFromDescStr(String desc, ClassLoader classLoader) {
|
public static MethodType redirectFromDescStr(String desc, ClassLoader classLoader) {
|
||||||
String methodDesc = remapper.mapMethodDesc(desc);
|
String methodDesc = remapper.mapMethodDesc(desc);
|
||||||
|
@ -154,7 +215,13 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindStatic(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException {
|
public static Object[] handleLookupFindStatic(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) {
|
||||||
|
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
||||||
|
return new Object[]{lookup, cl, method == null ? name : method.getName(), methodType};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static MethodHandle redirectLookupFindStatic(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException {
|
||||||
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
return lookup.findStatic(cl, method.getName(), methodType);
|
return lookup.findStatic(cl, method.getName(), methodType);
|
||||||
|
@ -164,14 +231,12 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindVirtual(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException {
|
public static Object[] handleLookupFindVirtual(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) {
|
||||||
if (ClassLoaderAdapter.isDefineClassMethod(cl, name, methodType)) {
|
return handleLookupFindStatic(lookup, cl, name, methodType);
|
||||||
Class<?>[] pTypes = methodType.parameterArray();
|
}
|
||||||
Class<?>[] classes = new Class<?>[pTypes.length + 1];
|
|
||||||
classes[0] = ClassLoader.class;
|
// bukkit -> srg
|
||||||
System.arraycopy(pTypes, 0, classes, 1, pTypes.length);
|
public static MethodHandle redirectLookupFindVirtual(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException {
|
||||||
return lookup.findStatic(ArclightReflectionHandler.class, name, MethodType.methodType(Class.class, classes));
|
|
||||||
}
|
|
||||||
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
return lookup.findVirtual(cl, method.getName(), methodType);
|
return lookup.findVirtual(cl, method.getName(), methodType);
|
||||||
|
@ -181,7 +246,13 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindSpecial(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType, Class<?> spec) throws NoSuchMethodException, IllegalAccessException {
|
public static Object[] handleLookupFindSpecial(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType, Class<?> spec) {
|
||||||
|
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
||||||
|
return new Object[]{lookup, cl, method == null ? name : method.getName(), methodType, spec};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static MethodHandle redirectLookupFindSpecial(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType, Class<?> spec) throws NoSuchMethodException, IllegalAccessException {
|
||||||
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
return lookup.findSpecial(cl, method.getName(), methodType, spec);
|
return lookup.findSpecial(cl, method.getName(), methodType, spec);
|
||||||
|
@ -191,49 +262,102 @@ public class ArclightReflectionHandler extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindGetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
public static Object[] handleLookupFindGetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) {
|
||||||
|
String field = remapper.tryMapFieldToSrg(cl, name);
|
||||||
|
return new Object[]{lookup, cl, field, type};
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static MethodHandle redirectLookupFindGetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
||||||
String field = remapper.tryMapFieldToSrg(cl, name);
|
String field = remapper.tryMapFieldToSrg(cl, name);
|
||||||
return lookup.findGetter(cl, field, type);
|
return lookup.findGetter(cl, field, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindSetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
public static Object[] handleLookupFindSetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) {
|
||||||
|
return handleLookupFindGetter(lookup, cl, name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static MethodHandle redirectLookupFindSetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
||||||
String field = remapper.tryMapFieldToSrg(cl, name);
|
String field = remapper.tryMapFieldToSrg(cl, name);
|
||||||
return lookup.findSetter(cl, field, type);
|
return lookup.findSetter(cl, field, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindStaticGetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
public static Object[] handleLookupFindStaticGetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) {
|
||||||
|
return handleLookupFindGetter(lookup, cl, name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static MethodHandle redirectLookupFindStaticGetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
||||||
String field = remapper.tryMapFieldToSrg(cl, name);
|
String field = remapper.tryMapFieldToSrg(cl, name);
|
||||||
return lookup.findStaticGetter(cl, field, type);
|
return lookup.findStaticGetter(cl, field, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static MethodHandle redirectFindStaticSetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
public static Object[] handleLookupFindStaticSetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) {
|
||||||
|
return handleLookupFindGetter(lookup, cl, name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bukkit -> srg
|
||||||
|
public static MethodHandle redirectLookupFindStaticSetter(MethodHandles.Lookup lookup, Class<?> cl, String name, Class<?> type) throws IllegalAccessException, NoSuchFieldException {
|
||||||
String field = remapper.tryMapFieldToSrg(cl, name);
|
String field = remapper.tryMapFieldToSrg(cl, name);
|
||||||
return lookup.findStaticSetter(cl, field, type);
|
return lookup.findStaticSetter(cl, field, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object[] handleClassLoaderLoadClass(ClassLoader loader, String binaryName) {
|
||||||
|
return new Object[]{loader, binaryName.startsWith(PREFIX) ?
|
||||||
|
remapper.mapType(binaryName.replace('.', '/')).replace('/', '.')
|
||||||
|
: binaryName};
|
||||||
|
}
|
||||||
|
|
||||||
// bukkit -> srg
|
// bukkit -> srg
|
||||||
public static Class<?> redirectClassLoaderLoadClass(ClassLoader loader, String canonicalName) throws ClassNotFoundException {
|
public static Class<?> redirectClassLoaderLoadClass(ClassLoader loader, String binaryName) throws ClassNotFoundException {
|
||||||
if (!canonicalName.startsWith(PREFIX)) {
|
if (!binaryName.startsWith(PREFIX)) {
|
||||||
return loader.loadClass(canonicalName);
|
return loader.loadClass(binaryName);
|
||||||
}
|
}
|
||||||
String replace = remapper.mapType(canonicalName.replace('.', '/')).replace('/', '.');
|
String replace = remapper.mapType(binaryName.replace('.', '/')).replace('/', '.');
|
||||||
return loader.loadClass(replace);
|
return loader.loadClass(replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object redirectDefineClassInvoke(Method method, Object src, Object[] param) throws Exception {
|
public static Object[] handleMethodInvoke(Method method, Object src, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
||||||
if (method.getDeclaringClass() == ArclightReflectionHandler.class && method.getName().equals("defineClass")) {
|
Product4<String, Class<?>[], String, Class<?>[]> invokeRule = ArclightRedirectAdapter.getInvokeRule(method);
|
||||||
Class<?>[] classes = new Class<?>[method.getParameterCount() + 1];
|
if (invokeRule != null) {
|
||||||
classes[0] = ClassLoader.class;
|
if (invokeRule._3 != null && method.getParameterCount() > 0) {
|
||||||
System.arraycopy(method.getParameterTypes(), 0, classes, 1, method.getParameterCount());
|
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._3, invokeRule._4);
|
||||||
method = ArclightReflectionHandler.class.getMethod(method.getName(), classes);
|
if (handleMethod.getReturnType().isArray()) {
|
||||||
Object[] args = new Object[param.length + 1];
|
return (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||||
args[0] = src;
|
} else {
|
||||||
System.arraycopy(param, 0, args, 1, param.length);
|
return new Object[]{method, src, handleMethod.invoke(null, param)};
|
||||||
return method.invoke(null, args);
|
}
|
||||||
} else return method.invoke(src, param);
|
} else {
|
||||||
|
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
||||||
|
return new Object[]{handleMethod, null, ArrayUtil.prepend(param, src)};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Object[]{method, src, param};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object redirectMethodInvoke(Method method, Object src, Object[] param) throws Throwable {
|
||||||
|
Product4<String, Class<?>[], String, Class<?>[]> invokeRule = ArclightRedirectAdapter.getInvokeRule(method);
|
||||||
|
if (invokeRule != null) {
|
||||||
|
if (invokeRule._3 != null && method.getParameterCount() > 0) {
|
||||||
|
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._3, invokeRule._4);
|
||||||
|
if (handleMethod.getReturnType().isArray()) {
|
||||||
|
Object[] result = (Object[]) handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||||
|
return method.invoke(result[0], Arrays.copyOfRange(result, 1, result.length));
|
||||||
|
} else {
|
||||||
|
return method.invoke(src, handleMethod.invoke(null, param));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Method handleMethod = remapper.getGeneratedHandlerClass().getMethod(invokeRule._1, invokeRule._2);
|
||||||
|
return handleMethod.invoke(null, ArrayUtil.prepend(param, src));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return method.invoke(src, param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> defineClass(ClassLoader loader, byte[] b, int off, int len) {
|
public static Class<?> defineClass(ClassLoader loader, byte[] b, int off, int len) {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package io.izzel.arclight.common.util;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
public class ArrayUtil {
|
||||||
|
|
||||||
|
public static Object[] prepend(Object[] array, Object obj) {
|
||||||
|
Object[] newArray = new Object[array.length + 1];
|
||||||
|
newArray[0] = obj;
|
||||||
|
System.arraycopy(array, 0, newArray, 1, array.length);
|
||||||
|
return newArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T[] prepend(T[] array, T obj, IntFunction<T[]> factory) {
|
||||||
|
T[] newArray = factory.apply(array.length + 1);
|
||||||
|
newArray[0] = obj;
|
||||||
|
System.arraycopy(array, 0, newArray, 1, array.length);
|
||||||
|
return newArray;
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,7 @@ repositories {
|
||||||
maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
||||||
maven { url = 'https://files.minecraftforge.net/maven/' }
|
maven { url = 'https://files.minecraftforge.net/maven/' }
|
||||||
maven { url = 'https://jitpack.io/' }
|
maven { url = 'https://jitpack.io/' }
|
||||||
|
maven { url = 'https://maven.izzel.io/releases' }
|
||||||
}
|
}
|
||||||
|
|
||||||
def embedLibs = [/*'org.spongepowered:mixin:0.8.1',*/ 'org.ow2.asm:asm-util:9.0',
|
def embedLibs = [/*'org.spongepowered:mixin:0.8.1',*/ 'org.ow2.asm:asm-util:9.0',
|
||||||
|
@ -81,6 +82,7 @@ dependencies {
|
||||||
embed 'net.md-5:bungeecord-chat:1.16-R0.4@jar'
|
embed 'net.md-5:bungeecord-chat:1.16-R0.4@jar'
|
||||||
embed "org.spigotmc:spigot-api:$minecraftVersion-R0.1-SNAPSHOT@jar"
|
embed "org.spigotmc:spigot-api:$minecraftVersion-R0.1-SNAPSHOT@jar"
|
||||||
embed 'com.github.ArclightTeam:mixin-tools:1.0.0@jar'
|
embed 'com.github.ArclightTeam:mixin-tools:1.0.0@jar'
|
||||||
|
embed 'io.izzel:tools:1.0.+'
|
||||||
annotationProcessor 'org.spongepowered:mixin:0.8.2:processor'
|
annotationProcessor 'org.spongepowered:mixin:0.8.2:processor'
|
||||||
annotationProcessor 'com.github.ArclightTeam:mixin-tools:1.0.0'
|
annotationProcessor 'com.github.ArclightTeam:mixin-tools:1.0.0'
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user