Skip to content

feat(maafw): 启动模拟器时按项目包名一并拉起游戏 - #638

Merged
qiyinxi merged 3 commits into
AUTO-MAS-Project:devfrom
qiyinxi:feat/maafw-game-package-20260909
Sep 9, 2026
Merged

feat(maafw): 启动模拟器时按项目包名一并拉起游戏#638
qiyinxi merged 3 commits into
AUTO-MAS-Project:devfrom
qiyinxi:feat/maafw-game-package-20260909

Conversation

@qiyinxi

@qiyinxi qiyinxi commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

摘要

  • MFW 用 Adb controller 时只开模拟器,游戏要等脚本自己那套流程冷启动。现在启动模拟器时可一并把游戏拉起来,接上 fix(emulator2): 带包启动改为三路齐发,并挡住被别家模拟器顶包的序列号 #635 的模拟器带包启动能力。
  • 包名默认从项目里自动识别:interface.json 中并没有包名字段(ProjectInterface 规格里就没有这一项),真正的包名写在 pipeline 节点的 StartApp 动作参数里。M9A 的九个服各自在 resource/<服>/pipeline/startup.json 覆盖同一个节点,靠 resource[].path 顺序叠加;MaaEnd 则放在 option 的 pipeline_override 里、取决于所选 ClientVersion。两种放法都已覆盖。
  • 这是约定而非契约,因此识别不出、或识别到多个互相矛盾的包名时一律不猜,回落到手动填写并在运行日志中说明原因。配置只新增 Game.PackageName 一项:填了即手动覆盖,留空即自动识别,同一概念不让用户选两次。
  • 顺带修正任务前后脚本的触发次数:此前前脚本在重试循环内、后脚本在每次尝试的 finally 内,一个用户重试三次就各跑三遍;现改为每用户各一次。后脚本仍保留在 finally,成功、重试全败与中途取消都会跑到。

本地验证

包名识别对着两个真实项目逐项实跑:

项目 结果
M9A 九个服(官服 / B 服 / OPPO / 小米 / 华为 / EN / JP / KR / 港澳台) 各自得到正确包名,含 base + global_jp + global_en 这类三层叠加
MaaEnd 五个 option case(CN / Bilibili / Global / VN / Cloud) 各自得到正确包名
顺序敏感性 颠倒 resource[].path 顺序会得到上一层的包名,符合覆盖语义
冲突与空输入 分别得到 ambiguous(附候选列表)与 not-found,均不猜测

前后脚本改动实跑 main_task 三条路径对照:

场景 改动前 改动后
第一次即成功 前 1 次 / 后 1 次 前 1 次 / 后 1 次
重试 3 次全失败 前 3 次 / 后 3 次 前 1 次 / 后 1 次
首次尝试时取消 前 1 次 / 后 1 次 前 1 次 / 后 1 次,CancelledError 仍正常外抛

自动化:python -m pytest tests 744 passed / 3 skipped(新增 13 个纯逻辑用例 + 8 subtests,并更新既有 test_maafw_config 的字段数量断言);收集门槛 --collect-only 747 条退出码 0;ruff format --checkruff check 对改动文件无问题;python scripts/changelog.py check 退出码 0。前端 yarn typecheckyarn lint 无问题,OpenAPI 由生成器更新(生成物为 CRLF,已按仓库行尾归一化,净差异仅 MaaFWConfig_Game.ts 一个文件)。

已知问题(均非本 PR 引入)

  • frontend/electron/services/backendService.test.ts 有一个用例稳定超时失败;本 PR 未改动 frontend/electron/ 下任何文件。
  • 后端 tests/task/test_maafw_embedded_prepare_cancel.py 的三个用例在仅按 uv sync --group dev 建立的环境下失败,原因是 dev 依赖组未包含 pytest-asyncio;补装后全部通过,上述 744 即为补装后的结果。
  • 任务前后脚本的触发口径在各专项间并不一致(MAA 与 HSR 为每用户一次,其余七个在重试循环内;取消时跑收尾脚本的此前仅 MaaFW 一家)。本 PR 只调整 MaaFW,统一其余专项宜另行处理。

