From 26fe3d0cff505a4dc69451b77102a47961fe0964 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Thu, 11 Apr 2024 16:37:44 +0100 Subject: [PATCH] Fix premature player kicks on shutdown When the server is stopping, the default execution handler method will throw a RejectedExecutionException in order to prevent further execution, this causes us to lose the actual kick reason. To mitigate this, we'll use a seperate marked class in order to gracefully ignore these. --- .../minecraft/network/Connection.java.patch | 24 ++++++++----- .../server/MinecraftServer.java.patch | 36 +++++++++++-------- .../ServerStopRejectedExecutionException.java | 20 +++++++++++ 3 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java 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 ca6a9a5e36..c7d8a673c6 100644 --- a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch @@ -108,7 +108,7 @@ } protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet packet) { -@@ -185,6 +231,55 @@ +@@ -185,11 +231,61 @@ if (packetlistener == null) { throw new IllegalStateException("Received a packet before the packet listener was initialized"); } else { @@ -164,7 +164,13 @@ if (packetlistener.shouldHandleMessage(packet)) { try { Connection.genericsFtw(packet, packetlistener); -@@ -205,7 +300,7 @@ + } catch (RunningOnDifferentThreadException cancelledpackethandleexception) { + ; ++ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop + } catch (RejectedExecutionException rejectedexecutionexception) { + this.disconnect((Component) Component.translatable("multiplayer.disconnect.server_shutdown")); + } catch (ClassCastException classcastexception) { +@@ -205,7 +301,7 @@ } private static void genericsFtw(Packet packet, PacketListener listener) { @@ -173,7 +179,7 @@ } private void validateListener(ProtocolInfo state, PacketListener listener) { -@@ -418,12 +513,26 @@ +@@ -418,12 +514,26 @@ } } @@ -200,7 +206,7 @@ } if (!this.isConnected() && !this.disconnectionHandled) { -@@ -431,7 +540,7 @@ +@@ -431,7 +541,7 @@ } if (this.channel != null) { @@ -209,7 +215,7 @@ } if (this.tickCount++ % 20 == 0) { -@@ -464,12 +573,15 @@ +@@ -464,12 +574,15 @@ } public void disconnect(DisconnectionDetails disconnectionInfo) { @@ -226,7 +232,7 @@ this.disconnectionDetails = disconnectionInfo; } -@@ -537,7 +649,7 @@ +@@ -537,7 +650,7 @@ } public void configurePacketHandler(ChannelPipeline pipeline) { @@ -235,7 +241,7 @@ public void write(ChannelHandlerContext channelhandlercontext, Object object, ChannelPromise channelpromise) throws Exception { super.write(channelhandlercontext, object, channelpromise); } -@@ -633,6 +745,7 @@ +@@ -633,6 +746,7 @@ } else { this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold)); } @@ -243,7 +249,7 @@ } else { if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { this.channel.pipeline().remove("decompress"); -@@ -641,6 +754,7 @@ +@@ -641,6 +755,7 @@ if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) { this.channel.pipeline().remove("compress"); } @@ -251,7 +257,7 @@ } } -@@ -661,6 +775,27 @@ +@@ -661,6 +776,27 @@ packetlistener1.onDisconnect(disconnectiondetails); } diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index 76de6823a4..3de10a1ff1 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -1232,6 +1232,15 @@ } public boolean isReady() { +@@ -1593,7 +2127,7 @@ + @Override + public void executeIfPossible(Runnable runnable) { + if (this.isStopped()) { +- throw new RejectedExecutionException("Server already shutting down"); ++ throw new io.papermc.paper.util.ServerStopRejectedExecutionException("Server already shutting down"); // Paper - do not prematurely disconnect players on stop + } else { + super.executeIfPossible(runnable); + } @@ -1632,13 +2166,19 @@ return this.functionManager; } @@ -1312,22 +1321,19 @@ try { arraylist = Lists.newArrayList(NativeModuleLister.listModules()); -@@ -2105,9 +2650,24 @@ - if (bufferedwriter != null) { - bufferedwriter.close(); - } -+ -+ } -+ +@@ -2108,6 +2653,21 @@ + + } + + // CraftBukkit start + public boolean isDebugging() { + return false; + } - ++ + public static MinecraftServer getServer() { + return SERVER; // Paper - } - ++ } ++ + @Deprecated + public static RegistryAccess getDefaultRegistryAccess() { + return CraftRegistry.getMinecraftRegistry(); @@ -1366,11 +1372,13 @@ } public boolean logIPs() { -@@ -2379,4 +2945,30 @@ - public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) { - +@@ -2377,6 +2943,32 @@ } + + public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) { + ++ } + + // Paper start - Add tick times API and /mspt command + public static class TickTimes { + private final long[] times; @@ -1394,6 +1402,6 @@ + } + return ((double) total / (double) times.length) * 1.0E-6D; + } -+ } + } + // Paper end - Add tick times API and /mspt command } diff --git a/paper-server/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java b/paper-server/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java new file mode 100644 index 0000000000..2c5cd77103 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/ServerStopRejectedExecutionException.java @@ -0,0 +1,20 @@ +package io.papermc.paper.util; + +import java.util.concurrent.RejectedExecutionException; + +public class ServerStopRejectedExecutionException extends RejectedExecutionException { + public ServerStopRejectedExecutionException() { + } + + public ServerStopRejectedExecutionException(final String message) { + super(message); + } + + public ServerStopRejectedExecutionException(final String message, final Throwable cause) { + super(message, cause); + } + + public ServerStopRejectedExecutionException(final Throwable cause) { + super(cause); + } +}