Skip to content

feat: 差分宇宙: 调用 auto simulated universe 项目;识别周奖励进度,添加每周打完14000就溜的选项#521

Open
JoshCai233 wants to merge 40 commits intoOneDragon-Anything:mainfrom
JoshCai233:sim-uni-x
Open

feat: 差分宇宙: 调用 auto simulated universe 项目;识别周奖励进度,添加每周打完14000就溜的选项#521
JoshCai233 wants to merge 40 commits intoOneDragon-Anything:mainfrom
JoshCai233:sim-uni-x

Conversation

@JoshCai233
Copy link
Copy Markdown
Contributor

@JoshCai233 JoshCai233 commented Sep 24, 2025

需要把Auto_Simulated_Universe 的项目源码放到文件夹 plugins/Auto_Simulated_Universe 中.

Summary by CodeRabbit

发行说明

  • 新功能

    • 新增“差分宇宙(世界X)”模式支持、奖励检测与自动化入口,支持调用外部差分宇宙插件并进行结果轮询
    • 新增脚本链式执行工具与设置界面中的差分宇宙配置、插件启动与保存操作
    • 设置中新增“仅积分奖励”开关与相关选项
  • 问题修复

    • 优化 OCR 与区域识别流程,提高界面检测稳定性
    • 简化并合并祝福/奇物选择流程,减少判定失败及流程不一致情况
  • 其他

    • 文档中新增相关项目链接及少量运行时依赖声明调整

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 24, 2025

Walkthrough

引入“差分宇宙 (WORLD_X)”自动化路径:新增脚本链与运行器、扩展 OCR 接口与区域识别、配置/状态与 UI 支持,并在多处将截图源统一为 last_screenshot,合并/禁用奇物选择逻辑以简化流程。

Changes

内聚 / 文件(s) 变更摘要
游戏数据配置
assets/game_data/screen_info/challenge_mission.yml, assets/game_data/screen_info/sim_uni.yml
支援按钮坐标重定位;新增差分宇宙区域(积分奖励、返回按钮、返回主界面);多处坐标/文本调整。
OCR 与屏幕工具
src/one_dragon/base/screen/screen_utils.py, src/one_dragon/base/matcher/template_matcher.py, src/one_dragon/base/operation/operation.py
新增 ocr()ocr_in_screen();find_area_in_screen 改为调用 ocr_in_screen;Operation 增加 ocr(...) 方法;若干调试注释添加。
脚本链配置与运行器
src/script_chainer/config/script_config.py, src/script_chainer/win_exe/script_runner.py
新增 ScriptConfig / ScriptChainConfig(YAML 持久化、增删改移)与脚本运行器(子进程启动、PID/进程监控、完成检查、清理、CLI 参数)。
SimUni 常量与配置
src/sr_od/app/sim_uni/sim_uni_const.py, src/sr_od/app/sim_uni/sim_uni_config.py, src/sr_od/app/sim_uni/sim_uni_run_record.py
新增 WORLD_X 枚举;默认周本改为 WORLD_X;新增 sim_uni_100 与 only_points_reward 配置;增加 run record 标志 points_reward_complete 并在周边界重置。
屏幕状态与状态机
src/sr_od/app/sim_uni/sim_uni_screen_state.py
添加 SIM_TYPE_X(差分宇宙);将 SIM_BLESS 从“选择祝福”改为“选择”;注释/禁用 SIM_CURIOS;调整匹配策略与祝福阈值。
SimUni 应用逻辑
src/sr_od/app/sim_uni/sim_uni_app.py
新增 _check_points_reward()_execute_sim_universe_x(),整合脚本链执行、文件同步与结果轮询,扩展 WORLD_X 路径与周本/积分分支。
操作流程与行为调整
多个 src/sr_od/app/sim_uni/operations/... 文件
广泛将 screenshot() 替换为 last_screenshot;禁用或合并奇物选择为统一选择路径;祝福确认改为固定两步点击序列;SimUniExit 新增 is_in_x 标志并据此采取返回主界面动作。
返回主界面与流程整合
src/sr_od/operations/back_to_normal_world_plus.py
优先尝试差分宇宙返回按钮并记录 is_in_x 传递给 SimUniExit;使用 last_screenshot;注释 SIM_CURIOS 路径;SimUniExit 调用签名更新。
指南与传送逻辑
src/sr_od/interastral_peace_guide/...
对差分宇宙任务增加早期返回;调整匹配优先级/容错;使用 last_screenshot。
进入游戏与通用操作
src/sr_od/operations/enter_game/enter_game.py
将 screenshot() 替换为 last_screenshot;部分登录路径由等待改为直接成功信号。
UI 与设置
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py, .github/README.md
新增差分宇宙配置区、插件启动与保存按钮、only_points_reward 开关;README 添加 Auto_Simulated_Universe 链接。
其他
pyproject.toml
新增运行依赖 psutil==6.1.1

Sequence Diagram(s)

sequenceDiagram
    participant App as SimUniApp
    participant Config as ScriptChainConfig
    participant Runner as ScriptRunner
    participant Plugin as Subprocess(插件)
    participant Monitor as Monitor(进程/超时)

    App->>Config: 构建/读取 ScriptConfig
    loop 对每个 ScriptConfig
        App->>Runner: run_script(script_config)
        Runner->>Plugin: spawn subprocess (plugin 脚本/GUI)
        activate Plugin
        Runner->>Monitor: 启动监控 (PID, timeout, game process)
        par 监控脚本进程
            Monitor->>Monitor: 检查 PID 存活/创建时间
        and 监控游戏进程
            Monitor->>Monitor: 检查游戏进程是否存在/退出
        end
        alt 达到完成条件 (CheckDoneMethods)
            Monitor-->>Runner: 返回成功
        else 超时或错误
            Monitor-->>Runner: 返回失败/原因
            Runner->>Plugin: kill/清理(可选)
        end
        deactivate Plugin
        Runner-->>App: 执行结果
        alt 成功
            App->>App: 更新状态 (elite_times, points_reward_complete)
        else 失败
            App->>App: 记录/重试/回退
        end
    end
Loading

Estimated code review effort

🎯 4 (复杂) | ⏱️ ~60 分钟

需重点审查:

  • script_runner.py 的子进程启动、PID 检测、等待与清理逻辑;
  • sim_uni_app.pysim_uni_screen_state.py 中 WORLD_X 路由、新节点与状态检测边界;
  • screen_utils.py 的 OCR 缓存策略、坐标偏移与与现有模板匹配的整合;
  • BackToNormalWorldPlusSimUniExit 的签名变更及调用处一致性;
  • 大量将 screenshot() 替换为 last_screenshot 的影响范围与竞态/时序问题。

Possibly related PRs

Poem

🐰 我跳过字段与坐标行,插件子进程排成队;
OCR 识出积分声,状态机里换新路。
兔兔点点小胡萝 🥕,自动化又多一局。

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 标题清晰准确地总结了主要变更:集成 Auto_Simulated_Universe 项目、识别周奖励进度、添加 14000 积分停止选项,与原始变更内容高度相关且具体。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

🧹 Nitpick comments (20)
src/one_dragon/base/matcher/template_matcher.py (1)

49-51: 避免硬编码调试路径,改用可控调试开关

硬编码 y:/template.png 易误导/误用;建议使用日志或受配置控制的调试导出,且输出到工作目录下的临时/日志路径。

可以改为(示例):

-        # cv2.imwrite('y:/template.png', template.get_image(template_type))
+        # if self.ctx and getattr(self.ctx, "debug_save_templates", False):
+        #     from one_dragon.utils import os_utils
+        #     out = os_utils.get_path_under_work_dir('.log', 'last_template.png')
+        #     cv2.imwrite(out, template.get_image(template_type))
src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py (1)

77-97: 移除“选择奇物”后请同步清理状态机边(避免悬空 from 节点)

本类已注释掉 @operation_node(name='选择奇物') 实现,但下方仍有 @node_from(from_name='选择奇物') 的入边引用;如该节点在本类内不再存在,建议移除该入边,避免状态机构建/可视化时出现悬空引用。

如需保留兼容,可添加一个空实现节点,直接路由到“确认后画面判断”。

src/script_chainer/config/script_config.py (1)

43-58: 类型标注与可空字段:显式声明 Optional 并允许 None

script_working_directory 允许为 None,但类型标注为 str。建议改为可选类型,避免静态检查告警与误用。

-                 script_working_directory: str = None,
+                 script_working_directory: str | None = None,

并同步将 self.script_working_directory 标注为 str | None

src/script_chainer/win_exe/script_runner.py (3)

145-149: 解析脚本参数请用 shlex.split 以兼容带空格/引号

简单 split() 无法正确处理带引号的参数。

-    if args and args.strip():
-        command.extend(args.split())
+    if args and args.strip():
+        import shlex
+        command.extend(shlex.split(args, posix=False))

257-275: 进程关闭更温和并增加兜底

直接 kill() 粗暴,可先 terminate() 并在超时后 kill();同理对游戏/脚本名杀进程亦可分两步。

如需,我可以补充一个带超时的 terminate_then_kill(name, timeout=3) 辅助函数。


315-323: finally 中的 return 会吞掉异常

会屏蔽上方潜在异常与退出码,建议移除该 return

-        return
+        pass
src/sr_od/interastral_peace_guide/guide_transport.py (1)

50-55: 差分宇宙分支直接成功:考虑补充最小等待或后置校验

直接 op_success("成功") 可能在目标场景尚未完全加载时继续后续流程。建议:

  • 追加一个极短等待(如 0.5–1s),或
  • 在后续首个节点执行前做一次轻量画面确认。
-        if self.mission.cate.cn == '差分宇宙':
-            return self.round_by_op_result(self.op_success("成功"))
+        if self.mission.cate.cn == '差分宇宙':
+            return self.round_by_op_result(self.op_success("成功"), wait=1)
src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (1)

107-112: 双确认点击逻辑请加存在性校验或容错等待

改为无条件点击右下确认再点中间确认,可能在部分界面仅存在其中一个按钮时误点空白区域。

  • 建议在点击前加入一次小范围截图+像素/文本判定,或缩短第二次点击的命中区域至更安全的中心偏下位置。
  • 若无法快速校验,至少将第二次点击置于 try/except 并缩短等待时间,失败走后续 wait_not_in_bless 快速返回。
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)

101-109: 点击路径分叉依赖屏幕区域配置,需确保已新增“差分宇宙返回主界面”区域

若该区域未在 Screen 配置中定义,将返回 AREA_NO_CONFIG 并导致流程失败。

@@     def click_empty(self) -> OperationRoundResult:
-        if self.is_in_x:
-            return self.round_by_find_and_click_area(screen, '模拟宇宙', '差分宇宙返回主界面',
-                                                     success_wait=2, retry_wait=1)
-        else:
-            return self.round_by_find_and_click_area(screen, '模拟宇宙', '点击空白处继续',
-                                                     success_wait=2, retry_wait=1)
+        if self.is_in_x:
+            result = self.round_by_find_and_click_area(screen, '模拟宇宙', '差分宇宙返回主界面',
+                                                       success_wait=2, retry_wait=1)
+            if not result.is_success:
+                # 兜底:旧路径尝试一次,避免卡住
+                return self.round_by_find_and_click_area(screen, '模拟宇宙', '点击空白处继续',
+                                                         success_wait=2, retry_wait=1)
+            return result
+        else:
+            return self.round_by_find_and_click_area(screen, '模拟宇宙', '点击空白处继续',
+                                                     success_wait=2, retry_wait=1)

同时请核验 assets 中“差分宇宙返回主界面”已配置 OCR/坐标区域。

src/sr_od/app/sim_uni/sim_uni_run_record.py (1)

95-106: period_reward_complete 的注释不准确

当前 docstring 写成“每周挑战精英的次数”,建议更正为“周期奖励是否已完成”。

-        """
-        每周挑战精英的次数
-        :return:
-        """
+        """
+        周期奖励(例如周积分/周奖励)是否已完成
+        :return:
+        """
src/one_dragon/base/screen/screen_utils.py (1)

66-66: 清理调试代码

文件中存在多处被注释掉的调试代码(如 cv2.imwrite 调用),建议删除这些无用的注释代码以保持代码整洁。

-# cv2.imwrite('y:/part.png', part)
-# cv2.imwrite('y:/screen.png', screen)
-# cv2.imwrite('y:/part.png', part)
-# cv2.imwrite('y:/part.png', to_ocr_part)
-
-# cv2.imwrite('y:/part.png', part)
-# for ocr_result, mrl in ocr_result_map.items():
-#     if str_utils.find_by_lcs(gt(area.text, 'game'), ocr_result, percent=area.lcs_percent):
-#         find = True
-#         break

Also applies to: 86-87, 130-134, 159-159

src/sr_od/app/sim_uni/operations/sim_uni_event.py (1)

297-308: 选择奇物功能已被注释但未完全移除

选择奇物的处理逻辑已被注释,表明功能正在被弃用并合并到选择祝福流程中。建议:

  1. 如果确定不再需要此功能,应完全删除这段代码
  2. 注释提到"固定选择第一项",但具体实现细节不清楚

请确认选择奇物的新处理逻辑是否已在选择祝福流程中正确实现。如果已实现,建议删除这段注释代码:

-    # 选择奇物合并到选择祝福中, 并且固定选择第一项
-    # @node_from(from_name='确定后判断', status=sim_uni_screen_state.ScreenState.SIM_CURIOS.value)
-    # @operation_node(name='选择奇物')
-    # def _choose_curio(self) -> OperationRoundResult:
-    #     op = SimUniChooseCurio(self.ctx, config=self.config)
-    #     op_result = op.execute()
-    #
-    #     if op_result.success:
-    #         return self.round_success()
-    #     else:
-    #         return self.round_retry(status=op_result.status)
src/sr_od/operations/back_to_normal_world_plus.py (1)

77-78: 注释代码应清理

选择奇物的处理已被注释,与 sim_uni_event.py 中的改动一致。建议删除这些注释代码。

-        # if sim_uni_state == sim_uni_screen_state.ScreenState.SIM_CURIOS.value:
-        #     return self.sim_uni_choose_curio()
src/sr_od/app/sim_uni/sim_uni_screen_state.py (1)

188-195: 清理已弃用的代码

in_sim_uni_choose_curio 函数已被注释,与整体的奇物选择功能整合一致。建议删除这段代码。

-# def in_sim_uni_choose_curio(ctx: SrContext, screen: MatLike) -> bool:
-#     """
-#     是否在模拟宇宙-选择奇物页面
-#     :param ctx: 上下文
-#     :param screen: 游戏画面
-#     :return:
-#     """
-#     return common_screen_state.in_secondary_ui(ctx, screen, ScreenState.SIM_CURIOS.value, lcs_percent=0.55)
assets/game_data/screen_info/sim_uni.yml (1)

33-46: 配置项文本字段可能需要调整

Line 40 的 text: 14000/14000 (其实没用) 包含调试性注释"(其实没用)",这在生产环境中可能不太合适。

建议将文本改为更规范的内容:

-  text: 14000/14000 (其实没用)
+  text: 14000/14000
src/sr_od/app/sim_uni/sim_uni_app.py (3)

61-78: OCR结果迭代中的未使用变量

Line 68 的循环中,变量 mrl 未被使用。根据 Python 惯例,应将其重命名为 __mrl

-        for ocr_result, mrl in ocr_result_map.items():
+        for ocr_result, _ in ocr_result_map.items():

176-180: 清空文件的方式可以优化

Line 178-179 使用 with open(..., 'w') 并传入空内容来清空文件。虽然这种方法有效,但可以更简洁。

-        if os.path.exists(plugin_run_result_path):
-            with open(plugin_run_result_path, 'w', encoding='utf-8') as file:
-                pass  # 不写入任何内容,仅清空
+        if os.path.exists(plugin_run_result_path):
+            open(plugin_run_result_path, 'w', encoding='utf-8').close()

145-154: 改进建议:将未使用的循环变量改为 _,无需额外 sleep(无限循环风险不存在)

验证结果:_check_period_reward 在未找到周奖励时返回 round_retry(..., wait=1),会在返回前 sleep 1s;循环有上限(for i in range(30))且在 FAIL 时 break、SUCCESS 时 return,因此不会导致无限循环。建议将 for i in range(30): 改为 for _ in range(30):;可选在该分支加少量日志以便排查。 位置:src/sr_od/app/sim_uni/sim_uni_app.py(_execute_sim_universe_x)

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (2)

35-47: 存在命令注入安全隐患

Line 46 使用 subprocess.Popen 执行外部命令,虽然 args.split() 看起来受控,但理论上仍存在潜在的安全风险。当前 args 是从固定路径构建的,相对安全。

建议使用列表形式传递参数,避免使用 split()

         command = [self.ctx.python_service.env_config.python_path]
         args = os.path.join(plugin_path, 'gui.py')
         script_working_directory = plugin_path
-        if args and args.strip():
-            command.extend(args.split())
+        command.append(args)
         subprocess.Popen(command, cwd=script_working_directory)

72-78: UI文本提示需要更明确

Line 76 的提示信息告诉用户需要下载项目,但没有提供具体的下载链接或更详细的安装说明。

建议改进提示文本,提供更清晰的指引:

         self.auto_simulated_universe_settings = PushSettingCard(
             icon=FluentIcon.APPLICATION,
             title='配置Auto_Simulated_Universe',
-            content='需要先去github下载该项目放到 plugins/Auto_Simulated_Universe文件夹中',
+            content='需要先下载 Auto_Simulated_Universe 项目到 plugins/Auto_Simulated_Universe 目录。详见使用文档。',
             text='配置'
         )

是否需要我帮您创建一个自动下载和安装插件的功能,或者生成详细的安装文档?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b04d447 and b370f39.

📒 Files selected for processing (25)
  • assets/game_data/interastral_peace_guide_data.yml (1 hunks)
  • assets/game_data/screen_info/challenge_mission.yml (2 hunks)
  • assets/game_data/screen_info/sim_uni.yml (6 hunks)
  • src/one_dragon/base/matcher/template_matcher.py (1 hunks)
  • src/one_dragon/base/operation/operation.py (1 hunks)
  • src/one_dragon/base/screen/screen_utils.py (5 hunks)
  • src/script_chainer/config/script_config.py (1 hunks)
  • src/script_chainer/win_exe/script_runner.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/auto_run/sim_uni_wait_level_start.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/bless/bless_utils.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/sim_uni_enter_fight.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/sim_uni_event.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/sim_uni_exit.py (3 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (3 hunks)
  • src/sr_od/app/sim_uni/sim_uni_config.py (2 hunks)
  • src/sr_od/app/sim_uni/sim_uni_const.py (1 hunks)
  • src/sr_od/app/sim_uni/sim_uni_run_record.py (3 hunks)
  • src/sr_od/app/sim_uni/sim_uni_screen_state.py (5 hunks)
  • src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (4 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py (1 hunks)
  • src/sr_od/interastral_peace_guide/guide_transport.py (1 hunks)
  • src/sr_od/operations/back_to_normal_world_plus.py (3 hunks)
  • src/sr_od/operations/enter_game/enter_game.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (14)
src/one_dragon/base/screen/screen_utils.py (8)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResultList (45-121)
src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py (2)
  • ocr (257-301)
  • run_ocr (156-192)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • OneDragonContext (56-251)
src/one_dragon/base/screen/screen_area.py (3)
  • ScreenArea (8-139)
  • is_text_area (93-98)
  • rect (36-37)
src/one_dragon/base/screen/screen_loader.py (1)
  • get_area (87-93)
src/one_dragon/envs/env_config.py (2)
  • ocr_cache (487-492)
  • ocr_cache (495-496)
src/one_dragon/base/matcher/ocr/ocr_service.py (1)
  • get_ocr_result_map (194-222)
src/one_dragon/utils/cv2_utils.py (2)
  • crop_image_only (595-603)
  • dilate (606-616)
src/sr_od/operations/enter_game/enter_game.py (2)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/one_dragon/base/operation/operation.py (1)
  • round_success (532-543)
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)
src/one_dragon/base/operation/operation.py (1)
  • round_by_find_and_click_area (618-683)
src/sr_od/app/sim_uni/sim_uni_run_record.py (2)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • only_period_reward (88-93)
  • only_period_reward (96-97)
  • elite_weekly_times (104-109)
  • elite_weekly_times (112-113)
src/one_dragon/base/config/yaml_operator.py (2)
  • get (90-91)
  • update (93-100)
src/sr_od/app/sim_uni/operations/bless/bless_utils.py (1)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResult (7-42)
src/sr_od/app/sim_uni/sim_uni_app.py (10)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • period_reward_complete (96-101)
  • period_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • weekly_uni_num (56-61)
  • weekly_uni_num (64-65)
  • only_period_reward (88-93)
  • only_period_reward (96-97)
src/sr_od/interastral_peace_guide/guide_transport.py (1)
  • GuideTransport (14-55)
src/sr_od/context/sr_pc_controller.py (1)
  • esc (46-48)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/script_chainer/config/script_config.py (3)
src/one_dragon/base/config/config_item.py (2)
  • ConfigItem (7-25)
  • get_config_item_from_enum (28-41)
src/one_dragon/base/config/yaml_config.py (1)
  • YamlConfig (9-102)
src/one_dragon/base/config/yaml_operator.py (1)
  • get (90-91)
src/sr_od/interastral_peace_guide/guide_transport.py (1)
src/one_dragon/base/operation/operation.py (2)
  • round_by_op_result (598-616)
  • round_by_find_area (685-706)
src/sr_od/operations/back_to_normal_world_plus.py (4)
src/one_dragon/base/operation/operation.py (3)
  • round_by_find_area (685-706)
  • round_by_click_area (708-737)
  • round_wait (545-556)
src/one_dragon/base/operation/operation_round_result.py (2)
  • is_success (29-30)
  • OperationRoundResult (13-47)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (1)
  • get_level_type (41-58)
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)
  • SimUniExit (14-109)