🤖 Generated with Claude Code

Sourcery 摘要

允许 MFW 模拟器运行自动启动已配置的游戏,并执行按用户划分的生命周期脚本,同时避免重试导致脚本重复执行。

新功能:

  • 启用 MFW ADB 模拟器启动时同时启动关联的 Android 游戏,支持使用手动配置的软件包名称,或通过基于项目的安全自动检测来确定软件包名称。
  • 添加 Game.PackageName 设置及相应的界面、API 模型和本地化说明,以支持手动覆盖或在必要时回退到自动检测。

错误修复:

  • 防止 MFW 任务前置脚本和任务后置脚本在每次重试时重复运行,改为每个用户仅执行一次,同时保留在成功、失败和取消情况下执行任务后置脚本的行为。

增强功能:

  • 从分层资源管道和任务管道覆盖配置中检测游戏软件包;当未找到软件包或发现冲突的软件包时拒绝猜测,并在任务日志中报告检测结果。

文档:

  • 在变更日志中记录新的 MFW 模拟器游戏启动行为以及按用户执行脚本的语义。

测试:

  • 增加对软件包规范化、管道提取、资源分层、任务覆盖、歧义处理、数据缺失和无法读取的管道文件的测试覆盖。
  • 更新 MFW 配置清单预期,以包含新的游戏软件包设置。
Original summary in English

Sourcery 摘要

允许 MFW 模拟器会话自动启动游戏,同时使生命周期脚本按每位用户执行一次,而不是每次重试执行一次。

新功能:

  • 支持 MFW ADB 模拟器运行在启动模拟器的同时启动已配置的 Android 游戏,可使用手动指定的包名或基于项目的安全自动检测。
  • 在后端、API 模型、前端配置和本地化 UI 中新增 Game.PackageName 设置。

错误修复:

  • 确保 MFW 的每用户 before-task 和 after-task 脚本按每位用户执行一次,而不是在重试时重复执行,同时保留 after-task 脚本在成功、失败和取消情况下的执行。

增强功能:

  • 从分层资源管道和选定的任务覆盖设置中检测游戏包,并在候选项缺失或冲突时报告问题,而不是进行猜测。

文档:

  • 在更新日志中记录新的 MFW 模拟器游戏启动行为以及按用户执行一次的生命周期脚本语义。

测试:

  • 增加对包名规范化、管道提取、分层资源和任务覆盖解析、歧义处理、数据缺失以及无法读取管道文件的测试覆盖。
  • 更新 MFW 配置清单预期,以包含新的游戏包设置。
Original summary in English

Summary by Sourcery

Allow MFW emulator sessions to launch their game automatically while making lifecycle scripts execute once per user rather than once per retry.

New Features:

  • Enable MFW ADB emulator runs to launch the configured Android game alongside the emulator, using a manual package name or safe project-based auto-detection.
  • Add the Game.PackageName setting across backend, API models, frontend configuration, and localized UI.

Bug Fixes:

  • Ensure MFW per-user before-task and after-task scripts execute once per user instead of repeating on retries, while preserving after-task execution on success, failure, and cancellation.

Enhancements:

  • Detect game packages from layered resource pipelines and selected task overrides, reporting missing or conflicting candidates without guessing.

Documentation:

  • Document the new MFW emulator game-launch behavior and per-user lifecycle script semantics in the changelog.

Tests:

  • Add coverage for package normalization, pipeline extraction, layered resource and task override resolution, ambiguity handling, missing data, and unreadable pipeline files.
  • Update MFW configuration inventory expectations for the new game package setting.

qiyinxi and others added 2 commits September 9, 2026 16:17
MaaFW 用 Adb controller 时只开模拟器,游戏要等脚本自己那套流程冷启动。模拟器侧
其实早有 open(idx, package_name),缺的是「这个项目要开哪个包」。

