Archiviert
13
0

Add support for the Netty Spigot build.

This required extensive reworking of the inner packet injection system
in ProtocolLib. 

I've also fixed a minior bug in the fuzzy member contract class.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-02-05 07:00:49 +01:00
Ursprung e8112dba0e
Commit 901ab1fdda
13 geänderte Dateien mit 750 neuen und 42 gelöschten Zeilen

Datei anzeigen

@ -78,9 +78,9 @@ class CleanupStaticMembers {
"com.comphenix.protocol.injector.player.PlayerInjector", "com.comphenix.protocol.injector.player.PlayerInjector",
"com.comphenix.protocol.injector.player.TemporaryPlayerFactory", "com.comphenix.protocol.injector.player.TemporaryPlayerFactory",
"com.comphenix.protocol.injector.EntityUtilities", "com.comphenix.protocol.injector.EntityUtilities",
"com.comphenix.protocol.injector.MinecraftRegistry", "com.comphenix.protocol.injector.packet.PacketRegistry",
"com.comphenix.protocol.injector.PacketInjector", "com.comphenix.protocol.injector.packet.PacketInjector",
"com.comphenix.protocol.injector.ReadPacketModifier", "com.comphenix.protocol.injector.packet.ReadPacketModifier",
"com.comphenix.protocol.injector.StructureCache", "com.comphenix.protocol.injector.StructureCache",
"com.comphenix.protocol.reflect.compiler.BoxingHelper", "com.comphenix.protocol.reflect.compiler.BoxingHelper",
"com.comphenix.protocol.reflect.compiler.MethodDescriptor" "com.comphenix.protocol.reflect.compiler.MethodDescriptor"

Datei anzeigen

@ -44,7 +44,7 @@ public class IntegerSet {
/** /**
* Determine whether or not the given element exists in the set. * Determine whether or not the given element exists in the set.
* @param value - the element to check. Must be in the range [0, count). * @param element - the element to check. Must be in the range [0, count).
* @return TRUE if the given element exists, FALSE otherwise. * @return TRUE if the given element exists, FALSE otherwise.
*/ */
public boolean contains(int element) { public boolean contains(int element) {

Datei anzeigen

@ -56,6 +56,7 @@ import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
import com.comphenix.protocol.injector.packet.PacketRegistry; import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler; import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.injector.player.PlayerInjectorBuilder; import com.comphenix.protocol.injector.player.PlayerInjectorBuilder;
import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
@ -142,6 +143,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
// Whether or not plugins are using the send/receive methods // Whether or not plugins are using the send/receive methods
private AtomicBoolean packetCreation = new AtomicBoolean(); private AtomicBoolean packetCreation = new AtomicBoolean();
// Spigot listener, if in use
private SpigotPacketInjector spigotInjector;
/** /**
* Only create instances of this class if protocol lib is disabled. * Only create instances of this class if protocol lib is disabled.
* @param unhookTask * @param unhookTask
@ -181,22 +185,30 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
}; };
try { try {
// Initialize injection mangers // Spigot
this.playerInjection = PlayerInjectorBuilder.newBuilder(). if (SpigotPacketInjector.canUseSpigotListener()) {
invoker(this). spigotInjector = new SpigotPacketInjector(classLoader, reporter, this, server);
server(server). this.playerInjection = spigotInjector.getPlayerHandler();
reporter(reporter). this.packetInjector = spigotInjector.getPacketInjector();
classLoader(classLoader).
packetListeners(packetListeners). } else {
injectionFilter(isInjectionNecessary). // Initialize standard injection mangers
buildHandler(); this.playerInjection = PlayerInjectorBuilder.newBuilder().
invoker(this).
this.packetInjector = PacketInjectorBuilder.newBuilder(). server(server).
invoker(this). reporter(reporter).
reporter(reporter). classLoader(classLoader).
classLoader(classLoader). packetListeners(packetListeners).
playerInjection(playerInjection). injectionFilter(isInjectionNecessary).
buildInjector(); buildHandler();
this.packetInjector = PacketInjectorBuilder.newBuilder().
invoker(this).
reporter(reporter).
classLoader(classLoader).
playerInjection(playerInjection).
buildInjector();
}
this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this); this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this);
@ -618,6 +630,8 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
* @param plugin - the parent plugin. * @param plugin - the parent plugin.
*/ */
public void registerEvents(PluginManager manager, final Plugin plugin) { public void registerEvents(PluginManager manager, final Plugin plugin) {
if (spigotInjector != null && !spigotInjector.register(plugin))
throw new IllegalArgumentException("Spigot has already been registered.");
try { try {
manager.registerEvents(new Listener() { manager.registerEvents(new Listener() {

Datei anzeigen

@ -28,6 +28,7 @@ import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.bukkit.Server;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.Packets; import com.comphenix.protocol.Packets;
@ -38,13 +39,14 @@ import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.player.TemporaryPlayerFactory.InjectContainer;
/** /**
* Injection method that overrides the NetworkHandler itself, and it's sendPacket-method. * Injection method that overrides the NetworkHandler itself, and it's queue-method.
* *
* @author Kristian * @author Kristian
*/ */
class NetworkObjectInjector extends PlayerInjector { public class NetworkObjectInjector extends PlayerInjector {
// Determine if we're listening // Determine if we're listening
private IntegerSet sendingFilters; private IntegerSet sendingFilters;
@ -54,6 +56,9 @@ class NetworkObjectInjector extends PlayerInjector {
// Shared callback filter - avoid creating a new class every time // Shared callback filter - avoid creating a new class every time
private static CallbackFilter callbackFilter; private static CallbackFilter callbackFilter;
// Temporary player factory
private static volatile TemporaryPlayerFactory tempPlayerFactory;
public NetworkObjectInjector(ClassLoader classLoader, ErrorReporter reporter, Player player, public NetworkObjectInjector(ClassLoader classLoader, ErrorReporter reporter, Player player,
ListenerInvoker invoker, IntegerSet sendingFilters) throws IllegalAccessException { ListenerInvoker invoker, IntegerSet sendingFilters) throws IllegalAccessException {
super(reporter, player, invoker); super(reporter, player, invoker);
@ -66,6 +71,21 @@ class NetworkObjectInjector extends PlayerInjector {
return sendingFilters.contains(packetID); return sendingFilters.contains(packetID);
} }
/**
* Create a temporary player for use during login.
* @param server - Bukkit server.
* @return The temporary player.
*/
public Player createTemporaryPlayer(Server server) {
if (tempPlayerFactory == null)
tempPlayerFactory = new TemporaryPlayerFactory();
// Create and associate this fake player with this network injector
Player player = tempPlayerFactory.createTemporaryPlayer(server);
((InjectContainer) player).setInjector(this);
return player;
}
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue(); Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue();

Datei anzeigen

@ -52,7 +52,7 @@ import com.google.common.collect.Maps;
* *
* @author Kristian * @author Kristian
*/ */
public class NetworkServerInjector extends PlayerInjector { class NetworkServerInjector extends PlayerInjector {
private volatile static CallbackFilter callbackFilter; private volatile static CallbackFilter callbackFilter;

Datei anzeigen

@ -58,10 +58,10 @@ abstract class PlayerInjector {
protected static Field proxyServerField; protected static Field proxyServerField;
protected static Field networkManagerField; protected static Field networkManagerField;
protected static Field inputField;
protected static Field netHandlerField; protected static Field netHandlerField;
protected static Field socketField; protected static Field socketField;
private static Field inputField;
private static Field entityPlayerField; private static Field entityPlayerField;
// Whether or not we're using a proxy type // Whether or not we're using a proxy type
@ -206,11 +206,6 @@ abstract class PlayerInjector {
if (queueMethod == null) if (queueMethod == null)
queueMethod = FuzzyReflection.fromClass(reference.getType()). queueMethod = FuzzyReflection.fromClass(reference.getType()).
getMethodByParameters("queue", MinecraftReflection.getPacketClass()); getMethodByParameters("queue", MinecraftReflection.getPacketClass());
// And the data input stream that we'll use to identify a player
if (inputField == null)
inputField = FuzzyReflection.fromObject(networkManager, true).
getFieldByType("java\\.io\\.DataInputStream");
} }
/** /**
@ -250,9 +245,9 @@ abstract class PlayerInjector {
public Socket getSocket() throws IllegalAccessException { public Socket getSocket() throws IllegalAccessException {
try { try {
if (socketField == null) if (socketField == null)
socketField = FuzzyReflection.fromObject(networkManager).getFieldListByType(Socket.class).get(0); socketField = FuzzyReflection.fromObject(networkManager, true).getFieldListByType(Socket.class).get(0);
if (socket == null) if (socket == null)
socket = (Socket) FieldUtils.readField(socketField, networkManager); socket = (Socket) FieldUtils.readField(socketField, networkManager, true);
return socket; return socket;
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
@ -570,11 +565,13 @@ abstract class PlayerInjector {
* @return The player's input stream. * @return The player's input stream.
*/ */
public DataInputStream getInputStream(boolean cache) { public DataInputStream getInputStream(boolean cache) {
if (inputField == null) // And the data input stream that we'll use to identify a player
throw new IllegalStateException("Input field is NULL.");
if (networkManager == null) if (networkManager == null)
throw new IllegalStateException("Network manager is NULL."); throw new IllegalStateException("Network manager is NULL.");
if (inputField == null)
inputField = FuzzyReflection.fromObject(networkManager, true).
getFieldByType("java\\.io\\.DataInputStream");
// Get the associated input stream // Get the associated input stream
try { try {
if (cache && cachedInput != null) if (cache && cachedInput != null)
@ -604,6 +601,16 @@ abstract class PlayerInjector {
return player; return player;
} }
/**
* Set the hooked player.
* <p>
* Should only be called during the creation of the injector.
* @param player - the new hooked player.
*/
public void setPlayer(Player player) {
this.player = player;
}
/** /**
* Object that can invoke the packet events. * Object that can invoke the packet events.
* @return Packet event invoker. * @return Packet event invoker.
@ -622,4 +629,12 @@ abstract class PlayerInjector {
else else
return player; return player;
} }
/**
* Set the real Bukkit player that we will use.
* @param updatedPlayer - the real Bukkit player.
*/
public void setUpdatedPlayer(Player updatedPlayer) {
this.updatedPlayer = updatedPlayer;
}
} }

Datei anzeigen

@ -138,7 +138,8 @@ public class PlayerInjectorBuilder {
// Fill any default fields // Fill any default fields
initializeDefaults(); initializeDefaults();
return new ProxyPlayerInjectionHandler(classLoader, reporter, injectionFilter, invoker, return new ProxyPlayerInjectionHandler(
packetListeners, server); classLoader, reporter, injectionFilter,
invoker, packetListeners, server);
} }
} }

Datei anzeigen

@ -81,7 +81,7 @@ class TemporaryPlayerFactory {
* </ul> * </ul>
* <p> * <p>
* Note that the player a player has not been assigned a name yet, and thus cannot be * Note that the player a player has not been assigned a name yet, and thus cannot be
* uniquely identified. Use the * uniquely identified. Use the address instead.
* @param injector - the player injector used. * @param injector - the player injector used.
* @param server - the current server. * @param server - the current server.
* @return A temporary player instance. * @return A temporary player instance.

Datei anzeigen

@ -0,0 +1,57 @@
package com.comphenix.protocol.injector.spigot;
import java.util.Set;
import org.bukkit.entity.Player;
import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.packet.PacketInjector;
public class DummyPacketInjector implements PacketInjector {
private SpigotPacketInjector injector;
private IntegerSet reveivedFilters;
public DummyPacketInjector(SpigotPacketInjector injector, IntegerSet reveivedFilters) {
this.injector = injector;
this.reveivedFilters = reveivedFilters;
}
@Override
public void undoCancel(Integer id, Object packet) {
// Do nothing yet
}
@Override
public boolean addPacketHandler(int packetID) {
reveivedFilters.add(packetID);
return true;
}
@Override
public boolean removePacketHandler(int packetID) {
reveivedFilters.remove(packetID);
return true;
}
@Override
public boolean hasPacketHandler(int packetID) {
return reveivedFilters.contains(packetID);
}
@Override
public Set<Integer> getPacketHandlers() {
return reveivedFilters.toSet();
}
@Override
public PacketEvent packetRecieved(PacketContainer packet, Player client) {
return injector.packetReceived(packet, client);
}
@Override
public void cleanupAll() {
reveivedFilters.clear();
}
}

Datei anzeigen

@ -0,0 +1,123 @@
package com.comphenix.protocol.injector.spigot;
import java.io.DataInputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.bukkit.entity.Player;
import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
class DummyPlayerHandler implements PlayerInjectionHandler {
private SpigotPacketInjector injector;
private IntegerSet sendingFilters;
public DummyPlayerHandler(SpigotPacketInjector injector, IntegerSet sendingFilters) {
this.injector = injector;
this.sendingFilters = sendingFilters;
}
@Override
public boolean uninjectPlayer(InetSocketAddress address) {
return true;
}
@Override
public boolean uninjectPlayer(Player player) {
injector.uninjectPlayer(player);
return true;
}
@Override
public void setPlayerHook(GamePhase phase, PlayerInjectHooks playerHook) {
throw new UnsupportedOperationException("This is not needed in Spigot.");
}
@Override
public void setPlayerHook(PlayerInjectHooks playerHook) {
throw new UnsupportedOperationException("This is not needed in Spigot.");
}
@Override
public void scheduleDataInputRefresh(Player player) {
// Fine
}
@Override
public void addPacketHandler(int packetID) {
sendingFilters.add(packetID);
}
@Override
public void removePacketHandler(int packetID) {
sendingFilters.remove(packetID);
}
@Override
public Set<Integer> getSendingFilters() {
return sendingFilters.toSet();
}
@Override
public void close() {
sendingFilters.clear();
}
@Override
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException {
injector.sendServerPacket(reciever, packet, filters);
}
@Override
public void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
injector.processPacket(player, mcPacket);
}
@Override
public void injectPlayer(Player player) {
injector.injectPlayer(player);
}
@Override
public void handleDisconnect(Player player) {
// Just ignore
}
@Override
public PlayerInjectHooks getPlayerHook(GamePhase phase) {
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
}
@Override
public PlayerInjectHooks getPlayerHook() {
// Pretend that we do
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
}
@Override
public Player getPlayerByConnection(DataInputStream inputStream, long playerTimeout, TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException("This is not needed in Spigot.");
}
@Override
public Player getPlayerByConnection(DataInputStream inputStream) throws InterruptedException {
throw new UnsupportedOperationException("This is not needed in Spigot.");
}
@Override
public void checkListener(PacketListener listener) {
// They're all fine!
}
@Override
public void checkListener(Set<PacketListener> listeners) {
// Yes, really
}
}

Datei anzeigen

@ -0,0 +1,447 @@
package com.comphenix.protocol.injector.spigot;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PlayerLoggedOutException;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.player.NetworkObjectInjector;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.reflect.MethodInfo;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.MapMaker;
/**
* Offload all the work to Spigot, if possible.
*
* @author Kristian
*/
public class SpigotPacketInjector implements SpigotPacketListener {
// Lazily retrieve the spigot listener class
private static volatile Class<?> spigotListenerClass;
private static volatile boolean classChecked;
// Packets that are not to be processed by the filters
private Set<Object> ignoredPackets = Collections.newSetFromMap(new MapMaker().weakKeys().<Object, Boolean>makeMap());
/**
* The amount of ticks to wait before removing all traces of a player.
*/
private static final int CLEANUP_DELAY = 100;
/**
* Retrieve the spigot packet listener class.
* @return The listener class.
*/
private static Class<?> getSpigotListenerClass() {
if (!classChecked) {
try {
spigotListenerClass = SpigotPacketInjector.class.getClassLoader().loadClass("org.spigotmc.netty.PacketListener");
} catch (ClassNotFoundException e) {
return null;
} finally {
// We've given it a try now
classChecked = true;
}
}
return spigotListenerClass;
}
/**
* Retrieve the register packet listener method.
* @return The method used to register a packet listener.
*/
private static Method getRegisterMethod() {
Class<?> clazz = getSpigotListenerClass();
if (clazz != null) {
try {
return clazz.getMethod("register", clazz, Plugin.class);
} catch (SecurityException e) {
// If this happens, then ... we're doomed
throw new RuntimeException("Reflection is not allowed.", e);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Cannot find register() method in " + clazz, e);
}
}
// Also bad
throw new IllegalStateException("Spigot could not be found!");
}
/**
* Determine if there is a Spigot packet listener.
* @return Spigot packet listener.
*/
public static boolean canUseSpigotListener() {
return getSpigotListenerClass() != null;
}
// The listener we will register on Spigot.
// Unfortunately, due to the use of PlayerConnection, INetworkManager and Packet, we're
// unable to reference it directly. But with CGLib, it shouldn't cost us much.
private Object dynamicListener;
// Reference to ProtocolLib
private Plugin plugin;
// Different sending filters
private IntegerSet queuedFilters;
private IntegerSet reveivedFilters;
// NetworkManager to injector and player
private ConcurrentMap<Object, NetworkObjectInjector> networkManagerInjector = new ConcurrentHashMap<Object, NetworkObjectInjector>();
// Player to injector
private ConcurrentMap<Player, NetworkObjectInjector> playerInjector = new ConcurrentHashMap<Player, NetworkObjectInjector>();
// Responsible for informing the PL packet listeners
private ListenerInvoker invoker;
private ErrorReporter reporter;
private Server server;
private ClassLoader classLoader;
/**
* Create a new spigot injector.
*/
public SpigotPacketInjector(ClassLoader classLoader, ErrorReporter reporter, ListenerInvoker invoker, Server server) {
this.classLoader = classLoader;
this.reporter = reporter;
this.invoker = invoker;
this.server = server;
this.queuedFilters = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1);
this.reveivedFilters = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1);
}
public boolean register(Plugin plugin) {
if (hasRegistered())
return false;
// Save the plugin too
this.plugin = plugin;
final Callback[] callbacks = new Callback[3];
final boolean[] found = new boolean[3];
// Packets received from the clients
callbacks[0] = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return SpigotPacketInjector.this.packetReceived(args[0], args[1], args[2]);
}
};
// Packet sent/queued
callbacks[1] = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return SpigotPacketInjector.this.packetQueued(args[0], args[1], args[2]);
}
};
// Don't care for everything else
callbacks[2] = NoOp.INSTANCE;
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(classLoader);
enhancer.setSuperclass(getSpigotListenerClass());
enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
// We'll be pretty stringent
if (matchMethod("packetReceived", method)) {
found[0] = true;
return 0;
} else if (matchMethod("packetQueued", method)) {
found[1] = true;
return 1;
} else {
found[2] = true;
return 2;
}
}
});
dynamicListener = enhancer.create();
// Verify methods
if (!found[0])
throw new IllegalStateException("Unable to find a valid packet receiver in Spigot.");
if (!found[1])
throw new IllegalStateException("Unable to find a valid packet queue in Spigot.");
// Lets register it too
try {
getRegisterMethod().invoke(null, dynamicListener, plugin);
} catch (Exception e) {
throw new RuntimeException("Cannot register Spigot packet listener.", e);
}
// If we succeed
return true;
}
/**
* Determine if the given method is a valid packet receiver or queued method.
* @param methodName - the expected name of the method.
* @param method - the method we're testing.
* @return TRUE if this is a correct method, FALSE otherwise.
*/
private boolean matchMethod(String methodName, Method method) {
return FuzzyMethodContract.newBuilder().
nameExact(methodName).
parameterCount(3).
parameterSuperOf(MinecraftReflection.getNetHandlerClass(), 1).
parameterSuperOf(MinecraftReflection.getPacketClass(), 2).
returnTypeExact(MinecraftReflection.getPacketClass()).
build().
isMatch(MethodInfo.fromMethod(method), null);
}
public boolean hasRegistered() {
return dynamicListener != null;
}
public PlayerInjectionHandler getPlayerHandler() {
return new DummyPlayerHandler(this, queuedFilters);
}
public PacketInjector getPacketInjector() {
return new DummyPacketInjector(this, reveivedFilters);
}
/**
* Retrieve the currently registered injector for the given player.
* @param player - injected player.
* @return The injector.
*/
NetworkObjectInjector getInjector(Player player) {
return playerInjector.get(player);
}
/**
* Retrieve or create a registered injector for the given network manager and connection.
* @param networkManager - a INetworkManager object.
* @param connection - a Connection (PlayerConnection, PendingConnection) object.
* @return The created NetworkObjectInjector with a temporary player.
*/
NetworkObjectInjector getInjector(Object networkManager, Object connection) {
NetworkObjectInjector dummyInjector = networkManagerInjector.get(networkManager);
if (dummyInjector == null) {
// Inject the network manager
try {
NetworkObjectInjector created = new NetworkObjectInjector(classLoader, reporter, null, invoker, null);
created.initializeLogin(connection);
created.setPlayer(created.createTemporaryPlayer(server));
dummyInjector = saveInjector(networkManager, created);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create dummy injector.", e);
}
}
return dummyInjector;
}
/**
* Save a given player injector for later.
* @param networkManager - the associated network manager.
* @param created - the created network object creator.
* @return Any other network injector that came before us.
*/
private NetworkObjectInjector saveInjector(Object networkManager, NetworkObjectInjector created) {
// Concurrency - use the same injector!
NetworkObjectInjector result = networkManagerInjector.putIfAbsent(networkManager, created);
if (result == null) {
result = created;
}
// Save the player as well
playerInjector.put(created.getPlayer(), created);
return result;
}
@Override
public Object packetReceived(Object networkManager, Object connection, Object packet) {
Integer id = invoker.getPacketID(packet);
if (id != null && reveivedFilters.contains(id)) {
// Check for ignored packets
if (ignoredPackets.remove(packet)) {
return packet;
}
Player sender = getInjector(networkManager, connection).getUpdatedPlayer();
PacketContainer container = new PacketContainer(id, packet);
PacketEvent event = packetReceived(container, sender);
if (!event.isCancelled())
return event.getPacket().getHandle();
else
return null; // Cancel
}
// Don't change anything
return packet;
}
@Override
public Object packetQueued(Object networkManager, Object connection, Object packet) {
Integer id = invoker.getPacketID(packet);
if (id != null & queuedFilters.contains(id)) {
// Check for ignored packets
if (ignoredPackets.remove(packet)) {
return packet;
}
Player reciever = getInjector(networkManager, connection).getUpdatedPlayer();
PacketContainer container = new PacketContainer(id, packet);
PacketEvent event = packetQueued(container, reciever);
if (!event.isCancelled())
return event.getPacket().getHandle();
else
return null; // Cancel
}
// Don't change anything
return packet;
}
/**
* Called to inform the event listeners of a queued packet.
* @param packet - the packet that is to be sent.
* @param reciever - the reciever of this packet.
* @return The packet event that was used.
*/
PacketEvent packetQueued(PacketContainer packet, Player reciever) {
PacketEvent event = PacketEvent.fromServer(this, packet, reciever);
invoker.invokePacketSending(event);
return event;
}
/**
* Called to inform the event listeners of a received packet.
* @param packet - the packet that has been receieved.
* @param sender - the client packet.
* @return The packet event that was used.
*/
PacketEvent packetReceived(PacketContainer packet, Player sender) {
PacketEvent event = PacketEvent.fromClient(this, packet, sender);
invoker.invokePacketRecieving(event);
return event;
}
/**
* Called when a player has logged in properly.
* @param player - the player that has logged in.
*/
void injectPlayer(Player player) {
try {
NetworkObjectInjector dummy = new NetworkObjectInjector(classLoader, reporter, player, invoker, null);
dummy.initializePlayer(player);
// Save this player for the network manager
NetworkObjectInjector realInjector = networkManagerInjector.get(dummy.getNetworkManager());
if (realInjector != null) {
// Update all future references
realInjector.setUpdatedPlayer(player);
playerInjector.put(player, realInjector);
} else {
// Ah - in that case, save this injector
saveInjector(dummy.getNetworkManager(), dummy);
}
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot inject " + player);
}
}
/**
* Uninject the given player.
* @param player - the player to uninject.
*/
void uninjectPlayer(Player player) {
final NetworkObjectInjector injector = getInjector(player);
if (player != null) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
// Clean up
playerInjector.remove(injector.getPlayer());
playerInjector.remove(injector.getUpdatedPlayer());
networkManagerInjector.remove(injector);
}
}, CLEANUP_DELAY);
}
}
/**
* Invoked when a plugin wants to sent a packet.
* @param reciever - the packet receiver.
* @param packet - the packet to transmit.
* @param filters - whether or not to invoke the packet listeners.
* @throws InvocationTargetException If anything went wrong.
*/
void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException {
NetworkObjectInjector networkObject = getInjector(reciever);
// If TRUE, process this packet like any other
if (filters)
ignoredPackets.remove(packet.getHandle());
else
ignoredPackets.add(packet.getHandle());
if (networkObject != null)
networkObject.sendServerPacket(packet.getHandle(), filters);
else
throw new PlayerLoggedOutException("Player " + reciever + " has logged out");
}
/**
* Invoked when a plugin wants to simulate receiving a packet.
* @param player - the supposed sender.
* @param mcPacket - the packet to receieve.
* @throws IllegalAccessException Reflection is not permitted.
* @throws InvocationTargetException Minecraft threw an exception.
*/
void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
NetworkObjectInjector networkObject = getInjector(player);
// We will always ignore this packet
ignoredPackets.add(mcPacket);
if (networkObject != null)
networkObject.processPacket(mcPacket);
else
throw new PlayerLoggedOutException("Player " + player + " has logged out");
}
}

Datei anzeigen

@ -0,0 +1,34 @@
package com.comphenix.protocol.injector.spigot;
/**
* Represents a proxy for a Spigot packet listener.
*
* @author Kristian
*/
interface SpigotPacketListener {
/**
* Called when a packet has been received and is about to be handled by the
* current Connection.
* <p>
* The returned packet will be the packet passed on for handling, or in the case of
* null being returned, not handled at all.
*
* @param networkManager the NetworkManager receiving the packet
* @param connection the connection which will handle the packet
* @param packet the received packet
* @return the packet to be handled, or null to cancel
*/
public Object packetReceived(Object networkManager, Object connection, Object packet);
/**
* Called when a packet is queued to be sent.The returned packet will be
* the packet sent. In the case of null being returned, the packet will not
* be sent.
*
* @param networkManager the NetworkManager which will send the packet
* @param connection the connection which queued the packet
* @param packet the queue packet
* @return the packet to be sent, or null if the packet will not be sent.
*/
public Object packetQueued(Object networkManager, Object connection, Object packet);
}

Datei anzeigen

@ -153,10 +153,7 @@ public abstract class AbstractFuzzyMember<T extends Member> extends AbstractFuzz
* Use this to prepare any special values. * Use this to prepare any special values.
*/ */
protected void prepareBuild() { protected void prepareBuild() {
// Permit any modifier if we havent's specified anything // No need to prepare anything
if (modifiersRequired == 0) {
modifiersRequired = Integer.MAX_VALUE;
}
} }
// Clone a given contract // Clone a given contract