From 7b9d97123888b86c31ab135347ac8d4f0771c3ac Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Tue, 20 Nov 2012 03:23:43 +0100 Subject: [PATCH] Use a separate asynchronous sending queue for every online player. This ensures that packets intended for player A doesn't have to wait for the packets of player B to be finished processing. --- .../protocol/async/AsyncFilterManager.java | 105 ++++----- .../protocol/async/PacketProcessingQueue.java | 24 +- .../protocol/async/PacketSendingQueue.java | 2 +- .../protocol/async/PlayerSendingHandler.java | 217 ++++++++++++++++++ .../protocol/events/PacketEvent.java | 25 +- .../injector/PacketFilterManager.java | 119 ++++++---- 6 files changed, 376 insertions(+), 116 deletions(-) create mode 100644 ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java index 7dd7b504..44f49bba 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/async/AsyncFilterManager.java @@ -23,6 +23,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitScheduler; @@ -52,12 +53,12 @@ public class AsyncFilterManager implements AsynchronousManager { private Set timeoutListeners; private PacketProcessingQueue serverProcessingQueue; - private PacketSendingQueue serverQueue; - - private PacketProcessingQueue clientProcessingQueue; - private PacketSendingQueue clientQueue; + + // Sending queues + private PlayerSendingHandler playerSendingHandler; + // Report exceptions private ErrorReporter reporter; // The likely main thread @@ -72,38 +73,16 @@ public class AsyncFilterManager implements AsynchronousManager { // Current packet index private AtomicInteger currentSendingIndex = new AtomicInteger(); - // Whether or not we're currently cleaning up - private volatile boolean cleaningUp; - public AsyncFilterManager(ErrorReporter reporter, BukkitScheduler scheduler, ProtocolManager manager) { // Initialize timeout listeners serverTimeoutListeners = new SortedPacketListenerList(); clientTimeoutListeners = new SortedPacketListenerList(); timeoutListeners = Sets.newSetFromMap(new ConcurrentHashMap()); - - // Server packets are synchronized already - this.serverQueue = new PacketSendingQueue(false) { - @Override - protected void onPacketTimeout(PacketEvent event) { - if (!cleaningUp) { - serverTimeoutListeners.invokePacketSending(AsyncFilterManager.this.reporter, event); - } - } - }; - - // Client packets must be synchronized - this.clientQueue = new PacketSendingQueue(true) { - @Override - protected void onPacketTimeout(PacketEvent event) { - if (!cleaningUp) { - clientTimeoutListeners.invokePacketSending(AsyncFilterManager.this.reporter, event); - } - } - }; - - this.serverProcessingQueue = new PacketProcessingQueue(serverQueue); - this.clientProcessingQueue = new PacketProcessingQueue(clientQueue); + + this.playerSendingHandler = new PlayerSendingHandler(reporter, serverTimeoutListeners, clientTimeoutListeners); + this.serverProcessingQueue = new PacketProcessingQueue(playerSendingHandler); + this.clientProcessingQueue = new PacketProcessingQueue(playerSendingHandler); this.scheduler = scheduler; this.manager = manager; @@ -219,15 +198,12 @@ public class AsyncFilterManager implements AsynchronousManager { List removed = serverProcessingQueue.removeListener(handler, listener.getSendingWhitelist()); // We're already taking care of this, so don't do anything - if (!cleaningUp) - serverQueue.signalPacketUpdate(removed, synchronusOK); + playerSendingHandler.sendServerPackets(removed, synchronusOK); } if (hasValidWhitelist(listener.getReceivingWhitelist())) { List removed = clientProcessingQueue.removeListener(handler, listener.getReceivingWhitelist()); - - if (!cleaningUp) - clientQueue.signalPacketUpdate(removed, synchronusOK); + playerSendingHandler.sendClientPackets(removed, synchronusOK); } } @@ -337,15 +313,14 @@ public class AsyncFilterManager implements AsynchronousManager { @Override public void cleanupAll() { - cleaningUp = true; serverProcessingQueue.cleanupAll(); - serverQueue.cleanupAll(); - + playerSendingHandler.cleanupAll(); timeoutListeners.clear(); + serverTimeoutListeners = null; clientTimeoutListeners = null; } - + @Override public void signalPacketTransmission(PacketEvent packet) { signalPacketTransmission(packet, onMainThread()); @@ -366,8 +341,12 @@ public class AsyncFilterManager implements AsynchronousManager { "A packet must have been queued before it can be transmitted."); // Only send if the packet is ready - if (marker.decrementProcessingDelay() == 0) { - getSendingQueue(packet).signalPacketUpdate(packet, onMainThread); + if (marker.decrementProcessingDelay() == 0) { + PacketSendingQueue queue = getSendingQueue(packet, false); + + // No need to create a new queue if the player has logged out + if (queue != null) + queue.signalPacketUpdate(packet, onMainThread); } } @@ -376,8 +355,27 @@ public class AsyncFilterManager implements AsynchronousManager { * @param packet - the packet. * @return The server or client sending queue the packet belongs to. */ - private PacketSendingQueue getSendingQueue(PacketEvent packet) { - return packet.isServerPacket() ? serverQueue : clientQueue; + public PacketSendingQueue getSendingQueue(PacketEvent packet) { + return playerSendingHandler.getSendingQueue(packet); + } + + /** + * Retrieve the sending queue this packet belongs to. + * @param packet - the packet. + * @param createNew - if TRUE, create a new queue if it hasn't already been created. + * @return The server or client sending queue the packet belongs to. + */ + public PacketSendingQueue getSendingQueue(PacketEvent packet, boolean createNew) { + return playerSendingHandler.getSendingQueue(packet, createNew); + } + + /** + * Retrieve the processing queue this packet belongs to. + * @param packet - the packet. + * @return The server or client sending processing the packet belongs to. + */ + public PacketProcessingQueue getProcessingQueue(PacketEvent packet) { + return packet.isServerPacket() ? serverProcessingQueue : clientProcessingQueue; } /** @@ -388,24 +386,23 @@ public class AsyncFilterManager implements AsynchronousManager { getProcessingQueue(packet).signalProcessingDone(); } - /** - * Retrieve the processing queue this packet belongs to. - * @param packet - the packet. - * @return The server or client sending processing the packet belongs to. - */ - private PacketProcessingQueue getProcessingQueue(PacketEvent packet) { - return packet.isServerPacket() ? serverProcessingQueue : clientProcessingQueue; - } - /** * Send any due packets, or clean up packets that have expired. */ public void sendProcessedPackets(int tickCounter, boolean onMainThread) { // The server queue is unlikely to need checking that often if (tickCounter % 10 == 0) { - serverQueue.trySendPackets(onMainThread); + playerSendingHandler.trySendServerPackets(onMainThread); } + + playerSendingHandler.trySendClientPackets(onMainThread); + } - clientQueue.trySendPackets(onMainThread); + /** + * Clean up after a given player has logged out. + * @param player - the player that has just logged out. + */ + public void removePlayer(Player player) { + playerSendingHandler.removePlayer(player); } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/async/PacketProcessingQueue.java b/ProtocolLib/src/main/java/com/comphenix/protocol/async/PacketProcessingQueue.java index 23defbf2..364b6c1f 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/async/PacketProcessingQueue.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/async/PacketProcessingQueue.java @@ -58,13 +58,13 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap processingQueue; // Packets for sending - private PacketSendingQueue sendingQueue; - - public PacketProcessingQueue(PacketSendingQueue sendingQueue) { - this(sendingQueue, INITIAL_CAPACITY, DEFAULT_QUEUE_LIMIT, DEFAULT_MAXIMUM_CONCURRENCY); + private PlayerSendingHandler sendingHandler; + + public PacketProcessingQueue(PlayerSendingHandler sendingHandler) { + this(sendingHandler, INITIAL_CAPACITY, DEFAULT_QUEUE_LIMIT, DEFAULT_MAXIMUM_CONCURRENCY); } - public PacketProcessingQueue(PacketSendingQueue sendingQueue, int initialSize, int maximumSize, int maximumConcurrency) { + public PacketProcessingQueue(PlayerSendingHandler sendingHandler, int initialSize, int maximumSize, int maximumConcurrency) { super(); this.processingQueue = Synchronization.queue(MinMaxPriorityQueue. @@ -74,7 +74,7 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap sendingQueue; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java new file mode 100644 index 00000000..2854814a --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/async/PlayerSendingHandler.java @@ -0,0 +1,217 @@ +package com.comphenix.protocol.async; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import org.bukkit.entity.Player; + +import com.comphenix.protocol.error.ErrorReporter; +import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.injector.SortedPacketListenerList; + +/** + * Contains every sending queue for every player. + * + * @author Kristian + */ +class PlayerSendingHandler { + + private ErrorReporter reporter; + private ConcurrentHashMap playerSendingQueues; + + // Timeout listeners + private SortedPacketListenerList serverTimeoutListeners; + private SortedPacketListenerList clientTimeoutListeners; + + // Whether or not we're currently cleaning up + private volatile boolean cleaningUp; + + /** + * Sending queues for a given player. + * + * @author Kristian + */ + private class QueueContainer { + private PacketSendingQueue serverQueue; + private PacketSendingQueue clientQueue; + + public QueueContainer() { + // Server packets are synchronized already + serverQueue = new PacketSendingQueue(false) { + @Override + protected void onPacketTimeout(PacketEvent event) { + if (!cleaningUp) { + serverTimeoutListeners.invokePacketSending(reporter, event); + } + } + }; + + // Client packets must be synchronized + clientQueue = new PacketSendingQueue(true) { + @Override + protected void onPacketTimeout(PacketEvent event) { + if (!cleaningUp) { + clientTimeoutListeners.invokePacketSending(reporter, event); + } + } + }; + } + + public PacketSendingQueue getServerQueue() { + return serverQueue; + } + + public PacketSendingQueue getClientQueue() { + return clientQueue; + } + } + + public PlayerSendingHandler(ErrorReporter reporter, + SortedPacketListenerList serverTimeoutListeners, SortedPacketListenerList clientTimeoutListeners) { + + this.reporter = reporter; + this.serverTimeoutListeners = serverTimeoutListeners; + this.clientTimeoutListeners = clientTimeoutListeners; + + // Initialize storage of queues + playerSendingQueues = new ConcurrentHashMap(); + } + + /** + * Retrieve the sending queue this packet belongs to. + * @param packet - the packet. + * @return The server or client sending queue the packet belongs to. + */ + public PacketSendingQueue getSendingQueue(PacketEvent packet) { + return getSendingQueue(packet, true); + } + + /** + * Retrieve the sending queue this packet belongs to. + * @param packet - the packet. + * @param createNew - if TRUE, create a new queue if it hasn't already been created. + * @return The server or client sending queue the packet belongs to. + */ + public PacketSendingQueue getSendingQueue(PacketEvent packet, boolean createNew) { + String name = packet.getPlayer().getName(); + QueueContainer queues = playerSendingQueues.get(name); + + // Safe concurrent initialization + if (queues == null && createNew) { + QueueContainer previous = playerSendingQueues.putIfAbsent(name, new QueueContainer()); + + if (previous != null) + queues = previous; + } + + // Check for NULL again + if (queues != null) + return packet.isServerPacket() ? queues.getServerQueue() : queues.getClientQueue(); + else + return null; + } + + /** + * Send all pending packets. + */ + public void sendAllPackets() { + if (!cleaningUp) { + for (QueueContainer queues : playerSendingQueues.values()) { + queues.getClientQueue().cleanupAll(); + queues.getServerQueue().cleanupAll(); + } + } + } + + /** + * Immediately send every server packet with the given list of IDs. + * @param ids - ID of every packet to send immediately. + * @param synchronusOK - whether or not we're running on the main thread. + */ + public void sendServerPackets(List ids, boolean synchronusOK) { + if (!cleaningUp) { + for (QueueContainer queue : playerSendingQueues.values()) { + queue.getServerQueue().signalPacketUpdate(ids, synchronusOK); + } + } + } + + /** + * Immediately send every client packet with the given list of IDs. + * @param ids - ID of every packet to send immediately. + * @param synchronusOK - whether or not we're running on the main thread. + */ + public void sendClientPackets(List ids, boolean synchronusOK) { + if (!cleaningUp) { + for (QueueContainer queue : playerSendingQueues.values()) { + queue.getClientQueue().signalPacketUpdate(ids, synchronusOK); + } + } + } + + /** + * Send any outstanding server packets. + * @param onMainThread - whether or not this is occuring on the main thread. + */ + public void trySendServerPackets(boolean onMainThread) { + for (QueueContainer queue : playerSendingQueues.values()) { + queue.getServerQueue().trySendPackets(onMainThread); + } + } + + /** + * Send any outstanding server packets. + * @param onMainThread - whether or not this is occuring on the main thread. + */ + public void trySendClientPackets(boolean onMainThread) { + for (QueueContainer queue : playerSendingQueues.values()) { + queue.getClientQueue().trySendPackets(onMainThread); + } + } + + /** + * Retrieve every server packet queue for every player. + * @return Every sever packet queue. + */ + public List getServerQueues() { + List result = new ArrayList(); + + for (QueueContainer queue : playerSendingQueues.values()) + result.add(queue.getServerQueue()); + return result; + } + + /** + * Retrieve every client packet queue for every player. + * @return Every client packet queue. + */ + public List getClientQueues() { + List result = new ArrayList(); + + for (QueueContainer queue : playerSendingQueues.values()) + result.add(queue.getClientQueue()); + return result; + } + + /** + * Send all pending packets and clean up queues. + */ + public void cleanupAll() { + cleaningUp = true; + + sendAllPackets(); + playerSendingQueues.clear(); + } + + /** + * Invoked when a player has just logged out. + * @param player - the player that just logged out. + */ + public void removePlayer(Player player) { + String name = player.getName(); + + // Every packet will be dropped - there's nothing we can do + playerSendingQueues.remove(name); + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketEvent.java b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketEvent.java index c0580967..61062772 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketEvent.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/events/PacketEvent.java @@ -20,6 +20,7 @@ package com.comphenix.protocol.events; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.lang.ref.WeakReference; import java.util.EventObject; import org.bukkit.entity.Player; @@ -32,8 +33,10 @@ public class PacketEvent extends EventObject implements Cancellable { * Automatically generated by Eclipse. */ private static final long serialVersionUID = -5360289379097430620L; - - private transient Player player; + + private transient WeakReference playerReference; + private transient Player offlinePlayer; + private PacketContainer packet; private boolean serverPacket; private boolean cancel; @@ -52,14 +55,14 @@ public class PacketEvent extends EventObject implements Cancellable { private PacketEvent(Object source, PacketContainer packet, Player player, boolean serverPacket) { super(source); this.packet = packet; - this.player = player; + this.playerReference = new WeakReference(player); this.serverPacket = serverPacket; } private PacketEvent(PacketEvent origial, AsyncMarker asyncMarker) { super(origial.source); this.packet = origial.packet; - this.player = origial.player; + this.playerReference = origial.playerReference; this.cancel = origial.cancel; this.serverPacket = origial.serverPacket; this.asyncMarker = asyncMarker; @@ -143,7 +146,7 @@ public class PacketEvent extends EventObject implements Cancellable { * @return The player associated with this event. */ public Player getPlayer() { - return player; + return playerReference.get(); } /** @@ -197,18 +200,20 @@ public class PacketEvent extends EventObject implements Cancellable { output.defaultWriteObject(); // Write the name of the player (or NULL if it's not set) - output.writeObject(player != null ? new SerializedOfflinePlayer(player) : null); + output.writeObject(playerReference.get() != null ? new SerializedOfflinePlayer(playerReference.get()) : null); } private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException { // Default deserialization input.defaultReadObject(); - final SerializedOfflinePlayer offlinePlayer = (SerializedOfflinePlayer) input.readObject(); + final SerializedOfflinePlayer serialized = (SerializedOfflinePlayer) input.readObject(); - if (offlinePlayer != null) { - // Better than nothing - player = offlinePlayer.getPlayer(); + // Better than nothing + if (serialized != null) { + // Store it, to prevent weak reference from cleaning up the reference + offlinePlayer = serialized.getPlayer(); + playerReference = new WeakReference(offlinePlayer); } } } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index 988e773b..a8706e90 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -598,46 +598,21 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok try { manager.registerEvents(new Listener() { - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.LOWEST) public void onPrePlayerJoin(PlayerJoinEvent event) { - try { - // Let's clean up the other injection first. - playerInjection.uninjectPlayer(event.getPlayer().getAddress()); - } catch (Exception e) { - reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject net handler for player.", e, event); - } + PacketFilterManager.this.onPrePlayerJoin(event); } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerJoin(PlayerJoinEvent event) { - try { - // This call will be ignored if no listeners are registered - playerInjection.injectPlayer(event.getPlayer()); - } catch (Exception e) { - reporter.reportDetailed(PacketFilterManager.this, "Unable to inject player.", e, event); - } + PacketFilterManager.this.onPlayerJoin(event); } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + @EventHandler(priority = EventPriority.MONITOR) public void onPlayerQuit(PlayerQuitEvent event) { - try { - playerInjection.handleDisconnect(event.getPlayer()); - playerInjection.uninjectPlayer(event.getPlayer()); - } catch (Exception e) { - reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject logged off player.", e, event); - } + PacketFilterManager.this.onPlayerQuit(event); } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + @EventHandler(priority = EventPriority.MONITOR) public void onPluginDisabled(PluginDisableEvent event) { - try { - // Clean up in case the plugin forgets - if (event.getPlugin() != plugin) { - removePacketListeners(event.getPlugin()); - } - } catch (Exception e) { - reporter.reportDetailed(PacketFilterManager.this, "Unable handle disabled plugin.", e, event); - } + PacketFilterManager.this.onPluginDisabled(event, plugin); } }, plugin); @@ -648,6 +623,47 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok } } + private void onPrePlayerJoin(PlayerJoinEvent event) { + try { + // Let's clean up the other injection first. + playerInjection.uninjectPlayer(event.getPlayer().getAddress()); + } catch (Exception e) { + reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject net handler for player.", e, event); + } + } + + private void onPlayerJoin(PlayerJoinEvent event) { + try { + // This call will be ignored if no listeners are registered + playerInjection.injectPlayer(event.getPlayer()); + } catch (Exception e) { + reporter.reportDetailed(PacketFilterManager.this, "Unable to inject player.", e, event); + } + } + + private void onPlayerQuit(PlayerQuitEvent event) { + try { + Player player = event.getPlayer(); + + asyncFilterManager.removePlayer(player); + playerInjection.handleDisconnect(player); + playerInjection.uninjectPlayer(player); + } catch (Exception e) { + reporter.reportDetailed(PacketFilterManager.this, "Unable to uninject logged off player.", e, event); + } + } + + private void onPluginDisabled(PluginDisableEvent event, Plugin protocolLibrary) { + try { + // Clean up in case the plugin forgets + if (event.getPlugin() != protocolLibrary) { + removePacketListeners(event.getPlugin()); + } + } catch (Exception e) { + reporter.reportDetailed(PacketFilterManager.this, "Unable handle disabled plugin.", e, event); + } + } + /** * Retrieve the number of listeners that expect packets during playing. * @return Number of listeners. @@ -689,7 +705,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok // Yes, this is crazy. @SuppressWarnings({ "unchecked", "rawtypes" }) - private void registerOld(PluginManager manager, Plugin plugin) { + private void registerOld(PluginManager manager, final Plugin plugin) { try { ClassLoader loader = manager.getClass().getClassLoader(); @@ -699,6 +715,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok Class eventPriority = loader.loadClass("org.bukkit.event.Event$Priority"); // Get the priority + Object priorityLowest = Enum.valueOf(eventPriority, "Lowest"); Object priorityMonitor = Enum.valueOf(eventPriority, "Monitor"); // Get event types @@ -714,26 +731,40 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok Method registerEvent = FuzzyReflection.fromObject(manager).getMethodByParameters("registerEvent", eventTypes, Listener.class, eventPriority, Plugin.class); + Enhancer playerLow = new Enhancer(); Enhancer playerEx = new Enhancer(); Enhancer serverEx = new Enhancer(); - playerEx.setSuperclass(playerListener); - playerEx.setClassLoader(classLoader); - playerEx.setCallback(new MethodInterceptor() { + playerLow.setSuperclass(playerListener); + playerLow.setClassLoader(classLoader); + playerLow.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // Must have a parameter + if (args.length == 1) { + Object event = args[0]; + + if (event instanceof PlayerJoinEvent) { + onPrePlayerJoin((PlayerJoinEvent) event); + } + } + return null; + } + }); + + playerEx.setSuperclass(playerListener); + playerEx.setClassLoader(classLoader); + playerEx.setCallback(new MethodInterceptor() { + @Override + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if (args.length == 1) { Object event = args[0]; // Check for the correct event if (event instanceof PlayerJoinEvent) { - Player player = ((PlayerJoinEvent) event).getPlayer(); - playerInjection.injectPlayer(player); + onPlayerJoin((PlayerJoinEvent) event); } else if (event instanceof PlayerQuitEvent) { - Player player = ((PlayerQuitEvent) event).getPlayer(); - playerInjection.handleDisconnect(player); - playerInjection.uninjectPlayer(player); + onPlayerQuit((PlayerQuitEvent) event); } } return null; @@ -751,16 +782,18 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok Object event = args[0]; if (event instanceof PluginDisableEvent) - removePacketListeners(((PluginDisableEvent) event).getPlugin()); + onPluginDisabled((PluginDisableEvent) event, plugin); } return null; } }); // Create our listener + Object playerProxyLow = playerLow.create(); Object playerProxy = playerEx.create(); Object serverProxy = serverEx.create(); + registerEvent.invoke(manager, playerJoinType, playerProxyLow, priorityLowest, plugin); registerEvent.invoke(manager, playerJoinType, playerProxy, priorityMonitor, plugin); registerEvent.invoke(manager, playerQuitType, playerProxy, priorityMonitor, plugin); registerEvent.invoke(manager, pluginDisabledType, serverProxy, priorityMonitor, plugin);