Commit 813a72f57c94031fdba852d9ab4fbcb7dd3d9496

Authored by Mumfrey
1 parent 239a6eb0

LiteLoader 1.6.4_02 - experimental - hook packet classes using ASM instead of re…

…flection, fall back to reflection if transformation fails
java/com/mumfrey/liteloader/core/Events.java
... ... @@ -12,6 +12,10 @@ import com.mumfrey.liteloader.Tickable;
12 12 import com.mumfrey.liteloader.core.hooks.HookChat;
13 13 import com.mumfrey.liteloader.core.hooks.HookLogin;
14 14 import com.mumfrey.liteloader.core.hooks.HookProfiler;
  15 +import com.mumfrey.liteloader.core.hooks.asm.ASMHookProxy;
  16 +import com.mumfrey.liteloader.core.hooks.asm.ChatPacketTransformer;
  17 +import com.mumfrey.liteloader.core.hooks.asm.LoginPacketTransformer;
  18 +import com.mumfrey.liteloader.core.hooks.asm.PacketTransformer;
15 19 import com.mumfrey.liteloader.util.ModUtilities;
16 20 import com.mumfrey.liteloader.util.PrivateFields;
17 21  
... ... @@ -37,6 +41,11 @@ public class Events implements IPlayerUsage
37 41 private final PluginChannels pluginChannels;
38 42  
39 43 /**
  44 + * ASM hook proxy
  45 + */
  46 + private final ASMHookProxy asmProxy;
  47 +
  48 + /**
40 49 * Reference to the minecraft timer
41 50 */
42 51 private Timer minecraftTimer;
... ... @@ -144,11 +153,12 @@ public class Events implements IPlayerUsage
144 153 * @param minecraft
145 154 * @param pluginChannels
146 155 */
147   - Events(LiteLoader loader, Minecraft minecraft, PluginChannels pluginChannels)
  156 + Events(LiteLoader loader, Minecraft minecraft, PluginChannels pluginChannels, ASMHookProxy asmProxy)
148 157 {
149 158 this.loader = loader;
150 159 this.minecraft = minecraft;
151 160 this.pluginChannels = pluginChannels;
  161 + this.asmProxy = asmProxy;
152 162 }
153 163  
154 164 /**
... ... @@ -239,16 +249,34 @@ public class Events implements IPlayerUsage
239 249 if ((this.chatListeners.size() > 0 || this.chatFilters.size() > 0) && !this.chatHooked)
240 250 {
241 251 this.chatHooked = true;
242   - HookChat.register();
243   - HookChat.registerPacketHandler(this);
  252 +
  253 + if (ChatPacketTransformer.isInjected())
  254 + {
  255 + PacketTransformer.registerProxy(Packet3Chat.class, this.asmProxy);
  256 + }
  257 + else
  258 + {
  259 + LiteLoader.getLogger().info("Callback injection failed for chat packet, injecting reflection hook");
  260 + HookChat.register();
  261 + HookChat.registerPacketHandler(this);
  262 + }
244 263 }
245 264  
246 265 // Login hook
247 266 if ((this.preLoginListeners.size() > 0 || this.loginListeners.size() > 0) && !this.loginHooked)
248 267 {
249 268 this.loginHooked = true;
250   - ModUtilities.registerPacketOverride(1, HookLogin.class);
251   - HookLogin.events = this;
  269 +
  270 + if (LoginPacketTransformer.isInjected())
  271 + {
  272 + PacketTransformer.registerProxy(Packet1Login.class, this.asmProxy);
  273 + }
  274 + else
  275 + {
  276 + LiteLoader.getLogger().info("Callback injection failed for login packet, injecting reflection hook");
  277 + ModUtilities.registerPacketOverride(1, HookLogin.class);
  278 + HookLogin.events = this;
  279 + }
252 280 }
253 281  
254 282 // Tick hook
... ... @@ -614,7 +642,7 @@ public class Events implements IPlayerUsage
614 642 }
615 643  
616 644 /**
617   - * Callback from the chat hook
  645 + * Callback from the reflective chat hook
618 646 *
619 647 * @param chatPacket
620 648 * @return
... ...
java/com/mumfrey/liteloader/core/LiteLoader.java
... ... @@ -35,6 +35,7 @@ import net.minecraft.src.SimpleReloadableResourceManager;
35 35 import net.minecraft.src.World;
36 36  
37 37 import com.mumfrey.liteloader.*;
  38 +import com.mumfrey.liteloader.core.hooks.asm.ASMHookProxy;
38 39 import com.mumfrey.liteloader.crashreport.CallableLiteLoaderBrand;
39 40 import com.mumfrey.liteloader.crashreport.CallableLiteLoaderMods;
40 41 import com.mumfrey.liteloader.gui.GuiControlsPaginated;
... ... @@ -149,6 +150,11 @@ public final class LiteLoader
149 150 private final LinkedList<ModFile> disabledMods = new LinkedList<ModFile>();
150 151  
151 152 /**
  153 + * ASM hook proxy
  154 + */
  155 + private final ASMHookProxy asmProxy = new ASMHookProxy();
  156 +
  157 + /**
152 158 * Event manager
153 159 */
154 160 private Events events;
... ... @@ -156,7 +162,7 @@ public final class LiteLoader
156 162 /**
157 163 * Plugin channel manager
158 164 */
159   - private final PluginChannels pluginChannels = new PluginChannels();
  165 + private final PluginChannels pluginChannels = new PluginChannels(this.asmProxy);