src/one_dragon/base/operation/operation.py (2)
src/one_dragon/base/screen/screen_utils.py (1)
  • ocr (96-136)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResultList (45-121)
src/script_chainer/win_exe/script_runner.py (4)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/script_chainer/config/script_config.py (7)
  • ScriptConfig (30-102)
  • ScriptChainConfig (105-217)
  • CheckDoneMethods (8-12)
  • invalid_message (77-102)
  • game_display_name (64-66)
  • check_done_display_name (69-74)
  • script_display_name (60-61)
src/sr_od/context/sr_context.py (1)
  • SrContext (163-338)
src/one_dragon/base/config/yaml_operator.py (2)
  • get (90-91)
  • is_file_exists (110-115)
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)
src/one_dragon/utils/i18_utils.py (1)
  • gt (50-61)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (7)
src/one_dragon_qt/widgets/column.py (1)
  • Column (5-25)
src/one_dragon_qt/widgets/setting_card/push_setting_card.py (1)
  • PushSettingCard (14-41)
src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (1)
  • SwitchSettingCard (15-69)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/one_dragon/envs/env_config.py (2)
  • python_path (108-112)
  • python_path (115-122)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
  • only_period_reward (88-93)
  • only_period_reward (96-97)
  • only_period_reward_adapter (100-101)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
src/one_dragon/base/config/yaml_operator.py (2)
  • get (90-91)
  • update (93-100)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
src/one_dragon_qt/widgets/setting_card/yaml_config_adapter.py (1)
  • YamlConfigAdapter (6-39)
🪛 Ruff (0.13.1)
src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py

202-202: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

src/sr_od/app/sim_uni/operations/bless/bless_utils.py

120-120: Do not use bare except

(E722)


120-121: try-except-pass detected, consider logging the exception

(S110)

src/sr_od/app/sim_uni/sim_uni_app.py

67-67: Loop control variable mrl not used within loop body

Rename unused mrl to _mrl

(B007)


147-147: Loop control variable i not used within loop body

(B007)


179-179: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

src/script_chainer/config/script_config.py

25-25: String contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF001)


25-25: String contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF001)


26-26: String contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF001)


43-43: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)

src/one_dragon/base/operation/operation.py

895-895: Unused method argument: success_wait

(ARG002)


895-895: Unused method argument: success_wait_round

(ARG002)


896-896: Unused method argument: retry_wait

(ARG002)


896-896: Unused method argument: retry_wait_round

(ARG002)


904-904: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


904-904: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)


905-905: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)


906-906: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


906-906: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)


907-907: Docstring contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF002)

src/script_chainer/win_exe/script_runner.py

25-25: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


97-97: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF003)


114-114: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


114-114: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


124-124: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


128-128: Do not catch blind exception: Exception

(BLE001)


129-129: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


129-129: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


130-130: Use explicit conversion flag

Replace with conversion flag

(RUF010)


161-161: subprocess call: check for execution of untrusted input

(S603)


163-163: subprocess call: check for execution of untrusted input

(S603)


165-165: Do not catch blind exception: Exception

(BLE001)


261-261: Do not catch blind exception: Exception

(BLE001)


267-267: Do not catch blind exception: Exception

(BLE001)


275-275: Do not catch blind exception: Exception

(BLE001)


322-322: return inside finally blocks cause exceptions to be silenced

(B012)

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py

46-46: subprocess call: check for execution of untrusted input

(S603)

🔇 Additional comments (16)
src/sr_od/operations/enter_game/enter_game.py (1)

12-12: 导入语句正确添加

新增的导入语句符合代码结构要求,为后续的返回值类型改进提供了必要的类型支持。

assets/game_data/screen_info/challenge_mission.yml (2)

36-41: 校准“队伍标题”区域坐标并留安全边界

坐标仅变动了 y2(214→64? 或 64 保持)请确认该矩形在 1920x1080/缩放设置下稳定覆盖“队伍”文本,建议上下各预留 3–5px 容错,以减小 OCR/模板抖动导致的误判。


50-53: “支援按钮”坐标上移与右扩需实测验证点击命中率

y 从 ~720→700、x2 到 1850,建议在不同语言包/抗锯齿差异下回归验证点击命中与识别是否稳定;必要时考虑配合模板/文本双通道判定。

src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py (1)

200-209: 去掉“仍在选奇物页”的回退逻辑后,确认不会卡在奇物页

原有在 SIM_CURIOS 时递减 curio_cnt_type 的退避已注释。若上游合并到“选择祝福”后仍可能停留在奇物页,当前实现会直接 round_success(state),可能导致流程不再自愈。请确认:该状态在新流程中确实不再出现,或由上游节点统一处理。

assets/game_data/interastral_peace_guide_data.yml (1)

513-518: 新增“差分宇宙/前往参与”项:确认与引导逻辑一致

请确认:

  • category 名与代码判断 self.mission.cate.cn == '差分宇宙' 完全一致;
  • “前往参与”在 UI 中确有一致文案,且 GuideChooseMission 能稳定命中。
src/sr_od/app/sim_uni/sim_uni_const.py (1)

54-55: WORLD_X 的 unique_id 规则与“正常宇宙”一致,确认下游是否依赖 00–09 序号

unique_id 仍为 sim_uni_normal_world_%02d(100→..._100)。请确认:

  • 下游是否按 00–09 范围做逻辑分支或排序;
  • max_diff = -1 的语义下游是否已兼容(例如计算难度上限时不直接 range(max_diff+1))。
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)

120-122: 优先匹配“前往参与”策略合理,但请确认文案与OCR配置一致

  • 顺序从“前往参与”回退到“传送/进入”符合预期,能兼容差分宇宙与旧流程。
  • 请确认 assets 中“前往参与”的翻译键与 gt(...,'game') 一致,且该词条已加入对应屏幕区域的OCR色域配置,否则可能长期匹配不到而频繁拖拽重试。
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)

19-31: 新增 is_in_x 参数与差分宇宙返回主界面支持:API 扩展合理

构造函数扩展和状态保存清晰,命名直观。

请确认所有调用点均已传入 is_in_x(例如 BackToNormalWorldPlus),以免行为不一致。

src/sr_od/app/sim_uni/sim_uni_run_record.py (2)

24-26: 新增 period_reward_complete 融入状态判定:逻辑清晰

按 only_period_reward 短路成功的逻辑合理,周一重置分支也一致。

请确认 sim_uni_app 中达成判断处已正确设置 period_reward_complete,且 UI 里新增“每周14000即止”选项与此字段联动。

Also applies to: 30-33


47-48: 每周重置同步清空 period_reward_complete:一致性良好

与 weekly/elite 周次重置对齐,避免跨周误判。

src/sr_od/app/sim_uni/operations/auto_run/sim_uni_wait_level_start.py (1)

61-67: 需要确认:为 SIM_CURIOS 状态添加兜底(跳过或处理)以避免奇物界面卡住

未在仓库中找到 src/sr_od/app/sim_uni/operations/auto_run/sim_uni_wait_level_start.py,无法验证变更;若确实禁用 SIM_CURIOS 分支,必须在对应位置加入可配置的跳过或继续等待(或恢复 SimUniChooseCurio 处理)以避免在层开始前的奇物界面卡住。

src/sr_od/app/sim_uni/operations/sim_uni_enter_fight.py (1)

293-295: SIM_CURIOS 不会被返回 — 注释分支是安全的

sim_uni_screen_state.py 中 ScreenState.SIM_CURIOS 与对 curio 的检测已被注释(src/sr_od/app/sim_uni/sim_uni_screen_state.py),get_sim_uni_screen_state 不会返回 SIM_CURIOS,故 sim_uni_enter_fight.py 中注释掉的分支不会导致“无限重试”。若需恢复奇物处理,请在 sim_uni_screen_state.py 恢复 curio 检测并同时在 sim_uni_enter_fight._handle_not_in_world 恢复对应分支。

Likely an incorrect or invalid review comment.

src/one_dragon/base/screen/screen_utils.py (1)

96-136: 新增的 OCR 函数实现正确

新增的 ocr 函数实现逻辑与现有的 find_area_in_screen 函数中的 OCR 处理逻辑一致,正确地:

  1. 处理了区域不存在的情况
  2. 支持 OCR 缓存和非缓存两种模式
  3. 正确处理了颜色范围过滤

返回类型 dict[str, MatchResultList] 与 OCR 服务的返回格式一致,集成良好。

src/sr_od/operations/back_to_normal_world_plus.py (2)

31-40: 差分宇宙退出逻辑正确实现

新增的差分宇宙退出逻辑正确地:

  1. 首先尝试识别差分宇宙返回按钮
  2. 记录 is_in_x 标志以区分是否在差分宇宙中
  3. 将此标志传递给 SimUniExit 以执行相应的退出流程

实现逻辑清晰合理。


111-111: ESC 键调用被注释

ESC 键调用被注释掉,改为点击右上角返回。这个改动的原因不明确。

请确认为什么要注释掉 ESC 键调用。如果 ESC 键不再需要,建议删除注释;如果是临时调试,建议恢复或说明原因。

src/sr_od/app/sim_uni/sim_uni_screen_state.py (1)

24-34: 新增差分宇宙类型并统一选择路径

正确添加了差分宇宙 (SIM_TYPE_X) 的支持,并将祝福选择统一为 '选择',注释掉了独立的奇物选择路径。这符合 PR 目标中提到的功能整合。

# Conflicts:
#	assets/game_data/screen_info/challenge_mission.yml
#	src/sr_od/app/sim_uni/operations/sim_uni_exit.py
@JoshCai233
Copy link
Copy Markdown
Contributor Author

目前代码应该只能给懂编程的人用,小白用了八成不会配置,不过估计没有多个小号的人都用三月七助手去了,开摆~

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

192-203: 修复重试逻辑中的错误

在 Python 的 for 循环中,修改循环变量 i 不会影响下一次迭代。当状态为 PAUSE 时执行 i -= 1 试图不计入重试次数,但这不会生效。

此问题在之前的审查中已标记但尚未修复。

建议使用 while 循环实现正确的重试逻辑:

         # 运行脚本, 重试次数 = 3
-        for i in range(3):
+        retry_count = 0
+        max_retries = 3
+        while retry_count < max_retries:
             if self.ctx.context_running_state == ContextRunStateEnum.STOP:
                 break
             elif self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
                 time.sleep(1)
-                i -= 1
                 continue
+            
             run_script(script_config, self.ctx)
+            retry_count += 1
+            
             if self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
                 time.sleep(1)
-                i -= 1
+                continue

205-206: 添加文件读取的错误处理

读取文件并转换为整数时缺少异常处理。如果文件不存在、为空或包含非数字内容,程序将崩溃。

此问题在之前的审查中已标记但尚未修复。

应用此 diff 添加错误处理:

             # 进程退出, 检查运行情况
-            with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
-                completed_num = int(file.readline())
+            try:
+                with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
+                    line = file.readline().strip()
+                    completed_num = int(line) if line else 0
+            except (ValueError, FileNotFoundError, OSError) as e:
+                log.error(f'读取运行结果文件失败: {e}')
+                completed_num = 0
🧹 Nitpick comments (3)
src/sr_od/app/sim_uni/sim_uni_app.py (3)

67-68: 修复未使用的循环变量

循环变量 mrl 未在循环体内使用,应重命名为 _mrl_ 以表明这是有意忽略的变量。

应用此 diff:

-        for ocr_result, mrl in ocr_result_map.items():
+        for ocr_result, _mrl in ocr_result_map.items():
             count_14000 += ocr_result.count('14000')

148-153: 修复未使用的循环变量

循环变量 i 未在循环体内使用。如果此循环仅用于重试,建议使用 _ 作为循环变量名以表明其未被使用。

应用此 diff:

-        if self.ctx.sim_uni_config.only_period_reward:
-            for i in range(30):
+        if self.ctx.sim_uni_config.only_period_reward:
+            for _ in range(30):
                 period_reward = self._check_period_reward()

179-179: 修正注释中的全角逗号

注释中使用了全角逗号 ,应改为半角逗号 ,

应用此 diff:

-                pass  # 不写入任何内容,仅清空
+                pass  # 不写入任何内容, 仅清空
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e146c9f and ab3b8e9.

