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 6dbac0f93481256dd57e76630ae9eea9d5c56849..e260462933a9f7065b2360e6bf9e4ee56069a705 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,7 @@ plugins { 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/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 +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -39,7 +39,7 @@ import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import com.mojang.brigadier.tree.CommandNode; // CraftBukkit -public class CommandSourceStack implements SharedSuggestionProvider { +public class CommandSourceStack implements 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")); @@ -172,6 +172,26 @@ public class CommandSourceStack implements SharedSuggestionProvider { return this.entity != null ? this.entity.asChatSender() : ChatSender.SYSTEM; } + // Paper start + @Override + public org.bukkit.entity.Entity getBukkitEntity() { + return getEntity() != null ? getEntity().getBukkitEntity() : null; + } + + @Override + public org.bukkit.World getBukkitWorld() { + return getLevel() != null ? getLevel().getWorld() : null; + } + + @Override + public org.bukkit.Location getBukkitLocation() { + Vec3 pos = getPosition(); + org.bukkit.World world = getBukkitWorld(); + Vec2 rot = getRotation(); + return world != null && pos != null ? new org.bukkit.Location(world, pos.x, pos.y, pos.z, rot != null ? rot.x : 0, rot != null ? rot.y : 0) : null; + } + // Paper end + @Override 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..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 { bukkit.add(node.getName()); } // Paper start - Async command map building + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper MinecraftServer.getServer().execute(() -> { runSync(player, bukkit, rootcommandnode); }); @@ -392,6 +393,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); @@ -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 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 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 }); }); } @@ -849,7 +853,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 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