引數剖析
命令生成器(Command Builder)的 API 附带了一个非常强大的参数解析器。它把字符串输入转换为 Java 的基本类型(整数、布尔值、字符串)或游戏中的对象(玩家、世界、方块类型等)。这一解析器支持可选参数和标志,它同时也可以处理使用 TAB 的参数自动补全。
解析过的参数存储在 CommandContext 对象中。如果解析器返回了单个对象,可以通过 CommandContext#getOne(String) 获取。可选参数和弱参数可能会返回 Optional.empty()。
很多解析器可能会返回多个对象(例如匹配用户名的多个玩家)。在这种情况下,你必须使用 CommandContext#getAll(String) 以获取所有可能的匹配项对应的 Collection,否则上下文对象会抛出异常!
当创建命令时,应考虑某个参数是否可以有多个返回值,比如原本应该有玩家参数的地方是否可以用选择器来支持多个玩家。若如此做,玩家在使用这个命令的时候就可以只输入一条命令,并且语法看起来也会很简洁,比如:/tell @a Who took the cookies?
小訣竅
你可以使用 GenericArguments#onlyOne(CommandElement) 元素来限制参数的返回数量,这样你可以安全使用 args.<T>getOne(String)。但用户仍然会在尝试选择多个值的时候收到相应的提示。
若要创建一个新的 CommandElement (参数),请使用 GenericArguments 这一工厂类(Factory Class)。许多 CommandElement 都需要一段短文本用于显示帮助或错误信息。
使用 CommandSpec.Builder#arguments(CommandElement…) 把 CommandElement 应用到命令生成器上。这一方法可以传入多个 CommandElement ,这样就可以解析多个参数(例如 /msg <player> <msg> )。传入多个参数等价于使用 GenericArguments#seq(CommandElement…) 把多个参数包装起来。
範例:建立一個具有多個引數的指令
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");
對於 GenericArguments 指令元素的概述
指令元素  | 
說明  | 
值的型態與數量  | 
|---|---|---|
  | 
期望没有参数,这也是   | 
|
Java 基本型態  | 
||
  | 
期望一个表示字符串的参数。  | 
一個   | 
  | 
把所有剩余的参数使用空格连接起来(对于消息命令来说十分有用)。  | 
一個   | 
  | 
期望一个表示布尔值的参数。  | 
一個   | 
  | 
期望一个表示整数的参数。  | 
一個   | 
  | 
期望一个表示浮点数的参数。  | 
一個   | 
遊戲物件  | 
||
  | 
期望一个表示在线玩家的参数,并 可能返回多个玩家 !  | 
多個   | 
  | 
和   | 
多個   | 
  | 
和   | 
多個   | 
  | 
期望一个表示世界的参数(包括尚未加载的世界)。  | 
多個   | 
  | 
期望一个表示维度的参数(如   | 
多個   | 
  | 
期望一个表示坐标(   | 
一個   | 
  | 
期望一个表示坐标(   | 
一個   | 
  | 
期望一个表示特定 CatalogType 成员的参数。  | 
多个匹配特定索引类型(Catalog Type)的实例  | 
匹配器  | 
||
  | 
返回一个允许从一组特定的值中选定的参数。  | 
一个特定的值  | 
  | 
期望一个表示特定文本序列的参数(例如   | 
一个特定的值  | 
  | 
期望一个表示给定枚举类型的值的参数。  | 
多个匹配给定枚举的元素  | 
辅助元素 用于把若干命令元素包装起来。其值类型是从被包装元素继承的。  | 
||
  | 
生成一串命令元素的序列(例如   | 
繼承  | 
  | 
期望一个表示重复数次的命令元素。  | 
多個繼承  | 
  | 
期望所有剩余的参数匹配给定命令元素。  | 
多個繼承  | 
  | 
使给定的命令元素可选。如果参数的格式无效或并没有更多的参数,将抛出一个异常。  | 
繼承  | 
  | 
使给定的命令元素可选。如果参数的格式无效或并没有更多的参数,将不会抛出一个异常。  | 
繼承  | 
  | 
返回给定命令元素中第一个可解析的元素(对像是   | 
繼承  | 
  | 
限制给定命令元素,使其只允许在给定上下文插入仅仅一个。  | 
繼承  | 
  | 
返回一个标志(Flag)生成器(例如  請參閱 指令旗標  | 
短旗標(Short Flag):一個  長旗標(Long Flag):一個  數值旗標(Value Flag):繼承  | 
  | 
要求命令执行者拥有使用给定命令参数的特定权限  | 
繼承  | 
  | 
要求命令执行者拥有使用给定命令参数的特定权限,但在命令执行者没有权限时不会报错。  | 
繼承  | 
小訣竅
详见 GenericArguments 以获取更详细的信息。
警告
不要认为 CommandElement 只会有一个返回值,事实上他们当中很多都支持多重返回值,甚至有些还支持正则表达式或命令选择器。这样做是为了让命令系统更容易使用。例子:/tell @a BanditPlayer has the cookies!。如果你希望某个参数永远只有一个返回值,请使用 GenericArguments#onlyOne(CommandElement)。
自定義指令元素
可以通过继承 CommandElement 类创建自定义命令元素(如解析 URL 或者一个 Vector2i 元素)。
CommandElement#parseValue(CommandSource, CommandArgs) 方法需要通过 CommandArgs#next() 方法获取没有处理过的字符串并将其转换为一个对象(Object),如果转换出错,应抛出一个 ArgumentParseException 异常。
CommandElement#complete(CommandSource, CommandArgs, CommandContext) 方法应使用 CommandArgs#peek() 方法读取下一个未处理过的参数。其返回一个 TAB 自动补全的列表。
範例:Vector2i 指令元素定義
在这一示例中,解析器读取两个传入的参数并将其转换为一个 Vector2i 。
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>");
    }
}
範例:Vector2i 指令元素用法
// /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();
小訣竅
请参阅源代码以获取更多关于 GenericArguments 类的用法示例。
在自定義指令元素使用選擇器
Sponge 提供了解析选择器的支持,所以你可以在自定义元素中使用选择器。使用选择器需要走两步:解析(从字符串中构建出 Selector)和解释(根据选择器获得一个包含所有被选中的 Entity 的集合)。
解析选择器字符串需用到 Selector#parse(String) 方法,为此需要传入整个选择器字符串(包含 @)。该方法会返回可用于查询和解释的 Selector 对象。注意,如果传入的字符串不是合法的选择器字符串,该方法会抛出一个 IllegalArgumentException 异常。
请使用 Selector#resolve(CommandSource) 来解释该选择器,它将返回一个包含有该选择器匹配中的所有 Entity 的集合。
下面的 CommandElement 类的 parseValue 方法会尝试解析一个选择器,并根据 CommandSource 的位置返回一个实体的集合。若传入的字符串开头不是 @,会抛出一个异常告知目标字符串不是选择器。
@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."));
}
小訣竅
关于标准 Sponge 中的 CommandElements 中选择器解析的具体过程,可参阅 SelectorCommandElement 类的源码。