Appearance
自定义命令开发
Bngeuit 采用注解式命令系统,支持主子命令结构、别名和命名空间。开发者可以通过简单的注解来注册自定义命令。
@Command 注解
@Command 注解用于标记命令类,定义命令的基本信息:
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Command {
String name(); // 主命令名
String[] aliases() default {}; // 别名
String description() default "";
String usage() default "";
}参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | String | ✅ | 主命令名(如 "test") |
aliases | String[] | ❌ | 命令别名(如 {"t", "tst"}) |
description | String | ❌ | 命令描述 |
usage | String | ❌ | 用法说明 |
@CommandBody 注解
@CommandBody 注解用于标记命令处理方法:
java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CommandBody {
String name() default ""; // 子命令名(空 = 主命令本身)
String desc() default "";
}参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | String | ❌ | 子命令名(空字符串表示主命令本身) |
desc | String | ❌ | 子命令描述 |
方法签名
所有命令处理方法必须遵循以下签名:
java
void execute(CommandSender sender, String[] args)sender- 命令发送者(用于回复消息)args- 命令参数数组
命令格式
<主命令> [子命令] [参数...]@CommandBody的name = ""→ 输入主命令时触发@CommandBody的name = "xxx"→ 输入主命令 xxx时触发
完整示例
基础命令
java
import cn.org.bukkit.bngeuit.command.Command;
import cn.org.bukkit.bngeuit.command.CommandBody;
import cn.org.bukkit.bngeuit.command.CommandSender;
import cn.org.bukkit.bngeuit.command.GroupCommandSender;
@Command(name = "test", aliases = {"t"}, description = "测试命令")
public class TestCommand {
@CommandBody // 主命令:test
public void execute(CommandSender sender, String[] args) {
sender.sendMessage("参数: " + String.join(" ", args));
}
@CommandBody(name = "info", desc = "查看信息") // 子命令:test info
public void info(CommandSender sender, String[] args) {
sender.sendMessage("TestPlugin v1.0");
}
}使用效果
test → execute(),无子命令
test hello world → execute(),args = ["hello", "world"]
test info → info()
t info → 别名 "t" = "test"CommandSender
所有命令方法都接收 CommandSender 作为第一参数,用于回复命令来源:
| 方法 | 返回类型 | 说明 |
|---|---|---|
getSenderId() | String | 发送者标识(群 OpenID / 用户 OpenID / CONSOLE) |
sendMessage(String) | void | 向命令来源发送回复 |
实现类
| 实现 | 场景 | 说明 |
|---|---|---|
GroupCommandSender | 群聊 | getSenderId() 即群 OpenID,sendMessage() 回复到群 |
C2CCommandSender | 私聊 | getSenderId() 即用户 OpenID,sendMessage() 回复到私聊 |
ConsoleSender | 控制台 | 回复输出到 System.out,全局单例,经 Bngeuit.getConsoleSender() 获取 |
示例
java
@CommandBody
public void execute(CommandSender sender, String[] args) {
if (sender instanceof GroupCommandSender) {
// 来自群聊
sender.sendMessage("来自群 " + sender.getSenderId());
} else if (sender instanceof C2CCommandSender) {
// 来自私聊
sender.sendMessage("来自私聊 " + sender.getSenderId());
} else if (sender instanceof ConsoleSender) {
// 来自控制台
sender.sendMessage("来自控制台");
}
}命令命名空间
每个命令归属一个插件,支持 插件名:命令 精确指定,用于解决同名命令冲突:
- 插件命令 → 命名空间 = 插件名(小写),例如
myplugin:test - 内置命令(
plugin == null)→ 保留命名空间bngeuit,例如bngeuit:stop
解析规则(大小写不敏感):
插件名:命令/bngeuit:命令精确命中 → 使用该命令- 否则回退到普通命令名(无冒号输入按普通命令匹配)
java
myplugin:test info # 精确指定某插件的 test 命令
bngeuit:stop # 内置命令
test info # 无冒号,按普通命令解析手动派发命令
框架外部可通过 Bngeuit.dispatchCommand(sender, commandLine) 以字符串形式执行任意命令(在调度器 sync 线程执行,与事件处理串行):
java
Bngeuit.dispatchCommand(Bngeuit.getConsoleSender(), "stop");
Bngeuit.dispatchCommand(Bngeuit.getConsoleSender(), "plugin reload myplugin");自动注册
插件 JAR 中的 @Command 类会被自动扫描并注册到 插件名: 命名空间,无需手动操作。
注册流程
- 框架启动时,
PluginManager扫描所有已加载插件的 JAR 文件 - 找到带有
@Command注解的类 - 扫描类中带有
@CommandBody注解的方法 - 将命令注册到命令管理器,命名空间为插件名(小写)
注意事项
- 命令类必须是公共的(
public) - 命令处理方法必须是公共的(
public) - 方法签名必须符合
void execute(CommandSender sender, String[] args) - 避免命令名冲突,建议使用插件特有的前缀
最佳实践
1. 命令命名规范
java
// ✅ 好的命名
@Command(name = "myplugin", aliases = {"mp"}, description = "我的插件命令")
// ❌ 避免通用名称,容易冲突
@Command(name = "test", aliases = {"t"})2. 子命令组织
java
@Command(name = "myplugin", description = "我的插件")
public class MyPluginCommand {
@CommandBody // myplugin
public void help(CommandSender sender, String[] args) {
sender.sendMessage("使用方法: myplugin <子命令>");
}
@CommandBody(name = "reload", desc = "重载配置")
public void reload(CommandSender sender, String[] args) {
// 重载逻辑
sender.sendMessage("配置已重载");
}
@CommandBody(name = "info", desc = "查看信息")
public void info(CommandSender sender, String[] args) {
sender.sendMessage("MyPlugin v1.0.0");
}
}3. 权限控制
java
@CommandBody(name = "admin", desc = "管理员命令")
public void admin(CommandSender sender, String[] args) {
// 检查是否为控制台
if (!(sender instanceof ConsoleSender)) {
sender.sendMessage("此命令只能在控制台使用");
return;
}
// 管理员逻辑
sender.sendMessage("管理员操作已执行");
}4. 参数验证
java
@CommandBody(name = "set", desc = "设置配置")
public void set(CommandSender sender, String[] args) {
if (args.length < 2) {
sender.sendMessage("用法: myplugin set <key> <value>");
return;
}
String key = args[0];
String value = args[1];
// 设置配置
sender.sendMessage("已设置 " + key + " = " + value);
}