Package keepcalm.mods.events.asm.transformers.events

Source Code of keepcalm.mods.events.asm.transformers.events.BlockEventHelpers

package keepcalm.mods.events.asm.transformers.events;

import java.util.HashMap;
import java.util.Iterator;


import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
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.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.VarInsnNode;

import cpw.mods.fml.relauncher.IClassTransformer;

public class BlockEventHelpers implements IClassTransformer {

  private HashMap<String,String> names;


  //private static final String itemInWorldUpdateDamageDesc = "()V"; unused

  public BlockEventHelpers() {
    names = ObfuscationHelper.getRelevantMappings();

  }

 

  @Override
  public byte[] transform(String name, byte[] bytes) {
    if (name.equalsIgnoreCase(names.get("itemStack_className"))) {
      return transformItemStack(bytes, names);
    }
    else if (name.equalsIgnoreCase(names.get("itemInWorldManager_className"))) {
      return transformItemInWorldManager(bytes, names);
    }
    else if (name.equalsIgnoreCase(names.get("block_className"))) {
      return transformBlock(bytes, names);
    }
    else if (name.equalsIgnoreCase(names.get("blockDispenser_className"))) {
      return transformDispenser(bytes, names);
    }
    else if (name.equalsIgnoreCase(names.get("blockFlowing_className"))) {
      return transformBlockFlowing(bytes);
    }
    else if (name.equalsIgnoreCase(names.get("blockPressurePlate_className"))) {
      return transformBlockPressurePlate(bytes);
    }
    else if (name.equalsIgnoreCase(names.get("netServerHandler_className"))) {
      return transformNetServerHandler(bytes);
    }

    return bytes;
  }
 
