Repository navigation
feat(m9a): 新增 MAS 原生 B 服登录,登录后交给 M9A 运行 - #1882
Conversation
- 新增 Run.LoginMode(Project/Mas):Mas 时由 MAS 处理 B 服隐私政策提示、登出并在登录记录里 选择目标账号,回到标题页后交给 M9A 的 StartUp 进游戏并运行 - MaaFW 引擎新增可选钩子 ensure_logged_in,模拟器连带拉起游戏后、首个任务前调用;失败按普通 失败重试,用户停止照常上抛 - Mas 模式不再向 M9A 下发「切换账号」,账号即登录记录里的完整昵称;启动/切号失败结束本轮 - 编辑页新增「登录方式」下拉(三语),前端 API 生成物按生成器更新;新增回归测试
|
复用神秘入口的「托管 Bilibili 游戏隐私政策」开关 IfAgreeBilibili:开启才自动同意,关闭时提示用户手动处理。登录方式仍放在 M9A 编辑页,不需要另加一份协议入口。 |
总体结论:修改后合并AUTO-MAS-Project/AUTO-MAS #1882 喵,这版已经把登录接入 MaaFW 的运行前钩子,但失败重试和账号确认仍有缺口,暂不建议直接合并。以下结论来自完整变更及调用链的静态核对,未运行项目代码、测试或真机流程。
验证与边界
—— dot酱敬上 🐾 |
- 引擎只在登录成功后记「已登录」,客户端被重试重启时清掉标记、下一轮重新验证,失败重试不再跳过登录 - 既认不出登录记录也认不出标题页时明确停止,不再把「没认出来」当成目标账号已登录 - 自动同意只复用全局 IfAgreeBilibili(默认关闭),关着时不点、提示手动处理并停止 - 所有循环先查总时限,adb input tap 失败直接抛错 - 登录后必须连续两帧认出标题页才判完成,过渡空帧只算未知画面 - 修正上游说明:B 服资源已声明,但「切换账号」仍只声明官服;补上游评估与移除计划 - 新增状态机边界测试(未知画面/协议关闭/空帧/标题确认/失败重试/重启重验证)
总体结论:修改后合并AUTO-MAS-Project/AUTO-MAS #1882 · 复审 喵,这次修复已对上上一轮的五个问题:登录成功后才缓存结果,重启后重新验证;未知画面明确失败;自动同意复用 仍需处理
文案建议(非阻断) 验证还差当前提交的证据
本次没有确认新的正常 ADB+B 服路径 P1。隐私处理循环现在有界,但各阶段分开计时,并非注释所称的共享 240 秒总预算;这点可同步澄清,不再按原来的无限循环问题重复报。 —— dot酱敬上 🐾 |
|
感谢评审,逐条处理如下(修复提交 P1 重试正确性
P1 账号隔离
P1 用户授权
P2 超时
P2 结果判定
说明修正
验证记录
关于「实际 MAS 调度链证据」本机验证时 MAS 调度侧链路已跑通(运行日志原文):
但进入「启动模拟器」阶段后,本机 dev 构建调用 登录流程本身已在真机(MuMu 12 + |
- 三语登录说明与账号提示按登录模式区分:M9A 登录时账号加入「切换账号」(官服),MAS 登录时账号是登录记录的完整昵称、只用于选号,并说明全局协议开关默认关闭 - ensure_logged_in 契约改为「登录成功才记完成,失败与客户端重启后重新验证」 - 隐私提示各阶段分别计时,更正「共享 240 秒总预算」的注释 - 新增隐私提示持续存在、标题与空帧交替不提前判成功的回归测试
|
感谢复审。已按意见更新,新提交 文案与契约同步
当前提交的验证记录
关于「临时补位缺少上游评估依据」(P2)先补可核实的事实依据:
因此这一步确实是「脚本该干的活、上游暂无入口」。按规范我们应当先评估向上游提 PR,但本项目目前没有形成该提案(开发验证阶段),于是临时补位在 MAS 的运行前钩子里,并在 请维护者明确一下这个例外是否被允许(复审意见里也给了这个选项):
关于「真实场景脱敏验证记录」本机 dev 构建的模拟器管理有一个环境问题: |
|
M9A确认不做隐私协议,我是现场怪,后续评审不纳入考虑,等正式版后没问题就合 |
总体结论:可以合并AUTO-MAS-Project/AUTO-MAS #1882 · 复审补充 宝宝,登录说明这次和实际行为对上啦:完整昵称怎么用、协议开关默认关闭、失败重试和客户端重启后重新验证,都说清楚了。两条新增测试也分别检查了隐私提示反复出现时能超时、标题与空帧交替时不能提前报成功,补到了前面点出的具体场景喵。 维护者已说明 M9A 不处理隐私协议,并明确这部分不再纳入后续评审。dot酱按这次取舍收回对应的上游评估阻断,不再为同一选择反复追问;这不扩大为其他游戏内能力的通用豁免。本轮增量只有说明、翻译和测试,没有再改生产登录逻辑,静态核对未发现新的必须修改项。 合并时点仍按维护者说的“等正式版后没问题就合”。作者报告的 28 passed 是本机记录,完整 MAS 调度链的真实场景仍未跑完;当前 CI 已放行,已读取 Ubuntu 全量测试日志,结果为 1505 passed、26 skipped;Windows 测试和构建仍在运行,格式等检查已通过。dot酱没有执行项目代码,也不把这些未完成的验证写成已通过。等正式版验证和仓库检查齐了,再由维护者决定落合并键就好啦。 —— dot酱拍拍爪敬上 🐾 |
AthenaHibou
left a comment
There was a problem hiding this comment.
CI 现状
pytest (windows-latest) 唯一失败的是 tests/tools/test_avd_shutdown.py::test_close_waits_for_android_until_deadline_then_falls_back,与本 PR 无关:该断言由 #1805 引入,Windows 上 android_wait 来自 time.monotonic() 的浮点差值,多出约 5.7e-14 的零头,刚好越过 28 秒预算(22.000000000000057 + 1 + 3 + 2 > 28)。Ubuntu 全绿,Windows 仅此一条。
建议改成常量 + 1 微秒容差(我已在本地按 Windows + 仓库 venv 验证通过,可以直接采用):
from app.utils.common.emulator2.avd.constants import CLOSE_BUDGET_SECONDS
# 等待值来自 time.monotonic() 的浮点差值,会带上 1e-14 级零头;预算断言留 1 微秒余量
assert (
android_wait + fallback_sync + console_wait + force_wait
<= CLOSE_BUDGET_SECONDS + 1e-6
)这只是一条 flaky 的修复,不改变 28 秒预算的检查强度。
审核意见
1. 魔改 AVD 上登录会失败(建议合并前修)
login.py 的截图/点击/前台判断全部走 subprocess.run([adb_path...])(app/task/M9A/login.py#L205-L263),但魔改 AVD 只向 MAS 私有 server 注册(app/utils/common/emulator2/avd/host.py#L26-L28),AvdManager.get_adb_path() 也刻意返回 None(app/utils/common/emulator2/avd/manager.py#L1001-L1008)。结果是 AVD 用户拿到 adb_path=None → "adb",连到 5037 或直接找不到设备,报「ADB 截图失败」。
游戏更新钩子已经处理了同一问题:adb_runner_scope(await resolve_host_adb(self))(app/task/MaaFW/tools/embedded/runner_task.py#L1624-L1626)。登录钩子目前只收到 adb_path,建议把 adb_runner(或 host_adb)一并传进钩子,或让钩子内部走 resolve_host_adb。这条需要在 AVD 上验证一次。
2. 黑箱归属需要维护者确认
登录(含选号、登出)属于游戏内操作,按 .agents/skills/mas-script-specialized-adapter/references/blackbox-boundary.md 属上游 M9A 领域。本 PR 已标注临时补位和移除计划,这点是好的;但「立项时未单独向上游提 PR,因为本实现属于 MAS 侧运行前编排」不属于规范允许的两种补位情形(上游评估不需要 / 上游周期过长)。建议先向上游提 issue/PR,或在 PR 里记录维护者明确接受该临时补位,避免合并后成为存量越界。
3. Win32 controller + Run.LoginMode = Mas 会静默跳过登录
_ensure_logged_in 只在 plan.controllerType == "Adb" 分支里调用(app/task/MaaFW/tools/embedded/runner_task.py#L1414-L1418)。用户切到 Mas 但用 Win32 controller 时既不会登录也没有提示,M9A 的 StartUp 会按当前已登录的账号继续跑,任务可能落在错的账号上。建议在 Win32 分支或整理期响亮提示/拦停。
4. OCR 输入通道与共享工具契约不一致
app/task/M9A/login.py#L224 传入的是 RGB;ocr_image 的文档写的是 BGR/灰度,仓内其他调用点都会做 cv2.cvtColor(..., cv2.COLOR_RGB2BGR)(如 app/task/BetterGI/tools/account_switch_native.py#L405-L410)。真机验证过能用,但建议统一转 BGR,避免和既有实现识别率不一致。
5. 标题页锚点与坐标适配
_TITLE_HINTS 里的 "ERS"(app/task/M9A/login.py#L94-L97)可能命中 PLAYERS / OTHERS 这类词,造成误判标题页;_EXIT_POINT、_EXPAND_POINT 与 _AGREE_* / _ACCOUNT_* 区间都是 16:9 实测值,非 16:9 时目前没有像 BetterGI 那样先告警。建议收紧 ERS,并补一条屏幕宽高比提示。
6. 注释与实现矛盾
app/task/MaaFW/tools/embedded/runner_task.py#L590-L591 写「重试重新开模拟器时不再登录」,但 _restart_client_before_retry 在重启客户端后会把标记清掉、下一轮重新登录(app/task/MaaFW/tools/embedded/runner_task.py#L3509-L3513)。注释建议改成「同一客户端会话内只登录一次;客户端重启后重新验证」。
7. 测试覆盖
tests/task/test_m9a_login_flow.py 覆盖了未知画面、隐私开关、空帧、标题确认、失败重试与重启清标记,边界抓得不错;但核心成功路径 _select_account(展开列表 → 选号 → 点登录)和 _logout_to_login_panel 只有真机证据。状态机是确定性的,用假画面补这两条成本很低,建议补上。
8. 细节
app/task/M9A/migration.py#L1460-L1485里变量仍叫official,实际语义已是「资源是否支持切号」,建议改名。- 隐私开关未开、账号为空这类配置错误也会走 3 轮重试(每轮重开模拟器/游戏),可以考虑标成不重试。
_wait_foreground不检查am start返回码,拉起失败要白等 90 秒才报超时。- 本次新增的是可观察的运行前流程,建议在 PR 正文补一句遥测结论(复用既有「运行失败」事件,或说明为何不采集)。
整体方向合理:LoginMode 默认 Project 保证存量行为不变,切号判据收敛在 supports_account_switch 一处,三语文案、生成物与 changelog 碎片齐全。合并前建议至少处理 第 1 条 并确认 第 2 条。
以上未在真实模拟器/AVD 上复跑登录流程,仅做了仓库内定向单测与静态审核。
|
已复核最新审核并推送修复:da8eb843d(fix(m9a): 修复私有 ADB 登录通道与控制器校验)。
验证环境:Windows / Python 3.12.13 / Ruff 0.16.8,使用仓库
黑箱归属说明已纠正:运行前调用不改变游戏内登录/登出/选号的归属;引用维护者已明确的隐私协议取舍,不扩大该例外,其余范围仍由维护者决定。遥测复用现有任务结局观察边界,不新增昵称、截图或逐帧采集。 @Douya36 麻烦基于 da8eb84 再做一轮实机测试,并补充脱敏结果:
本轮未操作真实游戏或模拟器;替身回归不代表实机已通过。请附模拟器/客户端版本、场景结果及脱敏日志或截图。 |
总体结论:可以合并AUTO-MAS-Project/AUTO-MAS #1882 · 复审补充 宝宝,这次把魔改 AVD 的登录通道接对啦:MaaFW 负责解析宿主 ADB 通道,M9A 的截图、点击、前台检查和拉起都复用它,没有再绕到默认 server。普通模拟器仍走原有路径,这处修得扎实喵。 dot酱核对了这轮新增的异步调用、失败传播与私有通道替身测试,也检查了当前目标分支的集成;静态审查范围内没有新的必须修改项。截图已转成共享 OCR 约定的 BGR,新增成功路径测试覆盖了登出、展开记录、选号到回标题页,不过这些替身断言不等于真机登录已通过。 作者报告的 38 项通过与全量测试中的 21 项失败,仍是作者侧记录;当前提交只查到标签同步检查通过,尚无测试 CI 结果。dot酱没有运行项目代码或游戏。合并时点继续按维护者已确认的“等正式版后没问题就合”,MuMu 与魔改 AVD 的实际轮换、失败重试仍要按评论中的场景验收,别让替身替真机盖章啦。 —— dot酱拍拍爪敬上 🐾 |
- 实机 2560x1440:登录后标题页的 START 常读不到,OCR 实际读到的是副标题 REVERSE 的残词 ERS/ERSE,恢复该锚点(比旧的 ERS 精确:整词匹配 ERSE 或 START/TART) - 登录成功顶栏的「<昵称> 欢迎回来」横幅也算标题页正向信号 - 冷启动会先出「警告:请在游戏前阅读」健康警告页,登录钩子跑在 M9A StartUp 之前,先点一下继续 - 补三条回归:ERSE 标题、欢迎横幅、健康警告页
#1882 追加一轮对抗性审查(基于
|
|
已按复审要求更新,推送 1. 同步最新 dev
2. 根据实机反馈修正标题页识别实机(MuMu 12 + B 服客户端 V4.1.0-113.0.1421-180)验证时发现两个问题:
已修正(提交
3. 实机验证结果
4. CI仍为 |
总体结论:可以合并AUTO-MAS-Project/AUTO-MAS #1882 · 复审补充 宝宝,标题页这次多了两条有明确依据的识别路径: dot酱对照了新增识别分支、对应回归测试,以及合入当前 dev 后的登录调用和重试接线;本轮静态核对没有确认新的必须修改项。模拟器关闭测试只给浮点误差留了 1 微秒余量,生产的 28 秒预算没有放宽。 不过这次还不能拿 CI 给真机盖章喵:当前 Python Tests 等检查停在 —— dot酱拍拍爪敬上 🐾 |
总体结论:修改后合并宝宝,这轮以 逻辑1. [P2] 登录钩子执行前,ADB 路径还没有完成既有的自动发现位置:runner_task.py:1411–1414、login.py:229–232。
具体例子是当前支持的「通用模拟器 + BlueStacks」:程序选 已执行真实 建议在调用登录钩子前完成既有的按地址发现,并传入确定的 ADB 路径。复用同一套发现能力即可。 2. [P2] 初始加载被固定 60 秒截断,调大启动等待时间也无效位置:login.py:629–636,调用时序见 runner_task.py:1411–1414。 登录钩子在 worker 的启动等待之前执行,把尚未出现登录记录或标题信号的加载画面也计入 我用真实 这会让加载耗时超过 60 秒的客户端在就绪前进入失败重试。建议让登录前的加载等待服从已有启动预算,区分“仍在启动”和“已就绪但无法确认账号”;到期仍无法确认账号时继续失败,保留当前防止串号的边界。 3. [P3,非阻断] 标题信号漏掉了完整的
|
- 认不出画面时的预算取 Game.WaitTime(上限仍是登录主循环 240 秒),冷启动加载画面不再误判 - 宿主推不出 ADB 路径时先按地址问 MaaFW Toolkit,钩子不再退回 PATH 里的 adb - adb 子进程改走受管入口:任务停止时随作用域回收,截图保留 PNG 原始 bytes - 标题锚点补完整 REVERSE(实机 OCR 有时能读全) - Mas 模式只接受「B 服」资源与 B 服包名,配错客户端在碰模拟器之前报错
|
@jinghero 谢谢,这轮按你基于 1. [P2] 登录钩子执行前完成 ADB 发现 2. [P2] 初始加载不再被固定 60 秒截断 3. [P3] 标题信号补完整 4. [P2] 普通 ADB 子进程接入停止清理 另外把对抗性审查里成本最低的一条一起做了: 验证: 仍未处理(既有边界,本轮未改):登录成功后不校验游戏 UID(只按昵称选号 + 标题页连续帧确认);登录记录列表不滚动查找;登录失败的可重试 / 不可重试分类没拆;Toolkit 发现只有单测覆盖,MuMu 真机走的是安装目录推出来的路径、没触发这条。 |
|
为啥把StartUp加名单里了? @Douya36 这个后面记得看一下,因为不把startup加进去是有原因的 |
|
不挡合并但是后续的优化方向:
|
|
我说回头要是没事干倒是可以把这个修补修补() |
|
@qiyinxi 谢谢,两条都回了。 1. 是我们加的( 已经按上游口径回退( 想确认一下你说的原因,好把注释写准:是指「 2. 三条优化方向
|
|
补一句状态说明:这个 PR 已经在 21:56 合入(squash 合并提交 为了让它真的落地,已单独开后续 PR #1896( |
## 摘要 - 把 `StartUp` 从 M9A 的 `abort_round_entries` 里去掉,与上游口径一致(只把「切换账号」列为关键任务):启动失败改回普通任务失败、本轮照常继续,不再提前结束本轮 - 隐私政策提示的拦停文案改成设置里的实际名字与位置:「托管Bilibili游戏隐私政策」→「设置 → 功能设置 → 神秘入口」 ## 测试与验证 - `python -m pytest tests/task/test_m9a_login_flow.py tests/task/test_m9a_login_mode.py tests/task/test_maafw_core.py tests/tools/test_avd_shutdown.py -q` → **51 passed**、`ruff check` 通过 - `test_only_account_switch_aborts_round` 断言 `StartUp` 不在名单、`SwitchAccount` 在;隐私文案用例沿用原有「未开启」断言 - 只改 M9A 特调声明与一处提示文案,登录状态机未改,真机流程不受影响 - 更新日志:属于 #1882 刚合入、尚未进正式版的功能的后续修正,按 beta-only 规则不带碎片(建议 `skip-changelog`) Co-authored-by: Douya36 <Douya36@users.noreply.github.com>
摘要
Run.LoginMode(默认Project;Mas= 由 MAS 完成 B 服登录):编辑页在「游戏包名」旁新增「登录方式」下拉ensure_logged_in:模拟器拉起游戏后、首个任务前处理隐私提示、登出后按登录记录里的昵称选号并登录,回到标题页交给 M9A 的StartUp;登录成功才记完成,失败或客户端重启后重新验证Mas模式下不再下发「切换账号」;账号即登录记录里的完整昵称;启动 / 切号失败结束本轮,登录失败按普通失败重试START/TART/ 完整REVERSE与残词ERSE、「<昵称> 欢迎回来」横幅;冷启动健康警告页会先点掉;登录前的等待服从Game.WaitTime,ADB 路径按地址补齐,adb 子进程随任务停止回收测试与验证
python -m pytest tests/task/test_m9a_login_flow.py tests/task/test_m9a_login_mode.py tests/task/test_maafw_core.py tests/tools/test_avd_shutdown.py -q→ 51 passed(提交57e3430d)REVERSE标题、Game.WaitTime等待预算、慢加载不被固定 60 秒截断、Mas资源 / 包名拦截(官服 / 国际服 / 官服客户端)、缺 adb 的可处理报错、取消时回收 adb 子进程、宿主按地址发现 ADB。这批用例在6c2e0ef0的干净 worktree 上全部失败,修复后通过288c4a80工作树):协议开关关闭 → 拦停并提示开启「托管Bilibili游戏隐私政策」;开关开启、游戏未登录 → 健康警告页 → 隐私同意 → 选号 → 登录 → 标题页确认;已登录再跑一次 → 成功(31.4 秒,走登出 → 确认 → 选号);Mas+ 官服 / 国际服资源、官服包名 → 三条都在碰模拟器之前给出明确报错Mas登录后仍不校验游戏 UID(按昵称选号 + 标题页确认);登录记录列表不滚动查找;资源 / 包名拦截发生在登录钩子(启动客户端之后、下发任务之前),不在运行计划阶段;Toolkit 按地址发现只有单测覆盖,MuMu 真机走的是安装目录推出来的路径、没触发这条