From 57c720681a4848f158b3f494a11a836f97baf96f Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Sat, 15 Sep 2012 20:09:34 +0200 Subject: [PATCH] Made the object injector somewhat workable. --- .../injector/NetworkObjectInjector.java | 39 ++++++++++++++----- .../reflect/instances/DefaultInstances.java | 36 ++++++++++++++--- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/ProtocolLib/src/com/comphenix/protocol/injector/NetworkObjectInjector.java b/ProtocolLib/src/com/comphenix/protocol/injector/NetworkObjectInjector.java index 6bf87444..b10767ac 100644 --- a/ProtocolLib/src/com/comphenix/protocol/injector/NetworkObjectInjector.java +++ b/ProtocolLib/src/com/comphenix/protocol/injector/NetworkObjectInjector.java @@ -1,8 +1,10 @@ package com.comphenix.protocol.injector; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.Socket; +import java.util.Arrays; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -60,10 +62,10 @@ public class NetworkObjectInjector extends PlayerInjector { if (networkManager != null) { final Object networkDelegate = networkManagerRef.getOldValue(); - - Enhancer ex = new Enhancer(); + final Class networkType = networkManager.getClass(); + final Enhancer ex = new Enhancer(); - ex.setSuperclass(networkManager.getClass()); + ex.setSuperclass(networkType); ex.setClassLoader(manager.getClassLoader()); ex.setCallback(new MethodInterceptor() { @Override @@ -79,12 +81,12 @@ public class NetworkObjectInjector extends PlayerInjector { System.out.println("[Thread " + current.getId() + "] I'm committing suicide!"); // This is bad. Very bad. Thus, we prefer the NetworkFieldInjector ... - throw new Error("Killing current thread."); + throw new Error("Killing current thread. Ignore this."); } } // OH OH! The queue method! - if (method.equals(queueMethod)) { + if (isEquivalentMethod(method, queueMethod)) { Packet packet = (Packet) args[0]; if (packet != null) { @@ -107,8 +109,8 @@ public class NetworkObjectInjector extends PlayerInjector { } }); - // Create instances of our network proxy. - DefaultInstances generator = DefaultInstances.fromArray(PrimitiveGenerator.INSTANCE, new InstanceProvider() { + // Hacks! Get your daily hack here! + DefaultInstances generator = new DefaultInstances(PrimitiveGenerator.INSTANCE, new InstanceProvider() { @Override public Object create(@Nullable Class type) { if (type.equals(Socket.class)) @@ -120,11 +122,22 @@ public class NetworkObjectInjector extends PlayerInjector { else return null; } - }); + + }) { + @SuppressWarnings("unchecked") + @Override + protected T createInstance(Class type, Constructor constructor, + Class[] types, Object[] params) { + // Use cglib instead of standard reflection + if (type.equals(networkType)) + return (T) ex.create(types, params); + else + return super.createInstance(type, constructor, types, params); + } + }; // Create our proxy object - @SuppressWarnings("unchecked") - Object networkProxy = generator.getDefault(ex.createClass()); + Object networkProxy = generator.getDefault(networkType); // Get the two threads we'll have to kill try { @@ -140,6 +153,12 @@ public class NetworkObjectInjector extends PlayerInjector { } } + // See if the two methods are the same + private boolean isEquivalentMethod(Method a, Method b) { + return a.getName().equals(b.getName()) && + Arrays.equals(a.getParameterTypes(), b.getParameterTypes()); + } + @Override public void cleanupAll() { // Clean up diff --git a/ProtocolLib/src/com/comphenix/protocol/reflect/instances/DefaultInstances.java b/ProtocolLib/src/com/comphenix/protocol/reflect/instances/DefaultInstances.java index d61b153d..4492a617 100644 --- a/ProtocolLib/src/com/comphenix/protocol/reflect/instances/DefaultInstances.java +++ b/ProtocolLib/src/com/comphenix/protocol/reflect/instances/DefaultInstances.java @@ -55,6 +55,15 @@ public class DefaultInstances { this.registered = registered; } + /** + * Construct a default instance generator using the given instance providers. + * @param instaceProviders - array of instance providers. + * @return An default instance generator. + */ + public DefaultInstances(InstanceProvider... instaceProviders) { + this(ImmutableList.copyOf(instaceProviders)); + } + /** * Construct a default instance generator using the given instance providers. * @param instaceProviders - array of instance providers. @@ -64,7 +73,6 @@ public class DefaultInstances { return new DefaultInstances(ImmutableList.copyOf(instaceProviders)); } - /** * Retrieves a immutable list of every default object providers that generates instances. * @return Table of instance providers. @@ -131,7 +139,7 @@ public class DefaultInstances { return (T) value; } - Constructor minimum = null; + Constructor minimum = null; int lastCount = Integer.MAX_VALUE; // Find the constructor with the fewest parameters @@ -142,7 +150,7 @@ public class DefaultInstances { // require itself in the constructor. if (types.length < lastCount) { if (!contains(types, type)) { - minimum = candidate; + minimum = (Constructor) candidate; lastCount = types.length; // Don't loop again if we've already found the best possible constructor @@ -163,7 +171,7 @@ public class DefaultInstances { params[i] = getDefaultInternal(types[i], providers, recursionLevel + 1); } - return (T) minimum.newInstance(params); + return createInstance(type, minimum, types, params); } } catch (Exception e) { @@ -174,8 +182,26 @@ public class DefaultInstances { return null; } + /** + * Used by the default instance provider to create a class from a given constructor. + * The default method uses reflection. + * @param type - the type to create. + * @param constructor - the constructor to use. + * @param types - type of each parameter in order. + * @param params - value of each parameter in order. + * @return The constructed instance. + */ + protected T createInstance(Class type, Constructor constructor, Class[] types, Object[] params) { + try { + return (T) constructor.newInstance(params); + } catch (Exception e) { + // Cannot create it + return null; + } + } + // We avoid Apache's utility methods to stay backwards compatible - private boolean contains(T[] elements, T elementToFind) { + protected boolean contains(T[] elements, T elementToFind) { // Search for the given element in the array for (T element : elements) { if (Objects.equal(elementToFind, element))