160 166  
161 167 /**
162 168 * Permission Manager
... ... @@ -350,7 +356,7 @@ public final class LiteLoader
350 356 this.minecraft = minecraft;
351 357  
352 358 // Create the event broker
353   - this.events = new Events(this, this.minecraft, this.pluginChannels);
  359 + this.events = new Events(this, this.minecraft, this.pluginChannels, this.asmProxy);
354 360  
355 361 // Spawn mod instances
356 362 this.loadMods();
... ...
java/com/mumfrey/liteloader/core/PluginChannels.java
... ... @@ -12,6 +12,9 @@ import net.minecraft.src.Packet250CustomPayload;
12 12  
13 13 import com.mumfrey.liteloader.PluginChannelListener;
14 14 import com.mumfrey.liteloader.core.hooks.HookPluginChannels;
  15 +import com.mumfrey.liteloader.core.hooks.asm.ASMHookProxy;
  16 +import com.mumfrey.liteloader.core.hooks.asm.CustomPayloadPacketTransformer;
  17 +import com.mumfrey.liteloader.core.hooks.asm.PacketTransformer;
15 18 import com.mumfrey.liteloader.permissions.PermissionsManagerClient;
16 19  
17 20 /**
... ... @@ -39,11 +42,16 @@ public class PluginChannels
39 42 * List of mods which implement PluginChannelListener interface
40 43 */
41 44 private LinkedList<PluginChannelListener> pluginChannelListeners = new LinkedList<PluginChannelListener>();
  45 +
  46 + private ASMHookProxy asmProxy;
42 47  
43 48 /**
44 49 * Package private
45 50 */
46   - PluginChannels() {}
  51 + PluginChannels(ASMHookProxy proxy)
  52 + {
  53 + this.asmProxy = proxy;
  54 + }
