aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/1030-Add-proper-async-player-disconnections.patch
blob: c4b7ef0d4089e3fb50bd128f9495ac26d4cbb305 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
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 9d6738b431867836c5e64bc13e887fd4af4627e1..e300293ba64a8ac54cc9c5348ecc9f3ed2d27e19 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -844,6 +844,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 fc242acade3ff06c9213428cde103cf078216382..b0bc66dc7248aae691dcab68b925b52a1695e63f 100644
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -143,11 +143,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
         }
 
     }
@@ -411,6 +407,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 f6d3baf1da22a474ccc9be80781091405362d7db..f0200e2e68e3ec88b82d337a76e22a6e80419b6f 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -767,7 +767,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
         // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async
         // CraftBukkit start
         if (!this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(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
@@ -779,7 +779,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
@@ -1224,14 +1224,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;
@@ -2364,7 +2364,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 {
@@ -2387,7 +2387,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;
@@ -2558,7 +2558,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
         // this.chatSpamThrottler.increment();
         if (!this.chatSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) {
             // 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
         }
 
     }
@@ -2570,7 +2570,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
             }
 
         }
@@ -2723,7 +2723,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
             }
 
         }
@@ -3334,7 +3334,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
         // Paper start - auto recipe limit
         if (!org.bukkit.Bukkit.isPrimaryThread()) {
             if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) {
-                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;
             }
         }