开发入门篇 /03/ 事件系统


概述

事件系统,就是在程序收到某种信号,比如收到消息、机器人上线下线等等的时候,通知已经注册监听器的程序,让它们对此作出反应。

所以,在实现机器人功能这一方面,事件系统非常重要。基本做法就是靠事件系统来处理用户发送的消息。

事件通道

要注册事件监听器,首先要获取一个事件通道 (EventChannelopen in new window)。

现在我们要做的,是选一个合适的情景,获取一个事件通道,并将它存到一个变量里以便复用。

获取事件通道、监听事件的代码均写在插件启用、加载的地方。若只使用 mirai-core 开发,则保证写在机器人登录之前即可。

公共事件通道

公共事件通道 (GlobalEventChannelopen in new window) 可以接收当前 mirai 已登录的所有机器人的消息。

以下代码支持链式调用

// kotlin
val channel = globalEventChannel()
// java,无法使用 globalEventChannel(), 可以用以下方法代替
EventChannel channel = GlobalEventChannel.INSTANCE.parentScope(this);

指定携程上下文和限制作用域

上面的代码中 .parentScope(this) 是限制消息通道的作用域。作用域很有用,当插件被停用时,插件的协程作用域也会被关闭,事件监听就会被同步停止。mirai-console 插件主类继承了 CoroutineScope,故可填入 this 作为参数。

非特殊情况下建议指定事件通道的携程上下文和限制作用域。

机器人消息通道

如果你只想接收单独机器人的事件,请使用以下代码

// kotlin
val channel = bot.eventChannel
// java
EventChannel channel = bot.getEventChannel();

其中 bot 实例可以通过 Bot.getInstanceBot.getInstanceOrNull 等途径获得,但需要注意的是这个方法只能获得已登录的机器人,也就是说在执行这两个方法的时候,机器人必须要已经登录了。

还记得 部署开发环境 中提到的 PostStartupExtension 吗?你可以注册这个钩子,将获取事件通道和注册监听器的代码写里面,就能保证在获取事件通道时,自动登录已完成了。且可以保证事件监听器只被注册一次

或者,我们可以换一种思路。

过滤

提示

没有特殊需要的话你可以跳过这部分,对你后续的开发没有影响。

在原来的事件通道的基础上,加上

  • .filterIsInstance<事件类>() 只监听某类事件,比如 BotEvent。默认情况下,所有事件都可以监听
  • .filter(e -> 条件).filter { 条件 } 根据条件过滤事件

示例如下

// kotlin
val channel = /*此处省略*/
    .filterIsInstance<BotEvent>()
    .filter { it.bot.id == 2431208142L }
// java
EventChannel channel = /*此处省略*/
    .filterIsInstance(BotEvent.class)
    .filter(event -> event.getBot().getId() == 2431208142L);

均为只接收机器人 2431208142 收到的机器人事件。

监听事件

获取好事件通道后,我们把它存到了一个变量 channel 里,接下来,我们将正式使用事件通道注册监听器,实现机器人功能。

提示

别急,你先别急