package coloredlightscore.src.asm.transformer; import coloredlightscore.src.asm.transformer.core.ASMUtils; import coloredlightscore.src.asm.transformer.core.MethodTransformer; import coloredlightscore.src.asm.transformer.core.NameMapper; import cpw.mods.fml.common.FMLLog; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; import static coloredlightscore.src.asm.ColoredLightsCoreDummyContainer.CLLog; public class TransformPlayerInstance extends MethodTransformer { private final String PLAYER_INSTANCE_CLASSNAME = "net.minecraft.server.management.PlayerManager$PlayerInstance"; private final String SEND_TO_ALL_PLAYERS_WATCHING_CHUNK = "sendToAllPlayersWatchingChunk (Lnet/minecraft/network/Packet;)V"; public TransformPlayerInstance() { // TODO Auto-generated constructor stub } @Override protected boolean transforms(ClassNode clazz, MethodNode method) { return NameMapper.getInstance().isMethod(method, PLAYER_INSTANCE_CLASSNAME, SEND_TO_ALL_PLAYERS_WATCHING_CHUNK); } @Override protected boolean transform(ClassNode clazz, MethodNode method) { if (NameMapper.getInstance().isMethod(method, PLAYER_INSTANCE_CLASSNAME, SEND_TO_ALL_PLAYERS_WATCHING_CHUNK)) { transformNewSendToAllPlayersWatchingChunk(method); return true; } else return false; } @Override protected boolean transforms(String className) { //return className.equals(NameMapper.getInstance().getClassName(PLAYER_INSTANCE_CLASSNAME).replace('/', '.')); return className.equals(PLAYER_INSTANCE_CLASSNAME); } protected void transformNewSendToAllPlayersWatchingChunk(MethodNode method) { // insert after 50 invokevirtual net.minecraft.network.NetHandlerPlayServer.sendPacket(net.minecraft.network.Packet) : void [38] MethodInsnNode insertionPoint = ASMUtils.findLastInvoke(method, Opcodes.INVOKEVIRTUAL, "net/minecraft/network/NetHandlerPlayServer", "sendPacket (Lnet/minecraft/network/Packet;)V", false); InsnList helperInvoke = new InsnList(); String playerInstance = NameMapper.getInstance().getClassName(PLAYER_INSTANCE_CLASSNAME); String chunkLocation = NameMapper.getInstance().getClassField(PLAYER_INSTANCE_CLASSNAME, "chunkLocation"); String chunkLocationDescriptor = NameMapper.getInstance().getJVMTypeObfuscated("Lnet/minecraft/world/ChunkCoordIntPair;"); String helperDescriptor = NameMapper.getInstance().getJVMTypeObfuscated("(Lnet/minecraft/entity/player/EntityPlayerMP;Lnet/minecraft/world/ChunkCoordIntPair;)V"); FMLLog.info("debug->field name is %s", chunkLocation); // Push EntityPlayerMP helperInvoke.add(new VarInsnNode(Opcodes.ALOAD, 3)); // Push this.ChunkCoordIntPair helperInvoke.add(new VarInsnNode(Opcodes.ALOAD, 0)); helperInvoke.add(new FieldInsnNode(Opcodes.GETFIELD, playerInstance, chunkLocation, chunkLocationDescriptor)); // Invoke helper function helperInvoke.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "coloredlightscore/server/PlayerManagerHelper", "sendToPlayerWatchingChunk", helperDescriptor)); if (insertionPoint != null) method.instructions.insert(insertionPoint, helperInvoke); else { CLLog.error("TransformPlayerInstance.transformNewSendToAllPlayersWatchingChunk() Could not find last invoke of sendPacket!"); ASMUtils.findLastInvoke(method, Opcodes.INVOKEVIRTUAL, "net/minecraft/network/NetHandlerPlayServer", "sendPacket (Lnet/minecraft/network/Packet;)V", true); } } }