Skip to content

feat: 實作 Win32 的啟動與關閉應用 / Impliment start app and stop app for Win32 - #1376

Open
kaihuang1122 wants to merge 8 commits into
MaaXYZ:mainfrom
kaihuang1122:main
Open

feat: 實作 Win32 的啟動與關閉應用 / Impliment start app and stop app for Win32#1376
kaihuang1122 wants to merge 8 commits into
MaaXYZ:mainfrom
kaihuang1122:main

Conversation

@kaihuang1122

@kaihuang1122 kaihuang1122 commented Jun 19, 2026

Copy link
Copy Markdown

Summary by Sourcery

实现 Win32 控制器对应用启动和停止的支持,并记录新的行为。

新功能:

  • 添加 Win32 控制器实现,通过可执行文件路径或命令启动应用程序。
  • 添加 Win32 控制器实现,通过关联窗口或可执行文件名停止应用程序。

文档:

  • 记录 Win32 控制器在启动应用时,将可执行文件路径或命令作为 intent 格式的用法。
  • 记录 Win32 控制器在 Win32 上的停止行为,允许在 intent 为空时,使用可选的基于进程名的终止方式或基于窗口的终止方式。
Original summary in English

Summary by Sourcery

Implement Win32 controller support for starting and stopping applications and document the new behavior.

New Features:

  • Add Win32 controller implementation for starting applications via executable path or command.
  • Add Win32 controller implementation for stopping applications either by associated window or by executable name.

Documentation:

  • Document Win32 controller intent format for starting apps as executable path or command.
  • Document Win32 controller stop behavior for Win32, allowing optional process-name based termination or window-based termination when intent is empty.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - 我发现了两个问题,并留下了一些高层次的反馈:

  • stop_app 中,直接将 intentPROCESSENTRY32W::szExeFile 匹配会在 intent 是完整路径(正如文档中建议的那样)而不仅仅是可执行文件名时失败;建议将 intent 规范化为文件名,或者显式限制为基础文件名(basename),以使行为更可预测。
  • 当前的 stop_app 逻辑始终使用 TerminateProcess,这相当强硬;当 hwnd_ 可用时,可以先尝试优雅关闭(例如发送 WM_CLOSE/WM_QUERYENDSESSION),再在必要时回退到强制终止,从而降低数据丢失或应用状态不一致的风险。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- In `stop_app`, matching `intent` directly against `PROCESSENTRY32W::szExeFile` will fail when `intent` is a full path (as suggested by the docs) rather than just the bare executable name; consider normalizing `intent` to a filename or explicitly constraining it to a basename to make behavior predictable.
- The current `stop_app` logic always uses `TerminateProcess`, which is quite forceful; when `hwnd_` is available you may want to attempt a graceful shutdown first (e.g., sending `WM_CLOSE`/`WM_QUERYENDSESSION`) before falling back to termination to reduce the risk of data loss or inconsistent app state.

## Individual Comments

