From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 19 Apr 2020 18:15:29 -0400 Subject: [PATCH] Implement 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 4b4aa6cc48abb6a2d31c2043e0eff25bca0d05b3..5fff9ffbede42644dc3639e9e0a31866981fa596 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..614eba6cc55d1eb7755cac35c671cb6f6cacca13 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 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 + @Override + public @org.jetbrains.annotations.Nullable net.kyori.adventure.text.Component componentMessage() { + return io.papermc.paper.brigadier.PaperBrigadier.componentFromMessage(this.message); + } + // Paper end } 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 ae7be8678ab2859b8eb5e04bc31d76271a74c66b..75b7b3cf90d1d67203ae19dc3302f06a57470f92 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 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 net.minecraft.server.MinecraftServer.getServer().execute(() -> { runSync(player, bukkit, rootcommandnode); }); @@ -501,6 +502,7 @@ public class Commands { private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { // Paper end - Async command map building + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit)); event.getPlayer().getServer().getPluginManager().callEvent(event); @@ -519,6 +521,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 efbc8236b148e3a194125d0ccfbd215a8cc8455a..e4073e8287952e1528dd855c79987a1677f921dd 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -743,8 +743,12 @@ 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.connection.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, command); + suggestEvent.setCancelled(suggestions.isEmpty()); + if (!suggestEvent.callEvent()) return; + this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); + // Paper end - Brigadier API }); }); } @@ -759,7 +763,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl builder.suggest(completion.suggestion(), PaperAdventure.asVanilla(completion.tooltip())); } }); - player.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, command); + suggestEvent.setCancelled(suggestions.isEmpty()); + if (!suggestEvent.callEvent()) return; + this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestEvent.getSuggestions())); + // Paper end - Brigadier API } }); // 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..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