Skip to content

完善鸣潮官方更新等待流程 - #408

Open
1w1w11w1 wants to merge 1 commit into
devfrom
feat/wuthering-waves-update
Open

完善鸣潮官方更新等待流程#408
1w1w11w1 wants to merge 1 commit into
devfrom
feat/wuthering-waves-update

Conversation

@1w1w11w1

@1w1w11w1 1w1w11w1 commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

变更摘要

  • 增加鸣潮官方启动器版本元数据检查,区分正式更新与预下载版本。
  • 将官方启动器更新、解压等待和版本校验接入 OK-WW 自动代理流程,下载与校验继续交由官方启动器处理。
  • 补充官服与国际服资源处理,并更新版本记录。

@sourcery-ai

sourcery-ai Bot commented Aug 22, 2026

Copy link
Copy Markdown

审查者指南

将《鸣潮》官方启动器版本元数据集成到 OK-WW 自动代理流程中,新增更新/预下载检测、通过 OCR 由启动器驱动的更新编排,以及本地版本轮询,同时继续将实际下载和验证完全交由官方启动器处理。

《鸣潮》官方启动器更新流程时序图

sequenceDiagram
    participant OKWW as OK-WW AutoProxy
    participant API as Official Update API
    participant Launcher as Official Launcher
    participant FS as Local Version Metadata

    OKWW->>API: check_wuthering_waves_update(launcher_path, resource)
    API-->>OKWW: default / predownload version metadata
    OKWW->>Launcher: _start_wuthering_waves_launcher()
    alt Formal update available
        OKWW->>Launcher: _click_wuthering_waves_launcher_text(Update)
        Launcher-->>FS: Download, install, and verify update
        loop Until target version is reached
            OKWW->>FS: _read_local_wuthering_waves_version(launcher_path)
            FS-->>OKWW: current version
        end
        OKWW->>OKWW: wait_wuthering_waves_update(launcher_path, target_version)
    else Predownload available
        OKWW->>Launcher: _click_wuthering_waves_launcher_text(预下载)
        OKWW->>Launcher: _click_wuthering_waves_launcher_text(确定下载)
    end
    OKWW->>OKWW: Start Wuthering Waves client
Loading

文件级变更

变更 详情 文件
重构《鸣潮》启动器路径解码,以公开安装目录解析功能,并添加具有健壮错误处理的本地版本文件解析。
  • 将启动器元数据解码拆分为安装目录辅助函数和进程路径辅助函数,以复用安装目录解析逻辑。
  • 添加 resolve_wuthering_waves_install_dir,用于验证 launcher.exe 是否存在并返回记录的安装目录。
  • 引入 _read_local_wuthering_waves_version,用于读取 launcherDownloadConfig.json、解析 JSON,并提取格式规范的版本字符串,同时提供用户友好的错误消息。
app/services/wuthering_waves.py
基于本地版本元数据,实现由官方启动器驱动的更新版本比较和异步等待逻辑。
  • 添加 _version_key 和 _is_newer_version 辅助函数,通过正则表达式提取并比较类似语义化版本的字符串。
  • 引入 wait_wuthering_waves_update,这是一个异步轮询循环,用于等待本地版本达到或超过目标版本;在临时读取失败时提供超时控制和调试日志。
  • 定义与更新相关的轮询间隔和全局超时常量,以控制等待行为。
app/services/wuthering_waves.py
添加基于异步 HTTP 的更新元数据检查器,以区分不同游戏资源的正式发布和预下载状态,并将其封装在数据类中。
  • 引入 WutheringWavesUpdateInfo 数据类,包含当前版本、正式发布版本和预下载版本字段、更新可用标志,以及用于判断是否应启动启动器的辅助属性。
  • 定义 _OFFICIAL_UPDATE_API,将官服和国际服映射到各自的元数据端点。
  • 使用 httpx.AsyncClient 实现 check_wuthering_waves_update,以获取 JSON、验证结构、读取默认版本和预下载版本信息、解析 predownloadSwitch、计算可用性标志,并记录简洁摘要。