📒 Files selected for processing (3)
  • assets/game_data/screen_info/sim_uni.yml (7 hunks)
  • src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (2 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (1)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/sr_od/app/sim_uni/sim_uni_app.py (8)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • period_reward_complete (96-101)
  • period_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (2)
  • get_sim_uni_initial_screen_state (208-233)
  • ScreenState (16-38)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
🪛 Ruff (0.13.1)
src/sr_od/app/sim_uni/sim_uni_app.py

67-67: Loop control variable mrl not used within loop body

Rename unused mrl to _mrl

(B007)


148-148: Loop control variable i not used within loop body

(B007)


179-179: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

🔇 Additional comments (7)
src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (1)

42-42: 确认 node_from(..., success=True)_check_reward 返回 SUCCESS 行为匹配,逻辑正确。

src/sr_od/app/sim_uni/sim_uni_app.py (2)

115-116: 差分宇宙状态判断逻辑正确

当配置为差分宇宙 (WORLD_X) 时正确地重写状态为 SIM_TYPE_X,使后续流程能正确路由到差分宇宙自动化节点。


122-140: 传送逻辑正确实现了差分宇宙和普通宇宙的分支

根据配置正确地分支到差分宇宙或普通宇宙的传送逻辑,两个分支都使用了一致的模式(获取分类、任务、执行传送),实现合理。

assets/game_data/screen_info/sim_uni.yml (4)

33-46: 检查文本字段的一致性

该区域的 text 字段设置为 "14000/14000 (其实没用)"lcs_percent 为 1.0,但注释暗示文本实际上未被使用。在 _check_period_reward 方法中,该区域用于 OCR 识别 "14000" 字符串。

建议:

  • 如果文本字段确实未用于匹配,应设置为空字符串 '' 并将 lcs_percent 改为 0.5(与其他类似区域一致)
  • 或者移除注释 "(其实没用)" 并设置更通用的文本模式

117-130: 差分宇宙返回按钮定义合理

新增的差分宇宙返回按钮复用了大世界返回按钮的模板 (ui_icon_10),但使用了不同的坐标区域以适配差分宇宙界面的布局,实现合理。


215-228: 差分宇宙返回主界面按钮定义正确

新增的返回主界面按钮区域定义合理,使用文本匹配 "返回主界面" 来识别按钮位置。

注意: AI 摘要提到可能存在重复条目,但在提供的代码中只看到一个定义。


10-10: 坐标调整看起来合理

对现有区域的坐标进行了微调:

  • 每周奖励红点 (line 10)
  • 退出对话框-确认 (line 165)
  • 楼层类型 (line 178)
  • 左上角标题 (line 316)

这些调整通常基于实际测试和屏幕识别的优化,在没有异常报告的情况下应该是合理的。

Also applies to: 165-165, 178-178, 316-316

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/sr_od/app/sim_uni/sim_uni_app.py (3)

156-190: 【已标记但未修复】必须在启动插件前验证路径存在性

此问题在之前的审查中已被标记为 Major 级别,但尚未修复。根据 PR 描述,用户需要手动下载 Auto_Simulated_Universe 插件,因此必须验证插件目录和脚本文件的存在性,否则会导致进程崩溃。

应用以下修复添加存在性检查:

         work_dir = os_utils.get_work_dir()
         plugin_path = os.path.join(work_dir, *['plugins', 'Auto_Simulated_Universe'])
+        script_file = os.path.join(plugin_path, 'diver.py')
+        
+        if not os.path.exists(plugin_path):
+            return self.round_fail(f'差分宇宙插件目录不存在: {plugin_path}')
+        if not os.path.exists(script_file):
+            return self.round_fail(f'差分宇宙脚本不存在: {script_file}')

         # 使用自身的 python 环境启动脚本
         script_config = ScriptConfig(
             script_path=self.ctx.python_service.env_config.python_path,
-            script_arguments=os.path.join(plugin_path, 'diver.py'),
+            script_arguments=script_file,
             script_working_directory=plugin_path,

同时验证 info.yml 配置文件的存在性:

         # 如果没有此用户的配置文件, 则复制默认配置文件到用户文件夹中; 默认 info.yml 存在
         plugin_config_file_path = os.path.join(plugin_path, 'info.yml')
+        if not os.path.exists(plugin_config_file_path):
+            return self.round_fail(f'差分宇宙配置文件不存在: {plugin_config_file_path}')
         if not os.path.exists(config_file_path):
             shutil.copy(plugin_config_file_path, config_file_path)

根据之前的审查意见


205-207: 【已标记但未修复】添加文件读取的错误处理

此问题在之前的审查中已被标记,但尚未修复。Lines 205-206 直接读取文件并转换为整数,如果文件不存在、为空或包含非数字内容,程序将崩溃。

应用以下修复添加异常处理:

             # 进程退出, 检查运行情况
-            with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
-                completed_num = int(file.readline())
+            try:
+                with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
+                    line = file.readline().strip()
+                    completed_num = int(line) if line else 0
+            except (ValueError, FileNotFoundError, OSError) as e:
+                log.error(f'读取运行结果文件失败: {e}')
+                completed_num = 0

根据之前的审查意见


192-203: 【已标记但未修复】修复重试循环逻辑

此问题在之前的审查中已被标记,但尚未修复。在 Python 的 for 循环中,修改循环变量 i 不会影响下一次迭代,因此 Lines 197 和 202 的 i -= 1 无效,暂停状态仍会消耗重试次数。

应用以下修复使用 while 循环正确处理重试:

         # 运行脚本, 重试次数 = 3
-        for i in range(3):
+        retry_count = 0
+        max_retries = 3
+        while retry_count < max_retries:
             if self.ctx.context_running_state == ContextRunStateEnum.STOP:
                 break
             elif self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
                 time.sleep(1)
-                i -= 1
                 continue
+            retry_count += 1
             run_script(script_config, self.ctx)
             if self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
                 time.sleep(1)
-                i -= 1
+                continue

根据之前的审查意见

🧹 Nitpick comments (4)
src/sr_od/app/sim_uni/sim_uni_app.py (4)

67-68: 移除未使用的循环变量

循环变量 mrl 未被使用。根据静态分析工具建议,应重命名为 _mrl 或使用 _ 来表示有意忽略。

-        for ocr_result, mrl in ocr_result_map.items():
+        for ocr_result, _ in ocr_result_map.items():
             count_14000 += ocr_result.count('14000')

107-107: 清理注释掉的代码

Line 107 包含被注释掉的 BackToNormalWorldPlus 调用。如果不再需要,建议删除以保持代码整洁。

-        # BackToNormalWorldPlus(self.ctx).execute()
-
         screen = self.screenshot()

147-153: 修复周期奖励检查的循环逻辑

循环变量 i 未被使用(静态分析提示),且循环次数固定为 30,这意味着如果 OCR 持续返回 RETRY,将执行 30 次后才会 break。这可能不是预期行为。

建议明确重试策略:

         if self.ctx.sim_uni_config.only_period_reward:
-            for i in range(30):
+            max_retries = 30
+            for _ in range(max_retries):
                 period_reward = self._check_period_reward()
                 if period_reward.result == OperationRoundResultEnum.SUCCESS:
                     return self.round_by_op_result(self.op_success("成功"))
                 if period_reward.result == OperationRoundResultEnum.FAIL:
                     break

179-179: 修正注释中的全角逗号

Line 179 的注释包含全角逗号(,),应改为半角逗号(,)。

-                pass  # 不写入任何内容,仅清空
+                pass  # 不写入任何内容, 仅清空
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab3b8e9 and 40bd685.

📒 Files selected for processing (1)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/sr_od/app/sim_uni/sim_uni_app.py (12)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (1)
  • SimUniClaimWeeklyReward (10-47)
src/one_dragon/base/screen/screen_utils.py (1)
  • ocr (96-136)
src/one_dragon/base/operation/operation.py (6)
  • ocr (894-913)
  • screenshot (477-484)
  • round_retry (558-569)
  • round_success (532-543)
  • round_fail (571-582)
  • round_by_op_result (598-616)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • period_reward_complete (96-101)
  • period_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (2)
  • get_sim_uni_initial_screen_state (208-233)
  • ScreenState (16-38)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • weekly_uni_num (56-61)
  • weekly_uni_num (64-65)
  • only_period_reward (88-93)
  • only_period_reward (96-97)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
🪛 Ruff (0.13.1)
src/sr_od/app/sim_uni/sim_uni_app.py

67-67: Loop control variable mrl not used within loop body

Rename unused mrl to _mrl

(B007)


148-148: Loop control variable i not used within loop body

(B007)


179-179: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

🔇 Additional comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

120-140: 验证传送操作的执行结果

当前代码执行 GuideTransport 但忽略其结果(Lines 130、138 注释掉了 return self.round_by_op_result(op.execute()))。如果传送失败,方法仍然返回成功,这可能导致后续节点在错误状态下执行。

建议验证传送失败的影响。如果传送必须成功才能继续,应恢复结果检查:

             op = GuideTransport(self.ctx, mission)
-            op.execute()
-            # return self.round_by_op_result(op.execute())
-            state = sim_uni_screen_state.ScreenState.SIM_TYPE_X.value
-            return self.round_success(state)
+            op_result = op.execute()
+            if not op_result.success:
+                return self.round_by_op_result(op_result)
+            return self.round_success(sim_uni_screen_state.ScreenState.SIM_TYPE_X.value)

相同修改应应用于 Line 137-140 的普通宇宙分支。


173-173: 验证提前调用 BackToNormalWorldPlus 的必要性

在启动外部脚本前调用 BackToNormalWorldPlus(self.ctx).execute() 似乎不寻常。通常该操作用于清理和返回大世界,但此时尚未执行任何可能导致状态异常的操作。

请确认:

  1. 在此处调用 BackToNormalWorldPlus 的目的是什么?
  2. 是否应该在脚本执行失败后才调用(如 Lines 213-214 所做的那样)?

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (1)

48-61: 参考之前的审查评论

此方法的错误处理和文件检查问题已在之前的审查中详细标注,请参考处理。

🧹 Nitpick comments (7)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (1)

68-95: 用户体验建议

差分宇宙配置的 UI 设计合理,正确使用了 PushSettingCard 和 SwitchSettingCard 组件。从 PR 目标可知,作者已意识到当前实现需要手动下载插件,更适合技术用户。

考虑在未来版本中提供以下改进以降低使用门槛:

  • 添加插件检测逻辑,在插件缺失时显示友好提示
  • 提供一键下载/安装功能
  • 在启动器中集成插件管理
assets/game_data/screen_info/sim_uni.yml (4)

117-130: 新增“差分宇宙返回按钮”与现有模板一致,建议复用公共逻辑

与“大世界返回按钮”同模板 ui_icon_10,OK。为减少维护成本,考虑抽取为统一“返回按钮”识别,按场景切换不同 rect,避免两处配置漂移。


162-166: “退出对话框-确认”区域高度异常扩大,可能是误改,易引入误识别

y2 由 ~697 提升到 1097,远超常见确认按钮高度范围,可能覆盖到下方文案或其他按钮,增加误触/误识别风险。请确认是否误将 697 改成了 1097;若属误改,建议恢复:

-  - 1097
+  - 697

若确因界面变化需要扩大区域,请附截图说明,并尽量收窄仅覆盖按钮本体。


176-179: “楼层类型”识别区域过宽,建议收窄以降低噪声

x2 扩至 420 可能引入多余元素(图标/装饰文本),降低OCR稳定性。建议基于样例截图收窄到仅覆盖“楼层类型”文字区域,必要时分平台/分分辨率配置。


215-228: “差分宇宙返回主界面”仅依赖OCR,建议增加模板兜底

当前仅 text: 返回主界面 + lcs 0.5。为应对字体/阴影/语言包差异,建议补充模板匹配(若有可用资源),或添加同义多文案(例如本地化变体)以提高稳健性。

src/sr_od/app/sim_uni/sim_uni_app.py (2)

103-118: 建议移除注释代码。

Line 107 的 BackToNormalWorldPlus 调用已被注释,建议根据实际需求决定是否保留或删除。差分宇宙路由逻辑正确。

如不需要此调用,应用以下修复:

     @node_from(from_name='检查运行次数')
     @node_from(from_name='调用差分宇宙自动化', success=False)
     @operation_node(name='识别初始画面')
     def _check_initial_screen(self) -> OperationRoundResult:
-        # BackToNormalWorldPlus(self.ctx).execute()
-
         screen = self.screenshot()
         state = sim_uni_screen_state.get_sim_uni_initial_screen_state(self.ctx, screen)

120-140: 移除注释代码并考虑简化重复逻辑。

Lines 130 和 138 的注释 return 语句应删除。此外,两个分支存在重复的 GuideTransport 调用模式,可考虑提取公共逻辑。

应用以下修复移除注释:

         if self.ctx.sim_uni_config.weekly_uni_num == 'WORLD_X':
             category = self.ctx.guide_data.best_match_category_by_name(gt('差分宇宙', 'game'), tab)
             mission = self.ctx.guide_data.best_match_mission_by_name('前往参与', category)
             op = GuideTransport(self.ctx, mission)
             op.execute()
-            # return self.round_by_op_result(op.execute())
             state = sim_uni_screen_state.ScreenState.SIM_TYPE_X.value
             return self.round_success(state)
         else:
             category = self.ctx.guide_data.best_match_category_by_name(gt('模拟宇宙', 'game'), tab)
             mission = self.ctx.guide_data.best_match_mission_by_name('模拟宇宙', category)
             op = GuideTransport(self.ctx, mission)
             op.execute()
-            # return self.round_by_op_result(op.execute())
             state = sim_uni_screen_state.ScreenState.SIM_TYPE_NORMAL.value
             return self.round_success(state)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40bd685 and 7dcfd2b.

📒 Files selected for processing (5)
  • assets/game_data/screen_info/sim_uni.yml (7 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
  • src/sr_od/app/sim_uni/sim_uni_config.py (2 hunks)
  • src/sr_od/app/sim_uni/sim_uni_run_record.py (3 hunks)
  • src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/sr_od/app/sim_uni/sim_uni_run_record.py
  • src/sr_od/app/sim_uni/sim_uni_config.py
🧰 Additional context used
🧬 Code graph analysis (2)
src/sr_od/app/sim_uni/sim_uni_app.py (8)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (2)
  • get_sim_uni_initial_screen_state (208-233)
  • ScreenState (16-38)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (6)
src/one_dragon_qt/widgets/column.py (1)
  • Column (5-25)
src/one_dragon_qt/widgets/setting_card/push_setting_card.py (1)
  • PushSettingCard (14-41)
src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (1)
  • SwitchSettingCard (15-69)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
  • only_points_reward (88-93)
  • only_points_reward (96-97)
  • only_points_reward_adapter (100-101)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
🪛 Ruff (0.13.3)
src/sr_od/app/sim_uni/sim_uni_app.py

65-65: Loop control variable mrl not used within loop body

Rename unused mrl to _mrl

(B007)


148-148: Loop control variable i not used within loop body

(B007)


179-179: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py

46-46: subprocess call: check for execution of untrusted input

(S603)

🔇 Additional comments (5)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (1)

97-120: UI 重构合理

将现有设置卡片重新组织到 SettingCardGroup 中提高了界面的可读性。排除 WORLD_X 的逻辑正确,因为差分宇宙不参与常规挑战配置。

assets/game_data/screen_info/sim_uni.yml (2)

10-10: 坐标微调需多分辨率/DPI回归验证

pc_rect 第3项从之前值改为 420。请在 16:9/16:10、100%/125%/150% DPI 下核验红点识别稳定性,避免误检/漏检。


316-316: 左上角标题左边界调整,需确认不截断首字符

左边界改为 50。请在不同分辨率下核验标题完整截取,避免首字被裁切导致OCR失败。

src/sr_od/app/sim_uni/sim_uni_app.py (2)

1-14: 导入声明正确。

新增的导入项均已在代码中使用,符合功能需求。


217-218: 节点路由配置正确。

节点注解已正确更新以支持差分宇宙流程,与新增的操作节点正确集成。

Also applies to: 293-293

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/one_dragon/base/screen/screen_utils.py (1)

59-62: 循环变量未使用

mrl 未被实际使用,可改成 _ 以消除噪音并便于静态检查。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7dcfd2b and acd1e43.

📒 Files selected for processing (1)
  • src/one_dragon/base/screen/screen_utils.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/one_dragon/base/screen/screen_utils.py (6)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResultList (45-121)
src/one_dragon/base/screen/screen_area.py (4)
  • is_text_area (93-98)
  • is_template_area (101-106)
  • rect (36-37)
  • ScreenArea (8-139)
src/one_dragon/utils/cv2_utils.py (1)
  • crop_image_only (595-603)
src/one_dragon/base/matcher/template_matcher.py (1)
  • match_template (17-51)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • OneDragonContext (56-251)
src/one_dragon/base/screen/screen_loader.py (1)
  • get_area (87-93)
🪛 Ruff (0.13.3)
src/one_dragon/base/screen/screen_utils.py

59-59: Loop control variable mrl not used within loop body

(B007)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/sr_od/app/sim_uni/sim_uni_app.py (1)

61-87: 必须修复 OCR 错误处理和逻辑缺陷。

此方法存在之前审查中已标记但尚未修复的关键问题:

  1. 缺少 OCR 错误处理: ocr 调用可能返回 None 或空结果,但代码未处理此情况。Line 71 的循环会因 ocr_result_mapNone 而崩溃。
  2. 逻辑错误: Line 78-80 当 count_14000 == 1 时返回 FAIL,但这表示奖励未完成(如 "7000/14000"),应返回 RETRY 以便继续执行差分宇宙自动化。

应用以下修复:

 def _check_points_reward(self) -> OperationRoundResult:
     last_count_14000 = -1
     # 默认设置找不到 14000 返回重试
     result = self.round_retry('未找到积分奖励', wait=0.2)
     # 识别到两次一致的结果就退出循环
     for _ in range(10):
         ocr_result_map = self.ocr(self.ctx.controller.screenshot(), '模拟宇宙', '差分宇宙-积分奖励')
+        if not ocr_result_map:
+            continue

         count_14000 = 0
         for ocr_result, _mrl in ocr_result_map.items():
             count_14000 += ocr_result.count('14000')
         if last_count_14000 != count_14000:
             last_count_14000 = count_14000
             time.sleep(1)
             continue

         if count_14000 == 1:
             # 只有一个 14000
-            result = self.round_fail('未打满积分奖励')
+            result = self.round_retry('未打满积分奖励', wait=1)
         elif count_14000 == 2:
             # 如果周计划未完成, 设置为已完成
             if not self.ctx.sim_uni_record.points_reward_complete:
                 self.ctx.sim_uni_record.points_reward_complete = True
             result = self.round_success('已打满积分奖励')
         break
     return result
🧹 Nitpick comments (3)
src/one_dragon/base/screen/screen_utils.py (1)

66-67: 建议移除注释掉的调试代码。

虽然注释掉的调试代码不会影响功能,但为了保持代码整洁,建议在合并前移除这些 cv2.imwrite 调试语句(包括 line 123 和 line 150 的类似代码)。

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (1)

53-72: 可选: 增强用户反馈机制

错误处理已经很完善,包含了源文件检查、目标目录创建和异常捕获。不过成功消息目前仅输出到日志,建议考虑在 UI 上显示操作结果提示(如消息框或状态栏通知),以改善用户体验。

关于第 71 行捕获宽泛的 Exception:虽然静态分析工具标记了此处,但在 UI 文件操作场景中捕获所有异常是合理的防御性做法。如果希望更精确,可改为捕获 OSError,但这不是必需的。

src/sr_od/app/sim_uni/sim_uni_app.py (1)

220-229: 建议捕获更广泛的 OSError 异常。

当前代码仅捕获 ValueErrorFileNotFoundError,虽然这些是最可能的错误,但建议也捕获 OSError 以处理其他潜在的文件系统错误(如权限错误等)。

应用此 diff 增强错误处理:

             # 进程退出, 检查运行情况
             for _ in range(3):
                 try:
                     with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
                         line = file.readline().strip()
                         completed_num = int(line) if line else 0
                     break
-                except (ValueError, FileNotFoundError) as e:
+                except (ValueError, OSError) as e:
                     log.error(f'读取运行结果文件失败: {e}')
                     completed_num = 0
                     time.sleep(5)

注: FileNotFoundErrorOSError 的子类,使用 OSError 可以捕获更多文件系统相关错误。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between acd1e43 and b0f3fb6.

📒 Files selected for processing (7)
  • src/one_dragon/base/operation/operation.py (1 hunks)
  • src/one_dragon/base/screen/screen_utils.py (5 hunks)
  • src/sr_od/app/sim_uni/operations/bless/bless_utils.py (4 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
  • src/sr_od/app/sim_uni/sim_uni_config.py (2 hunks)
  • src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (4 hunks)
  • src/sr_od/operations/enter_game/enter_game.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/one_dragon/base/operation/operation.py
  • src/sr_od/operations/enter_game/enter_game.py
🧰 Additional context used
🧬 Code graph analysis (5)
src/sr_od/app/sim_uni/sim_uni_app.py (9)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/one_dragon/base/operation/operation.py (6)
  • round_retry (558-569)
  • ocr (894-906)
  • screenshot (477-484)
  • round_fail (571-582)
  • round_success (532-543)
  • round_by_op_result (598-616)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • weekly_uni_num (56-61)
  • weekly_uni_num (64-65)
  • only_points_reward (88-93)
  • only_points_reward (96-97)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
src/one_dragon/base/config/yaml_operator.py (2)
  • get (90-91)
  • update (93-100)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
src/one_dragon_qt/widgets/setting_card/yaml_config_adapter.py (1)
  • YamlConfigAdapter (6-39)
src/one_dragon/base/screen/screen_utils.py (8)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResultList (45-121)
src/one_dragon/base/matcher/ocr/ocr_matcher.py (2)
  • ocr (47-60)
  • run_ocr (36-45)
src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py (2)
  • ocr (257-301)
  • run_ocr (156-192)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • OneDragonContext (56-251)
src/one_dragon/base/screen/screen_area.py (4)
  • ScreenArea (8-139)
  • is_text_area (93-98)
  • rect (36-37)
  • left_top (44-45)
src/one_dragon/base/screen/screen_loader.py (1)
  • get_area (87-93)
src/one_dragon/base/matcher/ocr/ocr_service.py (1)
  • get_ocr_result_map (194-222)
src/one_dragon/utils/cv2_utils.py (2)
  • crop_image_only (595-603)
  • dilate (606-616)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (7)
src/one_dragon_qt/widgets/column.py (1)
  • Column (5-25)
src/one_dragon_qt/widgets/setting_card/push_setting_card.py (1)
  • PushSettingCard (14-41)
src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (1)
  • SwitchSettingCard (15-69)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/one_dragon/envs/env_config.py (2)
  • python_path (108-112)
  • python_path (115-122)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
  • only_points_reward (88-93)
  • only_points_reward (96-97)
  • only_points_reward_adapter (100-101)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
src/sr_od/app/sim_uni/operations/bless/bless_utils.py (2)
src/one_dragon/base/screen/screen_area.py (4)
  • x1 (48-49)
  • y1 (56-57)
  • x2 (52-53)
  • y2 (60-61)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResult (7-42)
🪛 Ruff (0.13.3)
src/sr_od/app/sim_uni/sim_uni_config.py

90-90: Docstring contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF002)


90-90: Docstring contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF002)

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py

51-51: subprocess call: check for execution of untrusted input

(S603)


71-71: Do not catch blind exception: Exception

(BLE001)

src/sr_od/app/sim_uni/operations/bless/bless_utils.py

113-113: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

🔇 Additional comments (8)
src/one_dragon/base/screen/screen_utils.py (4)

8-8: LGTM!

新增的 MatchResultList 导入是必需的,用于支持新添加的 OCR 函数签名。


57-57: LGTM!

重构为调用 ocr_in_screen 提高了代码复用性,且新函数已正确处理坐标偏移。


76-86: LGTM!

新增的公共函数 ocr 提供了便捷的 API 入口,通过区域名称获取配置后委托给 ocr_in_screen 处理,设计合理。


89-127: 已解决先前审查意见,实现正确!

新增的 ocr_in_screen 函数正确实现了区域 OCR 功能:

  1. 缓存路径(lines 100-105):委托给 ocr_service.get_ocr_result_map,该服务内部处理坐标偏移
  2. 非缓存路径(lines 106-121):
    • 裁剪图像到指定区域
    • 根据配置应用颜色掩码
    • 执行 OCR
    • 关键修复: lines 120-121 正确添加了区域偏移量,解决了先前审查中标记的坐标偏移问题

这确保了缓存和非缓存路径返回的坐标都是相对于完整屏幕的全局坐标,调用方可以直接用于点击操作。

基于先前的审查意见。

src/sr_od/app/sim_uni/operations/bless/bless_utils.py (3)

192-196: LGTM!已正确添加属性检查

通过 hasattr 检查避免了在非 SimUniBless 对象上访问 .level.path 属性导致的 AttributeError,解决了之前评审中指出的问题。

基于之前的评审反馈。


210-214: LGTM!属性检查一致

第二优先级列表中同样添加了属性检查,与第一优先级的处理保持一致。


226-230: LGTM!兜底逻辑的属性检查正确

在兜底分支中仅检查 .level 属性即可,因为该分支不访问 .path。逻辑正确。

基于之前的评审反馈。

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (1)

84-88: 功能成熟度提示

TODO 注释表明插件的自动下载和更新机制尚未实现。同时,第 88 行的 content 中硬编码了路径 plugins/Auto_Simulated_Universe,如果未来路径结构调整,需要手动更新此处的文本。

根据 PR 目标描述,作者提到"当前代码更适合懂编程的用户",这与 TODO 注释一致。建议在后续迭代中考虑:

  1. 实现插件的自动下载/更新机制
  2. 将路径等配置项提取为常量以便统一维护
  3. 将详细的使用说明移至文档,UI 中仅保留简要提示

JoshCai233 and others added 3 commits October 12, 2025 23:15
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (1)

83-110: 修正 region 注释的位置。

第 110 行的 # endregion 注释位置正确,但第 135 行的 # endregion 注释似乎放错位置了。第 135 行应该是第二个 region(模拟宇宙配置)的结束位置,而不是第一个 region 的结束。

建议调整为:

         self.save_auto_simulated_universe_settings.clicked.connect(self._on_save_auto_simulated_universe_settings_clicked)
         group_x.addSettingCard(self.save_auto_simulated_universe_settings)
-        # endregion
+        # endregion 差分宇宙配置
 
-        # region 模拟宇宙
+        # region 模拟宇宙配置

然后在第 131 行之后(self.challenge_opt_list[i.value.idx] = challenge_opt 后)添加:

        # endregion 模拟宇宙配置

并移除第 135 行的 # endregion

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0f3fb6 and e0719ad.

📒 Files selected for processing (2)
  • src/sr_od/app/sim_uni/sim_uni_config.py (2 hunks)
  • src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (6)
src/one_dragon_qt/widgets/setting_card/push_setting_card.py (1)
  • PushSettingCard (14-41)
src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (1)
  • SwitchSettingCard (15-69)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/one_dragon/envs/env_config.py (2)
  • python_path (108-112)
  • python_path (115-122)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
  • only_points_reward (88-92)
  • only_points_reward (102-103)
  • only_points_reward_adapter (106-107)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
src/sr_od/app/sim_uni/sim_uni_config.py (3)
src/one_dragon/base/config/yaml_operator.py (2)
  • get (90-91)
  • update (93-100)
src/sr_od/app/sim_uni/sim_uni_const.py (1)
  • SimUniWorldEnum (42-54)
src/one_dragon_qt/widgets/setting_card/yaml_config_adapter.py (1)
  • YamlConfigAdapter (6-39)
🪛 Ruff (0.13.3)
src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py

51-51: subprocess call: check for execution of untrusted input

(S603)


53-53: Do not catch blind exception: Exception

(BLE001)


74-74: Do not catch blind exception: Exception

(BLE001)

src/sr_od/app/sim_uni/sim_uni_config.py

93-93: unindent does not match any outer indentation level

(invalid-syntax)


94-94: Unexpected indentation

(invalid-syntax)


94-94: Expected a statement

(invalid-syntax)


94-94: Expected a statement

(invalid-syntax)


94-95: Expected a statement

(invalid-syntax)


99-99: Unexpected indentation

(invalid-syntax)

🔇 Additional comments (6)
src/sr_od/app/sim_uni/sim_uni_config.py (3)

51-53: LGTM!

新增的 sim_uni_100 属性遵循了现有的命名模式和实现方式,与差分宇宙(WORLD_X)的定义相匹配。


61-61: LGTM!

将每周挑战宇宙的默认值更新为 WORLD_X.name(差分宇宙)是合理的变更,与本次 PR 引入的新功能保持一致。属性和适配器的默认值也保持了同步。

Also applies to: 69-69


101-107: LGTM!

setter 和 adapter 的实现正确,参数类型与属性返回类型保持一致(bool)。在修复属性定义的语法错误后,这部分代码可以正常工作。

src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py (3)

1-4: 导入模块恰当。

新增的导入模块(os、shutil、subprocess)均为新功能所需,使用标准库和项目现有工具模块,符合最佳实践。


56-75: 配置保存逻辑完善。

此方法正确处理了源文件检查、目标目录创建和错误日志记录,异常处理适合 UI 代码场景。实现符合之前审查建议。


156-158: 适配器初始化正确。

only_points_reward 开关的适配器初始化逻辑正确,与其他配置项保持一致。

Comment on lines +87 to +91
# todo 如何扔进启动器里/自动下载/更新, 以及下载之后放哪
self.auto_simulated_universe_settings = PushSettingCard(
icon=FluentIcon.APPLICATION,
title='配置Auto_Simulated_Universe',
content='需要先去github下载该项目放到 plugins/Auto_Simulated_Universe文件夹中',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

澄清插件部署方式。

第 91 行提示用户需要手动下载项目并放置到 plugins/Auto_Simulated_Universe 目录。但根据 PR 描述,Auto_Simulated_Universe 项目源码已经被放入仓库路径。请确认:

  1. 插件代码是否已包含在此 PR 中?
  2. 如果是,此提示信息应更新为引导用户如何配置而非下载。
  3. 如果否,TODO 注释(第 87 行)提到的自动下载/更新机制是否有计划实现?

运行以下脚本检查插件目录是否已存在于仓库中:


🏁 Script executed:

#!/bin/bash
# 检查 Auto_Simulated_Universe 插件是否存在于仓库中

# 查找插件目录
fd -t d "Auto_Simulated_Universe" plugins/

# 如果存在,列出其主要文件
if [ -d "plugins/Auto_Simulated_Universe" ]; then
    echo "插件目录存在,主要文件:"
    ls -la plugins/Auto_Simulated_Universe/ | head -20
else
    echo "插件目录不存在于仓库中"
fi

Length of output: 107


澄清插件部署方式
仓库中未包含 plugins/Auto_Simulated_Universe 目录:

  • 若插件源码应随仓库发布,请将其添加至该目录,并更新第91行提示,引导用户完成配置;
  • 若继续依赖手动下载,请保留下载说明,并在第87行 TODO 中说明是否及何时实现自动下载/更新机制。
🤖 Prompt for AI Agents
In src/sr_od/gui/interface/sim_uni/sim_uni_setting_interface.py around lines 87
to 91, clarify how the Auto_Simulated_Universe plugin is deployed: either add
the plugin source into the repository under plugins/Auto_Simulated_Universe and
update the title/content text on line 91 to instruct users that the plugin is
bundled and where to find it, or keep the manual-download message and update the
TODO on line 87 to state that automatic download/update is not yet implemented
and indicate when/if it will be added; make the chosen behavior explicit in both
the comment and the displayed content so users know whether they must download
the plugin themselves or it comes with the repo.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

184-184: 建议检查返回大世界操作的结果。

Line 184 的 BackToNormalWorldPlus(self.ctx).execute() 未检查返回结果。如果返回大世界失败,后续的插件执行可能在错误状态下进行。

建议记录失败情况:

-        BackToNormalWorldPlus(self.ctx).execute()
+        op_result = BackToNormalWorldPlus(self.ctx).execute()
+        if not op_result.success:
+            log.warning(f'返回大世界失败: {op_result.status}')

196-196: 修正注释中的标点符号。

注释使用了全角逗号和分号,应改为半角标点以保持一致性。

-        # 如果没有此用户的配置文件, 则复制默认配置文件到用户文件夹中; 默认 info.yml 存在
+        # 如果没有此用户的配置文件,则复制默认配置文件到用户文件夹中;默认 info.yml 存在
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b164bb8 and dd7a4b9.

📒 Files selected for processing (1)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/sr_od/app/sim_uni/sim_uni_app.py (10)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (2)
  • get_sim_uni_initial_screen_state (208-233)
  • ScreenState (16-38)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • weekly_uni_num (56-61)
  • weekly_uni_num (64-65)
  • only_points_reward (88-93)
  • only_points_reward (96-97)
src/sr_od/interastral_peace_guide/guide_transport.py (1)
  • GuideTransport (14-55)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
🔇 Additional comments (3)
src/sr_od/app/sim_uni/sim_uni_app.py (3)

1-14: 导入语句正确支持新功能。

新增的导入语句(ContextRunStateEnumScriptConfigrun_script 等)正确支持差分宇宙外部脚本执行功能。


135-150: 验证忽略传送操作结果的合理性。

Lines 139 和 147 调用了 op.execute() 但未检查返回结果(原 return 语句已注释)。如果传送失败,错误将被忽略,可能导致后续逻辑在错误的状态下执行。

请确认这是预期行为。如果传送可能失败,建议至少记录错误日志:

op_result = op.execute()
if not op_result.success:
    log.warning(f'传送失败: {op_result.status}')

152-238: 之前审查中标记的关键问题已修复。

此代码段已正确修复了之前审查中标记的多个关键问题:

  1. ✅ 已添加插件目录和脚本文件存在性检查(Lines 165-168)
  2. ✅ 已添加配置文件存在性检查(Lines 198-199)
  3. ✅ 重试逻辑已改用 while 循环和独立计数器(Lines 205-217)
  4. ✅ 文件读取已添加异常处理(Lines 220-229)

这些修复有效解决了之前的进程崩溃风险和逻辑缺陷。

# Conflicts:
#	src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py
#	src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py
#	src/sr_od/interastral_peace_guide/guide_transport.py
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)

137-137: 更新错误消息以反映新的匹配逻辑。

错误消息仍显示"匹配失败 传送/进入",但现在匹配逻辑已包含 "前往参与"。建议更新为更完整的提示信息。

应用此 diff 以修复:

-            log.error('匹配失败 传送/进入')
+            log.error('匹配失败 前往参与/传送/进入')
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd7a4b9 and 66d085a.

📒 Files selected for processing (5)
  • assets/game_data/interastral_peace_guide_data.yml (1 hunks)
  • assets/game_data/screen_info/challenge_mission.yml (1 hunks)
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (1 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py (1 hunks)
  • src/sr_od/interastral_peace_guide/guide_transport.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • assets/game_data/interastral_peace_guide_data.yml
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py
  • src/sr_od/interastral_peace_guide/guide_transport.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)
src/one_dragon/utils/i18_utils.py (1)
  • gt (50-61)
🔇 Additional comments (1)
assets/game_data/screen_info/challenge_mission.yml (1)

47-60: 请说明"支援按钮"坐标调整的原因与验证。

第 50-52 行的坐标范围从 [1740, 720, 1830, 750] 更改为 [1740, 700, 1850, 750](Y 轴向上移动 20px,X 轴右侧扩展 20px)。

请澄清以下问题:

  • 此调整是否为游戏 UI 更新导致的位置修正?
  • 该坐标是否已在实际环境中验证并确保正确识别按钮区域?
  • 此变更与 PR 中的"差分宇宙"集成是否相关?

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66d085a and 0f871b8.

⛔ Files ignored due to path filters (2)
  • assets/template/guide/simulated_universe/mask.png is excluded by !**/*.png
  • assets/template/guide/simulated_universe/raw.png is excluded by !**/*.png
📒 Files selected for processing (4)
  • assets/game_data/interastral_peace_guide_data.yml (1 hunks)
  • assets/game_data/screen_info/guide.yml (2 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/app/sim_uni/sim_uni_app.py
🧬 Code graph analysis (2)
src/sr_od/app/sim_uni/sim_uni_app.py (8)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/one_dragon/base/operation/operation.py (7)
  • round_retry (558-569)
  • ocr (894-906)
  • screenshot (477-484)
  • round_fail (571-582)
  • round_success (532-543)
  • execute (277-355)
  • round_by_op_result (598-616)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
  • add_elite_times (119-126)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)
src/one_dragon/utils/i18_utils.py (1)
  • gt (50-61)
🔇 Additional comments (2)
assets/game_data/interastral_peace_guide_data.yml (1)

555-558: 删除残留的“前往模拟宇宙”任务条目

差分宇宙 分类下的任务列表仍包含 前往模拟宇宙。该按钮在新版本界面已由 前往参与 取代,运行时 GuideChooseMission 会按 mission_name 匹配不到文本而直接失败,阻塞这一任务。请移除或改名这一残留项,避免误选后无法传送。

-        - mission_name: "前往模拟宇宙"
-          display_name: "前往模拟宇宙"
-          show_in_power_plan: true
-          power: 0
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)

131-138: 补全日志文案涵盖“前往参与”

新增匹配顺序首尝试“前往参与”,但失败日志仍写“匹配失败 传送/进入”,调试时看不到首个关键词,信息不准确。建议把报错更新为“匹配失败 前往参与/传送/进入”。

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/sr_od/app/sim_uni/sim_uni_app.py (1)

113-128: 建议移除注释掉的代码。

Line 117 的 BackToNormalWorldPlus 调用被注释掉了。如果确定不再需要,请移除此行以保持代码整洁。

差分宇宙的路由逻辑(lines 125-126)正确。

应用此 diff 移除注释代码:

-        # BackToNormalWorldPlus(self.ctx).execute()
-
         screen = self.screenshot()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f871b8 and 7cfb2fd.

📒 Files selected for processing (3)
  • assets/game_data/interastral_peace_guide_data.yml (1 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (4 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • assets/game_data/interastral_peace_guide_data.yml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/app/sim_uni/sim_uni_app.py
🧬 Code graph analysis (2)
src/sr_od/app/sim_uni/sim_uni_app.py (9)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (28-32)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-276)
src/one_dragon/base/operation/operation.py (6)
  • round_retry (558-569)
  • ocr (894-906)
  • screenshot (477-484)
  • round_fail (571-582)
  • round_success (532-543)
  • round_by_op_result (598-616)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
  • add_elite_times (119-126)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • weekly_uni_num (56-61)
  • weekly_uni_num (64-65)
  • only_points_reward (88-93)
  • only_points_reward (96-97)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/operations/back_to_normal_world_plus.py (1)
  • BackToNormalWorldPlus (15-161)
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)
src/one_dragon/utils/i18_utils.py (1)
  • gt (50-61)
🔇 Additional comments (7)
src/sr_od/interastral_peace_guide/guide_choose_mission.py (1)

131-137: 差分宇宙按钮优先匹配处理得当

先匹配“前往参与”再回退到“传送/进入”,既满足新场景,又保持旧逻辑兼容;日志同步覆盖三种候选项也方便排错。

src/sr_od/app/sim_uni/sim_uni_app.py (6)

1-14: 导入语句合理。

新增的导入(shutil, time, ContextRunStateEnum, OperationRoundResultEnum, os_utils, ScriptConfig, run_script)都在后续的 _execute_sim_universe_x 方法中被正确使用。


61-87: 积分奖励检测逻辑正确。

根据之前的澄清,此处的 FAIL 语义表示"奖励未完成,需要继续执行差分宇宙自动化",SUCCESSRETRY 表示"提前返回,跳过自动化"。当前实现:

  • 使用稳定检测模式(连续两次识别结果一致才退出,lines 73-76),避免OCR抖动
  • count_14000 == 1 返回 FAIL 以继续自动化流程,符合预期
  • OCR 返回空字典时循环会继续重试,逻辑正确

根据检索到的学习记录(Based on learnings)。


130-149: 传送逻辑已修复并正确实现。

之前的审查意见已得到修复:

  • Lines 146-149 现在正确检查 op_result.success,失败时立即返回,避免在错误状态下继续执行
  • 差分宇宙和普通模拟宇宙的路由分支清晰合理

151-183: 验证在脚本执行前调用 BackToNormalWorldPlus 的必要性。

Line 183 在运行差分宇宙脚本前调用 BackToNormalWorldPlus(self.ctx).execute()。这可能是为了确保在干净的状态下启动脚本,但也可能导致不必要的导航(如果已经处于正确状态)。

请验证:

  1. 此调用是否必要(脚本是否要求特定的初始状态)
  2. 如果传送失败是否需要检查返回值

另外,Lines 164-167 和 Lines 170-182 的文件/目录存在性检查以及 ScriptConfig 配置都很合理,正确修复了之前审查中标记的问题。


239-256: 节点路由更新正确。

Line 240 添加了从 传送 节点且状态为 SIM_TYPE_NORMAL 时的路由,与差分宇宙的路由逻辑互补,正确实现了两种模式的分支。


314-319: 奖励领取路由正确整合差分宇宙流程。

Line 315 添加的路由确保差分宇宙自动化成功完成后正确进入每周奖励领取流程,流程闭环合理。

# Conflicts:
#	assets/game_data/interastral_peace_guide_data.yml
#	src/one_dragon/base/screen/screen_utils.py
#	src/sr_od/app/sim_uni/sim_uni_app.py
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/sr_od/interastral_peace_guide/guide_transport.py (1)

70-74: 注释与代码逻辑存在潜在冲突

Line 70 的注释说明"模拟宇宙的cate是差分宇宙",但在 Line 50-51 已对所有 cate.cn == '差分宇宙' 的情况提前返回。这使得 Line 71-72 的 mission_name == '前往模拟宇宙' 检查对于 '差分宇宙' 分类的任务变成不可达代码。

建议:

  1. 如果 Line 50-51 的提前返回已经覆盖了所有差分宇宙场景,请更新或移除 Line 70 的注释以避免混淆
  2. 如果 '前往模拟宇宙' 任务不属于 '差分宇宙' 分类,请明确注释说明两者的关系
♻️ Duplicate comments (3)
assets/game_data/screen_info/sim_uni.yml (1)

33-46: ⚠️ [重复问题] OCR配置过于严格且含注释文本,"打满14000即停"逻辑易失效

这是之前审查中指出的问题,当前仍未修复:

  • text 含注释"14000/14000 (其实没用)" 包含实现备注,OCR 难以完全匹配
  • lcs_percent=1.0 不现实:要求完全相同的字符串,在不同字体/抗锯齿下会频繁失效,导致判断逻辑失灵
  • 忽视动态进度:玩家每周奖励进度会动态变化(e.g. 13720/14000),不应依赖精确字符串匹配

建议方案(2选1):

轻量修复(放宽匹配,去掉无关文案):

- text: 14000/14000 (其实没用)
- lcs_percent: 1.0
+ text: ''
+ lcs_percent: 0.5

然后在业务代码侧解析该截图区域的数字,用正则 (\d{3,5})/14000 提取进度数字,比较数值而非字符串。

稳健方案(代码侧自主解析):
保持 text: ''lcs_percent: 0.5,由后端代码负责截取该 pc_rect 区域并用OCR提取数字,避免前端YAML配置过度绑定UI文本。

src/one_dragon/base/operation/operation.py (1)

1101-1113: Operation.ocr 的返回文档与实际类型不一致,需要同步

这里类型标注是 dict[str, MatchResultList],实现也直接返回 screen_utils.ocr 的结果 map,但 docstring 仍写成 OperationRoundResult,容易误导调用方和静态检查。

建议同步更新 docstring 的返回说明,例如:

     def ocr(self, screen: MatLike, screen_name: str, area_name: str) -> dict[str, MatchResultList]:
-        """在区域内使用OCR。
-
-        Args:
-            screen: 截图图像。
-            screen_name: 屏幕名称。
-            area_name: 区域名称。
-
-        Returns:
-            OperationRoundResult: 匹配结果。
-        """
-
-        return screen_utils.ocr(ctx=self.ctx, screen=screen, screen_name=screen_name, area_name=area_name)
+        """在指定画面区域执行 OCR,并返回识别结果映射。
+
+        Args:
+            screen: 截图图像。
+            screen_name: 屏幕名称。
+            area_name: 区域名称。
+
+        Returns:
+            dict[str, MatchResultList]: key 为识别文本,value 为对应的匹配结果列表。
+        """
+
+        return screen_utils.ocr(ctx=self.ctx, screen=screen, screen_name=screen_name, area_name=area_name)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (1)

133-134: 0.15 阈值过低导致误判风险(已在历史评审中标记)

Line 133 将 lcs_percent_threshold 设置为 0.15,仅需 15% 的相似度即可匹配成功,极易产生误判。历史评审已明确指出此问题。

参考仓库中其他位置:

  • Line 190 的 in_sim_uni_choose_bless 使用 0.55
  • Line 129, 136, 139 等处使用 0.51

必须将阈值提高到至少 0.3-0.5(建议与 Line 190 保持一致使用 0.55),或提供配置选项并在真实 OCR 样本上进行回归测试。

基于历史评审意见,应用以下修改:

-    if bless and str_utils.find_best_match_by_lcs(ScreenState.SIM_BLESS.value, titles, lcs_percent_threshold=0.15) is not None:
+    if bless and str_utils.find_best_match_by_lcs(ScreenState.SIM_BLESS.value, titles, lcs_percent_threshold=0.55) is not None:
🧹 Nitpick comments (2)
src/one_dragon/base/screen/screen_utils.py (2)

60-62: 新 OCR 入口 ocr/ocr_in_screen 逻辑正确,修复了坐标偏移问题

  • find_area_in_screen 文本区域分支改为调用 ocr_in_screen,复用同一套 OCR 流程,减少了重复代码,行为清晰。
  • ocr_in_screen 在非缓存路径下先裁剪子图,再对每个 MatchResultList 调用 add_offset(rect.left_top),补上区域偏移,这点很好地解决了之前“子图坐标系”导致点击偏移的问题。
  • 顶层 ocr(ctx, screen, screen_name, area_name) 简化了按画面/区域进行 OCR 的调用方式,和 Operation.ocr 的封装也保持一致。

可以作为小改进的是:ocr_in_screenarea 允许为 None,现在的注解是 area: ScreenArea,可以考虑改为 area: ScreenArea | None(或 Optional[ScreenArea])以匹配 (area is None) 的防御逻辑,但这只是类型层面的可选优化。

Also applies to: 81-133


71-72: 硬编码调试路径建议后续考虑配置化或统一调试开关

两处注释里的路径(例如 "y:/screen.png""y:/part.png")目前是硬编码的盘符和文件名,虽然现在是注释不会执行,但如果以后为排查问题临时打开,很容易忘记关或在非 Windows 环境/无该盘符环境下出错。后续如果需要长期保留这类输出,建议走统一的调试开关和可配置输出目录。

Also applies to: 155-156

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cfb2fd and bb4f074.

📒 Files selected for processing (7)
  • assets/game_data/screen_info/challenge_mission.yml (1 hunks)
  • assets/game_data/screen_info/sim_uni.yml (7 hunks)
  • src/one_dragon/base/operation/operation.py (1 hunks)
  • src/one_dragon/base/screen/screen_utils.py (6 hunks)
  • src/sr_od/app/sim_uni/sim_uni_screen_state.py (5 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py (1 hunks)
  • src/sr_od/interastral_peace_guide/guide_transport.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/interastral_peace_guide/guide_transport.py
🧬 Code graph analysis (4)
src/sr_od/interastral_peace_guide/guide_transport.py (1)
src/one_dragon/base/operation/operation.py (1)
  • round_by_op_result (766-787)
src/one_dragon/base/operation/operation.py (5)
src/one_dragon/base/screen/screen_utils.py (1)
  • ocr (81-91)
src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py (1)
  • ocr (327-371)
src/one_dragon/base/matcher/ocr/ocr_matcher.py (1)
  • ocr (47-60)
src/onnxocr/onnx_paddleocr.py (1)
  • ocr (28-61)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResultList (45-121)
src/one_dragon/base/screen/screen_utils.py (8)
src/one_dragon/base/matcher/match_result.py (1)
  • MatchResultList (45-121)
src/one_dragon/base/geometry/rectangle.py (3)
  • area (52-57)
  • add_offset (45-49)
  • left_top (30-31)
src/one_dragon/base/matcher/ocr/onnx_ocr_matcher.py (2)
  • ocr (327-371)
  • run_ocr (209-255)
src/one_dragon/base/matcher/ocr/ocr_matcher.py (2)
  • ocr (47-60)
  • run_ocr (36-45)
src/one_dragon/base/screen/screen_area.py (4)
  • ScreenArea (8-143)
  • is_text_area (97-102)
  • rect (36-37)
  • left_top (44-45)
src/one_dragon/base/screen/screen_loader.py (1)
  • get_area (87-93)
src/one_dragon/envs/env_config.py (2)
  • ocr_cache (472-477)
  • ocr_cache (480-481)
src/one_dragon/base/matcher/ocr/ocr_service.py (1)
  • get_ocr_result_map (186-214)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (1)
src/one_dragon/utils/str_utils.py (1)
  • find_best_match_by_lcs (107-130)
🔇 Additional comments (12)
assets/game_data/screen_info/challenge_mission.yml (2)

75-88: AI摘要与实际代码坐标不一致。

AI摘要声称坐标从 [1740, 720, 1830, 750] 变更为 [700, 1850, 750, ...],但根据代码标记,实际的新坐标应为 [1740, 700, 1850, 750]。摘要的坐标描述不完整或不准确。

具体变更:

  • Y1: 720 → 700(上移20像素)
  • X2: 1830 → 1850(宽度增加20像素)
  • X1 和 Y2 保持不变

77-81: 请验证"支援按钮"的屏幕坐标是否正确。

本次修改调整了支援按钮的检测区域边界。虽然坐标形成了有效的矩形区域(x1 < x2,y1 < y2),但需要确认这些新坐标是否与游戏的当前UI布局相匹配,以确保自动化脚本能够正确识别并点击该按钮。

建议通过以下方式验证:

  • 在游戏中截屏确认支援按钮的实际位置
  • 验证新坐标 [1740, 700, 1850, 750] 是否包含整个支援按钮
  • 检查该变更是否因游戏UI更新而必要
assets/game_data/screen_info/sim_uni.yml (3)

10-10: 验证较大幅度的坐标调整是否经过游戏测试 ``

多处区域坐标进行了显著调整(特别是第 165 行 y 坐标从 651 → 1097),建议确认:

  1. 这些改动是否对应游戏 UI 实际变化(版本更新、分辨率改动等)
  2. 是否在不同分辨率和游戏设置下进行过验证
  3. 相关的UI定位逻辑是否已在实际游戏中测试通过

建议在合并前补充截图或测试记录,确保这些坐标在目标游戏版本中仍然准确。

Also applies to: 165-165, 178-178, 316-316


117-130: 新增"差分宇宙返回按钮"区域配置合理 ``

区域配置采用模板匹配(template_id: ui_icon_10)而非文本匹配,搭配中等宽松度 lcs_percent: 0.5,相比纯OCR方案更鲁棒。与"大世界返回按钮"的微小坐标差异(pc_rect 偏移)符合游戏UI差异预期。


215-228: 新增"差分宇宙返回主界面"区域配置稳健 ``

文本匹配配置相对清晰(无多余注释),lcs_percent: 0.5 允许合理的字体/渲染差异容限,区域大小和位置合理。

src/one_dragon/base/screen/screen_utils.py (1)

317-325: find_by_ocr 返回条件简化为 to_click is not None 合理

这里直接用 return to_click is not None 表达“是否找到目标文本”,与上方循环逻辑一致,语义更直观,行为上等价于原先的布尔标记实现,没有功能性问题。

src/sr_od/app/sim_uni/sim_uni_screen_state.py (5)

24-24: 新增差分宇宙类型枚举

正确添加了 SIM_TYPE_X 枚举以支持差分宇宙,符合 PR 目标。


53-53: 改用 LCS 匹配提升一致性

将楼层类型识别改为使用 find_best_match_by_lcs,与文件中其他识别逻辑保持一致,这是一个合理的重构。


119-124: 正确添加了差分宇宙状态检测

新增了 sim_uni_x_idxsim_uni_x_gold_idx 的检测,并在 Line 124 的条件判断中正确包含了这些新索引。实现逻辑正确,符合差分宇宙支持的需求。


193-200: 注释掉的奇物选择函数与其他变更一致

in_sim_uni_choose_curio 函数被注释掉,与 Line 33 注释掉 SIM_CURIOS 枚举以及 Line 142-144 注释掉奇物检测逻辑保持一致。整体变更方向统一:将奇物选择合并到通用的"选择"状态中。


27-33: Verify downstream compatibility when merging selection states

The change consolidates distinct selection scenarios (blessing, equation, curios) into a single SIM_BLESS = '选择' state. Confirm that:

  1. All code consuming get_sim_uni_screen_state() can handle the merged '选择' state without needing to distinguish between selection types
  2. Commented curio-related code (lines 142-144, 193-200) has no active references
src/sr_od/interastral_peace_guide/guide_transport.py (1)

50-51: Unable to verify due to repository access failure

The repository could not be cloned for verification. Cannot confirm or refute whether the early return at lines 50-51 bypasses wait logic or impacts downstream operations. Unable to verify if GuideTransport callers depend on wait_at_last behavior or if this creates actual runtime issues.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/sr_od/app/sim_uni/sim_uni_app.py (1)

203-233: 暂停后跳过结果检查仍会导致脚本重复执行,且文件读取异常类型略少

当前重试循环:

while retry_count < max_retries:
    if self.ctx.context_running_state == ContextRunStateEnum.STOP:
        break
    elif self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
        time.sleep(1)
        continue
    run_script(script_config, self.ctx)
    if self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
        time.sleep(1)
        continue
    retry_count += 1

    # 进程退出, 检查运行情况
    for _ in range(3):
        try:
            with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
                ...
        except (ValueError, FileNotFoundError) as e:
            ...

存在两个问题(之前审查已提到,本次实现仍然保留):

  1. 脚本结束后 PAUSE 会跳过结果检查并导致重复执行

    • 如果 run_script 正常跑完、插件按预期写入了 notif.txt,但用户此时点了暂停,代码会在 Lines 213-215 直接 continue 回到循环顶部,不会读取结果文件,也不会增加 retry_count
    • 解除暂停后循环会再次执行 run_script,造成脚本重复跑、且上一轮“已完成”的结果被完全忽略。
  2. 文件读取只捕获 ValueErrorFileNotFoundError,未涵盖一般性的 OSError

    • 如权限问题、路径异常等会抛出 OSError,目前不会被捕获,仍有崩溃风险(虽然概率不高)。

建议按之前的思路小幅调整循环结构:

@@
-        while retry_count < max_retries:
-            if self.ctx.context_running_state == ContextRunStateEnum.STOP:
-                break
-            elif self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
-                time.sleep(1)
-                continue
-            run_script(script_config, self.ctx)
-            if self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
-                time.sleep(1)
-                continue
-            retry_count += 1
+        while retry_count < max_retries:
+            if self.ctx.context_running_state == ContextRunStateEnum.STOP:
+                break
+            elif self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
+                time.sleep(1)
+                continue
+            retry_count += 1
+            run_script(script_config, self.ctx)

@@
-            for _ in range(3):
-                try:
-                    with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
-                        line = file.readline().strip()
-                        completed_num = int(line) if line else 0
-                    break
-                except (ValueError, FileNotFoundError) as e:
+            for _ in range(3):
+                try:
+                    with open(plugin_run_result_path, 'r', encoding='utf-8') as file:
+                        line = file.readline().strip()
+                        completed_num = int(line) if line else 0
+                    break
+                except (ValueError, FileNotFoundError, OSError) as e:
                     log.error(f'读取运行结果文件失败: {e}')
                     completed_num = 0
                     time.sleep(5)

这样可以保证:

  • 每一次实际执行脚本后都会跑一次结果检查,不会因为用户在脚本刚结束时按下暂停就丢失该轮结果;
  • 暂停只会阻止“开始新一轮执行”,而不会跳过结果判定;
  • 文件读写的异常覆盖面更完整。
🧹 Nitpick comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

61-87: 积分奖励检测逻辑与特殊 FAIL 语义是自洽的

这里通过两次稳定 OCR 结果确认积分状态,count_14000 为 0/1/2 分别对应“未找到 / 进行中 / 已打满”,并且:

  • 默认 result = round_retry('未找到积分奖励'),当一直识别不到或噪声较大时会以 RETRY 结束;
  • count_14000 == 1 时返回 round_fail('未打满积分奖励'),结合调用方 if points_reward.result != OperationRoundResultEnum.FAIL: return points_reward 的约定,确实表示“奖励未满,需要继续执行差分宇宙自动化”;
  • count_14000 == 2 时设置 points_reward_complete = True 并返回 SUCCESS,用于“提前返回、去领奖或直接结束”。

整体实现和上层状态机约定是一致的,没有明显逻辑 Bug。若后续想进一步增强鲁棒性,可以考虑在循环结束仍为默认 RETRY 时打一次日志,方便排查 OCR 长时间不稳定的问题(可选)。Based on learnings, FAIL/SUCCESS/RETRY 语义在此处已按约定正确使用。


155-160: 建议在 only_points_reward 分支显式注释 FAIL 的“继续打”语义

only_points_reward 分支通过:

points_reward = self._check_points_reward()
if points_reward.result != OperationRoundResultEnum.FAIL:
    return points_reward

FAIL 解释为“积分未打满,需要继续执行差分宇宙自动化”,而 SUCCESS/RETRY 则意味着“提前返回、跳过脚本”。这与上游约定是正确的,但和框架其它地方对 FAIL=“出错/终止”的直觉相反,后续维护者不看调用栈会比较难理解。

建议在这里或 _check_points_reward 上方补一行说明性的注释,例如:

# 注意:在积分检测中 FAIL 表示“奖励未打满,继续执行差分宇宙自动化”

以免以后误改成 == SUCCESS 或误把 FAIL 当成异常处理。Based on learnings, 这里的 FAIL 语义确实是“继续打”,不是错误。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb4f074 and 63bab3b.

📒 Files selected for processing (1)
  • src/sr_od/app/sim_uni/sim_uni_app.py (5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/app/sim_uni/sim_uni_app.py
🧬 Code graph analysis (1)
src/sr_od/app/sim_uni/sim_uni_app.py (5)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (34-38)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-102)
src/one_dragon/base/screen/screen_utils.py (1)
  • ocr (81-91)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
🔇 Additional comments (4)
src/sr_od/app/sim_uni/sim_uni_app.py (4)

130-149: 传送结果现在正确向上游传播,避免异常状态下继续流程

transport() 中现在根据 weekly_uni_num 选择差分宇宙 / 普通模拟宇宙的目标任务,并且:

op = GuideTransport(self.ctx, mission)
op_result = op.execute()
if not op_result.success:
    return self.round_by_op_result(op_result)
return self.round_success(state)

这修复了之前“忽略传送失败而强行认为成功”的问题,一旦识别/传送失败会立刻通过 round_by_op_result 中断状态机,避免在错误前置画面上继续自动化,逻辑合理。


161-201: 插件路径与配置文件存在性校验已补齐

plugin_pathdiver.pyinfo.yml 都在运行前做了存在性检查,并且缺失时直接 round_fail(...) 返回,避免了直接 open/copy 导致的崩溃:

if not os.path.exists(plugin_path):
    return self.round_fail(...)
if not os.path.exists(script_file):
    return self.round_fail(...)
...
if not os.path.exists(plugin_config_file_path):
    return self.round_fail(...)

这基本覆盖了之前审查中提到的“必须在启动外部插件前校验目录/脚本/配置存在性”的需求,行为现在是安全的。


239-241: 普通模拟宇宙分支的节点绑定合理

新增的:

@node_from(from_name='传送', status=sim_uni_screen_state.ScreenState.SIM_TYPE_NORMAL.value)
@operation_node(name='选择宇宙')
def _choose_sim_uni_num(...)

让“传送到模拟宇宙入口(SIM_TYPE_NORMAL)”后显式进入选宇宙节点,与差分宇宙的 SIM_TYPE_X 分支形成对称,状态机结构清晰,没有发现逻辑问题。


314-316: 差分宇宙自动化成功后直接衔接每周奖励领取

通过:

@node_from(from_name='调用差分宇宙自动化', success=True)
@operation_node(name='领取每周奖励')
def check_reward_before_exit(...)

_execute_sim_universe_x 的 SUCCESS(即检测到 14000/14000 的场景)接到 SimUniClaimWeeklyReward,与 STATUS_TO_WEEKLY_REWARD 分支复用同一领取逻辑,设计干净也便于维护。

# Conflicts:
#	src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py
#	src/sr_od/app/sim_uni/operations/sim_uni_exit.py
#	src/sr_od/app/sim_uni/sim_uni_app.py
#	src/sr_od/interastral_peace_guide/guide_transport.py
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/sr_od/challenge_mission/use_trailblaze_power.py (1)

1-1: 移除未使用的导入以消除变量名遮蔽。

Line 1 的 from PIL.ImageChops import screen 导入未被使用,且与 Lines 110, 157, 211, 227 的局部变量 screen 重名,造成变量名遮蔽。

应用以下 diff 移除未使用的导入:

-from PIL.ImageChops import screen
 from typing import Optional, Callable, ClassVar
src/sr_od/operations/enter_game/enter_game.py (1)

119-148: 第 145 行使用 screenshot() 而非 last_screenshot 是正确的

在输入账号密码后(经过多次 time.sleep 和键盘输入操作),需要获取最新的屏幕状态来检测"同意"按钮和"进入游戏"按钮。此处使用 screenshot() 是正确的做法。

但请注意第 119 行使用了 last_screenshot,而该截图在后续的密码输入操作(第 121-134 行)后会变得过时。第 136-142 行仍在使用第 119 行的旧 screen 变量来检测"同意"按钮,这可能导致检测失败。

建议在检测"同意"按钮前刷新截图:

         time.sleep(1.5)

-        result = self.round_by_find_area(screen, '进入游戏', '文本-同意-旧')
+        screen = self.screenshot()
+        result = self.round_by_find_area(screen, '进入游戏', '文本-同意-旧')
         if result.is_success:
             self.round_by_click_area('进入游戏', '国服-同意按钮-旧')

         result = self.round_by_find_area(screen, '进入游戏', '文本-同意-新')
src/sr_od/app/sim_uni/operations/sim_uni_event.py (1)

232-233: @node_from(from_name='选择奇物') 引用了不存在的节点

第 232 行的 @node_from(from_name='选择奇物') 仍然引用了被注释掉的 _choose_curio 方法(原第 299 行)。这会导致:

  1. 如果有其他代码尝试通过"选择奇物"状态转换到"确定后判断",会因找不到源节点而失败
  2. _get_screen_state 检测到 SIM_CURIOS 状态时(第 257 行 curio=True),_check_after_confirm 会返回该状态,但没有对应的处理节点

建议:

  1. 移除第 232 行的 @node_from(from_name='选择奇物')
  2. 或者在 _get_screen_state 中将 curio=True 改为 curio=False 以避免检测奇物状态
 @node_from(from_name='丢弃祝福')
 @node_from(from_name='祝福强化')
-@node_from(from_name='选择奇物')
 @node_from(from_name='丢弃奇物')
 @node_from(from_name='点击空白处关闭')

Also applies to: 297-307

src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (1)

70-80: fast_back_to_world 场景下 choose_bless_time 可能为 None,存在运行时异常风险

本文件的逻辑有一个较隐蔽但会直接导致异常的问题:

  • handle_init 中将 self.choose_bless_time 初始化为 None

  • choose 方法里:

    • OCR 成功分支(if result.is_success:)直接 return self.round_success(...)choose_bless_time 赋值。
    • 只有 OCR 没识别到确认按钮、走到固定坐标点击的 fallback 分支时,才在 114 行设置了 self.choose_bless_time = time.time()
  • wait_not_in_bless 中,当 fast_back_to_world=True 且仍在祝福界面时,会执行:

    if sim_uni_screen_state.in_sim_uni_choose_bless(self.ctx, screen):
        if now - self.choose_bless_time >= 2:
            ...

如果本次选择祝福是通过 OCR 分支正常确认的(这是最常见情况),此时 choose_bless_time 仍为 Nonenow - self.choose_bless_time 会抛出 TypeError,一旦 fast_back_to_world 为真并且在调用 wait_not_in_bless 时还没离开祝福界面,就会直接炸掉。

建议在 OCR 成功分支也记录选择时间,修复方式示例(仅展示 choose 方法相关部分):

@@     def choose(self) -> OperationRoundResult:
-            result = self.round_by_ocr_and_click(
-                screen=screen,
-                target_cn='确认',
-            )
-            if result.is_success:
-                return self.round_success(status=result.status, wait=0.1)
+            result = self.round_by_ocr_and_click(
+                screen=screen,
+                target_cn='确认',
+            )
+            if result.is_success:
+                # 无论是否走 fallback,都需要记录选祝福的时间,供 fast_back_to_world 使用
+                self.choose_bless_time = time.time()
+                return self.round_success(status=result.status, wait=0.1)
@@
-            confirm_point = SimUniChooseBless.CONFIRM_BEFORE_LEVEL_BTN.center
-            log.info('选择祝福后未识别到确认 尝试固定位置点击 中间')
-            self.ctx.controller.click(confirm_point)
-            self.choose_bless_time = time.time()
-            return self.round_success(wait=0.1)
+            confirm_point = SimUniChooseBless.CONFIRM_BEFORE_LEVEL_BTN.center
+            log.info('选择祝福后未识别到确认 尝试固定位置点击 中间')
+            self.ctx.controller.click(confirm_point)
+            self.choose_bless_time = time.time()
+            return self.round_success(wait=0.1)

其他改动(改用 last_screenshot、以及“先点右下角再点中间”的固定坐标点击)本身逻辑清晰,能规避点到“查看已有方程”的问题,没有明显副作用;关键是要补上上面的时间记录,避免 fast_back_to_world 模式下出现异常。

Also applies to: 84-115, 147-168

src/sr_od/app/sim_uni/sim_uni_app.py (1)

92-111: 严重:存在不可达代码。

Line 94 的 return self.round_success() 导致后续代码(lines 95-111)永远不会被执行。这包括指定宇宙检查、异常次数检查和每日/每周精英次数检查等关键逻辑。

如果这是调试代码,请移除或添加条件判断;如果是有意为之,请删除后续无用代码。

     @operation_node(name='检查运行次数', is_start_node=True)
     def _check_times(self) -> OperationRoundResult:
         self.ctx.init_for_sim_uni()
-        return self.round_success()
         if self.specified_uni_num is not None:
             if self.get_reward_cnt < self.max_reward_to_get:
                 return self.round_success()
♻️ Duplicate comments (8)
src/sr_od/app/sim_uni/operations/event/sim_uni_reward.py (2)

88-101: 截图新鲜度验证(同上)

此处的更改与 _get_reward 方法相同,需要确保 last_screenshot 在节点执行时已更新到最新状态,以正确识别"点击空白处关闭"的画面(第 95 行)。


104-115: 截图新鲜度验证(同上)

此处的更改与前两个方法相同,需要确保状态检查时 last_screenshot 反映了当前实际画面,以正确判断是继续领取奖励还是退出(第 111 行)。

src/sr_od/operations/enter_game/enter_game.py (1)

94-96: 点击"文本-点击进入"后返回 round_success 可能导致操作提前结束

在非强制登录分支中,点击"文本-点击进入"后返回 round_success(result.status, wait=1)。由于"画面识别"节点可能没有针对此 status 的出边(@node_from),这会导致 EnterGame 操作直接结束,而非继续等待进入游戏。

建议改为 round_wait 以保持状态机循环,继续检测后续画面状态:

         else:
             result = self.round_by_find_and_click_area(screen, '进入游戏', '文本-点击进入')
             if result.is_success:
-                return self.round_success(result.status, wait=1)
+                return self.round_wait(result.status, wait=1)
src/script_chainer/win_exe/script_runner.py (2)

222-229: 使用字符串 'None' 作为哨兵值不够健壮。

使用 'None' 字符串判断是否使用 PID 检测方式容易出错。建议使用空字符串或实际的 None 值。此外,pid_status.get('alive') 可能返回 None(access_denied 情况),导致布尔逻辑混乱。

-        if script_config.script_process_name == 'None':
+        if not script_config.script_process_name or script_config.script_process_name == 'None':
             pid_status = is_pid_running(process.pid)
-            script_current_existed: bool = pid_status.get('alive') and pid_status.get('create_time') < subprocess_create_time + 5
+            alive = pid_status.get('alive')
+            create_time = pid_status.get('create_time', 0)
+            script_current_existed: bool = bool(alive) and (create_time < subprocess_create_time + 5)
         else:
             script_current_existed: bool = is_process_existed(script_config.script_process_name)

203-206: 严重:ctx 为 None 时会导致 AttributeError。

run_scriptctx 参数默认值为 None,但 lines 204-206 直接访问 ctx.context_running_state 而无空值检查。当 run() 函数调用 run_script(script_config) 时(line 297),未传入 ctx,会导致程序崩溃。

     while True:
-        if ((script_config.stop_chain_when_pause_pressed and ctx.context_running_state == ContextRunStateEnum.PAUSE)
-                or ctx.context_running_state == ContextRunStateEnum.STOP):
+        if ctx is not None and (
+            (script_config.stop_chain_when_pause_pressed and ctx.context_running_state == ContextRunStateEnum.PAUSE)
+            or ctx.context_running_state == ContextRunStateEnum.STOP
+        ):
             break
src/script_chainer/config/script_config.py (3)

117-131: 缺少字段:YAML 加载时未读取 stop_chain_when_pause_pressed 和 script_working_directory。

ScriptConfig 构造函数接受这两个参数,但从 YAML 加载时未读取它们,导致配置丢失。

             ScriptConfig(
                 script_path=i.get('script_path', ''),
                 script_process_name=i.get('script_process_name', ''),
                 game_process_name=i.get('game_process_name', ''),
                 run_timeout_seconds=i.get('run_timeout_seconds', 3600),
                 check_done=i.get('check_done', ''),
+                stop_chain_when_pause_pressed=i.get('stop_chain_when_pause_pressed', False),
                 kill_script_after_done=i.get('kill_script_after_done', True),
                 kill_game_after_done=i.get('kill_game_after_done', True),
                 script_arguments=i.get('script_arguments', ''),
                 notify_start=i.get('notify_start', True),
                 notify_done=i.get('notify_done', True),
+                script_working_directory=i.get('script_working_directory', None),
             )

142-160: 缺少字段:YAML 保存时未持久化 stop_chain_when_pause_pressed 和 script_working_directory。

保存时缺少这两个字段,编辑后无法落盘。

                 {
                     'script_path': i.script_path,
                     'script_process_name': i.script_process_name,
                     'game_process_name': i.game_process_name,
                     'run_timeout_seconds': i.run_timeout_seconds,
                     'check_done': i.check_done,
+                    'stop_chain_when_pause_pressed': i.stop_chain_when_pause_pressed,
                     'kill_script_after_done': i.kill_script_after_done,
                     'kill_game_after_done': i.kill_game_after_done,
                     'script_arguments': i.script_arguments,
                     'notify_start': i.notify_start,
                     'notify_done': i.notify_done,
+                    'script_working_directory': i.script_working_directory,
                 }

70-76: check_done_display_name 返回值类型错误。

当前返回 config.value(机器值如 game_closed),应返回 config.labelconfig.ui_text 以显示人类可读文案。

     @property
     def check_done_display_name(self) -> str:
         config = get_config_item_from_enum(CheckDoneMethods, self.check_done)
         if config is not None:
-            return config.value
+            return config.label
         else:
             return ''
🧹 Nitpick comments (25)
src/sr_od/challenge_mission/click_challenge.py (1)

24-27: 确认 last_screenshot 的刷新时机与空值兜底

这里从“即时截图”切到复用 self.last_screenshot,性能更好,但需要确认两点:

  1. last_screenshot 的刷新时机:
    当前节点执行前,是否一定有统一的截图流程更新了 last_screenshot?如果中间存在 UI 变化但未重新截图,这里可能会基于过期画面去点“挑战按钮”,造成误点或找不到按钮。

  2. 空值 / 异常兜底:
    如果在某些异常路径下 last_screenshot 仍为 None 或未初始化,下游 round_by_find_and_click_area 可能直接报错。可以考虑在本地兜底一次,例如:

-        screen = self.last_screenshot
+        screen = self.last_screenshot or self.screenshot()

这样既保持“正常路径下复用缓存截图”,又能在缓存缺失时自动补一张,避免整轮任务直接异常中断。

src/sr_od/interastral_peace_guide/guid_choose_tab.py (1)

28-40: 复用 last_screenshot 的改动没问题,建议增加空值兜底以提升健壮性

当前节点直接使用 self.last_screenshot,逻辑上没问题,也符合本 PR 在全局复用最近一帧截图的方向。但如果有调用路径在进入该节点前没有刷新 last_screenshot(或调试时直接单步进入该 Operation),这里可能拿到 None 或过期截图,导致识别失败或潜在异常(取决于下游函数对 None 的处理)。

可以在本处加一层兜底,既不影响已有“统一前置截图”的优化,又提高节点在独立复用/调试场景下的健壮性,例如:

-        screen = self.last_screenshot
+        screen = self.last_screenshot
+        if screen is None:
+            # 兜底:若上游未刷新 last_screenshot,则现场截图一次
+            screen = self.screenshot()

如果框架层能够严格保证每轮运行前都刷新 last_screenshot,则此修改可视为可选增强而非必需。

src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_mm.py (1)

63-75: 改用 last_screenshot 的前置约束需要再确认一下

这里从 self.screenshot() 改为直接使用 self.last_screenshot,在“统一复用 last_screenshot”这一大方向上是合理的,可以避免重复截屏、保证本轮操作使用同一帧画面。

但有两个点建议确认一下:

  • _execute_one_round 的所有调用路径上,是否已经由上层 runner/基类在本轮开始前必然刷新self.last_screenshot
    • 首次进入该节点、异常恢复后重进、长时间卡在别的操作后回来时,如果没有刷新,可能拿到 None 或过旧画面,导致:
      • is_normal_in_world 误判;
      • 小地图剪裁/分析失败或得到错误的敌人位置。
  • 是否需要在统一位置(例如 SrOperation 基类的某个入口)做一个兜底:
    • last_screenshot 为空则主动截一张,或加一个 debug 级别的断言日志,方便后续排查截屏链路问题。

如果当前架构已经保证“每轮必刷 last_screenshot”,那本改动可以直接接受;否则建议在那个公共入口补一层保护,避免此类节点在极端情况下吃到空 / 过期截图。

src/sr_od/operations/move/move_without_pos.py (1)

44-47: 使用 last_screenshot 的契约需要保证刷新时机,建议说明或做轻量防御

这里从“即时截图”切到复用 self.last_screenshot,整体思路(减少重复截图、与其他节点对齐)是 OK 的。不过有两个点建议确认一下:

  1. 进入 _turn 前是否在统一调度层强保证last_screenshot 已更新?如果存在直接调用该 Operation 的路径而未先刷新截图,cut_mini_map 可能拿到 None 或过期画面。
  2. 为了容错,可以考虑在这里做一个非常轻量的防御性兜底,例如在调度层保证失败时至少打日志/断言,或者在本方法中做显式检查:
-        screen = self.last_screenshot
+        screen = self.last_screenshot
+        # 可选:防御性兜底,避免 last_screenshot 为空时直接崩溃
+        if screen is None:
+            screen = self.screenshot()

如果项目已经在更高一层严格控制截图节奏,这里至少建议补一行注释说明“调用前必须先刷新 last_screenshot”,方便以后维护时不踩坑。

src/sr_od/challenge_mission/choose_challenge_times.py (1)

28-44: 确认 last_screenshot 的刷新时机,避免使用过期或空截图

choose() 现在直接用 self.last_screenshot,如果运行链路里没有在进入该节点前统一刷新截图,一旦:

  • last_screenshot 仍是上一个界面的画面,_get_current_times() 可能一直读出 0 导致反复重试,或读到错误次数;
  • last_screenshotNone,后续 crop_image_only / OCR 会直接异常。

如果运行器已经保证每轮都会先更新 last_screenshot 到当前“选择挑战次数”界面,那这里就没问题;否则建议加一个轻量兜底,例如:

     @operation_node(name='选择', node_max_retry_times=5, is_start_node=True)
     def choose(self) -> OperationRoundResult:
-        screen = self.last_screenshot
+        screen = self.last_screenshot
+        if screen is None:
+            # 仅在未拿到缓存截图时退回到主动截图
+            screen = self.screenshot()

可以根据你对全局截图策略的规划,决定是否需要这个兜底逻辑。

src/sr_od/operations/move/move_directly.py (1)

111-112: 明确截图策略:优先复用 last_screenshot,避免含糊 TODO

这里的 # todo 这一句是否有必要 本身信息量不大,而且从 PR 其它文件的改动来看,整体趋势是尽量复用本轮已获取的截图而不是处处重新 screenshot()

建议:

  1. 若上层调度已经在每轮统一更新 self.last_screenshot,这里可以改成“优先用 last_screenshot,不存在时再回退到重新截图”,并把 TODO 注释替换为说明性注释,例如:
-        # todo 这一句是否有必要
-        screen = self.screenshot()
+        # 优先复用本轮的 last_screenshot,如无则回退到重新截图
+        screen = self.last_screenshot
+        if screen is None:
+            screen = self.screenshot()
  1. 如果目前还无法保证有可用的 last_screenshot,那至少可以删掉或改写 TODO,说明为什么“此处仍需强制截图”(例如:作为起始节点,依赖自身截图,不走全局截图流程),避免以后读代码的人继续困惑。

整体来说属于风格与性能层面的优化,不是功能性 bug,可以在确认 Runner 行为后再决定是否改动实现。

src/sr_od/interastral_peace_guide/guide_check_power.py (1)

42-51: 确认 last_screenshot 生命周期,必要时增加兜底截图

这里直接使用 self.last_screenshot 作为识别输入,如果在某些调用路径下该字段尚未初始化或未在进入节点前刷新,有两类潜在问题:

  • None 时,get_power_and_qty(screen) 内部传给 OCR / cv2_utils.crop_image_only 会直接异常。
  • 不是当前页面的最新画面时,体力 / 沉浸器识别会偏离真实状态。

建议你确认当前运行器 / 装饰器在进入本节点前一定会刷新 last_screenshot;若存在不确定路径,可考虑在本处做一个轻量兜底,既不影响已有统一截图逻辑,又能防止极端路径直接崩溃,例如:

-        screen = self.last_screenshot
+        screen = self.last_screenshot
+        if screen is None:
+            # 兜底:在没有统一预截图时自行补一张
+            screen = self.screenshot()

这样当框架已统一刷新截图时不会多拍一张,只有在未设置的情况下才额外调用。

src/sr_od/operations/interact/catapult.py (1)

57-57: 在 Catapult.check_on_screen 上关闭前置截图是合理的小优化

这个节点内部已经在 time.sleep(3) 之后主动调用 self.screenshot() 获取当前画面,框架层的默认前置截图只会多拍一张完全没用到的图片。显式设为 screenshot_before_round=False 能减少一次截图 IO,不改变现有逻辑行为。

如果之后打算跟随本 PR 的整体策略,改为依赖 last_screenshot 而不在节点内主动截图,再记得一并检查这里的 screenshot_before_round 配置是否也需要调整即可。

src/sr_od/operations/interact/move_interact.py (1)

51-51: MoveInteract.check_screen 关闭前置截图与当前实现相符

check_screen 自己在短暂 sleep 之后调用 self.screenshot() 获取最新画面,再做 OCR 与交互尝试,框架默认的前置截图同样是完全没用上的。改为 screenshot_before_round=False 可以避免每轮多一次截图开销,尤其在多次 round_wait() 重试的场景下更省资源,逻辑行为不变。

如果后续希望进一步和本 PR 其它节点统一成“只用 last_screenshot,不在节点内部截图”,可以考虑把这里改成使用 last_screenshot 并在上游统一截图;那时再根据需要决定是否恢复默认的前置截图。

src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_interact_by_detect.py (1)

68-84: 使用 last_screenshot 的前提需要确认刷新时机

这里把 screen 改为 self.last_screenshot,和本 PR 其它改动保持了风格一致,从性能和一致性的角度没有问题。但这带来两个隐含前提,需要在框架层面保证:

  1. 在每一轮节点(包括 move)执行前,调度器一定已经刷新过 last_screenshot,且与当前输入状态匹配;
  2. 首次进入该节点时 last_screenshot 不会是 None,否则 _check_interact_word / sim_uni_yolo.run 等会在空对象上工作甚至直接抛异常。

建议你回顾一下 SrOperation / 运行器中截图更新的流程,确认上述前提始终成立。如果存在某些路径可能没有提前刷新截图,可以考虑在此处做一个轻量兜底,例如:

-        screen = self.last_screenshot
+        screen = self.last_screenshot
+        if screen is None:  # 可选兜底,视全局约定决定是否需要
+            screen = self.screenshot()

如果项目明确约定“进入任何节点前必然已刷新 last_screenshot”,则可以保持当前实现,只需在文档或基类注释中写清这一假设即可。

src/sr_od/app/div_uni/operations/choose_oe_file.py (1)

69-69: 正确设置 screenshot_before_round=False

该参数设置是正确的,因为方法在执行动作(点击存档)后才需要截图(第 87 行)。这避免了在方法开始时进行无用的截图。

可选建议:添加注释说明为何禁用自动截图,以提高代码可读性。

可应用以下改进增强可读性:

 @node_from(from_name='识别画面', status='左上角标题-存档管理')
 @node_from(from_name='等待存档管理画面')
-@operation_node(name='选择存档', screenshot_before_round=False)
+@operation_node(name='选择存档', screenshot_before_round=False)  # 点击后再截图,无需预截图
 def choose_file(self) -> OperationRoundResult:
src/sr_od/interastral_peace_guide/guide_choose_category.py (1)

29-36: 使用 last_screenshot 做状态判断时建议确认生命周期与兜底策略

这里从即时截屏切到 self.last_screenshot,逻辑上没问题,但有两个点建议确认一下:
1)wait_screen 是起始节点,如果本轮开始前没有统一更新 last_screenshot,这里可能拿到的是前一轮画面的截图或 None,从而误判是否在目标 UI;
2)当 skip_wait 为 True 时,其实不会用到 screen,可以考虑在 skip_wait 为 False 且需要真正判断时再读取,或在 last_screenshot 为空时按需补一张截图作为兜底。

