Archiviert
13
0

Added support for a hook method that can intercept map chunk packets.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2012-09-26 03:31:59 +02:00
Ursprung e04a78fc04
Commit 22f2f45d1e
5 geänderte Dateien mit 186 neuen und 34 gelöschten Zeilen

Datei anzeigen

@ -12,7 +12,12 @@ import net.sf.cglib.proxy.MethodProxy;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.instances.CollectionGenerator;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
import com.comphenix.protocol.reflect.instances.PrimitiveGenerator;
/** /**
* Represents a player hook into the NetServerHandler class. * Represents a player hook into the NetServerHandler class.
@ -21,7 +26,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
*/ */
public class NetworkServerInjector extends PlayerInjector { public class NetworkServerInjector extends PlayerInjector {
private static Method sendPacket; private static Method sendPacketMethod;
public NetworkServerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException { public NetworkServerInjector(Player player, PacketFilterManager manager, Set<Integer> sendingFilters) throws IllegalAccessException {
super(player, manager, sendingFilters); super(player, manager, sendingFilters);
@ -33,8 +38,8 @@ public class NetworkServerInjector extends PlayerInjector {
// Get the send packet method! // Get the send packet method!
if (hasInitialized) { if (hasInitialized) {
if (sendPacket == null) if (sendPacketMethod == null)
sendPacket = FuzzyReflection.fromObject(serverHandler).getMethodByParameters("sendPacket", Packet.class); sendPacketMethod = FuzzyReflection.fromObject(serverHandler).getMethodByName("sendPacket.*");
} }
} }
@ -45,7 +50,7 @@ public class NetworkServerInjector extends PlayerInjector {
if (serverDeleage != null) { if (serverDeleage != null) {
try { try {
// Note that invocation target exception is a wrapper for a checked exception // Note that invocation target exception is a wrapper for a checked exception
sendPacket.invoke(serverDeleage, packet); sendPacketMethod.invoke(serverDeleage, packet);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw e; throw e;
@ -67,14 +72,17 @@ public class NetworkServerInjector extends PlayerInjector {
if (serverHandlerRef.getValue() instanceof Factory) if (serverHandlerRef.getValue() instanceof Factory)
return; return;
Class<?> serverClass = serverHandler.getClass();
Enhancer ex = new Enhancer(); Enhancer ex = new Enhancer();
ex.setClassLoader(manager.getClassLoader()); ex.setClassLoader(manager.getClassLoader());
ex.setSuperclass(serverHandler.getClass()); ex.setSuperclass(serverClass);
ex.setCallback(new MethodInterceptor() { ex.setCallback(new MethodInterceptor() {
@Override @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// The send packet method! // The send packet method!
if (method.equals(sendPacket)) { if (method.equals(sendPacketMethod)) {
Packet packet = (Packet) args[0]; Packet packet = (Packet) args[0];
if (packet != null) { if (packet != null) {
@ -97,14 +105,39 @@ public class NetworkServerInjector extends PlayerInjector {
} }
}); });
// Use the existing field values when we create our copy
DefaultInstances serverInstances = DefaultInstances.fromArray(
ExistingGenerator.fromObjectFields(serverHandler),
PrimitiveGenerator.INSTANCE,
CollectionGenerator.INSTANCE);
Object proxyObject = serverInstances.forEnhancer(ex).getDefault(serverClass);
// Inject it now // Inject it now
serverHandlerRef.setValue(ex.create()); if (proxyObject != null) {
serverHandlerRef.setValue(proxyObject);
}
} }
@Override @Override
public void cleanupAll() { public void cleanupAll() {
if (serverHandlerRef != null) if (serverHandlerRef != null) {
serverHandlerRef.revertValue(); serverHandlerRef.revertValue();
}
try {
if (getNetHandler() != null) {
// Restore packet listener
try {
FieldUtils.writeField(netHandlerField, networkManager, serverHandlerRef.getOldValue(), true);
} catch (IllegalAccessException e) {
// Oh well
e.printStackTrace();
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} }
@Override @Override

Datei anzeigen

@ -490,7 +490,7 @@ public final class PacketFilterManager implements ProtocolManager {
if (event instanceof PlayerJoinEvent) if (event instanceof PlayerJoinEvent)
injectPlayer(((PlayerJoinEvent) event).getPlayer()); injectPlayer(((PlayerJoinEvent) event).getPlayer());
else if (event instanceof PlayerQuitEvent) else if (event instanceof PlayerQuitEvent)
injectPlayer(((PlayerQuitEvent) event).getPlayer()); uninjectPlayer(((PlayerQuitEvent) event).getPlayer());
} }
return null; return null;
} }

Datei anzeigen

@ -127,7 +127,7 @@ abstract class PlayerInjector {
* @return Current net handler. * @return Current net handler.
* @throws IllegalAccessException Unable to find or retrieve net handler. * @throws IllegalAccessException Unable to find or retrieve net handler.
*/ */
private Object getNetHandler() throws IllegalAccessException { protected Object getNetHandler() throws IllegalAccessException {
// What a mess // What a mess
try { try {

Datei anzeigen

@ -20,6 +20,10 @@ package com.comphenix.protocol.reflect.instances;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.*; import java.util.*;
import javax.print.CancelablePrintJob;
import net.sf.cglib.proxy.Enhancer;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -100,6 +104,38 @@ public class DefaultInstances {
return getDefaultInternal(type, registered, 0); return getDefaultInternal(type, registered, 0);
} }
/**
* Retrieve the constructor with the fewest number of parameters.
* @param type - type to construct.
* @return A constructor with the fewest number of parameters, or NULL if the type has no constructors.
*/
@SuppressWarnings("unchecked")
public <T> Constructor<T> getMinimumConstructor(Class<T> type) {
Constructor<T> minimum = null;
int lastCount = Integer.MAX_VALUE;
// Find the constructor with the fewest parameters
for (Constructor<?> candidate : type.getConstructors()) {
Class<?>[] types = candidate.getParameterTypes();
// Note that we don't allow recursive types - that is, types that
// require itself in the constructor.
if (types.length < lastCount) {
if (!contains(types, type)) {
minimum = (Constructor<T>) candidate;
lastCount = types.length;
// Don't loop again if we've already found the best possible constructor
if (lastCount == 0)
break;
}
}
}
return minimum;
}
/** /**
* Retrieves a default instance or value that is assignable to this type. * Retrieves a default instance or value that is assignable to this type.
* <p> * <p>
@ -137,35 +173,17 @@ public class DefaultInstances {
return (T) value; return (T) value;
} }
Constructor<T> minimum = null; Constructor<T> minimum = getMinimumConstructor(type);
int lastCount = Integer.MAX_VALUE; int parameterCount = minimum.getParameterTypes().length;
// Find the constructor with the fewest parameters
for (Constructor<?> candidate : type.getConstructors()) {
Class<?>[] types = candidate.getParameterTypes();
// Note that we don't allow recursive types - that is, types that
// require itself in the constructor.
if (types.length < lastCount) {
if (!contains(types, type)) {
minimum = (Constructor<T>) candidate;
lastCount = types.length;
// Don't loop again if we've already found the best possible constructor
if (lastCount == 0)
break;
}
}
}
// Create the type with this constructor using default values. This might fail, though. // Create the type with this constructor using default values. This might fail, though.
try { try {
if (minimum != null) { if (minimum != null) {
Object[] params = new Object[lastCount]; Object[] params = new Object[parameterCount];
Class<?>[] types = minimum.getParameterTypes(); Class<?>[] types = minimum.getParameterTypes();
// Fill out // Fill out
for (int i = 0; i < lastCount; i++) { for (int i = 0; i < parameterCount; i++) {
params[i] = getDefaultInternal(types[i], providers, recursionLevel + 1); params[i] = getDefaultInternal(types[i], providers, recursionLevel + 1);
} }
@ -180,6 +198,24 @@ public class DefaultInstances {
return null; return null;
} }
/**
* Construct default instances using the CGLIB enhancer object instead.
* @param enhancer - a CGLIB enhancer to use.
* @return A default instance generator that uses the CGLIB enhancer.
*/
public DefaultInstances forEnhancer(Enhancer enhancer) {
final Enhancer ex = enhancer;
return new DefaultInstances(registered) {
@SuppressWarnings("unchecked")
@Override
protected <T> T createInstance(Class<T> type, Constructor<T> constructor, Class<?>[] types, Object[] params) {
// Use the enhancer instead
return (T) ex.create(types, params);
}
};
}
/** /**
* Used by the default instance provider to create a class from a given constructor. * Used by the default instance provider to create a class from a given constructor.
* The default method uses reflection. * The default method uses reflection.

Datei anzeigen

@ -0,0 +1,83 @@
package com.comphenix.protocol.reflect.instances;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection;
/**
* Provides instance constructors using a list of existing values.
* <p>
* Only one instance per individual class.
* @author Kristian
*/
public class ExistingGenerator implements InstanceProvider {
@SuppressWarnings("rawtypes")
private Map<Class, Object> existingValues = new HashMap<Class, Object>();
private ExistingGenerator() {
// Only accessible to the constructors
}
/**
* Automatically create an instance provider from a objects public and private fields.
* <p>
* If two or more fields share the same type, the last declared non-null field will take
* precedent.
* @param object - object to create an instance generator from.
* @return The instance generator.
*/
public static ExistingGenerator fromObjectFields(Object object) {
ExistingGenerator generator = new ExistingGenerator();
// Read instances from every field.
for (Field field : FuzzyReflection.fromObject(object, true).getFields()) {
try {
Object value = FieldUtils.readField(field, object, true);
if (value != null)
generator.addObject(value);
} catch (Exception e) {
// Yes, swallow it. No, really.
}
}
return generator;
}
/**
* Create an instance generator from a pre-defined array of values.
* @param values - values to provide.
* @return An instance provider that uses these values.
*/
public static ExistingGenerator fromObjectArray(Object[] values) {
ExistingGenerator generator = new ExistingGenerator();
for (Object value : values)
generator.addObject(value);
return generator;
}
private void addObject(Object value) {
if (value == null)
throw new IllegalArgumentException("Value cannot be NULL.");
existingValues.put(value.getClass(), value);
}
@Override
public Object create(@Nullable Class<?> type) {
Object value = existingValues.get(type);
// NULL values indicate that the generator failed
return value;
}
}