Skip to content

feat(m9a): 新增 MAS 原生 B 服登录,登录后交给 M9A 运行 - #1882

Merged
qiyinxi merged 8 commits into
AUTO-MAS-Project:devfrom
Douya36:feat/m9a-mas-bilibili-login
Nov 9, 2026
Merged

qiyinxi merged 8 commits into
AUTO-MAS-Project:devfrom
Douya36:feat/m9a-mas-bilibili-login

Conversation

@Douya36

@Douya36 Douya36 commented Nov 8, 2026 •

Copy link
Copy Markdown

摘要

  • 新增 M9A 的 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)
  • 新增 10 条回归:完整 REVERSE 标题、Game.WaitTime 等待预算、慢加载不被固定 60 秒截断、Mas 资源 / 包名拦截(官服 / 国际服 / 官服客户端)、缺 adb 的可处理报错、取消时回收 adb 子进程、宿主按地址发现 ADB。这批用例在 6c2e0ef0 的干净 worktree 上全部失败,修复后通过
  • 实机(MuMu 12 + B 服客户端 V4.1.0-113.0.1421-180,288c4a80 工作树):协议开关关闭 → 拦停并提示开启「托管Bilibili游戏隐私政策」;开关开启、游戏未登录 → 健康警告页 → 隐私同意 → 选号 → 登录 → 标题页确认;已登录再跑一次 → 成功(31.4 秒,走登出 → 确认 → 选号);Mas + 官服 / 国际服资源、官服包名 → 三条都在碰模拟器之前给出明确报错
  • 测试数据(账号昵称等)一律使用虚构值,不含真实账号名
  • 环境:Windows 11 / Python 3.12.13 / Node 24.22.2
  • 未覆盖:Mas 登录后仍不校验游戏 UID(按昵称选号 + 标题页确认);登录记录列表不滚动查找;资源 / 包名拦截发生在登录钩子(启动客户端之后、下发任务之前),不在运行计划阶段;Toolkit 按地址发现只有单测覆盖,MuMu 真机走的是安装目录推出来的路径、没触发这条

- 新增 Run.LoginMode(Project/Mas):Mas 时由 MAS 处理 B 服隐私政策提示、登出并在登录记录里
  选择目标账号,回到标题页后交给 M9A 的 StartUp 进游戏并运行
- MaaFW 引擎新增可选钩子 ensure_logged_in,模拟器连带拉起游戏后、首个任务前调用;失败按普通
  失败重试,用户停止照常上抛
- Mas 模式不再向 M9A 下发「切换账号」,账号即登录记录里的完整昵称;启动/切号失败结束本轮
- 编辑页新增「登录方式」下拉(三语),前端 API 生成物按生成器更新;新增回归测试
@github-actions github-actions Bot added 专项: M9A 类型: 新增 按更新日志碎片自动设置 labels Nov 8, 2026
@jinghero

jinghero commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

复用神秘入口的「托管 Bilibili 游戏隐私政策」开关 IfAgreeBilibili:开启才自动同意,关闭时提示用户手动处理。登录方式仍放在 M9A 编辑页,不需要另加一份协议入口。

jinghero commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1882

喵,这版已经把登录接入 MaaFW 的运行前钩子,但失败重试和账号确认仍有缺口,暂不建议直接合并。以下结论来自完整变更及调用链的静态核对,未运行项目代码、测试或真机流程。

  1. [P1|重试正确性] 登录失败后,下一次尝试会跳过登录。
    runner_task.py:1653–1677 在调用钩子前就把 _login_checked 设为 True。首次因账号为空、找不到昵称或截图失败抛错后,外层仍会重试,却没有清除此标记;第二轮直接下发任务。Mas 模式又已移除上游 SwitchAccount,启动成功不能补回目标账号验证。请仅在登录成功后记录完成,并在客户端重启后重新验证;失败重试不得绕过前置登录。

  2. [P1|账号隔离] 未识别到登录页不能作为目标账号已登录。
    login.py:475–505 对未知画面等待 60 秒后直接放行,代码明确包括“游戏已在主界面”。用户停在账号甲的主界面、MAS 计划运行乙时,这条路径不会选号。已核对上游 StartUp 可以接管已有主界面,并不校验 MAS 的目标昵称,因此可能把乙的任务和结果落在甲的会话上。请在无法确认身份时明确停止,或回到可验证的登录页重新选号;不要用识别缺失代替成功。

  3. [P1|用户授权] 自动同意必须复用现有 IfAgreeBilibili。
    login.py:265–276 找到“同意”后无条件点击,而既有 Function.IfAgreeBilibili 默认 False,调用链也没有检查它。仅开启 Mas 登录就会绕过默认关闭的自动同意设置。请按维护者已有要求复用该开关:开启才点击,关闭时提示手动处理并停止当前登录,不新增另一份协议入口。也要防止第 1 项重试绕过这个停止条件。

  4. [P2|超时] 隐私提示持续存在时会绕过总时限。
    login.py:482–484 与 384–386 的隐私分支在检查 deadline 前 continue;tap_point 又忽略 adb input 的退出码。截图正常但输入注入失败、提示一直留在屏幕上时,会反复点击而不受 240 秒限制。每条 adb 命令的超时不能限制整个循环,RunTimeLimit 也只包住后面的脚本执行。请让所有分支受统一可取消时限约束,并将点击失败转换为明确错误。

  5. [P2|结果判定] 单帧没有登录文字不等于已回到标题页。
    login.py:383–389 只要一帧没有“登录记录/切换其他账号”,就睡眠 3 秒并宣布登录完成,期间没有再截图。有效黑屏、过渡动画或 OCR 漏字都能满足这个条件,共享 OCR 也允许正常返回空列表。请用标题页等正向完成信号确认交接,未知画面继续有界等待或报错,不能提前记成功。

