任务流水线(Pipeline)协议
基础格式
任务流水线采用 JSON 格式描述,由若干节点(Node)构成,每个节点包含以下核心属性:
{
"NodeA": {
"recognition": "OCR", // 识别算法
"action": "Click", // 执行动作
"next: [ // 后继节点列表
"NodeB",
"NodeC"
],
// 其他扩展属性...
},
// 其他节点定义...
}
执行逻辑
流程控制机制
任务触发
- 通过 tasker.post_task 接口指定入口节点启动任务
顺序检测
- 对当前节点的 next 列表进行顺序检测
- 依次尝试识别每个子节点配置的 recognition 特征
中断机制
- 当检测到某个子节点匹配成功时,立即终止后续节点检测
- 执行匹配节点的 action 定义的操作
后继处理
- 操作执行完成后,将激活节点切换为当前节点
- 重复执行上述检测流程
终止条件
当满足以下任意条件时,任务流程终止:
- 当前节点的 next 列表为空
- 所有后继节点持续检测失败直至超时
应用示例
场景描述
Android 设置界面存在菜单 显示
/存储
/无障碍
,其中 存储
打开后包含二级菜单 游戏
/应用
。
配置示例
{
"开始示例": {
"next": [
"进入显示",
"进入存储",
"进入无障碍"
]
},
"进入显示": {
"recognition": XXX,
"action": "Click",
// ...
},
"进入存储": {
"recognition": XXX,
"action": "Click",
"next": [
"进入游戏二级菜单",
"进入应用二级菜单"
]
},
"进入无障碍": {
// ...
},
"进入游戏二级菜单": {
"action": "Swipe",
"next": []
},
"进入应用二级菜单": {
// ...
},
// ...
}
执行过程推演
情况一
情况二
属性字段
注:对于必选字段,Pipeline JSON 文件中仍可为空,但需在实际执行前通过接口设置。
recognition
: string
识别算法类型。可选,默认DirectHit
。
可选的值:DirectHit
|TemplateMatch
|FeatureMatch
|ColorMatch
|OCR
|NeuralNetworkClassify
|NeuralNetworkDetect
|Custom
详见 算法类型。action
: string
执行的动作。可选,默认DoNothing
。
可选的值:DoNothing
|Click
|LongPress
|Swipe
|MultiSwipe
|Key
|InputText
|StartApp
|StopApp
|StopTask
|Command
|Custom
详见 动作类型。next
: string | list<string, >
接下来要执行的节点列表。可选,默认空。
按顺序识别 next 中的每个节点,只执行第一个识别到的。interrupt
: string | list<string, >next
中全部未识别到时的候补节点列表,会执行类似中断操作。可选,默认空。
若next
中的节点全部未识别到,则会按序识别该中断列表中的每个节点,并执行第一个识别到的。在后续节点全部执行完成后,重新跳转到该节点来再次尝试识别。
例如: A: { next: [B, C], interrupt: [D, E] }
当 B, C 未识别到而识别到 D 时,会去完整的执行 D 及 D.next。但当 D 的流水线完全执行完毕后。会再次回到节点 A,继续尝试识别 B, C, D, E 。
该字段多用于异常处理,例如 D 是识别 “网络断开提示框”,在点击确认并等待网络连接成功后,继续之前的节点流程。is_sub
: bool
(已在 2.x 版本中废弃,但保留兼容性,推荐使用interrupt
替代)
是否是子节点。可选,默认 false 。
如果是子节点,执行完本节点(及后续 next 等)后,会返回来再次识别本节点 所在的 next 列表。
例如:A.next = [B, Sub_C, D],这里的 Sub_C.is_sub = true,
若匹配上了 Sub_C,在完整执行完 Sub_C 及后续节点后,会返回来再次识别 [B, Sub_C, D] 并执行命中项及后续节点。rate_limit
: uint
识别速率限制,单位毫秒。可选,默认 1000 。
每轮识别next
+interrupt
最低消耗rate_limit
毫秒,不足的时间将会 sleep 等待。timeout
: uintnext
+interrupt
识别超时时间,毫秒。可选,默认 20 * 1000 。
具体逻辑为while(!timeout) { foreach(next + interrupt); sleep_until(rate_limit); }
。on_error
: string | list<string, >
当识别超时,或动作执行失败后,接下来会执行该列表中的节点。可选,默认空。timeout_next
: string | list<string, >
(已在 2.x 版本中废弃,但保留兼容性,推荐使用on_error
替代)
超时后执行的节点列表。可选,默认空。inverse
: bool
反转识别结果,识别到了当做没识别到,没识别到的当做识别到了。可选,默认 false 。
请注意由此识别出的节点,Click 等动作的点击自身将失效(因为实际并没有识别到东西),若有需求可单独设置target
。enabled
: bool
是否启用该 node。可选,默认 true 。
若为 false,其他 node 的 next 列表中的该 node 会被跳过,既不会被识别也不会被执行。pre_delay
: uint
识别到 到 执行动作前 的延迟,毫秒。可选,默认 200 。
推荐尽可能增加中间过程节点,少用延迟,不然既慢还不稳定。post_delay
: uint
执行动作后 到 识别 next 的延迟,毫秒。可选,默认 200 。
推荐尽可能增加中间过程节点,少用延迟,不然既慢还不稳定。pre_wait_freezes
: uint | object
识别到 到 执行动作前,等待画面不动了的时间,毫秒。可选,默认 0 ,即不等待。
连续pre_wait_freezes
毫秒 画面 没有较大变化 才会退出动作。
若为 object,可设置更多参数,详见 等待画面静止。
具体的顺序为pre_wait_freezes
-pre_delay
-action
-post_wait_freezes
-post_delay
。post_wait_freezes
: uint | object
行动动作后 到 识别 next,等待画面不动了的时间,毫秒。可选,默认 0 ,即不等待。
其余逻辑同pre_wait_freezes
。focus
: any
关注节点,会额外产生部分回调消息。可选,默认 null,不产生回调消息。
详见 节点通知。
默认属性
请参考 default_pipeline.jsonDefault
中可设置所有字段的默认值;算法/动作名 的对象中可设置对应算法/动作 的默认参数值。
算法类型
DirectHit
直接命中,即不进行识别,直接执行动作。
TemplateMatch
模板匹配,即“找图”。
该算法属性需额外部分字段:
roi
: array<int, 4> | string
识别区域坐标。可选,默认 [0, 0, 0, 0] ,即全屏。- array<int, 4>: 识别区域坐标,[x, y, w, h],若希望全屏可设为 [0, 0, 0, 0] 。
- string: 填写节点名,在之前执行过的某节点识别到的目标范围内识别。
roi_offset
: array<int, 4>
在roi
的基础上额外移动再作为范围,四个值分别相加。可选,默认 [0, 0, 0, 0] 。template
: string | list<string, >
模板图片路径,需要image
文件夹的相对路径。必选。
所使用的图片需要是无损原图缩放到 720p 后的裁剪。请参考 这里。
支持填写文件夹路径,将递归加载其中所有图片文件。threshold
: double | list<double, >
模板匹配阈值。可选,默认 0.7 。
若为数组,长度需和template
数组长度相同。order_by
: string
结果排序方式。可选,默认Horizontal
。
可选的值:Horizontal
|Vertical
|Score
|Random
。
可结合index
字段使用。index
: int
命中第几个结果。可选,默认 0 。
假设共有 N 个结果,则index
的取值范围为 [-N, N - 1] ,其中负数使用类 Python 的规则转换为 N - index 。若超出范围,则视为当前识别无结果。method
: int
模板匹配算法,即 cv::TemplateMatchModes。可选,默认 5 。
仅支持 1、3、5,可简单理解为越大的越精确,但也会更慢。
详情请参考 OpenCV 官方文档。green_mask
: bool
是否进行绿色掩码。可选,默认 false 。
若为 true,可以将图片中不希望匹配的部分涂绿 RGB: (0, 255, 0),则不对绿色部分进行匹配。
FeatureMatch
特征匹配,泛化能力更强的“找图”,具有抗透视、抗尺寸变化等特点。
该算法属性需额外部分字段:
roi
: array<int, 4> | string
同TemplateMatch
.roi
。roi_offset
: array<int, 4>
同TemplateMatch
.roi_offset
。template
: string | list<string, >
模板图片路径,需要image
文件夹的相对路径。必选。
支持填写文件夹路径,将递归加载其中所有图片文件。count
: int
匹配的特征点的最低数量要求(阈值)。可选,默认 4 。order_by
: string
结果排序方式。可选,默认Horizontal
。
可选的值:Horizontal
|Vertical
|Score
|Area
|Random
。
可结合index
字段使用。index
: int
命中第几个结果。可选,默认 0 。
假设共有 N 个结果,则index
的取值范围为 [-N, N - 1] ,其中负数使用类 Python 的规则转换为 N - index 。若超出范围,则视为当前识别无结果。green_mask
: bool
是否进行绿色掩码。可选,默认 false 。
若为 true,可以将图片中不希望匹配的部分涂绿 RGB: (0, 255, 0),则不对绿色部分进行匹配。detector
: string
特征检测器。可选,默认SIFT
。
目前支持以下算法:- SIFT
计算复杂度高,具有尺度不变性、旋转不变性。效果最好。 - KAZE
适用于 2D 和 3D 图像,具有尺度不变性、旋转不变性。 - AKAZE
计算速度较快,具有尺度不变性、旋转不变性。 - BRISK
计算速度非常快,具有尺度不变性、旋转不变性。 - ORB
计算速度非常快,具有旋转不变性。但不具有尺度不变性。
各算法特点详情可自行进一步查询。
- SIFT
ratio
: double
KNN 匹配算法的距离比值,[0 - 1.0] , 越大则匹配越宽松(更容易连线)。可选,默认 0.6 。
ColorMatch
颜色匹配,即“找色”。
该算法属性需额外部分字段:
roi
: array<int, 4> | string
同TemplateMatch
.roi
。roi_offset
: array<int, 4>
同TemplateMatch
.roi_offset
。method
: int
颜色匹配方式。即 cv::ColorConversionCodes。可选,默认 4 (RGB) 。
常用值:4 (RGB, 3 通道), 40 (HSV, 3 通道), 6 (GRAY, 1 通道)。
详情请参考 OpenCV 官方文档。lower
: list<int, > | list<list<int, >>
颜色下限值。必选。最内层 list 长度需和method
的通道数一致。upper
: list<int, > | list<list<int, >>
颜色上限值。必选。最内层 list 长度需和method
的通道数一致。count
: int
符合的像素点的最低数量要求(阈值)。可选,默认 1。order_by
: string
结果排序方式。可选,默认Horizontal
。
可选的值:Horizontal
|Vertical
|Score
|Area
|Random
。
可结合index
字段使用。index
: int
命中第几个结果。可选,默认 0 。
假设共有 N 个结果,则index
的取值范围为 [-N, N - 1] ,其中负数使用类 Python 的规则转换为 N - index 。若超出范围,则视为当前识别无结果。connected
: bool
是否是相连的点才会被计数。可选,默认 false 。
若为是,在完成颜色过滤后,则只会计数像素点 全部相连 的最大块。
若为否,则不考虑这些像素点是否相连。
OCR
文字识别。
该算法属性需额外部分字段:
roi
: array<int, 4> | string
同TemplateMatch
.roi
。roi_offset
: array<int, 4>
同TemplateMatch
.roi_offset
。expected
: string | list<string, >
期望的结果,支持正则。必选。threshold
: double
模型置信度阈值。可选,默认 0.3 。replace
: array<string, 2> | list<array<string, 2>>
部分文字识别结果不准确,进行替换。可选。order_by
: string
结果排序方式。可选,默认Horizontal
。
可选的值:Horizontal
|Vertical
|Area
|Length
|Random
。
可结合index
字段使用。index
: int
命中第几个结果。可选,默认 0 。
假设共有 N 个结果,则index
的取值范围为 [-N, N - 1] ,其中负数使用类 Python 的规则转换为 N - index 。若超出范围,则视为当前识别无结果。only_rec
: bool
是否仅识别(不进行检测,需要精确设置roi
)。可选,默认 false 。model
: string
模型 文件夹 路径。使用model/ocr
文件夹的相对路径。可选,默认为空。
若为空,则为model/ocr
根目录下的模型文件。
文件夹中需要包含rec.onnx
,det.onnx
,keys.txt
三个文件。
NeuralNetworkClassify
深度学习分类,判断图像中的 固定位置 是否为预期的“类别”。
该算法属性需额外部分字段:
roi
: array<int, 4> | string
同TemplateMatch
.roi
。roi_offset
: array<int, 4>
同TemplateMatch
.roi_offset
。labels
: list<string, >
标注,即每个分类的名字。可选。
仅影响调试图片及日志等,若未填写则会填充 "Unknown" 。model
: string
模型文件路径。使用model/classify
文件夹的相对路径。必选。
目前仅支持 ONNX 模型,参考 NNClassify 食谱。expected
: int | list<int, >
期望的分类下标。order_by
: string
结果排序方式。可选,默认Horizontal
。
可选的值:Horizontal
|Vertical
|Score
|Random
。
可结合index
字段使用。index
: int
命中第几个结果。可选,默认 0 。
假设共有 N 个结果,则index
的取值范围为 [-N, N - 1] ,其中负数使用类 Python 的规则转换为 N - index 。若超出范围,则视为当前识别无结果。
举例:例如画面中 固定位置 可能出现 猫、狗、老鼠,我们训练了支持该三分类的模型。
希望识别到 猫 或 老鼠 才点击,而识别到 狗 不点击,则相关字段为:
{
"labels": ["Cat", "Dog", "Mouse"],
"expected": [0, 2]
}
注意这些值需要与模型实际输出相符。
NeuralNetworkDetect
深度学习目标检测,高级版“找图”。
与分类器主要区别在于“找”,即支持任意位置。但通常来说模型复杂度会更高,需要更多的训练集、训练时间,使用时的资源占用(推理开销)也会成倍上涨。
该算法属性需额外部分字段:
roi
: array<int, 4> | string
同TemplateMatch
.roi
。roi_offset
: array<int, 4>
同TemplateMatch
.roi_offset
。labels
: list<string, >
标注,即每个分类的名字。可选。
仅影响调试图片及日志等,若未填写则会填充 "Unknown" 。model
: string
模型文件路径。使用model/detect
文件夹的相对路径。必选。
目前支持 YoloV8 ONNX 模型,其他同样输入输出的 Yolo 模型理论上也可以支持,但未经测试。
训练参考 NNDetect 食谱。expected
: int | list<int, >
期望的分类下标。threshold
: double | list<double, >
模型置信度阈值。可选,默认 0.3 。
若为数组,长度需和expected
数组长度相同。order_by
: string
结果排序方式。可选,默认Horizontal
。
可选的值:Horizontal
|Vertical
|Score
|Area
|Random
。
可结合index
字段使用。index
: int
命中第几个结果。可选,默认 0 。
假设共有 N 个结果,则index
的取值范围为 [-N, N - 1] ,其中负数使用类 Python 的规则转换为 N - index 。若超出范围,则视为当前识别无结果。
举例:例如画面中可能出现 猫、狗、老鼠,我们训练了支持该三分类的检测模型。
希望检测到 猫 或 老鼠 才点击,而识别到 狗 不点击,则相关字段为:
{
"labels": ["Cat", "Dog", "Mouse"],
"expected": [0, 2]
}
注意这些值需要与模型实际输出相符。
Custom
执行通过 MaaResourceRegisterCustomRecognition
接口传入的识别器句柄。
该算法属性需额外部分字段:
custom_recognition
: string
识别名,同注册接口传入的识别名。同时会通过MaaCustomRecognitionCallback
.custom_recognition_name
传出。必选。custom_recognition_param
: any
识别参数,任意类型,会通过MaaCustomRecognitionCallback
.custom_recognition_param
传出。可选,默认空 json,即{}
。roi
: array<int, 4> | string
同TemplateMatch
.roi
,会通过MaaCustomRecognitionCallback
.roi
传出。可选,默认 [0, 0, 0, 0] 。roi_offset
: array<int, 4>
同TemplateMatch
.roi_offset
。
动作类型
DoNothing
什么都不做。
Click
点击。
该动作属性需额外部分字段:
target
: true | string | array<int, 4>
点击的位置。可选,默认 true 。- true: 点击本节点中刚刚识别到的目标(即点击自身)。
- string: 填写节点名,点击之前执行过的某节点识别到的目标。
- array<int, 4>: 点击固定坐标区域内随机一点,[x, y, w, h],若希望全屏可设为 [0, 0, 0, 0] 。
target_offset
: array<int, 4>
在target
的基础上额外移动再点击,四个值分别相加。可选,默认 [0, 0, 0, 0] 。
LongPress
长按。
该动作属性需额外部分字段:
target
: true | string | array<int, 4>
长按的位置。可选,默认 true 。值同上述Click
.target
。target_offset
: array<int, 4>
在target
的基础上额外移动再长按,四个值分别相加。可选,默认 [0, 0, 0, 0] 。duration
: uint
长按持续时间,单位毫秒。可选,默认 1000 。
Swipe
线性滑动。
该动作属性需额外部分字段:
begin
: true | string | array<int, 4>
滑动起点。可选,默认 true 。值同上述Click
.target
。begin_offset
: array<int, 4>
在begin
的基础上额外移动再作为起点,四个值分别相加。可选,默认 [0, 0, 0, 0] 。end
: true | string | array<int, 4>
滑动终点。可选,默认 true 。值同上述Click
.target
。end_offset
: array<int, 4>
在end
的基础上额外移动再作为终点,四个值分别相加。可选,默认 [0, 0, 0, 0] 。duration
: uint
滑动持续时间,单位毫秒。可选,默认 200 。
MultiSwipe
多指线性滑动。
该动作属性需额外部分字段:
swipes
: list<object,>
多个滑动的数组。必选。
数组元素顺序没有影响,只基于starting
确定顺序。starting
: uint
滑动起始时间,单位毫秒。可选,默认 0 。MultiSwipe
额外字段,该滑动会在本 action 中第starting
毫秒才开始。begin
: true | string | array<int, 4>
滑动起点。可选,默认 true 。值同上述Click
.target
。begin_offset
: array<int, 4>
在begin
的基础上额外移动再作为起点,四个值分别相加。可选,默认 [0, 0, 0, 0] 。end
: true | string | array<int, 4>
滑动终点。可选,默认 true 。值同上述Click
.target
。end_offset
: array<int, 4>
在end
的基础上额外移动再作为终点,四个值分别相加。可选,默认 [0, 0, 0, 0] 。duration
: uint
滑动持续时间,单位毫秒。可选,默认 200 。
举例:
{
"A": {
"action": "MultiSwipe",
"swipes": [
{
"begin": xxx,
"end": xxx
},
{
"starting": 500,
"begin": xxx,
"end": xxx
}
]
}
}
Key
按键。
InputText
输入文本。
input_text
: string
要输入的文本,部分控制器仅支持 ascii 。
StartApp
启动 App 。
该动作属性需额外部分字段:
package
: string
启动入口。必选。
需要填入 package name 或 activity ,例如com.hypergryph.arknights
或com.hypergryph.arknights/com.u8.sdk.U8UnityContext
。
StopApp
关闭 App 。
该动作属性需额外部分字段:
package
: string
要关闭的程序。必选。
需要填入 package name ,例如com.hypergryph.arknights
。
StopTask
停止当前任务链(MaaTaskerPostTask 传入的单个任务链)。
Command
执行命令。
该动作属性需额外部分字段:
exec
: string
执行的程序路径。必选。args
: list<string,>
执行的参数。可选。
支持部分运行期参数替换:{ENTRY}
: 任务入口名。{NODE}
: 当前节点名。{IMAGE}
: 截图保存到文件的路径。该文件在进程退出前删除,若要持久保存请自行复制。{BOX}
: 识别命中的目标,格式为[x, y, w, h]
。{RESOURCE_DIR}
: 最后一次加载的资源文件夹路径。{LIBRARY_DIR}
: MaaFW 库所在的文件夹路径。
detach
: bool
分离子进程,即不等待子进程执行完成,直接继续执行后面的任务。可选,默认 false。
举例:
{
"NodeA": {
"action": "Command",
"exec": "Python",
"args": [
"{RESOURCE_DIR}/my_script/test.py",
"Haha",
"{IMAGE}",
"{NODE}",
"{BOX}"
]
},
"NodeB": {
"action": "Command",
"exec": "{RESOURCE_DIR}/my_exec/my_exec.exe"
}
}
实际将会执行命令
# NodeA
Python C:/MaaXXX/resource/my_script/test.py Haha C:/temp/123.png NodeA [0,0,0,0]
# NodeB
C:/MaaXXX/resource/my_exec/my_exec.exe
Custom
执行通过 MaaResourceRegisterCustomAction
接口传入的动作句柄。
该动作属性需额外部分字段:
custom_action
: string
动作名,同注册接口传入的识别器名。同时会通过MaaCustomActionCallback
.custom_action_name
传出。必选。custom_action_param
: any
动作参数,任意类型,会通过MaaCustomActionCallback
.custom_action_param
传出。可选,默认空 json,即{}
。target
: true | string | array<int, 4>
同Click
.target
,会通过MaaCustomActionCallback
.box
传出。可选,默认 true 。target_offset
: array<int, 4>
同Click
.target_offset
。
等待画面静止
等待画面静止。需连续一定时间 画面 没有较大变化 才会退出动作。
字段值为 uint 或 object,举例:
{
"A": {
"pre_wait_freezes": 500
},
"B": {
"pre_wait_freezes": {
// more properties ...
}
}
}
若值为 object,可设置部分额外字段:
time
: uint
连续time
毫秒 画面 没有较大变化 才会退出动作。可选,默认 1 。target
: true | string | array<int, 4>
等待的目标。可选,默认 true。值同上述Click
.target
。target_offset
: array<int, 4>
在target
的基础上额外移动再作为等待目标,四个值分别相加。可选,默认 [0, 0, 0, 0] 。threshold
: double
判断“没有较大变化”的模板匹配阈值。可选,默认 0.95 。method
: int
判断“没有较大变化”的模板匹配算法,即 cv::TemplateMatchModes。可选,默认 5 。
同TemplateMatch
.method
。rate_limit
: uint
识别速率限制,单位毫秒。可选,默认 1000 。
每次识别最低消耗rate_limit
毫秒,不足的时间将会 sleep 等待。timeout
: uint
识别超时时间,毫秒。可选,默认 20 * 1000 。
节点通知
详见 回调协议(还没写 x