PaperMC/patches/unapplied/server/Async-command-map-building.patch
2024-12-03 17:58:41 +01:00

96 lines
5.9 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Callahan <mr.callahhh@gmail.com>
Date: Wed, 8 Apr 2020 02:42:14 -0500
Subject: [PATCH] Async command map building
This adds a custom pool inorder to make sure that they are closed
without much though, as it doesn't matter if the client is not sent
commands if the server is restarting. Using the default async pool caused issues to arise
due to the shutdown logic generally being much later.
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/commands/Commands.java
+++ b/src/main/java/net/minecraft/commands/Commands.java
@@ -0,0 +0,0 @@ public class Commands {
if ( org.spigotmc.SpigotConfig.tabComplete < 0 ) return; // Spigot
// CraftBukkit start
// Register Vanilla commands into builtRoot as before
+ // Paper start - Perf: Async command map building
+ // Copy root children to avoid concurrent modification during building
+ final Collection<CommandNode<CommandSourceStack>> commandNodes = new java.util.ArrayList<>(this.dispatcher.getRoot().getChildren());
+ COMMAND_SENDING_POOL.execute(() -> this.sendAsync(player, commandNodes));
+ }
+
+ // Fixed pool, but with discard policy
+ public static final java.util.concurrent.ExecutorService COMMAND_SENDING_POOL = new java.util.concurrent.ThreadPoolExecutor(
+ 2, 2, 0, java.util.concurrent.TimeUnit.MILLISECONDS,
+ new java.util.concurrent.LinkedBlockingQueue<>(),
+ new com.google.common.util.concurrent.ThreadFactoryBuilder()
+ .setNameFormat("Paper Async Command Builder Thread Pool - %1$d")
+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER))
+ .build(),
+ new java.util.concurrent.ThreadPoolExecutor.DiscardPolicy()
+ );
+
+ private void sendAsync(ServerPlayer player, Collection<CommandNode<CommandSourceStack>> dispatcherRootChildren) {
+ // Paper end - Perf: Async command map building
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues
RootCommandNode vanillaRoot = new RootCommandNode();
@@ -0,0 +0,0 @@ public class Commands {
RootCommandNode<SharedSuggestionProvider> rootcommandnode = new RootCommandNode();
map.put(this.dispatcher.getRoot(), rootcommandnode);
- this.fillUsableCommands(this.dispatcher.getRoot(), rootcommandnode, player.createCommandSourceStack(), map);
+ this.fillUsableCommands(dispatcherRootChildren, rootcommandnode, player.createCommandSourceStack(), map); // Paper - Perf: Async command map building; pass copy of children
Collection<String> bukkit = new LinkedHashSet<>();
for (CommandNode node : rootcommandnode.getChildren()) {
bukkit.add(node.getName());
}
+ // Paper start - Perf: Async command map building
+ net.minecraft.server.MinecraftServer.getServer().execute(() -> {
+ runSync(player, bukkit, rootcommandnode);
+ });
+ }
+ private void runSync(ServerPlayer player, Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootcommandnode) {
+ // Paper end - Perf: Async command map building
PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
event.getPlayer().getServer().getPluginManager().callEvent(event);
@@ -0,0 +0,0 @@ public class Commands {
player.connection.send(new ClientboundCommandsPacket(rootcommandnode));
}
- private void fillUsableCommands(CommandNode<CommandSourceStack> tree, CommandNode<SharedSuggestionProvider> result, CommandSourceStack source, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> resultNodes) {
- Iterator iterator = tree.getChildren().iterator();
+ // Paper start - Perf: Async command map building; pass copy of children
+ private void fillUsableCommands(Collection<CommandNode<CommandSourceStack>> children, CommandNode<SharedSuggestionProvider> result, CommandSourceStack source, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> resultNodes) {
+ Iterator iterator = children.iterator();
+ // Paper end - Perf: Async command map building
while (iterator.hasNext()) {
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
@@ -0,0 +0,0 @@ public class Commands {
resultNodes.put(commandnode2, commandnode3);
result.addChild(commandnode3);
if (!commandnode2.getChildren().isEmpty()) {
- this.fillUsableCommands(commandnode2, commandnode3, source, resultNodes);
+ this.fillUsableCommands(commandnode2.getChildren(), commandnode3, source, resultNodes); // Paper - Perf: Async command map building; pass children directly
}
}
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
MinecraftServer.LOGGER.info("Stopping server");
+ Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
// CraftBukkit start
if (this.server != null) {
this.server.disablePlugins();