如果运行框架已经保证“每轮节点执行前都会刷新 last_screenshot”,那当前实现可以保持,只是建议在注释或文档里说明这一点,方便以后维护者理解依赖关系。

src/sr_od/app/support_character/support_character_app.py (1)

38-44: 使用 last_screenshot 代替即时截图的前置条件需要确认

这里从即时 self.screenshot()(推测原实现)迁移到复用 self.last_screenshot,性能和一致性上是好事,但有两个前提需要确认:

  1. 生命周期 / 初始化:在进入 _click_ellipsis 节点前,框架是否必然已经更新过 self.last_screenshot?如果有可能为 None 或是上一个流程残留的旧图,这里会直接把“无图/旧图”传给 get_phone_menu_ellipsis_pos,行为会和之前“现拍一张”不同。
  2. 防御性处理(可选):如果基类仍保留 self.screenshot(),可以考虑在这里做一个兜底,既不破坏“统一由调度层刷图”的设计,又提升健壮性。例如:
-        screen = self.last_screenshot
+        screen = self.last_screenshot
+        if screen is None:
+            # 兜底:极端情况下仍保证有一张当前截图
+            screen = self.screenshot()

如果框架已经严格保证“每轮节点执行前都更新 last_screenshot”,可以只在文档/注释里说明这一约束;否则建议加类似兜底逻辑以减少偶发空图/旧图导致的误判。

