跳到主要内容

命令注册

在前面的章节中,我们详细了解了 Brigadier 的工作原理,但从未真正说明如何注册命令。所以我们现在就来做这件事!

LifecycleEventManager

在 Paper 中,Brigadier 命令是使用 LifecycleEventManager 注册的。这是一个特殊的类,它允许我们以一种方式注册命令,使我们永远不必 担心处理各种服务器重载事件,比如 /reload。相反,无论我们使用 LifecycleEventManager 注册什么,都会在需要时重新注册。

但如何获取能够注册命令的 LifecycleEventManager 呢?有两个"上下文"可以使用 LifecycleEventManager。第一个, 也是首选的,是在我们插件的 PluginBootstrap 类中。

在插件引导程序中注册

备注

这需要你使用 paper-plugin.yml 插件

如果你不使用 paper-plugin.yml,你可以在插件的主类中注册命令

我们可以通过在引导方法中运行 context.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {}) 来获取能够注册命令的 LifecycleEventManager,像这样:

CustomPluginBootstrap.java
public class CustomPluginBootstrap implements PluginBootstrap {

@Override
public void bootstrap(BootstrapContext context) {
context.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
// 在这里注册你的命令...
});
}
}

快速回顾一下这一切的含义: 通过运行 context.getLifecycleManager(),我们获得一个 LifecycleEventManager<BootstrapContext> 对象。我们可以在其上调用 LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler) 来获取我们正确的生命周期事件。第一个参数声明 我们想要注册内容的生命周期事件类型,第二个参数是一个看起来像这样的接口:

@FunctionalInterface
public interface LifecycleEventHandler<E extends LifecycleEvent> {
void run(E event);
}

由于它是一个函数式接口,我们可以不实现它,而只是传入一个有一个参数 E 且没有返回值的 lambda。E 泛型类型是一个 ReloadableRegistrarEvent<Commands>,因此也是我们的 lambda 参数的类型。

ReloadableRegistrarEvent<Commands> 类有两个方法:ReloadableRegistrarEvent.Cause cause()Commands registrar()。对我们来说更相关的方法是 registrar 方法。通过它我们可以注册我们的命令。

在插件主类中注册

在插件主类中获取用于命令的 LifecycleEventManager 与在 PluginBootstrap 类中访问它的方式非常相似,区别在于 我们不是使用在 PluginBootstrap 类的引导方法中提供给我们的 BootstrapContext 来获取 LifecycleEventManager,而是可以直接使用 JavaPlugin#getLifecycleManager 来检索它。

PluginMainClass.java
public final class PluginMainClass extends JavaPlugin {

@Override
public void onEnable() {
this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
// 在这里注册你的命令...
});
}
}

这遵循与 PluginBootstrap 相同的概念,只是我们不是得到一个 LifecycleEventManager<BootstrapContext>,而是得到一个 LifecycleEventManager<Plugin>。这对我们的用例来说并不重要,但你最好知道这一点。 其余的方法与 PluginBootstrap 参数化的 LifecycleEventManager 完全相同。

使用 Commands 类注册命令

现在我们通过事件处理程序中的 commands.registrar() 访问了 Commands 类的实例,我们可以访问 Commands#register 方法的几个重载。

注册 LiteralCommandNode

大多数情况下,你会使用 LiteralArgumentBuilder 来构建你的命令树。为了从该对象检索 LiteralCommandNode,我们需要调用 LiteralArgumentBuilder#build() 方法:

LiteralArgumentBuilder<CommandSourceStack> command = Commands.literal("testcmd")
.then(Commands.literal("argument_one"))
.then(Commands.literal("argument_two"));

LiteralCommandNode<CommandSourceStack> buildCommand = command.build();

或者简短一点:

LiteralCommandNode<CommandSourceStack> buildCommand = Commands.literal("testcmd")
.then(Commands.literal("argument_one"))
.then(Commands.literal("argument_two"))
.build();

现在我们已经检索到了 LiteralCommandNode,我们可以注册它。为此我们有多个重载,它们可以选择设置别名和/或描述。 注册我们的 "testcmd" 可能看起来像这样:

this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
commands.registrar().register(buildCommand);
});

注册 BasicCommand

BasicCommand 是一种类似 Bukkit 的定义命令的方式。我们不是构建命令树, 而是允许所有用户输入并将参数作为简单的字符串数组检索。这种类型的命令对于非常简单的基于文本的命令特别有用, 比如 /broadcast 命令。你可以在这里阅读更多关于基本命令的详细信息。

假设你已经有了你的 BasicCommand 对象,我们可以这样注册它:

final BasicCommand basicCommand = ...;

this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
commands.registrar().register("commandname", basicCommand);
});

LiteralCommandNode 类似,我们也有重载来为我们的命令设置各种附加信息。

进一步参考

  • 关于 LifecycleEventManager 的快速参考,请点击这里