Archiviert
13
0

Create a dummy injector if we haven't yet injected the player.

Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-03-04 00:44:09 +01:00
Ursprung d387b2d792
Commit 6019ab177c
6 geänderte Dateien mit 150 neuen und 85 gelöschten Zeilen

Datei anzeigen

@ -47,6 +47,19 @@ public class BlockingHashMap<TKey, TValue> {
// Map of locked objects // Map of locked objects
private final ConcurrentMap<TKey, Object> locks; private final ConcurrentMap<TKey, Object> locks;
/**
* Retrieve a cache loader that will always throw an exception.
* @return An invalid cache loader.
*/
public static <TKey, TValue> CacheLoader<TKey, TValue> newInvalidCacheLoader() {
return new CacheLoader<TKey, TValue>() {
@Override
public TValue load(TKey key) throws Exception {
throw new IllegalStateException("Illegal use. Access the map directly instead.");
}
};
}
/** /**
* Initialize a new map. * Initialize a new map.
*/ */
@ -59,12 +72,8 @@ public class BlockingHashMap<TKey, TValue> {
locks.remove(entry.getKey()); locks.remove(entry.getKey());
} }
}).build( }).build(
new CacheLoader<TKey, TValue>() { BlockingHashMap.<TKey, TValue>newInvalidCacheLoader()
@Override );
public TValue load(TKey key) throws Exception {
throw new IllegalStateException("Illegal use. Access the map directly instead.");
}
});
backingMap = backingCache.asMap(); backingMap = backingCache.asMap();
// Normal concurrent hash map // Normal concurrent hash map

Datei anzeigen

