package zmaster587.advancedRocketry.asm;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
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.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
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.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import zmaster587.advancedRocketry.AdvancedRocketry;
import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraft.launchwrapper.Launch;
public class ClassTransformer implements IClassTransformer {
private static final String CLASS_KEY_ENTITYRENDERER = "net.minecraft.client.renderer.EntityRenderer";
private static final String CLASS_KEY_ENTITYLIVEINGBASE = "net.minecraft.entity.EntityLivingBase";
private static final String CLASS_KEY_ENTITYLIVINGRENDERER = "net.minecraft.client.renderer.entity.RenderLivingEntity";
private static final String CLASS_KEY_ENTITY = "net.minecraft.entity.Entity";
private static final String CLASS_KEY_ENTITY_PLAYER_SP = "net.minecraft.client.entity.EntityPlayerSP";
private static final String CLASS_KEY_ENTITY_PLAYER_MP = "net.minecraft.client.entity.EntityPlayerMP";
private static final String CLASS_KEY_ENTITY_PLAYER = "net.minecraft.entity.player.EntityPlayer";
private static final String CLASS_KEY_ENTITY_ITEM = "net.minecraft.entity.EntityItem";
private static final String CLASS_KEY_NETHANDLERPLAYSERVER = "net.minecraft.network.NetHandlerPlayServer";
private static final String CLASS_KEY_C03PACKETPLAYER = "net.minecraft.network.play.client.C03PacketPlayer";
private static final String CLASS_KEY_WORLD = "net.minecraft.world.World";
private static final String CLASS_KEY_BLOCK = "net.minecraft.block.Block";
private static final String CLASS_KEY_BLOCK_BED = "net.minecraft.block.BlockBed";
private static final String CLASS_KEY_WORLDPROVIDER = "net.minecraft.world.WorldProvider";
private static final String METHOD_KEY_PROCESSPLAYER = "processPlayer";
private static final String METHOD_KEY_JUMP = "jump";
private static final String METHOD_KEY_MOVEENTITY = "moveEntity";
private static final String METHOD_KEY_SETPOSITION = "setPosition";
private static final String METHOD_KEY_MOUNTENTITY = "mountEntity";
private static final String METHOD_KEY_ONLIVINGUPDATE = "net.minecraft.client.entity.EntityPlayerSP.onLivingUpdate";
private static final String METHOD_KEY_ONUPDATE = "net.minecraft.client.entity.Entity.onUpdate";
private static final String METHOD_KEY_GETLOOKVEC = "net.minecraft.entity.EntityLivingBase.getLookVec";
private static final String METHOD_KEY_DORENDER = "net.minecraft.client.renderer.entity.RenderLivingEntity.doRender";
private static final String METHOD_KEY_MOVEENTITYWITHHEADING = "net.minecraft.entity.EntityLivingBase.moveEntityWithHeading";
private static final String METHOD_KEY_MOVEFLYING = "net.minecraft.entity.Entity.moveFlying";
private static final String METHOD_KEY_SETBLOCK = CLASS_KEY_WORLD + ".setBlock";
private static final String METHOD_KEY_SETBLOCKMETADATAWITHNOTIFY = CLASS_KEY_WORLD + ".setBlockMetadataWithNotify";
private static final String METHOD_KEY_ONBLOCKACTIVATED = CLASS_KEY_BLOCK + "onBlockActivated";
private static final String FIELD_YAW = "net.minecraft.client.renderer.EntityRenderer.rotationYaw";
private static final String FIELD_PITCH = "net.minecraft.client.renderer.EntityRenderer.rotationPitch";
private static final String FIELD_PREV_YAW = "net.minecraft.client.renderer.EntityRenderer.prevRotationYaw";
private static final String FIELD_PREV_PITCH = "net.minecraft.client.renderer.EntityRenderer.prevRotationPitch";
private static final String FIELD_PLAYERENTITY = "net.minecraft.network.NetHandlerPlayServer.playerEntity";
private static final String FIELD_HASMOVED = "net.minecraft.network.NetHandlerPlayServer.hasMoved";
private static final String FIELD_RIDINGENTITY = "net.minecraft.entity.Entity.ridingEntity";
private static final String FIELD_PROVIDER = CLASS_KEY_WORLD + "provider";
private static final HashMap<String, SimpleEntry<String, String>> entryMap = new HashMap<String, SimpleEntry<String, String>>();
private static boolean obf;
/*private class ClassEntry {
String name, obfName, desc;
public ClassEntry(String name, String obfName, String desc) {
this.name = name;
this.obfName = obfName;
this.desc = desc;
}
public String getObfName() {return obfName; }
public String getDeobfName() {return name; }
public String getDesc() {return desc;}
}*/
public ClassTransformer() {
obf = !(boolean)Launch.blackboard.get("fml.deobfuscatedEnvironment");
//TODO: obf names
entryMap.put(CLASS_KEY_ENTITYRENDERER, new SimpleEntry<String, String>("net/minecraft/client/renderer/EntityRenderer", "blt"));
entryMap.put(CLASS_KEY_ENTITYLIVEINGBASE, new SimpleEntry<String, String>("net/minecraft/entity/EntityLivingBase", "sv"));
entryMap.put(CLASS_KEY_ENTITYLIVINGRENDERER, new SimpleEntry<String, String>("net/minecraft/client/renderer/entity/RendererLivingEntity", ""));
entryMap.put(CLASS_KEY_ENTITY, new SimpleEntry<String, String>("net/minecraft/entity/Entity","sa"));
entryMap.put(CLASS_KEY_ENTITY_PLAYER_SP, new SimpleEntry<String, String>("net/minecraft/client/entity/EntityPlayerSP",""));
entryMap.put(CLASS_KEY_ENTITY_PLAYER_MP, new SimpleEntry<String, String>("net/minecraft/entity/player/EntityPlayerMP",""));
entryMap.put(CLASS_KEY_ENTITY_PLAYER, new SimpleEntry<String, String>("net/minecraft/entity/player/EntityPlayer","yz"));
entryMap.put(CLASS_KEY_ENTITY_ITEM, new SimpleEntry<String, String>("net/minecraft/entity/item/EntityItem","xk"));
entryMap.put(CLASS_KEY_NETHANDLERPLAYSERVER, new SimpleEntry<String, String>("net/minecraft/network/NetHandlerPlayServer",""));
entryMap.put(CLASS_KEY_C03PACKETPLAYER, new SimpleEntry<String, String>("net/minecraft/network/play/client/C03PacketPlayer",""));
entryMap.put(CLASS_KEY_WORLD, new SimpleEntry<String, String>("net/minecraft/world/World","ahb"));
entryMap.put(CLASS_KEY_BLOCK, new SimpleEntry<String, String>("net/minecraft/block/Block","aji"));
entryMap.put(CLASS_KEY_BLOCK_BED, new SimpleEntry<String, String>("net/minecraft/block/BlockBed","ajh"));
entryMap.put(CLASS_KEY_WORLDPROVIDER, new SimpleEntry<String, String>("net/minecraft/world/WorldProvider","aqo"));
entryMap.put(METHOD_KEY_PROCESSPLAYER, new SimpleEntry<String, String>("processPlayer",""));
entryMap.put(METHOD_KEY_MOVEENTITY, new SimpleEntry<String, String>("moveEntity",""));
entryMap.put(METHOD_KEY_SETPOSITION, new SimpleEntry<String, String>("setPosition",""));
entryMap.put(METHOD_KEY_GETLOOKVEC, new SimpleEntry<String, String>("getLook", ""));
entryMap.put(METHOD_KEY_DORENDER, new SimpleEntry<String, String>("doRender",""));
entryMap.put(METHOD_KEY_MOVEENTITYWITHHEADING, new SimpleEntry<String, String>("moveEntityWithHeading","e"));
entryMap.put(METHOD_KEY_MOVEFLYING, new SimpleEntry<String, String>("moveFlying",""));
entryMap.put(METHOD_KEY_ONLIVINGUPDATE, new SimpleEntry<String, String>("onLivingUpdate","e"));
entryMap.put(METHOD_KEY_ONUPDATE, new SimpleEntry<String, String>("onUpdate","h"));
entryMap.put(METHOD_KEY_MOUNTENTITY, new SimpleEntry<String, String>("mountEntity", "a"));
entryMap.put(METHOD_KEY_JUMP, new SimpleEntry<String, String>("jump",""));
entryMap.put(METHOD_KEY_SETBLOCK, new SimpleEntry<String, String>("setBlock", "d"));
entryMap.put(METHOD_KEY_SETBLOCKMETADATAWITHNOTIFY, new SimpleEntry<String, String>("setBlockMetadataWithNotify", "a"));
entryMap.put(METHOD_KEY_ONBLOCKACTIVATED, new SimpleEntry<String, String>("onBlockActivated", "a"));
entryMap.put(FIELD_YAW, new SimpleEntry<String, String>("rotationYaw", "blt"));
entryMap.put(FIELD_PITCH, new SimpleEntry <String, String>("rotationPitch", "blt"));
entryMap.put(FIELD_PREV_YAW, new SimpleEntry<String, String>("prevRotationYaw", "blt"));
entryMap.put(FIELD_PREV_PITCH, new SimpleEntry<String, String>("prevRotationPitch", "blt"));
entryMap.put(FIELD_PLAYERENTITY, new SimpleEntry<String, String>("playerEntity", ""));
entryMap.put(FIELD_HASMOVED, new SimpleEntry<String, String>("hasMoved", ""));
entryMap.put(FIELD_RIDINGENTITY, new SimpleEntry<String,String>("ridingEntity", "m"));
entryMap.put(FIELD_PROVIDER, new SimpleEntry<String,String>("provider", "t"));
}
@Override
public byte[] transform(String name, String transformedName,
byte[] bytes) {
//Vanilla deobf
String changedName = name.replace('.','/');
//Need to override setPosition to fix bounding boxes
/*if(changedName.equals(getName(CLASS_KEY_NETHANDLERPLAYSERVER))) {
ClassNode cn = startInjection(bytes);
MethodNode processPlayer = getMethod(cn, "setPlayerLocation", "(DDDFF)V");
if(processPlayer != null ) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
for (int i = processPlayer.instructions.size()-1; i > 0; i--) {
AbstractInsnNode ain = processPlayer.instructions.get(i);
if(ain.getOpcode() == Opcodes.ALOAD) {
pos = ain;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_NETHANDLERPLAYSERVER), getName(FIELD_PLAYERENTITY), "L" + getName(CLASS_KEY_ENTITY_PLAYER_MP) + ";"));
nodeAdd.add(new VarInsnNode(Opcodes.DLOAD, 1));
nodeAdd.add(new VarInsnNode(Opcodes.DLOAD, 3));
nodeAdd.add(new VarInsnNode(Opcodes.DLOAD, 5));
nodeAdd.add(new VarInsnNode(Opcodes.FLOAD, 7));
nodeAdd.add(new VarInsnNode(Opcodes.FLOAD, 8));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_NETHANDLERPLAYSERVER), getName(FIELD_PLAYERENTITY), "L" + getName(CLASS_KEY_ENTITY_PLAYER_MP) + ";"));
nodeAdd.add(new TypeInsnNode(Opcodes.CHECKCAST, getName(CLASS_KEY_ENTITYLIVEINGBASE)));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "netHandlerSetPlayerLocation", "(L" + getName(CLASS_KEY_ENTITY_PLAYER_MP) + ";DDDFFI)V", false));
nodeAdd.add(new InsnNode(Opcodes.RETURN));
processPlayer.instructions.insertBefore(processPlayer.instructions.getFirst(), nodeAdd);
}
return finishInjection(cn);
}
if(changedName.equals(getName(CLASS_KEY_ENTITY))) {
ClassNode cn = startInjection(bytes);
MethodNode setPosition = getMethod(cn, getName(METHOD_KEY_SETPOSITION), "(DDD)V");
if(setPosition != null) {
final InsnList nodeAdd = new InsnList();
final LabelNode jumpNode = new LabelNode();
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new TypeInsnNode(Opcodes.INSTANCEOF, getName(CLASS_KEY_ENTITYLIVEINGBASE)));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, jumpNode));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new TypeInsnNode(Opcodes.CHECKCAST, getName(CLASS_KEY_ENTITYLIVEINGBASE)));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new TypeInsnNode(Opcodes.CHECKCAST, getName(CLASS_KEY_ENTITYLIVEINGBASE)));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new VarInsnNode(Opcodes.DLOAD, 1));
nodeAdd.add(new VarInsnNode(Opcodes.DLOAD, 3));
nodeAdd.add(new VarInsnNode(Opcodes.DLOAD, 5));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "setPosition", "(L" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";IDDD)V", false));
nodeAdd.add(jumpNode);
setPosition.instructions.insertBefore(setPosition.instructions.getLast().getPrevious(), nodeAdd);
}
return finishInjection(cn);
}
if(changedName.equals(getDeobfName(CLASS_KEY_ENTITY_PLAYER_SP))) {
ClassNode cn = startInjection(bytes);
MethodNode onLivingUpdate = getMethod(cn, getName(METHOD_KEY_ONLIVINGUPDATE), "()V");
if(onLivingUpdate != null)
{
final InsnList nodeAdd = new InsnList();
final LabelNode label = new LabelNode();
final LabelNode endOfInvokeLabel = new LabelNode();
AbstractInsnNode pos = null;
AbstractInsnNode gotoPos = null;
int eqnum = 13;
for (int i = 0; i < onLivingUpdate.instructions.size(); i++) {
AbstractInsnNode ain = onLivingUpdate.instructions.get(i);
if(ain.getOpcode() == Opcodes.IFEQ && eqnum-- == 0) {
pos = ain;
for(i=i+1, eqnum = 4; i < onLivingUpdate.instructions.size(); i++) {
//eqnum = 2;
ain = onLivingUpdate.instructions.get(i);
if(ain.getOpcode() == Opcodes.ALOAD && eqnum-- == 0) {
gotoPos = ain;
break;
}
}
break;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, endOfInvokeLabel));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "moveFlyingVerticalOverride", "(L" + getName(CLASS_KEY_ENTITY_PLAYER_SP) + ";I)V", false));
nodeAdd.add(new JumpInsnNode(Opcodes.GOTO, label));
nodeAdd.add(endOfInvokeLabel);
onLivingUpdate.instructions.insert(pos, nodeAdd);
onLivingUpdate.instructions.insertBefore(gotoPos, label);
}
return finishInjection(cn);
}
if(changedName.equals(getDeobfName(CLASS_KEY_ENTITYLIVINGRENDERER))) {
ClassNode cn = startInjection(bytes);
MethodNode doRender = getMethod(cn, getName(METHOD_KEY_DORENDER), "(L" + getName(CLASS_KEY_ENTITYLIVEINGBASE)+";DDDFF)V");
if(doRender != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
int eqnum = 2;
for (int i = 0; i < doRender.instructions.size(); i++) {
AbstractInsnNode ain = doRender.instructions.get(i);
if(ain.getOpcode() == Opcodes.IFEQ && eqnum-- == 0) {
for(i = i - 1; i > 0; i--) {
ain = doRender.instructions.get(i);
if(ain.getOpcode() == Opcodes.FSTORE) {
pos = ain;
break;
}
}
break;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 1));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 1));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformEntity", "(IL" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";)V", false));
doRender.instructions.insert(pos, nodeAdd);
}
return finishInjection(cn);
}
if(changedName.equals(getDeobfName(CLASS_KEY_ENTITYLIVEINGBASE))) {
ClassNode cn = startInjection(bytes);
MethodNode moveFlying = new MethodNode(Opcodes.ACC_PUBLIC, getName(METHOD_KEY_MOVEFLYING), "(FFF)V", null, null);
MethodNode moveEntity = new MethodNode(Opcodes.ACC_PUBLIC, getName(METHOD_KEY_MOVEENTITY), "(DDD)V", null, null);
MethodNode setPosition = new MethodNode(Opcodes.ACC_PUBLIC, getName(METHOD_KEY_SETPOSITION), "(DDD)V", null, null);
//Add need to override setPosition in entitybase to fix collision boxes
final InsnList moveEntityNode = new InsnList();
final LabelNode jumpToMoveEntity = new LabelNode();
final LabelNode jumpToEndEntity = new LabelNode();
moveEntityNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveEntityNode.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
moveEntityNode.add(new JumpInsnNode(Opcodes.IFNE, jumpToMoveEntity));
moveEntityNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveEntityNode.add(new VarInsnNode(Opcodes.DLOAD, 1));
moveEntityNode.add(new VarInsnNode(Opcodes.DLOAD, 3));
moveEntityNode.add(new VarInsnNode(Opcodes.DLOAD, 5));
moveEntityNode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, getName(CLASS_KEY_ENTITY), getName(METHOD_KEY_MOVEENTITY), "(DDD)V", false));
moveEntityNode.add(new JumpInsnNode(Opcodes.GOTO, jumpToEndEntity));
moveEntityNode.add(jumpToMoveEntity);
moveEntityNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveEntityNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveEntityNode.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
moveEntityNode.add(new VarInsnNode(Opcodes.DLOAD, 1));
moveEntityNode.add(new VarInsnNode(Opcodes.DLOAD, 3));
moveEntityNode.add(new VarInsnNode(Opcodes.DLOAD, 5));
moveEntityNode.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "moveEntity", "(L" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";IDDD)V", false));
moveEntityNode.add(jumpToEndEntity);
moveEntityNode.add(new InsnNode(Opcodes.RETURN));
moveEntity.instructions.insert(moveEntityNode);
cn.methods.add(moveEntity);
//Add moveFlying methods nodes
final InsnList moveFlyingNode = new InsnList();
final LabelNode jumpTo = new LabelNode();
final LabelNode endJump = new LabelNode();
moveFlyingNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveFlyingNode.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
moveFlyingNode.add(new JumpInsnNode(Opcodes.IFNE, jumpTo));
moveFlyingNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveFlyingNode.add(new VarInsnNode(Opcodes.FLOAD, 1));
moveFlyingNode.add(new VarInsnNode(Opcodes.FLOAD, 2));
moveFlyingNode.add(new VarInsnNode(Opcodes.FLOAD, 3));
moveFlyingNode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, getName(CLASS_KEY_ENTITY), getName(METHOD_KEY_MOVEFLYING), "(FFF)V", false));
moveFlyingNode.add(new JumpInsnNode(Opcodes.GOTO, endJump));
moveFlyingNode.add(jumpTo);
moveFlyingNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveFlyingNode.add(new VarInsnNode(Opcodes.ALOAD, 0));
moveFlyingNode.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
moveFlyingNode.add(new VarInsnNode(Opcodes.FLOAD, 1));
moveFlyingNode.add(new VarInsnNode(Opcodes.FLOAD, 2));
moveFlyingNode.add(new VarInsnNode(Opcodes.FLOAD, 3));
moveFlyingNode.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "moveFlying", "(L" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";IFFF)V", false));
moveFlyingNode.add(endJump);
moveFlyingNode.add(new InsnNode(Opcodes.RETURN));
moveFlying.instructions.insert(moveFlyingNode);
cn.methods.add(moveFlying);
//End add moveFlying method nodes
cn.fields.add(new FieldNode(Opcodes.ACC_PUBLIC, "gravRotation", Type.INT_TYPE.getDescriptor(), "I", new Integer(1)));
//TODO: might break in obf
MethodNode constructor = getMethod(cn, "<init>", "(Lnet/minecraft/world/World;)V");
MethodNode getLook = getMethod(cn, getName(METHOD_KEY_GETLOOKVEC), "(F)Lnet/minecraft/util/Vec3;");
MethodNode moveEntityWithHeading = getMethod(cn, getName(METHOD_KEY_MOVEENTITYWITHHEADING), "(FF)V");
MethodNode jump = getMethod(cn, getName(METHOD_KEY_JUMP), "()V");
if(constructor != null) {
final InsnList nodeAdd = new InsnList();
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new InsnNode(Opcodes.ICONST_1));
nodeAdd.add(new FieldInsnNode(Opcodes.PUTFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
constructor.instructions.insertBefore(constructor.instructions.getLast(), nodeAdd);
}
if(jump != null) {
final InsnList nodeAdd = new InsnList();
LabelNode skipAddLabel = new LabelNode();
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, skipAddLabel));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "livingEntityJump", "(IL" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";)V", false));
nodeAdd.add(new InsnNode(Opcodes.RETURN));
nodeAdd.add(skipAddLabel);
jump.instructions.insertBefore(jump.instructions.getFirst(), nodeAdd);
}
if(moveEntityWithHeading != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null, endAssign = null;
LabelNode skipAddLabel = new LabelNode();
LabelNode endEdit = new LabelNode();
for (int i = moveEntityWithHeading.instructions.size()-1; i > 0; i--) {
AbstractInsnNode ain = moveEntityWithHeading.instructions.get(i);
if(ain.getOpcode() == Opcodes.GOTO) {
for( i = i + 1; i < moveEntityWithHeading.instructions.size(); i++) {
ain = moveEntityWithHeading.instructions.get(i);
if(ain.getOpcode() == Opcodes.ALOAD && pos == null) {
pos = ain;
}
if(ain.getOpcode() == Opcodes.PUTFIELD) {
endAssign = ain;
break;
}
}
break;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, skipAddLabel));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD,0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformGravity", "(IL" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";)V", false));
nodeAdd.add(new JumpInsnNode(Opcodes.GOTO, endEdit));
nodeAdd.add(skipAddLabel);
moveEntityWithHeading.instructions.insertBefore(pos, nodeAdd);
moveEntityWithHeading.instructions.insert(endAssign, endEdit);
}
//Make look direction consistent with transformed camera
if(getLook != null) {
final InsnList nodeAdd = new InsnList();
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new VarInsnNode(Opcodes.FLOAD, 1));
//TODO: might break in obf
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "createModifiedLookVector", "(L" + getName(CLASS_KEY_ENTITYLIVEINGBASE) +";IF)Lnet/minecraft/util/Vec3;", false));
nodeAdd.add(new InsnNode(Opcodes.ARETURN));
getLook.instructions.insertBefore(getLook.instructions.getFirst(), nodeAdd);
}
return finishInjection(cn);
}
//Transform Camera as needed
if(changedName.equals(getDeobfName(CLASS_KEY_ENTITYRENDERER))) {
ClassNode cn = startInjection(bytes);
//TODO: obfuscated names
MethodNode orientCamera = getMethod(cn, "orientCamera", "(F)V");
MethodNode updateCameraAndRender = getMethod(cn, "updateCameraAndRender", "(F)V");
if(orientCamera != null) {
final InsnList nodeAdd = new InsnList();
final InsnList nodeAdd2 = new InsnList();
final InsnList nodeAdd3 = new InsnList();
final InsnList nodeAdd4 = new InsnList();
AbstractInsnNode pos = null;
AbstractInsnNode pos2 = null;
int ifneNum = 1;
int invokeNum = 1;
AbstractInsnNode pos3 = null;
int gotoNum = 3;
for (int i = 0; i < orientCamera.instructions.size(); i++) {
AbstractInsnNode ain = orientCamera.instructions.get(i);
if (ain.getOpcode() == Opcodes.IFNE && ifneNum-- == 0) {
pos = ain;
}
if(pos != null && ain.getOpcode() == Opcodes.INVOKESTATIC && invokeNum-- == 0) {
pos2 = ain;
}
if (ain.getOpcode() == Opcodes.GOTO && gotoNum-- == 0) {
pos3 = ain;
}
}
LabelNode gotoLabel = new LabelNode();
LabelNode gotoLabel2 = new LabelNode();
nodeAdd.add(new FieldInsnNode(Opcodes.GETSTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "rotate", "Z"));
//nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 2));
//nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, gotoLabel2));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 2));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITYLIVEINGBASE), "gravRotation", "I"));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 2));
nodeAdd.add(new VarInsnNode(Opcodes.FLOAD,1));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformCamera2", "(IL" + getName(CLASS_KEY_ENTITYLIVEINGBASE) + ";F)V", false));
nodeAdd.add(new JumpInsnNode(Opcodes.GOTO, gotoLabel));
nodeAdd.add(gotoLabel2);
nodeAdd3.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformCamera", "()V", false));
nodeAdd4.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformCamera", "()V", false));
orientCamera.instructions.insertBefore(orientCamera.instructions.get(orientCamera.instructions.indexOf(pos3)), nodeAdd3);
orientCamera.instructions.insertBefore(orientCamera.instructions.get(orientCamera.instructions.indexOf(pos3)+8), nodeAdd4);
orientCamera.instructions.insertBefore(orientCamera.instructions.get(orientCamera.instructions.indexOf(pos)-4), nodeAdd);
orientCamera.instructions.insertBefore(orientCamera.instructions.get(orientCamera.instructions.indexOf(pos2)+1), gotoLabel);
//TODO: OVerride Entity.setAngles
//639
}
/*if(orientCamera != null) {
final InsnList nodeAdd = new InsnList();
final InsnList nodeAdd2 = new InsnList();
AbstractInsnNode pos = null;
int gotoNum = 3;
for (int i = 0; i < orientCamera.instructions.size(); i++) {
AbstractInsnNode ain = orientCamera.instructions.get(i);
if (ain.getOpcode() == Opcodes.GOTO && gotoNum-- == 0) {
pos = ain;
break;
}
}
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformCamera", "()V", false));
nodeAdd2.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformCamera", "()V", false));
orientCamera.instructions.insertBefore(orientCamera.instructions.get(orientCamera.instructions.indexOf(pos)), nodeAdd);
orientCamera.instructions.insertBefore(orientCamera.instructions.get(orientCamera.instructions.indexOf(pos)+8), nodeAdd2);
//TODO: OVerride Entity.setAngles
}
if(updateCameraAndRender != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
int fmulNum = 4;
for (int i = 0; i < updateCameraAndRender.instructions.size(); i++) {
AbstractInsnNode ain = updateCameraAndRender.instructions.get(i);
if (ain.getOpcode() == Opcodes.INVOKEVIRTUAL && fmulNum-- == 0) {
pos = ain;
break;
}
}
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/client/ClientHelper", "transformMouse", "()V", false));
updateCameraAndRender.instructions.insertBefore(updateCameraAndRender.instructions.get(updateCameraAndRender.instructions.indexOf(pos)+1), nodeAdd);
}
return finishInjection(cn);
}*/
/*
* from net.minecraft.entity.player.EntityPlayer
*
* public void mountEntity(Entity p_70078_1_)
* {
* if (this.ridingEntity != null && p_70078_1_ == null)
* {
* if (!this.worldObj.isRemote)
* {
* this.dismountEntity(this.ridingEntity);
* }
*
* if (this.ridingEntity != null)
* {
* //Begin insert
* if(this.ridingEntity instanceof IDismountHandler)
* this.ridingEntity.onDismount(this)
* return;
* //End Insert
* this.ridingEntity.riddenByEntity = null;
* }
*
* this.ridingEntity = null;
* }
* else
* {
* super.mountEntity(p_70078_1_);
* }
* }
* */
/*if(changedName.equals(getName(CLASS_KEY_ENTITY_PLAYER))) {
ClassNode cn = startInjection(bytes);
MethodNode mountEntityMethod = getMethod(cn, getName(METHOD_KEY_MOUNTENTITY), "(L"+ getName(CLASS_KEY_ENTITY) + ";)V");
if(mountEntityMethod != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
for(int i = mountEntityMethod.instructions.size() - 1; i >= 0; i--) {
AbstractInsnNode ain = mountEntityMethod.instructions.get(i);
if(ain.getOpcode() == Opcodes.IFNULL) {
pos = ain;
break;
}
}
if (pos == null) { //Thermos
// https://github.com/CyberdyneCC/Thermos/blob/master/patches/net/minecraft/entity/player/EntityPlayer.java.patch#L124
MethodNode mn = getMethod(cn, "setPassengerOf", "(L"+ getName(CLASS_KEY_ENTITY) + ";)V");
if (mn == null) return bytes;
AbstractInsnNode p = null;
int counter = 0;
for(int i = mountEntityMethod.instructions.size() - 1; i >= 0; i--) {
p = mountEntityMethod.instructions.get(i);
if(p.getOpcode() == Opcodes.IFNONNULL && ++counter==2) break;
}
LabelNode jL = new LabelNode();
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 2));
nodeAdd.add(new TypeInsnNode(Opcodes.INSTANCEOF, "zmaster587/libVulpes/api/IDismountHandler"));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, jL));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 2));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "zmaster587/libVulpes/api/IDismountHandler", "handleDismount", "(L" + getName(CLASS_KEY_ENTITY) + ";)V", true));
nodeAdd.add(new InsnNode(Opcodes.RETURN));
nodeAdd.add(jL);
mountEntityMethod.instructions.insert(p, nodeAdd);
return finishInjection(cn);
}
LabelNode jumpLabel = new LabelNode();
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITY), getName(FIELD_RIDINGENTITY), "L" + getName(CLASS_KEY_ENTITY) + ";"));
nodeAdd.add(new TypeInsnNode(Opcodes.INSTANCEOF, "zmaster587/libVulpes/api/IDismountHandler"));
nodeAdd.add(new JumpInsnNode(Opcodes.IFEQ, jumpLabel));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new FieldInsnNode(Opcodes.GETFIELD, getName(CLASS_KEY_ENTITY), getName(FIELD_RIDINGENTITY), "L" + getName(CLASS_KEY_ENTITY) + ";"));
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "zmaster587/libVulpes/api/IDismountHandler", "handleDismount", "(L" + getName(CLASS_KEY_ENTITY) + ";)V", true));
nodeAdd.add(new InsnNode(Opcodes.RETURN));
nodeAdd.add(jumpLabel);
mountEntityMethod.instructions.insert(pos, nodeAdd);
}
else
AdvancedRocketry.logger.severe("ASM injection into EntityPlayer.mountEntity FAILED!");
return finishInjection(cn);
}*/
if(changedName.equals(getName(CLASS_KEY_ENTITY_ITEM))) {
ClassNode cn = startInjection(bytes);
MethodNode onUpdate = getMethod(cn, getName(METHOD_KEY_ONUPDATE), "()V");
if(onUpdate != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
List<AbstractInsnNode> removeNodes = new LinkedList<AbstractInsnNode>();
int numALoadsInARow = 0;
int firstALoadIndex = 0;
AbstractInsnNode ain;
for(int i = onUpdate.instructions.size() - 1; i >= 0; i--) {
ain = onUpdate.instructions.get(i);
if(ain.getOpcode() == Opcodes.ALOAD) {
if(numALoadsInARow == 0)
firstALoadIndex = i;
numALoadsInARow++;
if(numALoadsInARow == 3) {
pos = ain;
break;
}
}
else
numALoadsInARow = 0;
}
int i = firstALoadIndex;
while((ain = onUpdate.instructions.get(--i)).getOpcode() != Opcodes.PUTFIELD);
while((ain = onUpdate.instructions.get(i--)).getOpcode() != Opcodes.ALOAD) {
removeNodes.add(ain);
}
removeNodes.add(ain);
pos = onUpdate.instructions.get(i);
for(AbstractInsnNode node : removeNodes)
onUpdate.instructions.remove(node);
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/util/GravityHandler", "applyGravity", "(L" + getName(CLASS_KEY_ENTITY) + ";)V", false));
onUpdate.instructions.insert(pos, nodeAdd);
}
return finishInjection(cn);
}
if(changedName.equals(getName(CLASS_KEY_ENTITYLIVEINGBASE))) {
ClassNode cn = startInjection(bytes);
MethodNode moveEntityWithHeading = getMethod(cn, getName(METHOD_KEY_MOVEENTITYWITHHEADING), "(FF)V");
if(moveEntityWithHeading != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
List<AbstractInsnNode> removeNodes = new LinkedList<AbstractInsnNode>();
for(int i = moveEntityWithHeading.instructions.size() - 1; i >= 0; i--) {
AbstractInsnNode ain = moveEntityWithHeading.instructions.get(i);
if(ain.getOpcode() == Opcodes.GOTO) {
pos = ain;
while(moveEntityWithHeading.instructions.get(++i).getOpcode() != Opcodes.ALOAD);
pos = moveEntityWithHeading.instructions.get(i-1);
ain = moveEntityWithHeading.instructions.get(i);
do {
moveEntityWithHeading.instructions.remove(ain);
removeNodes.add(ain);
ain = moveEntityWithHeading.instructions.get(i);
} while(ain.getOpcode() != Opcodes.PUTFIELD);
moveEntityWithHeading.instructions.remove(ain);
break;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/util/GravityHandler", "applyGravity", "(L" + getName(CLASS_KEY_ENTITY) + ";)V", false));
moveEntityWithHeading.instructions.insert(pos, nodeAdd);
}
return finishInjection(cn);
}
//On block change insert a call to the atmosphere handler
if(changedName.equals(getName(CLASS_KEY_WORLD))) {
ClassNode cn = startInjection(bytes);
MethodNode setBlockMethod = getMethod(cn, getName(METHOD_KEY_SETBLOCK), "(IIIL" + getName(CLASS_KEY_BLOCK) +";II)Z");
MethodNode setBlockMetaMethod = getMethod(cn, getName(METHOD_KEY_SETBLOCKMETADATAWITHNOTIFY), "(IIIII)Z");
if(setBlockMethod != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
int fmulNum = 2;
for (int i = setBlockMethod.instructions.size()-1; i >= 0 ; i--) {
AbstractInsnNode ain = setBlockMethod.instructions.get(i);
if (ain.getOpcode() == Opcodes.IRETURN && --fmulNum == 0) {
pos = ain;
break;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 1));
nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 2));
nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 3));
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/atmosphere/AtmosphereHandler", "onBlockChange", "(L" + getName(CLASS_KEY_WORLD) + ";III)V", false));
setBlockMethod.instructions.insertBefore(pos, nodeAdd);
}
else
AdvancedRocketry.logger.fatal("ASM injection into World.setBlock FAILED!");
if(setBlockMetaMethod != null) {
final InsnList nodeAdd = new InsnList();
AbstractInsnNode pos = null;
int fmulNum = 2;
for (int i = setBlockMetaMethod.instructions.size()-1; i >= 0 ; i--) {
AbstractInsnNode ain = setBlockMetaMethod.instructions.get(i);
if (ain.getOpcode() == Opcodes.IRETURN && --fmulNum == 0) {
pos = ain;
break;
}
}
nodeAdd.add(new VarInsnNode(Opcodes.ALOAD, 0)); //this
nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 1)); //x
nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 2)); //y
nodeAdd.add(new VarInsnNode(Opcodes.ILOAD, 3)); //z
nodeAdd.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "zmaster587/advancedRocketry/atmosphere/AtmosphereHandler", "onBlockMetaChange", "(L" + getName(CLASS_KEY_WORLD) + ";III)V", false));
setBlockMetaMethod.instructions.insertBefore(pos, nodeAdd);
}
else
AdvancedRocketry.logger.fatal("ASM injection into World.setBlockMeta FAILED!");
return finishInjection(cn);
}
return bytes;
}
private ClassNode startInjection(byte[] bytes) {
final ClassNode node = new ClassNode();
final ClassReader reader = new ClassReader(bytes);
reader.accept(node, 0);
return node;
}
private byte[] finishInjection(ClassNode node) {
final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
node.accept(writer);
return writer.toByteArray();
}
private MethodNode getMethod(ClassNode node, String name, String sig) {
for(MethodNode methodNode : node.methods) {
if(methodNode.name.equals(name) && methodNode.desc.equals(sig))
return methodNode;
}
return null;
}
public static String getName(String key) {
SimpleEntry<String, String> entry = entryMap.get(key);
if(entry == null)
return "";
else
if(obf)
return entry.getValue();
else
return entry.getKey();
}
private String getDeobfName(String key) {
SimpleEntry<String, String> entry = entryMap.get(key);
if(entry == null)
return "";
else
return entry.getKey();
}
}