From a97a4eefd05de45616f8f04227523a4489a44ad7 Mon Sep 17 00:00:00 2001 From: arcade_kappa Date: Sat, 13 Jul 2024 17:54:38 +0800 Subject: [PATCH] Fix ccl patching --- .../cleanroommc/fugue/helper/HookHelper.java | 13 ++++- .../ClassHierarchyManagerTransformer.java | 48 ++++++++++++------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/cleanroommc/fugue/helper/HookHelper.java b/src/main/java/com/cleanroommc/fugue/helper/HookHelper.java index d8d2c8f..d66f560 100644 --- a/src/main/java/com/cleanroommc/fugue/helper/HookHelper.java +++ b/src/main/java/com/cleanroommc/fugue/helper/HookHelper.java @@ -4,8 +4,6 @@ import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.MixinEnvironment; -import org.spongepowered.asm.mixin.Mixins; import top.outlands.foundation.TransformerDelegate; import top.outlands.foundation.boot.ActualClassLoader; @@ -16,6 +14,7 @@ import java.nio.file.Paths; import java.security.CodeSource; import java.util.*; +import java.util.function.Function; public class HookHelper { public static boolean isInterface(int opcode) { @@ -144,4 +143,14 @@ public static void TickCentralPreLoad() { public static boolean isClassExist(String clazz) { return Launch.classLoader.isClassExist(clazz); } + + public static Object computeIfAbsent(Map map, Object key, Function function) { + if (map.containsKey(key)) { + return map.get(key); + } else { + Object value = function.apply(key); + map.put(key, value); + return value; + } + } } diff --git a/src/main/java/com/cleanroommc/fugue/transformer/ClassHierarchyManagerTransformer.java b/src/main/java/com/cleanroommc/fugue/transformer/ClassHierarchyManagerTransformer.java index 9417e34..76e9530 100644 --- a/src/main/java/com/cleanroommc/fugue/transformer/ClassHierarchyManagerTransformer.java +++ b/src/main/java/com/cleanroommc/fugue/transformer/ClassHierarchyManagerTransformer.java @@ -3,6 +3,10 @@ import com.cleanroommc.fugue.common.Fugue; import javassist.ClassPool; import javassist.CtClass; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; import top.outlands.foundation.IExplicitTransformer; import java.io.ByteArrayInputStream; @@ -10,26 +14,34 @@ public class ClassHierarchyManagerTransformer implements IExplicitTransformer { @Override public byte[] transform(byte[] bytes) { - try { - ClassPool pool = ClassPool.getDefault(); - CtClass cc = pool.makeClass(new ByteArrayInputStream(bytes)); - cc.getMethod("getOrCreateCache", "(Ljava/lang/String;)Lcodechicken/asm/ClassHierarchyManager$SuperCache;").setBody( - """ + ClassNode classNode = new ClassNode(); + ClassReader classReader = new ClassReader(bytes); + classReader.accept(classNode, 0); + if (classNode.methods != null) + { + for (MethodNode methodNode : classNode.methods) + { + if (methodNode.name.equals("getOrCreateCache")) { + InsnList instructions = methodNode.instructions; + if (instructions != null) { - codechicken.asm.ClassHierarchyManager.SuperCache cache; - if (!superclasses.containsKey($1)) { - cache = new codechicken.asm.ClassHierarchyManager.SuperCache(); - superclasses.put($1, cache); - } else { - cache = superclasses.get($1); - } - return (codechicken.asm.ClassHierarchyManager.SuperCache)cache; + for (AbstractInsnNode insnNode : instructions) + { + if (insnNode instanceof MethodInsnNode methodInsnNode) + { + if (methodInsnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) { + instructions.insert(methodInsnNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "com/cleanroommc/fugue/helper/HookHelper", "computeIfAbsent", "(Ljava/util/Map;Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;", false)); + instructions.remove(methodInsnNode); + } + } + } } - """); - bytes = cc.toBytecode(); - } catch (Throwable t) { - Fugue.LOGGER.error("Exception {} on {}", t, this.getClass().getSimpleName()); + } + } } - return bytes; + ClassWriter classWriter = new ClassWriter(0); + + classNode.accept(classWriter); + return classWriter.toByteArray(); } }