@ -20,15 +20,7 @@ package com.comphenix.protocol.injector.player;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import net.sf.cglib.proxy.*;
import java.util.Map;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -44,8 +36,8 @@ import com.comphenix.protocol.reflect.ObjectWriter;
import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.reflect.instances.ExistingGenerator; import com.comphenix.protocol.reflect.instances.ExistingGenerator;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Maps;
/** /**
* Represents a player hook into the NetServerHandler class. * Represents a player hook into the NetServerHandler class.
@ -57,7 +49,6 @@ class NetworkServerInjector extends PlayerInjector {
private volatile static CallbackFilter callbackFilter; private volatile static CallbackFilter callbackFilter;
private volatile static Field disconnectField; private volatile static Field disconnectField;
private volatile static Method sendPacketMethod;
private InjectedServerConnection serverInjection; private InjectedServerConnection serverInjection;
// Determine if we're listening // Determine if we're listening
@ -88,67 +79,6 @@ class NetworkServerInjector extends PlayerInjector {
return sendingFilters.contains(packetID); return sendingFilters.contains(packetID);
} }
@Override
public void initialize(Object injectionSource) throws IllegalAccessException {
super.initialize(injectionSource);
// Get the send packet method!
if (hasInitialized) {
if (sendPacketMethod == null) {
try {
sendPacketMethod = FuzzyReflection.fromObject(serverHandler).getMethodByName("sendPacket.*");
} catch (IllegalArgumentException e) {
Map<String, Method> netServer = getMethodList(
MinecraftReflection.getNetServerHandlerClass(), MinecraftReflection.getPacketClass());
Map<String, Method> netHandler = getMethodList(
MinecraftReflection.getNetHandlerClass(), MinecraftReflection.getPacketClass());
// Remove every method in net handler from net server
for (String methodName : netHandler.keySet()) {
netServer.remove(methodName);
}
// The remainder is the send packet method
if (netServer.size() == 1) {
Method[] methods = netServer.values().toArray(new Method[0]);
sendPacketMethod = methods[0];
} else {
throw new IllegalArgumentException("Unable to find the sendPacket method in NetServerHandler/PlayerConnection.");
}
}
}
}
}
/**
* Retrieve a method mapped list of every method with the given signature.
* @param source - class source.
* @param params - parameters.
* @return Method mapped list.
*/
private Map<String, Method> getMethodList(Class<?> source, Class<?>... params) {
return getMappedMethods(
FuzzyReflection.fromClass(source, true).
getMethodListByParameters(Void.TYPE, params)
);
}
/**
* Retrieve every method as a map over names.
* <p>
* Note that overloaded methods will only occur once in the resulting map.
* @param methods - every method.
* @return A map over every given method.
*/
private Map<String, Method> getMappedMethods(List<Method> methods) {
Map<String, Method> map = Maps.newHashMap();
for (Method method : methods) {
map.put(method.getName(), method);
}
return map;
}
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue(); Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
@ -156,7 +86,7 @@ class NetworkServerInjector extends PlayerInjector {
if (serverDelegate != null) { if (serverDelegate != 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
sendPacketMethod.invoke(serverDelegate, packet); MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw e; throw e;
@ -233,10 +163,12 @@ class NetworkServerInjector extends PlayerInjector {
// Share callback filter - that way, we avoid generating a new class for // Share callback filter - that way, we avoid generating a new class for
// every logged in player. // every logged in player.
if (callbackFilter == null) { if (callbackFilter == null) {
final Method sendPacket = MinecraftMethods.getSendPacketMethod();
callbackFilter = new CallbackFilter() { callbackFilter = new CallbackFilter() {
@Override @Override
public int accept(Method method) { public int accept(Method method) {
if (method.equals(sendPacketMethod)) if (method.equals(sendPacket))
return 0; return 0;
else else
return 1; return 1;

Datei anzeigen

@ -23,6 +23,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.Factory;
@ -30,6 +31,7 @@ import org.bukkit.Server;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.Packets; import com.comphenix.protocol.Packets;
import com.comphenix.protocol.concurrency.BlockingHashMap;
import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketAdapter;
@ -42,8 +44,11 @@ import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.server.AbstractInputStreamLookup; import com.comphenix.protocol.injector.server.AbstractInputStreamLookup;
import com.comphenix.protocol.injector.server.InputStreamLookupBuilder; import com.comphenix.protocol.injector.server.InputStreamLookupBuilder;
import com.comphenix.protocol.injector.server.SocketInjector; import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
/** /**
@ -64,6 +69,12 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
// The last successful player hook // The last successful player hook
private PlayerInjector lastSuccessfulHook; private PlayerInjector lastSuccessfulHook;
// Dummy injection
private Cache<Player, PlayerInjector> dummyInjectors =
CacheBuilder.newBuilder().
expireAfterWrite(30, TimeUnit.SECONDS).
build(BlockingHashMap.<Player, PlayerInjector>newInvalidCacheLoader());
// Player injection // Player injection
private Map<Player, PlayerInjector> playerInjection = Maps.newConcurrentMap(); private Map<Player, PlayerInjector> playerInjection = Maps.newConcurrentMap();
@ -522,12 +533,43 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
if (result instanceof PlayerInjector) if (result instanceof PlayerInjector)
return (PlayerInjector) result; return (PlayerInjector) result;
else else
return null; // Make a dummy injector them
return createDummyInjector(player);
} else { } else {
return injector; return injector;
} }
} }
/**
* Construct a simple dummy injector incase none has been constructed.
* @param player - the CraftPlayer to construct for.
* @return A dummy injector, or NULL if the given player is not a CraftPlayer.
*/
private PlayerInjector createDummyInjector(Player player) {
if (!MinecraftReflection.getCraftPlayerClass().isAssignableFrom(player.getClass())) {
// No - this is not safe
return null;
}
try {
PlayerInjector dummyInjector = getHookInstance(player, PlayerInjectHooks.NETWORK_SERVER_OBJECT);
dummyInjector.initializePlayer(player);
// This probably means the player has disconnected
if (dummyInjector.getSocket() == null) {
return null;
}
inputStreamLookup.setSocketInjector(dummyInjector.getAddress(), dummyInjector);
dummyInjectors.asMap().put(player, dummyInjector);
return dummyInjector;
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access fields.", e);
}
}
/** /**
* Retrieve a player injector by looking for its NetworkManager. * Retrieve a player injector by looking for its NetworkManager.
* @param networkManager - current network manager. * @param networkManager - current network manager.

Datei anzeigen

@ -24,11 +24,13 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher; import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/** /**
* Retrieves fields and methods by signature, not just name. * Retrieves fields and methods by signature, not just name.
@ -422,6 +424,22 @@ public class FuzzyReflection {
throw new IllegalArgumentException("Unable to find a method that matches " + matcher); throw new IllegalArgumentException("Unable to find a method that matches " + matcher);
} }
/**
* Retrieve every method as a map over names.
* <p>
* Note that overloaded methods will only occur once in the resulting map.
* @param methods - every method.
* @return A map over every given method.
*/
public Map<String, Method> getMappedMethods(List<Method> methods) {
Map<String, Method> map = Maps.newHashMap();
for (Method method : methods) {
map.put(method.getName(), method);
}
return map;
}
/** /**
* Retrieve a list of every constructor that matches the given matcher. * Retrieve a list of every constructor that matches the given matcher.
* <p> * <p>

Datei anzeigen

@ -0,0 +1,64 @@
package com.comphenix.protocol.utility;
import java.lang.reflect.Method;
import java.util.Map;
import com.comphenix.protocol.reflect.FuzzyReflection;
/**
* Static methods for accessing Minecraft methods.
*
* @author Kristian
*/
public class MinecraftMethods {
// For player connection
private volatile static Method sendPacketMethod;
/**
* Retrieve the send packet method in PlayerConnection/NetServerHandler.
* @return The send packet method.
*/
public static Method getSendPacketMethod() {
if (sendPacketMethod == null) {
Class<?> serverHandlerClass = MinecraftReflection.getNetServerHandlerClass();
try {
sendPacketMethod = FuzzyReflection.fromObject(serverHandlerClass).getMethodByName("sendPacket.*");
} catch (IllegalArgumentException e) {
Map<String, Method> netServer = getMethodList(
serverHandlerClass, MinecraftReflection.getPacketClass());
Map<String, Method> netHandler = getMethodList(
MinecraftReflection.getNetHandlerClass(), MinecraftReflection.getPacketClass());
// Remove every method in net handler from net server
for (String methodName : netHandler.keySet()) {
netServer.remove(methodName);
}
// The remainder is the send packet method
if (netServer.size() == 1) {
Method[] methods = netServer.values().toArray(new Method[0]);
sendPacketMethod = methods[0];
} else {
throw new IllegalArgumentException("Unable to find the sendPacket method in NetServerHandler/PlayerConnection.");
}
}
}
return sendPacketMethod;
}
/**
* Retrieve a method mapped list of every method with the given signature.
* @param source - class source.
* @param params - parameters.
* @return Method mapped list.
*/
private static Map<String, Method> getMethodList(Class<?> source, Class<?>... params) {
FuzzyReflection reflect = FuzzyReflection.fromClass(source, true);
return reflect.getMappedMethods(
reflect.getMethodListByParameters(Void.TYPE, params)
);
}
}