Appearance
事件系统概述
插件通过 @SubscribeEvent 注解即可监听机器人的各类事件。
事件分为两大体系:
- 接收事件(
event/receive/)— 网关 DISPATCH 推送(群消息、私聊、互动、成员变动、入群申请等)与两个生命周期就绪事件(ReadyEvent仅 WS 模式、WebhookReadyEvent仅 Webhook 模式),共 18 种 - 发送事件(
event/send/)— 机器人主动操作(发消息、上传、撤回、禁言、审批、菜单、面板等)前触发,共 23 种,全部可取消
「机器人上线」的推荐做法
插件做上线初始化(如启动定时任务)时,推荐实现 Plugin.onActive() 而非监听 ReadyEvent:onActive() 在两种接入模式统一触发一次(WS 全部分片就绪 / Webhook 回调服务就绪),无需判断接入模式与分片;ReadyEvent 是 WebSocket 网关专属事件(每分片各触发一次),Webhook 模式不会触发,对应的是 WebhookReadyEvent。
@SubscribeEvent
java
import cn.org.bukkit.bngeuit.Bngeuit;
import cn.org.bukkit.bngeuit.event.SubscribeEvent;
import cn.org.bukkit.bngeuit.event.receive.GroupAtMessageEvent;
import cn.org.bukkit.bngeuit.event.receive.C2CMessageEvent;
import cn.org.bukkit.bngeuit.event.receive.ReadyEvent;
import cn.org.bukkit.bngeuit.event.receive.InteractionEvent;
public class MyListener {
@SubscribeEvent
public void onGroupAt(GroupAtMessageEvent e) {
Bngeuit.replyGroupText(
e.getGroupOpenid(), e.getId(), 1,
"收到: " + e.getContent()
);
}
@SubscribeEvent
public void onC2CMessage(C2CMessageEvent e) {
Bngeuit.replyC2CText(
e.getAuthor().id(), e.getId(), 1,
"收到私聊"
);
}
@SubscribeEvent
public void onReady(ReadyEvent e) {
// 机器人启动完成(仅 WebSocket 模式;多分片时每片触发一次,可用 e.getShardId() 区分)
if (e.getShardId() == 0) {
// 只对 shard 0 做一次全局初始化
}
}
@SubscribeEvent
public void onInteraction(InteractionEvent e) {
// 必须响应,否则客户端一直 loading
Bngeuit.respondInteraction(e.getId(),
cn.org.bukkit.bngeuit.core.BotApi.InteractionResponseCode.SUCCESS);
}
}包位置
SubscribeEvent、Event、Cancellable、EventPriority 在 cn.org.bukkit.bngeuit.event; 具体事件类分属 event.receive 与 event.send 两个子包。
规则
- 标注在 public 方法上
- 有且仅有 一个参数,类型继承自
Event - 方法名、参数名无限制
- 插件 JAR 内的类会被自动扫描注册
发送事件与取消
发送事件(event/send/)在机器人调用 HTTP API 之前触发,实现 Cancellable 接口。取消后对应操作被跳过,API 返回 null:
java
import cn.org.bukkit.bngeuit.event.SubscribeEvent;
import cn.org.bukkit.bngeuit.event.EventPriority;
import cn.org.bukkit.bngeuit.event.send.GroupMessageSendEvent;
@SubscribeEvent(priority = EventPriority.P1) // 最先执行
public void onGroupSend(GroupMessageSendEvent e) {
if (e.getContent() != null && e.getContent().contains("敏感词")) {
e.setCancelled(true); // 阻止这条群消息发送
}
}事件优先级
@SubscribeEvent(priority = EventPriority.XXX),数字越小越先执行:
| 优先级 | 说明 |
|---|---|
P1 | 最高,最先执行(适合过滤、权限检查) |
P2 | 较高 |
P3 | 普通(默认) |
P4 | 较低 |
P5 | 最低 |
P6 | 监看,无论事件是否取消都会执行 |
@SubscribeEvent(ignoreCancelled = true) 可在事件已被其他处理器取消时仍执行本方法。
触发自定义事件
Bngeuit.callEvent(event) 可同步触发任意 Event 子类:
java
public class MyEvent extends Event { ... }
@SubscribeEvent
public void onMyEvent(MyEvent e) { ... }
// 触发(按优先级分发;若事件实现 Cancellable 且被取消,返回 false)
boolean ok = Bngeuit.callEvent(new MyEvent());在 JavaPlugin 中使用
java
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
getLogger().info("插件已启用");
}
@SubscribeEvent
public void onGroupAt(GroupAtMessageEvent e) {
Bngeuit.replyGroupText(
e.getGroupOpenid(), e.getId(), 1,
"你好," + e.getAuthor().username()
);
}
}自动扫描
插件 JAR 内的所有 @SubscribeEvent 方法会被自动注册,无需手动操作。
事件 Metadata 系统
所有事件都支持 Metadata 系统,允许在不同优先级的处理器之间传递数据。
基本用法
java
import cn.org.bukkit.bngeuit.event.SubscribeEvent;
import cn.org.bukkit.bngeuit.event.EventPriority;
import cn.org.bukkit.bngeuit.metadata.MetadataValue;
import cn.org.bukkit.bngeuit.event.receive.GroupAtMessageEvent;
public class MetadataExample {
// P1 处理器:设置标记
@SubscribeEvent(priority = EventPriority.P1)
public void onCheck(GroupAtMessageEvent e) {
if (isSpam(e.getContent())) {
e.setMetadata("spam", new MetadataValue(true, this));
}
}
// P3 处理器:读取标记
@SubscribeEvent(priority = EventPriority.P3)
public void onHandle(GroupAtMessageEvent e) {
MetadataValue spam = e.getMetadata("spam");
if (spam != null && Boolean.TRUE.equals(spam.value())) {
// 是垃圾消息,跳过处理
return;
}
// 正常处理...
}
}MetadataValue
| 方法 | 返回类型 | 说明 |
|---|---|---|
value() | Object | 原始值(可为 null) |
source() | Object | 来源对象(通常是设置 metadata 的插件实例) |
as(type) | T | 类型转换(类型不匹配抛 ClassCastException) |
asSafe(type) | T | 安全类型转换(类型不匹配返回 null) |
Event Metadata 方法
| 方法 | 说明 |
|---|---|
setMetadata(key, value) | 设置 metadata |
getMetadata(key) | 获取 metadata(不存在返回 null) |
hasMetadata(key) | 是否存在指定 key |
removeMetadata(key) | 移除指定 key |
clearMetadata() | 移除所有 metadata |
生命周期
Metadata 生命周期与事件对象绑定,事件分发完成后自动回收。
