From 16ef8463261fd7bcec06fec8eb61fb54caef744c Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:17:17 -0500 Subject: [PATCH 1/3] Don't schedule disconnect logic This seems to be a change based on some ancient code. Execute blocking is a bit of a misleading name, but if the disconnect is currently on the main thread, we will execute it right away, else we will block the thread until its done. However, that method WILL never be called async due to the callsite (disconnect) delegating it to the main thread and blocking already. This now brings back the behavior of disconnect being processed right away, rather than later. --- ...ion-checking-in-player-move-packet-ha.patch | 18 +++++++++--------- .../0024-Improve-keepalive-ping-system.patch | 4 ++-- .../ServerCommonPacketListenerImpl.java.patch | 15 ++++++--------- .../ServerGamePacketListenerImpl.java.patch | 6 +----- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/paper-server/patches/features/0023-Optimise-collision-checking-in-player-move-packet-ha.patch b/paper-server/patches/features/0023-Optimise-collision-checking-in-player-move-packet-ha.patch index eb7f987dfa2b..220189d50e2c 100644 --- a/paper-server/patches/features/0023-Optimise-collision-checking-in-player-move-packet-ha.patch +++ b/paper-server/patches/features/0023-Optimise-collision-checking-in-player-move-packet-ha.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Optimise collision checking in player move packet handling Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd8537c92b9dc 100644 +index d418edb869e960d68f8788bd39b77fa7c47fc4a7..3c2e9e6a1218d38573405a2747bee2fd66dc12fc 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -624,6 +624,7 @@ public class ServerGamePacketListenerImpl +@@ -623,6 +623,7 @@ public class ServerGamePacketListenerImpl } rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); @@ -17,7 +17,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 double verticalDelta = d4; d3 = d - rootVehicle.getX(); d4 = d1 - rootVehicle.getY(); -@@ -635,12 +636,21 @@ public class ServerGamePacketListenerImpl +@@ -634,12 +635,21 @@ public class ServerGamePacketListenerImpl d7 = d3 * d3 + d4 * d4 + d5 * d5; boolean flag1 = false; if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot @@ -42,7 +42,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 rootVehicle.absSnapTo(x, y, z, f, f1); this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); rootVehicle.removeLatestMovementRecording(); -@@ -719,9 +729,32 @@ public class ServerGamePacketListenerImpl +@@ -718,9 +728,32 @@ public class ServerGamePacketListenerImpl } private boolean noBlocksAround(Entity entity) { @@ -78,7 +78,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 } @Override -@@ -1503,7 +1536,7 @@ public class ServerGamePacketListenerImpl +@@ -1502,7 +1535,7 @@ public class ServerGamePacketListenerImpl } } @@ -87,7 +87,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above -@@ -1542,6 +1575,7 @@ public class ServerGamePacketListenerImpl +@@ -1541,6 +1574,7 @@ public class ServerGamePacketListenerImpl boolean flag1 = this.player.verticalCollisionBelow; this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move @@ -95,7 +95,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 // Paper start - prevent position desync if (this.awaitingPositionFromClient != null) { return; // ... thanks Mojang for letting move calls teleport across dimensions. -@@ -1575,7 +1609,17 @@ public class ServerGamePacketListenerImpl +@@ -1574,7 +1608,17 @@ public class ServerGamePacketListenerImpl } // Paper start - Add fail move event @@ -114,7 +114,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 if (!allowMovement) { io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK, toX, toY, toZ, toYaw, toPitch, false); -@@ -1710,7 +1754,7 @@ public class ServerGamePacketListenerImpl +@@ -1709,7 +1753,7 @@ public class ServerGamePacketListenerImpl private boolean updateAwaitingTeleport() { if (this.awaitingPositionFromClient != null) { @@ -123,7 +123,7 @@ index 214613e9422606b7b1f37716fc060db63c38849a..e158d614abed8d16e80192c0c9abd853 this.awaitingTeleportTime = this.tickCount; this.teleport( this.awaitingPositionFromClient.x, -@@ -1729,6 +1773,34 @@ public class ServerGamePacketListenerImpl +@@ -1728,6 +1772,34 @@ public class ServerGamePacketListenerImpl } } diff --git a/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch b/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch index f046496ff6a4..d22790c21bb6 100644 --- a/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch +++ b/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch @@ -100,7 +100,7 @@ index 21d50675bfe90c2276890779eb23de58ac915b9a..7be34e37562875313b8e43357921b5fe } } diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed501aad6239 100644 +index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f69b53623e 100644 --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -39,12 +39,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -223,7 +223,7 @@ index 079ab378920c0e52ef4e42ef20b37bd389f40870..b8a4b4cc02a2fc6b70f4b840796eed50 } } -@@ -427,6 +460,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -425,6 +458,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } protected CommonListenerCookie createCookie(ClientInformation clientInformation) { diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index 0f41a4c322e1..aa1169665e49 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -219,7 +219,7 @@ if (packet.isTerminal()) { this.close(); } -@@ -174,19 +_,114 @@ +@@ -174,20 +_,113 @@ } } @@ -312,14 +312,10 @@ + new ClientboundDisconnectPacket(disconnectionDetails.reason()), + PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails)) + ); -+ this.onDisconnect(disconnectionDetails); this.connection.setReadOnly(); -- this.server.executeBlocking(this.connection::handleDisconnection); -- } -+ // CraftBukkit - Don't wait -+ this.server.scheduleOnMain(this.connection::handleDisconnection); // Paper -+ } -+ + this.server.executeBlocking(this.connection::handleDisconnection); + } + + // Paper start - add proper async disconnect + public final void disconnectAsync(Component component, io.papermc.paper.connection.DisconnectionReason reason) { + this.disconnectAsync(new DisconnectionDetails(component, java.util.Optional.empty(), java.util.Optional.empty(), java.util.Optional.empty(), java.util.Optional.of(reason))); @@ -338,9 +334,10 @@ + + public abstract io.papermc.paper.connection.PaperCommonConnection paperConnection(); + // Paper end - add proper async disconnect - ++ protected boolean isSingleplayerOwner() { return this.server.isSingleplayerOwner(new NameAndId(this.playerProfile())); + } @@ -204,6 +_,6 @@ } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index cb5a872dad48..4f9b30e9523c 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -83,7 +83,7 @@ public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) { super(server, connection, cookie); -@@ -276,11 +_,26 @@ +@@ -276,8 +_,22 @@ player.connection = this; player.getTextFilter().join(); this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(player.getUUID(), server::enforceSecureProfile); @@ -108,10 +108,6 @@ @Override public void tick() { -+ if (this.isDisconnected()) return; // Paper - if (this.ackBlockChangesUpTo > -1) { - this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); - this.ackBlockChangesUpTo = -1; @@ -290,11 +_,13 @@ this.keepConnectionAlive(); this.chatSpamThrottler.tick(); From e9bf7b29b106cbb8dfc3942e1845db4cfb901b11 Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:58:28 -0500 Subject: [PATCH 2/3] This seems to be a really ancient flag that was used to prevent disconnect from being called multiple times. This is no longer an issue, as onDisconnect is now guarded by a vanilla disconnectionHandled check. However, this does require we properly wait for the connection to close. I am not sure about the best solution for that, as alternatively we can possibly treat the connection has inactive on a custom flag set. Also remove the hack needed on server login, as we now properly disconnect the connection. --- ...ocity-compression-and-cipher-natives.patch | 6 ++-- .../0024-Improve-keepalive-ping-system.patch | 28 ++++++++----------- .../minecraft/network/Connection.java.patch | 9 +----- .../network/PacketProcessor.java.patch | 3 +- .../ServerCommonPacketListenerImpl.java.patch | 7 ++--- .../ServerGamePacketListenerImpl.java.patch | 12 ++------ .../ServerLoginPacketListenerImpl.java.patch | 14 ++-------- 7 files changed, 23 insertions(+), 56 deletions(-) diff --git a/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch b/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch index 86b04d15d7f5..e67f7c58956b 100644 --- a/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch +++ b/paper-server/patches/features/0006-Use-Velocity-compression-and-cipher-natives.patch @@ -267,7 +267,7 @@ index 35b8a2bddeefff2b1ba8ed75ec780c41d59ce92f..1baa8daf880c5f87f1d72ecf0e1b93c7 + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index 8817a2d6500d1bdce96d87dc8f7f364ccfa390e5..19ec939529eb638bdc4d7fd9260f161fae118314 100644 +index 57a0c5696a5ddacaa9908650a9f17ec0c6036c22..0449faff49b857eec4bc45c46f4b3348e7eb9532 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java @@ -728,11 +728,22 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -335,10 +335,10 @@ index 309845b28306dfa5946e79b80e5b1dde82dd68cd..33e1cdb00d648c992af03a9768992531 .add( new ServerBootstrap() diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index ec5bd4568872c48addd26dd652868e0e5df57038..31bc0a105152a7f24a4126542bea7dbebc3e037c 100644 +index 7699f3022402b19ac57f40e586628c68bf646aad..4f00ad88fa268bd1a1ebd412cfa4d4c5e08f3ca8 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -245,11 +245,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, +@@ -242,11 +242,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, } SecretKey secretKey = packet.getSecretKey(_private); diff --git a/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch b/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch index d22790c21bb6..0753bc12ccc7 100644 --- a/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch +++ b/paper-server/patches/features/0024-Improve-keepalive-ping-system.patch @@ -100,7 +100,7 @@ index 21d50675bfe90c2276890779eb23de58ac915b9a..7be34e37562875313b8e43357921b5fe } } diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f69b53623e 100644 +index 045fe927ddf47191c9e8e3f0febe2cf2aaa90126..d083bb6f45ec2dadd5607d1dd1f6e13da2749b74 100644 --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -39,12 +39,13 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -121,7 +121,7 @@ index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f6 private volatile boolean suspendFlushingOnServerThread = false; // CraftBukkit start public final org.bukkit.craftbukkit.CraftServer cserver; -@@ -61,13 +62,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -60,13 +61,14 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) { this.server = server; this.connection = connection; @@ -137,7 +137,7 @@ index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f6 // Paper end } -@@ -100,13 +102,41 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -99,13 +101,35 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { @@ -167,25 +167,19 @@ index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f6 + if (ka.challengeId() == packet.getId()) { + itr.remove(); + -+ if (!this.processedDisconnect) { -+ LOGGER.info("Disconnecting {} for sending keepalive response ({}) out-of-order!", this.playerProfile().name(), packet.getId()); -+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); -+ return; -+ } -+ break; ++ LOGGER.info("Disconnecting {} for sending keepalive response ({}) out-of-order!", this.playerProfile().name(), packet.getId()); ++ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); ++ return; + } } + -+ if (!this.processedDisconnect) { -+ LOGGER.info("Disconnecting {} for sending keepalive response ({}) without matching challenge!", this.playerProfile().name(), packet.getId()); -+ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); -+ return; -+ } ++ LOGGER.info("Disconnecting {} for sending keepalive response ({}) without matching challenge!", this.playerProfile().name(), packet.getId()); ++ this.disconnectAsync(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); + // Paper end - improve keepalives } @Override -@@ -233,20 +263,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -232,20 +256,23 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack protected void keepConnectionAlive() { Profiler.get().push("keepAlive"); long millis = Util.getMillis(); @@ -204,7 +198,7 @@ index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f6 - this.keepAliveChallenge = millis; - this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge)); + // Paper start - improve keepalives -+ if (this.checkIfClosed(millis) && !this.processedDisconnect) { ++ if (this.checkIfClosed(millis)) { + long currTime = System.nanoTime(); + + if ((currTime - this.keepAlive.lastKeepAliveTx) >= java.util.concurrent.TimeUnit.SECONDS.toNanos(1L)) { @@ -223,7 +217,7 @@ index 58e9c069c252f7222e35c5a3fc80b2a104396ff9..c35bf8cc33658e7b8e49051d25c027f6 } } -@@ -425,6 +458,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -424,6 +451,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } protected CommonListenerCookie createCookie(ClientInformation clientInformation) { diff --git a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch index 9e277b37beeb..3dc6fc6029a6 100644 --- a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch @@ -218,7 +218,7 @@ } if (this.tickCount++ % 20 == 0) { -@@ -393,12 +_,13 @@ +@@ -393,6 +_,7 @@ } public void disconnect(DisconnectionDetails disconnectionDetails) { @@ -226,13 +226,6 @@ if (this.channel == null) { this.delayedDisconnect = disconnectionDetails; } - - if (this.isConnected()) { -- this.channel.close().awaitUninterruptibly(); -+ this.channel.close(); // We can't wait as this may be called from an event loop. - this.disconnectionDetails = disconnectionDetails; - } - } @@ -533,6 +_,13 @@ } } diff --git a/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch b/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch index ee4fd097d9fe..a6a32c617fb2 100644 --- a/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch @@ -43,7 +43,7 @@ } } -@@ -44,8 +_,29 @@ +@@ -44,8 +_,28 @@ this.closed = true; } @@ -69,7 +69,6 @@ public void handle() { + packetProcessing.push(this.listener); // Paper - detailed watchdog information + try { // Paper - detailed watchdog information -+ if (this.listener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players if (this.listener.shouldHandleMessage(this.packet)) { try { this.packet.handle(this.listener); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index aa1169665e49..0875a4651b70 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -9,13 +9,12 @@ private final boolean transferred; private long keepAliveTime; private boolean keepAlivePending; -@@ -46,6 +_,17 @@ +@@ -46,6 +_,16 @@ private boolean closed = false; private int latency; private volatile boolean suspendFlushingOnServerThread = false; + // CraftBukkit start + public final org.bukkit.craftbukkit.CraftServer cserver; -+ public boolean processedDisconnect; + // CraftBukkit end + public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks + private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit @@ -210,7 +209,7 @@ public void send(Packet packet, @Nullable ChannelFutureListener sendListener) { + // CraftBukkit start -+ if (packet == null || this.processedDisconnect) { // Spigot ++ if (packet == null) { + return; + } else if (packet instanceof net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket defaultSpawnPositionPacket && this instanceof ServerGamePacketListenerImpl serverGamePacketListener) { + serverGamePacketListener.player.compassTarget = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(defaultSpawnPositionPacket.respawnData().pos(), serverGamePacketListener.getPlayer().level()); @@ -241,7 +240,7 @@ - new ClientboundDisconnectPacket(disconnectionDetails.reason()), - PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails)) + // CraftBukkit start - fire PlayerKickEvent -+ if (this.processedDisconnect) { ++ if (!this.connection.isConnected()) { + return; + } + if (!this.cserver.isPrimaryThread()) { diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 4f9b30e9523c..6c629d9454fc 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -1359,17 +1359,9 @@ return; } } -@@ -1395,24 +_,50 @@ - +@@ -1396,23 +_,42 @@ @Override public void onDisconnect(DisconnectionDetails details) { -+ // CraftBukkit start - Rarely it would send a disconnect line twice -+ if (this.processedDisconnect) { -+ return; -+ } else { -+ this.processedDisconnect = true; -+ } -+ // CraftBukkit end LOGGER.info("{} lost connection: {}", this.player.getPlainTextName(), details.reason().getString()); - this.removePlayerFromWorld(); + // Paper start - Fix kick event leave message not being sent @@ -2678,7 +2670,7 @@ + } + + public final boolean isDisconnected() { -+ return (!this.player.joining && !this.connection.isConnected()) || this.processedDisconnect; // Paper - Fix duplication bugs ++ return (!this.player.joining && !this.connection.isConnected()); + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch index f7a4161d565d..7e0cabdf9a25 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch @@ -17,7 +17,7 @@ private static final int MAX_TICKS_BEFORE_LOGIN = 600; private final byte[] challenge; final MinecraftServer server; -@@ -56,10 +_,15 @@ +@@ -56,10 +_,14 @@ final ServerActivityMonitor serverActivityMonitor; public volatile ServerLoginPacketListenerImpl.State state = ServerLoginPacketListenerImpl.State.HELLO; private int tick; @@ -31,11 +31,10 @@ + private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support + public java.util.@Nullable UUID requestedUuid; // Paper + private final io.papermc.paper.connection.PaperPlayerLoginConnection paperLoginConnection; // Paper - Config API -+ private volatile boolean disconnecting = false; // Paper - Fix disconnect still ticking login public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) { this.server = server; -@@ -67,10 +_,20 @@ +@@ -67,10 +_,19 @@ this.serverActivityMonitor = this.server.getServerActivityMonitor(); this.challenge = Ints.toByteArray(RandomSource.create().nextInt()); this.transferred = transferred; @@ -44,7 +43,6 @@ @Override public void tick() { -+ if (this.disconnecting) return; // Paper - Fix disconnect being called multiple times due to not awaiting for disconnect + // Paper start - login cookie API + // Don't block the connection + if (this.paperLoginConnection.isAwaitingCookies()) { @@ -80,14 +78,6 @@ @Override public boolean isAcceptingMessages() { return this.connection.isConnected(); -@@ -95,6 +_,7 @@ - LOGGER.info("Disconnecting {}: {}", this.getUserName(), reason.getString()); - this.connection.send(new ClientboundLoginDisconnectPacket(reason)); - this.connection.disconnect(reason); -+ this.disconnecting = true; // Paper - Fix disconnect still ticking login - } catch (Exception var3) { - LOGGER.error("Error whilst disconnecting player", (Throwable)var3); - } @@ -117,7 +_,14 @@ @Override public void handleHello(ServerboundHelloPacket packet) { From 00cd35e52a955f125325a8e89b7754531689c5a8 Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Sat, 7 Feb 2026 22:41:42 -0500 Subject: [PATCH 3/3] Force prevent the connection from ticking on disconnect This has two effects: - Most notably, the old executeBlocking did not actually work as the connection is typically still open at this stage. This is because it waits for disconnect to be sent before actually closing the connection. - We will now mark the connection to be killed on disconnect, where the forceKill will cause the connection to be cleaned up when its ticked. This seems like a vanilla bug and should be reported. This also removes the old ontick on disconnect. As that caused some things to incorrectly complete on tick anyways. The original bug is not applicable anymore. --- .../net/minecraft/network/Connection.java.patch | 3 ++- .../ServerCommonPacketListenerImpl.java.patch | 13 +++++++------ .../network/ServerConnectionListener.java.patch | 15 ++++++++++++++- .../server/players/PlayerList.java.patch | 3 +-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch index 3dc6fc6029a6..f7d003aa0000 100644 --- a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch @@ -12,11 +12,12 @@ private volatile @Nullable PacketListener disconnectListener; private volatile @Nullable PacketListener packetListener; private @Nullable DisconnectionDetails disconnectionDetails; -@@ -81,6 +_,43 @@ +@@ -81,6 +_,44 @@ private boolean handlingFault; private volatile @Nullable DisconnectionDetails delayedDisconnect; @Nullable BandwidthDebugMonitor bandwidthDebugMonitor; + public String hostname = ""; // CraftBukkit - add field ++ public boolean killConnectionOnNextTick = false; // Paper - Force kill connection ticking + // Paper start - NetworkClient implementation + public int protocolVersion; + public java.net.InetSocketAddress virtualHost; diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index 0875a4651b70..a05ccdfcb6c5 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -218,7 +218,7 @@ if (packet.isTerminal()) { this.close(); } -@@ -174,20 +_,113 @@ +@@ -174,19 +_,112 @@ } } @@ -312,9 +312,11 @@ + PacketSendListener.thenRun(() -> this.connection.disconnect(disconnectionDetails)) + ); this.connection.setReadOnly(); - this.server.executeBlocking(this.connection::handleDisconnection); - } - +- this.server.executeBlocking(this.connection::handleDisconnection); +- } ++ this.connection.killConnectionOnNextTick = true; // Paper - Force kill connection ticking. Let this close the connection ++ } ++ + // Paper start - add proper async disconnect + public final void disconnectAsync(Component component, io.papermc.paper.connection.DisconnectionReason reason) { + this.disconnectAsync(new DisconnectionDetails(component, java.util.Optional.empty(), java.util.Optional.empty(), java.util.Optional.empty(), java.util.Optional.of(reason))); @@ -333,10 +335,9 @@ + + public abstract io.papermc.paper.connection.PaperCommonConnection paperConnection(); + // Paper end - add proper async disconnect -+ + protected boolean isSingleplayerOwner() { return this.server.isSingleplayerOwner(new NameAndId(this.playerProfile())); - } @@ -204,6 +_,6 @@ } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch index d4308c9813fd..09923df18109 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch @@ -100,7 +100,7 @@ public SocketAddress startMemoryChannel() { ChannelFuture channelFuture; synchronized (this.channels) { -@@ -141,6 +_,13 @@ +@@ -141,12 +_,26 @@ public void tick() { synchronized (this.connections) { @@ -114,6 +114,19 @@ Iterator iterator = this.connections.iterator(); while (iterator.hasNext()) { + Connection connection = iterator.next(); + if (!connection.isConnecting()) { + if (connection.isConnected()) { ++ // Paper start - Force kill connection ticking ++ // also call this multiple times, doesnt matter ++ if (connection.killConnectionOnNextTick) { ++ connection.handleDisconnection(); ++ return; ++ } ++ // Paper end - Force kill connection ticking + try { + connection.tick(); + } catch (Exception var7) { @@ -160,6 +_,7 @@ connection.setReadOnly(); } diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index 7ba449bd2628..ffdc9d4b4da9 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -266,7 +266,7 @@ } @Override -@@ -290,56 +_,137 @@ +@@ -290,56 +_,136 @@ } protected void save(ServerPlayer player) { @@ -304,7 +304,6 @@ + this.cserver.getPluginManager().callEvent(playerQuitEvent); + player.getBukkitEntity().disconnect(); + -+ if (this.server.isSameThread()) player.doTick(); // SPIGOT-924 // Paper - Improved watchdog support; don't tick during emergency shutdowns + // CraftBukkit end + + // Paper start - Configurable player collision; Remove from collideRule team if needed