Skip to content

Using Chimera Commands

Matthias Ngeo edited this page Apr 9, 2019 · 41 revisions

Creating a Command

A command can be either a Literal (recommended) or LiteralCommandNode. Both represent a literal command that can contain any number of subcommands and arguments. For brevity sake, only Literal is used in the example below.

Literal is a Chimera exclusive LiteralCommandNode subclass that supports aliases, optional children and modification of otherwise non-modifiable fields.

A Literal can be built using a builder created using either Literal.of(name) or the more verbose Literal.<CommandSender>builder(name).

import com.karuslabs.commons.command.tree.nodes.Literal;

Literal<CommandSender> tell = Literal.of("tell").alias("t")
                                     .then(arguments) // covered in the next section
                                     .build();

Creating an Argument

An argument can be either an Argument (recommended) or ArgumentCommandNode. Both represent a variable argument that can be parsed into a type based on its ArgumentType.

Argument is a Chimera exclusive ArgumentCommandNode subclass that supports aliases, optional children and modification of otherwise non-modifiable fields.

An Argument can be built using a builder created using either Argument.of(name, type) or the more verbose Argument.<CommandSender>builder(name, type).

In this example, we will create two arguments using different inbuilt ArgumentTypes. Inbuilt types provided by Chimera provide suggestions by default. Creating a custom ArgumentType is beyond the scope of this guide. For brevity sake, only Argument is used in the example below.

import com.karuslabs.commons.command.tree.nodes.Argument;
import com.karuslabs.commons.command.types.PlayersType;

import com.mojang.brigadier.arguments.StringArgumentType;

Argument.Builder<CommandSender, List<Player>> players = Argument.of("players", new PlayersType()); // Inbuilt players type provided by Chimera

Argument.Builder<CommandSender, String> message = Argument.of("message", StringArgumentType.string()) // Inbuilt string type provided by Mojang
                                                          .suggests((context, builder) -> builder.suggest("\"Hello World!\"").buildFuture());
        
Argument<CommandSender, List<Player>> arguments = players.then(message).build(); // Chains player and message

Adding Behaviour to a Command and Argument

The commands created in the previous sections will not do nothing if executed as we did not define any behaviour for them. Behaviour can be attached to the commands using either Executable<T> (recommended) or Command<T>.

Executable<T> is a Chimera exclusive Command<T> subinterface that supports optional arguments and returns an integer indicating success.

A Executable<T> or Command<T> of the last command or argument will be always be executed, i.e. if the user entered "a b c", c will be executed. Given the same commands and if the user entered "a b" instead, b will be executed.

In this examples, we edit the code snippets from the previous sections to attach an Executable<CommandSender>.

import com.karuslabs.commons.command.Executable;
        

Literal<CommandSender> tell = Literal.of("tell").alias("t")
                                     .executes(context -> context.getSource().sendMessage("Hello darkness my old friend")) // <-- Add this
                                     .then(message)
                                     .build();

Argument.Builder<CommandSender, List<Player>> players = Argument.of("players", new PlayersType());
Argument.Builder<CommandSender, String> message = Argument.of("message", StringArgumentType.string())
                                                          .executes(context -> { // <-- Add this
                                                              CommandSender sender = context.getSource();
                                                              List<Player> recipents = context.getArgument("players", List.class);
                                                              String entered = context.getArgument("message", String.class);   
                                                              
                                                              recipents.forEach(p -> p.sendMessage(sender + " says: " + entered));
                                                           })
                                                          .suggests((context, builder) -> builder.suggest("\"Hello World!\"").buildFuture());

Registering the Command

After creating a command, its arguments and attaching behaviour to it, the command must be registered to a Dispatcher. A Dispatcher is the entry point of the framework to which commands are registered.

Registered commands are not immediately available if registered after YourPlugin.onLoad() and YourPlugin.onEnable(). In such cases, Dispatcher.update() must be manually called.

import com.karuslabs.commons.command.Dispatcher;

Dispatcher dispatcher = Dispatcher.of(yourPlugin);
dispatcher.getRoot().addChild(tell);
dispatcher.update(); // Only needed if we added "tell" after YourPlugin.onLoad() and YourPlugin.onEnable() has been called.

Putting Everything Together

After finishing this guide, the tell command should look something like this.

import com.karuslabs.commons.command.Dispatcher;
import com.karuslabs.commons.command.Executable;
import com.karuslabs.commons.command.tree.nodes.Literal;
import com.karuslabs.commons.command.tree.nodes.Argument;
import com.karuslabs.commons.command.types.PlayersType;
import com.mojang.brigadier.arguments.StringArgumentType;        
            
Argument.Builder<CommandSender, List<Player>> players = Argument.of("players", new PlayersType()); // Inbuilt players type provided by Chimera
Argument.Builder<CommandSender, String> message = Argument.of("message", StringArgumentType.string()) // Inbuilt string type provided by Mojang
                                                          .executes(context -> { 
                                                              CommandSender sender = context.getSource();
                                                              List<Player> recipents = context.getArgument("players", List.class);
                                                              String entered = context.getArgument("message", String.class);   
                                                              
                                                              recipents.forEach(p -> p.sendMessage(sender.getName() + " says: " + entered));
                                                           })
                                                          .suggests((context, builder) -> builder.suggest("\"Hello World!\"").buildFuture());
        
Argument<CommandSender, List<Player>> arguments = players.then(message).build();

Literal<CommandSender> tell = Literal.of("tell").alias("t")
                                     .executes(context -> context.getSource().sendMessage("Hello darkness my old friend"))
                                     .then(arguments)
                                     .build();

Dispatcher dispatcher = Dispatcher.of(yourPlugin);
dispatcher.getRoot().addChild(tell);
dispatcher.update(); // Only needed if we added "tell" after YourPlugin.onLoad() and YourPlugin.onEnable() has been called.

Further Reference

Clone this wiki locally