app/services/wuthering_waves.py
将官方启动器更新逻辑集成到 OK-WW 自动代理流程中,使用 OCR 点击启动器界面按钮,并在启动游戏前协调更新检查。
  • 在 AutoProxy 状态中跟踪 launcher_path 和专用的 launcher_process_manager,并在加载配置期间完成初始化。
  • 添加 _click_wuthering_waves_launcher_text,使用 OCRTool.click_txt 配合特定资源的窗口标题和简单重试逻辑,点击本地化的按钮文本。
  • 实现 _start_wuthering_waves_launcher:当 launcher.exe 尚未运行时启动它,并通过 ProcessManager 进行管理。
  • 实现 _trigger_wuthering_waves_launcher_update,通过 OCR 点击更新或预下载按钮及确认按钮来驱动启动器界面,记录相关操作,并在开始正式发布更新时调用 wait_wuthering_waves_update。
  • 添加 _check_and_trigger_wuthering_waves_update,用于调用 check_wuthering_waves_update、优雅地处理失败、评估 should_start_launcher,并在需要时触发由界面驱动的更新。
  • 扩展 _mas_launch_game_before_task,在处理游戏客户端进程生命周期之前执行官方更新检查/触发步骤。
app/task/Okww/AutoProxy.py
更新 OK-WW 日志和版本元数据记录。
  • 调整 set_okww 中的日志消息,改用不包含 f-string 插值的静态字符串。
  • 更新 res/version.json,以记录与扩展后的《鸣潮》更新流程相关的新版本。
app/task/Okww/AutoProxy.py
res/version.json

提示和命令

与 Sourcery 交互

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

自定义使用体验

访问你的控制面板

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

获取帮助

Original review guide in English

Reviewer's Guide

Integrates Wuthering Waves official launcher version metadata into the OK-WW auto-proxy flow, adding update/predownload detection, launcher-driven update orchestration via OCR, and local version polling, while keeping actual download and verification fully delegated to the official launcher.

Sequence diagram for the Wuthering Waves official launcher update flow

sequenceDiagram
    participant OKWW as OK-WW AutoProxy
    participant API as Official Update API
    participant Launcher as Official Launcher
    participant FS as Local Version Metadata

    OKWW->>API: check_wuthering_waves_update(launcher_path, resource)
    API-->>OKWW: default / predownload version metadata
    OKWW->>Launcher: _start_wuthering_waves_launcher()
    alt Formal update available
        OKWW->>Launcher: _click_wuthering_waves_launcher_text(Update)
        Launcher-->>FS: Download, install, and verify update
        loop Until target version is reached
            OKWW->>FS: _read_local_wuthering_waves_version(launcher_path)
            FS-->>OKWW: current version
        end
        OKWW->>OKWW: wait_wuthering_waves_update(launcher_path, target_version)
    else Predownload available
        OKWW->>Launcher: _click_wuthering_waves_launcher_text(预下载)
        OKWW->>Launcher: _click_wuthering_waves_launcher_text(确定下载)
    end
    OKWW->>OKWW: Start Wuthering Waves client
Loading

File-Level Changes

Change Details Files
Refactor Wuthering Waves launcher path decoding to expose install directory resolution and add local version file parsing with robust error handling.
  • Split launcher metadata decoding into an install-dir helper and a process-path helper to reuse install directory resolution.
  • Add resolve_wuthering_waves_install_dir to validate launcher.exe existence and return the recorded install directory.
  • Introduce _read_local_wuthering_waves_version to read launcherDownloadConfig.json, parse JSON, and extract a clean version string with user-friendly error messages.
app/services/wuthering_waves.py
Implement version comparison and async waiting logic for official launcher-driven updates based on local version metadata.
  • Add _version_key and _is_newer_version helpers to compare semantic-like version strings extracted via regex.
  • Introduce wait_wuthering_waves_update, an async polling loop that waits for the local version to reach or exceed the target, with timeout and debug logging on transient read failures.
  • Define update-related constants for polling interval and global timeout to control waiting behavior.
app/services/wuthering_waves.py
Add an async HTTP-based update metadata checker that distinguishes release and predownload states for different game resources, encapsulated in a dataclass.
  • Introduce WutheringWavesUpdateInfo dataclass with fields for current, release, and predownload versions, flags for update availability, and a helper property to decide whether to start the launcher.
  • Define _OFFICIAL_UPDATE_API mapping for 官服 and 国际服 to their respective metadata endpoints.
  • Implement check_wuthering_waves_update using httpx.AsyncClient to fetch JSON, validate structure, read default and predownload version info, interpret predownloadSwitch, compute availability flags, and log a concise summary.