47 55  
48 56 /**
49 57 *
... ... @@ -53,8 +61,17 @@ public class PluginChannels
53 61 // Plugin channels hook
54 62 if (this.pluginChannelListeners.size() > 0 && !this.hookInitDone)
55 63 {
56   - HookPluginChannels.register();
57   - HookPluginChannels.registerPacketHandler(this);
  64 + if (CustomPayloadPacketTransformer.isInjected())
  65 + {
  66 + PacketTransformer.registerProxy(Packet250CustomPayload.class, this.asmProxy);
  67 + }
  68 + else
  69 + {
  70 + LiteLoader.getLogger().info("Callback injection failed for custom payload packet, injecting reflection hook");
  71 + HookPluginChannels.register();
  72 + HookPluginChannels.registerPacketHandler(this);
  73 + }
  74 +
58 75 this.hookInitDone = true;
59 76 }
60 77 }
... ...
java/com/mumfrey/liteloader/core/hooks/HookProfiler.java
... ... @@ -140,6 +140,7 @@ public class HookProfiler extends Profiler
140 140 {
141 141 if (Thread.currentThread() != this.minecraftThread)
142 142 {
  143 + this.logger.severe("Profiler cross thread access detected, this indicates an error with one of your mods.");
143 144 throw new ProfilerCrossThreadAccessException(Thread.currentThread().getName());
144 145 }
145 146  
... ... @@ -203,6 +204,7 @@ public class HookProfiler extends Profiler
203 204 {
204 205 if (Thread.currentThread() != this.minecraftThread)
205 206 {
  207 + this.logger.severe("Profiler cross thread access detected, this indicates an error with one of your mods.");
206 208 throw new ProfilerCrossThreadAccessException(Thread.currentThread().getName());
207 209 }
208 210  
... ...
java/com/mumfrey/liteloader/core/hooks/asm/ASMHookProxy.java 0 → 100644
  1 +package com.mumfrey.liteloader.core.hooks.asm;
  2 +
  3 +import com.mumfrey.liteloader.core.Events;
  4 +import com.mumfrey.liteloader.core.LiteLoader;
  5 +import com.mumfrey.liteloader.core.PluginChannels;
  6 +
  7 +import net.minecraft.src.NetHandler;
  8 +import net.minecraft.src.Packet1Login;
  9 +import net.minecraft.src.Packet250CustomPayload;
  10 +import net.minecraft.src.Packet3Chat;
  11 +
  12 +/**
  13 + * Proxy class which handles the redirected calls from the injected packet hooks and routes them to the
  14 + * relevant liteloader handler classes. We do this rather than patching a bunch of bytecode into the packet
  15 + * classes themselves because this is easier to maintain.
  16 + *
  17 + * @author Adam Mummery-Smith
  18 + */
  19 +public class ASMHookProxy
  20 +{
  21 + /**
  22 + * Packet3Chat::processPacket()
  23 + *
  24 + * @param netHandler
  25 + * @param packet
  26 + */
  27 + public void handleChatPacket(NetHandler netHandler, Packet3Chat packet)
  28 + {
  29 + Events events = LiteLoader.getEvents();
  30 + if (events.onChat(packet))
  31 + {
  32 + netHandler.handleChat(packet);
  33 + }
  34 + }
  35 +
  36 + /**
  37 + * Packet3Chat::processPacket()
  38 + *
  39 + * @param netHandler
  40 + * @param packet
  41 + */
  42 + public void handleLoginPacket(NetHandler netHandler, Packet1Login packet)
  43 + {
  44 + Events events = LiteLoader.getEvents();
  45 + if (events.onPreLogin(netHandler, packet))
  46 + {
  47 + netHandler.handleLogin(packet);
  48 + events.onConnectToServer(netHandler, packet);
  49 + }
  50 + }
  51 +
  52 + /**
  53 + * Packet3Chat::processPacket()
  54 + *
  55 + * @param netHandler
  56 + * @param packet
  57 + */
  58 + public void handleCustomPayloadPacket(NetHandler netHandler, Packet250CustomPayload packet)
  59 + {
  60 + netHandler.handleCustomPayload(packet);
  61 +
  62 + PluginChannels pluginChannels = LiteLoader.getPluginChannels();
  63 + pluginChannels.onPluginChannelMessage(packet);
  64 + }
  65 +}
... ...
java/com/mumfrey/liteloader/core/hooks/asm/ChatPacketTransformer.java 0 → 100644
  1 +package com.mumfrey.liteloader.core.hooks.asm;
  2 +
  3 +/**
  4 + * Transformer for Packet 3 (chat)
  5 + *
  6 + * @author Adam Mummery-Smith
  7 + */
  8 +public class ChatPacketTransformer extends PacketTransformer
  9 +{
  10 + private static boolean injected = false;
  11 +
  12 + public ChatPacketTransformer()
  13 + {
  14 + // TODO Obfuscation 1.6.4
  15 + super("net.minecraft.src.Packet3Chat", "dm", "handleChatPacket");
  16 + }
  17 +
  18 + @Override
  19 + protected void notifyInjected()
  20 + {
  21 + ChatPacketTransformer.injected = true;
  22 + }
  23 +
  24 + public static boolean isInjected()
  25 + {
  26 + return ChatPacketTransformer.injected;
  27 + }
  28 +}