### Comment 1
<location path="source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp" line_range="260-269" />
<code_context>
+        return false;
+    }
+
+    std::wstring cmd = MAA_NS::to_u16(intent);
+
+    STARTUPINFOW si;
+    PROCESS_INFORMATION pi;
+    ZeroMemory(&si, sizeof(si));
+    si.cb = sizeof(si);
+    ZeroMemory(&pi, sizeof(pi));
+
+    if (!CreateProcessW(nullptr, cmd.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
+        DWORD err = GetLastError();
+        if (err == ERROR_ELEVATION_REQUIRED) {
+            LogInfo << "Elevation required. Falling back to ShellExecuteExW...";
+            SHELLEXECUTEINFOW sei = { sizeof(sei) };
+            sei.fMask = SEE_MASK_NOCLOSEPROCESS;
+            sei.lpVerb = L"runas";
+            sei.lpFile = cmd.c_str();
+            sei.nShow = SW_SHOWNORMAL;
+            if (ShellExecuteExW(&sei)) {
</code_context>
<issue_to_address>
**issue (bug_risk):** 将完整命令行作为 `ShellExecuteExW``lpFile` 使用时,可能会把参数误解为可执行文件路径的一部分。

这里的 `cmd` 包含完整命令行(可执行文件 + 参数),但 `ShellExecuteExW` 期望 `lpFile` 只包含可执行文件,剩余部分放在 `lpParameters` 中。如果 `intent` 包含参数,这里可能会失败,或者指向错误的可执行文件。请将 `intent` 拆分为可执行文件和参数(例如使用类似 `CommandLineToArgvW` 的解析方式),把可执行文件赋值给 `sei.lpFile`,其余参数赋值给 `sei.lpParameters`。
</issue_to_address>

### Comment 2
<location path="source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp" line_range="331-340" />
<code_context>
+        return true;
+    }
+
+    std::wstring target_exe = MAA_NS::to_u16(intent);
+    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hSnap == INVALID_HANDLE_VALUE) {
+        LogError << "CreateToolhelp32Snapshot failed, error:" << GetLastError();
+        return false;
+    }

-    return false;
+    PROCESSENTRY32W pe;
+    pe.dwSize = sizeof(pe);
+    bool terminated_any = false;
+
+    if (Process32FirstW(hSnap, &pe)) {
+        do {
+            if (target_exe == pe.szExeFile) {
+                HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
+                if (hProcess) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** 直接将 `target_exe``pe.szExeFile` 比较,在处理完整路径和大小写时比较脆弱。

在 Windows 上,`PROCESSENTRY32W::szExeFile` 通常只是可执行文件名(例如 `foo.exe`),而 `intent` 可能是完整路径,且/或使用不同的大小写。直接用 `std::wstring` 做相等比较是区分大小写的,在这些情况下会失败。建议先从 `target_exe` 中提取基础文件名(例如使用 `PathFindFileNameW` 或类似方法),再与 `szExeFile` 进行不区分大小写的比较。

建议实现:

```cpp
    std::wstring target_exe = MAA_NS::to_u16(intent);

    // Extract executable basename (without path) for robust comparison with PROCESSENTRY32W::szExeFile
    std::wstring target_exe_name = target_exe;
    const auto last_sep_pos = target_exe_name.find_last_of(L"\\/");
    if (last_sep_pos != std::wstring::npos && last_sep_pos + 1 < target_exe_name.size()) {
        target_exe_name = target_exe_name.substr(last_sep_pos + 1);
    }

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

```

```cpp
    if (Process32FirstW(hSnap, &pe)) {
        do {
            // Compare executable names case-insensitively to handle differing casing
            if (_wcsicmp(target_exe_name.c_str(), pe.szExeFile) == 0) {

```

如果该翻译单元中尚未包含对应声明,你可能需要:
1. 在文件顶部添加 `#include <cwchar>`(或其它提供 `_wcsicmp` 的头文件)。
2. 确保构建设置允许使用 `_wcsicmp`(它是常见的 MSVC 扩展;在 Windows 项目中通常已经可用)。
</issue_to_address>

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,请考虑分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进评审质量。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In stop_app, matching intent directly against PROCESSENTRY32W::szExeFile will fail when intent is a full path (as suggested by the docs) rather than just the bare executable name; consider normalizing intent to a filename or explicitly constraining it to a basename to make behavior predictable.
  • The current stop_app logic always uses TerminateProcess, which is quite forceful; when hwnd_ is available you may want to attempt a graceful shutdown first (e.g., sending WM_CLOSE/WM_QUERYENDSESSION) before falling back to termination to reduce the risk of data loss or inconsistent app state.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `stop_app`, matching `intent` directly against `PROCESSENTRY32W::szExeFile` will fail when `intent` is a full path (as suggested by the docs) rather than just the bare executable name; consider normalizing `intent` to a filename or explicitly constraining it to a basename to make behavior predictable.
- The current `stop_app` logic always uses `TerminateProcess`, which is quite forceful; when `hwnd_` is available you may want to attempt a graceful shutdown first (e.g., sending `WM_CLOSE`/`WM_QUERYENDSESSION`) before falling back to termination to reduce the risk of data loss or inconsistent app state.

## Individual Comments

### Comment 1
<location path="source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp" line_range="260-269" />
<code_context>
+        return false;
+    }
+
+    std::wstring cmd = MAA_NS::to_u16(intent);
+
+    STARTUPINFOW si;
+    PROCESS_INFORMATION pi;
+    ZeroMemory(&si, sizeof(si));
+    si.cb = sizeof(si);
+    ZeroMemory(&pi, sizeof(pi));
+
+    if (!CreateProcessW(nullptr, cmd.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
+        DWORD err = GetLastError();
+        if (err == ERROR_ELEVATION_REQUIRED) {
+            LogInfo << "Elevation required. Falling back to ShellExecuteExW...";
+            SHELLEXECUTEINFOW sei = { sizeof(sei) };
+            sei.fMask = SEE_MASK_NOCLOSEPROCESS;
+            sei.lpVerb = L"runas";
+            sei.lpFile = cmd.c_str();
+            sei.nShow = SW_SHOWNORMAL;
+            if (ShellExecuteExW(&sei)) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Using the full command line as `lpFile` for `ShellExecuteExW` can misinterpret arguments as part of the executable path.

Here `cmd` contains the full command line (exe + args), but `ShellExecuteExW` expects only the executable in `lpFile` and the rest in `lpParameters`. If `intent` includes arguments, this can fail or target the wrong executable. Please split `intent` into executable and arguments (e.g., via `CommandLineToArgvW`-style parsing), assign the executable to `sei.lpFile` and the remaining arguments to `sei.lpParameters`.
</issue_to_address>

### Comment 2
<location path="source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp" line_range="331-340" />
<code_context>
+        return true;
+    }
+
+    std::wstring target_exe = MAA_NS::to_u16(intent);
+    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hSnap == INVALID_HANDLE_VALUE) {
+        LogError << "CreateToolhelp32Snapshot failed, error:" << GetLastError();
+        return false;
+    }

-    return false;
+    PROCESSENTRY32W pe;
+    pe.dwSize = sizeof(pe);
+    bool terminated_any = false;
+
+    if (Process32FirstW(hSnap, &pe)) {
+        do {
+            if (target_exe == pe.szExeFile) {
+                HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
+                if (hProcess) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Directly comparing `target_exe` to `pe.szExeFile` is brittle regarding full paths and case sensitivity.

On Windows, `PROCESSENTRY32W::szExeFile` is typically just the executable name (e.g., `foo.exe`), while `intent` may be a full path and/or use different casing. A direct `std::wstring` equality is case-sensitive and will fail in those cases. Consider normalizing by extracting the basename from `target_exe` (e.g., via `PathFindFileNameW` or similar) and comparing it to `szExeFile` case-insensitively.

Suggested implementation:

```cpp
    std::wstring target_exe = MAA_NS::to_u16(intent);

    // Extract executable basename (without path) for robust comparison with PROCESSENTRY32W::szExeFile
    std::wstring target_exe_name = target_exe;
    const auto last_sep_pos = target_exe_name.find_last_of(L"\\/");
    if (last_sep_pos != std::wstring::npos && last_sep_pos + 1 < target_exe_name.size()) {
        target_exe_name = target_exe_name.substr(last_sep_pos + 1);
    }

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

```

```cpp
    if (Process32FirstW(hSnap, &pe)) {
        do {
            // Compare executable names case-insensitively to handle differing casing
            if (_wcsicmp(target_exe_name.c_str(), pe.szExeFile) == 0) {

```

If not already present in this translation unit, you may need to:
1. Add `#include <cwchar>` (or another header that provides `_wcsicmp`) near the top of the file.
2. Ensure your build settings allow use of `_wcsicmp` (it's a common MSVC extension; typically already available in Windows projects).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp Outdated
Comment thread source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp
@kaihuang1122

kaihuang1122 commented Jun 19, 2026

Copy link
Copy Markdown
Author

針對 sourcery-ai 提出的反饋:

  1. 作為底層引擎的API,使用者應當知道並使用精確的進程名,非嚴格比對可能導致誤殺其他進程。
  2. 大多數遊戲收到WM_CLOSE只會彈出類似「是否退出遊戲」的對話框,不利於自動化場景的構建。

因此,我認為應該拒絕 sourcery-ai 的建議。

@MistEO

MistEO commented Jun 20, 2026

Copy link
Copy Markdown
Member

嵌套太多了,尽量用守卫模式。然后不要用 do while(0)

@kaihuang1122

Copy link
Copy Markdown
Author

嵌套太多了,尽量用守卫模式。然后不要用 do while(0)

Fixed,多謝指教,僅存的 do while 是 微軟寫法 且我認為具有必要性

zmdyy0318 pushed a commit to MaaEnd/MaaEnd that referenced this pull request Jun 27, 2026
- close #1995
  - close #3555

## 概述

為 `AndroidOpenGame` 與 `CloseGame` 任務新增多伺服器支援,允許使用者在 ADB / PlayCover
環境下選擇目標客戶端版本。伺服器特化邏輯被模組化至 `pipeline/GameSwitch/` 目錄中,保持任務定義的簡潔與可維護性。

## 變更內容

### 新增 CloseGame 任務

- 新增 `assets/tasks/CloseGame.json`,註冊為獨立任務並掛載 `ClientVersion` 選項。
- 在 `assets/interface.json` 中引入 CloseGame 任務。


(在實作時支援了Win32的CloseGame,但fw的api尚未實裝,具體測試於[此PR版本](MaaXYZ/MaaFramework#1376))


### 新增 ClientVersion 選項(伺服器選擇)

在 `assets/tasks/AndroidOpenGame.json` 中定義全域 `ClientVersion` 選項(`type:
select`),提供 5 個選項:

| 選項 | 包名 |
|------|------|
| ~~自動偵測~~ | ~~依序嘗試所有包名~~ |
| 官服 (Hypergryph) | `com.hypergryph.endfield` |
| B 服 (Bilibili) | `com.hypergryph.endfield.bilibili` |
| 國際服 (Gryphline) | `com.gryphline.endfield.gp` |
| 越南服 (Gryphline VN) | `com.gryphline.endfield.gp.vn` |

- 選項設定 `"controller": ["ADB", "PlayCover"]`,僅在 Android 環境下生效。
- 選項標籤附加「僅安卓適用」提示,避免 Win32 使用者混淆。

### 模組化 Pipeline 架構 (`GameSwitch/`)

將伺服器特化的啟動/關閉邏輯從 `pipeline_override` 中抽離,建立獨立的路由節點:

**`resource_adb/pipeline/GameSwitch/`**(ADB 實際邏輯):

- `AndroidOpenGame.json`:定義
`AndroidOpenGame_Auto`、`AndroidOpenGame_CN`、`AndroidOpenGame_Bilibili`、`AndroidOpenGame_Global`、`AndroidOpenGame_VN`
節點,各自攜帶對應的 `StartApp` action。
- `CloseGame.json`:定義
`CloseGame_Auto`、`CloseGame_CN`、`CloseGame_Bilibili`、`CloseGame_Global`、`CloseGame_VN`
節點,各自攜帶對應的 `StopApp` action。

**`resource/pipeline/GameSwitch/`**(Win32 相容樁節點):

- `AndroidOpenGame.json`:空白樁節點,確保跨平台 linter 檢查通過。
- `CloseGame.json`:帶有 `StopApp` 的樁節點,確保 Win32 環境下 `CloseGame`
路由仍可正常關閉遊戲。

~~**自動偵測策略:**~~
- ~~**啟動 (Auto)**:透過 `on_error` 鏈式嘗試:官服 → B服 → 國際服 → 越南服,首個成功即停止。~~
- ~~**關閉 (Auto)**:透過 `next` 鏈式執行:依序對所有四個包名發送 `StopApp`,確保完整關閉。~~

## 變更檔案

```
assets/interface.json                                    # 引入 CloseGame 任務
assets/tasks/AndroidOpenGame.json                        # 定義 ClientVersion 選項與路由
assets/tasks/CloseGame.json                              # 新增 CloseGame 任務定義
assets/resource/pipeline/OpenGame.json                   # 移除 AndroidOpenGame 預設 action
assets/resource/pipeline/GameSwitch/AndroidOpenGame.json # Win32 樁節點
assets/resource/pipeline/GameSwitch/CloseGame.json       # Win32 CloseGame 節點(含樁)
assets/resource_adb/pipeline/GameSwitch/AndroidOpenGame.json  # ADB 啟動邏輯
assets/resource_adb/pipeline/GameSwitch/CloseGame.json        # ADB 關閉邏輯
assets/locales/interface/zh_cn.json                      # 簡體中文翻譯
assets/locales/interface/zh_tw.json                      # 繁體中文翻譯
assets/locales/interface/en_us.json                      # 英文翻譯
assets/locales/interface/ja_jp.json                      # 日文翻譯
assets/locales/interface/ko_kr.json                      # 韓文翻譯
```

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

新功能:
- 引入一级任务 **CloseGame**,并为不同客户端版本提供路由支持。
- 为 **AndroidOpenGame** 添加 **ClientVersion** 选择选项,以便在 ADB 和 PlayCover
上针对特定的服务器/客户端包进行操作。

改进:
- 重构 **AndroidOpenGame** 和 **CloseGame** 逻辑,将其拆分为适用于不同平台和服务器的模块化
**GameSwitch** 流水线节点。
- 调整 **OpenGame** 流水线,将 Android 特定行为委托给 **GameSwitch** 路由节点处理。

文档:
- 更新多种语言的本地化界面字符串,以反映新的 **CloseGame** 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

</details>
github-actions Bot pushed a commit to Koala-27/MaaEnd-Koala that referenced this pull request Jun 29, 2026
- close MaaEnd/MaaEnd#1995
  - close MaaEnd/MaaEnd#3555

## 概述

為 `AndroidOpenGame` 與 `CloseGame` 任務新增多伺服器支援,允許使用者在 ADB / PlayCover
環境下選擇目標客戶端版本。伺服器特化邏輯被模組化至 `pipeline/GameSwitch/` 目錄中,保持任務定義的簡潔與可維護性。

## 變更內容

### 新增 CloseGame 任務

- 新增 `assets/tasks/CloseGame.json`,註冊為獨立任務並掛載 `ClientVersion` 選項。
- 在 `assets/interface.json` 中引入 CloseGame 任務。

(在實作時支援了Win32的CloseGame,但fw的api尚未實裝,具體測試於[此PR版本](MaaXYZ/MaaFramework#1376))

### 新增 ClientVersion 選項(伺服器選擇)

在 `assets/tasks/AndroidOpenGame.json` 中定義全域 `ClientVersion` 選項(`type:
select`),提供 5 個選項:

| 選項 | 包名 |
|------|------|
| ~~自動偵測~~ | ~~依序嘗試所有包名~~ |
| 官服 (Hypergryph) | `com.hypergryph.endfield` |
| B 服 (Bilibili) | `com.hypergryph.endfield.bilibili` |
| 國際服 (Gryphline) | `com.gryphline.endfield.gp` |
| 越南服 (Gryphline VN) | `com.gryphline.endfield.gp.vn` |

- 選項設定 `"controller": ["ADB", "PlayCover"]`,僅在 Android 環境下生效。
- 選項標籤附加「僅安卓適用」提示,避免 Win32 使用者混淆。

### 模組化 Pipeline 架構 (`GameSwitch/`)

將伺服器特化的啟動/關閉邏輯從 `pipeline_override` 中抽離,建立獨立的路由節點:

**`resource_adb/pipeline/GameSwitch/`**(ADB 實際邏輯):

- `AndroidOpenGame.json`:定義
`AndroidOpenGame_Auto`、`AndroidOpenGame_CN`、`AndroidOpenGame_Bilibili`、`AndroidOpenGame_Global`、`AndroidOpenGame_VN`
節點,各自攜帶對應的 `StartApp` action。
- `CloseGame.json`:定義
`CloseGame_Auto`、`CloseGame_CN`、`CloseGame_Bilibili`、`CloseGame_Global`、`CloseGame_VN`
節點,各自攜帶對應的 `StopApp` action。

**`resource/pipeline/GameSwitch/`**(Win32 相容樁節點):

- `AndroidOpenGame.json`:空白樁節點,確保跨平台 linter 檢查通過。
- `CloseGame.json`:帶有 `StopApp` 的樁節點,確保 Win32 環境下 `CloseGame`
路由仍可正常關閉遊戲。

~~**自動偵測策略:**~~
- ~~**啟動 (Auto)**:透過 `on_error` 鏈式嘗試:官服 → B服 → 國際服 → 越南服,首個成功即停止。~~
- ~~**關閉 (Auto)**:透過 `next` 鏈式執行:依序對所有四個包名發送 `StopApp`,確保完整關閉。~~

## 變更檔案

```
assets/interface.json                                    # 引入 CloseGame 任務
assets/tasks/AndroidOpenGame.json                        # 定義 ClientVersion 選項與路由
assets/tasks/CloseGame.json                              # 新增 CloseGame 任務定義
assets/resource/pipeline/OpenGame.json                   # 移除 AndroidOpenGame 預設 action
assets/resource/pipeline/GameSwitch/AndroidOpenGame.json # Win32 樁節點
assets/resource/pipeline/GameSwitch/CloseGame.json       # Win32 CloseGame 節點(含樁)
assets/resource_adb/pipeline/GameSwitch/AndroidOpenGame.json  # ADB 啟動邏輯
assets/resource_adb/pipeline/GameSwitch/CloseGame.json        # ADB 關閉邏輯
assets/locales/interface/zh_cn.json                      # 簡體中文翻譯
assets/locales/interface/zh_tw.json                      # 繁體中文翻譯
assets/locales/interface/en_us.json                      # 英文翻譯
assets/locales/interface/ja_jp.json                      # 日文翻譯
assets/locales/interface/ko_kr.json                      # 韓文翻譯
```

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

新功能:
- 引入一级任务 **CloseGame**,并为不同客户端版本提供路由支持。
- 为 **AndroidOpenGame** 添加 **ClientVersion** 选择选项,以便在 ADB 和 PlayCover
上针对特定的服务器/客户端包进行操作。

改进:
- 重构 **AndroidOpenGame** 和 **CloseGame** 逻辑,将其拆分为适用于不同平台和服务器的模块化
**GameSwitch** 流水线节点。
- 调整 **OpenGame** 流水线,将 Android 特定行为委托给 **GameSwitch** 路由节点处理。

文档:
- 更新多种语言的本地化界面字符串,以反映新的 **CloseGame** 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

</details>
Koala-27 pushed a commit to Koala-27/MaaEnd-Koala that referenced this pull request Jun 30, 2026
- close MaaEnd/MaaEnd#1995
  - close MaaEnd/MaaEnd#3555

## 概述

為 `AndroidOpenGame` 與 `CloseGame` 任務新增多伺服器支援,允許使用者在 ADB / PlayCover
環境下選擇目標客戶端版本。伺服器特化邏輯被模組化至 `pipeline/GameSwitch/` 目錄中,保持任務定義的簡潔與可維護性。

## 變更內容

### 新增 CloseGame 任務

- 新增 `assets/tasks/CloseGame.json`,註冊為獨立任務並掛載 `ClientVersion` 選項。
- 在 `assets/interface.json` 中引入 CloseGame 任務。


(在實作時支援了Win32的CloseGame,但fw的api尚未實裝,具體測試於[此PR版本](MaaXYZ/MaaFramework#1376))


### 新增 ClientVersion 選項(伺服器選擇)

在 `assets/tasks/AndroidOpenGame.json` 中定義全域 `ClientVersion` 選項(`type:
select`),提供 5 個選項:

| 選項 | 包名 |
|------|------|
| ~~自動偵測~~ | ~~依序嘗試所有包名~~ |
| 官服 (Hypergryph) | `com.hypergryph.endfield` |
| B 服 (Bilibili) | `com.hypergryph.endfield.bilibili` |
| 國際服 (Gryphline) | `com.gryphline.endfield.gp` |
| 越南服 (Gryphline VN) | `com.gryphline.endfield.gp.vn` |

- 選項設定 `"controller": ["ADB", "PlayCover"]`,僅在 Android 環境下生效。
- 選項標籤附加「僅安卓適用」提示,避免 Win32 使用者混淆。

### 模組化 Pipeline 架構 (`GameSwitch/`)

將伺服器特化的啟動/關閉邏輯從 `pipeline_override` 中抽離,建立獨立的路由節點:

**`resource_adb/pipeline/GameSwitch/`**(ADB 實際邏輯):

- `AndroidOpenGame.json`:定義
`AndroidOpenGame_Auto`、`AndroidOpenGame_CN`、`AndroidOpenGame_Bilibili`、`AndroidOpenGame_Global`、`AndroidOpenGame_VN`
節點,各自攜帶對應的 `StartApp` action。
- `CloseGame.json`:定義
`CloseGame_Auto`、`CloseGame_CN`、`CloseGame_Bilibili`、`CloseGame_Global`、`CloseGame_VN`
節點,各自攜帶對應的 `StopApp` action。

**`resource/pipeline/GameSwitch/`**(Win32 相容樁節點):

- `AndroidOpenGame.json`:空白樁節點,確保跨平台 linter 檢查通過。
- `CloseGame.json`:帶有 `StopApp` 的樁節點,確保 Win32 環境下 `CloseGame`
路由仍可正常關閉遊戲。

~~**自動偵測策略:**~~
- ~~**啟動 (Auto)**:透過 `on_error` 鏈式嘗試:官服 → B服 → 國際服 → 越南服,首個成功即停止。~~
- ~~**關閉 (Auto)**:透過 `next` 鏈式執行:依序對所有四個包名發送 `StopApp`,確保完整關閉。~~

## 變更檔案

```
assets/interface.json                                    # 引入 CloseGame 任務
assets/tasks/AndroidOpenGame.json                        # 定義 ClientVersion 選項與路由
assets/tasks/CloseGame.json                              # 新增 CloseGame 任務定義
assets/resource/pipeline/OpenGame.json                   # 移除 AndroidOpenGame 預設 action
assets/resource/pipeline/GameSwitch/AndroidOpenGame.json # Win32 樁節點
assets/resource/pipeline/GameSwitch/CloseGame.json       # Win32 CloseGame 節點(含樁)
assets/resource_adb/pipeline/GameSwitch/AndroidOpenGame.json  # ADB 啟動邏輯
assets/resource_adb/pipeline/GameSwitch/CloseGame.json        # ADB 關閉邏輯
assets/locales/interface/zh_cn.json                      # 簡體中文翻譯
assets/locales/interface/zh_tw.json                      # 繁體中文翻譯
assets/locales/interface/en_us.json                      # 英文翻譯
assets/locales/interface/ja_jp.json                      # 日文翻譯
assets/locales/interface/ko_kr.json                      # 韓文翻譯
```

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

新功能:
- 引入一级任务 **CloseGame**,并为不同客户端版本提供路由支持。
- 为 **AndroidOpenGame** 添加 **ClientVersion** 选择选项,以便在 ADB 和 PlayCover
上针对特定的服务器/客户端包进行操作。

改进:
- 重构 **AndroidOpenGame** 和 **CloseGame** 逻辑,将其拆分为适用于不同平台和服务器的模块化
**GameSwitch** 流水线节点。
- 调整 **OpenGame** 流水线,将 Android 特定行为委托给 **GameSwitch** 路由节点处理。

文档:
- 更新多种语言的本地化界面字符串,以反映新的 **CloseGame** 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

</details>
ocsin1 pushed a commit to ocsin1/ci-test that referenced this pull request Jul 10, 2026
- close MaaEnd/MaaEnd#1995
  - close MaaEnd/MaaEnd#3555

## 概述

為 `AndroidOpenGame` 與 `CloseGame` 任務新增多伺服器支援,允許使用者在 ADB / PlayCover
環境下選擇目標客戶端版本。伺服器特化邏輯被模組化至 `pipeline/GameSwitch/` 目錄中,保持任務定義的簡潔與可維護性。

## 變更內容

### 新增 CloseGame 任務

- 新增 `assets/tasks/CloseGame.json`,註冊為獨立任務並掛載 `ClientVersion` 選項。
- 在 `assets/interface.json` 中引入 CloseGame 任務。


(在實作時支援了Win32的CloseGame,但fw的api尚未實裝,具體測試於[此PR版本](MaaXYZ/MaaFramework#1376))


### 新增 ClientVersion 選項(伺服器選擇)

在 `assets/tasks/AndroidOpenGame.json` 中定義全域 `ClientVersion` 選項(`type:
select`),提供 5 個選項:

| 選項 | 包名 |
|------|------|
| ~~自動偵測~~ | ~~依序嘗試所有包名~~ |
| 官服 (Hypergryph) | `com.hypergryph.endfield` |
| B 服 (Bilibili) | `com.hypergryph.endfield.bilibili` |
| 國際服 (Gryphline) | `com.gryphline.endfield.gp` |
| 越南服 (Gryphline VN) | `com.gryphline.endfield.gp.vn` |

- 選項設定 `"controller": ["ADB", "PlayCover"]`,僅在 Android 環境下生效。
- 選項標籤附加「僅安卓適用」提示,避免 Win32 使用者混淆。

### 模組化 Pipeline 架構 (`GameSwitch/`)

將伺服器特化的啟動/關閉邏輯從 `pipeline_override` 中抽離,建立獨立的路由節點:

**`resource_adb/pipeline/GameSwitch/`**(ADB 實際邏輯):

- `AndroidOpenGame.json`:定義
`AndroidOpenGame_Auto`、`AndroidOpenGame_CN`、`AndroidOpenGame_Bilibili`、`AndroidOpenGame_Global`、`AndroidOpenGame_VN`
節點,各自攜帶對應的 `StartApp` action。
- `CloseGame.json`:定義
`CloseGame_Auto`、`CloseGame_CN`、`CloseGame_Bilibili`、`CloseGame_Global`、`CloseGame_VN`
節點,各自攜帶對應的 `StopApp` action。

**`resource/pipeline/GameSwitch/`**(Win32 相容樁節點):

- `AndroidOpenGame.json`:空白樁節點,確保跨平台 linter 檢查通過。
- `CloseGame.json`:帶有 `StopApp` 的樁節點,確保 Win32 環境下 `CloseGame`
路由仍可正常關閉遊戲。

~~**自動偵測策略:**~~
- ~~**啟動 (Auto)**:透過 `on_error` 鏈式嘗試:官服 → B服 → 國際服 → 越南服,首個成功即停止。~~
- ~~**關閉 (Auto)**:透過 `next` 鏈式執行:依序對所有四個包名發送 `StopApp`,確保完整關閉。~~

## 變更檔案

```
assets/interface.json                                    # 引入 CloseGame 任務
assets/tasks/AndroidOpenGame.json                        # 定義 ClientVersion 選項與路由
assets/tasks/CloseGame.json                              # 新增 CloseGame 任務定義
assets/resource/pipeline/OpenGame.json                   # 移除 AndroidOpenGame 預設 action
assets/resource/pipeline/GameSwitch/AndroidOpenGame.json # Win32 樁節點
assets/resource/pipeline/GameSwitch/CloseGame.json       # Win32 CloseGame 節點(含樁)
assets/resource_adb/pipeline/GameSwitch/AndroidOpenGame.json  # ADB 啟動邏輯
assets/resource_adb/pipeline/GameSwitch/CloseGame.json        # ADB 關閉邏輯
assets/locales/interface/zh_cn.json                      # 簡體中文翻譯
assets/locales/interface/zh_tw.json                      # 繁體中文翻譯
assets/locales/interface/en_us.json                      # 英文翻譯
assets/locales/interface/ja_jp.json                      # 日文翻譯
assets/locales/interface/ko_kr.json                      # 韓文翻譯
```

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

新功能:
- 引入一级任务 **CloseGame**,并为不同客户端版本提供路由支持。
- 为 **AndroidOpenGame** 添加 **ClientVersion** 选择选项,以便在 ADB 和 PlayCover
上针对特定的服务器/客户端包进行操作。

改进:
- 重构 **AndroidOpenGame** 和 **CloseGame** 逻辑,将其拆分为适用于不同平台和服务器的模块化
**GameSwitch** 流水线节点。
- 调整 **OpenGame** 流水线,将 Android 特定行为委托给 **GameSwitch** 路由节点处理。

文档:
- 更新多种语言的本地化界面字符串,以反映新的 **CloseGame** 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

</details>
Koala-27 pushed a commit to Koala-27/MaaEnd-Koala that referenced this pull request Jul 17, 2026
- close MaaEnd/MaaEnd#1995
  - close MaaEnd/MaaEnd#3555

## 概述

為 `AndroidOpenGame` 與 `CloseGame` 任務新增多伺服器支援,允許使用者在 ADB / PlayCover
環境下選擇目標客戶端版本。伺服器特化邏輯被模組化至 `pipeline/GameSwitch/` 目錄中,保持任務定義的簡潔與可維護性。

## 變更內容

### 新增 CloseGame 任務

- 新增 `assets/tasks/CloseGame.json`,註冊為獨立任務並掛載 `ClientVersion` 選項。
- 在 `assets/interface.json` 中引入 CloseGame 任務。


(在實作時支援了Win32的CloseGame,但fw的api尚未實裝,具體測試於[此PR版本](MaaXYZ/MaaFramework#1376))


### 新增 ClientVersion 選項(伺服器選擇)

在 `assets/tasks/AndroidOpenGame.json` 中定義全域 `ClientVersion` 選項(`type:
select`),提供 5 個選項:

| 選項 | 包名 |
|------|------|
| ~~自動偵測~~ | ~~依序嘗試所有包名~~ |
| 官服 (Hypergryph) | `com.hypergryph.endfield` |
| B 服 (Bilibili) | `com.hypergryph.endfield.bilibili` |
| 國際服 (Gryphline) | `com.gryphline.endfield.gp` |
| 越南服 (Gryphline VN) | `com.gryphline.endfield.gp.vn` |

- 選項設定 `"controller": ["ADB", "PlayCover"]`,僅在 Android 環境下生效。
- 選項標籤附加「僅安卓適用」提示,避免 Win32 使用者混淆。

### 模組化 Pipeline 架構 (`GameSwitch/`)

將伺服器特化的啟動/關閉邏輯從 `pipeline_override` 中抽離,建立獨立的路由節點:

**`resource_adb/pipeline/GameSwitch/`**(ADB 實際邏輯):

- `AndroidOpenGame.json`:定義
`AndroidOpenGame_Auto`、`AndroidOpenGame_CN`、`AndroidOpenGame_Bilibili`、`AndroidOpenGame_Global`、`AndroidOpenGame_VN`
節點,各自攜帶對應的 `StartApp` action。
- `CloseGame.json`:定義
`CloseGame_Auto`、`CloseGame_CN`、`CloseGame_Bilibili`、`CloseGame_Global`、`CloseGame_VN`
節點,各自攜帶對應的 `StopApp` action。

**`resource/pipeline/GameSwitch/`**(Win32 相容樁節點):

- `AndroidOpenGame.json`:空白樁節點,確保跨平台 linter 檢查通過。
- `CloseGame.json`:帶有 `StopApp` 的樁節點,確保 Win32 環境下 `CloseGame`
路由仍可正常關閉遊戲。

~~**自動偵測策略:**~~
- ~~**啟動 (Auto)**:透過 `on_error` 鏈式嘗試:官服 → B服 → 國際服 → 越南服,首個成功即停止。~~
- ~~**關閉 (Auto)**:透過 `next` 鏈式執行:依序對所有四個包名發送 `StopApp`,確保完整關閉。~~

## 變更檔案

```
assets/interface.json                                    # 引入 CloseGame 任務
assets/tasks/AndroidOpenGame.json                        # 定義 ClientVersion 選項與路由
assets/tasks/CloseGame.json                              # 新增 CloseGame 任務定義
assets/resource/pipeline/OpenGame.json                   # 移除 AndroidOpenGame 預設 action
assets/resource/pipeline/GameSwitch/AndroidOpenGame.json # Win32 樁節點
assets/resource/pipeline/GameSwitch/CloseGame.json       # Win32 CloseGame 節點(含樁)
assets/resource_adb/pipeline/GameSwitch/AndroidOpenGame.json  # ADB 啟動邏輯
assets/resource_adb/pipeline/GameSwitch/CloseGame.json        # ADB 關閉邏輯
assets/locales/interface/zh_cn.json                      # 簡體中文翻譯
assets/locales/interface/zh_tw.json                      # 繁體中文翻譯
assets/locales/interface/en_us.json                      # 英文翻譯
assets/locales/interface/ja_jp.json                      # 日文翻譯
assets/locales/interface/ko_kr.json                      # 韓文翻譯
```

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

新功能:
- 引入一级任务 **CloseGame**,并为不同客户端版本提供路由支持。
- 为 **AndroidOpenGame** 添加 **ClientVersion** 选择选项,以便在 ADB 和 PlayCover
上针对特定的服务器/客户端包进行操作。

改进:
- 重构 **AndroidOpenGame** 和 **CloseGame** 逻辑,将其拆分为适用于不同平台和服务器的模块化
**GameSwitch** 流水线节点。
- 调整 **OpenGame** 流水线,将 Android 特定行为委托给 **GameSwitch** 路由节点处理。

文档:
- 更新多种语言的本地化界面字符串,以反映新的 **CloseGame** 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

为 Android 游戏启动与关闭引入可配置的客户端版本路由,并在流水线中新增专用的 CloseGame 任务。

新功能:
- 新增顶层任务 CloseGame,支持针对不同 Android 客户端包进行路由,并兼容 Win32。
- 在 AndroidOpenGame 任务中新增 ClientVersion 选择选项,以便在 ADB 和 PlayCover
环境中针对特定的 Android 服务器/客户端包进行目标定位。

增强:
- 将 AndroidOpenGame 和 CloseGame 重构为模块化的 GameSwitch
流水线节点,用于按平台和服务器进行特定路由,并将 Android 相关行为从通用的 OpenGame 流水线中拆分出去。

文档:
- 更新多语言本地化界面字符串,以反映新的 CloseGame 任务和客户端版本选择选项。

<details>
<summary>Original summary in English</summary>

## Summary by Sourcery

Introduce configurable client version routing for Android game launch
and closure, and add a dedicated CloseGame task wired into the pipeline.

New Features:
- Add a CloseGame top-level task with routing support for different
Android client packages and Win32 compatibility.
- Add a ClientVersion selection option to the AndroidOpenGame task to
target specific Android server/client packages in ADB and PlayCover
environments.

Enhancements:
- Refactor AndroidOpenGame and CloseGame into modular GameSwitch
pipeline nodes for platform- and server-specific routing, delegating
Android behavior out of the generic OpenGame pipeline.

Documentation:
- Update localized interface strings in multiple languages to reflect
the new CloseGame task and client version selection options.

</details>

</details>
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.

2 participants