Archiviert
13
0

Made the object injector somewhat workable.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-09-15 20:09:34 +02:00
Ursprung 7e28aefb75
Commit 57c720681a
2 geänderte Dateien mit 60 neuen und 15 gelöschten Zeilen

Datei anzeigen

@ -1,8 +1,10 @@
package com.comphenix.protocol.injector; package com.comphenix.protocol.injector;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.Socket; import java.net.Socket;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -60,10 +62,10 @@ public class NetworkObjectInjector extends PlayerInjector {
if (networkManager != null) { if (networkManager != null) {
final Object networkDelegate = networkManagerRef.getOldValue(); final Object networkDelegate = networkManagerRef.getOldValue();
final Class<?> networkType = networkManager.getClass();
final Enhancer ex = new Enhancer();
Enhancer ex = new Enhancer(); ex.setSuperclass(networkType);
ex.setSuperclass(networkManager.getClass());
ex.setClassLoader(manager.getClassLoader()); ex.setClassLoader(manager.getClassLoader());
ex.setCallback(new MethodInterceptor() { ex.setCallback(new MethodInterceptor() {
@Override @Override
@ -79,12 +81,12 @@ public class NetworkObjectInjector extends PlayerInjector {
System.out.println("[Thread " + current.getId() + "] I'm committing suicide!"); System.out.println("[Thread " + current.getId() + "] I'm committing suicide!");
// This is bad. Very bad. Thus, we prefer the NetworkFieldInjector ... // 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! // OH OH! The queue method!
if (method.equals(queueMethod)) { if (isEquivalentMethod(method, queueMethod)) {
Packet packet = (Packet) args[0]; Packet packet = (Packet) args[0];
if (packet != null) { if (packet != null) {
@ -107,8 +109,8 @@ public class NetworkObjectInjector extends PlayerInjector {
} }
}); });
// Create instances of our network proxy. // Hacks! Get your daily hack here!
DefaultInstances generator = DefaultInstances.fromArray(PrimitiveGenerator.INSTANCE, new InstanceProvider() { DefaultInstances generator = new DefaultInstances(PrimitiveGenerator.INSTANCE, new InstanceProvider() {
@Override @Override
public Object create(@Nullable Class<?> type) { public Object create(@Nullable Class<?> type) {
if (type.equals(Socket.class)) if (type.equals(Socket.class))
@ -120,11 +122,22 @@ public class NetworkObjectInjector extends PlayerInjector {
else else
return null; 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 // Create our proxy object
@SuppressWarnings("unchecked") Object networkProxy = generator.getDefault(networkType);
Object networkProxy = generator.getDefault(ex.createClass());
// Get the two threads we'll have to kill // Get the two threads we'll have to kill
try { 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 @Override
public void cleanupAll() { public void cleanupAll() {
// Clean up // Clean up

Datei anzeigen

@ -55,6 +55,15 @@ public class DefaultInstances {
this.registered = registered; 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. * Construct a default instance generator using the given instance providers.
* @param instaceProviders - array of instance providers. * @param instaceProviders - array of instance providers.
@ -64,7 +73,6 @@ public class DefaultInstances {
return new DefaultInstances(ImmutableList.copyOf(instaceProviders)); return new DefaultInstances(ImmutableList.copyOf(instaceProviders));
} }
/** /**
* Retrieves a immutable list of every default object providers that generates instances. * Retrieves a immutable list of every default object providers that generates instances.
* @return Table of instance providers. * @return Table of instance providers.
@ -131,7 +139,7 @@ public class DefaultInstances {
return (T) value; return (T) value;
} }
Constructor<?> minimum = null; Constructor<T> minimum = null;
int lastCount = Integer.MAX_VALUE; int lastCount = Integer.MAX_VALUE;
// Find the constructor with the fewest parameters // Find the constructor with the fewest parameters
@ -142,7 +150,7 @@ public class DefaultInstances {
// require itself in the constructor. // require itself in the constructor.
if (types.length < lastCount) { if (types.length < lastCount) {
if (!contains(types, type)) { if (!contains(types, type)) {
minimum = candidate; minimum = (Constructor<T>) candidate;
lastCount = types.length; lastCount = types.length;
// Don't loop again if we've already found the best possible constructor // 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); params[i] = getDefaultInternal(types[i], providers, recursionLevel + 1);
} }
return (T) minimum.newInstance(params); return createInstance(type, minimum, types, params);
} }
} catch (Exception e) { } catch (Exception e) {
@ -174,8 +182,26 @@ public class DefaultInstances {
return null; 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 // 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 // Search for the given element in the array
for (T element : elements) { for (T element : elements) {
if (Objects.equal(elementToFind, element)) if (Objects.equal(elementToFind, element))