src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)

19-30: SimUniExit 新增 is_in_x 与改用 last_screenshot 的实现总体合理

  • 构造函数增加 is_in_x 并在 click_empty 分支中点击 “差分宇宙返回主界面”,能很好地区分普通模拟宇宙与差分宇宙的结算流程;默认值为 False 也可以保证旧调用方不破坏。
  • check_screen / click_exit / click_confirm / click_empty 统一改用 self.last_screenshot,配合 @operation_node 默认的 screenshot_before_round=True,能减少重复截图,逻辑上与之前的逐次截图等价。

可以考虑的小改进:

  • __init__ 的 docstring 目前只写了 :param ctx:,建议顺手补充 :param is_in_x: 的含义(是否处于差分宇宙),方便后续维护者理解参数语义。

Also applies to: 39-40, 73-74, 93-95, 101-109

src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py (1)

185-209: 已弃用的 SIM_CURIOS 分支可以考虑从代码中移除

_check_after_confirm 中关于 SIM_CURIOS 的处理逻辑已经整体注释掉,注释上也说明“选择奇物合并到选择祝福中,并且固定选择第一项”。如果后续确实不再打算恢复该分支,建议:

  • 直接删除 200–208 行这段大块注释,改在类或方法注释中简要说明“奇物选择逻辑已合并到祝福选择”即可,避免误导后续维护者认为该逻辑还会回归。

