Remapper does not need a plugin now.

This commit is contained in:
IzzelAliz 2020-07-17 17:10:18 +08:00
parent ac871c63d3
commit 9d1be58b04
14 changed files with 176 additions and 185 deletions

View File

@ -6,7 +6,6 @@ import io.izzel.arclight.api.EnumHelper;
import io.izzel.arclight.api.Unsafe; import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger; 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.log.ArclightLazyLogManager;
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
import io.izzel.arclight.common.util.EnumTypeFactory; import io.izzel.arclight.common.util.EnumTypeFactory;
import io.izzel.arclight.i18n.ArclightConfig; import io.izzel.arclight.i18n.ArclightConfig;
import io.izzel.arclight.i18n.ArclightLocale; import io.izzel.arclight.i18n.ArclightLocale;
@ -14,7 +13,6 @@ import net.minecraftforge.server.ServerMain;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Objects;
import java.util.jar.Attributes; import java.util.jar.Attributes;
import java.util.jar.Manifest; import java.util.jar.Manifest;
@ -38,8 +36,6 @@ public abstract class ArclightMain {
} }
try { try {
printLogo(); printLogo();
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
Objects.requireNonNull(ArclightRemapper.INSTANCE);
this.beforeStart(); this.beforeStart();
this.dirtyHacks(); this.dirtyHacks();
ServerMain.main(args); ServerMain.main(args);

View File

@ -4,7 +4,7 @@ import com.google.common.io.ByteStreams;
import io.izzel.arclight.common.asm.SwitchTableFixer; import io.izzel.arclight.common.asm.SwitchTableFixer;
import io.izzel.arclight.common.bridge.bukkit.JavaPluginLoaderBridge; 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.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.Bukkit;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.plugin.java.JavaPluginLoader;
@ -36,7 +36,7 @@ public class PluginClassLoaderMixin extends URLClassLoader {
@Shadow @Final private URL url; @Shadow @Final private URL url;
// @formatter:on // @formatter:on
private PluginRemapper remapper; private ClassLoaderRemapper remapper;
public PluginClassLoaderMixin(URL[] urls) { public PluginClassLoaderMixin(URL[] urls) {
super(urls); super(urls);
@ -74,7 +74,7 @@ public class PluginClassLoaderMixin extends URLClassLoader {
classBytes = SwitchTableFixer.INSTANCE.processClass(classBytes); classBytes = SwitchTableFixer.INSTANCE.processClass(classBytes);
classBytes = Bukkit.getUnsafe().processClass(description, path, classBytes); classBytes = Bukkit.getUnsafe().processClass(description, path, classBytes);
if (remapper == null) { if (remapper == null) {
remapper = ArclightRemapper.INSTANCE.createPluginRemapper(this.loader, this); remapper = ArclightRemapper.INSTANCE.createClassLoaderRemapper(this);
} }
classBytes = remapper.remapClass(classBytes); classBytes = remapper.remapClass(classBytes);

View File

@ -16,14 +16,20 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; 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/"; 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)) { if (shouldGenerate(classNode.name, inheritanceProvider)) {
HashSet<Map.Entry<String, String>> set = new HashSet<>(); 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) { for (Map.Entry<String, String> entry : set) {
String name = entry.getKey(); String name = entry.getKey();
String desc = entry.getValue(); 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); name = remapper.mapType(name);
MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, name, desc, null, null); MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, name, desc, null, null);
methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); methodNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));

View File

@ -17,10 +17,11 @@ import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
public class ArclightRedirectAdapter { public class ArclightRedirectAdapter implements PluginTransformer {
private static String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class); public static final ArclightRedirectAdapter INSTANCE = new ArclightRedirectAdapter();
private static Map<MethodInsnNode, MethodInsnNode> methodRedirects = ImmutableMap private static final String REPLACED_NAME = Type.getInternalName(ArclightReflectionHandler.class);
private static final Map<MethodInsnNode, MethodInsnNode> METHOD_REDIRECTS = ImmutableMap
.<MethodInsnNode, MethodInsnNode>builder() .<MethodInsnNode, MethodInsnNode>builder()
.put( .put(
method(Opcodes.INVOKEVIRTUAL, Field.class, "getName"), method(Opcodes.INVOKEVIRTUAL, Field.class, "getName"),
@ -104,14 +105,19 @@ public class ArclightRedirectAdapter {
) )
.build(); .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) { for (MethodNode methodNode : classNode.methods) {
ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator(); ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
AbstractInsnNode insnNode = iterator.next(); AbstractInsnNode insnNode = iterator.next();
if (insnNode instanceof MethodInsnNode) { if (insnNode instanceof MethodInsnNode) {
MethodInsnNode from = (MethodInsnNode) insnNode; 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(); MethodInsnNode key = entry.getKey();
if ( if (
key.getOpcode() == from.getOpcode() && key.getOpcode() == from.getOpcode() &&
@ -151,5 +157,4 @@ public class ArclightRedirectAdapter {
String desc = Type.getMethodDescriptor(method); String desc = Type.getMethodDescriptor(method);
return new MethodInsnNode(opcode, owner, name, desc); return new MethodInsnNode(opcode, owner, name, desc);
} }
} }

View File

@ -3,21 +3,23 @@ package io.izzel.arclight.common.mod.util.remapper;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import io.izzel.arclight.api.Unsafe; 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.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.bukkit.plugin.java.JavaPluginLoader;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URLClassLoader; import java.util.ArrayList;
import java.util.List;
public class ArclightRemapper { public class ArclightRemapper {
public static final ArclightRemapper INSTANCE; public static final ArclightRemapper INSTANCE;
static { static {
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
try { try {
INSTANCE = new ArclightRemapper(); INSTANCE = new ArclightRemapper();
} catch (Exception e) { } catch (Exception e) {
@ -28,6 +30,7 @@ public class ArclightRemapper {
private final JarMapping toNmsMapping; private final JarMapping toNmsMapping;
private final JarMapping toBukkitMapping; private final JarMapping toBukkitMapping;
public final InheritanceMap inheritanceMap; public final InheritanceMap inheritanceMap;
private final List<PluginTransformer> transformerList = new ArrayList<>();
public ArclightRemapper() throws Exception { public ArclightRemapper() throws Exception {
this.toNmsMapping = new JarMapping(); this.toNmsMapping = new JarMapping();
@ -50,10 +53,16 @@ public class ArclightRemapper {
inheritanceProvider.add(new ClassLoaderProvider(ClassLoader.getSystemClassLoader())); inheritanceProvider.add(new ClassLoaderProvider(ClassLoader.getSystemClassLoader()));
this.toNmsMapping.setFallbackInheritanceProvider(inheritanceProvider); this.toNmsMapping.setFallbackInheritanceProvider(inheritanceProvider);
this.toBukkitMapping.setFallbackInheritanceProvider(inheritanceProvider); this.toBukkitMapping.setFallbackInheritanceProvider(inheritanceProvider);
this.transformerList.add(ArclightInterfaceInvokerGen.INSTANCE);
this.transformerList.add(ArclightRedirectAdapter.INSTANCE);
} }
public PluginRemapper createPluginRemapper(JavaPluginLoader loader, URLClassLoader plugin) { public ClassLoaderRemapper createClassLoaderRemapper(ClassLoader classLoader) {
return new PluginRemapper(copyOf(toNmsMapping), copyOf(toBukkitMapping), loader, plugin); return new ClassLoaderRemapper(copyOf(toNmsMapping), copyOf(toBukkitMapping), classLoader);
}
public List<PluginTransformer> getTransformerList() {
return transformerList;
} }
private static long pkgOffset, clOffset, mdOffset, fdOffset, mapOffset; private static long pkgOffset, clOffset, mdOffset, fdOffset, mapOffset;

View File

@ -4,15 +4,14 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import com.google.common.collect.Maps; 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.api.Unsafe;
import io.izzel.arclight.common.mod.util.remapper.generated.ArclightReflectionHandler;
import net.md_5.specialsource.JarMapping; import net.md_5.specialsource.JarMapping;
import net.md_5.specialsource.JarRemapper; import net.md_5.specialsource.JarRemapper;
import net.md_5.specialsource.RemappingClassAdapter; import net.md_5.specialsource.RemappingClassAdapter;
import net.md_5.specialsource.repo.ClassRepo; import net.md_5.specialsource.repo.ClassRepo;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
@ -27,7 +26,6 @@ import org.spongepowered.asm.service.MixinService;
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.net.URLClassLoader;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -36,33 +34,30 @@ import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; 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 Logger LOGGER = LogManager.getLogger("Arclight");
private static final String PREFIX = "net/minecraft/"; private static final String PREFIX = "net/minecraft/";
private final PluginInheritanceProvider inheritanceProvider;
private final ClassRepo classRepo;
private final JarMapping toBukkitMapping; private final JarMapping toBukkitMapping;
private final JarRemapper toBukkitRemapper; private final JarRemapper toBukkitRemapper;
private final URLClassLoader plugin; private final ClassLoader classLoader;
private final String generatedHandler; private final String generatedHandler;
public PluginRemapper(JarMapping jarMapping, JarMapping toBukkitMapping, JavaPluginLoader loader, URLClassLoader plugin) { public ClassLoaderRemapper(JarMapping jarMapping, JarMapping toBukkitMapping, ClassLoader classLoader) {
super(jarMapping); super(jarMapping);
this.toBukkitMapping = toBukkitMapping; this.toBukkitMapping = toBukkitMapping;
this.plugin = plugin; this.classLoader = classLoader;
this.classRepo = SharedClassRepo.get(loader, plugin);
this.inheritanceProvider = new PluginInheritanceProvider(this.classRepo);
this.jarMapping.setInheritanceMap(ArclightRemapper.INSTANCE.inheritanceMap); this.jarMapping.setInheritanceMap(ArclightRemapper.INSTANCE.inheritanceMap);
this.jarMapping.setFallbackInheritanceProvider(this.inheritanceProvider); this.jarMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
this.toBukkitMapping.setFallbackInheritanceProvider(this.inheritanceProvider); this.toBukkitMapping.setFallbackInheritanceProvider(GlobalClassRepo.inheritanceProvider());
this.toBukkitRemapper = new JarRemapper(this.toBukkitMapping); this.toBukkitRemapper = new JarRemapper(this.toBukkitMapping);
this.generatedHandler = generateReflectionHandler(); this.generatedHandler = generateReflectionHandler();
GlobalClassRepo.INSTANCE.addRepo(new ClassLoaderRepo(this.classLoader));
} }
public URLClassLoader getPluginClassLoader() { public ClassLoader getClassLoader() {
return plugin; return classLoader;
} }
public JarMapping toBukkitMapping() { public JarMapping toBukkitMapping() {
@ -77,8 +72,8 @@ public class PluginRemapper extends JarRemapper {
return toBukkitRemapper; return toBukkitRemapper;
} }
public ClassRepo getClassRepo() { public String getGeneratedHandler() {
return classRepo; return generatedHandler;
} }
// BiMap: srg -> bukkit // BiMap: srg -> bukkit
@ -204,7 +199,7 @@ public class PluginRemapper extends JarRemapper {
private boolean shouldRemap(String internalName) { private boolean shouldRemap(String internalName) {
Boolean b = cacheRemap.get(internalName); Boolean b = cacheRemap.get(internalName);
if (b != null) return b; if (b != null) return b;
for (String s : inheritanceProvider.getAll(internalName)) { for (String s : GlobalClassRepo.inheritanceProvider().getAll(internalName)) {
if (s.startsWith(PREFIX)) { if (s.startsWith(PREFIX)) {
cacheRemap.put(internalName, true); cacheRemap.put(internalName, true);
return true; return true;
@ -230,7 +225,7 @@ public class PluginRemapper extends JarRemapper {
if (ArclightRemapper.INSTANCE.inheritanceMap.hasParents(owner)) { if (ArclightRemapper.INSTANCE.inheritanceMap.hasParents(owner)) {
parents = ArclightRemapper.INSTANCE.inheritanceMap.getParents(owner); parents = ArclightRemapper.INSTANCE.inheritanceMap.getParents(owner);
} else { } else {
parents = this.inheritanceProvider.getParents(owner); parents = GlobalClassRepo.inheritanceProvider().getParents(owner);
ArclightRemapper.INSTANCE.inheritanceMap.setParents(owner, parents); ArclightRemapper.INSTANCE.inheritanceMap.setParents(owner, parents);
} }
@ -249,7 +244,7 @@ public class PluginRemapper extends JarRemapper {
} }
public byte[] remapClass(byte[] arr) { public byte[] remapClass(byte[] arr) {
return remapClassFile(arr, classRepo); return remapClassFile(arr, GlobalClassRepo.INSTANCE);
} }
@Override @Override
@ -262,8 +257,9 @@ public class PluginRemapper extends JarRemapper {
RemappingClassAdapter mapper = new RemappingClassAdapter(node, this, repo); RemappingClassAdapter mapper = new RemappingClassAdapter(node, this, repo);
reader.accept(mapper, ClassReader.SKIP_FRAMES); reader.accept(mapper, ClassReader.SKIP_FRAMES);
ArclightRedirectAdapter.redirect(node, generatedHandler); for (PluginTransformer transformer : ArclightRemapper.INSTANCE.getTransformerList()) {
ArclightInterfaceInvokerGen.generate(node, this.classRepo, this, this.inheritanceProvider); transformer.handleClass(node, this);
}
// 有的插件的编译器奇奇怪怪的所以在这里要重新计算 frame // 有的插件的编译器奇奇怪怪的所以在这里要重新计算 frame
ClassWriter wr = new PluginClassWriter(ClassWriter.COMPUTE_FRAMES); ClassWriter wr = new PluginClassWriter(ClassWriter.COMPUTE_FRAMES);
@ -272,14 +268,14 @@ public class PluginRemapper extends JarRemapper {
return wr.toByteArray(); return wr.toByteArray();
} }
private static AtomicInteger atomicInteger = new AtomicInteger(); private static final AtomicInteger COUNTER = new AtomicInteger();
private String generateReflectionHandler() { private String 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");
ClassWriter writer = new ClassWriter(0); 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)); ClassVisitor visitor = new ClassRemapper(writer, new NameRemapper(name));
node.accept(visitor); node.accept(visitor);
byte[] bytes = writer.toByteArray(); byte[] bytes = writer.toByteArray();
@ -296,7 +292,7 @@ public class PluginRemapper extends JarRemapper {
private static class NameRemapper extends Remapper { 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; private final String internal;
@ -306,14 +302,14 @@ public class PluginRemapper extends JarRemapper {
@Override @Override
public String mapType(String internalName) { public String mapType(String internalName) {
if (internalName.equals(origin)) { if (internalName.equals(ORIGIN)) {
return internal; return internal;
} }
return super.mapType(internalName); return super.mapType(internalName);
} }
} }
private class PluginClassWriter extends ClassWriter { private static class PluginClassWriter extends ClassWriter {
public PluginClassWriter(int flags) { public PluginClassWriter(int flags) {
super(flags); super(flags);
@ -321,11 +317,11 @@ public class PluginRemapper extends JarRemapper {
@Override @Override
protected String getCommonSuperClass(String type1, String type2) { protected String getCommonSuperClass(String type1, String type2) {
Collection<String> parents = inheritanceProvider.getAll(type2); Collection<String> parents = GlobalClassRepo.inheritanceProvider().getAll(type2);
if (parents.contains(type1)) { if (parents.contains(type1)) {
return type1; return type1;
} }
if (inheritanceProvider.getAll(type1).contains(type2)) { if (GlobalClassRepo.inheritanceProvider().getAll(type1).contains(type2)) {
return type2; return type2;
} }
do { do {
@ -335,7 +331,7 @@ public class PluginRemapper extends JarRemapper {
} }
private String getSuper(final String typeName) { private String getSuper(final String typeName) {
ClassNode node = classRepo.findClass(typeName); ClassNode node = GlobalClassRepo.INSTANCE.findClass(typeName);
if (node == null) return "java/lang/Object"; if (node == null) return "java/lang/Object";
return node.superName; return node.superName;
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class PluginInheritanceProvider implements InheritanceProvider { 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; private final ClassRepo classRepo;
@ -34,7 +34,7 @@ public class PluginInheritanceProvider implements InheritanceProvider {
} }
public Collection<String> getAll(String className) { 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; if (collection != null) return collection;
ClassNode node = classRepo.findClass(className); ClassNode node = classRepo.findClass(className);
@ -48,7 +48,7 @@ public class PluginInheritanceProvider implements InheritanceProvider {
parents.add("java/lang/Object"); parents.add("java/lang/Object");
} }
sharedInheritanceMap.put(className, parents); SHARED_INHERITANCE_MAP.put(className, parents);
return parents; return parents;
} }
} }

View File

@ -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);
}

View File

@ -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
}
}
}

View File

@ -1,7 +1,7 @@
package io.izzel.arclight.common.mod.util.remapper.generated; package io.izzel.arclight.common.mod.util.remapper.generated;
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import io.izzel.arclight.common.mod.util.remapper.PluginRemapper;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@ -14,11 +14,11 @@ public class ArclightReflectionHandler {
private static final String PREFIX = "net.minecraft."; private static final String PREFIX = "net.minecraft.";
public static PluginRemapper remapper; public static ClassLoaderRemapper remapper;
// bukkit -> srg // bukkit -> srg
public static Class<?> redirectForName(String cl) throws ClassNotFoundException { public static Class<?> redirectForName(String cl) throws ClassNotFoundException {
return redirectForName(cl, true, remapper.getPluginClassLoader()); return redirectForName(cl, true, remapper.getClassLoader());
} }
// bukkit -> srg // bukkit -> srg

View File

@ -3,7 +3,7 @@ import java.nio.file.attribute.BasicFileAttributes
allprojects { allprojects {
group 'io.izzel.arclight' group 'io.izzel.arclight'
version '1.0.2' version '1.0.3-SNAPSHOT'
ext { ext {
agpVersion = '1.7' agpVersion = '1.7'