包名不在 interface.json 里——MaaFramework 的 ProjectInterface 规格没有这一项,
实测两个真实项目也都没有。真正的包名写在 pipeline 节点的 StartApp 动作参数里,
而且两种放法都存在:M9A 的九个服各自在 resource/<服>/pipeline/startup.json 里
覆盖同一个节点 Start1999,靠 interface 的 resource[].path 顺序叠加;MaaEnd 则放在
option 的 pipeline_override 里,取决于用户选的 ClientVersion。

所以 game_package.py 按同一套顺序推断:先按 resource[].path 顺序扫 pipeline,再把
已选任务的 pipelineOverride 按节点名盖上去,最后看还剩几个互不相同的包名。剩一个
才用,一个都没有或剩多个都不猜——挑错了会去启动另一个游戏,比不启动更糟,两种情况
都会在运行日志里说清楚原因并回落到手填。

配置只加 Game.PackageName 一项而不是「开关 + 输入框」两项:填了就是手动覆盖,
留空就是自动识别,同一个概念不让用户选两次。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
前脚本原先在重试循环里,一个用户重试三次就跑三遍;后脚本在每次尝试的 finally 里,
同样跑三遍。用户期望的口径是「第一次启动跑一次,完全结束时跑一次」,取消也算完全结束。

对照其余十个专项:MAA 与 HSR 是「每用户一次」,其余七个和 MaaFW 一样在重试循环里;
而「取消时跑收尾」全仓只有 MaaFW 一家做到(它用了 finally)。所以本次只把次数改对,
保留 finally——取消、重试全败、成功三条路都要跑到收尾脚本。

前脚本挪进同一个 try 的开头,与 finally 里的后脚本严格配对:跑过前脚本就一定跑后脚本。
实测(本地驱动 main_task):重试三次全失败由「前 3 次 / 后 3 次」变为「前 1 次 / 后 1 次」;
第一次成功与中途取消都是各 1 次,CancelledError 仍正常外抛。

其余十个专项的口径不一致,不在本次范围内。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @qiyinxi, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 3 days and 3 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 9, 2026

Copy link
Copy Markdown

审查者指南

该 PR 为 MFW ADB controller 引入了从项目 pipeline 自动推断 Android 游戏包名的机制,并允许手动覆盖;解析遵循 resource 顺序和任务 pipeline override 的覆盖语义,对不确定结果安全回落为仅启动模拟器。同时将任务前后脚本调整为每用户各执行一次,并完善前端配置、日志提示、测试和文档更新。

MFW 模拟器和游戏启动时序图

sequenceDiagram
    participant Runner as MaaFWRunner
    participant Resolver as resolve_game_package
    participant Project as ProjectPipelines
    participant Emulator as EmulatorManager

    Runner->>Runner: Read Game.PackageName
    alt Manual package name configured
        Runner->>Emulator: open(emulator_index, package_name)
    else Automatic detection
        Runner->>Resolver: resolve_game_package(resource_paths, task_overrides)
        Resolver->>Project: Read resource pipeline files in order
        Resolver->>Project: Apply task pipelineOverride values
        alt One package candidate
            Resolver-->>Runner: PackageResolution resolved
            Runner->>Emulator: open(emulator_index, package)
        else None or conflicting candidates
            Resolver-->>Runner: not-found or ambiguous
            Runner->>Emulator: open(emulator_index, empty package)
        end
    end
Loading

MFW 每用户任务脚本时序图

sequenceDiagram
    participant Runner as main_task
    participant Before as execute_script_task
    participant Tasks as MFWTaskLoop
    participant After as execute_script_task

    Runner->>Before: execute_script_task(ScriptBeforeTask, 脚本前任务)
    Runner->>Tasks: _run_pretasks()
    loop Retry attempts
        Runner->>Tasks: Run one attempt
    end
    alt Success, all retries failed, or cancellation
        Runner->>After: execute_script_task(ScriptAfterTask, 脚本后任务)
    end
    Runner-->>Runner: Propagate CancelledError when cancelled
Loading

MFW 游戏包解析流程图

