summaryrefslogtreecommitdiffhomepage
path: root/patches/server/1067-Add-proper-async-player-disconnections.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/1067-Add-proper-async-player-disconnections.patch')
-rw-r--r--patches/server/1067-Add-proper-async-player-disconnections.patch168
1 files changed, 168 insertions, 0 deletions
diff --git a/patches/server/1067-Add-proper-async-player-disconnections.patch b/patches/server/1067-Add-proper-async-player-disconnections.patch
new file mode 100644
index 0000000000..a1280f8798
--- /dev/null
+++ b/patches/server/1067-Add-proper-async-player-disconnections.patch
@@ -0,0 +1,168 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Spottedleaf <[email protected]>
+Date: Wed, 16 Oct 2024 06:41:32 -0700
+Subject: [PATCH] Add proper async player disconnections
+
+Blocking can cause performance problems
+
+diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
+index 3e550f8e7cd4f4e16f499a8a2a4b95420270f07a..4a8356a714ed50d4a32bcf046a2e16491bef014b 100644
+--- a/src/main/java/net/minecraft/network/Connection.java
++++ b/src/main/java/net/minecraft/network/Connection.java
+@@ -850,6 +850,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
+
+ }
+
++ // Paper start - add proper async disconnect
++ public void enableAutoRead() {
++ if (this.channel != null) {
++ this.channel.config().setAutoRead(true);
++ }
++ }
++ // Paper end - add proper async disconnect
++
+ public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
+ if (compressionThreshold >= 0) {
+ com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher
+diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+index 6998f32f8d79dbdb6b31ffaa126602fc4a428616..7174f8c89a7cdcf40ff28f6636ecfb23b13ccdaa 100644
+--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
++++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+@@ -136,11 +136,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
+ this.latency = (this.latency * 3 + i) / 4;
+ this.keepAlivePending = false;
+ } else if (!this.isSingleplayerOwner()) {
+- // Paper start - This needs to be handled on the main thread for plugins
+- server.submit(() -> {
+- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause
+- });
+- // Paper end - This needs to be handled on the main thread for plugins
++ this.disconnectAsync(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - add proper async disconnect
+ }
+
+ }
+@@ -404,6 +400,31 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
+ minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper
+ }
+
++ // Paper start - add proper async disconnect
++ public void disconnectAsync(net.kyori.adventure.text.Component reason, PlayerKickEvent.Cause cause) {
++ this.disconnectAsync(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason), cause);
++ }
++
++ public void disconnectAsync(Component reason, PlayerKickEvent.Cause cause) {
++ this.disconnectAsync(new DisconnectionDetails(reason), cause);
++ }
++
++ public void disconnectAsync(DisconnectionDetails disconnectionInfo, PlayerKickEvent.Cause cause) {
++ if (this.cserver.isPrimaryThread()) {
++ this.disconnect(disconnectionInfo, cause);
++ return;
++ }
++ this.connection.setReadOnly();
++ this.server.scheduleOnMain(() -> {
++ ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo, cause);
++ if (ServerCommonPacketListenerImpl.this.player.quitReason == null) {
++ // cancelled
++ ServerCommonPacketListenerImpl.this.connection.enableAutoRead();
++ }
++ });
++ }
++ // Paper end - add proper async disconnect
++
+ protected boolean isSingleplayerOwner() {
+ return this.server.isSingleplayerOwner(this.playerProfile());
+ }
+diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+index befeaac4786760f6847a5945da2296a3e68dbb17..064d52d4479727c6a32bf357be8da32d1760e7fc 100644
+--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+@@ -791,7 +791,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+ // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async
+ // CraftBukkit start
+ if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper - configurable tab spam limits
+- this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause
++ this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause // Paper - add proper async disconnect
+ return;
+ }
+ // CraftBukkit end
+@@ -803,7 +803,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+ // Paper start
+ final int index;
+ if (packet.getCommand().length() > 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) {
+- this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM);
++ this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - add proper async disconnect
+ return;
+ }
+ // Paper end
+@@ -1190,14 +1190,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+
+ if (byteTotal > byteAllowed) {
+ ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size());
+- this.disconnect(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause
++ this.disconnectAsync(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
+ return;
+ }
+ }
+ // Paper end - Book size limits
+ // CraftBukkit start
+ if (this.lastBookTick + 20 > MinecraftServer.currentTick) {
+- this.disconnect(Component.literal("Book edited too quickly!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause
++ this.disconnectAsync(Component.literal("Book edited too quickly!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
+ return;
+ }
+ this.lastBookTick = MinecraftServer.currentTick;
+@@ -2354,7 +2354,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+
+ private void tryHandleChat(String s, Runnable runnable, boolean sync) { // CraftBukkit
+ if (ServerGamePacketListenerImpl.isChatMessageIllegal(s)) {
+- this.disconnect((Component) Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper
++ this.disconnectAsync((Component) Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper // Paper - add proper async disconnect
+ } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
+ this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false));
+ } else {
+@@ -2377,7 +2377,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+
+ if (optional.isEmpty()) {
+ ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
+- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes
++ this.disconnectAsync(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes // Paper - add proper async disconnect
+ }
+
+ return optional;
+@@ -2550,7 +2550,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+ // this.chatSpamTickCount += 20;
+ if (counted && this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - exclude from SpigotConfig.spamExclusions
+ // CraftBukkit end
+- this.disconnect((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause
++ this.disconnectAsync((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause // Paper - add proper async disconnect
+ }
+
+ }
+@@ -2562,7 +2562,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+ synchronized (this.lastSeenMessages) {
+ if (!this.lastSeenMessages.applyOffset(packet.offset())) {
+ ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
+- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes
++ this.disconnectAsync(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes // Paper - add proper async disconnect
+ }
+
+ }
+@@ -2710,7 +2710,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+ }
+
+ if (i > 4096) {
+- this.disconnect((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause
++ this.disconnectAsync((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause // Paper - add proper async disconnect
+ }
+
+ }
+@@ -3314,7 +3314,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
+ // Paper start - auto recipe limit
+ if (!org.bukkit.Bukkit.isPrimaryThread()) {
+ if (this.recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) {
+- this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause
++ this.disconnectAsync(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause // Paper - add proper async disconnect
+ return;
+ }
+ }