这只是可读性层面的清理,不影响当前行为。

src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_elite_route_v2.py (1)

44-53: 精英路线中统一使用 last_screenshot 的改动是合理的

  • before_route / _check_red / _detect_reward 中通过 screen = self.last_screenshot 读取画面,配合 @operation_node 默认截图行为,可避免重复截图,YOLO 和小地图分析逻辑未改,行为保持一致。
  • _detect_reward 仍然在同一帧上做 YOLO 检测并依据结果返回不同的状态值,与原来的控制流匹配。

另外一点可留意(非必须修改):

  • _boss_exit 仍然构造 SimUniExit(self.ctx),如果未来需要在差分宇宙的精英层复用本路线,记得在调用处考虑传入 is_in_x=True,以便退出时走“差分宇宙返回主界面”的分支。

Also applies to: 63-72, 130-164, 220-228

src/sr_od/app/sim_uni/operations/bless/sim_uni_drop_bless.py (1)

56-70: 丢弃祝福指令改用 last_screenshot 整体安全,初始状态常量可顺带确认下

  • check_screen_state / choose_bless 改为从 self.last_screenshot 读取画面,结合 @operation_node 默认的 screenshot_before_round=True,每轮开始前都会自动刷新截图,和原来的显式截图行为等价且更高效。
  • 丢弃祝福的点击与确认流程本身未修改,round 结果与状态机逻辑保持不变。

