Skip to content

Ayaka是如何工作的?

可能一些概念暂时无法完全理解,请向后看,因为一些概念需要在不同的地方多次阐述才能讲解清楚

插件、群组、消息

ayaka的世界中,插件、群组、消息的关系如下

图片

AyakaGroup

ayaka收到一个新的群组的消息时,就会自动新建一个AyakaGroup对象(后简称为group),该对象内部保存有一个状态指针和一个字典(用来保存该群组内的临时数据,bot重启后丢失)

图片

AyakaApp、AyakaState和唯一状态树

每个ayaka衍生插件里都有一个或若干个AyakaApp对象(后简称为app)。在插件代码加载阶段,生成这些app的时候,ayaka会根据它们身上注册的回调函数的情况,生成唯一一棵状态树,所有的状态结点都位于这棵状态树上

图片

group内部的状态指针则指向该树上的某个结点,表示该群组当前所处的状态。默认指向root状态(又叫闲置状态)

状态转移

状态可以通过调用app.goto()app.set_state()方法进行转移,状态转移时,如果存在相应的进入回调退出回调,还会顺次执行它们

root状态,变更为root.插件2状态,再变回root状态(相当于打开了插件2后又关闭插件2)

图片

root.插件2.游戏中.出牌状态,变更为root.插件1.睡眠状态:

图片

root状态转移到root.插件2状态,相当于群组开启了插件2,从闲置状态(没有任何插件在运行)转移到运行插件2的状态

root.插件2状态转移到root状态,相当于群组关闭了插件2,恢复到闲置状态

命令回调、消息回调、上溯查找和阻断

每个状态下都可以注册命令回调(对具有命令抬头(例如#)的消息进行响应)和普通消息回调

对应的装饰器:

说明 代码
在闲置状态下进行注册 @app.on_idle()
在指定状态下进行注册 @app.on_state()
注册命令回调 @app.on_cmd()
注册消息回调 @app.on_text()

在消息从ayaka来到group后,ayaka会根据group当前状态指针所指的状态,进行上溯查找,查找满足触发条件的回调来处理消息

图片

假如当前状态是root.插件2,但是在该状态中并没有找到符合的命令回调(例如:消息是#睡觉,但是root.插件2并没有命令为睡觉的命令回调),则继续查找父状态,可一路上溯至root结点

若均没有符合的命令回调,则该消息(即使有命令抬头)退化成普通消息来处理,并且处理方式同样是一路上溯至root结点

注意,对于状态结点而言,其命令回调和消息回调可能有0个,1个或若干个

若为0个,则说明不符合,需要继续上溯查找,直到root结点

在注册回调的时候同时可以指定是否阻断,注册回调时均默认阻断

对应装饰器:

说明 代码
不阻断 @app.on_no_block()
阻断 无需装饰器,默认为阻断

若有符合的回调,但是其设置为不阻断,那么在执行了该回调后,ayaka会继续上述的查找流程,直到结束

deep

但是上节所说的上溯查找被施加了一定的限制

大部分情况下,我们不会期望父状态结点的回调会在群组处于子状态时被触发,它们就像是幽灵一样,令人困惑

因此,这些回调在注册时,默认其可向下影响的深度为0,也就说,它对下一层状态(以及更深的状态)来说是不可见的,因而上溯查找时也不会找到它

图片

如果设置为1,则其对直系子结点可见,对孙结点不可见

如果设置为any,则其对所有后代结点可见

对应装饰器:

说明 代码
设置深度为any @app.on_deep_all()
设置深度为n @app.on_deep_all(n)
设置深度为0 无需装饰器,默认为0

这些AyakaState到底有什么用呢?

提供独立的命令空间

通过这些状态,把各种各样的回调隔离开,不再会有 一人高呼万人响应 的尴尬

不同状态下,可以保存有相同命令的不同回调。这些回调仅在对应状态下才会响应指令,执行任务。这样保证了命令空间的纯净,各个插件的指令不会相互污染

同时,通过deep上溯查找的特点,又可以让一些父状态的方法复用给子状态使用,兼具灵活性

这些AyakaGroup到底有什么用呢?

提供独立的数据空间

显然,不同群组的状态是独立的,互不影响的,仅一点就这需要我们设计AyakaGroup来保存不同群组的状态

同时,不同群组还有保存其他数据的需求,比如某投票插件需要保存目前所有参与人员的投票情况,显然不同群组的投票必须是独立的,这同样需要AyakaGroup来保存不同群组的数据

这些AyakaApp到底有什么用呢?

通过AyakaApp,把上述概念都打包到一个app身上,只需调用相应装饰器注册回调即可实现上述效果

同时,app也提供了一些有益的属性,在下一章详细介绍这些属性

下一步

在这里~ ↘