108 lines
4.4 KiB
Java
108 lines
4.4 KiB
Java
package io.gitlab.jfronny.libjf.unsafe.asm.patch.targeting;
|
|
|
|
import io.gitlab.jfronny.libjf.LibJf;
|
|
import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer;
|
|
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
|
|
import org.objectweb.asm.Type;
|
|
import org.objectweb.asm.tree.ClassNode;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
public class InterfaceImplTargetPatch implements Patch {
|
|
public static final Map<String, Set<String>> INTERFACES = new HashMap<>();
|
|
private final String targetInterface;
|
|
private final Patch methodPatch;
|
|
|
|
public InterfaceImplTargetPatch(String targetInterfaceIntermediary, Patch methodPatch) {
|
|
this.targetInterface = AsmTransformer.MAPPING_RESOLVER.mapClassName(AsmTransformer.INTERMEDIARY, targetInterfaceIntermediary).replace('.', '/');
|
|
this.methodPatch = methodPatch;
|
|
}
|
|
|
|
@Override
|
|
public void apply(ClassNode klazz) {
|
|
scanInterfaces(klazz);
|
|
if (getUpper(klazz.name).contains(targetInterface)) {
|
|
if (AsmTransformer.INSTANCE.debugLogsEnabled()) LibJf.LOGGER.info("Found " + klazz.name + " implementing " + targetInterface);
|
|
methodPatch.apply(klazz);
|
|
}
|
|
}
|
|
|
|
private static void scanInterfaces(ClassNode klazz) {
|
|
if (INTERFACES.containsKey(klazz.name)) return;
|
|
INTERFACES.put(klazz.name, new HashSet<>());
|
|
for (String anInterface : klazz.interfaces) {
|
|
INTERFACES.get(klazz.name).add(anInterface);
|
|
}
|
|
if (klazz.superName != null) {
|
|
INTERFACES.get(klazz.name).add(klazz.superName);
|
|
}
|
|
INTERFACES.put(klazz.name, Set.copyOf(INTERFACES.get(klazz.name)));
|
|
for (String s : INTERFACES.get(klazz.name)) {
|
|
String n = s.replace('/', '.');
|
|
if (AsmTransformer.isClassUnmoddable(n, AsmTransformer.INSTANCE.getCurrentConfig()))
|
|
continue;
|
|
try {
|
|
InterfaceImplTargetPatch.class.getClassLoader().loadClass(n);
|
|
} catch (Throwable e) {
|
|
throw new RuntimeException("Could not load super class " + s + " of " + klazz.name, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void scanInterfaces(Class<?> klazz) {
|
|
String n = Type.getInternalName(klazz);
|
|
if (INTERFACES.containsKey(n)) return;
|
|
INTERFACES.put(n, new HashSet<>());
|
|
for (Class<?> anInterface : klazz.getInterfaces()) {
|
|
INTERFACES.get(n).add(Type.getInternalName(anInterface));
|
|
}
|
|
Class<?> superC = klazz.getSuperclass();
|
|
if (superC != null) {
|
|
INTERFACES.get(n).add(Type.getInternalName(superC));
|
|
}
|
|
INTERFACES.put(n, Set.copyOf(INTERFACES.get(n)));
|
|
for (String s : INTERFACES.get(n)) {
|
|
String nn = s.replace('/', '.');
|
|
if (AsmTransformer.isClassUnmoddable(nn, AsmTransformer.INSTANCE.getCurrentConfig()))
|
|
continue;
|
|
try {
|
|
scanInterfaces(InterfaceImplTargetPatch.class.getClassLoader().loadClass(nn));
|
|
} catch (Throwable e) {
|
|
throw new RuntimeException("Could not load super class " + s + " of " + n, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Set<String> getUpper(String className) {
|
|
Set<String> s = INTERFACES.get(className);
|
|
if (s == null) {
|
|
if (!className.startsWith("java/")
|
|
&& !className.startsWith("com/mojang/")
|
|
&& !className.startsWith("net/minecraft/")
|
|
&& !className.startsWith("jdk/")
|
|
&& !className.startsWith("it/unimi/dsi/fastutil/")
|
|
&& !className.startsWith("com/google/")
|
|
) {
|
|
if (AsmTransformer.INSTANCE.debugLogsEnabled()) LibJf.LOGGER.info("Non-default class not considered for interface scanning: " + className);
|
|
INTERFACES.put(className, Set.of());
|
|
return Set.of();
|
|
}
|
|
try {
|
|
scanInterfaces(Class.forName(className.replace('/', '.')));
|
|
s = INTERFACES.get(className);
|
|
} catch (ClassNotFoundException e) {
|
|
LibJf.LOGGER.error("Could not get base for " + className, e);
|
|
return Set.of();
|
|
}
|
|
}
|
|
s = new HashSet<>(s);
|
|
for (String s1 : s.toArray(new String[0])) {
|
|
s.addAll(getUpper(s1));
|
|
}
|
|
return s;
|
|
}
|
|
}
|