flowchart TD
    A["MFW ADB controller starts"] --> B{"Game.PackageName filled?"}
    B -->|Yes| C["Use manual package name"]
    B -->|No| D["Scan resource pipeline files in resource path order"]
    D --> E["Apply task pipelineOverride"]
    E --> F{"Remaining package names"}
    F -->|Exactly one| G["Use detected package name"]
    F -->|None| H["Log not-found; launch emulator only"]
    F -->|Multiple| I["Log ambiguous candidates; launch emulator only"]
    C --> J["emulator_manager.open with package name"]
    G --> J
    H --> K["emulator_manager.open without game package"]
    I --> K
Loading

文件级变更

变更 详情 文件
为 MFW ADB controller 增加模拟器启动时自动拉起游戏的包名解析与配置覆盖机制。
  • 新增 Game.PackageName 配置,并贯通后端 schema、前端类型、默认值、编辑页面及中英日文案。
  • 扫描按 interface resource[].path 顺序叠加的 pipeline 文件,解析 StartApp 节点并规范化 package/Activity;再应用已选任务的 pipelineOverride。
  • 对唯一候选、无候选和冲突候选分别处理:自动启动、记录原因并跳过、记录候选并跳过;手动包名优先。
  • 将解析结果传入 emulator_manager.open,使 ADB 模式启动模拟器时可同时启动游戏。
app/models/config.py
app/models/schema.py
app/task/MaaFW/tools/embedded/game_package.py
app/task/MaaFW/tools/embedded/runner_task.py
frontend/src/api/models/MaaFWConfig_Game.ts
frontend/src/composables/useMaaFWScriptConfig.ts
frontend/src/i18n/locales/en-US.ts
frontend/src/i18n/locales/ja-JP.ts
frontend/src/i18n/locales/zh-CN.ts
frontend/src/types/script.ts
frontend/src/views/EditView/Script/MaaFWScriptEdit/ControlConfigSection.vue
调整 MFW 每用户任务前后脚本的生命周期,使其不再随重试重复执行。
  • 将前置脚本移到用户级重试循环外,每用户执行一次。
  • 将后置脚本保留在外层 finally,在成功、重试失败和取消时执行一次,并在模拟器清理前运行。
app/task/MaaFW/tools/embedded/runner_task.py
补充包名解析和配置模型的回归覆盖,并更新版本与变更记录。
  • 测试节点提取、Activity 规范化、resource 顺序覆盖、任务 override、冲突/空输入及坏文件容错。
  • 更新配置字段数量断言、CHANGELOG 和版本文件。
tests/task/test_maafw_game_package.py
tests/task/test_maafw_config.py
CHANGELOG.md
res/version.json

提示和命令

