Skip to content

事件系统概述

插件通过 @SubscribeEvent 注解即可监听机器人的各类事件。

事件分为两大体系:

  • 接收事件event/receive/)— 网关 DISPATCH 推送(群消息、私聊、互动、成员变动、入群申请等)与两个生命周期就绪事件ReadyEvent 仅 WS 模式、WebhookReadyEvent 仅 Webhook 模式),共 18 种
  • 发送事件event/send/)— 机器人主动操作(发消息、上传、撤回、禁言、审批、菜单、面板等)前触发,共 23 种,全部可取消

「机器人上线」的推荐做法

插件做上线初始化(如启动定时任务)时,推荐实现 Plugin.onActive() 而非监听 ReadyEventonActive() 在两种接入模式统一触发一次(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);
    }
}

包位置

SubscribeEventEventCancellableEventPrioritycn.org.bukkit.bngeuit.event; 具体事件类分属 event.receiveevent.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 生命周期与事件对象绑定,事件分发完成后自动回收。