... ...
java/com/mumfrey/liteloader/core/hooks/asm/CrashReportTransformer.java 0 → 100644
  1 +package com.mumfrey.liteloader.core.hooks.asm;
  2 +
  3 +import java.util.ListIterator;
  4 +
  5 +import net.minecraft.launchwrapper.IClassTransformer;
  6 +
  7 +import org.objectweb.asm.ClassReader;
  8 +import org.objectweb.asm.ClassWriter;
  9 +import org.objectweb.asm.Opcodes;
  10 +import org.objectweb.asm.tree.AbstractInsnNode;
  11 +import org.objectweb.asm.tree.ClassNode;
  12 +import org.objectweb.asm.tree.InsnList;
  13 +import org.objectweb.asm.tree.MethodInsnNode;
  14 +import org.objectweb.asm.tree.MethodNode;
  15 +import org.objectweb.asm.tree.VarInsnNode;
  16 +
  17 +public class CrashReportTransformer implements IClassTransformer
  18 +{
  19 + private static final String classMappingCallableJVMFlags = "net.minecraft.src.CallableJVMFlags";
  20 +
  21 + // TODO Obfuscation 1.6.4
  22 + private static final String classMappingCallableJVMFlagsObf = "h";
  23 +
  24 + @Override
  25 + public byte[] transform(String name, String transformedName, byte[] basicClass)
  26 + {
  27 + if (classMappingCallableJVMFlags.equals(name) || classMappingCallableJVMFlagsObf.equals(name))
  28 + {
  29 + try
  30 + {
  31 + return this.transformCallableJVMFlags(basicClass);
  32 + }
  33 + catch (Exception ex) {}
  34 + }
  35 +
  36 + return basicClass;
  37 + }
  38 +
  39 + /**
  40 + * Inject the additional callback for populating the crash report into the CallableJVMFlags class
  41 + *
  42 + * @param basicClass basic class
  43 + * @return transformed class
  44 + */
  45 + private byte[] transformCallableJVMFlags(byte[] basicClass)
  46 + {
  47 + ClassReader classReader = new ClassReader(basicClass);
  48 + ClassNode classNode = new ClassNode();
  49 + classReader.accept(classNode, ClassReader.EXPAND_FRAMES);
  50 +
  51 + for (MethodNode method : classNode.methods)
  52 + {
  53 + if ("<init>".equals(method.name))
  54 + {
  55 + this.transformCallableJVMFlagsConstructor(method);
  56 + }
  57 + }
  58 +
  59 + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  60 + classNode.accept(writer);
  61 + return writer.toByteArray();
  62 + }
  63 +
  64 + /**
  65 + * @param ctor
  66 + */
  67 + public void transformCallableJVMFlagsConstructor(MethodNode ctor)
  68 + {
  69 + InsnList code = new InsnList();
  70 + code.add(new VarInsnNode(Opcodes.ALOAD, 1));
  71 + code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mumfrey/liteloader/core/LiteLoader", "populateCrashReport", "(Ljava/lang/Object;)V"));
  72 +
  73 + ListIterator<AbstractInsnNode> insns = ctor.instructions.iterator();
  74 + while (insns.hasNext())
  75 + {
  76 + AbstractInsnNode insnNode = insns.next();
  77 + if (insnNode.getOpcode() == Opcodes.RETURN)
  78 + ctor.instructions.insertBefore(insnNode, code);
  79 + }
  80 + }
  81 +}
