Added support for a hook method that can intercept map chunk packets.
Dieser Commit ist enthalten in:
Ursprung
e04a78fc04
Commit
22f2f45d1e
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
In neuem Issue referenzieren
Einen Benutzer sperren