app/services/wuthering_waves.py
Integrate official launcher update logic into the OK-WW AutoProxy pipeline, using OCR to press launcher UI buttons and coordinating update checks before game launch.
  • Track launcher_path and a dedicated launcher_process_manager in AutoProxy state, initialized during configuration loading.
  • Add _click_wuthering_waves_launcher_text to use OCRTool.click_txt with resource-specific window titles and simple retry behavior to click localized button texts.
  • Implement _start_wuthering_waves_launcher to launch launcher.exe when not already running, managed via ProcessManager.
  • Implement _trigger_wuthering_waves_launcher_update to drive the launcher UI: clicking update or predownload and confirmation buttons via OCR, logging actions, and invoking wait_wuthering_waves_update when a release update is started.
  • Add _check_and_trigger_wuthering_waves_update to call check_wuthering_waves_update, gracefully handle failures, evaluate should_start_launcher, and trigger UI-driven update as needed.
  • Extend _mas_launch_game_before_task to run the official update check/trigger step before handling the game client process lifecycle.
app/task/Okww/AutoProxy.py
Update OK-WW logging and version metadata records.
  • Adjust a log message in set_okww to use a static string without f-string interpolation.
  • Update res/version.json to record the new version associated with the extended Wuthering Waves update flow.
app/task/Okww/AutoProxy.py
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

@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.

嘿——我发现了 2 个问题

面向 AI Agent 的提示
请处理本次代码审查中的评论:

## 单独评论

### 评论 1
<location path="app/services/wuthering_waves.py" line_range="151-152" />
<code_context>
+
+
+def _is_newer_version(candidate: str | None, current: str | None) -> bool:
+    if not candidate or not current:
+        return False
+    return _version_key(candidate) > _version_key(current)
+
+
</code_context>
<issue_to_address>
**问题 (bug_risk):**`launcherDownloadConfig.json` 缺失或不包含可用的本地版本时,`_is_newer_version` 始终返回 `False`,因此正式更新和预下载都会被报告为不可用,并且永远不会启动官方启动器。

**触发条件:** 本地启动器版本记录不存在、为空,或在之前的安装/更新过程中被删除时。

**建议修复:** 将未知的本地版本视为需要启动启动器,或者明确使检查失败,而不是报告没有更新。

```suggestion
    if not current:
        return True
```
</issue_to_address>

