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
|
// 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
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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>
|
||||||
|
@ -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