验证与边界

  • 新增 7 个测试覆盖模式、队列及首次空账号失败,没有覆盖上述两次尝试间的行为或登录画面状态机。优先补同一 runner 首次失败后重试、初始处于另一账号主界面、协议开关关闭、提示持续存在和过渡空帧这些可观察边界。
  • 当前 Python Tests、格式、构建、锁文件、误回退及更新日志等运行仍为 action_required;仅碎片标签同步成功,不能视为 CI 已通过。作者所述 MuMu 两账号 4/4 属于作者验证记录,现有材料没有附可核验的脱敏截图/录屏,修复后请补实际 MAS 调度链证据。
  • 已核对上游当前 interface 声明了 B 服资源,但 SwitchAccount 仍限官服,不能把“能启动 B 服”视为“能按昵称选号”。请修正“原版只声明官服”的说明,并补上允许临时补位的上游评估或受阻依据;不能只用“上游没有”代替项目要求的判断过程。

—— dot酱敬上 🐾

- 引擎只在登录成功后记「已登录」,客户端被重试重启时清掉标记、下一轮重新验证,失败重试不再跳过登录
- 既认不出登录记录也认不出标题页时明确停止,不再把「没认出来」当成目标账号已登录
- 自动同意只复用全局 IfAgreeBilibili(默认关闭),关着时不点、提示手动处理并停止
- 所有循环先查总时限,adb input tap 失败直接抛错
- 登录后必须连续两帧认出标题页才判完成,过渡空帧只算未知画面
- 修正上游说明:B 服资源已声明,但「切换账号」仍只声明官服;补上游评估与移除计划
- 新增状态机边界测试(未知画面/协议关闭/空帧/标题确认/失败重试/重启重验证)

jinghero commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

AUTO-MAS-Project/AUTO-MAS #1882 · 复审

喵,这次修复已对上上一轮的五个问题:登录成功后才缓存结果,重启后重新验证;未知画面明确失败;自动同意复用 IfAgreeBilibili;隐私提示循环有界且检查点击失败;交接前要求连续两帧标题信号。已沿真实重试和逐账号创建 runner 的路径核对,不再把这些原问题列为未修复。以下仍是静态审查,未运行项目代码、测试或真机流程。

仍需处理

  1. [P2|项目边界] 临时补位说明还缺上游评估依据。
    login.py:53–56 以“MAS 侧运行前编排”解释未向上游提出方案,但这里实际执行的是游戏内登出、选号和登录。项目黑箱规范 明确把这类动作归上游,临时补位需要上游不受理或周期阻塞等依据。已确认上游有 B 服资源、尚无等价昵称选号入口,移除计划也补上了;“目前没有入口”仍不能替代这个判断。请补可核实的上游评估/受阻依据,或请维护者明确该例外,再决定保留补位还是移到上游。这是项目规范问题,不是重新认定运行时串号。

文案建议(非阻断)
三语登录说明及账号提示 仍写“原版只支持官服”,账号提示仍说填写后自动加入官服切号,也未说明全局协议开关默认关闭。建议同步中英日文案,并按登录模式说明完整昵称的用途。钩子契约 仍写重试重开模拟器不再登录,也建议与这次正确的重启重验证行为同步。

验证还差当前提交的证据

  • 新增状态机测试已有实质覆盖,但 runner 的两项测试是直接调用 helper,尚不等于完整调度链验证。请补当前版本的最小回归结果,重点核对首次登录失败后重试不会下发未登录任务、隐私提示持续存在时能超时,以及标题/空帧交替不会提前成功。
  • PR 正文的测试和双账号 4/4 记录仍对应上一版。当前 Python Tests、格式、构建、锁文件、更新日志与误回退检查均为 action_required,只有碎片标签同步成功,不能视为新提交 CI 通过。请补当前版本的命令、环境及结果,以及登录失败后重试、目标账号切换、协议开关关闭等真实场景的脱敏验证记录。上述场景均未由本次审查独立运行。

本次没有确认新的正常 ADB+B 服路径 P1。隐私处理循环现在有界,但各阶段分开计时,并非注释所称的共享 240 秒总预算;这点可同步澄清,不再按原来的无限循环问题重复报。

—— dot酱敬上 🐾

@Douya36

Douya36 commented Nov 8, 2026

Copy link
Copy Markdown
Author

感谢评审,逐条处理如下(修复提交 d4040ca8,已推送到本 PR)。

P1 重试正确性

  • runner_task._ensure_logged_in 改为登录成功后才置 _login_checked;失败保持未完成,重试会重新走登录钩子。
  • 客户端被重试重启(_restart_client_before_retry 关闭游戏/模拟器)时清掉标记,下一轮重新验证。
  • 测试:test_failed_login_is_retried_not_skipped、test_client_restart_resets_login_marker。

P1 账号隔离

  • 删除「等 60 秒按已登录继续」的回退;既认不出登录记录、也认不出标题页时明确抛错停止(提示把游戏放到标题页或登录界面),不再用「识别缺失」代替成功。
  • 测试:test_unknown_screen_stops_instead_of_assuming_logged_in。

P1 用户授权

  • _agree_privacy 复用全局 Config.setting.Function.IfAgreeBilibili(默认关闭):关闭时不点「同意」,抛错提示手动处理并停止本次登录,不新增第二份开关。
  • 测试:test_privacy_prompt_requires_agreement_switch、test_privacy_prompt_clicked_when_switch_on。

P2 超时

  • 所有等待循环先查总时限再处理画面(主循环、_wait_panel_closed)。
  • adb input tap 检查退出码,失败直接抛错。

