diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
index 07330826..29dfebaf 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolLibrary.java
@@ -173,8 +173,14 @@ public class ProtocolLibrary extends JavaPlugin {
updater = new Updater(this, logger, "protocollib", getFile(), "protocol.info");
unhookTask = new DelayedSingleTask(this);
- protocolManager = PacketFilterManager.createManager(
- getClassLoader(), getServer(), this, version, unhookTask, reporter);
+ protocolManager = PacketFilterManager.newBuilder().
+ classLoader(getClassLoader()).
+ server(getServer()).
+ library(this).
+ minecraftVersion(version).
+ unhookTask(unhookTask).
+ reporter(reporter).
+ build();
// Setup error reporter
detailedReporter.addGlobalParameter("manager", protocolManager);
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java
new file mode 100644
index 00000000..1edad3c8
--- /dev/null
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterBuilder.java
@@ -0,0 +1,255 @@
+package com.comphenix.protocol.injector;
+
+import javax.annotation.Nonnull;
+
+import org.bukkit.Server;
+import org.bukkit.event.world.WorldInitEvent;
+import org.bukkit.plugin.Plugin;
+
+import com.comphenix.executors.BukkitFutures;
+import com.comphenix.protocol.async.AsyncFilterManager;
+import com.comphenix.protocol.error.ErrorReporter;
+import com.comphenix.protocol.error.Report;
+import com.comphenix.protocol.error.ReportType;
+import com.comphenix.protocol.injector.player.InjectedServerConnection;
+import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
+import com.comphenix.protocol.utility.MinecraftReflection;
+import com.comphenix.protocol.utility.MinecraftVersion;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
+public class PacketFilterBuilder {
+ public static final ReportType REPORT_TEMPORARY_EVENT_ERROR = new ReportType("Unable to register or handle temporary event.");
+
+ private ClassLoader classLoader;
+ private Server server;
+ private Plugin library;
+ private MinecraftVersion mcVersion;
+ private DelayedSingleTask unhookTask;
+ private ErrorReporter reporter;
+
+ // Whether or not we need to enable Netty
+ private AsyncFilterManager asyncManager;
+ private boolean nettyEnabled;
+
+ /**
+ * Update the current class loader.
+ * @param classLoader - current class loader.
+ * @return This builder, for chaining.
+ */
+ public PacketFilterBuilder classLoader(@Nonnull ClassLoader classLoader) {
+ if (classLoader == null)
+ throw new IllegalArgumentException("classLoader cannot be NULL.");
+ this.classLoader = classLoader;
+ return this;
+ }
+
+ /**
+ * Set the current server.
+ * @param server - current server.
+ * @return This builder, for chaining.
+ */
+ public PacketFilterBuilder server(@Nonnull Server server) {
+ if (server == null)
+ throw new IllegalArgumentException("server cannot be NULL.");
+ this.server = server;
+ return this;
+ }
+
+ /**
+ * Set a reference to the plugin instance of ProtocolLib.
+ * @param library - plugin instance.
+ * @return This builder, for chaining.
+ */
+ public PacketFilterBuilder library(@Nonnull Plugin library) {
+ if (library == null)
+ throw new IllegalArgumentException("library cannot be NULL.");
+ this.library = library;
+ return this;
+ }
+
+ /**
+ * Set the current Minecraft version.
+ * @param mcVersion - Minecraft version.
+ * @return This builder, for chaining.
+ */
+ public PacketFilterBuilder minecraftVersion(@Nonnull MinecraftVersion mcVersion) {
+ if (mcVersion == null)
+ throw new IllegalArgumentException("minecraftVersion cannot be NULL.");
+ this.mcVersion = mcVersion;
+ return this;
+ }
+
+ /**
+ * Set the task used to delay unhooking when ProtocolLib is no in use.
+ * @param unhookTask - the unhook task.
+ * @return This builder, for chaining.
+ */
+ public PacketFilterBuilder unhookTask(@Nonnull DelayedSingleTask unhookTask) {
+ if (unhookTask == null)
+ throw new IllegalArgumentException("unhookTask cannot be NULL.");
+ this.unhookTask = unhookTask;
+ return this;
+ }
+
+ /**
+ * Set the error reporter.
+ * @param reporter - new error reporter.
+ * @return This builder, for chaining.
+ */
+ public PacketFilterBuilder reporter(@Nonnull ErrorReporter reporter) {
+ if (reporter == null)
+ throw new IllegalArgumentException("reporter cannot be NULL.");
+ this.reporter = reporter;
+ return this;
+ }
+
+ /**
+ * Determine if we should prepare to hook Netty in Spigot.
+ *
+ * This is calculated in the {@link #build()} method.
+ * @return TRUE if we should, FALSE otherwise.
+ */
+ public boolean isNettyEnabled() {
+ return nettyEnabled;
+ }
+
+ /**
+ * Retrieve the class loader set in this builder.
+ * @return The class loader.
+ */
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ /**
+ * Retrieve the current CraftBukkit server.
+ * @return Current server.
+ */
+ public Server getServer() {
+ return server;
+ }
+
+ /**
+ * Retrieve a reference to the current ProtocolLib instance.
+ * @return ProtocolLib.
+ */
+ public Plugin getLibrary() {
+ return library;
+ }
+
+ /**
+ * Retrieve the current Minecraft version.
+ * @return Current version.
+ */
+ public MinecraftVersion getMinecraftVersion() {
+ return mcVersion;
+ }
+
+ /**
+ * Retrieve the task that is used to delay unhooking when ProtocolLib is no in use.
+ * @return The unhook task.
+ */
+ public DelayedSingleTask getUnhookTask() {
+ return unhookTask;
+ }
+
+ /**
+ * Retrieve the error reporter.
+ * @return Error reporter.
+ */
+ public ErrorReporter getReporter() {
+ return reporter;
+ }
+
+ /**
+ * Retrieve the asynchronous manager.
+ *
+ * This is first constructed the {@link #build()} method.
+ * @return The asynchronous manager.
+ */
+ public AsyncFilterManager getAsyncManager() {
+ return asyncManager;
+ }
+
+ /**
+ * Create a new packet filter manager.
+ * @return A new packet filter manager.
+ */
+ public InternalManager build() {
+ if (reporter == null)
+ throw new IllegalArgumentException("reporter cannot be NULL.");
+ if (classLoader == null)
+ throw new IllegalArgumentException("classLoader cannot be NULL.");
+
+ asyncManager = new AsyncFilterManager(reporter, server.getScheduler());
+ nettyEnabled = false;
+
+ // Spigot
+ if (SpigotPacketInjector.canUseSpigotListener()) {
+ // If the server hasn't loaded yet - wait
+ if (InjectedServerConnection.getServerConnection(reporter, server) == null) {
+ // We need to delay this until we know if Netty is enabled
+ final DelayedPacketManager delayed = new DelayedPacketManager(reporter);
+
+ // They must reference each other
+ delayed.setAsynchronousManager(asyncManager);
+ asyncManager.setManager(delayed);
+
+ Futures.addCallback(BukkitFutures.nextEvent(library, WorldInitEvent.class),
+ new FutureCallback() {
+ @Override
+ public void onSuccess(WorldInitEvent event) {
+ // Nevermind
+ if (delayed.isClosed())
+ return;
+
+ try {
+ registerSpigot(delayed);
+ } catch (Exception e) {
+ onFailure(e);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ reporter.reportWarning(PacketFilterBuilder.this, Report
+ .newBuilder(REPORT_TEMPORARY_EVENT_ERROR).error(error));
+ }
+ });
+
+ System.out.println("Delaying due to Spigot");
+
+ // Let plugins use this version instead
+ return delayed;
+ } else {
+ nettyEnabled = !MinecraftReflection.isMinecraftObject(
+ InjectedServerConnection.getServerConnection(reporter, server));
+ }
+ }
+
+ // Otherwise - construct the packet filter manager right away
+ return buildInternal();
+ }
+
+ private void registerSpigot(DelayedPacketManager delayed) {
+ // Use netty if we have a non-standard ServerConnection class
+ nettyEnabled = !MinecraftReflection.isMinecraftObject(
+ InjectedServerConnection.getServerConnection(reporter, server));
+
+ // Switch to the standard manager
+ delayed.setDelegate(buildInternal());
+ }
+
+ /**
+ * Construct a new packet filter manager without checking for Netty.
+ * @return A new packet filter manager.
+ */
+ private PacketFilterManager buildInternal() {
+ PacketFilterManager manager = new PacketFilterManager(this);
+
+ // It's a cyclic reference, but it's too late to fix now
+ asyncManager.setManager(manager);
+ return manager;
+ }
+}
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 a95309ed..2848cfe5 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
@@ -22,7 +22,6 @@ import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -43,11 +42,9 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.PluginDisableEvent;
-import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
-import com.comphenix.executors.BukkitFutures;
import com.comphenix.protocol.AsynchronousManager;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.async.AsyncFilterManager;
@@ -59,7 +56,6 @@ import com.comphenix.protocol.events.*;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
import com.comphenix.protocol.injector.packet.PacketRegistry;
-import com.comphenix.protocol.injector.player.InjectedServerConnection;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.injector.player.PlayerInjectorBuilder;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.ConflictStrategy;
@@ -67,12 +63,9 @@ import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
-import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
public final class PacketFilterManager implements ProtocolManager, ListenerInvoker, InternalManager {
@@ -94,8 +87,6 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
public static final ReportType REPORT_CANNOT_UNREGISTER_PLUGIN = new ReportType("Unable to handle disabled plugin.");
public static final ReportType REPORT_PLUGIN_VERIFIER_ERROR = new ReportType("Verifier error: %s");
- public static final ReportType REPORT_TEMPORARY_EVENT_ERROR = new ReportType("Unable to register or handle temporary event.");
-
/**
* Sets the inject hook type. Different types allow for maximum compatibility.
* @author Kristian
@@ -182,17 +173,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
/**
* Only create instances of this class if protocol lib is disabled.
*/
- public PacketFilterManager(
- ClassLoader classLoader, Server server, Plugin library,
- AsyncFilterManager asyncManager, MinecraftVersion mcVersion,
- final DelayedSingleTask unhookTask,
- ErrorReporter reporter, boolean nettyEnabled) {
-
- if (reporter == null)
- throw new IllegalArgumentException("reporter cannot be NULL.");
- if (classLoader == null)
- throw new IllegalArgumentException("classLoader cannot be NULL.");
-
+ public PacketFilterManager(PacketFilterBuilder builder) {
// Used to determine if injection is needed
Predicate isInjectionNecessary = new Predicate() {
@Override
@@ -213,16 +194,16 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
this.sendingListeners = new SortedPacketListenerList();
// References
- this.unhookTask = unhookTask;
- this.server = server;
- this.classLoader = classLoader;
- this.reporter = reporter;
+ this.unhookTask = builder.getUnhookTask();
+ this.server = builder.getServer();
+ this.classLoader = builder.getClassLoader();
+ this.reporter = builder.getReporter();
// The plugin verifier
- this.pluginVerifier = new PluginVerifier(library);
+ this.pluginVerifier = new PluginVerifier(builder.getLibrary());
// Use the correct injection type
- if (nettyEnabled) {
+ if (builder.isNettyEnabled()) {
spigotInjector = new SpigotPacketInjector(classLoader, reporter, this, server);
this.playerInjection = spigotInjector.getPlayerHandler();
this.packetInjector = spigotInjector.getPacketInjector();
@@ -236,7 +217,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
classLoader(classLoader).
packetListeners(packetListeners).
injectionFilter(isInjectionNecessary).
- version(mcVersion).
+ version(builder.getMinecraftVersion()).
buildHandler();
this.packetInjector = PacketInjectorBuilder.newBuilder().
@@ -246,7 +227,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
playerInjection(playerInjection).
buildInjector();
}
- this.asyncFilterManager = asyncManager;
+ this.asyncFilterManager = builder.getAsyncManager();
// Attempt to load the list of server and client packets
try {
@@ -256,87 +237,15 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_PACKET_LIST).error(e));
}
}
-
- public static InternalManager createManager(
- final ClassLoader classLoader, final Server server, final Plugin library,
- final MinecraftVersion mcVersion, final DelayedSingleTask unhookTask,
- final ErrorReporter reporter) {
-
- final AsyncFilterManager asyncManager = new AsyncFilterManager(reporter, server.getScheduler());
-
- // Spigot
- if (SpigotPacketInjector.canUseSpigotListener()) {
- // We need to delay this until we know if Netty is enabled
- final DelayedPacketManager delayed = new DelayedPacketManager(reporter);
-
- // They must reference each other
- delayed.setAsynchronousManager(asyncManager);
- asyncManager.setManager(delayed);
- final Callable