命令要求
有时你想限制玩家使用和/或查看某些命令或子命令的能力。正是为了这个目的,
ArgumentBuilder<S> 类有一个 requires(Predicate<S>) 方法来定义使用命令树特定分支的要求。
和往常一样,泛型参数 S 就是一个 CommandSourceStack,为我们提供执行实体、命令发送者和命令位置。
定义权限
要求最常见的用例之一是权限。通常,这些权限是在命令发送者上检查的,因为那是实际运行命令的实体/控制台/对象, 即使它是作为其他人(执行者)运行的。一个带有权限的简单命令可能看起来像这样:
Commands.literal("testcmd")
.requires(sender -> sender.getSender().hasPermission("permission.test"))
.executes(ctx -> {
ctx.getSource().getSender().sendRichMessage("<gold>你有权限运行这个命令!");
return Command.SINGLE_SUCCESS;
});
这个命令要求发送者具有 permission.test 权限。
但你不仅可以定义权限,还可以要求发送者是服务器操作员,像这样:
Commands.literal("testcmd")
.requires(sender -> sender.getSender().isOp())
.executes(ctx -> {
ctx.getSource().getSender().sendRichMessage("<gold>你是服务器操作员!");
return Command.SINGLE_SUCCESS;
});
定义更高级的谓词
你不必仅限于检查权限 - 因为它是一个谓词,可以返回任何布尔值。例如,你可以检查 玩家的物品栏中是否有钻石剑:
Commands.literal("givesword")
.requires(sender -> sender.getExecutor() instanceof Player player && !player.getInventory().contains(Material.DIAMOND_SWORD))
.executes(ctx -> {
if (ctx.getSource().getExecutor() instanceof Player player) {
player.getInventory().addItem(ItemType.DIAMOND_SWORD.createItemStack());
}
return Command.SINGLE_SUCCESS;
});
乍看之下,这工作得很好。但它有一个很大的缺陷 - 由于客户端不知道这个要求,它仍然显示命令 可以执行,即使要求解析为 false。但如果客户端尝试运行该命令,服务器会报告该命令不存在(意味着 要求未满足):
我们如何解决这个问题?Player 接口有一个名为 #updateCommands() 的方法专门用于这种情况。它重新发送当前注册的命令回
客户端,试图重新加载命令。现在,我们可以创建一个新命令,让玩家可以更新自己的命令以重新同步其命令状态:
Commands.literal("reloadcommands")
.executes(ctx -> {
if (ctx.getSource().getExecutor() instanceof Player player) {
player.updateCommands();
player.sendRichMessage("<gold>成功更新了你的命令!");
}
return Command.SINGLE_SUCCESS;
});
自动化命令重载
强制玩家重载自己的命令对用户体验来说不是一个可行的选择。出于这个原因,你可以自动化这个行为。调用 更新命令方法次数多少都是安全的,但通常应该避免,因为它可能会消耗大量带宽。如果可能的话,你应该将这些 放在非常具体的位置。此外,这个方法是完全线程安全的,这意味着你可以从异步上下文中自由调用它。