From 01a465c7591e7d0411f0a625aa247c550bb310ad Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Fri, 9 May 2025 23:28:05 +0900 Subject: [PATCH] fix packets sent before switch connection state --- .../0168-async-switch-connection-state.patch | 147 +++++++++++------- 1 file changed, 88 insertions(+), 59 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0168-async-switch-connection-state.patch b/leaf-server/minecraft-patches/features/0168-async-switch-connection-state.patch index a2a45ac5..a0894663 100644 --- a/leaf-server/minecraft-patches/features/0168-async-switch-connection-state.patch +++ b/leaf-server/minecraft-patches/features/0168-async-switch-connection-state.patch @@ -5,56 +5,74 @@ Subject: [PATCH] async switch connection state diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index f998cf8d70302a21289de4d84b46d322d0b8a8fe..624f1782a83ea0f8764b78819c23229fbfe51f49 100644 +index f998cf8d70302a21289de4d84b46d322d0b8a8fe..32f26640664135c9f7f45f8b204b7ff412fe343e 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java -@@ -337,11 +337,17 @@ public class Connection extends SimpleChannelInboundHandler> { - } - } - -+ // Leaf start - public void setupInboundProtocol(ProtocolInfo protocolInfo, T packetInfo) { - this.validateListener(protocolInfo, packetInfo); +@@ -342,6 +342,11 @@ public class Connection extends SimpleChannelInboundHandler> { if (protocolInfo.flow() != this.getReceiving()) { throw new IllegalStateException("Invalid inbound protocol: " + protocolInfo.id()); } else { -+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { -+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { -+ this.channel.config().setAutoRead(false); -+ } ++ // Leaf start ++ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { ++ this.channel.config().setAutoRead(false); + } ++ // Leaf end this.packetListener = packetInfo; this.disconnectListener = null; UnconfiguredPipelineHandler.InboundConfigurationTask inboundConfigurationTask = UnconfiguredPipelineHandler.setupInboundProtocol(protocolInfo); -@@ -351,7 +357,14 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -351,7 +356,14 @@ public class Connection extends SimpleChannelInboundHandler> { inboundConfigurationTask = inboundConfigurationTask.andThen(context -> context.pipeline().addAfter("decoder", "bundler", packetBundlePacker)); } - syncAfterConfigurationChange(this.channel.writeAndFlush(inboundConfigurationTask)); ++ // Leaf start + var cf = this.channel.writeAndFlush(inboundConfigurationTask); -+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { -+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { -+ cf.addListener((ChannelFutureListener) Connection::syncAfterConfigurationChange); -+ return; -+ } ++ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { ++ cf.addListener((ChannelFutureListener) Connection::syncAfterConfigurationChange); ++ return; + } + syncAfterConfigurationChange(cf); ++ // Leaf end } } -@@ -369,9 +382,17 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -369,9 +381,41 @@ public class Connection extends SimpleChannelInboundHandler> { } boolean flag = protocolInfo.id() == ConnectionProtocol.LOGIN; - syncAfterConfigurationChange(this.channel.writeAndFlush(outboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = flag))); + var cf = this.channel.writeAndFlush(outboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = flag)); ++ // Leaf start + if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { + if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { -+ cf.addListener((ChannelFutureListener) Connection::syncAfterConfigurationChange); -+ return; ++ throw new IllegalStateException("Thread failed netty thread check: Switching outbound protocol state use setupOutboundProtocolAsync instead"); + } + } ++ // Leaf end + syncAfterConfigurationChange(cf); ++ } ++ } ++ // Leaf start ++ public @Nullable ChannelFuture setupOutboundProtocolAsync(ProtocolInfo protocolInfo) { ++ if (protocolInfo.flow() != this.getSending()) { ++ throw new IllegalStateException("Invalid outbound protocol: " + protocolInfo.id()); ++ } else { ++ UnconfiguredPipelineHandler.OutboundConfigurationTask outboundConfigurationTask = UnconfiguredPipelineHandler.setupOutboundProtocol(protocolInfo); ++ BundlerInfo bundlerInfo = protocolInfo.bundlerInfo(); ++ if (bundlerInfo != null) { ++ PacketBundleUnpacker packetBundleUnpacker = new PacketBundleUnpacker(bundlerInfo); ++ outboundConfigurationTask = outboundConfigurationTask.andThen( ++ context -> context.pipeline().addAfter("encoder", "unbundler", packetBundleUnpacker) ++ ); ++ } ++ ++ boolean flag = protocolInfo.id() == ConnectionProtocol.LOGIN; ++ var cf = this.channel.writeAndFlush(outboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = flag)); ++ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { ++ cf.addListener((ChannelFutureListener) Connection::syncAfterConfigurationChange); ++ return cf; ++ } ++ return null; } } + // Leaf end @@ -62,68 +80,79 @@ index f998cf8d70302a21289de4d84b46d322d0b8a8fe..624f1782a83ea0f8764b78819c23229f public void setListenerForServerboundHandshake(PacketListener packetListener) { if (this.packetListener != null) { diff --git a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java -index 2e9eb04c7c4342393c05339906c267bca9ff29b1..3608d499b1bcca1f6507bf58cd307ae5d9a0bca1 100644 +index 2e9eb04c7c4342393c05339906c267bca9ff29b1..c70d5a0db1dfd01eab323aefd07d6e81dd188927 100644 --- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java -@@ -140,12 +140,23 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis +@@ -140,11 +140,32 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis } } -+ private volatile boolean changedState = false; // Leaf ++ private volatile boolean changingState = false; // Leaf @Override public void handleConfigurationFinished(ServerboundFinishConfigurationPacket packet) { -- PacketUtils.ensureRunningOnSameThread(packet, this, this.server); -- this.finishCurrentTask(JoinWorldTask.TYPE); -- this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))); -- + // Leaf start -+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { -+ if (!changedState) { -+ this.finishCurrentTask(JoinWorldTask.TYPE); -+ this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))); -+ } -+ changedState = true; -+ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); -+ } else { -+ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); ++ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && !changingState) { ++ changingState = true; + this.finishCurrentTask(JoinWorldTask.TYPE); -+ this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))); ++ this.connection.setupOutboundProtocolAsync(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))).addListener(l -> { ++ try { ++ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); ++ } catch (net.minecraft.server.RunningOnDifferentThreadException ignored) { ++ } catch ( ++ io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop ++ } catch (java.util.concurrent.RejectedExecutionException var6) { ++ this.connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown")); ++ } catch (ClassCastException var7) { ++ LOGGER.error("Received {} that couldn't be processed", packet.getClass(), var7); ++ this.connection.disconnect(Component.translatable("multiplayer.disconnect.invalid_packet")); ++ } ++ }); ++ return; + } + // Leaf end + PacketUtils.ensureRunningOnSameThread(packet, this, this.server); +- this.finishCurrentTask(JoinWorldTask.TYPE); +- this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))); ++ if (!org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { this.finishCurrentTask(JoinWorldTask.TYPE); } // Leaf ++ if (!org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))); } // Leaf + try { PlayerList playerList = this.server.getPlayerList(); - if (playerList.getPlayer(this.gameProfile.getId()) != null) { diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index e9ce273812259627b61824ca4ffe83d301a4d946..0b5c9d55a7638c894a27eaeba8c98154a0b1380a 100644 +index e9ce273812259627b61824ca4ffe83d301a4d946..d7c113706d94ea510ddf7d0fffa927a15b198e9a 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -472,11 +472,26 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -472,11 +472,32 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); } -+ private volatile boolean changedState = false; // Leaf ++ private volatile boolean changingState = false; // Leaf @Override public void handleLoginAcknowledgement(ServerboundLoginAcknowledgedPacket packet) { -- PacketUtils.ensureRunningOnSameThread(packet, this, this.server); // CraftBukkit -- Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); -- this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); + // Leaf start -+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { -+ if (!changedState) { -+ Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); -+ this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); -+ } -+ changedState = true; -+ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); -+ } else { -+ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); -+ Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); -+ this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); ++ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && !changingState) { ++ changingState = true; ++ this.connection.setupOutboundProtocolAsync(ConfigurationProtocols.CLIENTBOUND).addListener(l -> { ++ try { ++ PacketUtils.ensureRunningOnSameThread(packet, this, this.server); ++ } catch (net.minecraft.server.RunningOnDifferentThreadException ignored) { ++ } catch ( ++ io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop ++ } catch (java.util.concurrent.RejectedExecutionException var6) { ++ this.connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown")); ++ } catch (ClassCastException var7) { ++ LOGGER.error("Received {} that couldn't be processed", packet.getClass(), var7); ++ this.connection.disconnect(Component.translatable("multiplayer.disconnect.invalid_packet")); ++ } ++ }); ++ return; + } -+ // PacketUtils.ensureRunningOnSameThread(packet, this, this.server); // CraftBukkit -+ // Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); -+ // this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); + // Leaf end ++ + PacketUtils.ensureRunningOnSameThread(packet, this, this.server); // CraftBukkit + Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); +- this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); ++ if (!org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) { this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); } // Leaf CommonListenerCookie commonListenerCookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred); ServerConfigurationPacketListenerImpl serverConfigurationPacketListenerImpl = new ServerConfigurationPacketListenerImpl( this.server, this.connection, commonListenerCookie, this.player // CraftBukkit