子命令

CommandSpec Builder 支持使用分层命令结构,就像下面这样:

  • /mail (父命令)
    • /mail send (子命令)
    • /mail read (子命令)

所有的子命令都有着单独的 CommandSpec ,并且可以像一个正常的命令一样去创建。

import org.spongepowered.api.text.Text;
import org.spongepowered.api.command.spec.CommandSpec;

// /mail read
CommandSpec readCmd = CommandSpec.builder()
    .permission("myplugin.mail.read")
    .description(Text.of("Read your inbox"))
    .executor(...)
    .build();

// /mail send
CommandSpec sendCmd = CommandSpec.builder()
    .permission("myplugin.mail.send")
    .description(Text.of("Send a mail"))
    .arguments(...)
    .executor(...)
    .build();

和正常的命令不同,子命令并不使用直接注册的方式,而是作为父命令的 CommandSpec Builder 的 CommandSpec.Builder#child(CommandCallable, String…) 的方法参数传入。当然,它们可以使用多个不同的别名,第一个别名将用于主名称,并且会在帮助中显示。

import org.spongepowered.api.Sponge;

CommandSpec mailCommandSpec = CommandSpec.builder()
    .permission("myplugin.mail")
    .description(Text.of("Send and receive mails"))
    .child(readCmd, "read", "r", "inbox")
    .child(sendCmd, "send", "s", "write")
    .build();

Sponge.getCommandManager().register(plugin, mailCommandSpec, "mail", "email");

回退行为

如果一个命令有子命令,那么相应的通过 CommandSpec.Builder#executor(CommandExecutor) 方法添加的 CommandExecutor 及与之相关的 CommandSpec.Builder#arguments(CommandElement) 都是可选的。父命令执行器存在与否,将决定选择子命令或者解析子命令参数出错时相应行为。

如果构建命令时未指定父命令执行器,那么在相应的子命令未找到或相应的参数解析错误时,相关代码将抛出一个 ArgumentParseException 异常。

如果父命令设置了相应的命令执行器,那么它将用于相关错误的回退行为,比如第一个参数不符合任何一个子命令的主名称或别名等。如果找到了子命令,但是无法解析相应参数,那么相应的回退行为将由 CommandSpec.Builder#childArgumentParseExceptionFallback(boolean) 方法设置的参数决定:

  • 如果为真(默认值),那么相应的 ArgumentParseException 将被丢弃,同时将参数传给父命令执行器解析处理。如果父命令执行器解析错误,那么相关代码将针对父命令执行器抛出相应的异常。这和以前的 API 版本的行为是相同的,也就是说子命令的参数解析错误不会出现。
  • 如果为假,那么父命令执行器将不会试图解析参数,同时抛出子命令在参数解析错误时产生的 ArgumentParseException 异常,不过这种行为将阻止父命令执行器执行某些特定类型的命令参数组合(比如说第一个参数和某个子命令相同)。

不管是何种回退行为,如果子命令在参数解析成功后执行的时候抛出异常,父命令执行器(如果有)都不会执行,子命令相关的错误信息也将会直接抛出并显示。