贺兰兰
真正的从零基础学Bukkit开发!—— 五.认识 Bukkit API 的命令系统

警告:请做好 PTSD 的准备,因为相比 Mojang 的 Brigadier 和 Sponge API 提供的 CommandSpec,Bukkit API 提供的这套命令系统实在**始,太简陋了

要想在 Bukkit API 中创建一个新的指令,我们需要进行以下操作:

  • 在 plugin.yml 中声明指令
  • 创建一个 CommandExecutor
  • 使用 Bukkit.getPluginCommand().setExecutor() 为指定指令设置 Executor

本例中,我们将创建一个 test 指令,输入以后可以显示指定玩家的 UUID 和所在的世界名称。

让我们一步一步进行下去...

在 plugin.yml 中声明指令

在 plugin.yml 中添加以下内容:

  1. commands:
  2.   [指令名]:
  3.     description:
  4.     usage:
  5.     permission:
  6.     permission-message:
复制代码

[指令名]:即指令名称

description:代表指令描述

usage:代表指令用法

permission:代表指令所需权限

permission-message:代表无权执行时的提示消息

事实上,由于在这里声明的内容使用起来并不是很灵活,因此一般人们仅使用缺省值,例如:

  1. commands:
  2.   [指令名]:
复制代码

本例中,我们键入如下内容:

  1. commands:
  2.   test:
复制代码

创建一个 CommandExecutor

让我们创建 TestCommand 类,然后继承 CommandExecutor 接口,然后实现 onCommand 方法

  1. public final TestCommand extends CommandExecutor{
  2.     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
  3.         return false;
  4.     }
  5. }
复制代码

onCommand 方法将会在玩家输入指定指令时被调用

我们可以看到  onCommand 方法拥有四个参数,让我们了解这四个参数各自的意义:

  • sender 代表指令的发送者,这些发送者可能是玩家,控制台或者命令方块
  • command 代表玩家执行的指令,在本例中,它一定是 test
  • label 代表被执行指令使用的别名(alias),由于我们没有设置别名,并且也无需检测这些别名,因此可以直接忽略
  • args 是一个 String 数组,代表玩家传入的参数。例如,当玩家输入 /test ABC DEF 时,args[0] 便得到了 "ABC" 值,args[1] 便得到了 "DEF" 值

值得一提的是,这些参数全部被标注了 @NotNull 注解,也就是意味着,这些参数被传入时必不为空,相对的是,使用@Nullable` 注解代表被注解的方法返回值/参数可为空。当然,Java 在语言层面上并没有可空参数的概念,这些注解都仅是开发者之间的约定,并不代表实际结果。

同时,可以看到该方法拥有一个 boolean 的返回值,这本身意味着指令参数是否正确 :如果为 false,那么 Bukkit API 便会为命令发送者发送刚才在 plugin.yml定义的 usage 字符串 —— 事实上,同样由于灵活性问题,开发者通常都将此处返回为 true ,即使命令发送者输入了错误的参数 —— 在那种情况下,开发者将会自行为命令发送者发送对应的提示消息。

重新回顾我们的需求:我们希望创建一个可以显示指定玩家 UUID 和所在世界名称的指令。分解一下这个需求:

  • 判断命令发送者是不是一个玩家,如果是,那么允许这个玩家不输入任何参数时显示自己的 UUID 和所在世界名称;如果不是,则必须提供玩家名称
  • 判断命令发送者是否输入了一个包含玩家名的参数,如果有,那么该玩家是否存在?如果存在,再显示该玩家的 UUID 和所在世界名称

从这个需求出发,我们写出了如下代码:

  1. public final TestCommand extends CommandExecutor{
  2.     public boolean onCommand(CommandSender sender,Command command,String label, String[] args) {
  3.         // 如果发送者是玩家
  4.         if(sender instanceof Player){
  5.             // 如果提供的参数数量大于1,那么不再继续执行,因为这不符合我们的要求
  6.             if(args.length > 1){
  7.                 sender.sendMessage("参数错误,请检查参数数量");
  8.                 return true;
  9.             }
  10.             // 如果没有提供参数,那么必然是查询自己的数据
  11.             if(args.length == 0){
  12.                 //将 Sender 对象强制转换为 Player 对象,因为上面已经判断过必为玩家,所以不会引发强转异常
  13.                 Player player = (Player) sender;
  14.                 player.sendMessage("您的 UUID 为:" + player.getUniqueID());
  15.                 player.sendMessage("您所在的世界名为:"+ player.getWorld().getName());
  16.                 return true;
  17.             // 如果提供了一个参数,那么必然是查询他人的数据
  18.             }else if(args.length == 1){
  19.                 //获取指定玩家
  20.                 Player player = Bukkit.getPlayer(args[0]);
  21.                 //如果玩家不在线,或玩家名称不存在,则 Bukkit#getPlayer(String) 方法将返回 null,因此我们必须在此处进行判空,避免引发 NullPointerException,即空指针异常
  22.                 if(player == null){
  23.                     sender.sendMessage("指定玩家不存在或不在线");
  24.                     return true;
  25.                 }
  26.                 player.sendMessage("指定玩家的 UUID 为:" + player.getUniqueID());
  27.                 player.sendMessage("指定玩家所在的世界名为:"+ player.getWorld().getName());
  28.                 return true;
  29.             }
  30.         // 如果发送者是控制台
  31.         }else if(sender instanceof ConsoleCommandSender){
  32.             // 如果提供的参数不为1,那么不再继续执行,因为这不符合我们的要求
  33.             if(args.length != 1){
  34.                 sender.sendMessage("参数错误,请检查参数数量");
  35.                 return true;
  36.             }
  37.             Player player = Bukkit.getPlayer(args[0]);
  38.             if(player == null){
  39.                 sender.sendMessage("指定玩家不存在或不在线");
  40.                 return true;
  41.             }
  42.             player.sendMessage("指定玩家的 UUID 为:" + player.getUniqueID());
  43.             player.sendMessage("指定玩家所在的世界名为:"+ player.getWorld().getName());
  44.             return true;
  45.         // 如果都不是
  46.         }else{
  47.             sender.sendMessage("不受支持的命令发送者类型");
  48.             return true;
  49.         }
  50.     }
  51. }
复制代码

为指定指令设置 Executor

在插件主类的 onEnable 方法中键入以下内容:

  1. Bukkit.getPluginCommand("test").setExecutor(new CommandExecutor());
复制代码

即可注册指令

至此,我们已经成功创建了一个指令,编译插件并进入游戏,输入 /test 即可看到效果。

来自群组: Server CT

虎牙伊南
大佬牛逼,支持!

P小黑
前排表示支持~~

玄月月
是贺兰兰!

XL洛曦
妙啊大佬awa

第一页 上一页 下一页 最后一页