From 736c78c71ef86b9fe382cd151354f7b85c66cd52 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 29 Nov 2024 17:04:32 +0100 Subject: [PATCH] Copy dispatcher root children before passing it into async tree building --- .../server/Async-command-map-building.patch | 35 +++++++++++++++++-- .../server/Brigadier-based-command-API.patch | 10 +++--- ...y-type-tags-suggestions-in-selectors.patch | 4 +-- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/patches/server/Async-command-map-building.patch b/patches/server/Async-command-map-building.patch index e92905e614..b402a39439 100644 --- a/patches/server/Async-command-map-building.patch +++ b/patches/server/Async-command-map-building.patch @@ -17,7 +17,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start // Register Vanilla commands into builtRoot as before + // Paper start - Perf: Async command map building -+ COMMAND_SENDING_POOL.execute(() -> this.sendAsync(player)); ++ // Copy root children to avoid concurrent modification during building ++ final Collection> commandNodes = new java.util.ArrayList<>(this.dispatcher.getRoot().getChildren()); ++ COMMAND_SENDING_POOL.execute(() -> this.sendAsync(player, commandNodes)); + } + + public static final java.util.concurrent.ExecutorService COMMAND_SENDING_POOL = java.util.concurrent.Executors.newFixedThreadPool(2, @@ -27,12 +29,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + .build() + ); + -+ private void sendAsync(ServerPlayer player) { ++ private void sendAsync(ServerPlayer player, Collection> dispatcherRootChildren) { + // Paper end - Perf: Async command map building Map, CommandNode> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues RootCommandNode vanillaRoot = new RootCommandNode(); @@ -0,0 +0,0 @@ public class Commands { + RootCommandNode 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 bukkit = new LinkedHashSet<>(); for (CommandNode node : rootcommandnode.getChildren()) { bukkit.add(node.getName()); } @@ -47,6 +56,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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 tree, CommandNode result, CommandSourceStack source, Map, CommandNode> resultNodes) { +- Iterator iterator = tree.getChildren().iterator(); ++ // Paper start - Perf: Async command map building; pass copy of children ++ private void fillUsableCommands(Collection> children, CommandNode result, CommandSourceStack source, Map, CommandNode> resultNodes) { ++ Iterator iterator = children.iterator(); ++ // Paper end - Perf: Async command map building + + while (iterator.hasNext()) { + CommandNode 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 diff --git a/patches/server/Brigadier-based-command-API.patch b/patches/server/Brigadier-based-command-API.patch index 1c16b26585..a4b25ba490 100644 --- a/patches/server/Brigadier-based-command-API.patch +++ b/patches/server/Brigadier-based-command-API.patch @@ -2136,7 +2136,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (int i = 0; i < Math.min(astacktraceelement.length, 3); ++i) { @@ -0,0 +0,0 @@ public class Commands { - private void sendAsync(ServerPlayer player) { + private void sendAsync(ServerPlayer player, Collection> dispatcherRootChildren) { // Paper end - Perf: Async command map building Map, CommandNode> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues - RootCommandNode vanillaRoot = new RootCommandNode(); @@ -2151,13 +2151,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 map.put(this.dispatcher.getRoot(), rootcommandnode); @@ -0,0 +0,0 @@ public class Commands { - } - private void fillUsableCommands(CommandNode tree, CommandNode result, CommandSourceStack source, Map, CommandNode> resultNodes) { + // Paper start - Perf: Async command map building; pass copy of children + private void fillUsableCommands(Collection> children, CommandNode result, CommandSourceStack source, Map, CommandNode> resultNodes) { + resultNodes.keySet().removeIf((node) -> !org.spigotmc.SpigotConfig.sendNamespaced && node.getName().contains( ":" )); // Paper - Remove namedspaced from result nodes to prevent redirect trimming ~ see comment below - Iterator iterator = tree.getChildren().iterator(); + Iterator iterator = children.iterator(); + // Paper end - Perf: Async command map building - while (iterator.hasNext()) { @@ -0,0 +0,0 @@ public class Commands { if (commandnode2.canUse(source)) { diff --git a/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch b/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch index 9f8d1de9d9..3a81de94fe 100644 --- a/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch +++ b/patches/server/Fix-entity-type-tags-suggestions-in-selectors.patch @@ -41,8 +41,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 { - resultNodes.keySet().removeIf((node) -> !org.spigotmc.SpigotConfig.sendNamespaced && node.getName().contains( ":" )); // Paper - Remove namedspaced from result nodes to prevent redirect trimming ~ see comment below - Iterator iterator = tree.getChildren().iterator(); + Iterator iterator = children.iterator(); + // Paper end - Perf: Async command map building + boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments while (iterator.hasNext()) {