Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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.<modid>.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!
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pluginManagement {
}

plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.41'
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.48'
}


213 changes: 118 additions & 95 deletions src/main/java/codechicken/lib/asm/ClassHeirachyManager.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -18,43 +17,60 @@
*/
public class ClassHeirachyManager implements IClassTransformer {

public static class SuperCache {
private static final Map<String, ClassInfo> superclasses = new ConcurrentHashMap<>(1000);

String superclass;
public HashSet<String> parents = new HashSet<String>();
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<String>(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<String, SuperCache> superclasses = new HashMap<String, SuperCache>();
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('/', '.');
}

/**
Expand All @@ -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);
}
}
}