package me.kcm; import java.util.ListIterator; import me.kcm.events.*; import net.minecraft.launchwrapper.IClassTransformer; import net.minecraftforge.fml.common.asm.transformers.DeobfuscationTransformer; import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; 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.FrameNode; 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.LineNumberNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; public class KajetansTransformer implements IClassTransformer { private void printPatch(Class c) { System.out.println("|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"); System.out.println("| Patching " + c.getSimpleName()); System.out.println("|___________________________________________________"); } @Override public byte[] transform(String old, String searge, byte[] bytes) { switch(searge) { case "net.minecraft.entity.EntityLivingBase": printPatch(LivingDamageCalculationEvent.class); return patchDamageHook(old, bytes, !old.equals(searge)); case "net.minecraft.entity.player.EntityPlayerMP": printPatch(PlayerTabListNameEvent.class); return patchTabList(old, bytes, !old.equals(searge)); case "net.minecraft.entity.Entity": printPatch(FarmlandTrampleEvent.class); return patchEntityCanTrample(old, bytes, !old.equals(searge)); case "net.minecraft.server.management.PlayerList": printPatch(PlayerConnectionEvent.class); return patchPlayerList(old, bytes, !old.equals(searge)); } return bytes; } /*ListIterator list = ins.iterator(); while(list.hasNext()) { AbstractInsnNode next = list.next(); System.out.println(getString(next)); }*/ public byte[] patchDamageHook(String c, byte[] bytes, boolean obfuscated) { try { ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); // EntityLivingBase <--> vp // damageEntity <--> func_70665_d <--> d MethodNode mn; if(obfuscated) { mn = classNode.methods.stream().filter(me -> me.name.equals("d")).filter(me -> "(Lur;F)V".equals(me.desc)).findAny().get(); } else { mn = classNode.methods.stream().filter(me -> me.name.equals("damageEntity")).findAny().get(); } InsnList ins = mn.instructions; ins.insert(ins.get(3), new VarInsnNode(Opcodes.FLOAD, 2)); if(obfuscated) { ins.insert(ins.get(4), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onDamageCalculation", "(Lvp;Lur;F)V", false)); } else { ins.insert(ins.get(4), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onDamageCalculation", "(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/util/DamageSource;F)V", false)); } while(ins.size() > 8) { ins.remove(ins.get(6)); } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } catch(Exception ex) { ex.printStackTrace(); } return bytes; } public byte[] patchTabList(String c, byte[] bytes, boolean obfuscated) { try { ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); // EntityPlayerMP <--> oq // getTabListDisplayName <--> func_175396_E <--> K // MD: oq/K ()Lhh; net/minecraft/entity/player/EntityPlayerMP/func_175396_E ()Lnet/minecraft/util/text/ITextComponent; MethodNode mn; if(obfuscated) { mn = classNode.methods.stream().filter(me -> me.name.equals("K")).filter(me -> "()Lhh;".equals(me.desc)).findAny().get(); } else { mn = classNode.methods.stream().filter(me -> me.name.equals("getTabListDisplayName")).findAny().get(); } InsnList ins = mn.instructions; ins.remove(ins.get(2)); ins.insert(ins.get(1), new VarInsnNode(Opcodes.ALOAD, 0)); if(obfuscated) { ins.insert(ins.get(2), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onGetTabListDisplayName", "(Loq;)Lhh;", false)); } else { ins.insert(ins.get(2), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onGetTabListDisplayName", "(Lnet/minecraft/entity/player/EntityPlayerMP;)Lnet/minecraft/util/text/ITextComponent;", false)); } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } catch(Exception ex) { ex.printStackTrace(); } return bytes; } public byte[] patchEntityCanTrample(String c, byte[] bytes, boolean obfuscated) { try { ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); // CL: vg net/minecraft/entity/Entity // Entity <--> vg // canTrample is forge function // Lnet/minecraft/world/World;Lnet/minecraft/block/Block;Lnet/minecraft/util/math/BlockPos;F // World <--> amu // Block <--> aow // BlockPos <--> et MethodNode mn = classNode.methods.stream().filter(me -> me.name.equals("canTrample")).findAny().get(); InsnList ins = mn.instructions; int i = ins.size(); LabelNode label = null; int counter = 0; while(counter < 3) { i--; if(ins.get(i) instanceof LabelNode) { counter++; label = (LabelNode) ins.get(i); } } while(ins.get(i).getOpcode() != Opcodes.IFLE) { i--; } ins.insert(ins.get(i), new JumpInsnNode(Opcodes.IFEQ, label)); if(obfuscated) { ins.insert(ins.get(i), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onEntityCanTrample", "(Lvg;Lamu;Laow;Let;F)Z", false)); } else { ins.insert(ins.get(i), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onEntityCanTrample", "(Lnet/minecraft/entity/Entity;Lnet/minecraft/world/World;" + "Lnet/minecraft/block/Block;Lnet/minecraft/util/math/BlockPos;F)Z", false)); } ins.insert(ins.get(i), new VarInsnNode(Opcodes.FLOAD, 4)); ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 3)); ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 2)); ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 1)); ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 0)); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } catch(Exception ex) { ex.printStackTrace(); } return bytes; } public byte[] patchPlayerList(String c, byte[] bytes, boolean obfuscated) { try { ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); // EntityPlayerMP <--> oq // initializeConnectionToPlayer <--> func_72355_a <--> a //MD: pl/a (Lgw;Loq;)V net/minecraft/server/management/PlayerList/func_72355_a // (Lnet/minecraft/network/NetworkManager;Lnet/minecraft/entity/player/EntityPlayerMP;)V // CL: pa net/minecraft/network/NetHandlerPlayServer // public void initializeConnectionToPlayer(NetworkManager netManager, EntityPlayerMP playerIn, NetHandlerPlayServer nethandlerplayserver) // its something else: (Lgw;Loq;Lpa;)V // it seems forge is already overwriting this method MethodNode mn = classNode.methods.stream().filter(me -> me.name.equals("initializeConnectionToPlayer")).findAny().get(); InsnList ins = mn.instructions; int index = 0; AbstractInsnNode node; // first part - inserting PlayerConnectionEvent hook // connection <--> field_71135_a <--> a // FD: oq/a net/minecraft/entity/player/EntityPlayerMP/field_71135_a String search = obfuscated ? "a" : "connection"; String playerOwner = obfuscated ? "oq" : "net/minecraft/entity/player/EntityPlayerMP"; boolean found = false; while(index < ins.size()) { node = ins.get(index); if(node instanceof FieldInsnNode) { FieldInsnNode field = (FieldInsnNode) node; if(field.name.equals(search) && field.owner.equals(playerOwner)) { found = true; break; } } index++; } if(!found) { System.out.println("Start of player connection was not found"); return bytes; } if(obfuscated) { ins.insert(ins.get(index), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onPlayerConnection", "(Loq;)V", false)); } else { ins.insert(ins.get(index), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onPlayerConnection", "(Lnet/minecraft/entity/player/EntityPlayerMP;)V", false)); } ins.insert(ins.get(index), new VarInsnNode(Opcodes.ALOAD, 2)); // end of first part - inserting PlayerConnectionEvent hook // second part - removing join message // func_70005_c_ // MD: aed/h_ ()Ljava/lang/String; net/minecraft/entity/player/EntityPlayer/func_70005_c_ ()Ljava/lang/String; String start = "equalsIgnoreCase"; String startDesc = "(Ljava/lang/String;)Z"; // func_148539_a // MD: pl/a (Lhh;)V net/minecraft/server/management/PlayerList/func_148539_a (Lnet/minecraft/util/text/ITextComponent;)V String end = obfuscated ? "a" : "sendMessage"; String endDesc = obfuscated ? "(Lhh;)V" : "(Lnet/minecraft/util/text/ITextComponent;)V"; found = false; while(index < ins.size()) { node = ins.get(index); if(node instanceof MethodInsnNode) { MethodInsnNode mnode = (MethodInsnNode) node; if(mnode.name.equals(start) && mnode.desc.equals(startDesc)) { found = true; break; } } index++; } if(!found) { System.out.println("Start of player join message was not found"); return bytes; } // moving to real start of the block "p.getName()..." index -= 3; while(true) { node = ins.get(index); if(node instanceof MethodInsnNode) { MethodInsnNode mnode = (MethodInsnNode) node; if(mnode.name.equals(end) && mnode.desc.equals(endDesc)) { ins.remove(node); break; } } ins.remove(node); } // End of second Part - Removing join message ListIterator list = ins.iterator(); while(list.hasNext()) { AbstractInsnNode next = list.next(); System.out.println(getString(next)); } ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } catch(Exception ex) { ex.printStackTrace(); } return bytes; } public String getString(AbstractInsnNode node) { StringBuilder sb = new StringBuilder(); sb.append(node.getClass().getSimpleName()); sb.append(" "); sb.append(node.getOpcode()); sb.append(" "); sb.append(node.getType()); sb.append(" "); if(node instanceof LineNumberNode) { LineNumberNode n = (LineNumberNode) node; sb.append(n.line); sb.append(" "); sb.append(n.start); } else if(node instanceof VarInsnNode) { VarInsnNode n = (VarInsnNode) node; sb.append(n.var); } else if(node instanceof MethodInsnNode) { MethodInsnNode n = (MethodInsnNode) node; sb.append(n.desc); sb.append(" "); sb.append(n.itf); sb.append(" "); sb.append(n.name); sb.append(" "); sb.append(n.owner); } else if(node instanceof FrameNode) { FrameNode n = (FrameNode) node; if(n.local != null) { n.local.forEach(s -> {sb.append(s); sb.append(" ");}); } if(n.stack != null) { n.stack.forEach(s -> {sb.append(s); sb.append(" ");}); } } else if(node instanceof InsnNode) { } else if(node instanceof FieldInsnNode) { FieldInsnNode n = (FieldInsnNode) node; sb.append(n.desc); sb.append(" "); sb.append(n.name); sb.append(" "); sb.append(n.owner); } return sb.toString(); } }