P2 结果判定

  • 登录后必须连续两帧认出标题页才判完成(_TITLE_CONFIRM_FRAMES = 2);过渡空帧 / 黑屏 / OCR 漏字只算未知画面,继续有界等待,到点失败。
  • 测试:test_empty_frames_do_not_declare_success、test_title_frames_confirm_handover。

说明修正

  • 「原版只声明官服」→「上游 interface 已声明 B 服资源,但「切换账号」仍只声明官服、没有按昵称选号的入口」;并在 AGENTS.md / login.py 补了上游评估与移除计划。

验证记录

  • ruff format --check .(986 files)、ruff check 通过
  • pytest tests/task/test_m9a_login_flow.py tests/task/test_m9a_login_mode.py tests/task/test_maafw_core.py -q → 26 passed
  • vp lint(0/0)、vp fmt --check、vue-tsc、i18n 审计、changelog 检查通过
  • CI 目前仍为 action_required(首次贡献的 fork PR 需维护者放行)

关于「实际 MAS 调度链证据」

本机验证时 MAS 调度侧链路已跑通(运行日志原文):

  • MaaFW 运行总览: project=M9A; version=v4.13.1; controller=ADB; resource=B 服; preset=自定义; enabled_tasks(3)=启动游戏 -> 领取奖励 -> 关闭游戏
  • [M9A] 已开启 MAS 登录:Info.Account 是 MAS 登录要选中的账号昵称,不再加入切换账号
  • [M9A] 已自动加入:启动游戏 / 关闭游戏
  • 运行环境准备成功:MaaFW Agent OK、运行前运行环境已重新准备完成

但进入「启动模拟器」阶段后,本机 dev 构建调用 MuMuManager.exe info -v 0 稳定返回 0xC0000409(同一命令从 cmd / PowerShell 调用正常;python / node 作父进程必崩,已排除 Python 版本、creationflags、stdio、env、cwd、父进程镜像名等因素),导致 MAS 无法管理 MuMu 实例,游戏内登录 → StartUp 这一段无法在 MAS 内完成。正式版 v5.7.0 的 mumu.py 调用方式与 dev 相同,因此判断为该机器上的环境问题,与本 PR 的登录逻辑无关。

登录流程本身已在真机(MuMu 12 + com.shenlan.m.reverse1999.bilibili)上单独验证:两个已保存账号四轮自动切换 4/4 通过(每轮 21–22 秒),隐私提示 / 登出 / 选号 / 回到标题页均正常。脱敏截图可按需补附。

- 三语登录说明与账号提示按登录模式区分:M9A 登录时账号加入「切换账号」(官服),MAS 登录时账号是登录记录的完整昵称、只用于选号,并说明全局协议开关默认关闭
- ensure_logged_in 契约改为「登录成功才记完成,失败与客户端重启后重新验证」
- 隐私提示各阶段分别计时,更正「共享 240 秒总预算」的注释
- 新增隐私提示持续存在、标题与空帧交替不提前判成功的回归测试
@Douya36

Douya36 commented Nov 8, 2026

Copy link
Copy Markdown
Author

感谢复审。已按意见更新,新提交 ba3d98c8。

文案与契约同步

  • 三语(zh_CN / en / ja)的登录说明与账号提示已按登录模式区分:
    • 「由 M9A 登录」:账号会加入「切换账号」(官服);
    • 「由 MAS 登录 B 服」:账号是登录记录里显示的完整昵称,只用于选中目标账号,不会加入「切换账号」;
    • 两种模式都说明:自动同意隐私提示复用全局「同意哔哩哔哩用户协议」开关(默认关闭),未开启时登录会停下并提示手动处理。
  • ensure_logged_in 钩子契约已改为「登录成功后才记完成;失败时下一次尝试重新调用,重试关闭游戏 / 模拟器(客户端重启)后重新验证」。
  • _LOGIN_TIMEOUT 注释已更正:主循环与等面板关闭分别计时,不是共享 240 秒总预算;整轮仍受 Run.RunTimeLimit 硬超时兜底。

当前提交的验证记录

  • pytest tests/task/test_m9a_login_flow.py tests/task/test_m9a_login_mode.py tests/task/test_maafw_core.py -q → 28 passed
  • 新增两条边界回归:
    • test_privacy_prompt_persists_until_timeout:隐私提示一直存在、点完同意又弹回时,在时限内失败而不是无限循环;
    • test_alternating_title_and_empty_frames_do_not_succeed:标题帧与空帧交替时凑不出连续两帧,不提前判成功。
  • ruff format --check .(986 files)、ruff check、vp lint、vp fmt --check、vue-tsc、i18n 审计、changelog 检查均通过。
  • PR 正文已更新为当前提交的命令、环境与结果。
  • CI 仍为 action_required(首次贡献的 fork PR 需维护者放行),放行后会跑 Windows + Ubuntu 全量测试。

关于「临时补位缺少上游评估依据」(P2)

先补可核实的事实依据:

  • 上游 M9A v4.13.1 的 interface.json 已声明 B 服资源({"name": "B 服", "path": ["./resource/base", "./resource/bilibili"], "controller": ["ADB", "PlayCover"]}),所以「能启动 B 服」成立;
  • 但「切换账号」任务仍只声明官服,且整个 interface 没有「按 B 站昵称选号」的入口——Info.Account 无法交给上游;
  • 已检索 MAA1999/M9A 的 issue(关键词:切换账号 B服 / bilibili 登录 / 选号),没有相关诉求或既有提案;
  • MAS 侧按黑箱规范不读取 / 反推上游内部状态,因此无法复用上游的登录记录或会话。

因此这一步确实是「脚本该干的活、上游暂无入口」。按规范我们应当先评估向上游提 PR,但本项目目前没有形成该提案(开发验证阶段),于是临时补位在 MAS 的运行前钩子里,并在 AGENTS.md / login.py 标注了移除计划。

