| title | Pipeline 编写指南 |
|---|---|
| order | 2 |
| icon | ri:git-branch-fill |
本项目由 create-maa-project 的 pipeline 模板生成,Pipeline 使用经典写法:recognition / action 为字符串、参数平铺在节点顶层:
{
"NodeName": {
"recognition": "TemplateMatch",
"template": "button.png",
"threshold": 0.8,
"action": {"type": "Click"}
}
}它与官方文档中 v2 协议的嵌套写法(recognition: {"type": ..., "param": {...}})结构等价。运行渠道为 MaaFramework stable(见 maa-project.json 的 maafw 字段,版本随渠道自动更新;发布包复用客户端那份原生库,故 runtimes/ 与 pyproject.toml 里 pin 的 maafw 版本须保持一致),字段合法性以 tools/schema/ 的 schema 与 pnpm check:schema 为准;通用协议细节可对照 MaaFramework Pipeline 协议。
Pipeline 节点用 JSON 定义,每个节点描述一个识别 → 动作 → 跳转的完整步骤:
{
"NodeName": {
"recognition": "TemplateMatch",
"roi": [
100,
200,
80,
50
],
"template": "button.png",
"threshold": 0.8,
"action": {"type": "Click"},
"next": [
"NextNode",
"FallbackNode"
]
}
}| 类型 | 适用场景 | 说明 |
|---|---|---|
| TemplateMatch | 静态 UI 元素 | OpenCV 模板匹配,图片放 image/ 目录,threshold 默认 0.7;template 支持数组(多模板任一命中即可,适合入口图存在多种样式/状态时兜底) |
| OCR | 动态文本 | PaddleOCR v5,expected 支持正则,roi 指定文字区域 |
| DirectHit | 路由分发 | 始终匹配成功,用于 next 分支控制 |
| Custom | 复杂逻辑 | Python 自定义识别,通过 @AgentServer.custom_recognition() 注册 |
| ColorMatch | 颜色过滤 | 配合 OCR 的 color_filter 字段使用,过滤背景干扰 |
| 类型 | 说明 |
|---|---|
| Click | 点击识别位置。target: true 点中心,target: [x,y,w,h] 偏移坐标 |
| DoNothing | 仅做识别路由,不执行操作 |
| Swipe | 滑动。param.begin / param.end / param.duration |
| Custom | Python 自定义动作,通过 @AgentServer.custom_action() 注册 |
| 字段 | 说明 |
|---|---|
pre_delay / post_delay |
动作前/后等待(毫秒);应避免使用,优先用 pre_wait_freezes / post_wait_freezes 或中间识别节点替代 |
post_wait_freezes |
等待画面静止不动(替代固定延迟,更智能) |
max_hit |
最大命中次数,超过后节点被跳过。用于循环出现的元素 |
timeout |
识别超时(ms),默认 20000 |
only_rec |
仅识别不动作(用于 TemplateMatch 时需注意 schema) |
focus |
命中/失败时显示日志通知 |
color_filter |
OCR 预处理颜色过滤,值为 ColorMatch 节点名 |
- 节点名称用点分隔层级,如
FarmResources.Start、ClaimRewards.CheckDaily - 前缀用功能模块英文名:
PVP.、BattlePass.、Common. - JumpBack 节点不加
next字段
模板图片统一放在 resource/base/image/ 下:
- 目录组织:按 pipeline 模块分子目录(如
image/event_stage/、image/farm_resources/);多模块共用的公共图直接放在image/根目录 - 文件命名:小写
snake_case,如flare_title.png、no_stamina.png、main_option.png - 区服差异图:放
resource/bilibili/image/、resource/taptap/image/对应目录(加载顺序见interface.json的resource字段) - 制作规范:以 1280×720 截图裁剪,尺寸适中(约 50×50 到 200×200),过大容易误匹配;ROI 与分辨率基线见 项目与资源约定
- 路径写法:Pipeline JSON 中
template写相对image/目录的路径,统一使用正斜杠(如event_stage/flare_title.png)
Pipeline 节点支持两类注释/占位字段(schema 已支持,不会报错):
doc/*_doc:节点功能说明*_code/code:必填字段占位,用于"模板路径统一在interface.json配置、不硬编码进 pipeline"的场景
"EnterBattle": {
"doc": "进入作战界面",
"template_code": "在 interface.json 的 pipeline_override 中配置 template",
"recognition": "TemplateMatch",
"roi": [885, 123, 340, 183],
"action": { "type": "Click" },
"next": ["CheckBattleInterface"]
}:::tip 为什么需要 *_code 占位?
TemplateMatch 的 template 字段是必填项,但若模板路径由 interface.json 的 pipeline_override 统一注入(换分辨率/换区服时只改一处),pipeline 文件中就没有可填的值。此时用 template_code 占位,既过 schema 校验,又提示开发者"模板在别处配置"。
:::
适合有明确先后顺序的操作(如启动游戏):
"LaunchGame": {
"recognition": "DirectHit",
"action": {
"type": "DoNothing",
"param": { "package": "com.phxh.official.nld" }
},
"next": ["ClickToStart"]
},
"ClickToStart": {
"recognition": "TemplateMatch",
"template": "click_to_start.png",
"action": { "type": "Click" },
"post_delay": 2000,
"next": ["DailyLoginReward", "CheckHomePage"]
}"HubNode": {
"recognition": "DirectHit",
"action": { "type": "DoNothing" },
"next": ["BranchA", "BranchB"]
}next 是 OR 逻辑:从上到下依次尝试,第一个识别成功的节点被执行。
适合需要反复进入子模块的场景(如领取奖励循环):
"ClaimRewards.MainHub": {
"recognition": "DirectHit",
"action": { "type": "DoNothing" },
"next": [
"[JumpBack]DispatchClaim.Start",
"[JumpBack]ClaimRewards.Start",
"[JumpBack]BattlePass.Start",
"[JumpBack]Mailbox.Start"
]
}[JumpBack] 节点命中后执行动作,然后跳回父节点重新尝试 next 列表。只有非 JumpBack 节点能退出循环。
JumpBack 叶子节点不要带 next 字段——执行完即回跳,路由由父节点的 next 控制。若该节点确实需要子链(例如枢纽节点本身),其 next 会被正常展开,整条子链执行完毕后才会回跳;命中节点「动作失败」时走 on_error 且不回跳(详见官方协议)。
本项目在此基础上提供了跨任务复用的通用回主页枢纽(Common.EnsureHome):把已知界面的处理节点放进枢纽的 next,调用方在 next 末位挂 [JumpBack]Common.EnsureHome,即可获得「卡在任何界面都能回主页再继续」的能力。枢纽定义、四条约束与已接入的任务见通用节点与回主页枢纽。
"BattleStage": {
"recognition": "DirectHit",
"action": { "type": "DoNothing" },
"next": [
"[JumpBack]ClickVictory",
"[JumpBack]ClickItemDialog",
"QuickBattle"
]
}战斗胜利 → 点击 → 跳回检测 → 再次战斗 → 体力不足时退出。
tasks/*.json 中用 pipeline_override 在运行时修改节点行为:
"pipeline_override": {
"FarmResources.Start": {
"next": ["FarmResources.ResourceCollect"]
},
"FarmResources.ClickStage": {
"custom_recognition_param": "{\"stage_name\": \"1-1\", \"stage_index\": 1, \"resource_type\": \"特别军费行动\"}"
}
}可以修改 next、roi、threshold、custom_action_param 等任意字段。
"ClaimButton": {
"max_hit": 5,
"recognition": "TemplateMatch",
...
}最多命中 5 次后跳过,适合循环出现的领取按钮。max_hit 跨会话计数。
对于颜色鲜明的文本,可以用 ColorMatch 预先过滤背景,提升 OCR 准确率:
"GoldTextFilter": {
"recognition": "ColorMatch",
"method": 4,
"lower": [[38, 31, 30]],
"upper": [[50, 44, 44]],
"count": 1000,
"connected": true
}在 OCR 节点中引用:
JOCR(roi=(x, y, w, h), color_filter="GoldTextFilter")分为两种兜底,按节点语义区分,禁止混用:
当节点的识别失败属于正常流程分支时(如"没找到每日徽章 → 检查每周徽章"),把兜底节点放在父节点的 next 列表中当前节点之后,利用 MaaFW 的顺序 OR 语义自动触达。
在 MaaFW 中,父节点识别成功后,会依次尝试 next 列表中的每个子节点,直到有一个子节点的识别成功为止。若前面的子节点识别失败,框架自动回落到下一个子节点继续尝试。因此,将兜底节点放在 next 列表末尾,即可在"前面所有正常分支都识别失败"时自然触达。
"ConfirmInterface": {
"next": [
"CheckDaily", // 先尝试检查每日徽章
"CheckWeekly", // CheckDaily 识别失败时,自动回落到每周徽章
"CheckMilitary" // 两者都失败时,再检查军旅徽章
]
}注意:上述"识别失败继续尝试后续节点"的行为发生在父节点的 next 列表层面。对于单个节点自身而言,其 next 字段仅在"该节点识别成功"后才会被进入;若该节点自身识别失败,则直接进入其 on_error(如有)或停止。因此,"否定检查"模式(识别成功=停止、识别失败=继续)无法通过单个节点的 next 实现,需保留 on_error(见下文)。
当兜底路径仅在异常/意外状态触发时(如关卡 UI 无法识别、快战按钮消失),保留 on_error 并加标记:
"FarmResources.Start": {
"desc": "从主页进入作战界面 [错误兜底: FarmResources.EnsureHome]",
"recognition": "TemplateMatch",
"template": "farm_resources/battle_entry.png",
"on_error": ["FarmResources.EnsureHome"]
}这类节点触发时说明遇到了预期外的 UI 状态,on_error 截图对调试有价值,应保留。
对于"识别到 X 就停止,没识别到就继续"的节点(如"检查关卡是否锁住"),不要依赖候选自身的 on_error 兜底:当该节点是父节点 next 列表中的候选时,识别失败只表示"候选未命中",不会触发节点自身的 on_error,列表若无后续候选会整列表失败并重试,造成死循环超时(实机验证:FarmResources.SelectSkillStage 曾因此循环 21 次 × 20s 后任务失败)。
正确写法是并列候选模式——把"继续"节点放在 next 列表中、检查节点之后,让它自然回落:
"SelectStage": {
"recognition": "DirectHit",
"next": [
"CheckLocked", // 命中=锁定停止;未命中→回落下一候选
"ClickStage" // 未命中时的继续分支(实际点击进入)
]
},
"CheckLocked": {
"recognition": "TemplateMatch",
"template": "lock_icon.png",
// 不设 on_error(候选位置不生效,保留反而误导)
"focus": {
"Node.Recognition.Succeeded": "已锁,停止",
"Node.Recognition.Failed": "未锁,继续"
}
}注意:CheckLocked 作为候选时会先评估一次,失败后自动尝试下一个候选(ClickStage),两者都失败才整列表失败。这种节点在 desc 中注明"否定检查(并列候选)"以辅助理解。
- 优先用
wait_freezes而非固定延迟 — 导航点击后画面可能仍在过渡,用post_wait_freezes等待画面静止比固定post_delay更可靠;仅在加载动画无法冻结时才用固定延迟 - OCR expected 是正则表达式 —
".*"匹配任意,"^text$"精确匹配 - ROI 以 1280x720 为基准 — 坐标
[x, y, w, h] - 兜底策略 — 流程兜底(正常可预期的走不通)放
next末尾;真错误兜底(异常状态)保留on_error并加[错误兜底]标记。详见上方"兜底策略"一节 next顺序重要 — 按"必须先判断的"优先 —next按优先级从高到低排列:先放需要优先排除的界面(如弹窗、错误提示),再放常规分支。反例:若主界面节点(识别频率高)排在弹窗节点前面,弹窗出现时主界面节点先命中,流程会卡死在错误界面。同优先级时按匹配频率排序,匹配快的放前面- 截图不全时加 roi — 缩小识别范围提升速度和准确率
- 清体力模式使用
ReduceBattleCount— 通过 Custom ActionReduceBattleCount动态减少战斗次数