Skip to content

Commit

Permalink
TransformerTransformer to transform the transformer
Browse files Browse the repository at this point in the history
No more exception spam on load
  • Loading branch information
Barteks2x committed Jan 2, 2022
1 parent 5cd9c42 commit 6e27e4a
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 44 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
1 change: 0 additions & 1 deletion src/main/java/ofdev/launchwrapper/OptifineDevRemapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,43 +72,16 @@ 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);
}
}

private static final OptifineDevRemapper remapper = OptifineDevRemapper.NOTCH_MCP;


public static IClassTransformer ofTransformer;

{
try {
Class<? extends IClassTransformer> ofTransformerClass =
(Class<? extends IClassTransformer>) 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;
Expand Down
90 changes: 79 additions & 11 deletions src/main/java/ofdev/launchwrapper/OptifineDevTweakerWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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("<init>")) {
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<? extends IClassTransformer> ofTransformerClass =
(Class<? extends IClassTransformer>) 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<String> args, File gameDir, File assetsDir, String profile) {
Expand Down Expand Up @@ -56,12 +130,6 @@ public class OptifineDevTweakerWrapper implements ITweaker {
Set<String> 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];
}
}
12 changes: 9 additions & 3 deletions src/main/java/ofdev/launchwrapper/UtilsLW.java
Original file line number Diff line number Diff line change
Expand Up @@ -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[]{
Expand Down

0 comments on commit 6e27e4a

Please sign in to comment.