... ...
java/com/mumfrey/liteloader/core/hooks/asm/CustomPayloadPacketTransformer.java 0 → 100644
  1 +package com.mumfrey.liteloader.core.hooks.asm;
  2 +
  3 +/**
  4 + * Transformer for Packet 250 (custom paylor)
  5 + *
  6 + * @author Adam Mummery-Smith
  7 + */
  8 +public class CustomPayloadPacketTransformer extends PacketTransformer
  9 +{
  10 + private static boolean injected = false;
  11 +
  12 + public CustomPayloadPacketTransformer()
  13 + {
  14 + // TODO Obfuscation 1.6.4
  15 + super("net.minecraft.src.Packet250CustomPayload", "ea", "handleCustomPayloadPacket");
  16 + }
  17 +
  18 + @Override
  19 + protected void notifyInjected()
  20 + {
  21 + CustomPayloadPacketTransformer.injected = true;
  22 + }
  23 +
  24 + public static boolean isInjected()
  25 + {
  26 + return CustomPayloadPacketTransformer.injected;
  27 + }
  28 +}
... ...
java/com/mumfrey/liteloader/core/hooks/asm/LoginPacketTransformer.java 0 → 100644
  1 +package com.mumfrey.liteloader.core.hooks.asm;
  2 +
  3 +/**
  4 + * Transformer for Packet 1 (login)
  5 + *
  6 + * @author Adam Mummery-Smith
  7 + */
  8 +public class LoginPacketTransformer extends PacketTransformer
  9 +{
  10 + private static boolean injected = false;
  11 +
  12 + public LoginPacketTransformer()
  13 + {
  14 + // TODO Obfuscation 1.6.4
  15 + super("net.minecraft.src.Packet1Login", "ep", "handleLoginPacket");
  16 + }
  17 +
  18 + @Override
  19 + protected void notifyInjected()
  20 + {
  21 + LoginPacketTransformer.injected = true;
  22 + }
  23 +
  24 + public static boolean isInjected()
  25 + {
  26 + return LoginPacketTransformer.injected;
  27 + }
  28 +}
