前言
这份文档对应的是一套轻量级 OlivOS 插件模板
因为有人提出现在的 OlivOS 的官方插件模板过于轻量,很多必要函数都需要自己实现也很麻烦;而之前我写的规则集插件模版又过于深度依赖 OlivaDiceCore 里面的必要函数,过于耦合化,故编写以下模板。本模板虽然没有和 OlivaDiceCore 完全解耦,但是其中的耦合化是必要的——实现群链在很多地方都方便不少。当然如果你的 OlivOS 并未装载 OlivaDiceCore,也完全没有影响。
注意,本说明和插件模板均为 vibe coding 所生成,但是所有函数和目录结构我均亲自确认和验证过,没有问题可以正常使用
下载链接
本模板已在 github 上进行开源:https://github.com/0Desom0/Desom-OlivaDice-Plugin/tree/main/%E7%A4%BA%E4%BE%8B/LightPluginTemplate
1. 模板定位
这套模板默认基于以下前提:
compatible_svn 为 190 或更高。
message_mode 为 olivos_string。框架通常下发 OP 码;为兼容适配器差异,模板同时识别 OP/CQ 的 reply 与 at 码,并支持 id、qq 参数。
- 配置界面同时提供桌面 GUI 和插件 WebUI,两者共用同一套配置文件。网页需要支持
webui_config 与插件消息桥的 OlivOS 版本;compatible_svn: 190 本身不代表该核心一定支持 WebUI。
模板会识别当前 Bot、bot_info.id、sub_self_id 与 sub_self_open_id。只指名其他账号时不响应,多个 at 中包含当前 Bot 时正常响应;群聊回复会引用触发消息。
2. 目录结构
当前模板目录如下:
LightPluginTemplate/
├── 模板说明文档.md
├── .flake8
├── tests/
│ └── test_webui.py
└── YourPluginName/
├── __init__.py
├── app.json
├── config.py
├── function.py
├── gui.py
├── main.py
├── message.py
├── message_custom.py
├── utils.py
├── webui.py
└── webui/
└── index.html
3. 运行时数据目录结构
模板运行后,数据会落在 plugin/data/YourPluginName/ 下。
其中分为两层:
3.1 全局配置
全局配置文件是:
plugin/data/YourPluginName/global_config.json
这份配置是 所有 Bot 共用 的。
目前只包含两个字段:
global_enable_switch
global_debug_mode_switch
3.2 Bot 级配置与回复目录
当前模板里,bot_config.json 不跟随 link;只有 storage、回复词与变量会按 linked_bot_hash 生效:
如果你还不知道这里的 link 指什么,可以先跳到 4.2 什么是 link,为什么要有 link 看解释。
plugin/data/YourPluginName/<raw_bot_hash>/bot_config.json
plugin/data/YourPluginName/<linked_bot_hash>/message_custom.json
plugin/data/YourPluginName/<linked_bot_hash>/message_variable.json
plugin/data/YourPluginName/<linked_bot_hash>/storage/
这意味着当前模板的数据会分成两部分:
bot_config.json 仍按原始 bot 保存
storage/目录,自定义回复,自定义变量按照 link_bot_hash 目录读取
这里还要再强调一点:
- 模板会在 init 阶段把 bot_config 与 linked 目录都初始化好。
- 初始化与后续保存时,都会直接使用最终解析出的
plugin/data/YourPluginName/<linked_bot_hash>/ 目录。
- 只有你是
从账号 的时候才会自动解析到主账号,其他情况就是你自己的 bot_hash 对应目录。
所以这里现在要明确区分两套语义:
- 原始配置目录:保存当前 bot 自己的
bot_config.json
- linked 运行目录:保存当前 bot 实际生效的 storage、回复词、变量
4. 术语说明
4.1 什么是 hag_id
hag_id 指的是:
- 带 host 的场景:
host_id|group_id
- 不带 host 的场景:
group_id
它的作用是标识“当前群”。
这个概念经常用于群配置、群开关、群权限判断。
4.2 什么是 link,为什么要有 link
这里说的 link,本质上不是一个单独的文件夹名,也不是一种新的 bot 身份,
而是一个“把当前账号映射到另一个账号去读取某些运行时数据”的逻辑关系。
在接了 OlivaDiceCore 的主从账号体系后,常见场景是:
- 一个主账号负责统一维护配置或回复词
- 若干从账号跟着主账号一起工作
- 从账号收到消息时,某些功能希望直接复用主账号那套内容,而不是每个号都各配一份
这时候就需要 link。
模板里所谓的 linked_bot_hash,可以理解成:
- 当前事件原本来自某个 bot
- 但在读取“会被主从账号共享”的那部分数据时
- 不一定继续用这个 bot 自己的原始 hash
- 而是先根据主从关系,解析出最终应该落到哪个 bot_hash 上
这个“最终用于共享数据读写的 bot_hash”,就是 linked_bot_hash。
为什么要有它,核心原因只有一个:
- 避免主从账号把同一套回复词、变量、运行期模板内容重复维护很多份
如果没有 link,那主账号和每个从账号都要各自维护自己的:
message_custom.json
message_variable.json
这样一来:
- 改一条回复词要改很多次
- 主从号的表现容易不一致
- 管理成本会明显变高
有了 link 以后,就可以把“共享的数据”统一收束到主账号对应的目录,
从账号在运行时直接复用主账号那份内容。
这里还需要特别提醒一个很容易误会的点:
- 本模板和
OlivaDiceCore 在“回复词解析是否跟随群链”这件事上,并不完全一样
OlivaDiceCore 自己解析回复时,默认是不跟随群链的,仍然读取各账号自己的回复词
- 但这个轻量模板里,回复词会跟随群链,其他地方都和
OlivaDiceCore 的群链逻辑是完全一致的。
也就是说:
- 如果你拿
OlivaDiceCore 的使用习惯来理解这个模板,就很容易误以为从账号会继续读自己的回复词
- 但本模板不是这样设计的;只要群链解析结果指向主账号,模板就会直接复用主账号那份回复词
这里还要特别强调:
link 是运行时读写策略,不是额外目录层级
- 所以模板不会创建
link/ 子目录
- 模板只是把回复词和变量直接写到最终解析出来的
linked_bot_hash 对应到准确的目录
本模板里 link 的作用范围是“除了 bot_config 之外的运行期 bot 数据”:
bot_config.json 不走 link
storage/ 走 link
message_custom.json 走 link
message_variable.json 走 link
所以你可以把它理解成一句话:
link 不是“把两个 bot 合并成一个 bot”
- 而是“让主从 bot 共用 storage、回复词、变量这类运行期数据,但 bot_config 仍保留各自独立”
5. GUI 设计说明
GUI 现在采用一个简单的双页签结构。
当前模板提供的页签有:
此外,这个模板已经在 app.json 中注册了一个插件菜单项:
- 标题:
打开插件配置
- 事件:
YourPluginName_Menu_001
OlivOS 触发该菜单事件后,会进入 main.py 的 Event.menu,再转交给 gui.py 中的 handle_menu_event 打开配置窗口。
窗口打开时会默认定位到当前触发菜单事件的那个 Bot,
但 Bot 配置页内部仍然提供一个下拉框,允许继续切换其他账号。
5.1 全局设置页
全局设置页保持成一个简单表单:
- 全局启用开关
- 全局调试模式开关
- 保存全局设置、打开总目录、刷新、关闭窗口按钮
5.2 Bot 配置页
Bot 配置页负责展示并修改当前菜单所属 Bot 的配置:
- 可切换当前 Bot 的下拉框
- 当前 Bot 信息
- 如果当前账号是从账号,则提示只有 storage、回复词、变量这些 linked 数据实际读取的主账号
- Bot 启用开关
- 保存 Bot 设置、打开目录、刷新等按钮
同时,为了不把主界面做得过重,以下功能改成从 Bot 配置页按钮打开子窗口:
5.3 回复词管理子窗口
回复词管理窗口采用树表加按钮条:
- 查看当前回复词条目、说明、内容
- 编辑回复词
- 恢复默认值或删除扩展条目
- 恢复全部默认回复
- 支持双击编辑
- 支持右键菜单执行“编辑”和“恢复/删除”
- “恢复默认回复”和“恢复/删除”都带二次确认
5.4 设主列表管理子窗口
设主列表管理窗口用于维护当前原始 Bot 目录中 bot_config.json 的 configured_master_list:
这依然保持模板当前的 linked 目录语义:
- 骰主列表不跟随群链
- 也就是当前窗口操作的是当前原始 bot 自己那份数据
5.5 WebUI 配置页面
登录 OlivOS WebUI 后,从侧栏“插件页面”进入“轻量级插件配置”。页面保留“全局设置”和“Bot 配置”两类设置,不需要额外启动 Web 服务,也不需要 Node.js、npm 或前端框架。
| 功能 | 网页中的操作 | 数据归属 |
| 全局启用、调试模式 | 勾选后点击“保存全局设置” | 所有 Bot 共用 global_config.json |
| 切换 Bot、启用当前 Bot | 下拉框选账号,修改后点击“保存 Bot 设置” | 原始 Bot 的 bot_config.json |
| 回复词管理 | 选择条目,查看说明,编辑并保存;默认词可恢复,扩展词可删除 | 按群链读取 message_custom.json |
| 恢复全部默认回复 | 确认后恢复源码默认值,并删除扩展回复词 | 影响共用这套回复词的主从账号 |
| 骰主列表 | 输入数字 ID 添加,支持多个 ID;多选后删除 | 原始 Bot 的 configured_master_list |
| 刷新配置 | 顶部“刷新配置”,重新读取 GUI、命令或文件修改后的数据 | 全局与当前 Bot |
| 查看目录 | 展开“数据目录”或“配置与回复目录”,点击路径选中后复制 | 展示 OlivOS 服务器上的路径 |
网页显示当前 Bot 及其回复词使用的主账号。Bot 开关和骰主列表不跟随群链;回复词、变量和 storage/ 保持原有的 linked 规则。保存开关或骰主时,会保留 disabled_group_list 等未编辑字段。页面暂不提供变量、群禁用列表编辑器,这些仍使用原有接口或命令。
未检测到 Bot 时,全局设置仍可修改。插件或 Bot 已关闭时,配置页面仍能用于重新启用。网页没有当前消息的 bot_info,不会通过群聊骰主权限来识别网页管理员;访问认证由 OlivOS WebUI 负责。
浏览器无法直接打开服务器的文件夹,所以网页提供路径查看和选中复制,桌面 GUI 继续保留打开目录按钮。网页支持窄屏与浏览器深浅配色;回复内容通过文本节点显示。删除、恢复以及放弃未保存的表单修改都使用页面内确认框,不依赖沙箱中不可用的 window.confirm()。
保存失败会显示错误,并保留编辑内容。请求超时只表示未收到回包,保存可能已经完成,应先刷新确认;页面不会自动重试写操作。多个管理界面同时修改同一个字段时,以最后一次成功保存为准。
5.6 WebUI 注册与通信
app.json 新增的注册内容如下,原有 menu_config 继续用于桌面 GUI:
"webui_config": [
{"title": "轻量级插件配置", "type": "iframe", "path": "webui/index.html"}
]
文件必须保存为 UTF-8 无 BOM。修改注册信息后需要重载插件。网页业务事件名是 YourPluginName_WebUI_Config,分别定义在 config.py 的 webui_event 和 webui/index.html 开头的 PAGE_CONFIG.eventName;重命名模板时应一起替换 YourPluginName,该事件不需要注册进 menu_config。
通信流程:
webui/index.html 使用 window.parent.postMessage 发送 olivos:plugin_event,携带事件名、唯一 request_id 和业务 payload。
- OlivOS 校验页面来源、绑定插件命名空间并处理登录会话,再把请求交给
main.Event.menu。
main.py 将带 data.webui 字典的请求交给 webui.handle_menu_event;普通桌面菜单才加载 gui.py 和 Tkinter,因此无 Tkinter 的环境也能加载网页接口。
webui.py 校验事件名、操作、Bot 列表及参数,调用 utils.py 读取或保存配置。Bot hash 必须来自宿主账号列表,linked hash 与磁盘路径由服务器计算。
- 使用原始
plugin_event.send('webui', request_id, response) 回包。前端检查父窗口、消息类型和请求 ID,再显示结果。
payload.action 支持:
| action | 附加字段 | 用途 |
get_state | 可选 bot_hash | 读取账号列表、全局与选中 Bot 的配置;账号已移除时回退到现存账号 |
save_global | global_enable_switch、global_debug_mode_switch | 保存两个布尔开关 |
save_bot | bot_hash、bot_enable_switch | 保存选中 Bot 的开关 |
save_reply | bot_hash、key、value | 保存现有回复词,文本最多 32768 字 |
reset_reply | bot_hash、key、confirm: true | 恢复默认词或删除扩展词 |
reset_replies | bot_hash、confirm: true | 恢复全部默认回复 |
add_masters / remove_masters | bot_hash、ids | 添加或删除数字字符串 ID,每次 1 至 100 个,每项 1 至 32 位 |
成功回包为 {"ok": true, "state": {...}},业务失败为 {"ok": false, "error": "说明"}。宿主转发失败时的顶层 error 也会显示。接口只返回页面需要的配置字段,不返回整个事件、账号连接信息或认证上下文。
页面运行在 sandbox="allow-scripts" 的 iframe 中。CSS 和 JavaScript 都内置于 index.html,不使用 CDN、localStorage、直接 fetch 或 WebSocket,也不读取父页面认证信息。详细接口与限制见 OlivOS 插件 WebUI 开发文档。
5.7 安装、打包与检查
- 将完整的
YourPluginName/ 复制到 OlivOS 的 plugin/app/,保留 webui.py 与 webui/index.html。
- 修改插件名称和命名空间时,全局替换源码与 HTML 中的
YourPluginName,核对 app.json 无 BOM。
- 重载插件,登录 WebUI,从侧栏入口打开配置页。直接打开 HTML 只能看布局,无法完成宿主通信。
- 在全局页测试保存、刷新;在 Bot 页测试切换账号、回复词保存和恢复、骰主添加与删除。使用主从账号时,确认只有回复词共享,Bot 开关和骰主仍独立。
- GUI 和 WebUI 操作同一套文件,另一界面点击刷新后应能看到已保存值。
- 打包
.opk 时,把 YourPluginName/ 内部的 app.json、Python 文件和 webui/ 放在压缩包根目录;不要漏掉 HTML,也不需要把 tests/、说明文档或本地运行数据打进 .opk。
在 LightPluginTemplate/ 目录中运行后端回归检查:
python -m unittest discover -s tests -v
测试使用临时数据目录与模拟的 OlivOS 事件,覆盖配置隔离、回复词群链、输入校验、保存失败和菜单分发,不连接真实 Bot。完整的登录认证、页面挂载和宿主消息投递仍需在实际 OlivOS 中验证。
5.8 如何定制 HTML 模板
webui/index.html 按“页面配置 → 分区样式 → HTML 表单 → 交互脚本”排列,使用展开的缩进和中文注释。可以按文件开头的修改指南定位需要调整的位置。
常用配置在文件开头的 PAGE_CONFIG:
| 配置项 | 默认值 | 修改用途 |
eventName | YourPluginName_WebUI_Config | 网页业务事件名,必须与 Python 的 config.webui_event 一致 |
title | 轻量级插件配置 | 页面标题与浏览器标题;设为 '' 时使用后端返回的插件名称 |
description | 页面简介文字 | 标题下方的介绍 |
requestTimeoutMs | 15000 | 等待回包的毫秒数,使用正数;超时后不会自动重试保存 |
defaultTab | 'global' | 首次打开全局页;改为 'bot' 则默认打开 Bot 页 |
features.replies | true | 是否显示回复词管理区 |
features.masters | true | 是否显示骰主列表管理区 |
features.directories | true | 是否显示数据目录路径 |
例如只需回复词编辑时,将 features.masters 改为 false,回复词面板会自动占满可用宽度。这些开关只影响界面显示,后端权限、接口和已有数据保持原有含义。隐藏功能区时保留对应 HTML 控件,通过配置开关控制显示即可。
外观参数在 CSS 开头的 :root:
- 修改
--accent-color、--accent-background 调整主题色;深色模式有独立的配色变量。
- 修改
--font-family、--font-size 调整字体。
- 修改
--page-max-width、--page-padding、--card-padding 调整宽度与留白。
- 修改
--card-radius、--control-radius 调整圆角,修改 --reply-editor-height 调整编辑框高度。
- 窄屏断点位于样式末尾的
@media (max-width: 740px),其中覆盖窄屏留白并改为单列布局。
按钮名称和字段标签直接写在 HTML 中,各区块有中文注释。id 用于脚本查找控件;data-control 标记请求期间需要禁用的控件,data-bot-control 额外要求有可用 Bot,data-directory 标记路径展示区。
扩展行为从底部的具名函数入手:
| 要修改的行为 | 对应函数 |
| 全局字段读取、保存 | renderGlobalSettings、handleSaveGlobalClick |
| Bot 开关读取、保存 | renderBotEnableSetting、handleSaveBotClick |
| 切换 Bot、回复词条目 | handleBotSelectionChange、handleReplySelectionChange |
| 回复词编辑、恢复 | handleSaveReplyClick、handleResetReplyClick、handleResetAllRepliesClick |
| 骰主增删 | handleAddMastersClick、handleRemoveMastersClick |
| 控件与函数的对应关系 | bindPageEvents |
| 请求发送与回包 | sendRequest、handleHostReply、runAction |
新增实际配置项时,需要同步增加 HTML 控件、表单读取与保存字段,并在 webui.py 添加对应的状态字段、输入校验和持久化操作。回复词长度与骰主 ID 数量等约束由前后端共同校验,调整时也要保持一致。消息来源和请求 ID 校验属于通信流程的一部分,应在扩展时保留。
6. 文件职责总览
下面按文件逐一说明职责。
6.1 __init__.py
作用:暴露 OlivOS 插件入口模块。
6.2 app.json
作用:定义插件元信息。
主要字段说明:
name:插件显示名。
namespace:插件命名空间。
message_mode:当前模板默认是 olivos_string。
compatible_svn:当前模板默认是 190。
priority:插件优先级。
menu_config:插件菜单注册表,当前模板注册了一个“打开插件配置”菜单项。
webui_config:插件网页入口,当前模板挂载 webui/index.html。
特别提示与兼容性说明:
关于 compatible_svn 与 At 码格式:
当前模板默认使用 compatible_svn >= 190。该字段决定了底层框架下发 At 信息的结构:
- 当设为
190 以下时,框架传递的 At 码形如 [OP:at,id=xxx]。
- 当设为
190 及以上时,框架会在协议端支持的情况下附加昵称信息,格式扩展为 [OP:at,id=xxx,name=xxx](若协议端未提供 name 属性,则回退为基础格式)。
关于 message_mode 与 OP 码标准:
当前模板默认采用 olivos_string(即 OP 码模式),而非传统的 CQ 码模式(对应配置为 old_string)。
- OP 码特征:在底层语法和结构上与 CQ 码保持高度一致,核心区别仅在于标识符的映射转换:将所有的前缀
CQ 替换为 OP,并将参数键名 qq 替换为 id,其余属性与语法约束均未改变。
- 兼容行为:命令输入同时接受
[OP:reply]、[CQ:reply]、[OP:at] 与 [CQ:at],回复输出仍使用 OP 码。
其他部分请参考官方文档:OlivOS 插件开发文档
当前模板的 menu_config 按官方最小模板要求提供 title 与 event 两个字段:
title:OlivOS 插件托盘里显示给用户看的菜单名。
event:点击菜单后传入 Event.menu 的事件名。
为了避免菜单事件名冲突,模板默认采用 命名空间_Menu_编号 的命名方式。
6.3 main.py
作用:纯事件入口。
这里只做这些事:
- 使用相对导入直接拿到
message、utils、webui 模块,桌面菜单触发时才加载 gui
init 时调用 utils.initialize_plugin 和 message.handle_init
init_after 时调用 message.handle_init_after
- 私聊消息转发给
message.handle_private_message
- 群聊消息转发给
message.handle_group_message
- 戳一戳事件转发给
message.handle_poke
- 好友申请事件转发给
message.handle_friend_add_request
- 群邀请事件转发给
message.handle_group_invite_request
- 群成员增加事件转发给
message.handle_group_member_increase
- 心跳事件转发给
message.handle_heartbeat
- 保存事件转发给
message.handle_save
- 网页菜单事件转发给
webui.handle_menu_event,普通菜单转发给 gui.handle_menu_event
这里不做:
原因很简单:入口文件越纯净,后续维护越稳。
这里额外需要注意一个运行时细节:
__init__.py 只显式导出 main,事件入口通过相对导入取得需要的子模块。
- 所以
main.py 不能写成 YourPluginName.message.handle_xxx(...) 这种依赖包属性的形式。
- 在 OlivOS 把插件复制到
plugin/tmp/... 目录后,这类写法很容易出现 module 'YourPluginName' has no attribute 'message'。
- 模板现在改为在
main.py 内部直接相对导入对应模块,从根源上规避这个问题。
6.4 config.py
作用:存放静态常量配置。
这里适合放:
- 插件名称
- 数据目录名称
- 文件名常量
- 默认配置结构
- GUI 页签标题
- WebUI 业务事件名
- 允许的前缀列表
这里不适合放:
换句话说,config.py 负责“定义是什么”,utils.py 负责“怎么使用这些定义”。
6.5 utils.py
作用:提供公共基础能力。
这是整个模板里功能最集中、最基础的模块。
它目前负责:
- 字符串安全处理
- 默认配置合并
- 文件/目录读写
- 调试、信息、错误日志输出
- 插件初始化与 Bot 数据目录初始化
- 运行期
Proc 缓存
- 主动发消息封装
send_message_force
- linked bot 目录初始化
- Bot 配置保持原始账号隔离,回复词、变量和 storage 跟随 linked_bot_hash
- hag_id 构建与拆分
- 前缀解析
- 命令解析
- at 解析
- 骰主 / 配置骰主 / 群主 / 群管判断
- OlivaDiceCore 群开关检查
- 回复词渲染
- 回复发送封装,可分别控制日志记录、at 当前发送者和是否引用触发消息
- Bot 自定义回复词与变量的读写
6.6 message.py
作用:负责消息解析与回复流程。
它是模板中的“消息调度层”,职责包括:
- 接收来自
main.py 的事件
- 读取当前全局配置与 Bot 配置
- 清理连续回复头并解析前缀、命令、参数和多个前置 at
- 只响应指名当前 Bot(含主从账号标识)的命令,群聊回复引用原消息
- 处理 poke 事件示例
- 处理好友申请、群邀请、群成员增加、heartbeat、save 等非消息事件示例
- 判断是否该继续处理消息
- 把命令路由到具体的处理函数
- 按原始 bot hash 读取 bot_config,按 linked_bot_hash 读取自定义回复与变量
- 用
utils.reply_message 发送结果
6.7 message_custom.py
作用:定义模板默认的回复词、变量、帮助文本、GUI 文案说明。
这里的内容是“默认值来源”,不是“运行时存储中心”。
也就是说:
- 模板运行时真正生效的回复词,是
message_custom.json 里的内容。
message_custom.py 提供的是初始默认文本和说明文案。
这样做的好处是:
- 模板作者可以很清楚地知道默认值在哪里。
- 用户改配置文件或在 GUI 里改回复词时,不会反向污染源码默认值。
6.8 gui.py
作用:实现通用 GUI。
它当前只负责:
- 渲染全局配置页
- 渲染 Bot 配置页
- 显示当前 Bot 的基本信息
- 编辑当前 Bot 的配置骰主与 Bot 开关
- 编辑当前 Bot 的自定义回复词
- 提供统一的布局、尺寸、样式辅助方法
它不负责:
6.9 function.py
作用:预留纯业务逻辑模块位置。
当前模板故意不在这个文件里放任何实际函数,因为这里装载插件功能函数。
也就是说,这里是放你的插件所需要实现的功能函数,也就是纯 Python 业务逻辑。
6.10 模板说明文档.md
作用:帮助使用模板的人快速理解整个结构。
也就是这篇文档
6.11 .flake8
作用:用于插件的 lint,进行格式规范化
6.12 webui.py 与 webui/index.html
webui.py:网页请求校验、配置操作分发、页面状态整理和原事件回包。数据读写继续调用 utils.py,不另建一套网页专用配置。
webui/index.html:集中配置 PAGE_CONFIG、外观变量、带分区注释的表单,以及具名的消息桥、表单操作和事件绑定函数。
tests/test_webui.py:脱离宿主验证后端行为与现有配置规则。
7. 配置分层原则
模板当前遵循下面这条非常重要的规则:
7.1 全局配置
所有 Bot 共用:
global_enable_switch
global_debug_mode_switch
7.2 Bot 配置
每个 Bot 独立:
7.3 回复词与变量
运行期按 linked_bot_hash 生效:
storage/
message_custom.json
message_variable.json
这样拆分之后,用户就很容易理解:
- 全局开关是“整个插件都怎样”。
- Bot 配置是“这个 Bot 自己怎样”。
- linked 运行数据是“这个 Bot 实际共用哪一套 storage、变量和回复内容”。
8. 命名约定
模板统一采用下划线命名法。
例如:
global_enable_switch
configured_master_list
build_hag_id
get_linked_bot_hash
虽然 OlivaDiceCore 通常使用小驼峰命名法,但是我还是更喜欢用下划线命名法。
9. 回复词自定义流程
模板里的回复词自定义流程如下:
message_custom.py 提供默认回复词。
utils.initialize_bot_storage 首次启动时,会把 message_custom.json 和 message_variable.json 初始化到对应的 bot_hash 目录。
message.py 在回复时,通过 utils.load_bot_message_custom 读取当前 Bot 对应 linked_bot_hash 目录下的回复词。
- 如果后续通过 GUI、WebUI 或保存接口写入回复词,文件会直接保存到对应的
plugin/data/YourPluginName/<linked_bot_hash>/message_custom.json。
gui.py 与 WebUI 的 Bot 配置页都提供回复词编辑能力。
所以后续你要新增一条可配置回复词,通常只需要做三件事:
- 在
message_custom.py 里补默认文本与说明。
- 在
message.py 里调用这条回复词。
- GUI 和 WebUI 刷新后都会自动把这条 key 列入可编辑列表。
10. 主动发消息与 poke 示例
模板现在额外提供了两类与官方最小模板同用途的能力:
10.1 主动发消息
对应封装:utils.send_message_force(bot_hash, send_type, target_id, message_text, Proc=None)
用途:
- 定时任务主动推送
- 菜单按钮触发后主动发消息
- 后台线程或其他没有现成
plugin_event 的场景
注意事项:
- 传入哪个
bot_hash,模板就会直接使用哪个 bot 发消息。
- 这里不遵循 link,因为 link 只用于数据读写,不代表 bot 自身会跟着切换。
send_type 一般传 group 或 private。
10.2 poke 事件
对应入口:main.Event.poke -> message.handle_poke
默认行为:
- 戳到当前 bot 时回复
reply_poke
- 自己戳自己时保留回复示例
- 仍然受全局开关与 Bot 开关控制
10.3 统一回复封装
对应封装:
utils.reply_message(
plugin_event,
message_text,
record_by_logger=True,
at_sender=False,
quote_reply=False,
)
其中 quote_reply 控制是否引用触发消息,默认关闭:
quote_reply=False:正常发送消息,但不引用触发消息。
quote_reply=True:群聊且消息 ID 有效时,自动追加 [OP:reply,id=消息ID]。
- 私聊或无法取得有效消息 ID 时,即使为
True 也不会追加引用。
11. flake8 校验规则
模板当前按以下规则校验:
[flake8]
extend-ignore = E203
max-line-length = 120
per-file-ignores =
*/__init__.py: F401
当前校验命令:
flake8 --extend-ignore=E203 --max-line-length=120 --per-file-ignores="*/__init__.py:F401" "...\LightPluginTemplate\YourPluginName"
12. 继续扩展时的建议
如果后续你要基于这个模板继续写插件,建议按下面顺序扩展:
- 先在
message_custom.py 补回复词与说明(包括现在模板里面为了演示,都有很多回复没有自定义到 message_custom.py 里面)
- 再在
message.py 增加命令与回复逻辑。
- 当某块业务开始变复杂时,再把纯逻辑拆到
function.py。
- 如果新增的是运行时数据,再写到
utils.py 对应的存储封装里。
- 新增网页配置项时,在
webui.py 增加明确的字段校验与状态字段,并在 webui/index.html 补上控件;继续通过消息桥调用,不直接从网页访问文件或核心 REST API。
这样扩展下来,整个插件就不会被逐渐写乱。
13. 结语
借用此贴的一句话
抛砖引玉的根本目的是引玉!
我希望大家能够根据这份教程写出更好的插件!如果你在实践过程中仍有疑问,欢迎大家在此贴下进行提问,我会一一进行解答
最后,祝各位开发者 bug 越写越少,没有用户在你的酒吧里点炒饭。
让每一个插件都成为 OlivOS 生态的闪耀星辰!