aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java
blob: a5d5c1dfb598cefd8b16fc7681c75716a1d590d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package moe.nea.firmament.init;

import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.chunk.SectionCompiler;
import net.minecraft.client.renderer.block.model.BlockStateModel;
import net.minecraft.core.BlockPos;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;

public class SectionBuilderRiser extends RiserUtils {

	Intermediary.InterClass SectionBuilder = Intermediary.<SectionCompiler>intermediaryClass();
	Intermediary.InterClass BlockPos = Intermediary.<BlockPos>intermediaryClass();
	Intermediary.InterClass BlockRenderManager = Intermediary.<BlockRenderDispatcher>intermediaryClass();
	Intermediary.InterClass BlockState = Intermediary.<BlockState>intermediaryClass();
	Intermediary.InterClass BlockStateModel = Intermediary.<BlockStateModel>intermediaryClass();
	String CustomBlockTextures = "moe.nea.firmament.features.texturepack.CustomBlockTextures";

	Intermediary.InterMethod getModel =
		Intermediary.intermediaryMethod(
			net.minecraft.client.renderer.block.BlockRenderDispatcher::getBlockModel,
			BlockStateModel,
			BlockState
		);

	@Override
	public void addTinkerers() {
		if (FabricLoader.getInstance().isModLoaded("fabric-renderer-indigo"))
			addTransformation(SectionBuilder, this::handle, true);
	}

	private void handle(ClassNode classNode) {
		System.out.println("AVAST! "+ getModel);
		for (MethodNode method : classNode.methods) {
			if ((method.name.endsWith("$fabric-renderer-indigo$hookBuildRenderBlock")
			     || method.name.endsWith("$fabric-renderer-indigo$hookChunkBuildTessellate")) &&
			    method.name.startsWith("redirect$")) {
				handleIndigo(method);
				return;
			}
		}
		System.err.println("Could not inject indigo rendering hook. Is a custom renderer installed (e.g. sodium)?");
	}

	private void handleIndigo(MethodNode method) {
		LocalVariableNode blockPosVar = null, blockStateVar = null;
		for (LocalVariableNode localVariable : method.localVariables) {
			if (Type.getType(localVariable.desc).equals(BlockPos.mapped())) {
				blockPosVar = localVariable;
			}
			if (Type.getType(localVariable.desc).equals(BlockState.mapped())) {
				blockStateVar = localVariable;
			}
		}
		if (blockPosVar == null || blockStateVar == null) {
			System.err.println("Firmament could inject into indigo: missing either block pos or blockstate");
			return;
		}
		for (AbstractInsnNode instruction : method.instructions) {
			if (instruction.getOpcode() != Opcodes.INVOKEVIRTUAL) continue;
			var methodInsn = (MethodInsnNode) instruction;
			if (!(methodInsn.name.equals(getModel.mapped()) &&
				Type.getObjectType(methodInsn.owner).equals(BlockRenderManager.mapped())))
				continue;
			method.instructions.insertBefore(
				methodInsn,
				new MethodInsnNode(
					Opcodes.INVOKESTATIC,
					getTypeForClassName(CustomBlockTextures).getInternalName(),
					"enterFallbackCall",
					Type.getMethodDescriptor(Type.VOID_TYPE)
				));

			var insnList = new InsnList();
			insnList.add(new MethodInsnNode(
				Opcodes.INVOKESTATIC,
				getTypeForClassName(CustomBlockTextures).getInternalName(),
				"exitFallbackCall",
				Type.getMethodDescriptor(Type.VOID_TYPE)
			));
			insnList.add(new VarInsnNode(Opcodes.ALOAD, blockPosVar.index));
			insnList.add(new VarInsnNode(Opcodes.ALOAD, blockStateVar.index));
			insnList.add(new MethodInsnNode(
				Opcodes.INVOKESTATIC,
				getTypeForClassName(CustomBlockTextures).getInternalName(),
				"patchIndigo",
				Type.getMethodDescriptor(
					(BlockStateModel).mapped(),
					(BlockStateModel).mapped(),
					(BlockPos).mapped(),
					(BlockState).mapped()),
				false
			));
			method.instructions.insert(methodInsn, insnList);
		}
	}
}