Skip to content

Commit 2ab2713

Browse files
authored
Stops draw/startDrawing in ISBRH (#1759)
1 parent 7cf652c commit 2ab2713

4 files changed

Lines changed: 155 additions & 8 deletions

File tree

src/main/java/com/gtnewhorizons/angelica/loading/fml/compat/CompatHandlers.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import com.gtnewhorizons.angelica.loading.fml.compat.handlers.ThaumicHorizonsCompatHandler;
99

1010
import java.util.ArrayList;
11-
import java.util.Collections;
1211
import java.util.List;
1312
import java.util.function.Supplier;
1413

@@ -45,20 +44,19 @@ public static List<ICompatHandler> getHandlers() {
4544

4645
/**
4746
* Returns extra transformers as well as the main transformer.
48-
* Returns an empty list if no handlers registered.
4947
*/
5048
public static List<String> getTransformers() {
5149
final List<ICompatHandler> handlers = getHandlers();
52-
if (handlers.isEmpty()) {
53-
return Collections.emptyList();
54-
}
55-
List<String> transformers = new ArrayList<>();
50+
List<String> transformers = new ArrayList<>();
5651
for (ICompatHandler handler : handlers) {
5752
if (handler.extraTransformers() != null) {
5853
transformers.addAll(handler.extraTransformers());
5954
}
6055
}
61-
transformers.add("com.gtnewhorizons.angelica.loading.fml.transformers.GenericCompatTransformer");
56+
if (!handlers.isEmpty()) {
57+
transformers.add("com.gtnewhorizons.angelica.loading.fml.transformers.GenericCompatTransformer");
58+
}
59+
transformers.add("com.gtnewhorizons.angelica.loading.fml.transformers.IsbrhTessellatorAbuseClassTransformer");
6260
return transformers;
6361
}
6462
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.gtnewhorizons.angelica.loading.fml.transformers;
2+
3+
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
4+
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
5+
import net.minecraft.launchwrapper.IClassTransformer;
6+
import org.apache.logging.log4j.LogManager;
7+
import org.apache.logging.log4j.Logger;
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.MethodInsnNode;
15+
import org.objectweb.asm.tree.MethodNode;
16+
17+
public class IsbrhTessellatorAbuseClassTransformer implements IClassTransformer {
18+
private static final Logger LOGGER = LogManager.getLogger("IsbrhTessellatorAbuse");
19+
private static final String ISBRH = "cpw/mods/fml/client/registry/ISimpleBlockRenderingHandler";
20+
private static final String TESSELLATOR = "net/minecraft/client/renderer/Tessellator";
21+
private static final String RENDER_WORLD_BLOCK_DESC = "(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;ILnet/minecraft/client/renderer/RenderBlocks;)Z";
22+
23+
private final String draw;
24+
private final String startDrawingQuads;
25+
private final String startDrawing;
26+
27+
public IsbrhTessellatorAbuseClassTransformer() {
28+
this(AngelicaClientTweaker.isObfEnv());
29+
}
30+
31+
public IsbrhTessellatorAbuseClassTransformer(boolean isObf) {
32+
this.draw = isObf ? "func_78381_a" : "draw";
33+
this.startDrawingQuads = isObf ? "func_78382_b" : "startDrawingQuads";
34+
this.startDrawing = isObf ? "func_78371_b" : "startDrawing";
35+
}
36+
37+
public boolean shouldTransform(byte[] classBytes) {
38+
final ClassReader cr = new ClassReader(classBytes);
39+
for (String iface : cr.getInterfaces()) {
40+
if (ISBRH.equals(iface)) return true;
41+
}
42+
return false;
43+
}
44+
45+
public boolean transformClassNode(String transformedName, ClassNode cn) {
46+
boolean changed = false;
47+
for (MethodNode mn : cn.methods) {
48+
if (!"renderWorldBlock".equals(mn.name) || !RENDER_WORLD_BLOCK_DESC.equals(mn.desc)) continue;
49+
50+
for (AbstractInsnNode insn : mn.instructions.toArray()) {
51+
if (!(insn instanceof MethodInsnNode min) || min.getOpcode() != Opcodes.INVOKEVIRTUAL || !TESSELLATOR.equals(min.owner)) continue;
52+
53+
final int popOp;
54+
final boolean pushIntResult;
55+
if (min.name.equals(draw) && "()I".equals(min.desc)) {
56+
popOp = Opcodes.POP;
57+
pushIntResult = true;
58+
} else if (min.name.equals(startDrawingQuads) && "()V".equals(min.desc)) {
59+
popOp = Opcodes.POP;
60+
pushIntResult = false;
61+
} else if (min.name.equals(startDrawing) && "(I)V".equals(min.desc)) {
62+
popOp = Opcodes.POP2;
63+
pushIntResult = false;
64+
} else {
65+
continue;
66+
}
67+
68+
mn.instructions.insertBefore(insn, new InsnNode(popOp));
69+
if (pushIntResult) mn.instructions.insertBefore(insn, new InsnNode(Opcodes.ICONST_0));
70+
mn.instructions.remove(insn);
71+
LOGGER.info("Stripped Tessellator.{} from {}#renderWorldBlock", min.name, cn.name);
72+
changed = true;
73+
}
74+
}
75+
return changed;
76+
}
77+
78+
@Override
79+
public byte[] transform(String name, String transformedName, byte[] basicClass) {
80+
if (basicClass == null || !shouldTransform(basicClass)) return basicClass;
81+
82+
final ClassReader cr = new ClassReader(basicClass);
83+
final ClassNode cn = new ClassNode();
84+
cr.accept(cn, 0);
85+
if (!transformClassNode(transformedName, cn)) return basicClass;
86+
87+
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
88+
cn.accept(cw);
89+
final byte[] bytes = cw.toByteArray();
90+
AngelicaClassDump.dumpClass(transformedName, basicClass, bytes, this);
91+
return bytes;
92+
}
93+
}

src/main/java/com/gtnewhorizons/angelica/loading/rfb/AngelicaRfbPlugin.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.gtnewhorizons.angelica.loading.rfb.transformers.RFBAngelicaRedirector;
44
import com.gtnewhorizons.angelica.loading.rfb.transformers.RFBCeleritasBlockTransformer;
5+
import com.gtnewhorizons.angelica.loading.rfb.transformers.RFBIsbrhTessellatorAbuseTransformer;
56
import com.gtnewhorizons.retrofuturabootstrap.api.PluginContext;
67
import com.gtnewhorizons.retrofuturabootstrap.api.RetroFuturaBootstrap;
78
import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer;
@@ -28,7 +29,8 @@ public void onConstruction(@NotNull PluginContext ctx) {
2829
final boolean isObf = RetroFuturaBootstrap.API.launchClassLoader().findClassMetadata("net.minecraft.world.World") == null;
2930
return new RfbClassTransformer[] {
3031
new RFBAngelicaRedirector(),
31-
new RFBCeleritasBlockTransformer(isObf)
32+
new RFBCeleritasBlockTransformer(isObf),
33+
new RFBIsbrhTessellatorAbuseTransformer(isObf)
3234
};
3335
}
3436
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.gtnewhorizons.angelica.loading.rfb.transformers;
2+
3+
import com.gtnewhorizons.angelica.loading.fml.transformers.IsbrhTessellatorAbuseClassTransformer;
4+
import com.gtnewhorizons.angelica.loading.shared.AngelicaClassDump;
5+
import com.gtnewhorizons.retrofuturabootstrap.api.ClassNodeHandle;
6+
import com.gtnewhorizons.retrofuturabootstrap.api.ExtensibleClassLoader;
7+
import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer;
8+
import org.intellij.lang.annotations.Pattern;
9+
import org.jetbrains.annotations.NotNull;
10+
import org.jetbrains.annotations.Nullable;
11+
12+
import java.util.jar.Manifest;
13+
14+
/** RfbClassTransformer wrapper for {@link IsbrhTessellatorAbuseClassTransformer} */
15+
public class RFBIsbrhTessellatorAbuseTransformer implements RfbClassTransformer {
16+
private final IsbrhTessellatorAbuseClassTransformer inner;
17+
18+
public RFBIsbrhTessellatorAbuseTransformer(boolean isObf) {
19+
inner = new IsbrhTessellatorAbuseClassTransformer(isObf);
20+
}
21+
22+
@Pattern("[a-z0-9-]+")
23+
@Override
24+
public @NotNull String id() {
25+
return "isbrh-tessellator-abuse";
26+
}
27+
28+
@Override
29+
public @NotNull String @Nullable [] sortAfter() {
30+
return new String[] {"*", "mixin:mixin"};
31+
}
32+
33+
@Override
34+
public @NotNull String @Nullable [] sortBefore() {
35+
return new String[] {"lwjgl3ify:redirect"};
36+
}
37+
38+
@Override
39+
public boolean shouldTransformClass(@NotNull ExtensibleClassLoader classLoader,
40+
@NotNull RfbClassTransformer.Context context, @Nullable Manifest manifest, @NotNull String className,
41+
@NotNull ClassNodeHandle classNode) {
42+
if (!classNode.isPresent()) return false;
43+
return inner.shouldTransform(classNode.getOriginalBytes());
44+
}
45+
46+
@Override
47+
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
48+
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
49+
if (inner.transformClassNode(className, classNode.getNode())) {
50+
classNode.computeMaxs();
51+
AngelicaClassDump.dumpRFBClass(className, classNode, this);
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)