Análise de Argumentos

The Command Builder API comes with a powerful argument parser. It converts the string input to java base types (integers, booleans, strings) or game objects (players, worlds, block types, …). The parser supports optional arguments and flags. It also handles TAB completion of arguments.

The parsed arguments are stored in the CommandContext object. If the parser returns a single object, obtain it with CommandContext#getOne(String). Optional and weak arguments may return Optional.empty().

Many of the parsers may return more than one object (e.g. multiple players with a matching username). In that case, you must use the CommandContext#getAll(String) method to get the Collection of possible matches. Otherwise, the context object will throw an exception!

When creating a command, consider whether the argument could return multiple values, for example, whether a player argument could support multiple players when using a selector. If you support multiple values the users need to type only one command and can use an easier command syntax. Example: /tell @a Who took the cookies?

Dica

You can use the GenericArguments#onlyOne(CommandElement) element to restrict the amount of returned values to a single one, so you can safely use args.<T>getOne(String). However the user will still get a message, if they try to select more than one value.

To create a new CommandElement (argument), use the GenericArguments factory class. Many command elements require a short text key, which is displayed in error and help messages.

Apply the CommandElement to the command builder with the CommandSpec.Builder#arguments(CommandElement…) method. It is possible to pass more than one CommandElement to the method, thus chaining multiple arguments (e.g. /msg <player> <msg>). This has the same effect as wrapping the CommandElement objects in a GenericArguments#seq(CommandElement…) element.

Example: Building a Command with Multiple Arguments

import org.spongepowered.api.Sponge;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.args.CommandContext;
import org.spongepowered.api.command.args.GenericArguments;
import org.spongepowered.api.command.spec.CommandExecutor;
import org.spongepowered.api.command.spec.CommandSpec;

PluginContainer plugin = ...;

CommandSpec myCommandSpec = CommandSpec.builder()
        .description(Text.of("Send a message to a player"))
        .permission("myplugin.command.message")

        .arguments(
                GenericArguments.onlyOne(GenericArguments.player(Text.of("player"))),
                GenericArguments.remainingJoinedStrings(Text.of("message")))

        .executor((CommandSource src, CommandContext args) -> {

            Player player = args.<Player>getOne("player").get();
            String message = args.<String>getOne("message").get();

            player.sendMessage(Text.of(message));

            return CommandResult.success();
        })
        .build();

Sponge.getCommandManager().register(plugin, myCommandSpec, "message", "msg", "m");

Overview of the GenericArguments command elements

Elemento do Comando

Descrição

Value Type & Amount

none

Expects no arguments. This is the default behavior of a CommandSpec.

Tipos Base do Java

string

Exige que um argumento seja uma string.

uma String

remainingJoinedStrings

Concatena todos os argumentos restantes separados por espaços (útil para comandos de mensagem).

uma String

bool

Exige que um argumento seja um booleano.

um Boolean

integer

Exige que um argumento seja um inteiro.

um Integer

doubleNum

Exige que um argumento seja um número de ponto flutuante de precisão dupla.

um Double

Objetos do Jogo

player

Exige que um argumento represente um jogador online. Pode retornar múltiplos jogadores!

múltiplas instâncias de Player

playerOrSource

Similar ao player, mas retorna o remetente do comando se nenhum jogador correspondente foi encontrado.

múltiplas instâncias de Player

userOrSource

Similar ao playerOrSource, mas retorna um usuário ao invés de um jogador.

múltiplas instâncias de User

world

Exige que um argumento represente um mundo (também inclui mundos não carregados).

múltiplas WorldProperties

dimension

Exige que um argumento represente uma dimensão (END, NETHER, OVERWORLD).

múltiplas instâncias de DimensionType

location

Exige que um argumento represente uma Location.

uma Location

vector3d

Exige que um argumento represente um Vector3d.

um Vector3d

catalogedElement

Expect an argument that is a member of the specified CatalogType.

multiple matching elements of the specified catalog type

Matchers

choices

Retorna um argumento que permite selecionar de um limitado conjunto de valores.

um valor específico

literal

Exige que uma sequência de argumentos (ex.: "eu", "te", "amo": /cmd eu te amo). Lança uma exceção se os argumentos não combinam.

um valor específico

enumValue

Exige que o argumento seja uma chave de uma enumeração provida.

multiple matching elements of the specified enum

Utilidades

Can be wrapped around command elements. The value type is inherited from the wrapped element.

seq

Builds a sequence of command elements (e.g. /cmd <arg1> <arg2> <arg3>).

inherited

repeated

Exige que um comando dado seja provido em um certo número de vezes.

múltiplo herdado

allOf

Exige que todos os argumentos restantes para combinar o elemento de comando provido.

múltiplo herdado

optional

Faz o elemento de comando provido ser opcional. Lança um erro se o argumento provido é de um formato inválido e não há mais argumentos.