请维护者明确一下这个例外是否被允许(复审意见里也给了这个选项):

  • 若允许:我们保持现状(临时补位 + 移除计划),并在上游提供等价入口后删除;
  • 若要求先走上游:我可以按你们的格式在 MAA1999/M9A 提一份 feature request(例如「按昵称选择已保存的 B 站账号」),把链接补进 PR 作为评估依据,MAS 侧实现等上游受理后再定去留。

关于「真实场景脱敏验证记录」

本机 dev 构建的模拟器管理有一个环境问题:MuMuManager.exe info -v 0 在由 python 父进程拉起时稳定返回 0xC0000409(cmd / PowerShell 拉起正常,已排除 Python 版本、creationflags、stdio、env、cwd、镜像名),导致 MAS 无法管理 MuMu 实例,登录失败重试 / 目标账号切换 / 协议开关关闭这三条真实场景在 MAS 内无法跑完。登录模块本身在真机上单独验证过:两个已保存账号四轮自动切换 4/4 通过(每轮 21–22 秒)。等模拟器问题解决后可以补完整 MAS 调度链的脱敏录屏。

@jinghero

jinghero commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

M9A确认不做隐私协议,我是现场怪,后续评审不纳入考虑,等正式版后没问题就合

@AthenaHibou
AthenaHibou requested a review from qiyinxi November 8, 2026 11:56

jinghero commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

总体结论:可以合并

AUTO-MAS-Project/AUTO-MAS #1882 · 复审补充

宝宝,登录说明这次和实际行为对上啦:完整昵称怎么用、协议开关默认关闭、失败重试和客户端重启后重新验证,都说清楚了。两条新增测试也分别检查了隐私提示反复出现时能超时、标题与空帧交替时不能提前报成功,补到了前面点出的具体场景喵。

维护者已说明 M9A 不处理隐私协议,并明确这部分不再纳入后续评审。dot酱按这次取舍收回对应的上游评估阻断,不再为同一选择反复追问;这不扩大为其他游戏内能力的通用豁免。本轮增量只有说明、翻译和测试,没有再改生产登录逻辑,静态核对未发现新的必须修改项。

合并时点仍按维护者说的“等正式版后没问题就合”。作者报告的 28 passed 是本机记录,完整 MAS 调度链的真实场景仍未跑完;当前 CI 已放行,已读取 Ubuntu 全量测试日志,结果为 1505 passed、26 skipped;Windows 测试和构建仍在运行,格式等检查已通过。dot酱没有执行项目代码,也不把这些未完成的验证写成已通过。等正式版验证和仓库检查齐了,再由维护者决定落合并键就好啦。

—— dot酱拍拍爪敬上 🐾

@qiyinxi qiyinxi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

鸡毛菜都可以合并了,没问题!

@AthenaHibou AthenaHibou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 上复跑登录流程,仅做了仓库内定向单测与静态审核。

Copy link
Copy Markdown
Member

已复核最新审核并推送修复:da8eb843d(fix(m9a): 修复私有 ADB 登录通道与控制器校验)。

  • 登录钩子传递 host_adb,魔改 AVD 的截图、点击、前台判断与拉起均走 MAS 私有通道;普通模拟器仍按 adb 路径和设备地址连接。
  • Win32 + LoginMode=Mas 在构建设备时明确报错,阻止静默跳过账号验证。
  • 截图转换为 BGR 后送 OCR;标题锚点改为 START/TART 整词匹配,去掉 ERS;非 16:9 首次截图给出提醒;检查 am start 失败。
  • 修正重启重验证注释、迁移变量名和超时说明;补登出→展开→选号→登录→标题确认的成功路径、私有通道/BGR 及 Win32 拦停回归。保留并提交审核建议的 AVD 关机预算浮点容差修复。

验证环境:Windows / Python 3.12.13 / Ruff 0.16.8,使用仓库 .venv。

  • .venv/Scripts/python.exe -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:38 passed。
  • 修改范围 Ruff check、format --check、git diff --check 与 python scripts/changelog.py check 通过。
  • 全量运行:1517 passed、21 failed、1 skipped(15 subtests passed)。这 21 项涉及其他模块的路径配置,测试临时目录位于应用目录内会被路径策略拒绝;已在原始 ba3d98c 隔离工作树复现同样 21 项失败,原始版本使用应用目录外临时目录重跑对应 150 项全部通过。因此不把本次全量执行写成全绿;未修改这些测试或路径策略。

黑箱归属说明已纠正:运行前调用不改变游戏内登录/登出/选号的归属;引用维护者已明确的隐私协议取舍,不扩大该例外,其余范围仍由维护者决定。遥测复用现有任务结局观察边界,不新增昵称、截图或逐帧采集。

@Douya36 麻烦基于 da8eb84 再做一轮实机测试,并补充脱敏结果:

  1. MuMu B 服两账号轮换,覆盖已登录标题页登出、按完整昵称选号、交给 StartUp 执行。
  2. 魔改 AVD 上同样跑一轮,重点确认私有 ADB 通道的截图、点击、前台拉起正常。
  3. 首次登录失败后重试不跳过登录,客户端重启后重新验证;协议开关关闭时拦停、开启时正常处理。
  4. Win32 + Mas 明确拦停;Project 模式保持原有流程。

本轮未操作真实游戏或模拟器;替身回归不代表实机已通过。请附模拟器/客户端版本、场景结果及脱敏日志或截图。

jinghero commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

总体结论:可以合并

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 标题、欢迎横幅、健康警告页

Copy link
Copy Markdown

#1882 追加一轮对抗性审查(基于 da8eb843d)

这轮重点不是看代码能不能跑通,而是按用户平时的操作顺序排查:定时运行、游戏没退出、多账号、弹窗遮挡、模拟器异常、运行中点停止。下面按严重程度排列,每条都附上建议改法。