  private byte[] transformNetServerHandler(byte[] bytes) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);
   
    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();
   
    while (methods.hasNext()) {
      MethodNode m = methods.next();
     
      if (m.name.equals(names.get("netServerHandler_handleUpdateSign_func")) && m.desc.equals(names.get("netServerHandler_handleUpdateSign_desc"))) {
        System.out.println("Found target method in NetServerHandler: " + m.name + m.desc);
       
        InsnList insns = new InsnList();
        insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
        insns.add(new VarInsnNode(Opcodes.ALOAD, 1));
        insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onSignChange", "(L" + names.get("netServerHandler_javaName") + ";L" + names.get("packet130UpdateSign_javaName") + ";)L" + names.get("packet130UpdateSign_javaName") + ";" ));
        LabelNode endIf = new LabelNode(new Label());
        insns.add(new VarInsnNode(Opcodes.ASTORE, 1));
        insns.add(new VarInsnNode(Opcodes.ALOAD, 1));
        insns.add(new JumpInsnNode(Opcodes.IFNONNULL, endIf));
        insns.add(new InsnNode(Opcodes.RETURN));
        insns.add(endIf);
       
        m.instructions.insert(insns);
      }
    }
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }

 
  // second IFNE from the end
  private byte[] transformBlockPressurePlate(byte[] bytes) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);
   
    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();
   
    while (methods.hasNext()) {
      MethodNode m = methods.next();
     
      if (m.name.equals(names.get("blockPressurePlate_setStateIfMobInteractsWithPlate_func")) && m.desc.equals("blockPressurePlate_setStateIfMobInteractsWithPlate_desc")) {
        System.out.println("Found target method within BlockPressurePlate: " + m.name + m.desc);
        int ifnes = 0;
        for (int i = m.instructions.size() - 1; i >= 0; i--) {
         
          if (m.instructions.get(i).getOpcode() == Opcodes.IFNE) {
            ifnes++;
            if (ifnes == 2) {
              // insert!
              i++;
              System.out.println("Found second IFNE node from the end, inserting code...");
              InsnList insns = new InsnList();
             
              insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
              insns.add(new VarInsnNode(Opcodes.ALOAD, 1));
              insns.add(new VarInsnNode(Opcodes.ILOAD, 2));
              insns.add(new VarInsnNode(Opcodes.ILOAD, 3));
              insns.add(new VarInsnNode(Opcodes.ILOAD, 4));
              insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper",
                  "onPressurePlateInteract", "(L" + names.get("blockPressurePlate_javaName") + ";L" + names.get("world_javaName") + ";III)Z"));
              LabelNode endIf = new LabelNode(new Label());
              insns.add(new JumpInsnNode(Opcodes.IFEQ, endIf));
              insns.add(new InsnNode(Opcodes.RETURN));
              insns.add(endIf);
              insns.add(new LabelNode(new Label()));
             
              m.instructions.insertBefore(m.instructions.get(i), insns);
             
            }
          }
         
        }
       
       
      }
    }
   
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }
 
  /* UNUSED ATM
  private byte[] transformBlockFire(byte[] bytes, HashMap<String, String> names) {
   
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);
   
    /*Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();
      if (m.name.equals(names.get("blockFireTargName")) && m.desc.equals(names.get("blockFireTargDesc"))) {
        System.out.println("Found target method: " + m.name + m.desc +"!");
       
      }
    } * /
   
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
   
  }*/
 
  private byte[] transformBlockFlowing(byte[] bytes) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn,  0);
   
   
    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();
     
      if (m.name.equals(names.get("blockFlowing_updateFlow_func")) &&m.desc.equals(names.get("blockFlowing_updateFlow_func"))) {
        System.out.println("Found target method: " + m.name + m.desc + "!");
       
       
        InsnList toAdd = new InsnList();
       
        toAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
        toAdd.add(new VarInsnNode(Opcodes.ALOAD, 1));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 2));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 3));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 4));///
        toAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC,
            "keepcalm/mods/events/ForgeEventHelper", "onBlockFlow",
            "(L" + names.get("block_javaName") + ";L" + names.get("world_javaName") + ";III)Z"));
        LabelNode endIf = new LabelNode(new Label());
        toAdd.add(new JumpInsnNode(Opcodes.IFEQ, endIf));
        toAdd.add(new InsnNode(Opcodes.RETURN));
        toAdd.add(endIf);
        toAdd.add(new LabelNode(new Label()));
       
        m.instructions.add(toAdd);
    }
     
    }
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }
 
  private byte[] transformBlock(byte[] bytes, HashMap<String,String> names) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);
   
    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();
     
      if (m.name.equals(names.get("block_breakBlock_func")) && m.desc.equals(names.get("block_breakBlock_desc"))) {
        System.out.println("Found global block break call: " + m.name + m.desc );
       
        InsnList toAdd = new InsnList();
       
        LabelNode lmmnode = new LabelNode(new Label());
       
        toAdd.add(new VarInsnNode(Opcodes.ALOAD, 1));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 2));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 3));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 4));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 5));
        toAdd.add(new VarInsnNode(Opcodes.ILOAD, 6));
        toAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onBlockBreak", "(L" + names.get("world_javaName") + ";IIIII)V"));
        toAdd.add(lmmnode);
        // insert at the beginning
        m.instructions.insert(toAdd);
        System.out.println("Inserted instructions!");
        // done!
        break;
      }
    }
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }
 
  private byte[] transformDispenser(byte[] bytes, HashMap<String, String> names) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);


    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();
      if (m.name.equals(names.get("blockDispenser_dispense_func")) && m.desc.equals(names.get("blockDispenser_dispense_desc"))) {
        System.out.println("Found target method: " + m.name + m.desc + "! Looking for landmark...");

        @SuppressWarnings("unchecked")
        Iterator<AbstractInsnNode> insns = m.instructions.iterator();

        while (insns.hasNext()) {
          AbstractInsnNode i = insns.next();

          if (i.getOpcode() == Opcodes.GETSTATIC && i.getNext().getOpcode() == Opcodes.IF_ACMPEQ) {
            System.out.println("Found insertion point - GETSTATIC followed by IF_ACMPEQ!");
            FieldInsnNode f = (FieldInsnNode) i;
            System.out.println("Does " + f.owner + " equal " + names.get("blockDispenser_JavaName") + "?");



            System.out.println("Found landmark! Inserting code...");
            InsnList toAdd = new InsnList();

            // mark end of our code
            LabelNode lmmnode = new LabelNode(new Label());
            // we want 1, 2, 3, 4, 8 - world, x, y, z, ItemStack
            toAdd.add(new VarInsnNode(Opcodes.ALOAD, 1));
            toAdd.add(new VarInsnNode(Opcodes.ILOAD, 2));
            toAdd.add(new VarInsnNode(Opcodes.ILOAD, 3));
            toAdd.add(new VarInsnNode(Opcodes.ILOAD, 4));
            toAdd.add(new VarInsnNode(Opcodes.ALOAD, 8));
            toAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onDispenseItem",
                "(L" + names.get("world_javaName") + ";IIIL" + names.get("itemStack_javaName") + ";)Z"));

            LabelNode endLabel = new LabelNode(new Label());
            toAdd.add(new JumpInsnNode(Opcodes.IFEQ, endLabel)); // if the return value of ^ is true
            // then return - it was cancelled - and so will not be run
            toAdd.add(new InsnNode(Opcodes.RETURN));
            toAdd.add(endLabel); // otherwise, continue on
            toAdd.add(lmmnode);

            System.out.println("Instructions have been compiled, adding to bytecode...");

            m.instructions.insertBefore(i.getNext(), toAdd);

            System.out.println("Finished patching BlockDispenser!");

            break;
          }
        }
      }
    }



    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }

  private byte[] transformItemStack(byte[] bytes, HashMap<String,String> names) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);
    //int idx = 0;
    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();
      //System.out.println("Method: " + m.name + " Desc: " + m.desc + "(wanted desc: " + itemStackTryPlaceDesc);
      if (m.name.equals(names.get("itemStack_tryPlace_func")) && m.desc.equals("itemStack_tryPlace_desc")) {
        System.out.println("Found target method: " + m.name + m.desc + "! Finding the last instruction!");

        //boolean found = false;
        System.out.println("Processing " + m.instructions.size() + " instructions...");
        for (int index = 0; index < m.instructions.size(); index++) {
          AbstractInsnNode instr = m.instructions.get(index);

          //System.out.println("Processing INSN at " + index +
          // " of type " + m.instructions.get(index).getType() +
          // ", OpCode " + m.instructions.get(index).getOpcode());

          // return integer (or boolean), load integer (or boolean)
          if (instr.getOpcode() == Opcodes.ILOAD && instr.getPrevious().getOpcode() == Opcodes.IRETURN) {
            System.out.println("Found IRETURN after ILOAD, inserting code before...");
            index++;
            InsnList toInject = new InsnList();
            /*toInject.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
            toInject.add(new VarInsnNode(Opcodes.ALOAD, 0));
            toInject.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V"));
            toInject.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
            toInject.add(new VarInsnNode(Opcodes.ALOAD, 1));
            toInject.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V"));*/
            LabelNode lmmnode = new LabelNode(new Label());
            // this
            toInject.add(new VarInsnNode(Opcodes.ALOAD, 0));
            // entityplayer
            toInject.add(new VarInsnNode(Opcodes.ALOAD, 1));
            // world
            toInject.add(new VarInsnNode(Opcodes.ALOAD, 2));
            // x y z direction
            toInject.add(new VarInsnNode(Opcodes.ILOAD, 3));
            toInject.add(new VarInsnNode(Opcodes.ILOAD, 4));
            toInject.add(new VarInsnNode(Opcodes.ILOAD, 5));
            toInject.add(new VarInsnNode(Opcodes.ILOAD, 6));
            toInject.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper", "onItemUse", String.format("(L%s;L%s;L%s;IIII)V", new Object[] {names.get("itemStack_javaName"), names.get("entityPlayer_javaName"), names.get("world_javaName")})));
            toInject.add(lmmnode);
            m.instructions.insertBefore(m.instructions.get(index), toInject);
            //System.out.println("Used desc: " + String.format("(L%s;L%s;L%s;IIII)V", new Object[] {names.get("itemStackJavaName"), names.get("entityPlayerJavaName"), names.get("worldJavaName")}));
            System.out.println("Finished patching ItemStack! - Inserted before " + index + ", toInject: " + toInject);
            break;
          }
        }

        //idx++;
      }

    }


    ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(writer);
    return writer.toByteArray();
  }

  private byte[] transformItemInWorldManager(byte[] bytes, HashMap<String,String> names) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);

    String targ = names.get("itemInWorldManager_updateBlockRemoving_func");

    @SuppressWarnings("unchecked")
    Iterator<MethodNode> methods = cn.methods.iterator();

    while (methods.hasNext()) {
      MethodNode m = methods.next();

      if (m.name.equals(targ) && m.desc.equals(names.get("itemInWorldManager_updateBlockRemoving_desc"))) {
        System.out.println("Found target for ItemInWorldManager transformation: " + m.name + m.desc + "! Searching for landmarks...");

        boolean seen = true;
        int occ = 0;
        for (int index = 0; index < m.instructions.size(); index++) {
          AbstractInsnNode instr = m.instructions.get(index);

          if (instr.getOpcode() == Opcodes.RETURN) {
            System.out.println("Found landmark: RETURN, searching for previous landmark...");
            int ifloc = index;
            while (m.instructions.get(index).getOpcode() != Opcodes.IF_ICMPEQ) index--;
            System.out.println("Found IF_ICMPEQ at index " + index + " to R, which is at " + ifloc + ". Inserting function call after this...");
            int loc = index + 1;
            System.out.println("Will insert code at: " + loc);
            // after, not at the same location
            LabelNode lmmnode = new LabelNode(new Label());

            InsnList toInject = new InsnList();

            // load 'this'
            toInject.add(new VarInsnNode(Opcodes.ALOAD, 0));
            // call the helper method
            System.out.println("Using desc: " + "(L" + names.get("itemInWorldManager_javaName") + ";)V");
            toInject.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "keepcalm/mods/events/ForgeEventHelper",
                "onBlockDamage", "(L" + names.get("itemInWorldManager_javaName") + ";)Z"));
            LabelNode endIf = new LabelNode(new Label());
            toInject.add(new JumpInsnNode(Opcodes.IFEQ, endIf));
            toInject.add(new InsnNode(Opcodes.RETURN));
            toInject.add(endIf);
            toInject.add(lmmnode);
            System.out.println("Finished compiling instruction nodes, inserting new instructions... at " + loc);

            m.instructions.insertBefore(m.instructions.get(index + 1), toInject);
            /*for (int i1 = 0; i1 < m.instructions.size(); i1++) {
              System.out.println("Location " + i1 + ": " + m.instructions.get(i1).getClass().getName());
              if (m.instructions.get(i1) instanceof MethodInsnNode) {
                MethodInsnNode x = (MethodInsnNode) m.instructions.get(i1);
                System.out.println("Location " + i1 + ": " + x.owner + "/" + x.name + x.desc);
              }
              else if (m.instructions.get(i1) instanceof LineNumberNode) {
                LineNumberNode x = (LineNumberNode) m.instructions.get(i1);
                System.out.println("Location " + i1 + ": Line " + x.line);
              }
            }*/
            //MethodInsnNode x = (MethodInsnNode) m.instructions.get(249);
            System.out.println("Finished patching ItemInWorldManager! The game will now continue!");
            break;
          }
          else if (instr.getOpcode() == Opcodes.PUTFIELD && instr.getPrevious().getOpcode() == Opcodes.ILOAD && ((VarInsnNode)instr.getPrevious()).var == 3 && instr.getNext() instanceof LabelNode && !seen) {
            occ++;
            if (occ > 0) seen = true;

            System.out.println("Found first occurance of misbehaving segment, ignoring...");
          }

        }


      }
    }


    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }

}
TOP

Related Classes of keepcalm.mods.events.asm.transformers.events.BlockEventHelpers

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.