Files
RRRosmontis 434869573f feat: 日常任务启动前增加画面预检
每天的首次云会话可能停在不可识别画面约 10 分钟(游戏做每日首登资源处理),MAA 在
每个任务上识别失败并烧掉当次尝试的额度(2026-09-23/09-24 连续两天实测,各损失整天
或近半天进度)。包装脚本现在在 /start 后、运行 MAA 前先观察画面:按截图体积分类
(黑屏 <20KB / 登录 200-350KB / 标题 ~480KB / 公告与主界面 >=650KB),对标题屏与
登录屏自动点按推进,出现可识别画面才交给 MAA;超时(默认 13 分钟)则放弃本轮、
释放会话并重试。分类阈值标定于真实截图样本,可调。
2026-09-24 09:45:59 +08:00

270 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# maa-online
在 Linux 无图形服务器上,通过网易云游戏运行《明日方舟》,并让官方 MAA/maa-cli 执行日常任务的实验性适配层。
> 本项目调用网易云游戏未公开的 HTTP、WebSocket 与 WebRTC 协议,可能随平台更新失效,也可能不符合平台服务条款。请仅用于个人研究,自行承担账号及服务风险;禁止多账号、商业代练或规避平台限制。
## 上游项目
本仓库是在以下开源项目及实验原型基础上整理的适配代码,不包含完整第三方源码、官方 MAA 二进制或任何用户凭据:
- **MAA 官方仓库(AGPL-3.0)**
https://github.com/MaaAssistantArknights/MaaAssistantArknights
- **maa-cli 官方仓库**
https://github.com/MaaAssistantArknights/maa-cli
- **网易云游戏后端原型(Apache-2.0)**
https://github.com/Tokisaki-Galaxy/netease_cloud_game_server
- **后端使用的网易云游戏 SDK fork(Apache-2.0)**
https://github.com/Tokisaki-Galaxy/netease_cloud_game_sdk
- **MAA 云游戏实验分支**
https://github.com/Tokisaki-Galaxy/MaaAssistantArknights/tree/support-cloudgame
- **最初的网易云游戏 SDK 原型(Apache-2.0)**
https://github.com/wupco/netease_cloud_game_sdk
- **MAA 社区实验讨论**
https://github.com/orgs/MaaAssistantArknights/discussions/14404
`backend/` 与 `backend/sdk/` 分别保留了相应上游的 Apache-2.0 LICENSE。MAA 和 maa-cli 由安装脚本从官方渠道下载,其许可证仍以各自上游为准。
## 工作原理
```text
官方 maa-cli / MaaCore
│ 标准 ADB 命令
▼
bin/adb-cloud
│ loopback HTTP
▼
backend/server.py
│ 网易 HTTP + WebSocket + WebRTC
▼
网易云游戏中的明日方舟
```
没有修改官方 MaaCore。`adb-cloud` 将 MaaCore 的截图、点击、滑动、文字输入和启动/停止命令转换成本地 HTTP 请求,因此官方 `maa self update`、`maa update` 与 `maa hot-update` 仍可使用。
## 环境要求
- Linux x86_64(其他架构需自行验证)
- Python 3.10+
- `python3-venv`、Git、curl
- 可访问网易云游戏和 GitHub
- 已完成实名认证的网易云游戏账号
- 已有或可登录的《明日方舟》官服账号
## 安装
```bash
git clone https://git.rrrosmontis.icu/RoyirinRosmontis/maa-online.git
cd maa-online
./install.sh
```
安装脚本会在仓库内部创建被 Git 忽略的 `runtime/`,安装 Python 依赖、官方 maa-cli、官方 MaaCore 和资源;不会下载或保存本仓库维护者的账号数据。
## 登录网易云游戏
```bash
runtime/venv/bin/python backend/login.py request <手机号>
runtime/venv/bin/python backend/login.py verify <短信验证码>
```
生成的 token 位于 `backend/token`,权限为 `0600`,且已被 `.gitignore` 排除。不要将 token、手机号、验证码、身份证信息、游戏截图或日志提交到 Git。
实名认证请在网易云游戏网页或 App 中自行完成,不要通过 Issue、聊天或配置文件提供身份证信息。
## 启动与运行
终端一:
```bash
bin/maa-online-server
```
终端二:
```bash
curl -X POST http://127.0.0.1:22888/start
bin/maa-online startup Official --batch -v
```
编辑日常配置:
```bash
bin/maa-online-config
```
验证配置:
```bash
bin/maa-online run daily --dry-run --batch
```
执行日常:
```bash
bin/maa-online run daily --batch -v
```
退出云游戏:
```bash
curl -X POST http://127.0.0.1:22888/exit
```
服务默认仅监听 `127.0.0.1:22888`,不要直接暴露到公网。
## 默认日常模板
`user_config/daily.example.toml` 是脱敏示例。首次安装时复制为被 Git 忽略的 `user_config/daily.toml`,包括:
- 基建一键轮换;
- 自动公招;
- 刷 `1-7` 清理理智;
- 信用商店与好友访问;
- 日常、周常及邮件奖励;
- 完成后退出云游戏。
示例默认不吃理智药、不碎石、不使用加急许可。运行前务必检查 `stage`、公招次数、信用商店列表和邮件领取选项。全部参数说明见 [`user_config/README.md`](user_config/README.md)。
## 更新
```bash
bin/maa-online-update
```
该脚本更新官方 maa-cli、MaaCore、基础资源和热更新资源。适配代码位于官方管理目录之外,不会被 `maa update` 清理。
## 自动定时执行
仓库自带 systemd 单元模板(`systemd/`)。以 root 执行:
```bash
sudo bin/maa-online-install-systemd
```
脚本会把单元渲染到 `/etc/systemd/system/`(`__ROOT__` 替换为当前检出路径)并启用:
| 单元 | 作用 |
|---|---|
| `maa-online-server.service` | 云游戏 API 常驻服务(`Restart=always`,启动前清除代理环境变量,限制 malloc arena 数量) |
| `maa-daily.timer` | 每天 04:00 起随机 0–2 小时触发日常任务 |
| `maa-online-recycle.timer` | 每天 03:59(游戏每日刷新前)重启 API 服务,回收内存 |
| `maa-online-memlog.timer` | 每分钟把服务内存/swap/arena 指标写入 `logs/memlog.csv` |
| `maa-update.timer` | 每周日 03:20 起随机 30 分钟执行更新 |
日常任务由 `bin/maa-online-daily-run` 驱动:等待 API 就绪 → 启动云游戏 → 在停滞看门狗下执行
`config/tasks/daily.toml` → 失败则释放云会话并重试。定时器使用 `Persistent=true`,机器重启
错过触发时间后会自动补跑;同一单元不会并发执行。
**内存回收**:一次流媒体会话会在 glibc 的 malloc arena 里留下大量不归还操作系统的冷匿名内存
(实测单个服务可累积到 2.5 GB 并填满 swap),因此有两层回收:`maa-daily.service` 在结束时
重启 API 服务(`ExecStopPost`),`maa-online-recycle.timer` 每天再独立回收一次。回收服务带
`ExecCondition=bin/maa-online-can-recycle` 守卫,日常任务运行期间会被自动跳过,不会打断任务。
重试采用**断点续跑**:`bin/maa-resume-tasks.py` 读取前几次尝试的日志,跳过已出现
`<任务类型> Completed` 的任务,只运行剩余任务;若全部完成则直接判定成功,不再开启新会话。
`StartUp` 永不跳过,因为每次 `/start` 都是全新的云实例。详见
[`user_config/README.md`](user_config/README.md#自动定时与断点续跑)。
**启动预检**:每次 `/start` 之后、交给 MAA 之前,包装脚本会先观察游戏画面(默认最多 13 分钟,
`MAA_ONLINE_PREFLIGHT_MAX_SECONDS` 可调):按截图体积分类画面状态(黑屏加载 / 登录屏 /
标题屏 / 公告与主界面),对标题屏和登录屏自动点按推进,直到出现可识别的游戏画面才启动 MAA。
每天的首次会话可能停在不可识别画面约 10 分钟(游戏在做每日首登的资源处理),没有这一步时
MAA 会在每个任务上识别失败,整次尝试的额度被白白烧掉(2026-09-23 与 09-24 连续两天实测)。
分类阈值标定在 `bin/maa-online-daily-run` 的注释里,游戏画面改版后可按需调整。
查看运行情况:
```bash
systemctl list-timers 'maa-*'
journalctl -u maa-daily.service -n 50
journalctl -u maa-online-server.service -n 50
```
**内存观测**:`maa-online-memlog.timer` 每分钟运行 `bin/maa-online-memlog`,把服务 cgroup 的内存
构成、swap 占用、进程 RSS 拆分(匿名 / 文件映射 / 其他)以及最大的文件映射追加到
`logs/memlog.csv`(超过 5 MB 自动滚动,保留一代)。字段见脚本内的 `FIELDS`。用法示例:
```bash
tail -f logs/memlog.csv # 实时观察
awk -F, 'NR>1 {print $1, $5, $20, $21, $22}' logs/memlog.csv # cgroup / heap / 匿名 / 文件映射
```
### 内存行为与可选的分配器调优
实测(2026-09):一次流媒体会话会让 API 服务的内存以约 **67 MB/分钟** 增长,跑完由回收机制清零。
已内置的措施是 `MALLOC_ARENA_MAX=2`(把 glibc 的 mmap arena 从 33 个降到 1 个)加上两层回收
(`maa-daily.service` 结束回收 + `maa-online-recycle.timer` 每日回收)。
需要注意:`MALLOC_ARENA_MAX=2` 只是改变了增长的形态——分配从多个 arena 挤回主 arena 后,增长
转入 brk 堆 `[heap]`,会话中 RSS 仍可达约 2.4 GB。回收机制因此仍是主要依靠;实测会话期间服务
的 swap 占用为 0(更早期的版本曾累积到 2.6 GB swap)。
以下措施**默认不启用**,因为会引入分配器开销,可能拖长任务时长:
```ini
# systemd/maa-online-server.service
Environment=MALLOC_MMAP_THRESHOLD_=131072 # >=128KB 走 mmap,free 即归还内核
Environment=MALLOC_TRIM_THRESHOLD_=131072 # 收缩堆顶
```
原因是这类负载下服务本身 CPU 占用很高(实测 35 分钟会话消耗约 14 分钟 CPU,单核约 40%),强制
1–4 MB 的截图缓冲走 mmap/munmap 会带来 syscall、缺页与 TLB 抖动,而这正是 glibc 动态 mmap 阈值
专门要避免的开销。若要启用,请先记录基线(任务耗时与 `logs/memlog.csv` 的 `cg_peak_mb`),启用
后再对比;不划算就删掉这两行并重启服务回滚。
其他同样未启用的选项:在 `backend/server.py` 里定期调用 `libc.malloc_trim(0)`(仅当空闲块位于堆顶
时有效,开销极低);降低 `MAA_ONLINE_FPS` 或分辨率以减少每帧缓冲的分配频率。
### 防止系统更新打断任务(needrestart)
如果主机启用了 `unattended-upgrades`,升级完库之后 `needrestart` 会重启仍在使用旧库的服务。
这类重启若落在日常任务窗口内,会直接打断当次执行,建议把 MAA 单元排除:
```
/etc/needrestart/conf.d/99-maa-online.conf
$nrconf{override_rc}{qr(^maa-.*\.service$)} = 0;
```
`override_rc` 为假值时 needrestart 会把该单元记入 skipped 并跳过重启。API 服务本身有
`Restart=always`,且每天 03:59 与每次任务结束后都会主动回收,不需要外部重启。
检查方式:升级时段执行 `journalctl --since '-10 min' | grep -iE 'needrestart|Restarting services'`。
## 离线测试
启动假后端:
```bash
runtime/venv/bin/python tests/fake_backend.py
```
另一个终端验证官方 MaaCore → ADB 适配层:
```bash
LD_LIBRARY_PATH="$PWD/runtime/home/.local/share/maa/lib" \
runtime/venv/bin/python tests/smoke_maa_connect.py
```
预期:
```text
MaaCore -> adb-cloud -> fake backend: PASS
```
## 已知限制
- 网易私有协议可能随时变化;
- 云视频压缩与网络抖动会降低 MAA 图像识别稳定性;
- 高频截图在低性能服务器上较慢,基建换班可能耗时较长;
- Home/ESC 等键值尚未完整验证;
- 云端会主动断开会话(信令 WebSocket close、视频流停滞)。后端会在检测到这类情况时自动拆除
会话并释放云端实例,日常包装脚本另有停滞看门狗与最多 3 次断点续跑重试,但仍无法保证每次都跑完;
- 云游戏免费额度通常有限(常见为每天 30 分钟),一次完整日常约 24 分钟,重试会进一步消耗额度;
- 后端可能出现少量 H.264 解码丢包警告;
- 游戏自动化会真实消耗招聘许可、理智、信用等资源,请先 dry-run 并审阅配置。
## 许可证
本仓库自有代码按 Apache License 2.0 发布,详见 [`LICENSE`](LICENSE)。派生文件及第三方组件同时受对应上游许可证约束。