先说明:前面提过的“登录失败后跳过验证”、Win32 静默跳过、私有 ADB 正常路径未接入、截图 BGR 等问题,这版已经有修复,不重复算旧账。以下有已反馈的实际问题,也有从当前代码推导出的条件性风险;后者需要补场景测试确认。

P1|建议合并前处理

1. 登录成功也可能被判失败(已有真实场景反馈)。

  • 场景: B 服登录完弹出欢迎横幅,把标题页的 START 挡住。MAS 目前只靠 OCR 连续看到 START/TART 才放行;挡住后就一直等,最后超时报错,重试也可能重复卡住。
  • 建议: 把“欢迎公告/弹窗遮挡标题页”做成明确状态:识别到可安全关闭的弹窗就关闭,再确认标题页;不要简单改成“看不到 START 就算成功”,否则会引入串号。请同时覆盖首次登录后和已有账号、准备登出切号时这两条路径。
  • 位置:login.py:标题识别、登录后等待、切号入口。

2. “点了目标昵称”还不等于“真正登录了目标账号”。

  • 场景: 选号点击没生效、面板状态异常,或者游戏里的登录会话没有切过去;当前只检查“目标昵称仍能被 OCR 看到 + 有登录按钮”,最后看到标题页就认定成功。并没有最终验证实际账号身份。多账号无人值守时,这比单纯报错危险:可能在错误账号上跑任务。
  • 建议: 至少确认目标账号确实变成选中状态;交给 M9A 执行账号任务前,尽可能通过可靠的账号标识再核对一次。若没有可靠标识,就不要把“返回标题页”表述为“账号身份已确认”,异常情况应停止而不是猜。
  • 位置:login.py:选号确认与完成判定。

3. MAS 登录模式没有校验是不是 B 服,可能用错客户端。

  • 场景: 用户切了 LoginMode=Mas,但资源还选“官服”,或手动填了官服包名。代码直接忽略 resource_name,沿用传入的包名去执行 B 服登录。普通配置失误会变成难排查的登录失败,甚至操作错客户端。
  • 建议: 在运行前校验 Mas 只允许 B 服资源,并检查实际包名是否为 com.shenlan.m.reverse1999.bilibili;不匹配直接给出清楚的提示。最好在检查/更新游戏、启动客户端之前拦截,前端也给出提示。
  • 位置:login.py:忽略资源与使用包名。

4. 用户点停止后,旧 ADB 点击可能还没真正停(条件性并发风险)。

  • 场景: 普通 ADB 路径用 asyncio.to_thread(subprocess.run)。取消协程不会自动终止线程里已经启动的 adb 子进程。极端情况下,用户停止任务、队列开始下一个账号时,上一轮迟到的点击才落到模拟器上。
  • 建议: 把 ADB 子进程纳入可取消的生命周期管理(例如异步子进程,取消时 terminate/kill 并 wait);确认本轮所有设备操作停止后才允许下一个账号操作同一设备。补“ADB 卡住 → 用户停止 → 下个账号启动”的回归测试。
  • 位置:login.py:ADB 执行入口。

5. 魔改 AVD 正常路径修好了,但查询私有通道失败时仍可能退回 5037(条件性风险)。

  • 场景: resolve_host_adb() 遇到异常会返回 None;登录模块就退回普通 adb。如果设备其实是魔改 AVD,这个降级可能让宿主又去碰默认 ADB server,与其他模拟器发生冲突。
  • 建议: 先区分“确定是普通模拟器”与“确定是魔改 AVD 但私有 ADB 出错”。前者可走普通 ADB;后者直接报错,不要静默降级。补私有通道获取失败的测试。
  • 位置:emulator_core.py:降级分支。

P2|建议补齐正常使用场景

6. 游戏已经停在主界面,定时任务反而跑不起来。 昨晚手动玩完没退出,第二天 MAS 认不出标题页或登录记录,会等约 60 秒后失败;这次拒绝串号是正确的,但正常状态不该只能让用户手动退回。建议支持安全返回标题页/登录记录再选号,做不到时明确提示并停止,不能直接放行。相关代码。

7. 明显靠重试解决不了的错误也会重试。 账号没填、昵称不存在、协议开关关闭、资源选错等属于配置/人工处理问题;重启游戏或模拟器只会浪费时间,甚至让用户刚准备处理的界面消失。建议把登录失败分成“可重试(临时截图/连接失败)”和“不可重试(配置错误/需要人工操作)”,后者直接结束本账号并给出原因。相关代码。

8. 登录准备时间没算进 Run.RunTimeLimit。 登录在 _build_device_config 阶段执行,而 RunTimeLimit 到 _run_maafw 才开始计时;前台等待、登录主循环、登录后确认又是分段超时,叠上重试后可能远超用户设定的运行上限。建议明确“全程上限”和“脚本任务上限”两种语义,或从本轮开始就传递同一个 deadline,避免超时叠加。设备准备 / 计时开始位置。

9. 保存的账号多了就找不到。 现在只在当前可见的登录记录里按完整昵称匹配,目标账号在下方需要滑动时会直接报“找不到”。建议增加有次数上限的滚动查找,划到底仍找不到才失败,同时处理同名账号不能区分的情况。相关代码。

10. 切登录模式可能把旧切号配置清掉。 在 Mas 模式下 supports_account_switch=False,保存/整理快照会移除旧 SwitchAccount 任务及对应选项;用户再切回 Project,原来的多账号切号配置可能恢复不了。建议切换模式时只隐藏/禁用不适用的任务,或先保留可恢复的原配置,并给出明确提示。相关代码。

