From 6e27e4aee0ca3ba5a9dd14fad6a0b599b4a97145 Mon Sep 17 00:00:00 2001 From: Bartosz Skrzypczak Date: Sun, 2 Jan 2022 18:26:39 +0100 Subject: [PATCH] TransformerTransformer to transform the transformer No more exception spam on load --- build.gradle | 2 +- .../launchwrapper/OptifineDevRemapper.java | 1 - .../OptifineDevTransformerWrapper.java | 29 +----- .../OptifineDevTweakerWrapper.java | 90 ++++++++++++++++--- .../java/ofdev/launchwrapper/UtilsLW.java | 12 ++- 5 files changed, 90 insertions(+), 44 deletions(-) diff --git a/build.gradle b/build.gradle index 2dca25e..39aae86 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ buildscript { apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'java' -version = "2.6.2" +version = "2.6.3" group = "ofdev" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "aa_do_not_rename_OptiFineDevTweaker" diff --git a/src/main/java/ofdev/launchwrapper/OptifineDevRemapper.java b/src/main/java/ofdev/launchwrapper/OptifineDevRemapper.java index 1dcdea9..0bef63e 100644 --- a/src/main/java/ofdev/launchwrapper/OptifineDevRemapper.java +++ b/src/main/java/ofdev/launchwrapper/OptifineDevRemapper.java @@ -38,7 +38,6 @@ public class OptifineDevRemapper extends Remapper { try { cpm = Class.forName("net.minecraftforge.fml.common.patcher.ClassPatchManager"); } catch (ClassNotFoundException ex) { - ex.printStackTrace(); cpm = Class.forName("cpw.mods.fml.common.patcher.ClassPatchManager"); // 1.7.10 } Object classPathManager = cpm.getField("INSTANCE").get(null); diff --git a/src/main/java/ofdev/launchwrapper/OptifineDevTransformerWrapper.java b/src/main/java/ofdev/launchwrapper/OptifineDevTransformerWrapper.java index 0032829..47afe2d 100644 --- a/src/main/java/ofdev/launchwrapper/OptifineDevTransformerWrapper.java +++ b/src/main/java/ofdev/launchwrapper/OptifineDevTransformerWrapper.java @@ -72,6 +72,7 @@ public class OptifineDevTransformerWrapper implements IClassTransformer { static { try { mcJar = FileSystems.newFileSystem(MC_JAR, Launch.classLoader); + Launch.classLoader.addURL(MC_JAR.toUri().toURL()); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -79,36 +80,8 @@ public class OptifineDevTransformerWrapper implements IClassTransformer { private static final OptifineDevRemapper remapper = OptifineDevRemapper.NOTCH_MCP; - public static IClassTransformer ofTransformer; - { - try { - Class ofTransformerClass = - (Class) OptifineDevTweakerWrapper.OF_TRANSFORMER_LAUNCH_CLASSLOADER; - - ofTransformer = ofTransformerClass.newInstance(); - URL ofUrl = ofTransformer.getClass().getProtectionDomain().getCodeSource().getLocation(); - - JarURLConnection connection = (JarURLConnection) ofUrl.openConnection(); - ZipFile file = new ZipFile(new File(connection.getJarFileURL().toURI())); - UtilsLW.setFieldValue(ofTransformerClass, "ofZipFile", ofTransformer, file); - - Class ofPatcher = Launch.classLoader.findClass("optifine.Patcher"); - - Object patchMapVal = UtilsLW.invokeMethod(ofPatcher, null, "getConfigurationMap", file); - Object patternsVal = UtilsLW.invokeMethod(ofPatcher, null, "getConfigurationPatterns", patchMapVal); - - UtilsLW.setFieldValue(ofTransformerClass, "patchMap", ofTransformer, patchMapVal); - UtilsLW.setFieldValue(ofTransformerClass, "patterns", ofTransformer, patternsVal); - System.out.println("Ignore the above, OptiFine should run anyway"); - - Launch.classLoader.addURL(MC_JAR.toUri().toURL()); - } catch (InstantiationException | IllegalAccessException | IOException | URISyntaxException | ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { if (basicClass == null || name == null) { return null; diff --git a/src/main/java/ofdev/launchwrapper/OptifineDevTweakerWrapper.java b/src/main/java/ofdev/launchwrapper/OptifineDevTweakerWrapper.java index e878ded..9198577 100644 --- a/src/main/java/ofdev/launchwrapper/OptifineDevTweakerWrapper.java +++ b/src/main/java/ofdev/launchwrapper/OptifineDevTweakerWrapper.java @@ -5,24 +5,98 @@ import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; import ofdev.common.Utils; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; +import java.net.JarURLConnection; +import java.net.URISyntaxException; +import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; import java.util.List; import java.util.Set; +import java.util.zip.ZipFile; // this is needed only in dev environment to get deobfuscated version of OptiFine running public class OptifineDevTweakerWrapper implements ITweaker { // this requires the jar to be loaded by FML before OptiFine, the easiest way to do it is to name it aa_SomeJar - public static final Class OF_TRANSFORMER_LAUNCH_CLASSLOADER = UtilsLW.loadClassLW("optifine.OptiFineClassTransformer"); + public static final Class OF_TRANSFORMER_LAUNCH_CLASSLOADER; + + static { + Launch.classLoader.registerTransformer("ofdev.launchwrapper.OptifineDevTweakerWrapper$OptiFineTransformerTransformer"); + OF_TRANSFORMER_LAUNCH_CLASSLOADER = UtilsLW.loadClassLW("optifine.OptiFineClassTransformer"); + } + + public static class OptiFineTransformerTransformer implements IClassTransformer { + @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (name != null && name.equals("optifine.OptiFineClassTransformer")) { + ClassReader cr = new ClassReader(basicClass); + ClassNode cn = new ClassNode(); + cr.accept(cn, 0); + for (MethodNode method : cn.methods) { + if (method.name.equals("")) { + AbstractInsnNode insn = null; + for (int i = 0; i < method.instructions.size(); i++) { + insn = method.instructions.get(i); + if (insn.getOpcode() == Opcodes.INVOKESPECIAL) { + break; + } + } + IntInsnNode loadThis = new IntInsnNode(Opcodes.ALOAD, 0); + MethodInsnNode initOptiTransformer = new MethodInsnNode(Opcodes.INVOKESTATIC, + "ofdev/launchwrapper/OptifineDevTweakerWrapper", + "initOptiTransformer", "(Ljava/lang/Object;)V", false); + method.instructions.insert(insn, loadThis); + method.instructions.insert(loadThis, initOptiTransformer); + method.instructions.insert(initOptiTransformer, new InsnNode(Opcodes.RETURN)); + } + } + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); + } + return basicClass; + } + } + + public static void initOptiTransformer(Object ofTransformer) { + OptifineDevTransformerWrapper.ofTransformer = (IClassTransformer) ofTransformer; + try { + Class ofTransformerClass = + (Class) OptifineDevTweakerWrapper.OF_TRANSFORMER_LAUNCH_CLASSLOADER; + + URL ofUrl = ofTransformer.getClass().getProtectionDomain().getCodeSource().getLocation(); + + JarURLConnection connection = (JarURLConnection) ofUrl.openConnection(); + ZipFile file = new ZipFile(new File(connection.getJarFileURL().toURI())); + UtilsLW.setFieldValue(ofTransformerClass, "ofZipFile", ofTransformer, file); + + Class ofPatcher = Launch.classLoader.findClass("optifine.Patcher"); + + Object patchMapVal = UtilsLW.invokeMethod(ofPatcher, null, "getConfigurationMap", file); + Object patternsVal = UtilsLW.invokeMethod(ofPatcher, null, "getConfigurationPatterns", patchMapVal); + + UtilsLW.setFieldValue(ofTransformerClass, "patchMap", ofTransformer, patchMapVal); + UtilsLW.setFieldValue(ofTransformerClass, "patterns", ofTransformer, patternsVal); + //System.out.println("Ignore the above, OptiFine should run anyway"); + UtilsLW.setFieldValue(ofTransformer.getClass(), "instance", null, ofTransformer); + + } catch (IOException | URISyntaxException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + public static Path CLASS_DUMP_LOCATION; @Override public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { @@ -56,12 +130,6 @@ public class OptifineDevTweakerWrapper implements ITweaker { Set transformerExceptions = UtilsLW.getFieldValue(LaunchClassLoader.class, Launch.classLoader, "transformerExceptions"); transformerExceptions.removeIf(t -> t.startsWith("optifine")); - - // OptiFine tweaker constructed new instance of optifine transformer, so it changed it's instance field - // now that OptiFine tweaker setup is done,fix it - Object ofTransformer = OptifineDevTransformerWrapper.ofTransformer; - UtilsLW.setFieldValue(ofTransformer.getClass(), "instance", null, ofTransformer); - return new String[0]; } } \ No newline at end of file diff --git a/src/main/java/ofdev/launchwrapper/UtilsLW.java b/src/main/java/ofdev/launchwrapper/UtilsLW.java index 7a0a05d..98e0ed9 100644 --- a/src/main/java/ofdev/launchwrapper/UtilsLW.java +++ b/src/main/java/ofdev/launchwrapper/UtilsLW.java @@ -172,14 +172,20 @@ public static void fixReflector() { try { Class reflector = UtilsLW.loadClassLW("Reflector"); + try { + reflector.getDeclaredField("ForgeBlock_getLightOpacity"); + } catch (NoSuchFieldException ignored) { + // 1.7.10 doesn't have this + return; + } Object ForgeBlock = UtilsLW.getFieldValue(reflector, null, "ForgeBlock"); Object ForgeBlock_getLightOpacity = UtilsLW.getFieldValue(reflector, null, "ForgeBlock_getLightOpacity"); Object ForgeBlock_getLightValue = UtilsLW.getFieldValue(reflector, null, "ForgeBlock_getLightValue"); Class ReflectorMethod = ForgeBlock_getLightOpacity.getClass(); - Class IBlockState = UtilsLW.loadClassLW("net.minecraft.block.state.IBlockState"); - Class IBlockAccess = UtilsLW.loadClassLW("net.minecraft.world.IBlockAccess"); - Class BlockPos = UtilsLW.loadClassLW("net.minecraft.util.math.BlockPos"); + Class IBlockState = UtilsLW.loadClassLW("net.minecraft.block.state.IBlockState"); + Class IBlockAccess = UtilsLW.loadClassLW("net.minecraft.world.IBlockAccess"); + Class BlockPos = UtilsLW.loadClassLW("net.minecraft.util.math.BlockPos"); if (UtilsLW.invokeMethod(ReflectorMethod, ForgeBlock_getLightOpacity, "getTargetMethod") == null) { Object new_ForgeBlock_getLightOpacity = UtilsLW.construct(ReflectorMethod, ForgeBlock, "getLightOpacity", new Class[]{