与 Sourcery 交互

  • 触发新的审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以回复审查评论并使用 @sourcery-ai issue,从该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题中的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title,随时(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文中任意位置写入 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary,随时(重新)生成摘要。
  • 生成审查者指南: 在 pull request 中评论 @sourcery-ai guide,即可随时(重新)生成审查者指南。
  • 解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这一功能会很有用。
  • 忽略所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想从新的审查开始,这一功能尤其有用——别忘了评论 @sourcery-ai review 来触发新的审查!

自定义使用体验

访问你的控制面板以:

  • 启用或禁用审查功能,例如 Sourcery 生成的 pull request 摘要、审查者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

该 PR 为 MFW ADB controller 引入了从项目 pipeline 自动推断 Android 游戏包名的机制,并允许手动覆盖;解析遵循 resource 顺序和任务 pipeline override 的覆盖语义,对不确定结果安全回落为仅启动模拟器。同时将任务前后脚本调整为每用户各执行一次,并完善前端配置、日志提示、测试和文档更新。

Sequence diagram for MFW emulator and game startup

sequenceDiagram
    participant Runner as MaaFWRunner
    participant Resolver as resolve_game_package
    participant Project as ProjectPipelines
    participant Emulator as EmulatorManager

    Runner->>Runner: Read Game.PackageName
    alt Manual package name configured
        Runner->>Emulator: open(emulator_index, package_name)
    else Automatic detection
        Runner->>Resolver: resolve_game_package(resource_paths, task_overrides)
        Resolver->>Project: Read resource pipeline files in order
        Resolver->>Project: Apply task pipelineOverride values
        alt One package candidate
            Resolver-->>Runner: PackageResolution resolved
            Runner->>Emulator: open(emulator_index, package)
        else None or conflicting candidates
            Resolver-->>Runner: not-found or ambiguous
            Runner->>Emulator: open(emulator_index, empty package)
        end
    end
Loading

Sequence diagram for per-user MFW task scripts

sequenceDiagram
    participant Runner as main_task
    participant Before as execute_script_task
    participant Tasks as MFWTaskLoop
    participant After as execute_script_task

    Runner->>Before: execute_script_task(ScriptBeforeTask, 脚本前任务)
    Runner->>Tasks: _run_pretasks()
    loop Retry attempts
        Runner->>Tasks: Run one attempt
    end
    alt Success, all retries failed, or cancellation
        Runner->>After: execute_script_task(ScriptAfterTask, 脚本后任务)
    end
    Runner-->>Runner: Propagate CancelledError when cancelled
Loading

Flow diagram for MFW game package resolution

flowchart TD
    A["MFW ADB controller starts"] --> B{"Game.PackageName filled?"}
    B -->|Yes| C["Use manual package name"]
    B -->|No| D["Scan resource pipeline files in resource path order"]
    D --> E["Apply task pipelineOverride"]
    E --> F{"Remaining package names"}
    F -->|Exactly one| G["Use detected package name"]
    F -->|None| H["Log not-found; launch emulator only"]
    F -->|Multiple| I["Log ambiguous candidates; launch emulator only"]
    C --> J["emulator_manager.open with package name"]
    G --> J
    H --> K["emulator_manager.open without game package"]
    I --> K
Loading

File-Level Changes

Change Details Files
为 MFW ADB controller 增加模拟器启动时自动拉起游戏的包名解析与配置覆盖机制。
  • 新增 Game.PackageName 配置,并贯通后端 schema、前端类型、默认值、编辑页面及中英日文案。
  • 扫描按 interface resource[].path 顺序叠加的 pipeline 文件,解析 StartApp 节点并规范化 package/Activity;再应用已选任务的 pipelineOverride。
  • 对唯一候选、无候选和冲突候选分别处理:自动启动、记录原因并跳过、记录候选并跳过;手动包名优先。
  • 将解析结果传入 emulator_manager.open,使 ADB 模式启动模拟器时可同时启动游戏。
app/models/config.py
app/models/schema.py
app/task/MaaFW/tools/embedded/game_package.py
app/task/MaaFW/tools/embedded/runner_task.py
frontend/src/api/models/MaaFWConfig_Game.ts
frontend/src/composables/useMaaFWScriptConfig.ts
frontend/src/i18n/locales/en-US.ts
frontend/src/i18n/locales/ja-JP.ts
frontend/src/i18n/locales/zh-CN.ts
frontend/src/types/script.ts
frontend/src/views/EditView/Script/MaaFWScriptEdit/ControlConfigSection.vue
调整 MFW 每用户任务前后脚本的生命周期,使其不再随重试重复执行。
  • 将前置脚本移到用户级重试循环外,每用户执行一次。
  • 将后置脚本保留在外层 finally,在成功、重试失败和取消时执行一次,并在模拟器清理前运行。
app/task/MaaFW/tools/embedded/runner_task.py
补充包名解析和配置模型的回归覆盖,并更新版本与变更记录。
  • 测试节点提取、Activity 规范化、resource 顺序覆盖、任务 override、冲突/空输入及坏文件容错。
  • 更新配置字段数量断言、CHANGELOG 和版本文件。
tests/task/test_maafw_game_package.py
tests/task/test_maafw_config.py
CHANGELOG.md
res/version.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

…afw-game-package-20260909

# Conflicts:
#	frontend/src/i18n/locales/en-US.ts
#	frontend/src/i18n/locales/ja-JP.ts
@qiyinxi
qiyinxi merged commit 17e0817 into AUTO-MAS-Project:dev Sep 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant