From 8ed13effa67d8b91bafaa9828c2671dcf9dd99b9 Mon Sep 17 00:00:00 2001
From: modmuss <modmuss50@gmail.com>
Date: Thu, 2 Nov 2023 10:32:56 +0000
Subject: [PATCH] Network addon session refactor (#3394)

* refactor network addon session handling

* Check payload size

* Fix ClientLoginNetworkAddon does not handle unsuccessful query responses
Closes #3384

* Adjust some logging.

---------

Co-authored-by: deirn <deirn@bai.lol>
(cherry picked from commit bff13c85458061ebc205f7264b5f4a8145b91976)
---
 .../ClientConfigurationNetworkAddon.java      | 11 +----
 .../client/ClientLoginNetworkAddon.java       | 11 ++---
 .../client/ClientPlayNetworkAddon.java        | 11 +----
 .../ClientCommonNetworkHandlerMixin.java      |  6 ---
 .../ClientLoginNetworkHandlerMixin.java       | 11 -----
 .../AbstractChanneledNetworkAddon.java        |  4 +-
 .../impl/networking/AbstractNetworkAddon.java | 44 +++++++++++++++----
 .../networking/GlobalReceiverRegistry.java    | 24 +++++++++-
 .../networking/payload/PayloadHelper.java     |  8 +++-
 .../ServerConfigurationNetworkAddon.java      | 10 +----
 .../server/ServerLoginNetworkAddon.java       |  9 ++--
 .../server/ServerPlayNetworkAddon.java        | 17 ++-----
 .../networking/ClientConnectionMixin.java     | 25 +++++++++--
 .../CustomPayloadC2SPacketMixin.java          |  8 +++-
 .../CustomPayloadS2CPacketMixin.java          |  8 +++-
 .../LoginQueryRequestS2CPacketMixin.java      |  8 +++-
 .../LoginQueryResponseC2SPacketMixin.java     |  8 +++-
 ...erverConfigurationNetworkHandlerMixin.java |  5 ---
 .../ServerLoginNetworkHandlerMixin.java       | 15 -------
 .../ServerPlayNetworkHandlerMixin.java        |  7 +--
 20 files changed, 131 insertions(+), 119 deletions(-)

diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java
index 9499e22e7..17ca09e3d 100644
--- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java
+++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientConfigurationNetworkAddon.java
@@ -18,7 +18,6 @@ package net.fabricmc.fabric.impl.networking.client;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.network.ClientConfigurationNetworkHandler;
@@ -51,17 +50,10 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw
 
 		// Must register pending channels via lateinit
 		this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.CONFIGURATION);
-
-		// Register global receivers and attach to session
-		this.receiver.startSession(this);
 	}
 
 	@Override
-	public void lateInit() {
-		for (Map.Entry<Identifier, ClientConfigurationNetworking.ConfigurationChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
-			this.registerChannel(entry.getKey(), entry.getValue());
-		}
-
+	protected void invokeInitEvent() {
 		ClientConfigurationConnectionEvents.INIT.invoker().onConfigurationInit(this.handler, this.client);
 	}
 
@@ -153,7 +145,6 @@ public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetw
 	@Override
 	protected void invokeDisconnectEvent() {
 		ClientConfigurationConnectionEvents.DISCONNECT.invoker().onConfigurationDisconnect(this.handler, this.client);
-		this.receiver.endSession(this);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java
index a8706d589..299179d41 100644
--- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java
+++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientLoginNetworkAddon.java
@@ -51,9 +51,11 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLo
 		super(ClientNetworkingImpl.LOGIN, "ClientLoginNetworkAddon for Client");
 		this.handler = handler;
 		this.client = client;
+	}
 
+	@Override
+	protected void invokeInitEvent() {
 		ClientLoginConnectionEvents.INIT.invoker().onLoginStart(this.handler, this.client);
-		this.receiver.startSession(this);
 	}
 
 	public boolean handlePacket(LoginQueryRequestS2CPacket packet) {
@@ -86,7 +88,7 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLo
 		try {
 			CompletableFuture<@Nullable PacketByteBuf> future = handler.receive(this.client, this.handler, buf, futureListeners::add);
 			future.thenAccept(result -> {
-				LoginQueryResponseC2SPacket packet = new LoginQueryResponseC2SPacket(queryId, new PacketByteBufLoginQueryResponse(result));
+				LoginQueryResponseC2SPacket packet = new LoginQueryResponseC2SPacket(queryId, result == null ? null : new PacketByteBufLoginQueryResponse(result));
 				GenericFutureListener<? extends Future<? super Void>> listener = null;
 
 				for (GenericFutureListener<? extends Future<? super Void>> each : futureListeners) {
@@ -114,11 +116,6 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLo
 	@Override
 	protected void invokeDisconnectEvent() {
 		ClientLoginConnectionEvents.DISCONNECT.invoker().onLoginDisconnect(this.handler, this.client);
-		this.receiver.endSession(this);
-	}
-
-	public void handleConfigurationTransition() {
-		this.receiver.endSession(this);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java
index d10f39925..9b7b94b13 100644
--- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java
+++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/impl/networking/client/ClientPlayNetworkAddon.java
@@ -18,7 +18,6 @@ package net.fabricmc.fabric.impl.networking.client;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import com.mojang.logging.LogUtils;
 import org.slf4j.Logger;
@@ -53,17 +52,10 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon<
 
 		// Must register pending channels via lateinit
 		this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.PLAY);
-
-		// Register global receivers and attach to session
-		this.receiver.startSession(this);
 	}
 
 	@Override
-	public void lateInit() {
-		for (Map.Entry<Identifier, ClientPlayNetworking.PlayChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
-			this.registerChannel(entry.getKey(), entry.getValue());
-		}
-
+	protected void invokeInitEvent() {
 		ClientPlayConnectionEvents.INIT.invoker().onPlayInit(this.handler, this.client);
 	}
 
@@ -148,7 +140,6 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon<
 	@Override
 	protected void invokeDisconnectEvent() {
 		ClientPlayConnectionEvents.DISCONNECT.invoker().onPlayDisconnect(this.handler, this.client);
-		this.receiver.endSession(this);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java
index 5fc2c7d15..494811ee7 100644
--- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java
+++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientCommonNetworkHandlerMixin.java
@@ -23,7 +23,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
 import net.minecraft.client.network.ClientCommonNetworkHandler;
 import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
-import net.minecraft.text.Text;
 
 import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
 import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon;
@@ -32,11 +31,6 @@ import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
 
 @Mixin(ClientCommonNetworkHandler.class)
 public abstract class ClientCommonNetworkHandlerMixin implements NetworkHandlerExtensions {
-	@Inject(method = "onDisconnected", at = @At("HEAD"))
-	private void handleDisconnection(Text reason, CallbackInfo ci) {
-		this.getAddon().handleDisconnect();
-	}
-
 	@Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true)
 	public void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
 		if (packet.payload() instanceof PacketByteBufPayload payload) {
diff --git a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientLoginNetworkHandlerMixin.java b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientLoginNetworkHandlerMixin.java
index bc447008e..285aee556 100644
--- a/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientLoginNetworkHandlerMixin.java
+++ b/fabric-networking-api-v1/src/client/java/net/fabricmc/fabric/mixin/networking/client/ClientLoginNetworkHandlerMixin.java
@@ -28,7 +28,6 @@ import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.network.ClientLoginNetworkHandler;
 import net.minecraft.network.ClientConnection;
 import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
-import net.minecraft.text.Text;
 
 import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
 import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon;
@@ -64,16 +63,6 @@ abstract class ClientLoginNetworkHandlerMixin implements NetworkHandlerExtension
 		}
 	}
 
-	@Inject(method = "onDisconnected", at = @At("HEAD"))
-	private void invokeLoginDisconnectEvent(Text reason, CallbackInfo ci) {
-		this.addon.handleDisconnect();
-	}
-
-	@Inject(method = "onSuccess", at = @At("HEAD"))
-	private void handleConfigurationTransition(CallbackInfo ci) {
-		addon.handleConfigurationTransition();
-	}
-
 	@Inject(method = "onSuccess", at = @At("TAIL"))
 	private void handleConfigurationReady(CallbackInfo ci) {
 		NetworkHandlerExtensions networkHandlerExtensions = (NetworkHandlerExtensions) connection.getPacketListener();
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java
index 8818ebc93..203d4dbff 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractChanneledNetworkAddon.java
@@ -60,8 +60,6 @@ public abstract class AbstractChanneledNetworkAddon<H> extends AbstractNetworkAd
 		this.sendableChannels = Collections.synchronizedSet(new HashSet<>());
 	}
 
-	public abstract void lateInit();
-
 	protected void registerPendingChannels(ChannelInfoHolder holder, NetworkState state) {
 		final Collection<Identifier> pending = holder.getPendingChannelsNames(state);
 
@@ -211,7 +209,7 @@ public abstract class AbstractChanneledNetworkAddon<H> extends AbstractNetworkAd
 		assert negotiatedVersion == 1; // We only support version 1 for now
 
 		commonVersion = negotiatedVersion;
-		this.logger.info("Negotiated common packet version {}", commonVersion);
+		this.logger.debug("Negotiated common packet version {}", commonVersion);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java
index 80e14cf46..c4057f878 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/AbstractNetworkAddon.java
@@ -52,6 +52,17 @@ public abstract class AbstractNetworkAddon<H> {
 		this.logger = LoggerFactory.getLogger(description);
 	}
 
+	public final void lateInit() {
+		this.receiver.startSession(this);
+		invokeInitEvent();
+	}
+
+	protected abstract void invokeInitEvent();
+
+	public final void endSession() {
+		this.receiver.endSession(this);
+	}
+
 	@Nullable
 	public H getHandler(Identifier channel) {
 		Lock lock = this.lock.readLock();
@@ -64,13 +75,32 @@ public abstract class AbstractNetworkAddon<H> {
 		}
 	}
 
+	private void assertNotReserved(Identifier channel) {
+		if (this.isReservedChannel(channel)) {
+			throw new IllegalArgumentException(String.format("Cannot (un)register handler for reserved channel with name \"%s\"", channel));
+		}
+	}
+
+	public void registerChannels(Map<Identifier, H> map) {
+		Lock lock = this.lock.writeLock();
+		lock.lock();
+
+		try {
+			for (Map.Entry<Identifier, H> entry : map.entrySet()) {
+				assertNotReserved(entry.getKey());
+
+				boolean unique = this.handlers.putIfAbsent(entry.getKey(), entry.getValue()) == null;
+				if (unique) handleRegistration(entry.getKey());
+			}
+		} finally {
+			lock.unlock();
+		}
+	}
+
 	public boolean registerChannel(Identifier channelName, H handler) {
 		Objects.requireNonNull(channelName, "Channel name cannot be null");
 		Objects.requireNonNull(handler, "Packet handler cannot be null");
-
-		if (this.isReservedChannel(channelName)) {
-			throw new IllegalArgumentException(String.format("Cannot register handler for reserved channel with name \"%s\"", channelName));
-		}
+		assertNotReserved(channelName);
 
 		Lock lock = this.lock.writeLock();
 		lock.lock();
@@ -90,10 +120,7 @@ public abstract class AbstractNetworkAddon<H> {
 
 	public H unregisterChannel(Identifier channelName) {
 		Objects.requireNonNull(channelName, "Channel name cannot be null");
-
-		if (this.isReservedChannel(channelName)) {
-			throw new IllegalArgumentException(String.format("Cannot register handler for reserved channel with name \"%s\"", channelName));
-		}
+		assertNotReserved(channelName);
 
 		Lock lock = this.lock.writeLock();
 		lock.lock();
@@ -129,6 +156,7 @@ public abstract class AbstractNetworkAddon<H> {
 	public final void handleDisconnect() {
 		if (disconnected.compareAndSet(false, true)) {
 			invokeDisconnectEvent();
+			endSession();
 		}
 	}
 
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java
index 13b2e87b0..452944539 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/GlobalReceiverRegistry.java
@@ -26,11 +26,15 @@ import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import net.minecraft.network.NetworkState;
 import net.minecraft.util.Identifier;
 
 public final class GlobalReceiverRegistry<H> {
+	private static final Logger LOGGER = LoggerFactory.getLogger(GlobalReceiverRegistry.class);
+
 	private final NetworkState state;
 
 	private final ReadWriteLock lock = new ReentrantReadWriteLock();
@@ -134,7 +138,11 @@ public final class GlobalReceiverRegistry<H> {
 		lock.lock();
 
 		try {
-			this.trackedAddons.add(addon);
+			if (this.trackedAddons.add(addon)) {
+				addon.registerChannels(handlers);
+			}
+
+			this.logTrackedAddonSize();
 		} finally {
 			lock.unlock();
 		}
@@ -145,17 +153,29 @@ public final class GlobalReceiverRegistry<H> {
 		lock.lock();
 
 		try {
+			this.logTrackedAddonSize();
 			this.trackedAddons.remove(addon);
 		} finally {
 			lock.unlock();
 		}
 	}
 
+	/**
+	 * In practice, trackedAddons should never contain more than the number of players.
+	 */
+	private void logTrackedAddonSize() {
+		if (LOGGER.isTraceEnabled() && this.trackedAddons.size() > 1) {
+			LOGGER.trace("{} receiver registry tracks {} addon instances", state.getId(), trackedAddons.size());
+		}
+	}
+
 	private void handleRegistration(Identifier channelName, H handler) {
 		Lock lock = this.lock.writeLock();
 		lock.lock();
 
 		try {
+			this.logTrackedAddonSize();
+
 			for (AbstractNetworkAddon<H> addon : this.trackedAddons) {
 				addon.registerChannel(channelName, handler);
 			}
@@ -169,6 +189,8 @@ public final class GlobalReceiverRegistry<H> {
 		lock.lock();
 
 		try {
+			this.logTrackedAddonSize();
+
 			for (AbstractNetworkAddon<H> addon : this.trackedAddons) {
 				addon.unregisterChannel(channelName);
 			}
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java
index efef0e8ce..70914bb08 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/payload/PayloadHelper.java
@@ -25,7 +25,13 @@ public class PayloadHelper {
 		byteBuf.writeBytes(data.copy());
 	}
 
-	public static PacketByteBuf read(PacketByteBuf byteBuf) {
+	public static PacketByteBuf read(PacketByteBuf byteBuf, int maxSize) {
+		int size = byteBuf.readableBytes();
+
+		if (size < 0 || size > maxSize) {
+			throw new IllegalArgumentException("Payload may not be larger than %d bytes".formatted(maxSize));
+		}
+
 		PacketByteBuf newBuf = PacketByteBufs.create();
 		newBuf.writeBytes(byteBuf.copy());
 		byteBuf.skipBytes(byteBuf.readableBytes());
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java
index 4ac8ee5da..93357b596 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerConfigurationNetworkAddon.java
@@ -18,7 +18,6 @@ package net.fabricmc.fabric.impl.networking.server;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import net.minecraft.network.NetworkState;
 import net.minecraft.network.PacketByteBuf;
@@ -52,16 +51,10 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw
 
 		// Must register pending channels via lateinit
 		this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.CONFIGURATION);
-
-		// Register global receivers and attach to session
-		this.receiver.startSession(this);
 	}
 
 	@Override
-	public void lateInit() {
-		for (Map.Entry<Identifier, ServerConfigurationNetworking.ConfigurationChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
-			this.registerChannel(entry.getKey(), entry.getValue());
-		}
+	protected void invokeInitEvent() {
 	}
 
 	public void preConfiguration() {
@@ -177,7 +170,6 @@ public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetw
 	@Override
 	protected void invokeDisconnectEvent() {
 		ServerConfigurationConnectionEvents.DISCONNECT.invoker().onConfigureDisconnect(handler, server);
-		this.receiver.endSession(this);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java
index 8c6b22200..957a56d7a 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerLoginNetworkAddon.java
@@ -67,9 +67,11 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLo
 		this.handler = handler;
 		this.server = ((ServerLoginNetworkHandlerAccessor) handler).getServer();
 		this.queryIdFactory = QueryIdFactory.create();
+	}
 
+	@Override
+	protected void invokeInitEvent() {
 		ServerLoginConnectionEvents.INIT.invoker().onLoginInit(handler, this.server);
-		this.receiver.startSession(this);
 	}
 
 	// return true if no longer ticks query
@@ -202,11 +204,6 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLo
 	@Override
 	protected void invokeDisconnectEvent() {
 		ServerLoginConnectionEvents.DISCONNECT.invoker().onLoginDisconnect(this.handler, this.server);
-		this.receiver.endSession(this);
-	}
-
-	public void handleConfigurationTransition() {
-		this.receiver.endSession(this);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java
index 3516d1cf1..0ed9f6a4b 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/impl/networking/server/ServerPlayNetworkAddon.java
@@ -18,8 +18,8 @@ package net.fabricmc.fabric.impl.networking.server;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
+import net.minecraft.network.ClientConnection;
 import net.minecraft.network.NetworkState;
 import net.minecraft.network.PacketByteBuf;
 import net.minecraft.network.packet.Packet;
@@ -35,31 +35,23 @@ import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon;
 import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
 import net.fabricmc.fabric.impl.networking.NetworkingImpl;
 import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
-import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor;
 
 public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon<ServerPlayNetworking.PlayChannelHandler> {
 	private final ServerPlayNetworkHandler handler;
 	private final MinecraftServer server;
 	private boolean sentInitialRegisterPacket;
 
-	public ServerPlayNetworkAddon(ServerPlayNetworkHandler handler, MinecraftServer server) {
-		super(ServerNetworkingImpl.PLAY, ((ServerCommonNetworkHandlerAccessor) handler).getConnection(), "ServerPlayNetworkAddon for " + handler.player.getEntityName());
+	public ServerPlayNetworkAddon(ServerPlayNetworkHandler handler, ClientConnection connection, MinecraftServer server) {
+		super(ServerNetworkingImpl.PLAY, connection, "ServerPlayNetworkAddon for " + handler.player.getEntityName());
 		this.handler = handler;
 		this.server = server;
 
 		// Must register pending channels via lateinit
 		this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.PLAY);
-
-		// Register global receivers and attach to session
-		this.receiver.startSession(this);
 	}
 
 	@Override
-	public void lateInit() {
-		for (Map.Entry<Identifier, ServerPlayNetworking.PlayChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
-			this.registerChannel(entry.getKey(), entry.getValue());
-		}
-
+	protected void invokeInitEvent() {
 		ServerPlayConnectionEvents.INIT.invoker().onPlayInit(this.handler, this.server);
 	}
 
@@ -139,7 +131,6 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon<
 	@Override
 	protected void invokeDisconnectEvent() {
 		ServerPlayConnectionEvents.DISCONNECT.invoker().onPlayDisconnect(this.handler, this.server);
-		this.receiver.endSession(this);
 	}
 
 	@Override
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java
index 191368af7..5c974d80f 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ClientConnectionMixin.java
@@ -30,6 +30,7 @@ import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.Unique;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
 import org.spongepowered.asm.mixin.injection.Redirect;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@@ -88,13 +89,29 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
 		}
 	}
 
-	@Inject(method = "channelInactive", at = @At("HEAD"))
-	private void handleDisconnect(ChannelHandlerContext channelHandlerContext, CallbackInfo ci) {
-		if (packetListener instanceof NetworkHandlerExtensions) { // not the case for client/server query
-			((NetworkHandlerExtensions) packetListener).getAddon().handleDisconnect();
+	@Inject(method = "setPacketListener", at = @At("HEAD"))
+	private void unwatchAddon(PacketListener packetListener, CallbackInfo ci) {
+		if (this.packetListener instanceof NetworkHandlerExtensions oldListener) {
+			oldListener.getAddon().endSession();
 		}
 	}
 
+	@Inject(method = "channelInactive", at = @At("HEAD"))
+	private void disconnectAddon(ChannelHandlerContext channelHandlerContext, CallbackInfo ci) {
+		if (packetListener instanceof NetworkHandlerExtensions extension) {
+			extension.getAddon().handleDisconnect();
+		}
+	}
+
+	@ModifyVariable(method = "handleDisconnection", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/listener/PacketListener;onDisconnected(Lnet/minecraft/text/Text;)V"))
+	private PacketListener disconnectAddon(PacketListener packetListener) {
+		if (packetListener instanceof NetworkHandlerExtensions extension) {
+			extension.getAddon().handleDisconnect();
+		}
+
+		return packetListener;
+	}
+
 	@Inject(method = "sendInternal", at = @At(value = "INVOKE", target = "Lio/netty/channel/ChannelFuture;addListener(Lio/netty/util/concurrent/GenericFutureListener;)Lio/netty/channel/ChannelFuture;", remap = false), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
 	private void sendInternal(Packet<?> packet, @Nullable PacketCallbacks callbacks, boolean flush, CallbackInfo ci, ChannelFuture channelFuture) {
 		if (callbacks instanceof GenericFutureListenerHolder holder) {
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java
index 17bd8b115..bb1966cc2 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadC2SPacketMixin.java
@@ -16,7 +16,9 @@
 
 package net.fabricmc.fabric.mixin.networking;
 
+import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -31,12 +33,16 @@ import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
 
 @Mixin(CustomPayloadC2SPacket.class)
 public class CustomPayloadC2SPacketMixin {
+	@Shadow
+	@Final
+	private static int MAX_PAYLOAD_SIZE;
+
 	@Inject(
 			method = "readPayload",
 			at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/c2s/common/CustomPayloadC2SPacket;readUnknownPayload(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/UnknownCustomPayload;"),
 			cancellable = true
 	)
 	private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable<CustomPayload> cir) {
-		cir.setReturnValue(new PacketByteBufPayload(id, PayloadHelper.read(buf)));
+		cir.setReturnValue(new PacketByteBufPayload(id, PayloadHelper.read(buf, MAX_PAYLOAD_SIZE)));
 	}
 }
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java
index ed4599ed1..59e905f97 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/CustomPayloadS2CPacketMixin.java
@@ -16,7 +16,9 @@
 
 package net.fabricmc.fabric.mixin.networking;
 
+import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -31,12 +33,16 @@ import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
 
 @Mixin(CustomPayloadS2CPacket.class)
 public class CustomPayloadS2CPacketMixin {
+	@Shadow
+	@Final
+	private static int MAX_PAYLOAD_SIZE;
+
 	@Inject(
 			method = "readPayload",
 			at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;readUnknownPayload(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/UnknownCustomPayload;"),
 			cancellable = true
 	)
 	private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable<CustomPayload> cir) {
-		cir.setReturnValue(new PacketByteBufPayload(id, PayloadHelper.read(buf)));
+		cir.setReturnValue(new PacketByteBufPayload(id, PayloadHelper.read(buf, MAX_PAYLOAD_SIZE)));
 	}
 }
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryRequestS2CPacketMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryRequestS2CPacketMixin.java
index 432a49162..181543f81 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryRequestS2CPacketMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryRequestS2CPacketMixin.java
@@ -16,7 +16,9 @@
 
 package net.fabricmc.fabric.mixin.networking;
 
+import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -31,8 +33,12 @@ import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
 
 @Mixin(LoginQueryRequestS2CPacket.class)
 public class LoginQueryRequestS2CPacketMixin {
+	@Shadow
+	@Final
+	private static int MAX_PAYLOAD_SIZE;
+
 	@Inject(method = "readPayload", at = @At("HEAD"), cancellable = true)
 	private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable<LoginQueryRequestPayload> cir) {
-		cir.setReturnValue(new PacketByteBufLoginQueryRequestPayload(id, PayloadHelper.read(buf)));
+		cir.setReturnValue(new PacketByteBufLoginQueryRequestPayload(id, PayloadHelper.read(buf, MAX_PAYLOAD_SIZE)));
 	}
 }
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryResponseC2SPacketMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryResponseC2SPacketMixin.java
index c83046038..e3ab52d22 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryResponseC2SPacketMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/LoginQueryResponseC2SPacketMixin.java
@@ -16,7 +16,9 @@
 
 package net.fabricmc.fabric.mixin.networking;
 
+import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -30,6 +32,10 @@ import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
 
 @Mixin(LoginQueryResponseC2SPacket.class)
 public class LoginQueryResponseC2SPacketMixin {
+	@Shadow
+	@Final
+	private static int MAX_PAYLOAD_SIZE;
+
 	@Inject(method = "readPayload", at = @At("HEAD"), cancellable = true)
 	private static void readResponse(int queryId, PacketByteBuf buf, CallbackInfoReturnable<LoginQueryResponsePayload> cir) {
 		boolean hasPayload = buf.readBoolean();
@@ -39,6 +45,6 @@ public class LoginQueryResponseC2SPacketMixin {
 			return;
 		}
 
-		cir.setReturnValue(new PacketByteBufLoginQueryResponse(PayloadHelper.read(buf)));
+		cir.setReturnValue(new PacketByteBufLoginQueryResponse(PayloadHelper.read(buf, MAX_PAYLOAD_SIZE)));
 	}
 }
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerConfigurationNetworkHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerConfigurationNetworkHandlerMixin.java
index c68f317e2..c9188cdc0 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerConfigurationNetworkHandlerMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerConfigurationNetworkHandlerMixin.java
@@ -141,11 +141,6 @@ public abstract class ServerConfigurationNetworkHandlerMixin extends ServerCommo
 		return false;
 	}
 
-	@Inject(method = "onDisconnected", at = @At("HEAD"))
-	private void handleDisconnection(Text reason, CallbackInfo ci) {
-		this.addon.handleDisconnect();
-	}
-
 	@Override
 	public ServerConfigurationNetworkAddon getAddon() {
 		return addon;
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerLoginNetworkHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerLoginNetworkHandlerMixin.java
index 6a7e7a2ad..bdd1c696a 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerLoginNetworkHandlerMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerLoginNetworkHandlerMixin.java
@@ -17,7 +17,6 @@
 package net.fabricmc.fabric.mixin.networking;
 
 import com.mojang.authlib.GameProfile;
-import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
 import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.Unique;
@@ -42,10 +41,6 @@ import net.fabricmc.fabric.impl.networking.server.ServerLoginNetworkAddon;
 
 @Mixin(ServerLoginNetworkHandler.class)
 abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtensions, DisconnectPacketSource, PacketCallbackListener {
-	@Shadow
-	@Final
-	private MinecraftServer server;
-
 	@Shadow
 	protected abstract void tickVerify(GameProfile profile);
 
@@ -82,16 +77,6 @@ abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtension
 		return -1;
 	}
 
-	@Inject(method = "onDisconnected", at = @At("HEAD"))
-	private void handleDisconnection(Text reason, CallbackInfo ci) {
-		this.addon.handleDisconnect();
-	}
-
-	@Inject(method = "sendSuccessPacket", at = @At("HEAD"))
-	private void handlePlayTransitionNormal(GameProfile profile, CallbackInfo ci) {
-		this.addon.handleConfigurationTransition();
-	}
-
 	@Override
 	public void sent(Packet<?> packet) {
 		if (packet instanceof LoginQueryRequestS2CPacket) {
diff --git a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java
index a24ae9064..f353fac1b 100644
--- a/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java
+++ b/fabric-networking-api-v1/src/main/java/net/fabricmc/fabric/mixin/networking/ServerPlayNetworkHandlerMixin.java
@@ -47,16 +47,11 @@ abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler
 
 	@Inject(method = "<init>", at = @At("RETURN"))
 	private void initAddon(CallbackInfo ci) {
-		this.addon = new ServerPlayNetworkAddon((ServerPlayNetworkHandler) (Object) this, this.server);
+		this.addon = new ServerPlayNetworkAddon((ServerPlayNetworkHandler) (Object) this, connection, server);
 		// A bit of a hack but it allows the field above to be set in case someone registers handlers during INIT event which refers to said field
 		this.addon.lateInit();
 	}
 
-	@Inject(method = "onDisconnected", at = @At("HEAD"))
-	private void handleDisconnection(Text reason, CallbackInfo ci) {
-		this.addon.handleDisconnect();
-	}
-
 	@Override
 	public ServerPlayNetworkAddon getAddon() {
 		return this.addon;