From a15152e96a0c1f8b8f6792f4308e8077e01614d2 Mon Sep 17 00:00:00 2001 From: Jason <11360596+jpenilla@users.noreply.github.com> Date: Sat, 6 Aug 2022 16:22:51 -0700 Subject: [PATCH] Allow old behavior for CommandRegisteredEvent (#8249) --- .../brigadier/BukkitBrigadierCommand.java | 5 + .../brigadier/CommandRegisteredEvent.java | 94 ++++++++++++++----- .../0298-Implement-Brigadier-Mojang-API.patch | 37 +++++++- ...-brigadier-child-sorting-performance.patch | 4 +- ...-Vanilla-Command-permission-checking.patch | 4 +- ...from-signs-not-firing-command-events.patch | 4 +- ...y-type-tags-suggestions-in-selectors.patch | 6 +- 7 files changed, 116 insertions(+), 38 deletions(-) diff --git a/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java b/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java index 3848933b6..0b1af3a8d 100644 --- a/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java +++ b/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/brigadier/BukkitBrigadierCommand.java @@ -5,5 +5,10 @@ import com.mojang.brigadier.suggestion.SuggestionProvider; import java.util.function.Predicate; +/** + * Brigadier {@link Command}, {@link SuggestionProvider}, and permission checker for Bukkit {@link Command}s. + * + * @param command source type + */ public interface BukkitBrigadierCommand extends Command, Predicate, SuggestionProvider { } diff --git a/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java b/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java index 7bfa71f15..b7e09256a 100644 --- a/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java +++ b/Paper-MojangAPI/src/main/java/com/destroystokyo/paper/event/brigadier/CommandRegisteredEvent.java @@ -13,18 +13,17 @@ import org.bukkit.event.server.ServerEvent; import org.jetbrains.annotations.NotNull; /** - * Fired anytime the server synchronizes Bukkit CommandMap to Brigadier. + * Fired anytime the server synchronizes Bukkit commands to Brigadier. * - * Allows a plugin to control the Literal and Argument nodes for this command to be - * sent to the client. - * This is done at Plugin Enable time after commands have been registered, but some - * plugins may use reflection to retrigger this rebuild during runtime. + * Allows a plugin to control the command node structure for its commands. + * This is done at Plugin Enable time after commands have been registered, but may also + * run at a later point in the server lifetime due to plugins, a server reload, etc. * * @deprecated Draft API - Subject to change until confirmed solves desired use cases */ @Deprecated @Warning(false) -public class CommandRegisteredEvent extends ServerEvent implements Cancellable { +public class CommandRegisteredEvent extends ServerEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final String commandLabel; @@ -33,6 +32,7 @@ public class CommandRegisteredEvent ext private final RootCommandNode root; private final ArgumentCommandNode defaultArgs; private LiteralCommandNode literal; + private boolean rawCommand = false; private boolean cancelled = false; public CommandRegisteredEvent(String commandLabel, BukkitBrigadierCommand brigadierCommand, Command command, RootCommandNode root, LiteralCommandNode literal, ArgumentCommandNode defaultArgs) { @@ -45,55 +45,99 @@ public class CommandRegisteredEvent ext } /** - * @return The command name being registered + * Gets the command label of the {@link Command} being registered. + * + * @return the command label */ public String getCommandLabel() { - return commandLabel; + return this.commandLabel; } /** - * @return The Bukkit API Brigadier Wrapped Command Object to handle executions and suggestions + * Gets the {@link BukkitBrigadierCommand} for the {@link Command} being registered. This can be used + * as the {@link com.mojang.brigadier.Command command executor} or + * {@link com.mojang.brigadier.suggestion.SuggestionProvider} of a {@link com.mojang.brigadier.tree.CommandNode} + * to delegate to the {@link Command} being registered. + * + * @return the {@link BukkitBrigadierCommand} */ public BukkitBrigadierCommand getBrigadierCommand() { - return brigadierCommand; - } - - public Command getCommand() { - return command; + return this.brigadierCommand; } /** - * @return Gets the root command node being used to register a command to. + * Gets the {@link Command} being registered. + * + * @return the {@link Command} + */ + public Command getCommand() { + return this.command; + } + + /** + * Gets the {@link RootCommandNode} which is being registered to. + * + * @return the {@link RootCommandNode} */ public RootCommandNode getRoot() { - return root; + return this.root; } /** - * Returns the Bukkit API's default handling of Arguments, if you wish to reuse it. - * @return + * Gets the Bukkit APIs default arguments node (greedy string), for if + * you wish to reuse it. + * + * @return default arguments node */ public ArgumentCommandNode getDefaultArgs() { - return defaultArgs; + return this.defaultArgs; } /** - * Returns the Bukkit API's default literal for this command, including the {@link #getDefaultArgs()} as a child already. - * @return + * Gets the {@link LiteralCommandNode} to be registered for the {@link Command}. + * + * @return the {@link LiteralCommandNode} */ public LiteralCommandNode getLiteral() { - return literal; + return this.literal; } /** - * Changes the literal used to register this command. The previous literable is mutable, so this is primarily if - * you want to completely replace the object. - * @param literal + * Sets the {@link LiteralCommandNode} used to register this command. The default literal is mutable, so + * this is primarily if you want to completely replace the object. + * + * @param literal new node */ public void setLiteral(LiteralCommandNode literal) { this.literal = literal; } + /** + * Gets whether this command should is treated as "raw". + * + * @see #setRawCommand(boolean) + * @return whether this command is treated as "raw" + */ + public boolean isRawCommand() { + return this.rawCommand; + } + + /** + * Sets whether this command should be treated as "raw". + * + *

A "raw" command will only use the node provided by this event for + * sending the command tree to the client. For execution purposes, the default + * greedy string execution of a standard Bukkit {@link Command} is used.

+ * + *

On older versions of Paper, this was the default and only behavior of this + * event.

+ * + * @param rawCommand whether this command should be treated as "raw" + */ + public void setRawCommand(final boolean rawCommand) { + this.rawCommand = rawCommand; + } + /** * {@inheritDoc} */ diff --git a/patches/server/0298-Implement-Brigadier-Mojang-API.patch b/patches/server/0298-Implement-Brigadier-Mojang-API.patch index c48ac178e..295727c04 100644 --- a/patches/server/0298-Implement-Brigadier-Mojang-API.patch +++ b/patches/server/0298-Implement-Brigadier-Mojang-API.patch @@ -21,6 +21,18 @@ index 6dbac0f93481256dd57e76630ae9eea9d5c56849..e260462933a9f7065b2360e6bf9e4ee5 // Paper start implementation("org.jline:jline-terminal-jansi:3.21.0") implementation("net.minecrell:terminalconsoleappender:1.3.0") +diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +index da6250df1c5f3385b683cffde47754bca4606f5e..3384501f83d445f45aa8233e98c7597daa67b8ef 100644 +--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java ++++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +@@ -34,6 +34,7 @@ public abstract class CommandNode implements Comparable> { + private final RedirectModifier modifier; + private final boolean forks; + private Command command; ++ public LiteralCommandNode clientNode = null; // Paper + // CraftBukkit start + public void removeCommand(String name) { + this.children.remove(name); diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java index a749ea8578fc8baeebd359e0275f1c3089beec13..981f08a537253516a6ce8b78f6cd04d7e5e1b546 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -62,7 +74,7 @@ index a749ea8578fc8baeebd359e0275f1c3089beec13..981f08a537253516a6ce8b78f6cd04d7 public boolean hasPermission(int level) { // CraftBukkit start diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 685e04b1f17938d49cd126bcfe2f488f21afbea2..54bf5558c9048c215aee518874f3d96ab473beb6 100644 +index 685e04b1f17938d49cd126bcfe2f488f21afbea2..d4e3dc8d67006dcff2a64d03c29ffc9414557017 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -385,6 +385,7 @@ public class Commands { @@ -81,8 +93,20 @@ index 685e04b1f17938d49cd126bcfe2f488f21afbea2..54bf5558c9048c215aee518874f3d96a PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit)); event.getPlayer().getServer().getPluginManager().callEvent(event); +@@ -410,6 +412,11 @@ public class Commands { + + while (iterator.hasNext()) { + CommandNode commandnode2 = (CommandNode) iterator.next(); ++ // Paper start ++ if (commandnode2.clientNode != null) { ++ commandnode2 = commandnode2.clientNode; ++ } ++ // Paper end + if ( !org.spigotmc.SpigotConfig.sendNamespaced && commandnode2.getName().contains( ":" ) ) continue; // Spigot + + if (commandnode2.canUse(source)) { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 88f58eeaf2566bdee2f6e44ddc1187f762345347..a033040751583270c9883652b2acb30c0d100e68 100644 +index c60baac35e4ae333971532ad2da6dd0925efc1a9..4f9adc601ccc84beaee91a6ca9d6cd2740c4416e 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -833,8 +833,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic @@ -116,7 +140,7 @@ index 88f58eeaf2566bdee2f6e44ddc1187f762345347..a033040751583270c9883652b2acb30c }); // Paper end - async tab completion diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java -index 83d81b9371902b0302d13e53b31c15fac4e67966..9e4a660bdeaa70536bd8aeb90aa4a6a979f3f061 100644 +index 83d81b9371902b0302d13e53b31c15fac4e67966..d113e54a30db16e2ad955170df6030d15de530d6 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java +++ b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java @@ -20,7 +20,7 @@ import org.bukkit.command.CommandException; @@ -128,7 +152,7 @@ index 83d81b9371902b0302d13e53b31c15fac4e67966..9e4a660bdeaa70536bd8aeb90aa4a6a9 private final CraftServer server; private final Command command; -@@ -31,10 +31,19 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command register(CommandDispatcher dispatcher, String label) { @@ -139,6 +163,7 @@ index 83d81b9371902b0302d13e53b31c15fac4e67966..9e4a660bdeaa70536bd8aeb90aa4a6a9 + // Paper start - Expose Brigadier to Paper-MojangAPI + com.mojang.brigadier.tree.RootCommandNode root = dispatcher.getRoot(); + LiteralCommandNode literal = LiteralArgumentBuilder.literal(label).requires(this).executes(this).build(); ++ LiteralCommandNode defaultNode = literal; + com.mojang.brigadier.tree.ArgumentCommandNode defaultArgs = RequiredArgumentBuilder.argument("args", StringArgumentType.greedyString()).suggests(this).executes(this).build(); + literal.addChild(defaultArgs); + com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent event = new com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent<>(label, this, this.command, root, literal, defaultArgs); @@ -146,6 +171,10 @@ index 83d81b9371902b0302d13e53b31c15fac4e67966..9e4a660bdeaa70536bd8aeb90aa4a6a9 + return null; + } + literal = event.getLiteral(); ++ if (event.isRawCommand()) { ++ defaultNode.clientNode = literal; ++ literal = defaultNode; ++ } + root.addChild(literal); + return literal; + // Paper end diff --git a/patches/server/0415-Optimize-brigadier-child-sorting-performance.patch b/patches/server/0415-Optimize-brigadier-child-sorting-performance.patch index 2d398241d..3651f34b1 100644 --- a/patches/server/0415-Optimize-brigadier-child-sorting-performance.patch +++ b/patches/server/0415-Optimize-brigadier-child-sorting-performance.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Optimize brigadier child sorting performance diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java -index da6250df1c5f3385b683cffde47754bca4606f5e..a4f97c1df86c574af9b9824a38034a3d76d6e357 100644 +index 3384501f83d445f45aa8233e98c7597daa67b8ef..20a7cdf87f307878d66922aaac0c60cff218e46c 100644 --- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java @@ -26,7 +26,7 @@ import java.util.function.Predicate; @@ -17,7 +17,7 @@ index da6250df1c5f3385b683cffde47754bca4606f5e..a4f97c1df86c574af9b9824a38034a3d private final Map> literals = new LinkedHashMap<>(); private final Map> arguments = new LinkedHashMap<>(); public Predicate requirement; -@@ -106,6 +106,8 @@ public abstract class CommandNode implements Comparable> { +@@ -107,6 +107,8 @@ public abstract class CommandNode implements Comparable> { this.arguments.put(node.getName(), (ArgumentCommandNode) node); } } diff --git a/patches/server/0466-Thread-Safe-Vanilla-Command-permission-checking.patch b/patches/server/0466-Thread-Safe-Vanilla-Command-permission-checking.patch index 8d25b8b50..9fcfe6080 100644 --- a/patches/server/0466-Thread-Safe-Vanilla-Command-permission-checking.patch +++ b/patches/server/0466-Thread-Safe-Vanilla-Command-permission-checking.patch @@ -9,10 +9,10 @@ to race conditions. Plus, .canUse we want to be safe for async anyways. diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java -index a4f97c1df86c574af9b9824a38034a3d76d6e357..d65defd5fc54086a969c568b93dfb05f40dd5a44 100644 +index 20a7cdf87f307878d66922aaac0c60cff218e46c..39844531b03eb8a6c70700b4ecbf0ff1a557424d 100644 --- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java +++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java -@@ -74,10 +74,10 @@ public abstract class CommandNode implements Comparable> { +@@ -75,10 +75,10 @@ public abstract class CommandNode implements Comparable> { public synchronized boolean canUse(final S source) { if (source instanceof CommandSourceStack) { try { diff --git a/patches/server/0675-Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/0675-Fix-commands-from-signs-not-firing-command-events.patch index db3b70bf7..c66c6d829 100644 --- a/patches/server/0675-Fix-commands-from-signs-not-firing-command-events.patch +++ b/patches/server/0675-Fix-commands-from-signs-not-firing-command-events.patch @@ -112,10 +112,10 @@ index 831db5ee21938d71e99bf9d17b92a6ca15531740..def4fdd2c7e4f925fa128692a744e5d1 public DyeColor getColor() { diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java -index 9e4a660bdeaa70536bd8aeb90aa4a6a979f3f061..2476727cd60034c4df2db36b9ed808e72d7b686f 100644 +index d113e54a30db16e2ad955170df6030d15de530d6..26f3a2799e687731d883e7733591f6934479e88d 100644 --- a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java +++ b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java -@@ -56,7 +56,7 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command commandnode2 = (CommandNode) iterator.next(); - if ( !org.spigotmc.SpigotConfig.sendNamespaced && commandnode2.getName().contains( ":" ) ) continue; // Spigot -@@ -443,6 +444,12 @@ public class Commands { + // Paper start +@@ -448,6 +449,12 @@ public class Commands { if (requiredargumentbuilder.getSuggestionsProvider() != null) { requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider()));