diff --git a/gradle.properties b/gradle.properties index 60abdc1..c0aecb5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -90,7 +90,9 @@ usesMixinDebug = false # Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. mixinPlugin = -# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +# Specify the package that contains all of your Mixins. The package must exist or +# the build will fail. If you have a package property defined in your mixins..json, +# it must match with this or the build will fail. mixinsPackage = # Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! @@ -166,6 +168,12 @@ curseForgeRelations = # projects. New projects should not use this parameter. # customArchiveBaseName = +# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory. +# runClientWorkingDirectory = run/client + +# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory. +# runServerWorkingDirectory = run/server + # Optional parameter to have the build automatically fail if an illegal version is used. # This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'. # The check is ONLY performed if the version is a git tag. diff --git a/settings.gradle b/settings.gradle index 7622cde..e883289 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,7 @@ pluginManagement { } plugins { - id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.41' + id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.48' } diff --git a/src/main/java/codechicken/lib/asm/ClassHeirachyManager.java b/src/main/java/codechicken/lib/asm/ClassHeirachyManager.java index 88e8291..f14932d 100644 --- a/src/main/java/codechicken/lib/asm/ClassHeirachyManager.java +++ b/src/main/java/codechicken/lib/asm/ClassHeirachyManager.java @@ -1,13 +1,12 @@ package codechicken.lib.asm; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraft.launchwrapper.Launch; -import net.minecraft.launchwrapper.LaunchClassLoader; +import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; @@ -18,43 +17,60 @@ */ public class ClassHeirachyManager implements IClassTransformer { - public static class SuperCache { + private static final Map superclasses = new ConcurrentHashMap<>(1000); - String superclass; - public HashSet parents = new HashSet(); - private boolean flattened; + static { + superclasses.put("java.lang.Object", ClassInfo.OBJECT); + } - public void add(String parent) { - parents.add(parent); + @Override + public byte[] transform(String name, String transformedName, byte[] bytes) { + if (bytes == null) return null; + if (!superclasses.containsKey(transformedName)) { + declareASM(transformedName, bytes); } + return bytes; + } - public void flatten() { - if (flattened) return; + private static ClassInfo declareASM(String name, byte[] bytes) { + final ClassNode node = ASMHelper.createClassNode(bytes, ClassReader.SKIP_CODE); + final ClassInfo classInfo = new ClassInfo(node); + superclasses.put(name, classInfo); + return classInfo; + } - for (String s : new ArrayList(parents)) { - SuperCache c = declareClass(s); - if (c != null) { - c.flatten(); - parents.addAll(c.parents); - } - } - flattened = true; - } + private static ClassInfo declareReflection(String name) throws ClassNotFoundException { + final Class aclass = Class.forName(name); + final ClassInfo classInfo = new ClassInfo(aclass); + superclasses.put(name, classInfo); + return classInfo; } - public static HashMap superclasses = new HashMap(); - private static LaunchClassLoader cl = Launch.classLoader; + private static ClassInfo declareClass(String name) { + try { + byte[] bytes = Launch.classLoader.getClassBytes(unKey(name)); + if (bytes != null) { + return declareASM(name, bytes); + } + } catch (Exception ignored) {} + try { + return declareReflection(name); + } catch (ClassNotFoundException ignored) {} + return null; + } - public static String toKey(String name) { - if (ObfMapping.obfuscated) - name = FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.'); - return name; + private static String toKey(String name) { + if (ObfMapping.obfuscated) { + return FMLDeobfuscatingRemapper.INSTANCE.map(name.replace('.', '/')).replace('/', '.'); + } + return name.replace('/', '.'); } - public static String unKey(String name) { - if (ObfMapping.obfuscated) - name = FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.'); - return name; + private static String unKey(String name) { + if (ObfMapping.obfuscated) { + return FMLDeobfuscatingRemapper.INSTANCE.unmap(name.replace('.', '/')).replace('/', '.'); + } + return name.replace('/', '.'); } /** @@ -68,83 +84,90 @@ public static boolean classExtends(String name, String superclass) { if (name.equals(superclass)) return true; - SuperCache cache = declareClass(name); - if (cache == null) // just can't handle this - return false; + ClassInfo classInfo = superclasses.get(name); + if (classInfo == null) classInfo = declareClass(name); + if (classInfo == null) return false; - cache.flatten(); - return cache.parents.contains(superclass); + return classInfo.hasSuper(superclass); } - private static SuperCache declareClass(String name) { + public static String getSuperClass(String name, boolean runtime) { name = toKey(name); - SuperCache cache = superclasses.get(name); - - if (cache != null) return cache; - - try { - byte[] bytes = cl.getClassBytes(unKey(name)); - if (bytes != null) cache = declareASM(bytes); - } catch (Exception e) {} - - if (cache != null) return cache; - - try { - cache = declareReflection(name); - } catch (ClassNotFoundException e) {} - - return cache; - } - - private static SuperCache declareReflection(String name) throws ClassNotFoundException { - Class aclass = Class.forName(name); - SuperCache cache = getOrCreateCache(name); - if (aclass.isInterface()) cache.superclass = "java.lang.Object"; - else if (name.equals("java.lang.Object")) return cache; - else cache.superclass = toKey(aclass.getSuperclass().getName()); + ClassInfo classInfo = superclasses.get(name); + if (classInfo == null) classInfo = declareClass(name); + if (classInfo == null || classInfo.superclass == null) return "java.lang.Object"; - cache.add(cache.superclass); - for (Class iclass : aclass.getInterfaces()) cache.add(toKey(iclass.getName())); - - return cache; + final String s = classInfo.superclass; + if (!runtime) { + return FMLDeobfuscatingRemapper.INSTANCE.unmap(s); + } + return s; } - private static SuperCache declareASM(byte[] bytes) { - ClassNode node = ASMHelper.createClassNode(bytes); - String name = toKey(node.name); + private static class ClassInfo { - SuperCache cache = getOrCreateCache(name); - cache.superclass = toKey(node.superName.replace('/', '.')); - cache.add(cache.superclass); - for (String iclass : node.interfaces) cache.add(toKey(iclass.replace('/', '.'))); + public static final ClassInfo OBJECT = new ClassInfo(); - return cache; - } - - @Override - public byte[] transform(String name, String tname, byte[] bytes) { - if (bytes == null) return null; + public final String superclass; + public final String[] interfaces; + public ClassInfo parent; - if (!superclasses.containsKey(tname)) declareASM(bytes); - - return bytes; - } + private ClassInfo() { + this.superclass = null; + this.interfaces = null; + } - public static SuperCache getOrCreateCache(String name) { - SuperCache cache = superclasses.get(name); - if (cache == null) superclasses.put(name, cache = new SuperCache()); - return cache; - } + public ClassInfo(ClassNode node) { + if ("java/lang/Object".equals(node.superName)) { + superclass = "java.lang.Object"; + parent = OBJECT; + } else { + superclass = toKey(node.superName); + } + if (node.interfaces.isEmpty()) { + interfaces = null; + } else { + interfaces = new String[node.interfaces.size()]; + for (int i = 0; i < node.interfaces.size(); i++) { + interfaces[i] = toKey(node.interfaces.get(i)); + } + } + } - public static String getSuperClass(String name, boolean runtime) { - name = toKey(name); - SuperCache cache = declareClass(name); - if (cache == null) return "java.lang.Object"; + public ClassInfo(Class aclass) { + if (aclass.isInterface()) { + this.superclass = "java.lang.Object"; + this.parent = OBJECT; + } else { + final Class superclass = aclass.getSuperclass(); + if (superclass == null || "java.lang.Object".equals(superclass.getName())) { + this.superclass = "java.lang.Object"; + this.parent = OBJECT; + } else { + this.superclass = toKey(superclass.getName()); + } + } + final Class[] interfaces = aclass.getInterfaces(); + if (interfaces.length == 0) { + this.interfaces = null; + } else { + this.interfaces = new String[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) { + this.interfaces[i] = toKey(interfaces[i].getName()); + } + } + } - cache.flatten(); - String s = cache.superclass; - if (!runtime) s = FMLDeobfuscatingRemapper.INSTANCE.unmap(s); - return s; + public boolean hasSuper(String superclass) { + if (this.superclass == null) return false; + if (this.superclass.equals(superclass)) return true; + ClassInfo parentInfo = this.parent; + if (parentInfo == null) parentInfo = superclasses.get(this.superclass); + if (parentInfo == null) parentInfo = declareClass(this.superclass); + if (parentInfo == null) return false; + this.parent = parentInfo; + return parentInfo.hasSuper(superclass); + } } }