aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java
blob: 3222a911473e40a4d24a116cf33321acf1eda7f1 (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
/*
 * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

package moe.nea.firmament.init;

import me.shedaniel.mm.api.ClassTinkerers;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;

import java.lang.reflect.Modifier;

public class HandledScreenRiser extends RiserUtils {
    String Screen = remapper.mapClassName("intermediary", "net.minecraft.class_437");
    String HandledScreen = remapper.mapClassName("intermediary", "net.minecraft.class_465");
    Type mouseScrolledDesc = Type.getMethodType(Type.BOOLEAN_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE);
    String mouseScrolled = remapper.mapMethodName("intermediary", "net.minecraft.class_364", "method_25401",
                                                  mouseScrolledDesc.getDescriptor());

    @Override
    public void addTinkerers() {
        ClassTinkerers.addTransformation(HandledScreen, this::handle);
    }

    void handle(ClassNode classNode) {
        MethodNode mouseScrolledNode = findMethod(classNode, mouseScrolled, mouseScrolledDesc);
        if (mouseScrolledNode == null) {
            mouseScrolledNode = new MethodNode(
                Modifier.PUBLIC,
                mouseScrolled,
                mouseScrolledDesc.getDescriptor(),
                null,
                new String[0]
            );
            var insns = mouseScrolledNode.instructions;
            // ALOAD 0, load this
            insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
            // DLOAD 1-4, load the 4 argument doubles. Note that since doubles are two entries wide we skip 2 each time.
            insns.add(new VarInsnNode(Opcodes.DLOAD, 1));
            insns.add(new VarInsnNode(Opcodes.DLOAD, 3));
            insns.add(new VarInsnNode(Opcodes.DLOAD, 5));
            insns.add(new VarInsnNode(Opcodes.DLOAD, 7));
            // INVOKESPECIAL call super method
            insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, getTypeForClassName(Screen).getInternalName(), mouseScrolled, mouseScrolledDesc.getDescriptor()));
            // IRETURN return int on stack (booleans are int at runtime)
            insns.add(new InsnNode(Opcodes.IRETURN));
            classNode.methods.add(mouseScrolledNode);
        }

        var insns = new InsnList();
        // ALOAD 0, load this
        insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
        // DLOAD 1-4, load the 4 argument doubles. Note that since doubles are two entries wide we skip 2 each time.
        insns.add(new VarInsnNode(Opcodes.DLOAD, 1));
        insns.add(new VarInsnNode(Opcodes.DLOAD, 3));
        insns.add(new VarInsnNode(Opcodes.DLOAD, 5));
        insns.add(new VarInsnNode(Opcodes.DLOAD, 7));
        // INVOKEVIRTUAL call custom handler
        insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
                                     getTypeForClassName(HandledScreen).getInternalName(),
                                     "mouseScrolled_firmament",
                                     mouseScrolledDesc.getDescriptor()));
        // Create jump target (but not insert it yet)
        var jumpIfFalse = new LabelNode();
        // IFEQ (if returned boolean == 0), jump to jumpIfFalse
        insns.add(new JumpInsnNode(Opcodes.IFEQ, jumpIfFalse));
        // LDC 1 (as int, which is what booleans are at runtime)
        insns.add(new LdcInsnNode(1));
        // IRETURN return int on stack (booleans are int at runtime)
        insns.add(new InsnNode(Opcodes.IRETURN));
        insns.add(jumpIfFalse);
        mouseScrolledNode.instructions.insert(insns);
    }

}