New command API#330
Conversation
|
Alright, here's some usage examples: import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;
import static com.velocitypowered.api.command.BrigadierCommand.argumentBuilder;
import com.google.inject.Inject;
import com.mojang.brigadier.CommandDispatcher;
import com.velocitypowered.api.command.BrigadierCommand;
import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.LegacyCommand;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.TextComponent;
@Plugin(id = "test-plugin")
public class TestPlugin {
private final ProxyServer server;
@Inject
public TestPlugin(final ProxyServer server) {
this.server = server;
}
@Subscribe
public void onProxyInitialization(final ProxyInitializeEvent event) {
CommandManager commandManager = server.getCommandManager();
BrigadierCommand command = commandManager.brigadierBuilder().register(
argumentBuilder("foo")
.then(argument("bar", integer()))
.executes(c -> {
System.out.println("Bar is " + getInteger(c, "bar"));
return 1;
})
.executes(c -> {
System.out.println("Called foo with no arguments");
return 1;
})
);
LegacyCommand legacyCommand = commandManager.legacyBuilder().register(context -> {
CommandSource source = context.source();
String[] arguments = context.arguments();
source.sendMessage(TextComponent.of("foo"));
});
}
} |
The main concern is the context type parameter added to the Command interface. According to https://wiki.eclipse.org/Evolving_Java-based_APIs_2#Evolving_API_interfaces_-_API_methods this is binary compatible due to Java's handling of raw types. Also adds back the CommandManager#register methods.
|
I reached a middle ground so current plugins can still directly register commands while adding a fluent command builder some may prefer (not many? do we even need it?). |
|
My API compatibility concerns are assuaged for now. In 2.0.0 we'll just outright force the explicit use of |
Is there a better name for this?
|
|
|
For the sake of conventions and consistency with the rest of the API, methods should start with a verb. I think |
|
It's common for immutable classes with getter accessors. See https://stackoverflow.com/a/1680515/4514467 for a more in depth answer. |
Registration not yet implemented. Removes the legacy builder, users can directly implement LegacyCommand as they do right now with the Command interface.
Also fixes the redirect issue by cloning the entire children tree. Compression should make the increased packet size negligible.
|
Alright, tested execution, tab complete and permission checks on 1.12.2, 1.16.1 and the console and everything looks fine. This is now ready for review.
We now clone the entire children tree on redirect, no matter what. |
|
Just to clarify your comment opening this to further review, the Brigadier |
- Fixes CommandManager API-breakage (leftover from the Velocity 2.0 merge intention) - Clarify BrigadierCommand.Builder#permission javadoc (still subject to be removed) - Correct execute return when the source doesn't have permission or a syntax error is made. This follows the #execute javadoc. Under this definition, a Brigadier command with a syntax error is not executed. The legacy behavior is preserved. - Revert git executable path
Avoids the horrible overengineered wrapping logic. Also preserves the previous logic of forwarding a #requires false return to the backend server. Also fixes sending suggestions the client doesn't have permission for.
Hinting allows non-Brigadier commands to provide LiteralCommandNodes and ArgumentCommandNodes that are only used to provide additional argument metadata and tab-complete suggestions. Note that the Brigadier Command of a hinting command node or any of its children is ignored, and will instead call the regular "legacy wrapper" arguments command (see BrigadierUtils#buildRawArgumentsLiteral). While introducing this feature I also noticed the manager doesn't keep track of registered Command instances. As noted before, this is correct as the Command interface is now a dummy transformer. However, hinting requires modifying **all** the aliases of a Command, so I introduced the CommandMeta interface, which keeps track of the aliases and hinting data for now. This commit also introduces new CommandManager#register methods that accept a CommandMeta object. The Command.Builder and BrigadierCommand.Builder interfaces became useless with this introduction, so I also removed them and made BrigadierCommand a final class that accepts the LiteralCommandNode instead.
astei
left a comment
There was a problem hiding this comment.
Going to look for some more eyes on this but LGTM
|
Without any further comments left to make here, I will merge this in. Thanks for your contribution @hugmanrique, it is greatly appreciated. |
|
That's huge, congrats @hugmanrique. Looks like a great implementation! |
Introduces a new command framework that supports both legacy
String[] argscommands and 1.13+ Brigadier commands.As discussed in #329 (comment) and #232, the current command framework lacks support for new command features. This PR adds 3 subinterfaces to
Command:BrigadierCommand,LegacyCommandandRawCommand. All execution-related methods such asexecuteandhasPermissionnow take a singleCommandInvocationargument that includes the command source and additional execution metadata such as theString[] argsfor legacy commands.TODO:
CommandExecutionContext,CommandContextandCommandInvocation