From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 19 Apr 2020 18:15:29 -0400 Subject: [PATCH] Brigadier Mojang API Adds AsyncPlayerSendCommandsEvent - Allows modifying on a per command basis what command data they see. Adds CommandRegisteredEvent - Allows manipulating the CommandNode to add more children/metadata for the client diff --git a/build.gradle.kts b/build.gradle.kts index 30edfbf16e7bed29b3261b51d9e4f3124beef026..eaaf9a9779f57ee048245899750bf7a1599b716f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,6 +14,7 @@ val alsoShade: Configuration by configurations.creating dependencies { implementation(project(":paper-api")) + implementation(project(":paper-mojangapi")) // 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/exceptions/CommandSyntaxException.java b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java index 3370731ee064d2693b972a0765c13dd4fd69f66a..09d486a05179b9d878e1c33725b4e614c3544da9 100644 --- a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java +++ b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java @@ -5,7 +5,7 @@ package com.mojang.brigadier.exceptions; import com.mojang.brigadier.Message; -public class CommandSyntaxException extends Exception { +public class CommandSyntaxException extends Exception implements net.kyori.adventure.util.ComponentMessageThrowable { // Paper - Brigadier API public static final int CONTEXT_AMOUNT = 10; public static boolean ENABLE_COMMAND_STACK_TRACES = true; public static BuiltInExceptionProvider BUILT_IN_EXCEPTIONS = new BuiltInExceptions(); @@ -73,4 +73,11 @@ public class CommandSyntaxException extends Exception { public int getCursor() { return cursor; } + + // Paper start - Brigadier API + @Override + public @org.jetbrains.annotations.Nullable net.kyori.adventure.text.Component componentMessage() { + return io.papermc.paper.brigadier.PaperBrigadier.componentFromMessage(this.message); + } + // Paper end - Brigadier API } diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java index da6250df1c5f3385b683cffde47754bca4606f5e..d8142624f9f3a5909e7cc5665f1629a1a67dd302 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; // Paper - Brigadier API // 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 edf49f2d9921b4517fb98929d842f7a62c5549df..0f98345f8adc6e9bf7fb2dc9ce4eba59a33ded61 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -45,7 +45,7 @@ import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import com.mojang.brigadier.tree.CommandNode; // CraftBukkit -public class CommandSourceStack implements ExecutionCommandSource, SharedSuggestionProvider { +public class CommandSourceStack implements ExecutionCommandSource, SharedSuggestionProvider, com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource { // Paper - Brigadier API public static final SimpleCommandExceptionType ERROR_NOT_PLAYER = new SimpleCommandExceptionType(Component.translatable("permissions.requires.player")); public static final SimpleCommandExceptionType ERROR_NOT_ENTITY = new SimpleCommandExceptionType(Component.translatable("permissions.requires.entity")); @@ -170,6 +170,26 @@ public class CommandSourceStack implements ExecutionCommandSource(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API net.minecraft.server.MinecraftServer.getServer().execute(() -> { runSync(player, bukkit, rootcommandnode); }); @@ -500,6 +501,7 @@ public class Commands { private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { // Paper end - Perf: Async command map building + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit)); event.getPlayer().getServer().getPluginManager().callEvent(event); @@ -518,6 +520,11 @@ public class Commands { while (iterator.hasNext()) { CommandNode commandnode2 = (CommandNode) iterator.next(); + // Paper start - Brigadier API + if (commandnode2.clientNode != null) { + commandnode2 = commandnode2.clientNode; + } + // Paper end - Brigadier API 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 2a49c02ad4baccc1fe3b0b69da0e584b7efec3ee..eb62f5f1a0dc0f7cd49d54af7f4899e94afc95ee 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -746,7 +746,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip())); } } - this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join())); + // Paper start - Brigadier API + com.mojang.brigadier.suggestion.Suggestions suggestions = builder.buildFuture().join(); + com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); + suggestEvent.setCancelled(suggestions.isEmpty()); + if (suggestEvent.callEvent()) { + this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); + } + // Paper end - Brigadier API } } @@ -755,8 +762,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { - if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [] from showing for plugins with nothing more to offer - this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions)); + // Paper start - Brigadier API + com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent suggestEvent = new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendSuggestionsEvent(this.getCraftPlayer(), suggestions, packet.getCommand()); + suggestEvent.setCancelled(suggestions.isEmpty()); + if (suggestEvent.callEvent()) { + this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); + } + // Paper end - Brigadier API }); } diff --git a/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/BukkitCommandWrapper.java 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; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftServer; -public class BukkitCommandWrapper implements com.mojang.brigadier.Command, Predicate, SuggestionProvider { +public class BukkitCommandWrapper implements com.mojang.brigadier.Command, Predicate, SuggestionProvider, com.destroystokyo.paper.brigadier.BukkitBrigadierCommand { // Paper private final CraftServer server; private final Command command; @@ -31,10 +31,24 @@ public class BukkitCommandWrapper implements com.mojang.brigadier.Command register(CommandDispatcher dispatcher, String label) { - return dispatcher.register( - LiteralArgumentBuilder.literal(label).requires(this).executes(this) - .then(RequiredArgumentBuilder.argument("args", StringArgumentType.greedyString()).suggests(this).executes(this)) - ); + // 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); + if (!event.callEvent()) { + return null; + } + literal = event.getLiteral(); + if (event.isRawCommand()) { + defaultNode.clientNode = literal; + literal = defaultNode; + } + root.addChild(literal); + return literal; + // Paper end } @Override