XZCLOUD · 插件开发文档
版本 v1.0.1 · 本平台支持两类插件:PHP 插件(原生)与 Python 插件(AstrBot 原生写法,强兼容) 每次插件能力变更必须同步更新本文档
1. 插件布局
text
plugins/ # PHP 插件
└── <作者>/<插件名>/
├── main.php # 入口(必须)
├── metadata.json # 元数据(必须)
└── _conf_schema.json # 配置 schema(可选,后台自动渲染表单)
plugins_py/ # Python 插件(AstrBot 原生写法)
└── <作者>/<插件名>/
├── main.py # 入口(必须)
├── metadata.json # 元数据(必须)
└── _conf_schema.json # 配置 schema(可选)创建后在后台「插件管理 → 重新扫描目录」即可看到并启用。也可以打成 zip 在「插件市场」在线安装。
metadata.json
json
{
"name": "HelloWorld",
"desc": "打招呼示例插件",
"version": "1.0.0",
"author": "XZQQ",
"repo": "https://github.com/your/repo"
}_conf_schema.json(可选)
json
{
"reply_prefix": { "type": "string", "description": "回复前缀", "default": "【XZCLOUD】" },
"max_len": { "type": "int", "description": "最大长度", "default": 100 },
"enabled_extra":{ "type": "bool", "description": "附加功能", "default": true }
}支持 type: string|int|float|bool,后台「插件管理 → 配置」自动生成表单,保存后热加载。
2. PHP 插件
2.1 最小示例(plugins/XZQQ/HelloWorld/main.php)
php
<?php
declare(strict_types=1);
use XZQQ\Event\MessageChain;
use XZQQ\Event\MessageEvent;
use XZQQ\Plugin\Filter;
use XZQQ\Plugin\PluginBase;
return new class extends PluginBase {
#[Filter\Command('hello', alias: ['hi', '你好'],
description: '打招呼',
usage: '/hello [名字]')]
public function onHello(MessageEvent $event): MessageChain
{
$name = $event->arg('name', '世界'); // 带参指令自动注入
return MessageChain::plain($this->config('reply_prefix', '【XZCLOUD】') . " 你好,{$name}!");
}
#[Filter\Command('dice')]
public function onDice(MessageEvent $event): MessageChain
{
return MessageChain::plain('🎲 你掷出了 ' . random_int(1, 6) . ' 点');
}
#[Filter\Command('admin', permission: 'admin')]
#[Filter\PermissionType('admin')]
public function onAdmin(MessageEvent $event): MessageChain
{
return MessageChain::plain('管理员专属指令');
}
#[Filter\Regex('/天气|下雨|气温/u')]
public function onWeather(MessageEvent $event): MessageChain
{
return MessageChain::plain('今天晴,25℃');
}
#[Filter\EventMessageType('GROUP_MESSAGE')]
public function onGroup(MessageEvent $event): MessageChain
{
if (!$event->isAtBot()) return MessageChain::empty(); // 未@不处理
return MessageChain::at($event->senderId)->plain(' 在的');
}
};要点:
main.phpreturn 一个PluginBase子类实例(匿名类即可)- 指令参数:带参方法(除
MessageEvent外的形参)自动从消息文本按顺序注入 - 返回值:
MessageChain(也可void不回复) $this->config('key', $default)读取_conf_schema.json配置
2.2 过滤器(PHP 属性)
| 属性 | 参数(按序) | 说明 |
|---|---|---|
#[Filter\Command] | name, alias[], description, usage, needAt, permission | 指令;前缀 / ! ! # # . .;needAt 群聊需@ |
#[Filter\CommandGroup] | name, alias[] | 指令组(子指令 group sub) |
#[Filter\Regex] | pattern | 正则匹配,捕获组注入形参 |
#[Filter\EventMessageType] | GROUP_MESSAGE/PRIVATE_MESSAGE/ALL | 事件类型过滤 |
#[Filter\PlatformAdapterType] | napcat/qqofficial/telegram/discord | 平台过滤 |
#[Filter\PermissionType] | admin/everyone/... | 权限过滤 |
#[Filter\CustomFilter] | 自定义过滤器类 | 高级扩展 |
2.3 MessageChain 常用构造
php
MessageChain::plain('文本');
MessageChain::image($url, $name);
MessageChain::video($url, $name);
MessageChain::record($url); // 语音
MessageChain::file($url, $name);
MessageChain::face(123); // QQ 表情 ID
MessageChain::at($userId);
MessageChain::atAll();
MessageChain::reply($messageId);
MessageChain::empty(); // 不回复2.4 生命周期与调试
onLoad(array $meta):插件加载时(每次进程启动)onInit():配置注入后- 后台「插件管理」显示
plugins.error(加载异常会写入,便于定位) - CLI:
php bin/xzqq plugin list查看已加载插件与指令
3. Python 插件(AstrBot 原生写法 · 强兼容)
3.1 兼容原理
平台内置 bridge/shim/astrbot/,提供与 AstrBot 同名同路径 的 API 包(from astrbot.api import star 等)。桥接进程把它放在 sys.path[0],因此 AstrBot 插件源码几乎原样可运行,无需改造、无需安装 AstrBot 依赖。
桥接进程通过 ws://127.0.0.1:9527/ws?role=bridge&token=<bridge_token> 与 PHP 守护进程互联:
- 插件加载/卸载/启用态由 PHP 侧
plugins表驱动(3 秒 diff 推送) - 插件回复经
result帧回传,由 PHP 侧重建消息链并发送
3.2 最小示例(plugins_py/XZQQ/HelloWorldPy/main.py)
python
from astrbot.api import star
from astrbot.api.event import filter, AstrMessageEvent
@star.register(name="helloworld_py", desc="打招呼示例", version="1.0.0", author="XZQQ")
class Main(star.Star):
'''插件主类:类名建议叫 Main;可带 (context) 形参接收上下文'''
def __init__(self, context):
super().__init__(context)
self.prefix = self.context.get_config().get("reply_prefix", "【XZCLOUD】")
@filter.command("hello", alias={"你好", "hi"})
async def hello(self, event: AstrMessageEvent, name: str = "世界"):
'''带参指令:name 自动从指令参数注入;默认值支持'''
yield event.plain_result(f"{self.prefix} 你好,{name}!")
@filter.command("ping")
async def ping(self, event: AstrMessageEvent):
event.stop_event() # 阻止后续插件处理
yield event.plain_result("pong")
@filter.regex(r"^(?:今天|明天)?天气.*")
async def weather(self, event: AstrMessageEvent):
yield event.plain_result("今天晴,25℃")
@filter.permission_type(filter.PermissionType.ADMIN)
@filter.command("pyinfo")
async def pyinfo(self, event: AstrMessageEvent):
yield event.plain_result("管理员信息")
async def initialize(self): # 生命周期:加载完成后调用
pass
async def terminate(self): # 生命周期:卸载/停用时调用
pass3.3 兼容 API 速查
| AstrBot 原生写法 | 本平台状态 |
|---|---|
from astrbot.api import star / @star.register | ✅ |
from astrbot.api.event import filter, AstrMessageEvent | ✅ |
@filter.command(name, alias={...}) / command_group / regex | ✅ |
@filter.event_message_type(EventMessageType.X) | ✅ |
@filter.platform_adapter_type(PlatformAdapterType.X) | ✅(napcat→AIOCQHTTP 等已映射) |
@filter.permission_type(PermissionType.ADMIN) | ✅(管理员名单在后台 settings.admin_ids) |
GreedyStr(吃掉剩余全部参数) | ✅ |
event.send(chain) / event.plain_result() / event.chain_result() / event.make_result() | ✅ |
event.image_result()/at_result()/reply_result()/face_result() | ✅ |
event.stop_event() / 返回 EventResultType | ✅ |
from astrbot.core.star... 等 core 导入路径 | ✅(已做 re-export) |
消息组件 Plain/Image/At/Reply/Face/Node/Json... | ✅ |
initialize()/terminate() 生命周期 | ✅ |
self.context.get_config() | ✅(读取本插件配置 + 全局配置) |
| LLM / Provider / TTS 等 AI 能力 | ❌ 本平台未内置,需自行实现 HTTP 调用 |
| 自定义 filter 类 | ⚠️ 可运行,但指令无法静态上报到后台 |
3.4 指令前缀与参数
- 前缀:
/ ! ! # # . .(与 AstrBot 一致) - 匹配逻辑与 PHP 侧
PluginManager::matchCommand()完全一致 - 参数按方法签名注入:字符串按空格切分;缺失必填参数则不触发;
GreedyStr聚合剩余 - 指令元数据(名称/别名/说明)通过 AST 静态扫描在 hello 时上报,后台「指令管理」可见并可同步到 QQ 官方
3.5 调试
bash
cd bridge
python3 astrbot_bridge.py --selftest # 本地自检:强制加载插件并回放 3 条测试消息
python3 astrbot_bridge.py --verbose # 前台运行并打印收发帧桥接配置 bridge/config.json:daemon_host/daemon_port/path/bridge_token/plugins_dir/handler_timeout;令牌须与 PHP 侧 config/app.php 的 plugin.bridge_token 一致。
4. 推荐实践
- 指令必须写
description/usage,后台指令面板与/help才能正常展示 - 敏感配置放
_conf_schema.json,由后台表单管理,勿硬编码密钥 - 网络请求加超时(插件 handler 有 30s 总超时,见
handler_timeout) - 群聊指令建议
needAt: true,避免打扰 - 插件的重活放后台线程/队列,勿阻塞事件循环(Python 侧用
await,PHP 侧同步执行需自行控制耗时)