Copy dispatcher root children before passing it into async tree building

This commit is contained in:
Nassim Jahnke 2024-11-29 17:04:32 +01:00
parent 4a5ff5039c
commit 736c78c71e
3 changed files with 40 additions and 9 deletions

View file

@ -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<CommandNode<CommandSourceStack>> 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<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());
}
@ -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<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

View file

@ -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<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();
@ -2151,13 +2151,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
map.put(this.dispatcher.getRoot(), rootcommandnode);
@@ -0,0 +0,0 @@ public class Commands {
}
private void fillUsableCommands(CommandNode<CommandSourceStack> tree, CommandNode<SharedSuggestionProvider> result, CommandSourceStack source, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> resultNodes) {
// 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) {
+ 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)) {

View file

@ -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()) {