Made the object injector somewhat workable.

This commit is contained in:
Kristian S. Stangeland 2012-09-15 20:09:34 +02:00
parent 7e28aefb75
commit 57c720681a
2 changed files with 60 additions and 15 deletions

View File

@ -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();
final Class<?> networkType = networkManager.getClass();
final Enhancer ex = new Enhancer();
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> T createInstance(Class<T> type, Constructor<T> 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

View File

@ -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<T> 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<T>) 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> T createInstance(Class<T> type, Constructor<T> 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 <T> boolean contains(T[] elements, T elementToFind) {
protected <T> boolean contains(T[] elements, T elementToFind) {
// Search for the given element in the array
for (T element : elements) {
if (Objects.equal(elementToFind, element))