de.sanandrew.core.manpack.transformer.TransformEntityCollision.java Source code

Java tutorial

Introduction

Here is the source code for de.sanandrew.core.manpack.transformer.TransformEntityCollision.java

Source

/*******************************************************************************************************************
 * Authors:   SanAndreasP
 * Copyright: SanAndreasP
 * License:   Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
 *                http://creativecommons.org/licenses/by-nc-sa/4.0/
 *******************************************************************************************************************/
package de.sanandrew.core.manpack.transformer;

import net.minecraft.launchwrapper.IClassTransformer;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;

public class TransformEntityCollision implements IClassTransformer {
    @Override
    public byte[] transform(String name, String transformedName, byte[] bytes) {
        if ("net.minecraft.world.World".equals(transformedName)) {
            return transformWorld(bytes);
        }

        if ("net.minecraft.entity.Entity".equals(transformedName)) {
            return transformEntity(bytes);
        }

        return bytes;
    }

    private static byte[] transformEntity(byte[] bytes) {
        ClassNode clazz = ASMHelper.createClassNode(bytes);

        MethodNode method = ASMHelper.getMethodNode(Opcodes.ACC_PUBLIC, ASMNames.MD_SAP_ENTITY_GET_BOUNDING_BOX);
        method.visitCode();
        Label l0 = new Label();
        method.visitLabel(l0);
        method.visitVarInsn(Opcodes.ALOAD, 2);
        method.visitInsn(Opcodes.ARETURN);
        Label l1 = new Label();
        method.visitLabel(l1);
        method.visitLocalVariable("this", ASMNames.CL_T_ENTITY, null, l0, l1, 0);
        method.visitLocalVariable("entity", ASMNames.CL_T_ENTITY, null, l0, l1, 1);
        method.visitLocalVariable("oldAABB", ASMNames.CL_T_AXIS_ALIGNED_BB, null, l0, l1, 2);
        method.visitMaxs(1, 2);
        method.visitEnd();

        clazz.methods.add(method);

        bytes = ASMHelper.createBytes(clazz, /*ClassWriter.COMPUTE_FRAMES |*/ ClassWriter.COMPUTE_MAXS);
        return bytes;
    }

    private static byte[] transformWorld(byte[] bytes) {
        ClassNode clazz = ASMHelper.createClassNode(bytes);
        MethodNode method = ASMHelper.findMethod(clazz, ASMNames.MD_WORLD_GET_COLLIDING_BB);

        InsnList needle = new InsnList();
        LabelNode ln = new LabelNode();
        needle.add(ln);
        needle.add(new LineNumberNode(-1, ln));
        needle.add(new VarInsnNode(Opcodes.ALOAD, 0));
        needle.add(new VarInsnNode(Opcodes.ALOAD, 1));
        needle.add(new VarInsnNode(Opcodes.ALOAD, 2));
        needle.add(new VarInsnNode(Opcodes.DLOAD, -1));
        needle.add(new VarInsnNode(Opcodes.DLOAD, -1));
        needle.add(new VarInsnNode(Opcodes.DLOAD, -1));
        needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_AABB_EXPAND, false));
        needle.add(
                ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_WORLD_GET_ENTITIES_EXCLUDE, false));
        needle.add(new VarInsnNode(Opcodes.ASTORE, -1));

        VarInsnNode insertPoint = (VarInsnNode) ASMHelper.findLastNodeFromNeedle(method.instructions, needle);

        InsnList injectList = new InsnList();
        injectList.add(new LabelNode());
        injectList.add(ASMHelper.getFieldInsnNode(Opcodes.GETSTATIC, ASMNames.FD_SAPUTILS_EVENT_BUS));
        injectList.add(new TypeInsnNode(Opcodes.NEW, ASMNames.CL_COLLIDING_ENTITY_CHECK_EVENT));
        injectList.add(new InsnNode(Opcodes.DUP));
        injectList.add(new VarInsnNode(Opcodes.ALOAD, 0));
        injectList.add(new VarInsnNode(Opcodes.ALOAD, insertPoint.var));
        injectList.add(new VarInsnNode(Opcodes.ALOAD, 1));
        injectList.add(new VarInsnNode(Opcodes.ALOAD, 2));
        injectList.add(
                ASMHelper.getMethodInsnNode(Opcodes.INVOKESPECIAL, ASMNames.MD_SAP_COLLENTITYCHKEVT_INIT, false));
        injectList.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_EVENT_BUS_POST, false));
        injectList.add(new InsnNode(Opcodes.POP));

        method.instructions.insert(insertPoint, injectList);

        // insert entity-sensitive bounding box method

        needle = new InsnList();
        ln = new LabelNode();
        needle.add(ln);
        needle.add(new LineNumberNode(-1, ln));
        needle.add(new VarInsnNode(Opcodes.ALOAD, 11));
        needle.add(new VarInsnNode(Opcodes.ILOAD, 12));
        needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEINTERFACE, ASMNames.MD_LIST_GET, true));
        needle.add(new TypeInsnNode(Opcodes.CHECKCAST, ASMNames.CL_ENTITY));
        needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_ENTITY_GET_BOUNDING_BOX, false));
        needle.add(new VarInsnNode(Opcodes.ASTORE, -1));

        insertPoint = (VarInsnNode) ASMHelper.findLastNodeFromNeedle(method.instructions, needle);

        injectList = new InsnList();
        injectList.add(new LabelNode());
        injectList.add(new VarInsnNode(Opcodes.ALOAD, 11));
        injectList.add(new VarInsnNode(Opcodes.ILOAD, 12));
        injectList.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEINTERFACE, ASMNames.MD_LIST_GET, true));
        injectList.add(new TypeInsnNode(Opcodes.CHECKCAST, ASMNames.CL_ENTITY));
        injectList.add(new VarInsnNode(Opcodes.ALOAD, 1));
        injectList.add(new VarInsnNode(Opcodes.ALOAD, insertPoint.var));
        injectList.add(
                ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_SAP_ENTITY_GET_BOUNDING_BOX, false));
        injectList.add(new VarInsnNode(Opcodes.ASTORE, insertPoint.var));

        method.instructions.insert(insertPoint, injectList);

        bytes = ASMHelper.createBytes(clazz, /*ClassWriter.COMPUTE_FRAMES |*/ ClassWriter.COMPUTE_MAXS);

        return bytes;
    }
}