### 评论 2
<location path="app/services/wuthering_waves.py" line_range="234" />
<code_context>
+    if not isinstance(payload, dict):
+        raise ValueError("鸣潮官方更新接口返回格式错误")
+
+    default_info = payload.get("default")
+    predownload_info = payload.get("predownload")
+    if not isinstance(default_info, dict):
+        raise ValueError("鸣潮官方更新接口缺少 default 版本信息")
+
+    release_version = str(default_info.get("version") or "").strip() or None
+    predownload_version = (
+        str(predownload_info.get("version") or "").strip()
+        if isinstance(predownload_info, dict)
</code_context>
<issue_to_address>
**问题 (bug_risk):** 当 API 响应包含 `default` 对象但没有有效的 `version` 时,该响应仍会被接受,导致 `release_version=None`,并且更新检测会被静默禁用,而不是拒绝格式错误的响应。

**触发条件:** 官方更新 API 返回不完整或暂时格式错误的 `default` 条目时。

**建议修复:** 验证 `default_info["version"]` 是非空字符串;当其缺失或无效时,抛出 `ValueError````suggestion
    release_version = default_info.get("version")
    if not isinstance(release_version, str) or not release_version.strip():
        raise ValueError("鸣潮官方更新接口缺少有效的 default version")
    release_version = release_version.strip()
```
</issue_to_address>

Sourcery 评估

需要人工审查。 需要先处理 2 个发现,并且该变更会根据远程版本接口和 OCR 操作官方启动器,自动下载、解压并覆盖本地游戏安装文件;如果版本判断或按钮识别错误,影响会在代码回滚后仍留在本地安装中。影响范围通常局限于单个游戏安装,可通过官方启动器重新更新或重装修复,但不能仅靠回滚完全撤销。

阻塞性发现:app/services/wuthering_waves.py:152app/services/wuthering_waves.py:234


Sourcery 对开源项目免费——如果您喜欢我们的审查结果,请考虑分享它们 ✨
帮助我变得更有用!请在每条评论上点击 👍 或 👎,我会利用这些反馈来改进审查结果。
Original comment in English

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="app/services/wuthering_waves.py" line_range="151-152" />
<code_context>
+
+
+def _is_newer_version(candidate: str | None, current: str | None) -> bool:
+    if not candidate or not current:
+        return False
+    return _version_key(candidate) > _version_key(current)
+
+
</code_context>
<issue_to_address>
**issue (bug_risk):** When `launcherDownloadConfig.json` is missing or contains no usable local version, `_is_newer_version` always returns `False`, so both formal updates and predownloads are reported as unavailable and the official launcher is never started.

**Triggers:** When the local launcher version record is absent, empty, or has been removed during a prior installation/update.

**Suggested fix:** Treat an unknown local version as requiring the launcher to start, or explicitly fail the check instead of reporting no update.

```suggestion
    if not current:
        return True
```
</issue_to_address>

### Comment 2
<location path="app/services/wuthering_waves.py" line_range="234" />
<code_context>
+    if not isinstance(payload, dict):
+        raise ValueError("鸣潮官方更新接口返回格式错误")
+
+    default_info = payload.get("default")
+    predownload_info = payload.get("predownload")
+    if not isinstance(default_info, dict):
+        raise ValueError("鸣潮官方更新接口缺少 default 版本信息")
+
+    release_version = str(default_info.get("version") or "").strip() or None
+    predownload_version = (
+        str(predownload_info.get("version") or "").strip()
+        if isinstance(predownload_info, dict)
</code_context>
<issue_to_address>
**issue (bug_risk):** An API response with a `default` object but without a valid `version` is accepted, producing `release_version=None` and silently disabling update detection instead of rejecting the malformed response.

**Triggers:** When the official update API returns an incomplete or temporarily malformed `default` entry.

**Suggested fix:** Validate that `default_info["version"]` is a non-empty string and raise `ValueError` when it is missing or invalid.

```suggestion
    release_version = default_info.get("version")
    if not isinstance(release_version, str) or not release_version.strip():
        raise ValueError("鸣潮官方更新接口缺少有效的 default version")
    release_version = release_version.strip()
```
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and 该变更会根据远程版本接口和 OCR 操作官方启动器,自动下载、解压并覆盖本地游戏安装文件;如果版本判断或按钮识别错误,影响会在代码回滚后仍留在本地安装中。影响范围通常局限于单个游戏安装,可通过官方启动器重新更新或重装修复,但不能仅靠回滚完全撤销。.

Blocking findings: app/services/wuthering_waves.py:152, app/services/wuthering_waves.py:234


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 on lines +151 to +152
if not candidate or not current:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

问题 (bug_risk):launcherDownloadConfig.json 缺失或不包含可用的本地版本时,_is_newer_version 始终返回 False,因此正式更新和预下载都会被报告为不可用,并且永远不会启动官方启动器。

触发条件: 本地启动器版本记录不存在、为空,或在之前的安装/更新过程中被删除时。

建议修复: 将未知的本地版本视为需要启动启动器,或者明确使检查失败,而不是报告没有更新。

Suggested change
if not candidate or not current:
return False
if not current:
return True
Original comment in English

issue (bug_risk): When launcherDownloadConfig.json is missing or contains no usable local version, _is_newer_version always returns False, so both formal updates and predownloads are reported as unavailable and the official launcher is never started.

Triggers: When the local launcher version record is absent, empty, or has been removed during a prior installation/update.

Suggested fix: Treat an unknown local version as requiring the launcher to start, or explicitly fail the check instead of reporting no update.

Suggested change
if not candidate or not current:
return False
if not current:
return True

if not isinstance(default_info, dict):
raise ValueError("鸣潮官方更新接口缺少 default 版本信息")

release_version = str(default_info.get("version") or "").strip() or None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

问题 (bug_risk): 当 API 响应包含 default 对象但没有有效的 version 时,该响应仍会被接受,导致 release_version=None,并且更新检测会被静默禁用,而不是拒绝格式错误的响应。

触发条件: 官方更新 API 返回不完整或暂时格式错误的 default 条目时。

建议修复: 验证 default_info["version"] 是非空字符串;当其缺失或无效时,抛出 ValueError

Suggested change
release_version = str(default_info.get("version") or "").strip() or None
release_version = default_info.get("version")
if not isinstance(release_version, str) or not release_version.strip():
raise ValueError("鸣潮官方更新接口缺少有效的 default version")
release_version = release_version.strip()
Original comment in English

issue (bug_risk): An API response with a default object but without a valid version is accepted, producing release_version=None and silently disabling update detection instead of rejecting the malformed response.

Triggers: When the official update API returns an incomplete or temporarily malformed default entry.

Suggested fix: Validate that default_info["version"] is a non-empty string and raise ValueError when it is missing or invalid.

Suggested change
release_version = str(default_info.get("version") or "").strip() or None
release_version = default_info.get("version")
if not isinstance(release_version, str) or not release_version.strip():
raise ValueError("鸣潮官方更新接口缺少有效的 default version")
release_version = release_version.strip()

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