顺带一个可检查但非本次改动引入的问题:

  • check_screen_state 在“跳过第一次画面检查”时返回的状态是 ScreenState.SIM_DROP_CURIOS.value(丢弃奇物),而本类语义是“丢弃祝福”。如果这是历史遗留的 copy-paste,可能更合适的是 SIM_DROP_BLESS(若枚举中存在)。建议你根据 sim_uni_screen_state 的定义确认一下该状态值是否刻意共享,如果只是笔误可顺路修正。

Also applies to: 71-85

src/sr_od/operations/back_to_normal_world_plus.py (1)

77-78: 注意:可能存在死代码。

SIM_CURIOS 分支被注释掉后,sim_uni_choose_curio 方法(lines 147-153)可能成为无用代码。如果确定不再需要此功能,建议一并移除相关方法和导入。

src/sr_od/app/sim_uni/sim_uni_app.py (3)

61-87: 建议添加 OCR 空结果防护。

根据之前的讨论,虽然 ocr 方法在失败时返回 {},但建议在迭代前显式检查,以提高代码健壮性和可读性。同时,基于已记录的学习内容,FAIL 在此处表示"奖励未完成,需要继续执行自动化"的语义是正确的。

         for _ in range(10):
             ocr_result_map = self.ocr(self.screenshot(), '模拟宇宙', '差分宇宙-积分奖励')
+            if not ocr_result_map:
+                time.sleep(1)
+                continue

             count_14000 = 0

117-118: 调试代码未清理。

BackToNormalWorldPlus(self.ctx).execute() 被注释掉,如果是调试用途请说明原因,否则建议删除注释代码。


155-159: 请确认注释代码的处理方式。

only_points_reward 的检查逻辑被注释掉。如果此功能已移除或计划在其他地方实现,请删除此注释代码;如果是暂时禁用,请添加 TODO 说明。

src/script_chainer/win_exe/script_runner.py (2)

21-52: 建议清理大量注释代码。

Lines 21-52 包含大量被注释掉的代码(Push 实例、logger 等)。如果不再需要,建议删除以提高代码可读性;如果计划恢复,请添加 TODO 说明。


96-103: print_message 中的 time.sleep 影响性能。

每次打印消息都会 sleep 0.1 秒,在频繁日志场景下会显著影响执行速度。请确认此延迟是否必要。

src/script_chainer/config/script_config.py (2)

78-105: invalid_message 属性缺少显式返回值。

当配置有效时,函数隐式返回 None。虽然调用方检查 if invalid_message is not None,但建议显式返回以提高代码清晰度。

         elif self.run_timeout_seconds <= 0:
             return '运行超时时间必须大于0'
+        return None

44-44: 类型提示建议使用显式 Optional。

PEP 484 建议使用显式的 Optional[str]str | None 而非隐式的 str = None

-                script_working_directory: str = None,
+                script_working_directory: str | None = None,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63bab3b and bc8c3c4.

📒 Files selected for processing (77)
  • src/script_chainer/config/script_config.py (1 hunks)
  • src/script_chainer/win_exe/script_runner.py (1 hunks)
  • src/sr_od/app/assignments/assignments_app.py (4 hunks)
  • src/sr_od/app/claim_email/email_app.py (2 hunks)
  • src/sr_od/app/daily_training/daily_training_app.py (1 hunks)
  • src/sr_od/app/div_uni/operations/choose_oe_file.py (3 hunks)
  • src/sr_od/app/div_uni/operations/choose_oe_support.py (3 hunks)
  • src/sr_od/app/div_uni/operations/ornamenet_extraction.py (4 hunks)
  • src/sr_od/app/echo_of_war/challenge_ehco_of_war.py (4 hunks)
  • src/sr_od/app/nameless_honor/nameless_honor_app.py (6 hunks)
  • src/sr_od/app/relic_salvage/relic_salvage_app.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/auto_run/reset_sim_uni_level.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_level.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_world.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/auto_run/sim_uni_wait_level_start.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/battle/sim_uni_fight_elite.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (4 hunks)
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_path.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_drop_bless.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/bless/sim_uni_upgrade_bless.py (5 hunks)
  • src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py (5 hunks)
  • src/sr_od/app/sim_uni/operations/entry/choose_sim_uni_diff.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/entry/choose_sim_uni_num.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/entry/sim_uni_start.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/event/sim_uni_reward.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/move_v1/move_to_next_level.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_detect.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_mm.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_interact_by_detect.py (1 hunks)
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_move_to_next_level_v3.py (7 hunks)
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_elite_route_v2.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_respite_route_v2.py (3 hunks)
  • src/sr_od/app/sim_uni/operations/sim_uni_enter_fight.py (2 hunks)
  • src/sr_od/app/sim_uni/operations/sim_uni_event.py (5 hunks)
  • src/sr_od/app/sim_uni/operations/sim_uni_exit.py (5 hunks)
  • src/sr_od/app/sim_uni/sim_uni_app.py (5 hunks)
  • src/sr_od/app/support_character/support_character_app.py (2 hunks)
  • src/sr_od/app/world_patrol/world_patrol_enter_fight.py (1 hunks)
  • src/sr_od/challenge_mission/choose_challenge_times.py (1 hunks)
  • src/sr_od/challenge_mission/choose_support_in_team.py (5 hunks)
  • src/sr_od/challenge_mission/click_challenge.py (1 hunks)
  • src/sr_od/challenge_mission/click_start_challenge.py (1 hunks)
  • src/sr_od/challenge_mission/use_trailblaze_power.py (4 hunks)
  • src/sr_od/interastral_peace_guide/guid_choose_tab.py (1 hunks)
  • src/sr_od/interastral_peace_guide/guide_check_power.py (1 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_category.py (2 hunks)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py (3 hunks)
  • src/sr_od/interastral_peace_guide/guide_transport.py (1 hunks)
  • src/sr_od/interastral_peace_guide/open_guide.py (2 hunks)
  • src/sr_od/operations/back_to_normal_world_plus.py (3 hunks)
  • src/sr_od/operations/battle/start_fight_for_elite.py (1 hunks)
  • src/sr_od/operations/cancel_mission_trace.py (1 hunks)
  • src/sr_od/operations/click_dialog_confirm.py (1 hunks)
  • src/sr_od/operations/enter_game/enter_game.py (4 hunks)
  • src/sr_od/operations/enter_game/switch_account.py (1 hunks)
  • src/sr_od/operations/interact/catapult.py (1 hunks)
  • src/sr_od/operations/interact/move_interact.py (1 hunks)
  • src/sr_od/operations/interact/talk_interact.py (1 hunks)
  • src/sr_od/operations/menu/click_phone_menu_item.py (1 hunks)
  • src/sr_od/operations/menu/open_phone_menu.py (1 hunks)
  • src/sr_od/operations/move/move_directly.py (1 hunks)
  • src/sr_od/operations/move/move_without_pos.py (1 hunks)
  • src/sr_od/operations/store/buy_store_item.py (4 hunks)
  • src/sr_od/operations/synthesize/synthesize.py (7 hunks)
  • src/sr_od/operations/team/check_team_members_in_world.py (1 hunks)
  • src/sr_od/operations/team/choose_support.py (3 hunks)
  • src/sr_od/operations/team/switch_member.py (1 hunks)
  • src/sr_od/operations/technique.py (8 hunks)
  • src/sr_od/operations/wait/wait_in_world.py (1 hunks)
  • src/sr_od/sr_map/operations/choose_floor.py (1 hunks)
  • src/sr_od/sr_map/operations/choose_planet.py (1 hunks)
  • src/sr_od/sr_map/operations/choose_region.py (3 hunks)
  • src/sr_od/sr_map/operations/choose_special_point.py (1 hunks)
  • src/sr_od/sr_map/operations/open_map.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/sr_od/interastral_peace_guide/guide_choose_mission.py
  • src/sr_od/app/sim_uni/operations/sim_uni_enter_fight.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/app/sim_uni/sim_uni_app.py
  • src/sr_od/interastral_peace_guide/guide_check_power.py
  • src/sr_od/app/echo_of_war/challenge_ehco_of_war.py
  • src/sr_od/app/sim_uni/operations/entry/choose_sim_uni_diff.py
  • src/sr_od/app/nameless_honor/nameless_honor_app.py
  • src/sr_od/operations/click_dialog_confirm.py
  • src/sr_od/app/relic_salvage/relic_salvage_app.py
  • src/sr_od/app/claim_email/email_app.py
  • src/sr_od/operations/interact/catapult.py
  • src/sr_od/challenge_mission/click_start_challenge.py
  • src/sr_od/app/sim_uni/operations/event/sim_uni_reward.py
  • src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py
  • src/sr_od/operations/technique.py
  • src/sr_od/sr_map/operations/choose_special_point.py
  • src/sr_od/operations/interact/move_interact.py
  • src/sr_od/challenge_mission/click_challenge.py
  • src/sr_od/operations/enter_game/switch_account.py
  • src/sr_od/app/assignments/assignments_app.py
  • src/sr_od/interastral_peace_guide/guide_transport.py
  • src/sr_od/app/daily_training/daily_training_app.py
  • src/sr_od/operations/wait/wait_in_world.py
  • src/sr_od/app/sim_uni/operations/entry/sim_uni_start.py
  • src/sr_od/operations/enter_game/enter_game.py
  • src/sr_od/challenge_mission/use_trailblaze_power.py
  • src/sr_od/operations/back_to_normal_world_plus.py
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.py
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py
  • src/sr_od/app/sim_uni/operations/sim_uni_exit.py
  • src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_elite_route_v2.py
  • src/sr_od/interastral_peace_guide/open_guide.py
🧬 Code graph analysis (17)
src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (1)
src/sr_od/operations/click_dialog_confirm.py (1)
  • click (25-28)
src/sr_od/app/sim_uni/sim_uni_app.py (5)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (34-38)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-104)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-277)
src/sr_od/app/sim_uni/sim_uni_run_record.py (3)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
  • add_elite_times (119-126)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
src/sr_od/app/relic_salvage/relic_salvage_app.py (1)
src/one_dragon/base/operation/operation.py (2)
  • round_by_find_and_click_area (789-857)
  • name (44-48)
src/sr_od/operations/interact/catapult.py (1)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (1)
src/one_dragon/base/operation/operation.py (2)
  • round_by_find_and_click_area (789-857)
  • status (51-55)
src/sr_od/operations/interact/move_interact.py (1)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/operations/enter_game/switch_account.py (1)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/app/assignments/assignments_app.py (1)
src/sr_od/app/claim_email/email_app.py (1)
  • _claim (55-58)
src/sr_od/interastral_peace_guide/guide_transport.py (1)
src/one_dragon/base/operation/operation.py (1)
  • round_by_op_result (766-787)
src/sr_od/operations/enter_game/enter_game.py (2)
src/one_dragon/base/operation/operation.py (2)
  • round_success (688-702)
  • status (51-55)
src/one_dragon/base/operation/operation_round_result.py (1)
  • OperationRoundResult (13-47)
src/sr_od/operations/back_to_normal_world_plus.py (2)
src/one_dragon/base/operation/operation.py (4)
  • round_by_find_area (859-883)
  • round_by_click_area (885-917)
  • round_wait (704-718)
  • status (51-55)
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)
  • SimUniExit (14-109)
src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_respite_route_v2.py (1)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.py (1)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py (1)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (5)
src/one_dragon/base/operation/operation.py (1)
  • round_by_find_and_click_area (789-857)
src/one_dragon/base/operation/operation_edge.py (1)
  • node_from (64-95)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_world.py (1)
  • click_empty (107-114)
src/one_dragon/base/operation/operation_round_result.py (1)
  • OperationRoundResult (13-47)
src/script_chainer/config/script_config.py (4)
src/one_dragon/base/config/config_item.py (2)
  • ConfigItem (7-25)
  • get_config_item_from_enum (28-41)
src/one_dragon/base/config/yaml_config.py (1)
  • YamlConfig (9-103)
src/one_dragon/base/config/yaml_operator.py (1)
  • get (90-91)
src/one_dragon/base/operation/operation.py (1)
  • data (58-62)
src/sr_od/app/div_uni/operations/choose_oe_file.py (3)
src/one_dragon/base/operation/operation.py (2)
  • round_by_find_area (859-883)
  • status (51-55)
src/one_dragon/base/operation/operation_edge.py (1)
  • node_from (64-95)
src/one_dragon/base/operation/operation_node.py (1)
  • operation_node (72-100)
🪛 Ruff (0.14.7)
src/script_chainer/win_exe/script_runner.py

25-25: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


97-97: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF003)


114-114: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


114-114: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


124-124: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


128-128: Do not catch blind exception: Exception

(BLE001)


129-129: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


129-129: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


130-130: Use explicit conversion flag

Replace with conversion flag

(RUF010)


161-161: subprocess call: check for execution of untrusted input

(S603)


163-163: subprocess call: check for execution of untrusted input

(S603)


165-165: Do not catch blind exception: Exception

(BLE001)


262-262: Do not catch blind exception: Exception

(BLE001)


268-268: Do not catch blind exception: Exception

(BLE001)


276-276: Do not catch blind exception: Exception

(BLE001)


323-323: return inside finally blocks cause exceptions to be silenced

(B012)

src/sr_od/challenge_mission/use_trailblaze_power.py

110-110: Redefinition of unused screen from line 1

(F811)


157-157: Redefinition of unused screen from line 1

(F811)


211-211: Redefinition of unused screen from line 1

(F811)


227-227: Redefinition of unused screen from line 1

(F811)

src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py

202-202: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

src/script_chainer/config/script_config.py

25-25: String contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF001)


25-25: String contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF001)


26-26: String contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF001)


44-44: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
src/script_chainer/win_exe/script_runner.py (3)

133-144: 严重:ctx 可能为 None 导致后续崩溃。

run_script 接受 ctx: SrContext = None,但 Line 297 调用时未传入 ctx,而 Lines 204-205 直接访问 ctx.context_running_state 会抛出 AttributeError。

必须在 run() 中创建并传入有效的 SrContext 实例,或在访问前添加空值检查。

应用此修改(方案1:添加空值检查):

-def run_script(script_config: ScriptConfig, ctx: SrContext = None) -> None:
+def run_script(script_config: ScriptConfig, ctx: SrContext | None = None) -> None:

并在 Line 204 添加检查:

     while True:
-        if ((script_config.stop_chain_when_pause_pressed and ctx.context_running_state == ContextRunStateEnum.PAUSE)
-                or ctx.context_running_state == ContextRunStateEnum.STOP):
+        if ctx is not None and (
+                (script_config.stop_chain_when_pause_pressed and ctx.context_running_state == ContextRunStateEnum.PAUSE)
+                or ctx.context_running_state == ContextRunStateEnum.STOP):
             break

222-230: 严重:字符串哨兵值和布尔逻辑错误。

Line 223 使用字符串 'None' 作为哨兵值不恰当,应使用 None 或空字符串检查。

Line 225 的逻辑存在问题:

  • pid_status.get('alive') 可能为 None(访问拒绝或错误)
  • pid_status.get('create_time') 可能为 None,时间比较会抛出 TypeError
  • Line 229: script_ever_existed or script_current_existedscript_current_existed 是非布尔值时会导致类型混乱

应用此修改:

-        if script_config.script_process_name == 'None':
+        if not script_config.script_process_name or script_config.script_process_name == 'None':
             pid_status = is_pid_running(process.pid)
-            script_current_existed: bool = pid_status.get('alive') and pid_status.get('create_time') < subprocess_create_time + 5
+            alive = pid_status.get('alive', False)
+            create_time = pid_status.get('create_time')
+            script_current_existed: bool = bool(alive) and (create_time is not None and create_time < subprocess_create_time + 5)
         else:
             script_current_existed: bool = is_process_existed(script_config.script_process_name)
-        script_closed = script_ever_existed and not script_current_existed
-        script_ever_existed = script_ever_existed or script_current_existed
+        script_closed = bool(script_ever_existed) and (not script_current_existed)
+        script_ever_existed = bool(script_ever_existed) or bool(script_current_existed)

280-307: 必须创建并传入 SrContext。

Line 297 调用 run_script(script_config) 时未传入 ctx 参数,导致 run_script 内部的 ctxNone,在 Lines 204-205 访问时会崩溃。

需要在 run() 开始时创建 SrContext 实例并传递给所有 run_script 调用。

应用此修改:

 def run():
     init(autoreset=True)
     args = parse_args()
     module_name: str = args.chain
     chain_config: ScriptChainConfig = ScriptChainConfig(module_name)
+    ctx = SrContext()
     try:
         if not chain_config.is_file_exists():
             print_message(f'脚本链配置不存在 {module_name}', "ERROR")
         else:
             for i in range(len(chain_config.script_list)):
                 script_config = chain_config.script_list[i]
-                run_script(script_config)
+                run_script(script_config, ctx)
                 if i < len(chain_config.script_list) - 1:
                     print_message('10秒后开始下一个脚本')
                     time.sleep(10)
🧹 Nitpick comments (1)
src/script_chainer/win_exe/script_runner.py (1)

21-53: 建议移除已注释的代码。

这段大量注释的代码(包括 Push 通知相关的功能)看起来不再使用。版本控制已经保存了历史记录,建议删除以保持代码整洁。

同样的问题也存在于 lines 285-322 的注释代码中。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc8c3c4 and f7632ca.

📒 Files selected for processing (1)
  • src/script_chainer/win_exe/script_runner.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.7)
src/script_chainer/win_exe/script_runner.py

25-25: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


97-97: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


111-111: Comment contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF003)


114-114: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


114-114: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


124-124: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


128-128: Do not catch blind exception: Exception

(BLE001)


129-129: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


129-129: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


130-130: Use explicit conversion flag

Replace with conversion flag

(RUF010)


161-161: subprocess call: check for execution of untrusted input

(S603)


163-163: subprocess call: check for execution of untrusted input

(S603)


165-165: Do not catch blind exception: Exception

(BLE001)


262-262: Do not catch blind exception: Exception

(BLE001)


268-268: Do not catch blind exception: Exception

(BLE001)


276-276: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (3)
src/script_chainer/win_exe/script_runner.py (3)

56-71: 实现正确,异常处理完善。

函数正确处理了空值和 psutil 的常见异常(NoSuchProcess、AccessDenied、ZombieProcess)。


73-86: 实现正确。

函数会终止所有匹配名称的进程,异常处理得当。


