diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java index 5f6466b6..e30fe521 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java @@ -29,6 +29,7 @@ import com.comphenix.protocol.async.AsyncFilterManager; import com.comphenix.protocol.events.ConnectionSide; import com.comphenix.protocol.events.MonitorAdapter; import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.injector.DelayedSingleTask; import com.comphenix.protocol.injector.PacketFilterManager; import com.comphenix.protocol.metrics.Statistics; import com.comphenix.protocol.reflect.compiler.BackgroundCompiler; @@ -58,13 +59,17 @@ public class ProtocolLibrary extends JavaPlugin { private int tickCounter = 0; private static final int ASYNC_PACKET_DELAY = 1; + // Used to unhook players after a delay + private DelayedSingleTask unhookTask; + // Used for debugging private boolean debugListener; @Override public void onLoad() { logger = getLoggerSafely(); - protocolManager = new PacketFilterManager(getClassLoader(), getServer(), logger); + unhookTask = new DelayedSingleTask(this); + protocolManager = new PacketFilterManager(getClassLoader(), getServer(), unhookTask, logger); } @Override @@ -181,6 +186,7 @@ public class ProtocolLibrary extends JavaPlugin { asyncPacketTask = -1; } + unhookTask.close(); protocolManager.close(); protocolManager = null; statistisc = null; diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedSingleTask.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedSingleTask.java new file mode 100644 index 00000000..b44de2ee --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedSingleTask.java @@ -0,0 +1,132 @@ +package com.comphenix.protocol.injector; + +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; + +/** + * Represents a single delayed task. + * + * @author Kristian + */ +public class DelayedSingleTask { + + protected int taskID = -1; + protected Plugin plugin; + protected BukkitScheduler scheduler; + protected boolean closed; + + /** + * Create a single task scheduler. + * @param plugin - owner plugin. + */ + public DelayedSingleTask(Plugin plugin) { + this.plugin = plugin; + this.scheduler = plugin.getServer().getScheduler(); + } + + /** + * Create a single task scheduler. + * @param plugin - owner plugin. + * @param scheduler - specialized scheduler. + */ + public DelayedSingleTask(Plugin plugin, BukkitScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + /** + * Schedule a single task for execution. + *
+ * Any previously scheduled task will be automatically cancelled. + *
+ * Note that a tick delay of zero will execute the task immediately.
+ *
+ * @param ticksDelay - number of ticks before the task is executed.
+ * @param task - the task to schedule.
+ * @return TRUE if the task was successfully scheduled or executed, FALSE otherwise.
+ */
+ public boolean schedule(long ticksDelay, Runnable task) {
+ if (ticksDelay < 0)
+ throw new IllegalArgumentException("Tick delay cannot be negative.");
+ if (task == null)
+ throw new IllegalArgumentException("task cannot be NULL");
+ if (closed)
+ return false;
+
+ // Special case
+ if (ticksDelay == 0) {
+ task.run();
+ return true;
+ }
+
+ // Boilerplate, boilerplate
+ final Runnable dispatch = task;
+
+ // Don't run multiple tasks!
+ cancel();
+ taskID = scheduler.scheduleSyncDelayedTask(plugin, new Runnable() {
+ @Override
+ public void run() {
+ dispatch.run();
+ taskID = -1;
+ }
+ }, ticksDelay);
+
+ return isRunning();
+ }
+
+ /**
+ * Whether or not a future task is scheduled to be executed.
+ * @return TRUE if a current task has been scheduled for execution, FALSE otherwise.
+ */
+ public boolean isRunning() {
+ return taskID >= 0;
+ }
+
+ /**
+ * Cancel a future task from being executed.
+ * @return TRUE if a task was cancelled, FALSE otherwise.
+ */
+ public boolean cancel() {
+ if (isRunning()) {
+ scheduler.cancelTask(taskID);
+ taskID = -1;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Retrieve the raw task ID.
+ * @return Raw task ID, or negative one if no task has been scheduled.
+ */
+ public int getTaskID() {
+ return taskID;
+ }
+
+ /**
+ * Retrieve the plugin this task belongs to.
+ * @return The plugin scheduling the current taks.
+ */
+ public Plugin getPlugin() {
+ return plugin;
+ }
+
+ /**
+ * Stop the current task and all future tasks scheduled by this instance.
+ */
+ public synchronized void close() {
+ if (!closed) {
+ cancel();
+ plugin = null;
+ scheduler = null;
+ closed = true;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ }
+}
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 2ce8ab6a..2bd87891 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
@@ -90,6 +90,13 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
NETWORK_SERVER_OBJECT;
}
+ // The amount of time to wait until we actually unhook every player
+ private static final int TICKS_PER_SECOND = 20;
+ private static final int UNHOOK_DELAY = 5 * TICKS_PER_SECOND;
+
+ // Delayed unhook
+ private DelayedSingleTask unhookTask;
+
// Create a concurrent set
private Set