0 29 \ No newline at end of file
... ...
java/com/mumfrey/liteloader/core/hooks/asm/PacketTransformer.java 0 → 100644
  1 +package com.mumfrey.liteloader.core.hooks.asm;
  2 +
  3 +import java.lang.reflect.Field;
  4 +import java.util.List;
  5 +
  6 +import org.objectweb.asm.ClassReader;
  7 +import org.objectweb.asm.ClassWriter;
  8 +import org.objectweb.asm.Opcodes;
  9 +import org.objectweb.asm.tree.ClassNode;
  10 +import org.objectweb.asm.tree.FieldInsnNode;
  11 +import org.objectweb.asm.tree.FieldNode;
  12 +import org.objectweb.asm.tree.InsnNode;
  13 +import org.objectweb.asm.tree.MethodInsnNode;
  14 +import org.objectweb.asm.tree.MethodNode;
  15 +import org.objectweb.asm.tree.VarInsnNode;
  16 +
  17 +import net.minecraft.launchwrapper.IClassTransformer;
  18 +
  19 +/**
  20 + * Class transformer which transforms a Packet class and alters the "processPacket" function to call the specified
  21 + * callback method in ASMHookProxy instead of the usual behaviour of calling handleXXXPacket in NetClientHandler.
  22 + *
  23 + * @author Adam Mummery-Smith
  24 + */
  25 +public abstract class PacketTransformer implements IClassTransformer
  26 +{
  27 + private static final String netHandlerClass = "net/minecraft/src/NetHandler";
  28 + private static final String processPacketMethod = "processPacket";
  29 +
  30 + // TODO Obfuscation 1.6.4
  31 + private static final String netHandlerClassObf = "ez";
  32 + private static final String processPacketMethodObf = "a";
  33 +
  34 + private final String packetClass;
  35 + private final String packetClassObf;
  36 +
  37 + private final String handlerMethodName;
  38 +
  39 + /**
  40 + * ctor
  41 + * @param packetClass Packet class name we want to override (FQ)
  42 + * @param packetClassObf Obfuscated packet class name
  43 + * @param handlerMethodName Method name to map to in handlerClass (must have signature (NetHandler, PacketClass)Void)
  44 + */
  45 + protected PacketTransformer(String packetClass, String packetClassObf, String handlerMethodName)
  46 + {
  47 + this.packetClass = packetClass;
  48 + this.packetClassObf = packetClassObf;
  49 + this.handlerMethodName = handlerMethodName;
  50 + }
  51 +
  52 + /* (non-Javadoc)
  53 + * @see net.minecraft.launchwrapper.IClassTransformer#transform(java.lang.String, java.lang.String, byte[])
  54 + */
  55 + @Override
  56 + public byte[] transform(String name, String transformedName, byte[] basicClass)
  57 + {
  58 + if (this.packetClass.equals(name) || this.packetClassObf.equals(name))
  59 + {
  60 + try
  61 + {
  62 + byte[] transformedClass = this.transformClass(name, basicClass);
  63 + this.notifyInjected();
  64 + return transformedClass;
  65 + }
  66 + catch (Exception ex) {}
  67 + }
  68 +
  69 + return basicClass;
  70 + }
  71 +
  72 + /**
  73 + * Found the packet class we want to transform, attempt to transform it
  74 + *
  75 + * @param className
  76 + * @param basicClass
  77 + * @return
  78 + */
  79 + private byte[] transformClass(String className, byte[] basicClass)
  80 + {
  81 + boolean transformed = true;
  82 +
  83 + ClassReader classReader = new ClassReader(basicClass);
  84 + ClassNode classNode = new ClassNode();
  85 + classReader.accept(classNode, ClassReader.EXPAND_FRAMES);
  86 +
  87 + // Try and transform obfuscated first
  88 + if (!this.tryTransformMethod(className, classNode, PacketTransformer.processPacketMethodObf, PacketTransformer.netHandlerClassObf))
  89 + {
  90 + // Try to transform non-obf for use in dev env
  91 + if (!this.tryTransformMethod(className, classNode, PacketTransformer.processPacketMethod, PacketTransformer.netHandlerClass))
  92 + {
  93 + transformed = false;
  94 + }
  95 + }
  96 +
  97 + // If we successfully transformed the method, transform the class and add a private static field "proxy" which will hold the handler
  98 + if (transformed)
  99 + {
  100 + classNode.fields.add(new FieldNode(Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC, "proxy", "Lcom/mumfrey/liteloader/core/hooks/asm/ASMHookProxy;", null, null));
  101 + }
  102 +
  103 + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  104 + classNode.accept(writer);
  105 + return writer.toByteArray();
  106 + }
  107 +
  108 + /**
  109 + * @param className
  110 + * @param classNode
  111 + * @param functionName
  112 + * @param netHandlerClassName
  113 + */
  114 + private boolean tryTransformMethod(String className, ClassNode classNode, String functionName, String netHandlerClassName)
  115 + {
  116 + MethodNode method = this.findMethodByNameAndSignature(classNode.methods, functionName, "(L" + netHandlerClassName + ";)V");
  117 +
  118 + if (method != null)
  119 + {
  120 + String targetMethodSig = "(L" + netHandlerClassName + ";L" + className.replace('.', '/') + ";)V";
  121 + this.transformMethod(className, method, targetMethodSig);
  122 + return true;
  123 + }
  124 +
  125 + return false;
  126 + }
  127 +
  128 + /**
  129 + * Clear the old method contents and replace with the call to our handler function
  130 + *
  131 + * @param method
  132 + * @param targetMethodSig
  133 + */
  134 + private void transformMethod(String className, MethodNode method, String targetMethodSig)
  135 + {
  136 + // Dump the old method content, we don't want it any more
  137 + method.instructions.clear();
  138 +
  139 + // Get the value of the "proxy" field from the object on the stack (which is "this")
  140 + method.instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, className.replace('.', '/'), "proxy", "Lcom/mumfrey/liteloader/core/hooks/asm/ASMHookProxy;"));
  141 +
  142 + // Push method argument 1 (NetHandler instance) onto the stack
  143 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
  144 +
  145 + // Push "this" onto the stack
  146 + method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
  147 +
  148 + // Invoke the handler function with the args we just pushed onto the stack
  149 + method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "com/mumfrey/liteloader/core/hooks/asm/ASMHookProxy", this.handlerMethodName, targetMethodSig));
  150 +
  151 + // Return
  152 + method.instructions.add(new InsnNode(Opcodes.RETURN));
  153 + }
  154 +
  155 + /**
  156 + * For subclasses, to set a local flag indicating the code was successfully injected
  157 + */
  158 + protected abstract void notifyInjected();
  159 +
  160 + /**
  161 + * @param classNode
  162 + * @param funcName
  163 + * @param funcNameObf
  164 + * @param funcSig
  165 + * @param funcSigObf
  166 + * @return
  167 + */
  168 + private MethodNode findMethodByNameAndSignature(List<MethodNode> methods, String funcName, String funcSig)
  169 + {
  170 + for (MethodNode method : methods)
  171 + {
  172 + if (funcName.equals(method.name) && funcSig.equals(method.desc))
  173 + return method;
  174 + }
  175 +
  176 + return null;
  177 + }
  178 +
  179 + /**
  180 + * Register the proxy (handler) for a packet
  181 + *
  182 + * @param packetClass
  183 + * @param proxy
  184 + */
  185 + public static void registerProxy(Class<?> packetClass, ASMHookProxy proxy)
  186 + {
  187 + try
  188 + {
  189 + Field fProxy = packetClass.getDeclaredField("proxy");
  190 + fProxy.setAccessible(true);
  191 + fProxy.set(null, proxy);
  192 + }
  193 + catch (Exception ex)
  194 + {
  195 + ex.printStackTrace();
  196 + }
  197 + }
  198 +}
