diff --git a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch index 9c6c0100fd..29d319525c 100644 --- a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch @@ -116,8 +116,9 @@ } catch (Exception exception) { MutableComponent ichatmutablecomponent = Component.literal(exception.getMessage() == null ? exception.getClass().getName() : exception.getMessage()); - if (Commands.LOGGER.isDebugEnabled()) { +- if (Commands.LOGGER.isDebugEnabled()) { - Commands.LOGGER.error("Command exception: /{}", command, exception); ++ if (commandlistenerwrapper.getServer().isDebugging() || Commands.LOGGER.isDebugEnabled()) { // Paper - Debugging + Commands.LOGGER.error("Command exception: /{}", s, exception); StackTraceElement[] astacktraceelement = exception.getStackTrace(); 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 201b8a3098..682b76c65d 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -698,28 +698,28 @@ if (flush) { Iterator iterator1 = this.getAllLevels().iterator(); -@@ -626,20 +925,44 @@ - @Override - public void close() { +@@ -628,18 +927,44 @@ this.stopServer(); -+ } -+ + } + + // CraftBukkit start + private boolean hasStopped = false; ++ private boolean hasLoggedStop = false; // Paper - Debugging + private final Object stopLock = new Object(); + public final boolean hasStopped() { + synchronized (this.stopLock) { + return this.hasStopped; + } - } ++ } + // CraftBukkit end - ++ public void stopServer() { + // CraftBukkit start - prevent double stopping on multiple threads + synchronized(this.stopLock) { + if (this.hasStopped) return; + this.hasStopped = true; + } ++ if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging + // CraftBukkit end if (this.metricsRecorder.isRecording()) { this.cancelRecordingMetrics(); @@ -744,7 +744,7 @@ } MinecraftServer.LOGGER.info("Saving worlds"); -@@ -693,6 +1016,15 @@ +@@ -693,6 +1018,15 @@ } catch (IOException ioexception1) { MinecraftServer.LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), ioexception1); } @@ -760,7 +760,7 @@ } -@@ -709,6 +1041,12 @@ +@@ -709,6 +1043,14 @@ } public void halt(boolean waitForShutdown) { @@ -769,11 +769,13 @@ + } + public void safeShutdown(boolean waitForShutdown, boolean isRestarting) { + this.isRestarting = isRestarting; ++ this.hasLoggedStop = true; // Paper - Debugging ++ if (isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging + // Paper end this.running = false; if (waitForShutdown) { try { -@@ -720,6 +1058,64 @@ +@@ -720,6 +1062,64 @@ } @@ -838,7 +840,7 @@ protected void runServer() { try { if (!this.initServer()) { -@@ -727,9 +1123,16 @@ +@@ -727,9 +1127,16 @@ } this.nextTickTimeNanos = Util.getNanos(); @@ -856,7 +858,7 @@ while (this.running) { long i; -@@ -744,12 +1147,31 @@ +@@ -744,12 +1151,31 @@ if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) { long k = j / i; @@ -888,7 +890,7 @@ boolean flag = i == 0L; if (this.debugCommandProfilerDelayStart) { -@@ -757,6 +1179,8 @@ +@@ -757,6 +1183,8 @@ this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); } @@ -897,7 +899,7 @@ this.nextTickTimeNanos += i; try { -@@ -830,6 +1254,13 @@ +@@ -830,6 +1258,13 @@ this.services.profileCache().clearExecutor(); } @@ -911,7 +913,7 @@ this.onServerExit(); } -@@ -889,9 +1320,16 @@ +@@ -889,9 +1324,16 @@ } private boolean haveTime() { @@ -929,7 +931,7 @@ public static boolean throwIfFatalException() { RuntimeException runtimeexception = (RuntimeException) MinecraftServer.fatalException.get(); -@@ -903,7 +1341,7 @@ +@@ -903,7 +1345,7 @@ } public static void setFatalException(RuntimeException exception) { @@ -938,7 +940,7 @@ } @Override -@@ -977,7 +1415,7 @@ +@@ -977,7 +1419,7 @@ } } @@ -947,7 +949,7 @@ Profiler.get().incrementCounter("runTask"); super.doRunTask(ticktask); } -@@ -1025,6 +1463,7 @@ +@@ -1025,6 +1467,7 @@ } public void tickServer(BooleanSupplier shouldKeepTicking) { @@ -955,7 +957,7 @@ long i = Util.getNanos(); int j = this.pauseWhileEmptySeconds() * 20; -@@ -1041,11 +1480,13 @@ +@@ -1041,11 +1484,13 @@ this.autoSave(); } @@ -969,7 +971,7 @@ ++this.tickCount; this.tickRateManager.tick(); this.tickChildren(shouldKeepTicking); -@@ -1055,12 +1496,18 @@ +@@ -1055,12 +1500,18 @@ } --this.ticksUntilAutosave; @@ -989,7 +991,7 @@ gameprofilerfiller.push("tallying"); long k = Util.getNanos() - i; int l = this.tickCount % 100; -@@ -1069,12 +1516,17 @@ +@@ -1069,12 +1520,17 @@ this.aggregatedTickTimesNanos += k; this.tickTimesNanos[l] = k; this.smoothedTickTimeMillis = this.smoothedTickTimeMillis * 0.8F + (float) k / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND * 0.19999999F; @@ -1008,7 +1010,7 @@ MinecraftServer.LOGGER.debug("Autosave started"); ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -1123,7 +1575,7 @@ +@@ -1123,7 +1579,7 @@ private ServerStatus buildServerStatus() { ServerStatus.Players serverping_serverpingplayersample = this.buildPlayerStatus(); @@ -1017,7 +1019,7 @@ } private ServerStatus.Players buildPlayerStatus() { -@@ -1133,7 +1585,7 @@ +@@ -1133,7 +1589,7 @@ if (this.hidesOnlinePlayers()) { return new ServerStatus.Players(i, list.size(), List.of()); } else { @@ -1026,7 +1028,7 @@ ObjectArrayList objectarraylist = new ObjectArrayList(j); int k = Mth.nextInt(this.random, 0, list.size() - j); -@@ -1154,24 +1606,55 @@ +@@ -1154,24 +1610,55 @@ this.getPlayerList().getPlayers().forEach((entityplayer) -> { entityplayer.connection.suspendFlushing(); }); @@ -1082,7 +1084,7 @@ gameprofilerfiller.push("tick"); -@@ -1186,6 +1669,7 @@ +@@ -1186,6 +1673,7 @@ gameprofilerfiller.pop(); gameprofilerfiller.pop(); @@ -1090,20 +1092,18 @@ } gameprofilerfiller.popPush("connection"); -@@ -1265,8 +1749,24 @@ - @Nullable - public ServerLevel getLevel(ResourceKey key) { +@@ -1267,6 +1755,22 @@ return (ServerLevel) this.levels.get(key); -+ } -+ + } + + // CraftBukkit start + public void addLevel(ServerLevel level) { + Map, ServerLevel> oldLevels = this.levels; + Map, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); + newLevels.put(level.dimension(), level); + this.levels = Collections.unmodifiableMap(newLevels); - } - ++ } ++ + public void removeLevel(ServerLevel level) { + Map, ServerLevel> oldLevels = this.levels; + Map, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); @@ -1115,7 +1115,7 @@ public Set> levelKeys() { return this.levels.keySet(); } -@@ -1296,7 +1796,7 @@ +@@ -1296,7 +1800,7 @@ @DontObfuscate public String getServerModName() { @@ -1124,7 +1124,7 @@ } public SystemReport fillSystemReport(SystemReport details) { -@@ -1347,7 +1847,7 @@ +@@ -1347,7 +1851,7 @@ @Override public void sendSystemMessage(Component message) { @@ -1133,7 +1133,7 @@ } public KeyPair getKeyPair() { -@@ -1481,10 +1981,20 @@ +@@ -1481,10 +1985,20 @@ @Override public String getMotd() { @@ -1155,7 +1155,7 @@ this.motd = motd; } -@@ -1507,7 +2017,7 @@ +@@ -1507,7 +2021,7 @@ } public ServerConnectionListener getConnection() { @@ -1164,7 +1164,7 @@ } public boolean isReady() { -@@ -1634,11 +2144,11 @@ +@@ -1634,11 +2148,11 @@ public CompletableFuture reloadResources(Collection dataPacks) { CompletableFuture completablefuture = CompletableFuture.supplyAsync(() -> { @@ -1178,7 +1178,7 @@ }, this).thenCompose((immutablelist) -> { MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist); List> list = TagLoader.loadTagsForExistingRegistries(resourcemanager, this.registries.compositeAccess()); -@@ -1654,6 +2164,7 @@ +@@ -1654,6 +2168,7 @@ }).thenAcceptAsync((minecraftserver_reloadableresources) -> { this.resources.close(); this.resources = minecraftserver_reloadableresources; @@ -1186,7 +1186,7 @@ this.packRepository.setSelected(dataPacks); WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); -@@ -1952,7 +2463,7 @@ +@@ -1952,7 +2467,7 @@ final List list = Lists.newArrayList(); final GameRules gamerules = this.getGameRules(); @@ -1195,7 +1195,7 @@ @Override public > void visit(GameRules.Key key, GameRules.Type type) { list.add(String.format(Locale.ROOT, "%s=%s\n", key.getId(), gamerules.getRule(key))); -@@ -2058,7 +2569,7 @@ +@@ -2058,7 +2573,7 @@ try { label51: { @@ -1204,31 +1204,32 @@ try { arraylist = Lists.newArrayList(NativeModuleLister.listModules()); -@@ -2105,8 +2616,23 @@ +@@ -2105,9 +2620,24 @@ if (bufferedwriter != null) { bufferedwriter.close(); } + + } -+ + + // CraftBukkit start + public boolean isDebugging() { + return false; -+ } -+ + } + + public static MinecraftServer getServer() { + return SERVER; // Paper + } - ++ + @Deprecated + public static RegistryAccess getDefaultRegistryAccess() { + return CraftRegistry.getMinecraftRegistry(); - } ++ } + // CraftBukkit end - ++ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { -@@ -2225,18 +2751,24 @@ + this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> { +@@ -2225,18 +2755,24 @@ } public void logChatMessage(Component message, ChatType.Bound params, @Nullable String prefix) { @@ -1257,17 +1258,15 @@ } public boolean logIPs() { -@@ -2377,6 +2909,32 @@ - } - +@@ -2379,4 +2915,30 @@ 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; - ++ + public TickTimes(int length) { + times = new long[length]; + } @@ -1287,6 +1286,6 @@ + } + return ((double) total / (double) times.length) * 1.0E-6D; + } - } ++ } + // Paper end - Add tick times API and /mspt command } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index 81838f6e80..813b398d03 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -29,7 +29,18 @@ } @Override -@@ -75,6 +82,12 @@ +@@ -63,6 +70,10 @@ + + @Override + public void onDisconnect(DisconnectionDetails info) { ++ // Paper start - Debugging ++ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) { ++ ServerConfigurationPacketListenerImpl.LOGGER.info("{} lost connection: {}, while in configuration phase {}", this.gameProfile, info.reason().getString(), currentTask != null ? currentTask.type().id() : "null"); ++ } else // Paper end + ServerConfigurationPacketListenerImpl.LOGGER.info("{} lost connection: {}", this.gameProfile, info.reason().getString()); + super.onDisconnect(info); + } +@@ -75,6 +86,12 @@ public void startConfiguration() { this.send(new ClientboundCustomPayloadPacket(new BrandPayload(this.server.getServerModName()))); ServerLinks serverlinks = this.server.serverLinks(); @@ -42,7 +53,7 @@ if (!serverlinks.isEmpty()) { this.send(new ClientboundServerLinksPacket(serverlinks.untrust())); -@@ -107,6 +120,7 @@ +@@ -107,6 +124,7 @@ @Override public void handleClientInformation(ServerboundClientInformationPacket packet) { this.clientInformation = packet.information(); @@ -50,7 +61,7 @@ } @Override -@@ -143,14 +157,14 @@ +@@ -143,18 +161,23 @@ return; } @@ -67,3 +78,12 @@ playerlist.placeNewPlayer(this.connection, entityplayer, this.createCookie(this.clientInformation)); } catch (Exception exception) { + ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); ++ // Paper start - Debugging ++ if (MinecraftServer.getServer().isDebugging()) { ++ exception.printStackTrace(); ++ } ++ // Paper end - Debugging + this.connection.send(new ClientboundDisconnectPacket(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA)); + this.connection.disconnect(ServerConfigurationPacketListenerImpl.DISCONNECT_REASON_INVALID_DATA); + } diff --git a/paper-server/src/main/java/io/papermc/paper/util/TraceUtil.java b/paper-server/src/main/java/io/papermc/paper/util/TraceUtil.java new file mode 100644 index 0000000000..479bb92d15 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/util/TraceUtil.java @@ -0,0 +1,25 @@ +package io.papermc.paper.util; + +import org.bukkit.Bukkit; + +public final class TraceUtil { + + public static void dumpTraceForThread(Thread thread, String reason) { + Bukkit.getLogger().warning(thread.getName() + ": " + reason); + StackTraceElement[] trace = StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()); + for (StackTraceElement traceElement : trace) { + Bukkit.getLogger().warning("\tat " + traceElement); + } + } + + public static void dumpTraceForThread(String reason) { + final Throwable thr = new Throwable(reason); + StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr); + thr.printStackTrace(); + } + + public static void printStackTrace(Throwable thr) { + StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(thr); + thr.printStackTrace(); + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index e9391811dc..e5a534c3ca 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1051,6 +1051,7 @@ public final class CraftServer implements Server { plugin.getDescription().getFullName(), "This plugin is not properly shutting down its async tasks when it is being reloaded. This may cause conflicts with the newly loaded version of the plugin" )); + if (console.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread(worker.getThread(), "still running"); // Paper - Debugging } io.papermc.paper.plugin.PluginInitializerManager.reload(this.console); // Paper this.loadPlugins();