Create a dummy injector if we haven't yet injected the player.
Dieser Commit ist enthalten in:
Ursprung
d387b2d792
Commit
6019ab177c
@ -47,6 +47,19 @@ public class BlockingHashMap<TKey, TValue> {
|
||||
// Map of locked objects
|
||||
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.
|
||||
*/
|
||||
@ -59,12 +72,8 @@ public class BlockingHashMap<TKey, TValue> {
|
||||
locks.remove(entry.getKey());
|
||||
}
|
||||
}).build(
|
||||
new CacheLoader<TKey, TValue>() {
|
||||
@Override
|
||||
public TValue load(TKey key) throws Exception {
|
||||
throw new IllegalStateException("Illegal use. Access the map directly instead.");
|
||||
}
|
||||
});
|
||||
BlockingHashMap.<TKey, TValue>newInvalidCacheLoader()
|
||||
);
|
||||
backingMap = backingCache.asMap();
|
||||
|
||||
// Normal concurrent hash map
|
||||
|
@ -20,15 +20,7 @@ package com.comphenix.protocol.injector.player;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
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 net.sf.cglib.proxy.*;
|
||||
|
||||
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.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Represents a player hook into the NetServerHandler class.
|
||||
@ -57,7 +49,6 @@ class NetworkServerInjector extends PlayerInjector {
|
||||
private volatile static CallbackFilter callbackFilter;
|
||||
|
||||
private volatile static Field disconnectField;
|
||||
private volatile static Method sendPacketMethod;
|
||||
private InjectedServerConnection serverInjection;
|
||||
|
||||
// Determine if we're listening
|
||||
@ -88,67 +79,6 @@ class NetworkServerInjector extends PlayerInjector {
|
||||
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
|
||||
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||
Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
|
||||
@ -156,7 +86,7 @@ class NetworkServerInjector extends PlayerInjector {
|
||||
if (serverDelegate != null) {
|
||||
try {
|
||||
// Note that invocation target exception is a wrapper for a checked exception
|
||||
sendPacketMethod.invoke(serverDelegate, packet);
|
||||
MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw e;
|
||||
@ -233,10 +163,12 @@ class NetworkServerInjector extends PlayerInjector {
|
||||
// Share callback filter - that way, we avoid generating a new class for
|
||||
// every logged in player.
|
||||
if (callbackFilter == null) {
|
||||
final Method sendPacket = MinecraftMethods.getSendPacketMethod();
|
||||
|
||||
callbackFilter = new CallbackFilter() {
|
||||
@Override
|
||||
public int accept(Method method) {
|
||||
if (method.equals(sendPacketMethod))
|
||||
if (method.equals(sendPacket))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
|
@ -23,6 +23,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.sf.cglib.proxy.Factory;
|
||||
|
||||
@ -30,6 +31,7 @@ import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.concurrency.BlockingHashMap;
|
||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
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.InputStreamLookupBuilder;
|
||||
import com.comphenix.protocol.injector.server.SocketInjector;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
@ -64,6 +69,12 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
||||
// The last successful player hook
|
||||
private PlayerInjector lastSuccessfulHook;
|
||||
|
||||
// Dummy injection
|
||||
private Cache<Player, PlayerInjector> dummyInjectors =
|
||||
CacheBuilder.newBuilder().
|
||||
expireAfterWrite(30, TimeUnit.SECONDS).
|
||||
build(BlockingHashMap.<Player, PlayerInjector>newInvalidCacheLoader());
|
||||
|
||||
// Player injection
|
||||
private Map<Player, PlayerInjector> playerInjection = Maps.newConcurrentMap();
|
||||
|
||||
@ -522,12 +533,43 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
|
||||
if (result instanceof PlayerInjector)
|
||||
return (PlayerInjector) result;
|
||||
else
|
||||
return null;
|
||||
// Make a dummy injector them
|
||||
return createDummyInjector(player);
|
||||
|
||||
} else {
|
||||
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.
|
||||
* @param networkManager - current network manager.
|
||||
|
@ -24,11 +24,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren