参数解析
命令生成器(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 类的源码。