0 199 \ No newline at end of file
... ...
java/com/mumfrey/liteloader/launch/LiteLoaderTransformer.java
1 1 package com.mumfrey.liteloader.launch;
2 2  
3   -import java.util.ListIterator;
4   -
5 3 import net.minecraft.launchwrapper.IClassTransformer;
6 4  
7   -import org.objectweb.asm.ClassReader;
8   -import org.objectweb.asm.ClassWriter;
9   -import org.objectweb.asm.Opcodes;
10   -import org.objectweb.asm.tree.AbstractInsnNode;
11   -import org.objectweb.asm.tree.ClassNode;
12   -import org.objectweb.asm.tree.InsnList;
13   -import org.objectweb.asm.tree.MethodInsnNode;
14   -import org.objectweb.asm.tree.MethodNode;
15   -import org.objectweb.asm.tree.VarInsnNode;
16   -
17 5 public class LiteLoaderTransformer implements IClassTransformer
18 6 {
19 7 private static final String classMappingRenderLightningBolt = "net.minecraft.src.RenderLightningBolt";
20   - private static final String classMappingCallableJVMFlags = "net.minecraft.src.CallableJVMFlags";
21 8  
22 9 // TODO Obfuscation 1.6.4
23 10 private static final String classMappingRenderLightningBoltObf = "bha";
24   - private static final String classMappingCallableJVMFlagsObf = "h";
25 11  
26 12 private static boolean postInit = false;
27 13  
... ... @@ -35,58 +21,6 @@ public class LiteLoaderTransformer implements IClassTransformer
35 21 LiteLoaderTweaker.postInit();
36 22 }
37 23  
38   - if (classMappingCallableJVMFlags.equals(name) || classMappingCallableJVMFlagsObf.equals(name))
39   - {
40   - try
41   - {
42   - return this.transformCallableJVMFlags(basicClass);
43   - }
44   - catch (Exception ex) {}
45   - }
46   -
47 24 return basicClass;
48 25 }
49   -
50   - /**
51   - * Inject the additional callback for populating the crash report into the CallableJVMFlags class
52   - *
53   - * @param basicClass basic class
54   - * @return transformed class
55   - */
56   - private byte[] transformCallableJVMFlags(byte[] basicClass)
57   - {
58   - ClassReader classReader = new ClassReader(basicClass);
59   - ClassNode classNode = new ClassNode();
60   - classReader.accept(classNode, ClassReader.EXPAND_FRAMES);
61   -
62   - for (MethodNode method : classNode.methods)
63   - {
64   - if ("<init>".equals(method.name))
65   - {
66   - this.transformCallableJVMFlagsConstructor(method);
67   - }
68   - }
69   -
70   - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
71   - classNode.accept(writer);
72   - return writer.toByteArray();
73   - }
74   -
75   - /**
76   - * @param ctor
77   - */
78   - public void transformCallableJVMFlagsConstructor(MethodNode ctor)
79   - {
80   - InsnList code = new InsnList();
81   - code.add(new VarInsnNode(Opcodes.ALOAD, 1));
82   - code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mumfrey/liteloader/core/LiteLoader", "populateCrashReport", "(Ljava/lang/Object;)V"));
83   -
84   - ListIterator<AbstractInsnNode> insns = ctor.instructions.iterator();
85   - while (insns.hasNext())
86   - {
87   - AbstractInsnNode insnNode = insns.next();
88   - if (insnNode.getOpcode() == Opcodes.RETURN)
89   - ctor.instructions.insertBefore(insnNode, code);
90   - }
91   - }
92 26 }
... ...
java/com/mumfrey/liteloader/launch/LiteLoaderTweaker.java
... ... @@ -61,6 +61,14 @@ public class LiteLoaderTweaker implements ITweaker
61 61  
62 62 private List<String> passThroughArgs;
63 63  
  64 + private static final String[] requiredTransformers = {
  65 + "com.mumfrey.liteloader.launch.LiteLoaderTransformer",
  66 + "com.mumfrey.liteloader.core.hooks.asm.CrashReportTransformer",
  67 + "com.mumfrey.liteloader.core.hooks.asm.ChatPacketTransformer",
  68 + "com.mumfrey.liteloader.core.hooks.asm.LoginPacketTransformer",
  69 + "com.mumfrey.liteloader.core.hooks.asm.CustomPayloadPacketTransformer"
  70 + };
  71 +
