Remapper does not need a plugin now.
This commit is contained in:
parent
ac871c63d3
commit
9d1be58b04
@ -6,7 +6,6 @@ import io.izzel.arclight.api.EnumHelper;
|
||||
import io.izzel.arclight.api.Unsafe;
|
||||
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
|
||||
import io.izzel.arclight.common.mod.util.log.ArclightLazyLogManager;
|
||||
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
|
||||
import io.izzel.arclight.common.util.EnumTypeFactory;
|
||||
import io.izzel.arclight.i18n.ArclightConfig;
|
||||
import io.izzel.arclight.i18n.ArclightLocale;
|
||||
@ -14,7 +13,6 @@ import net.minecraftforge.server.ServerMain;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
@ -38,8 +36,6 @@ public abstract class ArclightMain {
|
||||
}
|
||||
try {
|
||||
printLogo();
|
||||
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
|
||||
Objects.requireNonNull(ArclightRemapper.INSTANCE);
|
||||
this.beforeStart();
|
||||
this.dirtyHacks();
|
||||
ServerMain.main(args);
|
||||
|
||||
@ -4,7 +4,7 @@ import com.google.common.io.ByteStreams;
|
||||
import io.izzel.arclight.common.asm.SwitchTableFixer;
|
||||
import io.izzel.arclight.common.bridge.bukkit.JavaPluginLoaderBridge;
|
||||
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
|
||||
import io.izzel.arclight.common.mod.util.remapper.PluginRemapper;
|
||||
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
@ -36,7 +36,7 @@ public class PluginClassLoaderMixin extends URLClassLoader {
|
||||
@Shadow @Final private URL url;
|
||||
// @formatter:on
|
||||
|
||||
private PluginRemapper remapper;
|
||||
private ClassLoaderRemapper remapper;
|
||||
|
||||
public PluginClassLoaderMixin(URL[] urls) {
|
||||
super(urls);
|
||||
@ -74,7 +74,7 @@ public class PluginClassLoaderMixin extends URLClassLoader {
|
||||
classBytes = SwitchTableFixer.INSTANCE.processClass(classBytes);
|
||||
classBytes = Bukkit.getUnsafe().processClass(description, path, classBytes);
|
||||
if (remapper == null) {
|
||||
remapper = ArclightRemapper.INSTANCE.createPluginRemapper(this.loader, this);
|
||||
remapper = ArclightRemapper.INSTANCE.createClassLoaderRemapper(this);
|
||||
}
|
||||
classBytes = remapper.remapClass(classBytes);
|
||||
|
||||
|
||||
@ -16,14 +16,20 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ArclightInterfaceInvokerGen {
|
||||
public class ArclightInterfaceInvokerGen implements PluginTransformer {
|
||||
|
||||
public static final ArclightInterfaceInvokerGen INSTANCE = new ArclightInterfaceInvokerGen();
|
||||
private static final String PREFIX = "net/minecraft/";
|
||||
|
||||
public static void generate(ClassNode classNode, ClassRepo classRepo, PluginRemapper remapper, InheritanceProvider inheritanceProvider) {
|
||||
@Override
|
||||
public void handleClass(ClassNode node, ClassLoaderRemapper remapper) {
|
||||
generate(node, remapper, GlobalClassRepo.inheritanceProvider());
|
||||
}
|
||||
|
||||
private static void generate(ClassNode classNode, ClassLoaderRemapper remapper, InheritanceProvider inheritanceProvider) {
|
||||
if (shouldGenerate(classNode.name, inheritanceProvider)) {
|
||||
HashSet<Map.Entry<String, String>> set = new HashSet<>();
|
||||
interfaceMethods(classNode.name, set, classRepo);
|
||||
interfaceMethods(classNode.name, set, GlobalClassRepo.INSTANCE);
|
||||
for (Map.Entry<String, String> entry : set) {
|
||||
String name = entry.getKey();
|
||||
String desc = entry.getValue();
|
||||
@ -47,7 +53,7 @@ public class ArclightInterfaceInvokerGen {
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodNode generateSynthetic(String name, String desc, MethodInsnNode node, PluginRemapper remapper) {
|
||||
private static MethodNode generateSynthetic(String name, String desc, MethodInsnNode node, ClassLoaderRemapper remapper) {
|
||||
name = remapper.mapType(name);
|
||||
MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, name, desc, null, null);
|
||||
methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
|
||||
|
||||
@ -17,10 +17,11 @@ import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ArclightRedirectAdapter {
|
||||
public class ArclightRedirectAdapter implements PluginTransformer {
|
||||
|
||||
private static String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
|
||||
private static Map<MethodInsnNode, MethodInsnNode> methodRedirects = ImmutableMap
|
||||
public static final ArclightRedirectAdapter INSTANCE = new ArclightRedirectAdapter();
|
||||
private static final String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
|
||||
private static final Map<MethodInsnNode, MethodInsnNode> METHOD_REDIRECTS = ImmutableMap
|
||||
.<MethodInsnNode, MethodInsnNode>builder()
|
||||
.put(
|
||||
method(Opcodes.INVOKEVIRTUAL, Field.class, "getName"),
|
||||
@ -104,14 +105,19 @@ public class ArclightRedirectAdapter {
|
||||
)
|
||||
.build();
|
||||
|
||||
public static void redirect(ClassNode classNode, String generatedOwner) {
|
||||
@Override
|
||||
public void handleClass(ClassNode node, ClassLoaderRemapper remapper) {
|
||||
redirect(node, remapper.getGeneratedHandler());
|
||||
}
|
||||
|
||||
private static void redirect(ClassNode classNode, String generatedOwner) {
|
||||
for (MethodNode methodNode : classNode.methods) {
|
||||
ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode insnNode = iterator.next();
|
||||
if (insnNode instanceof MethodInsnNode) {
|
||||
MethodInsnNode from = (MethodInsnNode) insnNode;
|
||||
for (Map.Entry<MethodInsnNode, MethodInsnNode> entry : methodRedirects.entrySet()) {
|
||||
for (Map.Entry<MethodInsnNode, MethodInsnNode> entry : METHOD_REDIRECTS.entrySet()) {
|
||||
MethodInsnNode key = entry.getKey();
|
||||
if (
|
||||
key.getOpcode() == from.getOpcode() &&
|
||||
@ -151,5 +157,4 @@ public class ArclightRedirectAdapter {
|
||||
String desc = Type.getMethodDescriptor(method);
|
||||
return new MethodInsnNode(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,21 +3,23 @@ package io.izzel.arclight.common.mod.util.remapper;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import io.izzel.arclight.api.Unsafe;
|
||||
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
|
||||
import net.md_5.specialsource.InheritanceMap;
|
||||
import net.md_5.specialsource.JarMapping;
|
||||
import net.md_5.specialsource.provider.ClassLoaderProvider;
|
||||
import net.md_5.specialsource.provider.JointProvider;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ArclightRemapper {
|
||||
|
||||
public static final ArclightRemapper INSTANCE;
|
||||
|
||||
static {
|
||||
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
|
||||
try {
|
||||
INSTANCE = new ArclightRemapper();
|
||||
} catch (Exception e) {
|
||||
@ -28,6 +30,7 @@ public class ArclightRemapper {
|
||||
private final JarMapping toNmsMapping;
|
||||
private final JarMapping toBukkitMapping;
|
||||
public final InheritanceMap inheritanceMap;
|
||||
private final List<PluginTransformer> transformerList = new ArrayList<>();
|
||||
|
||||
public ArclightRemapper() throws Exception {
|
||||
this.toNmsMapping = new JarMapping();
|
||||
@ -50,10 +53,16 @@ public class ArclightRemapper {
|
||||
inheritanceProvider.add(new ClassLoaderProvider(ClassLoader.getSystemClassLoader()));
|
||||
this.toNmsMapping.setFallbackInheritanceProvider(inheritanceProvider);
|
||||
this.toBukkitMapping.setFallbackInheritanceProvider(inheritanceProvider);
|
||||
this.transformerList.add(ArclightInterfaceInvokerGen.INSTANCE);
|
||||
this.transformerList.add(ArclightRedirectAdapter.INSTANCE);
|
||||
}
|
||||
|
||||
public PluginRemapper createPluginRemapper(JavaPluginLoader loader, URLClassLoader plugin) {
|
||||
return new PluginRemapper(copyOf(toNmsMapping), copyOf(toBukkitMapping), loader, plugin);
|
||||
public ClassLoaderRemapper createClassLoaderRemapper(ClassLoader classLoader) {
|
||||
return new ClassLoaderRemapper(copyOf(toNmsMapping), copyOf(toBukkitMapping), classLoader);
|
||||
}
|
||||
|
||||
public List<PluginTransformer> getTransformerList() {
|
||||
return transformerList;
|
||||
}
|
||||
|
||||
private static long pkgOffset, clOffset, mdOffset, fdOffset, mapOffset;
|
||||
|
||||
@ -4,15 +4,14 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
|
||||
import io.izzel.arclight.api.Unsafe;
|
||||
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
|
||||
import net.md_5.specialsource.JarMapping;
|
||||
import net.md_5.specialsource.JarRemapper;
|
||||
import net.md_5.specialsource.RemappingClassAdapter;
|
||||
import net.md_5.specialsource.repo.ClassRepo;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
@ -27,7 +26,6 @@ import org.spongepowered.asm.service.MixinService;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@ -36,33 +34,30 @@ import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class PluginRemapper extends JarRemapper {
|
||||
public class ClassLoaderRemapper extends JarRemapper {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("Arclight");
|
||||
private static final String PREFIX = "net/minecraft/";
|
||||
|
||||
private final PluginInheritanceProvider inheritanceProvider;
|
||||
private final ClassRepo classRepo;
|
||||
private final JarMapping toBukkitMapping;
|
||||
private final JarRemapper toBukkitRemapper;
|
||||
private final URLClassLoader plugin;
|
||||
private final ClassLoader classLoader;
|
||||
private final String generatedHandler;
|
||||
|
||||
public PluginRemapper(JarMapping jarMapping, JarMapping toBukkitMapping, JavaPluginLoader loader, URLClassLoader plugin) {
|
||||
public ClassLoaderRemapper(JarMapping jarMapping, JarMapping toBukkitMapping, ClassLoader classLoader) {
|
||||
super(jarMapping);
|
||||
this.toBukkitMapping = toBukkitMapping;
|
||||
this.plugin = plugin;
|
||||
this.classRepo = SharedClassRepo.get(loader, plugin);
|
||||
this.inheritanceProvider = new PluginInheritanceProvider(this.classRepo);
|
||||
this.classLoader = classLoader;
|
||||
this.jarMapping.setInheritanceMap(ArclightRemapper.INSTANCE.inheritanceMap);
|
||||
this.jarMapping.setFallbackInheritanceProvider(this.inheritanceProvider);
|
||||
this.toBukkitMapping.setFallbackInheritanceProvider(this.inheritanceProvider);
|
||||
this.jarMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
||||
this.toBukkitMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
|
||||
this.toBukkitRemapper = new JarRemapper(this.toBukkitMapping);
|
||||
this.generatedHandler = generateReflectionHandler();
|
||||
GlobalClassRepo.INSTANCE.addRepo(new ClassLoaderRepo(this.classLoader));
|
||||
}
|
||||
|
||||
public URLClassLoader getPluginClassLoader() {
|
||||
return plugin;
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public JarMapping toBukkitMapping() {
|
||||
@ -77,8 +72,8 @@ public class PluginRemapper extends JarRemapper {
|
||||
return toBukkitRemapper;
|
||||
}
|
||||
|
||||
public ClassRepo getClassRepo() {
|
||||
return classRepo;
|
||||
public String getGeneratedHandler() {
|
||||
return generatedHandler;
|
||||
}
|
||||
|
||||
// BiMap: srg -> bukkit
|
||||
@ -204,7 +199,7 @@ public class PluginRemapper extends JarRemapper {
|
||||
private boolean shouldRemap(String internalName) {
|
||||
Boolean b = cacheRemap.get(internalName);
|
||||
if (b != null) return b;
|
||||
for (String s : inheritanceProvider.getAll(internalName)) {
|
||||
for (String s : GlobalClassRepo.inheritanceProvider().getAll(internalName)) {
|
||||
if (s.startsWith(PREFIX)) {
|
||||
cacheRemap.put(internalName, true);
|
||||
return true;
|
||||
@ -230,7 +225,7 @@ public class PluginRemapper extends JarRemapper {
|
||||
if (ArclightRemapper.INSTANCE.inheritanceMap.hasParents(owner)) {
|
||||
parents = ArclightRemapper.INSTANCE.inheritanceMap.getParents(owner);
|
||||
} else {
|
||||
parents = this.inheritanceProvider.getParents(owner);
|
||||
parents = GlobalClassRepo.inheritanceProvider().getParents(owner);
|
||||
ArclightRemapper.INSTANCE.inheritanceMap.setParents(owner, parents);
|
||||
}
|
||||
|
||||
@ -249,7 +244,7 @@ public class PluginRemapper extends JarRemapper {
|
||||
}
|
||||
|
||||
public byte[] remapClass(byte[] arr) {
|
||||
return remapClassFile(arr, classRepo);
|
||||
return remapClassFile(arr, GlobalClassRepo.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -262,8 +257,9 @@ public class PluginRemapper extends JarRemapper {
|
||||
RemappingClassAdapter mapper = new RemappingClassAdapter(node, this, repo);
|
||||
reader.accept(mapper, ClassReader.SKIP_FRAMES);
|
||||
|
||||
ArclightRedirectAdapter.redirect(node, generatedHandler);
|
||||
ArclightInterfaceInvokerGen.generate(node, this.classRepo, this, this.inheritanceProvider);
|
||||
for (PluginTransformer transformer : ArclightRemapper.INSTANCE.getTransformerList()) {
|
||||
transformer.handleClass(node, this);
|
||||
}
|
||||
|
||||
// 有的插件的编译器奇奇怪怪的,所以在这里要重新计算 frame
|
||||
ClassWriter wr = new PluginClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
@ -272,14 +268,14 @@ public class PluginRemapper extends JarRemapper {
|
||||
return wr.toByteArray();
|
||||
}
|
||||
|
||||
private static AtomicInteger atomicInteger = new AtomicInteger();
|
||||
private static final AtomicInteger COUNTER = new AtomicInteger();
|
||||
|
||||
private String generateReflectionHandler() {
|
||||
try {
|
||||
ClassNode node = MixinService.getService().getBytecodeProvider().getClassNode(Type.getInternalName(ArclightReflectionHandler.class));
|
||||
Preconditions.checkNotNull(node, "node");
|
||||
ClassWriter writer = new ClassWriter(0);
|
||||
String name = Type.getInternalName(ArclightReflectionHandler.class) + "_" + atomicInteger.getAndIncrement();
|
||||
String name = Type.getInternalName(ArclightReflectionHandler.class) + "_" + COUNTER.getAndIncrement();
|
||||
ClassVisitor visitor = new ClassRemapper(writer, new NameRemapper(name));
|
||||
node.accept(visitor);
|
||||
byte[] bytes = writer.toByteArray();
|
||||
@ -296,7 +292,7 @@ public class PluginRemapper extends JarRemapper {
|
||||
|
||||
private static class NameRemapper extends Remapper {
|
||||
|
||||
private static String origin = Type.getInternalName(ArclightReflectionHandler.class);
|
||||
private static final String ORIGIN = Type.getInternalName(ArclightReflectionHandler.class);
|
||||
|
||||
private final String internal;
|
||||
|
||||
@ -306,14 +302,14 @@ public class PluginRemapper extends JarRemapper {
|
||||
|
||||
@Override
|
||||
public String mapType(String internalName) {
|
||||
if (internalName.equals(origin)) {
|
||||
if (internalName.equals(ORIGIN)) {
|
||||
return internal;
|
||||
}
|
||||
return super.mapType(internalName);
|
||||
}
|
||||
}
|
||||
|
||||
private class PluginClassWriter extends ClassWriter {
|
||||
private static class PluginClassWriter extends ClassWriter {
|
||||
|
||||
public PluginClassWriter(int flags) {
|
||||
super(flags);
|
||||
@ -321,11 +317,11 @@ public class PluginRemapper extends JarRemapper {
|
||||
|
||||
@Override
|
||||
protected String getCommonSuperClass(String type1, String type2) {
|
||||
Collection<String> parents = inheritanceProvider.getAll(type2);
|
||||
Collection<String> parents = GlobalClassRepo.inheritanceProvider().getAll(type2);
|
||||
if (parents.contains(type1)) {
|
||||
return type1;
|
||||
}
|
||||
if (inheritanceProvider.getAll(type1).contains(type2)) {
|
||||
if (GlobalClassRepo.inheritanceProvider().getAll(type1).contains(type2)) {
|
||||
return type2;
|
||||
}
|
||||
do {
|
||||
@ -335,7 +331,7 @@ public class PluginRemapper extends JarRemapper {
|
||||
}
|
||||
|
||||
private String getSuper(final String typeName) {
|
||||
ClassNode node = classRepo.findClass(typeName);
|
||||
ClassNode node = GlobalClassRepo.INSTANCE.findClass(typeName);
|
||||
if (node == null) return "java/lang/Object";
|
||||
return node.superName;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package io.izzel.arclight.common.mod.util.remapper;
|
||||
|
||||
import net.md_5.specialsource.repo.ClassRepo;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public class ClassLoaderRepo implements ClassRepo {
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClassLoaderRepo(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode findClass(String internalName) {
|
||||
URL url = classLoader.getResource(internalName + ".class");
|
||||
if (url == null) return null;
|
||||
try {
|
||||
URLConnection connection = url.openConnection();
|
||||
try (InputStream inputStream = connection.getInputStream()) {
|
||||
ClassReader reader = new ClassReader(inputStream);
|
||||
ClassNode classNode = new ClassNode();
|
||||
reader.accept(classNode, ClassReader.SKIP_CODE);
|
||||
return classNode;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package io.izzel.arclight.common.mod.util.remapper;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import net.md_5.specialsource.repo.ClassRepo;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.service.MixinService;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class GlobalClassRepo implements ClassRepo {
|
||||
|
||||
public static final GlobalClassRepo INSTANCE = new GlobalClassRepo();
|
||||
private static final PluginInheritanceProvider PROVIDER = new PluginInheritanceProvider(INSTANCE);
|
||||
|
||||
private final LoadingCache<String, ClassNode> cache = CacheBuilder.newBuilder().maximumSize(65536).build(CacheLoader.from(this::findParallel));
|
||||
private final Set<ClassRepo> repos = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
private GlobalClassRepo() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode findClass(String internalName) {
|
||||
try {
|
||||
return cache.get(internalName);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ClassNode findParallel(String internalName) {
|
||||
return this.repos.parallelStream()
|
||||
.map(it -> it.findClass(internalName))
|
||||
.filter(Objects::nonNull)
|
||||
.findAny()
|
||||
.orElseGet(() -> this.findMinecraft(internalName));
|
||||
}
|
||||
|
||||
private ClassNode findMinecraft(String internalName) {
|
||||
try {
|
||||
return MixinService.getService().getBytecodeProvider().getClassNode(internalName);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(internalName, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addRepo(ClassRepo repo) {
|
||||
this.repos.add(repo);
|
||||
}
|
||||
|
||||
public void removeRepo(ClassRepo repo) {
|
||||
this.repos.remove(repo);
|
||||
}
|
||||
|
||||
public static PluginInheritanceProvider inheritanceProvider() {
|
||||
return PROVIDER;
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package io.izzel.arclight.common.mod.util.remapper;
|
||||
|
||||
import io.izzel.arclight.common.bridge.bukkit.JavaPluginLoaderBridge;
|
||||
import net.md_5.specialsource.repo.ClassRepo;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class PluginClassRepo implements ClassRepo {
|
||||
|
||||
private final SharedClassRepo shared;
|
||||
private JavaPluginLoaderBridge loader;
|
||||
private URLClassLoader plugin;
|
||||
|
||||
protected PluginClassRepo(SharedClassRepo shared, JavaPluginLoader loader, URLClassLoader plugin) {
|
||||
this.shared = shared;
|
||||
this.loader = (JavaPluginLoaderBridge) (Object) loader;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode findClass(String internalName) {
|
||||
if (plugin == null) return shared.findClass(internalName);
|
||||
if (loader.bridge$getLoaders().contains(plugin)) {
|
||||
plugin = null;
|
||||
}
|
||||
ClassNode node = shared.findClass(internalName);
|
||||
if (node == null && plugin != null) {
|
||||
return shared.findIn(plugin, internalName + ".class");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class PluginInheritanceProvider implements InheritanceProvider {
|
||||
|
||||
private static Map<String, Collection<String>> sharedInheritanceMap = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Collection<String>> SHARED_INHERITANCE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private final ClassRepo classRepo;
|
||||
|
||||
@ -34,7 +34,7 @@ public class PluginInheritanceProvider implements InheritanceProvider {
|
||||
}
|
||||
|
||||
public Collection<String> getAll(String className) {
|
||||
Collection<String> collection = sharedInheritanceMap.get(className);
|
||||
Collection<String> collection = SHARED_INHERITANCE_MAP.get(className);
|
||||
if (collection != null) return collection;
|
||||
|
||||
ClassNode node = classRepo.findClass(className);
|
||||
@ -48,7 +48,7 @@ public class PluginInheritanceProvider implements InheritanceProvider {
|
||||
parents.add("java/lang/Object");
|
||||
}
|
||||
|
||||
sharedInheritanceMap.put(className, parents);
|
||||
SHARED_INHERITANCE_MAP.put(className, parents);
|
||||
return parents;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
package io.izzel.arclight.common.mod.util.remapper;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
public interface PluginTransformer {
|
||||
|
||||
void handleClass(ClassNode node, ClassLoaderRemapper remapper);
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
package io.izzel.arclight.common.mod.util.remapper;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import io.izzel.arclight.common.bridge.bukkit.JavaPluginLoaderBridge;
|
||||
import net.md_5.specialsource.repo.ClassRepo;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.service.MixinService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public class SharedClassRepo implements ClassRepo {
|
||||
|
||||
private static SharedClassRepo classRepo;
|
||||
|
||||
protected final JavaPluginLoaderBridge loader;
|
||||
private final Cache<String, ClassNode> cache = CacheBuilder.newBuilder().maximumSize(65536).build();
|
||||
|
||||
protected SharedClassRepo(JavaPluginLoader loader) {
|
||||
this.loader = ((JavaPluginLoaderBridge) (Object) loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode findClass(String internalName) {
|
||||
ClassNode ret = cache.getIfPresent(internalName);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
try {
|
||||
ret = MixinService.getService().getBytecodeProvider().getClassNode(internalName);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (ret == null) {
|
||||
ret = findPlugins(internalName + ".class");
|
||||
}
|
||||
if (ret != null) {
|
||||
cache.put(internalName, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private ClassNode findPlugins(String name) {
|
||||
for (URLClassLoader classLoader : loader.bridge$getLoaders()) {
|
||||
ClassNode node = findIn(classLoader, name);
|
||||
if (node != null) return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected ClassNode findIn(URLClassLoader classLoader, String name) {
|
||||
URL url = HelperClassLoader.find(classLoader, name);
|
||||
if (url == null) return null;
|
||||
try {
|
||||
URLConnection connection = url.openConnection();
|
||||
try (InputStream inputStream = connection.getInputStream()) {
|
||||
ClassReader reader = new ClassReader(inputStream);
|
||||
ClassNode classNode = new ClassNode();
|
||||
reader.accept(classNode, ClassReader.SKIP_CODE);
|
||||
return classNode;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ClassRepo get(JavaPluginLoader loader, URLClassLoader plugin) {
|
||||
if (classRepo == null) {
|
||||
synchronized (SharedClassRepo.class) {
|
||||
if (classRepo == null) {
|
||||
classRepo = new SharedClassRepo(loader);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new PluginClassRepo(classRepo, loader, plugin);
|
||||
}
|
||||
|
||||
private static class HelperClassLoader extends URLClassLoader {
|
||||
|
||||
public HelperClassLoader(URL[] urls) {
|
||||
super(urls);
|
||||
}
|
||||
|
||||
static URL find(URLClassLoader classLoader, String resource) {
|
||||
return classLoader.findResource(resource); // search local
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
package io.izzel.arclight.common.mod.util.remapper.generated;
|
||||
|
||||
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
|
||||
import org.objectweb.asm.Type;
|
||||
import io.izzel.arclight.common.mod.util.remapper.PluginRemapper;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
@ -14,11 +14,11 @@ public class ArclightReflectionHandler {
|
||||
|
||||
private static final String PREFIX = "net.minecraft.";
|
||||
|
||||
public static PluginRemapper remapper;
|
||||
public static ClassLoaderRemapper remapper;
|
||||
|
||||
// bukkit -> srg
|
||||
public static Class<?> redirectForName(String cl) throws ClassNotFoundException {
|
||||
return redirectForName(cl, true, remapper.getPluginClassLoader());
|
||||
return redirectForName(cl, true, remapper.getClassLoader());
|
||||
}
|
||||
|
||||
// bukkit -> srg
|
||||
|
||||
@ -3,7 +3,7 @@ import java.nio.file.attribute.BasicFileAttributes
|
||||
|
||||
allprojects {
|
||||
group 'io.izzel.arclight'
|
||||
version '1.0.2'
|
||||
version '1.0.3-SNAPSHOT'
|
||||
|
||||
ext {
|
||||
agpVersion = '1.7'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user