258-278: 清理逻辑正确。

进程终止逻辑实现得当,异常处理完善。

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/sr_od/app/sim_uni/sim_uni_app.py (1)

151-241: _execute_sim_universe_x:插件校验与运行循环整体合理,暂停后结果处理存在潜在重复执行风险

  • 插件路径、diver.py 和默认 info.yml 的存在性检查,以及用户配置文件的同步流程都很到位,可以避免大部分“没装插件/缺配置”导致的硬崩。
  • 运行前清空 logs/notif.txt,并在运行后读取首行、带重试和异常日志的文件解析逻辑也比较稳健。

需要注意的是 run-loop 中这段逻辑:

run_script(script_config, self.ctx)
# auto_simulated_universe 运行结束, 检查是否按了暂停键, 如果按了暂停键则认为是人为中止其运行从而忽略其返回值
if self.ctx.context_running_state == ContextRunStateEnum.PAUSE:
    time.sleep(1)
    continue
retry_count += 1
# 然后才去读取 plugin_run_result_path

这意味着:如果脚本正常结束后,用户“恰好”在 run_script 返回与这次检查之间按下暂停键,本次运行写入的 completed_num 会被完全忽略,解除暂停后会再跑一次脚本,可能造成不必要的重复执行。你这里明显是想在“用户主动中止(PAUSE)”时忽略结果并且不消耗重试次数,但可以考虑微调顺序,例如“先读取一次结果文件(若 completed_num>0 直接返回)、再处理 PAUSE/STOP/重试逻辑”,以兼顾用户中途终止和成功完成后的边界情况。

🧹 Nitpick comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

113-128: 初始画面 WORLD_X 分支逻辑 OK,可避免硬编码字符串

_check_initial_screen 在识别到 SIM_TYPE_NORMALweekly_uni_num == 'WORLD_X' 时,将状态切为 SIM_TYPE_X,逻辑上能按配置在普通宇宙入口和差分宇宙入口间切换,没有问题。不过这里直接用 'WORLD_X' 字符串比较,后续如果枚举名调整容易踩坑,建议改成 SimUniWorldEnum.WORLD_X.name 来消除魔法字符串。


130-149: 传送到差分/普通宇宙的分支合理,但需考虑 mission 为 None 的情况

根据 weekly_uni_num 在“前往参与”和“前往模拟宇宙”两个引导任务间切换,并且现在正确检查 GuideTransport.execute() 的返回值并用 round_by_op_result 传播失败,这一部分逻辑是健康的。不过 best_match_mission_by_name 返回的是 Optional,如果极端情况下未能匹配到 mission(配置或文本变化),当前代码会把 None 传进 GuideTransport 导致直接异常崩溃,建议在构造 GuideTransport 前判空并返回 round_fail + 适当日志,提升鲁棒性。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7632ca and 4206250.

📒 Files selected for processing (1)
  • src/sr_od/app/sim_uni/sim_uni_app.py (5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/app/sim_uni/sim_uni_app.py
🧬 Code graph analysis (1)
src/sr_od/app/sim_uni/sim_uni_app.py (10)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (34-38)
src/one_dragon/base/operation/operation_round_result.py (2)
  • OperationRoundResult (13-47)
  • OperationRoundResultEnum (6-10)
src/script_chainer/config/script_config.py (1)
  • ScriptConfig (30-104)
src/script_chainer/win_exe/script_runner.py (1)
  • run_script (133-277)
src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_world.py (1)
  • SimUniRunWorld (18-114)
src/sr_od/app/sim_uni/sim_uni_run_record.py (2)
  • points_reward_complete (96-101)
  • points_reward_complete (104-105)
src/sr_od/app/sim_uni/sim_uni_screen_state.py (2)
  • get_sim_uni_initial_screen_state (213-238)
  • ScreenState (16-38)
src/sr_od/app/sim_uni/sim_uni_config.py (4)
  • weekly_uni_num (56-61)
  • weekly_uni_num (64-65)
  • only_points_reward (88-93)
  • only_points_reward (96-97)
src/sr_od/interastral_peace_guide/guide_data.py (1)
  • best_match_mission_by_name (115-128)
src/one_dragon/utils/os_utils.py (1)
  • get_work_dir (45-56)
🔇 Additional comments (3)
src/sr_od/app/sim_uni/sim_uni_app.py (3)

61-87: _check_points_reward 的 FAIL/SUCCESS 语义与调用方一致

这里根据 OCR 统计 14000 次数,count_14000 == 1 返回 round_fail('未打满积分奖励')== 2 返回 round_success('已打满积分奖励'),其它情况保持默认 round_retry('未找到积分奖励'),结合 _execute_sim_universe_xif points_reward.result != OperationRoundResultEnum.FAIL: return points_reward 的调用方式,可以正确实现“FAIL=奖励未满需继续自动化,SUCCESS/RETRY=跳过自动化”的特例语义;两帧一致性判断也有助于降低误识别,整体实现是合理的。

Based on learnings, ...


243-259: 从“传送”状态接入选择宇宙节点的改动是合理的

新增 @node_from(from_name='传送', status=SIM_TYPE_NORMAL) 让流程既可以从初始画面直接进入“选择宇宙”,也可以在通过星槎传送后继续进入同一节点,这样 WORLD_X/普通宇宙两条路径在状态机层面更统一,整体设计没有明显问题。


318-323: 差分宇宙自动化成功后直接衔接每周奖励领取流程是合理的

新增 @node_from(from_name='调用差分宇宙自动化', success=True)check_reward_before_exit,可以在积分奖励判定为 SUCCESS(即 14000/14000)时直接进入 SimUniClaimWeeklyReward 领取周奖励,并与原有 STATUS_TO_WEEKLY_REWARD 路径复用同一节点,状态流转清晰且符合“打满就溜”的需求。

# Conflicts:
#	src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py
#	src/sr_od/app/sim_uni/operations/sim_uni_exit.py
#	src/sr_od/app/sim_uni/sim_uni_app.py
#	src/sr_od/interastral_peace_guide/guide_transport.py
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

182-182: 考虑是否需要在脚本运行前调用 BackToNormalWorldPlus。

Line 182 在启动外部脚本前调用 BackToNormalWorldPlus,这可能会增加不必要的延迟。如果此时已经处于正确的游戏状态(差分宇宙入口),这个调用可能是多余的。

建议评估是否可以移除此调用,或在注释中说明其必要性(例如确保游戏状态干净)。


202-239: 脚本执行重试逻辑基本合理,存在罕见边缘情况。

重试逻辑已修复之前 for 循环中修改循环变量无效的问题,现在使用 while 循环和显式计数器是正确的。文件读取的错误处理(lines 221-230)也很完善。

不过存在一个罕见的边缘情况:如果脚本成功完成并写入了结果,但在 Line 215 检查之前用户按下暂停键,当前代码会跳过结果检查并重新运行脚本。虽然这种情况极少发生(需要在脚本完成与 Line 215 之间的极短时间窗口内按暂停),但理论上可能导致重复执行。

可选的优化方案

可以考虑在检测到暂停后仍然尝试读取结果文件,如果文件显示成功(completed_num > 0)则直接使用该结果,避免不必要的重试:

run_script(script_config, self.ctx)
# 即使检测到暂停,也先尝试读取结果
retry_count += 1

# 进程退出, 检查运行情况
for _ in range(3):
    # ... 文件读取逻辑
    
if completed_num > 0:
    # 记录完成次数, 返回失败然后下次运行即可领奖励
    self.ctx.sim_uni_record.add_elite_times()
    return self.round_by_op_result(self.op_fail("已打完, 前往领奖励"))

# 如果结果为0且检测到暂停/停止,可以在这里决定是否继续
if self.ctx.context_running_state in (ContextRunStateEnum.STOP, ContextRunStateEnum.PAUSE):
    break

但考虑到这是极少见的边缘情况,且当前实现已经足够健壮,是否优化可由团队决定。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4206250 and 4108d4d.

📒 Files selected for processing (1)
  • src/sr_od/app/sim_uni/sim_uni_app.py (6 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-13T12:07:30.874Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/sr_od/app/sim_uni/sim_uni_app.py:61-87
Timestamp: 2025-10-13T12:07:30.874Z
Learning: 在 `_check_points_reward()` 中,`OperationRoundResult` 的语义与常规不同:`FAIL` 表示"奖励未完成,需要继续执行自动化",而 `SUCCESS` 和 `RETRY` 表示"提前返回,跳过自动化"。这是因为调用方使用 `if result != FAIL: return` 来判断是否跳过后续的自动化脚本执行。

Applied to files:

  • src/sr_od/app/sim_uni/sim_uni_app.py
🔇 Additional comments (2)
src/sr_od/app/sim_uni/sim_uni_app.py (2)

128-147: 传送逻辑实现正确。

代码根据配置正确区分了差分宇宙和模拟宇宙的路径,并且妥善检查了传送操作的结果。之前审查中关于缺少 op_result 检查的问题已得到修复。


149-201: 外部脚本调用的准备工作实现完善。

代码正确实现了插件目录、脚本文件和配置文件的存在性校验,配置文件同步逻辑清晰,运行结果文件的清空处理也很稳妥。之前审查中关于缺少存在性检查和配置文件校验的问题已全部修复。

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/script_chainer/win_exe/script_runner.py (3)

21-52: 移除或文档化大段注释代码。

文件中包含 32 行注释掉的 Push 通知相关代码。如果该功能已被移除,建议删除这些注释以保持代码整洁;如果计划将来启用,建议添加 TODO 注释说明原因和时间表。


164-166: 建议细化异常处理以提升可观测性。

多处使用了宽泛的 Exception 捕获(lines 164, 261, 267, 275),这可能会隐藏意外错误。虽然当前实现会记录异常信息(exc_info=True),但建议根据具体场景捕获更精确的异常类型(如 OSError, psutil.Error 等),或在日志中添加更多上下文信息以便排查问题。

Also applies to: 261-262, 267-268, 275-276


279-296: 建议创建 SrContext 实例并传递给 run_script。

虽然之前的评审已指出 run_script 中 ctx 可能为 None 的问题,但当前 run() 函数未传递任何上下文。建议实例化 SrContext 并传递给 run_script,以支持优雅的暂停/停止控制(lines 203-205)。

🔎 建议的实现
 def run():
     init(autoreset=True)
     args = parse_args()
     module_name: str = args.chain
     chain_config: ScriptChainConfig = ScriptChainConfig(module_name)
+    ctx = SrContext()
+    ctx.init_by_config()
     # push_instance = get_push_instance()
     try:
         if not chain_config.is_file_exists():
             print_message(f'脚本链配置不存在 {module_name}', "ERROR")
         else:
             for i in range(len(chain_config.script_list)):
                 script_config = chain_config.script_list[i]
                 # if script_config.notify_start:
                 #     if push_instance is not None:
                 #         push_instance.send(
                 #             content=f'脚本链 {module_name} 开始运行: {script_config.script_display_name}'
                 #         )
-                run_script(script_config)
+                run_script(script_config, ctx)
                 # if script_config.notify_done:

注意:需要确保 SrContext 的初始化不依赖外部状态。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4108d4d and 2268627.

📒 Files selected for processing (1)
  • src/script_chainer/win_exe/script_runner.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/script_chainer/win_exe/script_runner.py (7)
src/one_dragon/base/conditional_operation/conditional_operator.py (1)
  • init (46-81)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (34-38)
src/script_chainer/config/script_config.py (7)
  • ScriptConfig (30-104)
  • ScriptChainConfig (107-219)
  • CheckDoneMethods (8-12)
  • invalid_message (79-104)
  • game_display_name (66-68)
  • check_done_display_name (71-76)
  • script_display_name (62-63)
src/sr_od/context/sr_context.py (1)
  • SrContext (163-335)
src/one_dragon/base/operation/operation.py (1)
  • status (51-55)
src/one_dragon/base/matcher/match_result.py (1)
  • extend (101-110)
src/one_dragon/base/config/yaml_operator.py (2)
  • get (90-91)
  • is_file_exists (111-116)
🪛 Ruff (0.14.8)
src/script_chainer/win_exe/script_runner.py

25-25: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


110-110: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


110-110: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


110-110: Comment contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF003)


113-113: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


113-113: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


123-123: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


127-127: Do not catch blind exception: Exception

(BLE001)


128-128: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


128-128: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


129-129: Use explicit conversion flag

Replace with conversion flag

(RUF010)


160-160: subprocess call: check for execution of untrusted input

(S603)


162-162: subprocess call: check for execution of untrusted input

(S603)


164-164: Do not catch blind exception: Exception

(BLE001)


261-261: Do not catch blind exception: Exception

(BLE001)


267-267: Do not catch blind exception: Exception

(BLE001)


275-275: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (5)
src/script_chainer/win_exe/script_runner.py (5)

56-70: 实现正确。

函数正确处理了空值检查和 psutil 异常情况。


73-85: 实现正确。

函数正确实现了进程终止逻辑,异常处理得当。


88-93: 实现正确。

参数解析逻辑清晰,使用标准库实现。


160-162: 验证脚本路径来源的安全性。

Line 160 和 162 使用 subprocess.Popen 执行来自配置的脚本路径。虽然 ScriptConfig 进行了基本验证(line 139-142),但请确认配置文件的访问权限受到适当限制,防止恶意路径注入。

根据静态分析提示。


325-326: 实现正确。

标准的 Python 主程序入口。

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/script_chainer/win_exe/script_runner.py (3)

216-223: 使用字符串 'None' 作为哨兵值存在风险。

Line 217 使用 script_config.script_process_name == 'None' 判断是否使用 PID 追踪方式。字符串 'None' 作为哨兵值不够稳妥,若实际进程名恰好为 'None' 将导致逻辑错误。建议使用 None 或空字符串作为哨兵。

🔎 建议的修复
-        if script_config.script_process_name == 'None':
+        if not script_config.script_process_name:  # None 或空字符串
             pid_status = is_pid_running(process.pid)
             script_current_existed: bool = pid_status.get('alive') and (pid_status.get('create_time') is not None) and pid_status.get('create_time') < subprocess_create_time + 5
         else:
             script_current_existed: bool = is_process_existed(script_config.script_process_name)

127-200: 严重:ctx 为 None 时会导致 AttributeError。

Line 127 函数签名允许 ctxNone(默认值),但 lines 198-199 直接访问 ctx.context_running_state 而未进行空值检查。Line 291 调用 run_script(script_config) 时未传入 ctx 参数,将导致运行时异常。

🔎 建议的修复方案

方案 1:在函数内部添加空值防护

 def run_script(script_config: ScriptConfig, ctx: SrContext = None) -> None:
     """
     运行脚本
     """
     script_path = script_config.script_path
     args = script_config.script_arguments
 
     invalid_message = script_config.invalid_message
     if invalid_message is not None:
         print_message(f'脚本配置不合法 跳过运行 {invalid_message}')
         return
 
     command = [script_path]
     if args and args.strip():
         command.extend(args.split())
 
     start_time = time.time()
 
     subprocess_created: bool = False
     subprocess_create_time: float = start_time
     process = None
 
     while True:
         now = time.time()
         # ... (subprocess creation logic)
         
     if not subprocess_created:
         print_message(f'子进程创建失败 {script_path}')
         return
     else:
         print_message(f'脚本子进程创建成功 {script_path}', level='PASS')
 
     script_ever_existed: bool = False
     game_ever_existed: bool = False
     is_done: bool = False
     while True:
-        if ((script_config.stop_chain_when_pause_pressed and ctx.context_running_state == ContextRunStateEnum.PAUSE)
-                or ctx.context_running_state == ContextRunStateEnum.STOP):
+        if ctx is not None and ((script_config.stop_chain_when_pause_pressed and ctx.context_running_state == ContextRunStateEnum.PAUSE)
+                or ctx.context_running_state == ContextRunStateEnum.STOP):
             break

方案 2(推荐):在 run() 函数中创建并传入 ctx 实例

run() 函数中创建 SrContext 实例并传递给 run_script,确保 ctx 始终非空。


100-124: 返回值结构不一致,建议统一。

函数在成功时返回包含 create_time 键的字典,但失败分支(lines 116, 119, 121, 124)未包含该键。尽管调用处(line 219)已使用 pid_status.get('create_time') is not None 进行防御,但统一返回结构能提升代码可维护性。

🔎 建议的修复
     except psutil.NoSuchProcess:
-        return {"alive": False, "reason": "process_exited"}
+        return {"alive": False, "reason": "process_exited", "create_time": None}
     except psutil.AccessDenied:
-        return {"alive": None, "reason": "access_denied"}
+        return {"alive": None, "reason": "access_denied", "create_time": None}
     except psutil.ZombieProcess:
-        return {"alive": False, "reason": "zombie_process"}
+        return {"alive": False, "reason": "zombie_process", "create_time": None}
     except Exception as e:
-        return {"alive": None, "reason": f"error: {str(e)}"}
+        return {"alive": None, "reason": f"error: {str(e)}", "create_time": None}
🧹 Nitpick comments (1)
src/script_chainer/win_exe/script_runner.py (1)

12-48: 建议移除大段注释代码,提升可读性。

Lines 12-48 包含大量注释代码(Push 实例、logger 配置、colorama 初始化等)。如果这些功能已确认不再使用,建议删除这些注释代码,通过版本控制系统管理历史记录,以保持代码整洁。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2268627 and d07e0b0.

📒 Files selected for processing (2)
  • pyproject.toml (1 hunks)
  • src/script_chainer/win_exe/script_runner.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • pyproject.toml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-21T03:02:25.697Z
Learnt from: JoshCai233
Repo: OneDragon-Anything/StarRailOneDragon PR: 521
File: src/script_chainer/win_exe/script_runner.py:96-102
Timestamp: 2025-12-21T03:02:25.697Z
Learning: In Python code across the project (e.g., src/script_chainer/win_exe/script_runner.py), prefer using the project's log module for logging to files instead of using print statements for console output. Print does not write to log files, so replace prints with logger calls (e.g., log.info, log.debug, log.error) and ensure proper logging configuration is in place.

Applied to files:

  • src/script_chainer/win_exe/script_runner.py
🧬 Code graph analysis (1)
src/script_chainer/win_exe/script_runner.py (2)
src/one_dragon/base/operation/one_dragon_context.py (1)
  • ContextRunStateEnum (34-38)
src/script_chainer/config/script_config.py (7)
  • ScriptConfig (30-104)
  • ScriptChainConfig (107-219)
  • CheckDoneMethods (8-12)
  • invalid_message (79-104)
  • game_display_name (66-68)
  • check_done_display_name (71-76)
  • script_display_name (62-63)
🪛 Ruff (0.14.8)
src/script_chainer/win_exe/script_runner.py

16-16: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


105-105: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


105-105: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


105-105: Comment contains ambiguous (FULLWIDTH COLON). Did you mean : (COLON)?

(RUF003)


108-108: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


108-108: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


118-118: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


122-122: Do not catch blind exception: Exception

(BLE001)


123-123: Comment contains ambiguous (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?

(RUF003)


123-123: Comment contains ambiguous (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?

(RUF003)


124-124: Use explicit conversion flag

Replace with conversion flag

(RUF010)


155-155: subprocess call: check for execution of untrusted input

(S603)


157-157: subprocess call: check for execution of untrusted input

(S603)


159-159: Do not catch blind exception: Exception

(BLE001)


256-256: Do not catch blind exception: Exception

(BLE001)


262-262: Do not catch blind exception: Exception

(BLE001)


270-270: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (1)
src/script_chainer/win_exe/script_runner.py (1)

139-157: 验证脚本路径和参数的来源安全性。

Lines 139-157 从配置中构建并执行命令。静态分析工具标记了潜在的不受信任输入执行风险(S603)。请确认:

  1. ScriptConfigscript_pathscript_arguments 是否经过适当验证
  2. 配置文件的访问权限是否受限,防止恶意修改
  3. 是否需要添加路径白名单或参数校验

如果配置文件由受信任的管理员维护且访问受限,当前实现是可接受的。

根据静态分析提示。

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