64 72 @SuppressWarnings("unchecked")
65 73 @Override
66 74 public void acceptOptions(List<String> args, File gameDirectory, File assetsDirectory, String profile)
... ... @@ -124,33 +132,45 @@ public class LiteLoaderTweaker implements ITweaker
124 132 if (arg.startsWith("-"))
125 133 {
126 134 if (classifier != null)
127   - classifier = this.addClassifiedArg(classifier, "");
  135 + {
  136 + this.addClassifiedArg(classifier, "");
  137 + classifier = null;
  138 + }
128 139 else if (arg.contains("="))
129   - classifier = this.addClassifiedArg(arg.substring(0, arg.indexOf('=')), arg.substring(arg.indexOf('=') + 1));
  140 + {
  141 + this.addClassifiedArg(arg.substring(0, arg.indexOf('=')), arg.substring(arg.indexOf('=') + 1));
  142 + }
130 143 else
  144 + {
131 145 classifier = arg;
  146 + }
132 147 }
133 148 else
134 149 {
135 150 if (classifier != null)
136   - classifier = this.addClassifiedArg(classifier, arg);
  151 + {
  152 + this.addClassifiedArg(classifier, arg);
  153 + classifier = null;
  154 + }
137 155 else
138 156 this.singularLaunchArgs.add(arg);
139 157 }
140 158 }
141 159 }
142 160  
143   - private String addClassifiedArg(String classifiedArg, String arg)
  161 + private void addClassifiedArg(String classifiedArg, String arg)
144 162 {
145 163 this.launchArgs.put(classifiedArg, arg);
146   - return null;
147 164 }
148 165  
149 166 @Override
150 167 public void injectIntoClassLoader(LaunchClassLoader classLoader)
151 168 {
152   - LiteLoaderTweaker.logger.info("Injecting LiteLoader class transformer");
153   - classLoader.registerTransformer(LiteLoaderTransformer.class.getName());
  169 + for (String requiredTransformerClassName : LiteLoaderTweaker.requiredTransformers)
  170 + {
  171 + LiteLoaderTweaker.logger.info(String.format("Injecting required class transformer '%s'", requiredTransformerClassName));
  172 + classLoader.registerTransformer(requiredTransformerClassName);
  173 + }
154 174  
155 175 for (String transformerClassName : LiteLoaderTweaker.modTransformers)
156 176 {
... ...