MaaAssistantArknights / MaaAssistantArknights/maa-cli
RFC: Config v2 (欢迎有兴趣的朋友提出意见)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 117
- Forks
- 39
- PR merge metrics
- No merged PRs in 30d
Description
# Config V2 设计规范
## 概述
- **Profile**(`profiles/*.toml`):定义*如何*连接——连接方式、客户端与可选的行为/进阶配置
- **Task**(`tasks/*.yaml`):定义*做什么*——带条件和覆盖的任务列表
在下面的例子里面,由于 Profile 更扁平,适合 TOML;Task 嵌套很深,更适合 YAML。但是,新版本依然支持 TOML,YAML,JSON 三种格式混合使用,你可以选择你喜欢的格式。
### 设计目标
V2 的目标有两个:
- **对用户更直观**:Profile 负责描述“如何连接”,Task 负责描述“做什么”,同时不再直接对接 MaaCore API。`client_type` 等运行上下文不再散落在任务参数中;任务文件也不再依赖多种隐式变换和不一致的规则,尤其体现在生命周期处理、参数传播,以及 variants 的激活逻辑上。
- **对实现更直接**:配置边界更清晰,`client_type` 的来源唯一,自动生命周期与手写生命周期的语义分离,单 Session 与多 Session 也分别建模。这样可以避免在运行时反复提取、合并、回填和兜底,减少隐式规则和特殊分支。
### 兼容性
Profile 和 Task 都有一个顶层字段 `version`
```toml
version = 2
```
- `version = 2` → 按 V2 解析
- `version = 1` → 按 V1 解析,不警告 (如果你暂时不想迁移的话,但是后续 V1 会删除,所以最终还是要迁移)
- 无 `version` → 按 V1 解析 + 弃用警告
Profile 和 Task 必须同时升级,不保证交叉兼容,必须是 Profile V1 + Task V1 或者 Profile V2 + Task V2.
---
## Profile 配置
### 顶层字段
```toml
version = 2 # 必填,标识配置格式版本
inherits = "default" # 可选,继承另一个 Profile,深度合并(子字段覆盖父字段)
client_type = "Official" # 可选
```
#### 继承示例
`inherits` 字段用来继承另一个 Profile,可以方便的实现配置复用:
```toml
# profiles/default.toml
version = 2
[connection]
type = "General"
address = "emulator-5554"
touch_mode = "MaaTouch"
```
```toml
# profiles/yostar-en.toml
version = 2
inherits = "default"
client_type = "YoStarEN" # 只改这一个字段,其余全部继承
```
#### 游戏客户端类型
`client_type` 是一个横跨多个作用域的配置,决定:
- 加载哪个全局资源包(如 YoStarEN → EN 资源)
- 部分 Preset 使用的游戏包名 / Bundle ID(如 PlayCover)
- 任务条件判断需要的 client_type
- 部分任务需要注入的 client_type
### `[connection]`
`type` 选择连接类型,除了 General 以外提供了一系列默认值,且决定哪些字段合法。此外,对于部分类型 (类如 Waydroid) 也负责确定如何管理外部环境。
```toml
[connection]
type = "General" # General / PlayCover / Waydroid / AVD / MuMuPro
```
#### `General`(通用模式,直接对标原始的 MaaCore API)
类似于旧版本,但是部分选项的位置和名字发生了变化。
```toml
[connection]
type = "General"
address = "emulator-5554" # 可选,缺省时从 `adb devices` 自动检测
adb_path = "adb" # 可选
touch_mode = "MaaTouch" # 可选:MaaTouch / MiniTouch / Adb
adb_lite = false # 可选
kill_adb_on_exit = false # 可选
config = "General" # 可选,连接时使用的配置,可能影响部分行为
```
#### `PlayCover`(macOS 通过 PlayCover 原生运行 iOS App)
`touch_mode` 内部固定为 `MacPlayTools`,平台差异资源 `iOS` 自动加载。
```toml
[connection]
type = "PlayCover"
address = "127.0.0.1:1717" # 可选,默认 127.0.0.1:1717
screencap_mod = "Default"
```
Playcover 支持多种截图模式:
- `Default`:默认兼容模式
- `BGR`:速度更快,使用目前没发现兼容性问题
- `SCK`:使用 macOS ScreenCaptureKit 速度最快,但是需要 cli 的宿主 (终端),被授予了截图权限
#### `Waydroid`(Linux Continer)
支持自动启动,连接地址在运行时从 `waydroid status` 获取:
```toml
[connection]
type = "Waydroid"
adb_path = "adb" # 可选
touch_mode = "MaaTouch" # 可选
adb_lite = false # 可选
```
#### `MuMuPro`(macOS)
类似于通用 ADB,但是有已知的 adb_path 和 address
```toml
[connection]
type = "MuMuPro"
address = "127.0.0.1:16384" # 可选
touch_mode = "MaaTouch" # 可选
adb_lite = false # 可选
kill_adb_on_exit = false # 可选
```
后续可以扩展更多类型,比如 AVD (自动启动),实体设备 (自动调节分辨率),以及 Windows 上面的 Mumu / 雷电(截图增强):
#### `AVD`(Android 虚拟设备)
`sdk_path` 必填,`adb_path` 和模拟器命令从中推导。
理论上支持截图增强,见 MaaAssistantArknights/MaaAssistantArknights#15608,有待实际实现
```toml
[connection]
type = "AVD"
sdk_path = "/home/user/Android/Sdk" # 必填
avd_name = "Pixel_6_API_33" # 可选,用于启动指定模拟器
touch_mode = "MaaTouch" # 可选
adb_lite = false # 可选
kill_adb_on_exit = false # 可选
```
### `[behavior]`
运行时行为偏好,所有字段可选。
```toml
[behavior]
auto_reconnect = true # 掉线后自动重连,默认 true
deployment_with_pause = false # 部署时暂停,默认 false
```
### `[advanced]`
进阶技术配置,大多数用户无需关注。所有字段可选。
```toml
[advanced]
inference_engine = "cpu" # cpu / gpu:0 / gpu:1 / ...,默认 cpu
user_resource = false # 从配置目录加载自定义资源,默认 false
```
### 完整示例
**最简配置(PlayCover):**
```toml
version = 2
[connection]
type = "PlayCover"
```
**完整配置(General):**
```toml
version = 2
client_type = "YoStarEN"
[connection]
type = "General"
address = "127.0.0.1:5555"
adb_path = "/usr/bin/adb"
touch_mode = "MaaTouch"
adb_lite = false
kill_adb_on_exit = false
[behavior]
auto_reconnect = true
[advanced]
inference_engine = "gpu:0"
user_resource = true
```
---
## Task 配置(`tasks/*.yaml`)
### 结构
### 生命周期管理
两个标志控制自动启停:
- `manage_environment_lifecycle`(默认 `true`):是否自动管理外部环境(如 Waydroid session、AVD)。由 Profile 的 `connection.type` 决定是否实际生效——General / PlayCover 等无外部环境的类型忽略此标志。
- `manage_game_lifecycle`(默认 `true`):是否自动管理游戏启停流程。
- 启用时,运行时会自动执行 StartUp / CloseDown,`client_type` 和 `account_name` 会自动注入给 StartUp。
- 禁用时,用户可以自己在 `tasks` 中手写 StartUp / CloseDown task。Runtime 仍会将 Profile 的 `client_type` 注入到这些 task 的 params 中,但不会从中提取 `client_type`, `client_type` 的唯一来源始终是 Profile,同时不再保证中间任务出错后依然执行 CloseDown。
### 任务
Task 文件支持两种模式,两者不能同时存在:
- `tasks`:任务列表模式,通常对于单账号任务;
- `sessions`:编排模式,主要用于多个账号按顺序轮跑;
#### 任务列表模式
```yaml
version = 2
manage_environment_lifecycle: true # 可选,默认 true
manage_game_lifecycle: true # 可选,默认 true
account_name: main # 可选,注入给 StartUp
tasks:
- type: Fight
# ...
```
#### 编排模式
所有 Session 共享 Profile 中的 `client_type`,只有 `account_name` 不同。实际按顺序串行执行。
`manage_environment_lifecycle` 只执行一次,(环境只启停一次)。
`manage_game_lifecycle` 每个 session 执行一次:
- 为 `true` 时,运行时会在各 Session 之间自动执行 CloseDown → StartUp
- 为 `false` 时,运行时仅按书写顺序执行,不做额外检查或兜底;如需切账号,需用户自己手写 StartUp / CloseDown
在 `sessions` 模式下:
- 顶层不能再出现 `account_name`
- 每个 Session 只描述该账号自己的 `tasks`
- Session 按顺序执行;当前 Session 未完成时,不会进入下一个 Session
- `manage_game_lifecycle = false` 时,Session 内允许手写 StartUp / CloseDown,但运行时不额外保证切换正确性
编排模式下的失败处理规则:
- 用户主动中断时,立即停止整个运行,不进入后续 Session
- 当前 Session 运行报错或掉线时,将该 Session 标记为失败,但继续执行后续 Session
- 如果启用了自动游戏生命周期,当前 Session 在报错或掉线后仍会先自动执行 CloseDown,再进入下一个 Session
- 最终结果需要反映所有失败的 Session,不能因为后续 Session 成功而吞掉前面的错误
```yaml
version = 2
manage_environment_lifecycle: true # 可选,默认 true,全局一次
sessions:
- account_name: main
tasks:
- type: Fight
params:
stage: "1-7"
- account_name: alt
tasks:
- type: Fight
params:
stage: CE-6
```
一个可能的痛点是,多 session 模式可能会存在大量的重复,所以后续可能会加上 template,允许复用。
现阶段主要使用可以利用 YAML 的锚点,一定程度进行复用。
### Task 定义
每个 Task 包含:
- `type`(必填):MaaCore 任务类型
- `name`(可选):控制最终显示在 Summary 里面的名字
- `if`(可选):控制该任务是否执行的条件;缺省表示始终执行
- `params`(可选):任务执行时始终传给 MaaCore 的基础参数
- `override_strategy`(可选):多个 override 同时命中时的处理策略,`first` 或 `merge`,默认 `first`
- `overrides`(可选):条件性参数覆盖列表,叠加在 `params` 之上
除非显式说明,V2 中的 `type` 都直接对应 MaaCore task 类型。V2 不额外引入新的“生命周期 task 类型”;自动启停由 `manage_*_lifecycle` 控制。
```yaml
tasks:
- type: Fight
name: Fight Daily
override_strategy: first
if:
weekdays: [Mon, Wed, Fri]
params:
stage: "1-7"
report_to_penguin: true
overrides:
- if: OnSideStory
params:
stage: ""
- if:
weekdays: [Tue, Thu, Sat]
params:
stage: CE-6
```
`overrides` 的应用策略由 `override_strategy` 决定:
- `first`(默认):按顺序找到第一个命中的 override,应用后停止
- `merge`:按顺序应用所有命中的 override,后者覆盖前者
无匹配时使用原始 `params`,任务照常执行 (注意,V1 版本则会静默跳过)。
### 执行语义
#### 自动游戏生命周期
当 `manage_game_lifecycle = true` 时:
- 单 Session 模式会在任务列表前后自动执行 StartUp / CloseDown
- `account_name` 会自动注入给 StartUp
- `client_type` 会自动注入给需要的任务参数
自动执行的 CloseDown 只在以下情况执行:
- 正常结束
- 运行报错
- 掉线停止
用户主动中断 (Ctrl-C) 时,不自动执行 CloseDown。后续可能添加配置/命令行参数,在报错的情况下,依然不关闭。
#### 手写生命周期
当 `manage_game_lifecycle = false` 时:
- `tasks` 中可以手写 StartUp / CloseDown,并允许任意穿插
- 运行时严格按书写顺序执行
- 不再根据 CloseDown 做任何额外兜底
- 失败或中断后的行为与普通任务一致
---
## 条件系统
条件出现在两处:
- `task.if`——决定任务是否执行
- `override.if`——决定该 override 是否应用
### 字符串形式(无参数条件)
```yaml
if: Always # 始终激活(缺省 if 时的默认行为)
if: OnSideStory # SideStory 期间激活(使用 Profile 中的 client_type)
```
其中:
- `OnSideStory`(字符串)表示检查当前 Profile 的 `client_type`
- `on_side_story: Xxx`(对象)表示显式检查指定客户端
### `Weekday`(星期)
唯一字段:`weekdays`。
```yaml
if:
weekdays: [Mon, Wed, Fri]
timezone: Official # 可选:Local(默认)/ Official / YoStarEN / ... / UTC 偏移整数
```
`timezone` 为客户端名称时,以服务器时间 04:00 作为换天边界。
### `DayMod`(天数取模)
唯一字段:`divisor`。满足 `num_days_from_ce % divisor == remainder` 时激活。
```yaml
if:
divisor: 2
remainder: 0 # 可选,默认 0
timezone: 8 # 可选,UTC 偏移整数
```
### `Time`(每日时间段,循环)
唯一字段:`time_after` 和/或 `time_before`。
```yaml
if:
time_after: "16:00:00"
time_before: "23:59:59"
timezone: Official # 可选
```
仅设 `time_after`:从该时刻到午夜激活。仅设 `time_before`:从午夜到该时刻激活。支持跨午夜的时间段(如 23:00–01:00)。
### `DateTime`(日期范围,一次性)
唯一字段:`start_date` 和/或 `end_date`。
```yaml
if:
start_date: "2024-08-01T00:00:00"
end_date: "2024-08-21T04:00:00"
timezone: 8 # 可选,UTC 偏移整数
```
### `OnSideStory`(指定客户端)
```yaml
if:
on_side_story: Txwy # 检查指定客户端的限时活动状态
```
这里的 `Txwy` 是显式目标客户端,与 Profile 当前使用的 `client_type` 无关。
### 组合条件
```yaml
# AND——所有子条件满足
if:
all:
- weekdays: [Mon, Wed, Fri]
- time_after: "16:00:00"
# OR——任一子条件满足
if:
any:
- weekdays: [Sat]
- weekdays: [Sun]
# NOT——取反
if:
not:
weekdays: [Sun]
```
---
## 完整 Task 示例
```yaml
manage_game_lifecycle: true
tasks:
# Fight:始终执行,但根据条件覆盖关卡
- type: Fight
params:
stage: "1-7"
report_to_penguin: true
penguin_id: "00000000"
overrides:
- if: OnSideStory
params:
stage: ""
- if:
weekdays: [Tue, Thu, Sat]
params:
stage: CE-6
# Mall:仅在 16:00 后执行
- type: Mall
if:
time_after: "16:00:00"
params:
shopping: true
credit_fight: true
buy_first: [招聘许可, 龙门币]
blacklist: [碳, 家具, 加急许可]
# Recruit:始终执行
- type: Recruit
params:
refresh: true
select: [4, 5]
confirm: [3, 4, 5]
```
---
## V1 → V2 迁移
### Profile 迁移
#### V1
```toml
[connection]
type = "ADB"
adb_path = "adb"
device = "emulator-5554"
config = "CompatMac"
[resource]
global_resource = "YoStarEN"
user_resource = true
[static_options]
cpu_ocr = true
[instance_options]
touch_mode = "MaaTouch"
deployment_with_pause = false
adb_lite_enabled = false
kill_adb_on_exit = false
```
#### V2
```toml
version = 2
client_type = "YoStarEN" # resource.global_resource 不再需要手动设,由 client_type 自动推导
[connection]
type = "General" # "ADB" → "General"
address = "emulator-5554" # "device" → "address"
adb_path = "adb"
touch_mode = "MaaTouch" # 原 instance_options.touch_mode
adb_lite = false # 原 instance_options.adb_lite_enabled
kill_adb_on_exit = false
config = "CompatMac"
[behavior]
deployment_with_pause = false # 原 instance_options.deployment_with_pause
[advanced]
inference_engine = "cpu" # 原 static_options.cpu_ocr = true → "cpu"
user_resource = true # 原 resource.user_resource
```
主要变化:
- 添加 `version = 2`
- `connection.type`:`ADB` → `General`
- `connection.device` → `connection.address`
- `resource.global_resource` / `platform_diff_resource` → 由 `client_type` 和 `connection.type` 自动推导,不再需要手动设
- `static_options` / `instance_options` → 拆分到 `[connection]`、`[behavior]`、`[advanced]`
### Task 迁移
#### V1
```yaml
tasks:
- type: StartUp
params:
start_game_enabled: true
client_type: Official
- type: Fight
params:
stage: "1-7"
variants:
- condition:
type: Weekday
weekdays: [Tue, Thu, Sat]
params:
stage: CE-6
- condition:
type: Always
params: {}
- type: CloseDown
```
#### V2
```yaml
manage_game_lifecycle: true # 替代手写 StartUp / CloseDown task
tasks:
- type: Fight
params:
stage: "1-7" # base params,始终使用
overrides: # variants → overrides
- if:
weekdays: [Tue, Thu, Sat] # condition → if,无需 type 标签
params:
stage: CE-6 # 不再需要 Always variant 保底
```
主要变化:
- `StartUp` / `CloseDown` task → `manage_game_lifecycle: true`(默认值),自动管理游戏启停
- `client_type` 不再在 task params 中设置,由 Profile 注入
- 用户仍可手写 StartUp / CloseDown(设 `manage_game_lifecycle: false`),但 `client_type` 只注入不提取,且运行时完全按书写顺序执行
- `variants` → `overrides`,仅覆盖参数,不影响任务是否执行
- `condition` → `if`,通过唯一字段推断类型,无需 `type` 标签
- 不再需要 `Always` variant 作为保底
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The proposal names profiles/*.toml and tasks/*.yaml as the configuration surfaces; start by reviewing the existing V1 profile and task handling in the CLI. Compare those paths with the V1→V2 examples, and treat completion as an agreed implementation of the V2 schema, compatibility behavior, and corresponding tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- json, rust, yaml
- Domain
- cli, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100