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 f1008d6e..6cfc086f 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
@@ -52,9 +52,10 @@ import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.*;
import com.comphenix.protocol.injector.packet.PacketInjector;
-import com.comphenix.protocol.injector.packet.InjectorFactory;
+import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
+import com.comphenix.protocol.injector.player.PlayerInjectorBuilder;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
@@ -181,10 +182,22 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
try {
// Initialize injection mangers
- this.playerInjection = new PlayerInjectionHandler(
- classLoader, reporter, isInjectionNecessary, this, packetListeners, server);
- this.packetInjector = InjectorFactory.getInstance().createProxyInjector(
- classLoader, this, playerInjection, reporter);
+ this.playerInjection = PlayerInjectorBuilder.newBuilder().
+ invoker(this).
+ server(server).
+ reporter(reporter).
+ classLoader(classLoader).
+ packetListeners(packetListeners).
+ injectionFilter(isInjectionNecessary).
+ buildHandler();
+
+ this.packetInjector = PacketInjectorBuilder.newBuilder().
+ invoker(this).
+ reporter(reporter).
+ classLoader(classLoader).
+ playerInjection(playerInjection).
+ buildInjector();
+
this.asyncFilterManager = new AsyncFilterManager(reporter, server.getScheduler(), this);
// Attempt to load the list of server and client packets
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/InjectorFactory.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/InjectorFactory.java
deleted file mode 100644
index e4bc18bc..00000000
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/InjectorFactory.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.comphenix.protocol.injector.packet;
-
-import com.comphenix.protocol.error.ErrorReporter;
-import com.comphenix.protocol.injector.ListenerInvoker;
-import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
-
-/**
- * A singleton factory for creating incoming packet injectors.
- *
- * @author Kristian
- */
-public class InjectorFactory {
- private static final InjectorFactory INSTANCE = new InjectorFactory();
-
- private InjectorFactory() {
- // No need to construct this
- }
-
- /**
- * Retrieve the factory singleton.
- * @return Factory singleton.
- */
- public static InjectorFactory getInstance() {
- return INSTANCE;
- }
-
- /**
- * Create a packet injector that intercepts packets by overriding the packet registry.
- * @param classLoader - current class loader.
- * @param manager - packet invoker.
- * @param playerInjection - to lookup Player by DataInputStream.
- * @param reporter - error reporter.
- * @return A packet injector with these features.
- * @throws IllegalAccessException If we fail to create the injector.
- */
- public PacketInjector createProxyInjector(
- ClassLoader classLoader, ListenerInvoker manager,
- PlayerInjectionHandler playerInjection, ErrorReporter reporter) throws IllegalAccessException {
-
- return new ProxyPacketInjector(classLoader, manager, playerInjection, reporter);
- }
-}
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjectorBuilder.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjectorBuilder.java
new file mode 100644
index 00000000..c3720b77
--- /dev/null
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjectorBuilder.java
@@ -0,0 +1,109 @@
+package com.comphenix.protocol.injector.packet;
+
+import javax.annotation.Nonnull;
+
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.error.ErrorReporter;
+import com.comphenix.protocol.injector.ListenerInvoker;
+import com.comphenix.protocol.injector.PacketFilterManager;
+import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
+import com.google.common.base.Preconditions;
+
+/**
+ * A builder responsible for creating incoming packet injectors.
+ *
+ * @author Kristian
+ */
+public class PacketInjectorBuilder {
+ protected PacketInjectorBuilder() {
+ // No need to construct this
+ }
+
+ /**
+ * Retrieve a new packet injector builder.
+ * @return Injector builder.
+ */
+ public static PacketInjectorBuilder newBuilder() {
+ return new PacketInjectorBuilder();
+ }
+
+ protected ClassLoader classLoader;
+ protected ListenerInvoker invoker;
+ protected ErrorReporter reporter;
+ protected PlayerInjectionHandler playerInjection;
+
+ /**
+ * Set the class loader to use during class generation.
+ * @param classLoader - new class loader.
+ * @return This builder, for chaining.
+ */
+ public PacketInjectorBuilder classLoader(@Nonnull ClassLoader classLoader) {
+ Preconditions.checkNotNull(classLoader, "classLoader cannot be NULL");
+ this.classLoader = classLoader;
+ return this;
+ }
+
+ /**
+ * The error reporter used by the created injector.
+ * @param reporter - new error reporter.
+ * @return This builder, for chaining.
+ */
+ public PacketInjectorBuilder reporter(@Nonnull ErrorReporter reporter) {
+ Preconditions.checkNotNull(reporter, "reporter cannot be NULL");
+ this.reporter = reporter;
+ return this;
+ }
+
+ /**
+ * The packet stream invoker.
+ * @param invoker - the invoker.
+ * @return This builder, for chaining.
+ */
+ public PacketInjectorBuilder invoker(@Nonnull ListenerInvoker invoker) {
+ Preconditions.checkNotNull(invoker, "invoker cannot be NULL");
+ this.invoker = invoker;
+ return this;
+ }
+
+ /**
+ * The packet stream invoker.
+ * @param invoker - the invoker.
+ * @return This builder, for chaining.
+ */
+ @Nonnull
+ public PacketInjectorBuilder playerInjection(@Nonnull PlayerInjectionHandler playerInjection) {
+ Preconditions.checkNotNull(playerInjection, "playerInjection cannot be NULL");
+ this.playerInjection = playerInjection;
+ return this;
+ }
+
+ /**
+ * Called before an object is created with this builder.
+ */
+ private void initializeDefaults() {
+ ProtocolManager manager = ProtocolLibrary.getProtocolManager();
+
+ // Initialize with default values if we can
+ if (classLoader == null)
+ classLoader = this.getClass().getClassLoader();
+ if (reporter == null)
+ reporter = ProtocolLibrary.getErrorReporter();
+ if (invoker == null)
+ invoker = (PacketFilterManager) manager;
+ if (playerInjection == null)
+ throw new IllegalStateException("Player injection parameter must be initialized.");
+ }
+
+ /**
+ * Create a packet injector using the provided fields or the default values.
+ *
+ * Note that any non-null builder parameters must be set.
+ * @return The created injector.
+ * @throws IllegalAccessException If anything goes wrong in terms of reflection.
+ */
+ public PacketInjector buildInjector() throws IllegalAccessException {
+ initializeDefaults();
+ return new ProxyPacketInjector(classLoader, invoker, playerInjection, reporter);
+ }
+}
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java
index dd03ea5d..f80bae7b 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/NetLoginInjector.java
@@ -38,7 +38,7 @@ class NetLoginInjector {
private ConcurrentMap