11. 固定坐标和单独的“确认”文字容易点错。 现在看到标题页就点固定退出位置,之后只找唯一“确认”;如果有其他弹窗、布局改变或不是 16:9,可能点错。建议同时识别弹窗类型/标题 + 按钮所在区域,确认是“退出当前账号”的弹窗再点击;不符合预期就停下让用户处理,不能只靠“确认”两个字。相关代码。

建议补的验收场景

至少覆盖:欢迎横幅挡住 START、已在主界面、B 服/官服配置不匹配、两个以上账号且需要滚动、登录未真正切换成功、私有 ADB 获取失败、ADB 操作中停止并切下个账号、错误配置不重复重启、切换登录模式后配置可恢复。

我的结论:这次不建议仅凭现有 CI 通过就合并。当前测试大多是预设 OCR 画面的替身测试,不能覆盖弹窗、真正选号结果和停止时的迟到 ADB 操作。建议优先处理 P1,再用实机/模拟器把这些组合场景走一遍。以上未声称每条都已实机复现。

@Douya36

Douya36 commented Nov 9, 2026

Copy link
Copy Markdown
Author

已按复审要求更新,推送 6c2e0ef0(含最新 dev 合并 3499a907)。

1. 同步最新 dev

  • 合并上游 dev(c3f6c11b,含 v5.8.0 与四级调度重构 refactor(scheduler)!: 迁移四级调度与任务运行树 #1845),无冲突
  • 相关测试 41 passed;全量 pytest tests → 1733 passed / 2 failed / 22 error,这 2+22 在干净 upstream/dev worktree 上同样复现(环境问题:临时目录与路径策略),不是本次改动引入

2. 根据实机反馈修正标题页识别

实机(MuMu 12 + B 服客户端 V4.1.0-113.0.1421-180)验证时发现两个问题:

  1. 登录成功后标题页的 START 太淡,OCR 读不到;实际能读到的只有副标题 REVERSE 的残词 ERS / ERSE。
  2. 冷启动会先出现「警告:请在游戏前阅读」健康警告页,而登录钩子跑在 M9A StartUp 之前。

已修正(提交 6c2e0ef0):

  • 标题页锚点改为 START / TART / ERSE 整词匹配(比旧版的裸 ERS 更精确,避免误判)
  • 登录成功顶栏的「<昵称> 欢迎回来」横幅也作为标题页正向信号
  • 冷启动的健康警告页先点一下继续
  • 新增 3 条回归:ERSE 标题、欢迎横幅、健康警告页

3. 实机验证结果

  • 协议开关关闭:4/4 轮全部被正确拦停(「检测到 bilibili 隐私政策提示,但未开启「同意哔哩哔哩用户协议」」)
  • 协议开关开启 + 单账号全流程:结果: 成功,说明「B 服登录完成,已确认回到游戏标题页,交给 M9A 进游戏运行」;期间依次完成 隐私同意 → 登出当前账号 → 按完整昵称选号 → 登录 → 标题页确认
  • 说明:连续 4 轮切换的验证脚本在本机遇到模拟器 adb 掉线 / 游戏状态问题(与登录模块无关),单账号全流程已在真机跑通;脱敏截图可按需提供

4. CI

仍为 action_required(首次贡献的 fork PR 需维护者放行),放行后会跑 Windows + Ubuntu 全量测试。

jinghero commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

总体结论:可以合并

AUTO-MAS-Project/AUTO-MAS #1882 · 复审补充

宝宝,标题页这次多了两条有明确依据的识别路径:ERSE 整词和“欢迎回来”横幅;冷启动的健康警告也会先处理。没有把“登录面板消失”偷换成“登录成功”,连续两帧确认、隐私开关和超时退出都还在,这点守住啦。

dot酱对照了新增识别分支、对应回归测试,以及合入当前 dev 后的登录调用和重试接线;本轮静态核对没有确认新的必须修改项。模拟器关闭测试只给浮点误差留了 1 微秒余量,生产的 28 秒预算没有放宽。

不过这次还不能拿 CI 给真机盖章喵:当前 Python Tests 等检查停在 action_required,只有标签同步检查通过。作者补充的单账号实机成功和 41 项测试通过属于作者侧记录,连续多账号轮换仍未完成;dot酱没有运行项目代码、测试或游戏。合并时点继续保留维护者已确认的正式版与实机验收条件。

—— dot酱拍拍爪敬上 🐾

jinghero commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

总体结论:修改后合并

宝宝,这轮以 6c2e0ef02aabb2ae1075f0b9008e82ad777d4454 对照 dev@c3f6c11b6e0807e49084869b6d4ecdf2b3733198 从头审查,未参考既有审核评论。按 pstack 的调用链、影响范围、边界契约、重试幂等性、进程生命周期和类型规则核查后,有 3 项 P2 建议合并前修正,另有 1 项非阻断的 P3。

逻辑

1. [P2] 登录钩子执行前,ADB 路径还没有完成既有的自动发现

位置:runner_task.py:1411–1414、login.py:229–232。

_resolve_adb_path() 返回 None 是现有受支持的路径,原本交给 worker 的 Toolkit.find_adb_devices() 按设备地址补齐。新钩子在 worker 前执行,却把 None 直接换成系统命令 adb。

具体例子是当前支持的「通用模拟器 + BlueStacks」:程序选 HD-Player.exe,实例填 --instance Pie64 | 127.0.0.1:5555,BlueStacks 已开启 ADB,Device.AdbPath 留空,系统 PATH 没有额外安装 adb。通用管理器可以启动模拟器并返回地址,但宿主只派生同目录的 adb.exe,BlueStacks 自带程序实际叫 HD-Adb.exe。项目锁定的 MaaFramework 5.12.3 发现规则 已支持这个布局。

已执行真实 GeneralDeviceManager.open → _resolve_adb_address → _resolve_adb_path → _build_device_config → 登录钩子 的边界重放,结果为 ONLINE → adb_path=None → FileNotFoundError: 'adb';对照现有 worker 的发现入口,能接收并使用 HD-Adb.exe。只有模拟器进程与 Windows 发现结果使用替身,宿主逻辑和 subprocess 报错均为实际执行。

建议在调用登录钩子前完成既有的按地址发现,并传入确定的 ADB 路径。复用同一套发现能力即可。

2. [P2] 初始加载被固定 60 秒截断,调大启动等待时间也无效

位置:login.py:629–636,调用时序见 runner_task.py:1411–1414。

登录钩子在 worker 的启动等待之前执行,把尚未出现登录记录或标题信号的加载画面也计入 _UNKNOWN_SCREEN_SECONDS=60。所以用户配置的 Game.WaitTime 和本模块的 _LOGIN_TIMEOUT=240 都无法让这段冷启动继续等到就绪。

我用真实 M9AConfig、运行计划、_build_device_config() 和登录状态机复现了一个明确条件:Game.WaitTime=120,设备已在前台,第 80 秒才出现登录记录。当前代码第 60 秒抛出“无法确认当前账号”,点击次数为 0,此时已有启动等待预算仍剩 60 秒。同一画面序列只放宽未知画面预算,便在第 86 秒完成选号、登录和标题页确认。这是虚拟时钟与 OCR 边界重放。

这会让加载耗时超过 60 秒的客户端在就绪前进入失败重试。建议让登录前的加载等待服从已有启动预算,区分“仍在启动”和“已就绪但无法确认账号”;到期仍无法确认账号时继续失败,保留当前防止串号的边界。

3. [P3,非阻断] 标题信号漏掉了完整的 REVERSE

位置:login.py:101–103、login.py:220–223。

注释把 logo 的 REVERSE 作为标题信号,实际却只对 START / TART / ERSE 做精确集合匹配。若 START 漏识、欢迎横幅已消失,而 OCR 正确读出完整 REVERSE,就会一直无法确认标题。

实际函数对照中,标题 OCR 只含 START 或 ERSE 时 _wait_panel_closed() 成功,只含 REVERSE 时超时。这个输入行为已复现,未将该画面组合称为真机实测。建议把完整 REVERSE 加入支持列表,并保留连续帧确认。

整体与生命周期

4. [P2] 普通 ADB 子进程没有接入停止清理

位置:login.py:244–250。

host_adb is None 时直接 asyncio.to_thread(subprocess.run, ...),创建的子进程没有登记到 TaskProcessScope。停止任务会取消等待协程,但不会终止线程里已经启动的命令;CancelledError 向上传播并不等于外部命令已停止。

已沿真实 TaskExecuteBase.stop() 的停止检查、force_close()、final_task() 完整路径做对照。用启动后延迟 0.8 秒写文件的本地子程序替代 ADB:当前实现中 stop() 返回、收尾完成、scope 关闭后,实际子进程句柄仍存活,随后出现写入;相同任务和子程序改走现有 ProcessRunner 后,停止时子进程被回收,没有迟到写入。这是实际进程执行证据,并非只测裸 Task.cancel()。

因此普通 ADB 的未完成命令无法随任务停止被回收,点击或拉起客户端的操作仍可能继续完成。当前还有命令自身的 15–30 秒超时,这不是无限期残留。

建议复用现有 受管进程创建入口 和取消清理。截图分支保留 PNG 原始 bytes,不要直接换成只返回解码文本的接口。

本轮在 Linux / Python 3.12.13、uv sync --locked --group dev 环境重跑 test_m9a_login_flow.py、test_m9a_login_mode.py、test_maafw_core.py、test_avd_shutdown.py,结果 41 passed;改动 Python 文件的 ruff check 和 git diff --check 通过。以上新增复现均已复跑,证据范围为实际宿主代码、边界重放及本地子进程生命周期;Windows、BlueStacks 和 B 服客户端的真机流程仍需对应环境验收。

- 认不出画面时的预算取 Game.WaitTime(上限仍是登录主循环 240 秒),冷启动加载画面不再误判
- 宿主推不出 ADB 路径时先按地址问 MaaFW Toolkit,钩子不再退回 PATH 里的 adb
- adb 子进程改走受管入口:任务停止时随作用域回收,截图保留 PNG 原始 bytes
- 标题锚点补完整 REVERSE(实机 OCR 有时能读全)
- Mas 模式只接受「B 服」资源与 B 服包名,配错客户端在碰模拟器之前报错
@Douya36

Douya36 commented Nov 9, 2026

Copy link
Copy Markdown
Author

@jinghero 谢谢,这轮按你基于 6c2e0ef0 的四条逐项改了,最新提交 288c4a80(在 6c2e0ef0 之上,dev 已是最新)。

1. [P2] 登录钩子执行前完成 ADB 发现
新增 runner_task._resolve_adb_path_by_toolkit():_ensure_logged_in 在 adb_path is None 时先按设备地址问 MaaFW Toolkit(与 worker _resolve_adb_device 同一套规则),拿到路径就写进运行日志再交给钩子;拿不到 / 没有 Toolkit 时保持原行为(交给 Runner),不再让钩子退回 PATH 里的 adb。
回归:test_login_hook_receives_toolkit_discovered_adb_path、test_toolkit_discovery_matches_device_address。

2. [P2] 初始加载不再被固定 60 秒截断
认不出画面的预算改为 max(60, Game.WaitTime),上限夹在登录主循环 240 秒内(login._unknown_screen_budget)。默认 Game.WaitTime=120,所以 WaitTime=120、第 80 秒才出现登录记录的场景现在能等到;「已就绪但认不出」到期仍按原边界失败(保留防串号),失败文案会带上实际等待秒数,方便区分「还在启动」和「停在别的画面」。
回归:test_unknown_screen_budget_follows_game_wait_time、test_slow_loading_is_not_cut_off_by_fixed_budget(后者在 6c2e0ef0 上按 0.2 秒预算失败,修复后通过)。

3. [P3] 标题信号补完整 REVERSE
_TITLE_HINTS 现在是 ("START", "TART", "REVERSE", "ERSE"),连续帧确认不变。
回归:test_title_logo_full_word_confirms_handover。

4. [P2] 普通 ADB 子进程接入停止清理
_Device 改为 create_subprocess + stop_process(kill_tree=True):取消 / 超时先回收子进程再抛出;截图分支用 exec-out 保留 PNG 原始 bytes,不经过文本解码。
回归:test_adb_command_is_stopped_when_task_is_cancelled;本次实机全流程的截图 / 点击 / dumpsys / am start 都走这条新路径。

另外把对抗性审查里成本最低的一条一起做了:Mas 只接受「B 服」资源与 com.shenlan.m.reverse1999.bilibili 包名,配错在碰模拟器之前就报错(test_mas_login_rejects_* 三条)。

验证: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;新增 10 条在 6c2e0ef0 的干净 worktree 上全部失败,修复后通过。实机(MuMu 12 + B 服 V4.1.0-113.0.1421-180)两轮成功:未登录全流程、已登录登出重选(31.4 秒);协议开关关闭仍按预期拦停。截图可按需提供(昵称需遮挡)。

仍未处理(既有边界,本轮未改):登录成功后不校验游戏 UID(只按昵称选号 + 标题页连续帧确认);登录记录列表不滚动查找;登录失败的可重试 / 不可重试分类没拆;Toolkit 发现只有单测覆盖,MuMu 真机走的是安装目录推出来的路径、没触发这条。

@qiyinxi

qiyinxi commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

为啥把StartUp加名单里了? @Douya36 这个后面记得看一下,因为不把startup加进去是有原因的

@qiyinxi

qiyinxi commented Nov 9, 2026

Copy link
Copy Markdown
Member

不挡合并但是后续的优化方向:

  1. 登录改走 MaaFW pipeline 重写(可以写好pupeline后直接进runner,插在startup和后面实际任务之间
  2. 改文案:PR 里把开关叫「同意哔哩哔哩用户协议」,还让用户「在设置里打开」,这和开关实际的名字、位置都对不上
  3. 资源不是「B服」时把「由 MAS 登录 B 服」置灰;现在选官服也能选 Mas,要到拉起客户端之后才报错

@qiyinxi
qiyinxi merged commit a6a377c into AUTO-MAS-Project:dev Nov 9, 2026
9 checks passed
@youngslin

Copy link
Copy Markdown

我说回头要是没事干倒是可以把这个修补修补()

@Douya36

Douya36 commented Nov 9, 2026

Copy link
Copy Markdown
Author

@qiyinxi 谢谢,两条都回了。

1. StartUp 进 abort 名单

是我们加的(0c4f9cc0),上游 dev 里 abort_round_entries 只有 {SwitchAccount: "切换账号失败"},这点你说得对。当时的想法是 Mas 模式下 StartUp 就是「从标题页进游戏」那一步,失败后继续跑任务大概率全停在标题页上,想早点结束本轮。

已经按上游口径回退(57e3430d):名单里只保留 SwitchAccount,StartUp 失败回到普通任务失败、本轮照常继续;app/task/M9A/AGENTS.md 和回归测试同步改了(test_only_account_switch_aborts_round 现在断言 StartUp 不在名单里,SwitchAccount 在)。

想确认一下你说的原因,好把注释写准:是指「StartUp 失败不代表游戏用不了」(比如已经在游戏内、只是没找到入口,后面任务还能跑),还是另有考虑?我们不想再猜着加回去。

2. 三条优化方向

  1. 改走 MaaFW pipeline:认同,这也是把选号从宿主 adb 状态机收回上游的正路,MAS 侧只保留「在 StartUp 之后、实际任务之前插一段」的编排。这条按后续 PR 做(本轮先把已知短板修完),到时候按你们的 pipeline 约定单独提。
  2. 文案:已改(57e3430d)。现在提示是「未开启「托管Bilibili游戏隐私政策」;请在「设置 → 功能设置 → 神秘入口」里打开该开关后重试」。原来写「同意哔哩哔哩用户协议」和「在设置里」确实都和实际名字、位置对不上。
  3. 资源不是「B 服」时置灰:认同。这里的坑是「生效资源」不等于表单值(Info.Resource 留空时会按控制器回落),前端自己判断会判错,所以打算把判断接在 /maafw/preview / 运行计划的 resourceName 上,并把后端校验从登录钩子(拉起客户端之后)提前到运行计划构建阶段。同样放后续 PR,本轮不动。

@Douya36

Douya36 commented Nov 9, 2026

Copy link
Copy Markdown
Author

补一句状态说明:这个 PR 已经在 21:56 合入(squash 合并提交 a6a377ca),我上一条说的回退(57e3430d)是在合并之后才推上分支的,所以不在合并结果里。

为了让它真的落地,已单独开后续 PR #1896(fix/m9a-startup-and-privacy-wording,基于最新 dev,4 文件 +13/−12):只做两件事——把 StartUp 从 abort_round_entries 去掉、把隐私开关文案对齐「托管Bilibili游戏隐私政策 / 设置 → 功能设置 → 神秘入口」。pipeline 重写与资源置灰按上一条说的另开 PR。

qiyinxi pushed a commit that referenced this pull request Nov 9, 2026
## 摘要

- 把 `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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

专项: M9A 类型: 新增 按更新日志碎片自动设置

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants