55import net .minecraft .launchwrapper .Launch ;
66import net .minecraft .launchwrapper .LaunchClassLoader ;
77import ofdev .common .Utils ;
8+ import org .objectweb .asm .ClassReader ;
9+ import org .objectweb .asm .ClassWriter ;
10+ import org .objectweb .asm .Opcodes ;
11+ import org .objectweb .asm .tree .AbstractInsnNode ;
12+ import org .objectweb .asm .tree .ClassNode ;
13+ import org .objectweb .asm .tree .InsnNode ;
14+ import org .objectweb .asm .tree .IntInsnNode ;
15+ import org .objectweb .asm .tree .MethodInsnNode ;
16+ import org .objectweb .asm .tree .MethodNode ;
817
918import java .io .File ;
1019import java .io .IOException ;
1120import java .io .UncheckedIOException ;
12- import java .nio . file . FileVisitResult ;
13- import java .nio . file . FileVisitor ;
14- import java .nio . file . Files ;
21+ import java .net . JarURLConnection ;
22+ import java .net . URISyntaxException ;
23+ import java .net . URL ;
1524import java .nio .file .Path ;
1625import java .nio .file .Paths ;
17- import java .nio .file .attribute .BasicFileAttributes ;
1826import java .util .List ;
1927import java .util .Set ;
28+ import java .util .zip .ZipFile ;
2029
2130// this is needed only in dev environment to get deobfuscated version of OptiFine running
2231public class OptifineDevTweakerWrapper implements ITweaker {
2332
2433 // this requires the jar to be loaded by FML before OptiFine, the easiest way to do it is to name it aa_SomeJar
25- public static final Class <?> OF_TRANSFORMER_LAUNCH_CLASSLOADER = UtilsLW .loadClassLW ("optifine.OptiFineClassTransformer" );
34+ public static final Class <?> OF_TRANSFORMER_LAUNCH_CLASSLOADER ;
35+
36+ static {
37+ Launch .classLoader .registerTransformer ("ofdev.launchwrapper.OptifineDevTweakerWrapper$OptiFineTransformerTransformer" );
38+ OF_TRANSFORMER_LAUNCH_CLASSLOADER = UtilsLW .loadClassLW ("optifine.OptiFineClassTransformer" );
39+ }
40+
41+ public static class OptiFineTransformerTransformer implements IClassTransformer {
42+ @ Override public byte [] transform (String name , String transformedName , byte [] basicClass ) {
43+ if (name != null && name .equals ("optifine.OptiFineClassTransformer" )) {
44+ ClassReader cr = new ClassReader (basicClass );
45+ ClassNode cn = new ClassNode ();
46+ cr .accept (cn , 0 );
47+ for (MethodNode method : cn .methods ) {
48+ if (method .name .equals ("<init>" )) {
49+ AbstractInsnNode insn = null ;
50+ for (int i = 0 ; i < method .instructions .size (); i ++) {
51+ insn = method .instructions .get (i );
52+ if (insn .getOpcode () == Opcodes .INVOKESPECIAL ) {
53+ break ;
54+ }
55+ }
56+ IntInsnNode loadThis = new IntInsnNode (Opcodes .ALOAD , 0 );
57+ MethodInsnNode initOptiTransformer = new MethodInsnNode (Opcodes .INVOKESTATIC ,
58+ "ofdev/launchwrapper/OptifineDevTweakerWrapper" ,
59+ "initOptiTransformer" , "(Ljava/lang/Object;)V" , false );
60+ method .instructions .insert (insn , loadThis );
61+ method .instructions .insert (loadThis , initOptiTransformer );
62+ method .instructions .insert (initOptiTransformer , new InsnNode (Opcodes .RETURN ));
63+ }
64+ }
65+ ClassWriter cw = new ClassWriter (ClassWriter .COMPUTE_FRAMES | ClassWriter .COMPUTE_MAXS );
66+ cn .accept (cw );
67+ return cw .toByteArray ();
68+ }
69+ return basicClass ;
70+ }
71+ }
72+
73+ public static void initOptiTransformer (Object ofTransformer ) {
74+ OptifineDevTransformerWrapper .ofTransformer = (IClassTransformer ) ofTransformer ;
75+ try {
76+ Class <? extends IClassTransformer > ofTransformerClass =
77+ (Class <? extends IClassTransformer >) OptifineDevTweakerWrapper .OF_TRANSFORMER_LAUNCH_CLASSLOADER ;
78+
79+ URL ofUrl = ofTransformer .getClass ().getProtectionDomain ().getCodeSource ().getLocation ();
80+
81+ JarURLConnection connection = (JarURLConnection ) ofUrl .openConnection ();
82+ ZipFile file = new ZipFile (new File (connection .getJarFileURL ().toURI ()));
83+ UtilsLW .setFieldValue (ofTransformerClass , "ofZipFile" , ofTransformer , file );
84+
85+ Class <?> ofPatcher = Launch .classLoader .findClass ("optifine.Patcher" );
86+
87+ Object patchMapVal = UtilsLW .invokeMethod (ofPatcher , null , "getConfigurationMap" , file );
88+ Object patternsVal = UtilsLW .invokeMethod (ofPatcher , null , "getConfigurationPatterns" , patchMapVal );
89+
90+ UtilsLW .setFieldValue (ofTransformerClass , "patchMap" , ofTransformer , patchMapVal );
91+ UtilsLW .setFieldValue (ofTransformerClass , "patterns" , ofTransformer , patternsVal );
92+ //System.out.println("Ignore the above, OptiFine should run anyway");
93+ UtilsLW .setFieldValue (ofTransformer .getClass (), "instance" , null , ofTransformer );
94+
95+ } catch (IOException | URISyntaxException | ClassNotFoundException e ) {
96+ throw new RuntimeException (e );
97+ }
98+ }
99+
26100 public static Path CLASS_DUMP_LOCATION ;
27101
28102 @ Override public void acceptOptions (List <String > args , File gameDir , File assetsDir , String profile ) {
@@ -56,12 +130,6 @@ public class OptifineDevTweakerWrapper implements ITweaker {
56130 Set <String > transformerExceptions =
57131 UtilsLW .getFieldValue (LaunchClassLoader .class , Launch .classLoader , "transformerExceptions" );
58132 transformerExceptions .removeIf (t -> t .startsWith ("optifine" ));
59-
60- // OptiFine tweaker constructed new instance of optifine transformer, so it changed it's instance field
61- // now that OptiFine tweaker setup is done,fix it
62- Object ofTransformer = OptifineDevTransformerWrapper .ofTransformer ;
63- UtilsLW .setFieldValue (ofTransformer .getClass (), "instance" , null , ofTransformer );
64-
65133 return new String [0 ];
66134 }
67135}
0 commit comments