inherited

optionalWeak

Faz o elemento de comando provido ser opcional. Não lança um erro se o argumento provido é de um formato inválido e não há mais argumentos.

inherited

firstParsing

Returns a command element that matches the first of the provided elements that parses (useful for command overloading, e.g. /settime <day|night|<number>).

inherited

onlyOne

Restricts the given command element to only insert one value into the context at the provided key.

inherited

flags

Returns a builder for command flags (e.g. /cmd [-a] [-b <value>]).

See Command Flags

Short Flag: one Boolean

Long Flag: one String

Value Flag: inherited

requiringPermission

Requires the command sender to have the specified permission in order to use the given command argument

inherited

requiringPermissionWeak

Requires the command sender to have the specified permission in order to use the given command argument. Does not throw an error if the user does not have the permission.

inherited

Dica

See the Javadocs for GenericArguments for more information.

Aviso

Don’t expect that a CommandElements will only ever return a single value, a lot of them support multiple return values; some might even support regular expressions or use a command selector. This is intentional as it makes commands easier to use. Example: /tell @a BanditPlayer has the cookies!. If you want to make sure to only get a single value use GenericArguments#onlyOne(CommandElement).

Custom Command Elements

It is possible to create custom command elements (e.g. a URL parser or a Vector2i element) by extending the abstract CommandElement class.

The CommandElement#parseValue(CommandSource, CommandArgs) method should fetch a raw argument string with CommandArgs#next() and convert it to an object. The method should throw an ArgumentParseException if the parsing fails.

The CommandElement#complete(CommandSource, CommandArgs, CommandContext) method should use CommandArgs#peek() to read the next raw argument. It returns a list of suggestions for TAB completion.

Example: Vector2i command element definition

The parser in this example reads two input arguments and converts them to a vector.

import com.flowpowered.math.vector.Vector2i;
import org.spongepowered.api.command.args.ArgumentParseException;
import org.spongepowered.api.command.args.CommandArgs;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.command.args.CommandElement;

import java.util.Collections;
import java.util.List;

public class Vector2iCommandElement extends CommandElement {

    protected Vector2iCommandElement(Text key) {
        super(key);
    }

    @Override
    protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {

        String xInput = args.next();
        int x = parseInt(xInput, args);

        String yInput = args.next();
        int y = parseInt(yInput, args);

        return new Vector2i(x, y);
    }

    private int parseInt(String input, CommandArgs args) throws ArgumentParseException {
        try {
            return Integer.parseInt(input);
        } catch(NumberFormatException e) {
            throw args.createError(Text.of("'" + input + "' is not a valid number!"));
        }
    }

    @Override
    public List<String> complete(CommandSource src, CommandArgs args, CommandContext context) {
        return Collections.emptyList();
    }

    @Override
    public Text getUsage(CommandSource src) {
        return Text.of("<x> <y>");
    }
}

Example: Vector2i command element usage

// /plottp <x> <y>
CommandSpec myCommandSpec = CommandSpec.builder()
        .description(Text.of("Teleport to a plot"))
        .permission("myplugin.command.plot.tp")

        .arguments(new Vector2iCommandElement(Text.of("coordinates")))

        .executor(new MyCommandExecutor())
        .build();

Dica

Look at the source code of the GenericArguments class for more examples.

Using Selectors in Custom Command Elements

Sponge provides support for parsing selectors, meaning that you can make use of them in your custom elements. There are two steps in using selectors, parsing (getting a Selector from the string) and resolving (getting a set of Entity objects selected by the selector).

To parse a selector string, use the Selector#parse(String) method, passing the entire selector, including the @ symbol. This will turn the string into a Selector object that can be queried or resolved. Note that if the string is not a valid selector, an IllegalArgumentException will be thrown.

To resolve this selector, use Selector#resolve(CommandSource). This will return a set of Entity objects selected by the selector.

The following parseValue method from the CommandElement class attempts to parse a selector and return a set of entities based on the location of the CommandSource. If the passed string does not start with @, an exception will be thrown indicating that the passed argument is not a selector.

@Override
protected Object parseValue(CommandSource source, CommandArgs args) throws ArgumentParseException {
    String nextArg = args.next();
    if (nextArg.startsWith("@")) {
        Set<Entity> selectedEntities;
        try {
            selectedEntities = Selector.parse(nextArg).resolve(source);
        } catch (IllegalArgumentException e) {
            throw args.createError(Text.of("Could not parse selector."));
        }

        if (selectedEntities.isEmpty()) {
            throw args.createError(Text.of("No entities selected."));
        }

        return selectedEntities;
    }

    throw args.createError(Text.of("Not a selector."));
}

Dica

Look at the SelectorCommandElement source code for an example of how selector parsing is performed in the standard Sponge CommandElements.