-
Notifications
You must be signed in to change notification settings - Fork 60
尝试删除一些冗余的截图 #555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
尝试删除一些冗余的截图 #555
Conversation
Walkthrough本次 PR 大量将各处获取屏幕的调用由即时截屏 Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 需要额外关注的点:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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 (2)
src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (2)
70-79:first_wait使用缓存截图是合理的,但skip_first_screen_check分支逻辑存在问题
本次把
screen = self.screenshot()改成screen = self.last_screenshot本身是合理的,能避免重复截图,只要框架保证每轮节点调用前都会刷新last_screenshot即可。但当前判断条件:
if not self.first_screen_check or not self.skip_first_screen_check: self.first_screen_check = False if not sim_uni_screen_state.in_sim_uni_choose_bless(screen, self.ctx.ocr): return self.round_retry('未在模拟宇宙-选择祝福页面', wait=1)与参数注释“
skip_first_screen_check: 是否跳过第一次的画面状态检查”不符:
- 默认
self.first_screen_check=True且skip_first_screen_check=True时,条件恒为 False,意味着永远不会做画面校验,self.first_screen_check也一直不会被置为 False。skip_first_screen_check=False时则每次都会进入分支,等价于“从不跳过首帧”,也和名称不符。建议在本 PR 或后续 PR 中修正为“仅首帧可跳过,其余帧都检查”,类似下面的实现(仅示意):
def first_wait(self): - screen = self.last_screenshot - - if not self.first_screen_check or not self.skip_first_screen_check: - self.first_screen_check = False - if not sim_uni_screen_state.in_sim_uni_choose_bless(screen, self.ctx.ocr): - return self.round_retry('未在模拟宇宙-选择祝福页面', wait=1) - - return self.round_success(wait=1) # 稍微等待祝福都出现了 + screen = self.last_screenshot + + # 第一次且允许跳过首帧检查:只更新标志并直接放行 + if self.first_screen_check and self.skip_first_screen_check: + self.first_screen_check = False + return self.round_success(wait=1) # 稍微等待祝福都出现了 + + # 之后每次都进行页面校验 + self.first_screen_check = False + if not sim_uni_screen_state.in_sim_uni_choose_bless(screen, self.ctx.ocr): + return self.round_retry('未在模拟宇宙-选择祝福页面', wait=1) + + return self.round_success(wait=1) # 稍微等待祝福都出现了这样既保留“首帧可跳过”的优化,又不会导致整个节点完全不做状态校验。
83-113:choose_bless_time仅在兜底分支赋值,fast_back_to_world=True时可能导致运行时异常这段逻辑中:
self.ctx.controller.click(target_bless_pos.rect.center) time.sleep(0.25) 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) # ... self.ctx.controller.click(confirm_point) self.choose_bless_time = time.time() return self.round_success(wait=0.1)
handle_init中将self.choose_bless_time初始化为None。这里只有在 OCR 未识别到确认按钮,走兜底点击固定坐标 时才给
self.choose_bless_time赋值。但在
wait_not_in_bless的fast_back_to_world分支中会无条件做:if sim_uni_screen_state.in_sim_uni_choose_bless(self.ctx, screen): if now - self.choose_bless_time >= 2: ...当:
fast_back_to_world=True,round_by_ocr_and_click正常识别到“确认”并返回成功,时,
self.choose_bless_time仍为None,now - self.choose_bless_time会抛出TypeError(float 与 NoneType 相减)。建议在点击祝福后就统一记录时间,而不是只在兜底分支中设置,例如:
else: self.ctx.controller.click(target_bless_pos.rect.center) - time.sleep(0.25) + self.choose_bless_time = time.time() + time.sleep(0.25) @@ - self.ctx.controller.click(confirm_point) - self.choose_bless_time = time.time() - return self.round_success(wait=0.1) + self.ctx.controller.click(confirm_point) + return self.round_success(wait=0.1)这样无论是 OCR 成功路径还是兜底路径,
wait_not_in_bless中都能拿到有效的choose_bless_time,避免运行时异常。
本 PR 将screen改为使用self.last_screenshot不会影响上述修正建议。
🧹 Nitpick comments (8)
src/sr_od/operations/team/check_team_members_in_world.py (1)
28-35: 改用last_screenshot的前置条件和兜底可以再确认一下这里直接用
self.last_screenshot作为整轮识别的输入,从调用方式上看与原来的self.screenshot()兼容,只要调度层在进入本节点前已经刷新过最新截图,就能达到减少冗余截图的目的。可以考虑两点小优化以提高鲁棒性:
- 明确(或在注释中标注)本节点依赖的前置条件:进入本节点前框架一定会刷新
last_screenshot;- 或者在这里做一次轻量兜底,例如当
last_screenshot为空/无效时回退到self.screenshot()再继续识别,避免在某些边缘流程下用到过期或空截图导致后续 OCR / 特征匹配异常。src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_path.py (1)
58-60: 确认节点同样完全依赖装饰器刷新截图,建议轻量防御
_confirm_path现在也直接使用self.last_screenshot,逻辑上与上一个节点保持一致,可以减少一次截图。但同样完全依赖@operation_node在每轮开始前更新last_screenshot。两个小建议供参考:
- 若以后给该节点加上
screenshot_before_round=False(例如为了优化性能),需要记得同步在节点内部恢复主动截图,否则这里会用到旧图。- 可以在需要强依赖截图的节点附近加一行注释,或在
round_by_find_and_click_area内对screen is None做个早期保护(直接round_retry),增强健壮性。当前改动本身是合理的,只是建议你在整体 PR 里再扫一遍这些依赖关系。
src/sr_od/operations/team/switch_member.py (1)
79-83: 确认对last_screenshot的依赖是否始终安全这里从主动
self.screenshot()改为直接使用self.last_screenshot,逻辑上依赖于:
@operation_node在每轮调用_wait_after_confirm之前都会自动更新一次last_screenshot;- 对这个节点当前和将来都不会设置
screenshot_before_round=False,也不会改变默认行为。在当前框架契约成立的前提下,这样可以有效避免重复截图、性能更好;但如果以后有人调整该节点的
operation_node参数或装饰器默认值,这里就可能拿到旧画面或None,导致误判或异常。建议你:
- 明确确认一下当前框架对该节点的截图时机保证;
- 如果希望提高健壮性,可以考虑在装饰器上显式标注一次
screenshot_before_round=True,以防默认值将来被改掉(保持零额外截图开销的前提下锁定契约)。src/sr_od/challenge_mission/choose_support_in_team.py (1)
40-150: 建议进行端到端测试验证功能正确性本次改动将所有节点的截图方式从
self.screenshot()改为self.last_screenshot,这是一个减少冗余截图的性能优化。建议:
- 功能测试:在实际环境中运行完整的支援角色选择流程,特别关注需要滚动列表查找角色的场景(触发第 81 行的拖动操作)
- 性能对比:对比改动前后的截图次数和执行时间,验证优化效果
- 边缘情况:测试找不到支援角色的情况(触发第 72-76 行的逻辑)
如果测试中发现识别失败,可能需要在某些关键位置(如拖动操作后)重新添加主动截图。
src/sr_od/app/sim_uni/operations/move_v2/sim_uni_move_to_next_level_v3.py (1)
205-245: 需要重点测试该高频检测方法该方法是实时控制的核心,包含高频率的屏幕状态检查(等待时间仅 0.02 秒)。使用
self.last_screenshot可能存在以下风险:
- 交互时机判断(第 229 行):移动过程中检测交互机会,若截图数据过时可能导致错过交互或误判
- 大世界状态检测(第 207 行):交互后需要快速判断是否已离开大世界,延迟可能导致逻辑错误
- 入口匹配(第 234 行):实时匹配下层入口位置,过时数据可能导致转向不准确
建议对该方法进行充分的实际场景测试,验证在高频调用下
last_screenshot的新鲜度是否满足检测精度要求。src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_respite_route_v2.py (1)
101-131: _detect_screen 禁用前置截图逻辑正确,注释可顺带更新这里在装饰器上设置
screenshot_before_round=False,由函数内部视角下拉后再调用self.screenshot()做识别,避免多余截屏且保证检测用图像是最新画面,和路由逻辑是匹配的。顺带一提,docstring 仍写着“识别游戏画面上是否有事件牌”,当前逻辑识别的是“黑塔”,后续有空可以把注释改成更贴切的描述。src/sr_od/app/assignments/assignments_app.py (1)
54-58: 委托流程统一使用 last_screenshot,建议后续顺带精简 _click_assignment 的截图
choose_tab、_claim_all、assign_again、_claim、_click_empty都改为从self.last_screenshot取screen传给 OCR/查找辅助方法;这些节点在读取前没有对画面做新的点击或移动,且装饰器使用默认screenshot_before_round=True,所以每轮进入节点前的那张截图就足够用,领取/再次派遣流程行为不变但少了多次self.screenshot()。可以考虑后续把_click_assignment里单独的self.screenshot()也改为复用last_screenshot(或者在该节点上设置screenshot_before_round=False,只保留内部截图),进一步统一和精简截屏逻辑。Also applies to: 62-69, 73-76, 80-88, 92-95
src/sr_od/operations/enter_game/enter_game.py (1)
153-156: logout_with_account_kept 中对旧 screen 的复用可以更稳健这里先基于
last_screenshot构造screen,然后调用round_by_click_area点击“退出并保留登陆记录”,接着仍把点击前的screen传给round_by_find_and_click_area查找“退出”按钮。根据round_by_find_and_click_area的实现(始终使用传入的screen),如果“退出”按钮是点击后才出现的,这一轮看到的始终是旧画面。这个行为在本次改动前就存在,只是现在顺手可以考虑把第二个调用的screen参数改成None,让它直接使用当前最新的last_screenshot做查找,会更贴近预期。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (60)
src/sr_od/app/assignments/assignments_app.py(3 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/nameless_honor/nameless_honor_app.py(1 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(1 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(3 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(4 hunks)src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py(2 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(2 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(1 hunks)src/sr_od/app/sim_uni/operations/sim_uni_event.py(4 hunks)src/sr_od/app/sim_uni/operations/sim_uni_exit.py(4 hunks)src/sr_od/app/sim_uni/sim_uni_app.py(1 hunks)src/sr_od/app/world_patrol/world_patrol_enter_fight.py(1 hunks)src/sr_od/challenge_mission/choose_support_in_team.py(5 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_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(1 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(3 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/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)
🧰 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/operations/event/sim_uni_reward.pysrc/sr_od/app/daily_training/daily_training_app.pysrc/sr_od/operations/enter_game/switch_account.pysrc/sr_od/operations/wait/wait_in_world.pysrc/sr_od/interastral_peace_guide/open_guide.pysrc/sr_od/interastral_peace_guide/guide_check_power.pysrc/sr_od/app/relic_salvage/relic_salvage_app.pysrc/sr_od/operations/interact/catapult.pysrc/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.pysrc/sr_od/app/assignments/assignments_app.pysrc/sr_od/operations/back_to_normal_world_plus.pysrc/sr_od/operations/click_dialog_confirm.pysrc/sr_od/sr_map/operations/choose_special_point.pysrc/sr_od/operations/enter_game/enter_game.pysrc/sr_od/operations/technique.pysrc/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_elite_route_v2.pysrc/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.pysrc/sr_od/operations/interact/move_interact.py
🧬 Code graph analysis (7)
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/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/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/assignments/assignments_app.py (1)
src/one_dragon/base/operation/operation.py (1)
round_by_find_and_click_area(789-857)
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/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/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)
🔇 Additional comments (93)
src/sr_od/operations/enter_game/switch_account.py (1)
26-43: 改动合理,逻辑清晰。添加
screenshot_before_round=False可以避免在 round 开始时自动截图,而方法内部在time.sleep(2)之后(第41行)手动调用self.screenshot()获取截图用于后续的确认按钮识别。这样的设计更合理:
- 第一次点击(第34行)可能不需要最新截图
- 等待 UI 响应后再截图,确保截图内容是最新的
这与 PR 目标"删除冗余截图"一致。
src/sr_od/operations/interact/catapult.py (1)
57-71: 关闭轮前截图以避免重复截图是合理的这里设置
screenshot_before_round=False,而方法内部仍在time.sleep(3)之后主动调用self.screenshot(),因此不会出现“没图可识别”的问题,只是去掉了框架层多余的一次自动截图,符合本 PR 减少冗余截图的目标,逻辑上是安全的。src/sr_od/operations/interact/move_interact.py (1)
51-80: 手动截图已覆盖需求,关闭轮前自动截图是安全的优化
check_screen在每次执行时都会先短暂等待再调用self.screenshot(),因此将装饰器改为screenshot_before_round=False仅移除了框架层的一次自动截图,不会影响交互按钮识别与后续逻辑,能减少一次冗余截图,改动是合理的。src/sr_od/operations/click_dialog_confirm.py (1)
24-28: Confirm call paths forlast_screenshotchangeThis change from
self.screenshot()toself.last_screenshotaligns with the PR's goal of reducing redundant screenshots. However, the behavioral safety depends on howClickDialogConfirm.click()is invoked:
- If called exclusively through the
@operation_nodeframework (which auto-updates screenshots before each round), the change is safe and reduces overhead.- If called directly elsewhere without prior screenshot capture, the method will use a potentially stale screenshot.
Verify that
ClickDialogConfirm.click()has no direct callers outside the operation framework, or confirm that all call sites ensurelast_screenshotis current.src/sr_od/app/sim_uni/operations/bless/sim_uni_drop_bless.py (2)
56-69: 改用last_screenshot符合“去重复截图”的思路这里直接复用
self.last_screenshot,与框架统一使用上一帧截图的策略一致,传入给get_sim_uni_screen_state的仍然是本轮画面,逻辑上没有引入额外分支或副作用,看起来是安全的重构。
72-85: 选择祝福节点同样复用上一帧截图,注意确认刷新时机
choose_bless也改为使用self.last_screenshot,能减少一次主动截图调用,只要SrOperation/装饰器在进入该节点前保证last_screenshot已刷新,这里识别祝福的位置与原先self.screenshot()的行为应保持一致。建议在实际运行一两轮模拟宇宙丢弃祝福流程,确认识别成功率无回退。src/sr_od/operations/move/move_directly.py (1)
111-112: Verifyoperation_nodedecorator's defaultscreenshot_before_roundbehavior.The TODO comment correctly questions whether the explicit
self.screenshot()call is necessary. Other files in this PR are addingscreenshot_before_round=Falseto the decorator, suggesting the parameter defaults toTrueand automatically captures a screenshot before each round. If this is the case,self.last_screenshotwould already contain the current frame, making the explicit call redundant and replaceable withself.last_screenshot.Check the
operation_nodedecorator definition to confirm the default value ofscreenshot_before_roundand decide whether to remove or keep this call.src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_path.py (1)
39-53: 使用last_screenshot的前置条件需要确认这里改为直接复用
self.last_screenshot,可以去掉多余的self.screenshot(),思路没问题。但这依赖于:
@operation_node在每一轮开始前一定会刷新截图并写入last_screenshot;- 尤其是这是
is_start_node=True的起始节点,首轮调用时也必须保证last_screenshot已被正确设置。建议你确认一下当前装饰器的默认参数(是否
screenshot_before_round=True),以及重试路径下round_retry回来是否总是会在下一轮前重新截图,以避免拿到None或过期截图的情况。src/sr_od/operations/synthesize/synthesize.py (7)
58-60: 使用last_screenshot的前置假设需要确认这里改为直接使用
self.last_screenshot,在减少重复截图上是合理的;前提是SrOperation/@operation_node在进入该起始节点前,一定已经更新过last_screenshot(且不是上一个操作残留的画面)。否则首次进入或异常路径下可能拿到None或过期截图,导致识别异常但不一定显性报错。建议确认框架中该节点的
screenshot_before_round默认值及调用顺序;若存在任何不确定场景,可以在此节点保留self.screenshot()作为兜底。
74-78: 与起始节点同样的截图策略变更这里同样改为使用
self.last_screenshot进行分类标题 OCR,逻辑本身未变,只依赖框架在本轮调用前已更新截图。行为与check_screen中的改动一致,请一并参考对行 58 的说明。
92-94: 选择物品节点复用上一轮截图,看起来是等价替换
choose_item中仅在本轮开始时做一次截图读取用于模板匹配,失败时通过拖动并round_retry进入下一轮再重新识别。改为self.last_screenshot后,只要每轮前由装饰器刷新截图,行为与原先调用self.screenshot()等价。
132-139: 数量选择节点使用缓存截图进行“材料不足”检测这里用
last_screenshot先做一次“材料不足”区域识别,之后点击“最大值”按钮本身不依赖后续截图更新。改动在逻辑上是安全的,同样依赖每轮前的截图刷新机制;和之前几个节点保持了一致的风格。
148-150: 点击“合成”按钮的识别逻辑复用上一帧,需确保对话框出现时重新截图
click_synthesize使用round_by_find_and_click_area配合screen = self.last_screenshot,只要在本轮开始时获取的就是当前界面(包含“合成”按钮),则与原先行为等价。这里没有在节点内产生新的状态变化再做二次识别,因此复用一帧截图是合理的。
159-161: 确认对话框识别依赖最新一轮截图
click_confirm需要在“点击合成”之后的新界面上寻找“合成确认”按钮。若调度器在进入本节点前会重新截图并刷新last_screenshot,此处改动就是单纯去除冗余调用,没有逻辑风险;否则会出现仍在使用点击前画面的情况。建议在整体流程跑一遍实测该对话框是否能稳定被识别。
170-172: 关闭空白点击节点的截图复用与前面保持一致
click_empty的逻辑与前一节点类似,仅在本轮开始时读取一次截图查找“点击空白处关闭”的区域。只要进入该节点前有重新截图,复用last_screenshot不影响功能,并统一了本文件的写法。src/sr_od/app/div_uni/operations/ornamenet_extraction.py (3)
132-135: 点击挑战节点改用last_screenshot这里将
self.screenshot()(推测)改为使用self.last_screenshot,只变更截图来源、不改业务逻辑,看起来与“减少重复截图”的 PR 目标一致,没有明显风险。
143-145: 等待类节点使用last_screenshot时需确认刷新时机
wait_mission_loaded和wait_back都是在“等待大世界角色图标”的节点中使用self.last_screenshot传给round_by_find_area。从代码上看逻辑是合理的,但有一点需要确认:
- 如果节点在
node_max_retry_times内会多次重试,而round_by_find_area只依赖传入的screen,则需要确保在每一轮重试前框架都会刷新last_screenshot,否则可能一直用旧图导致识别失败或变慢。建议你确认一下 Operation 框架里
last_screenshot的更新策略(例如在每轮/每节点前自动截图并更新),确保这两个等待节点在重试时拿到的是最新画面;如果已经有保证则这处改动是安全的。Also applies to: 205-206
189-196: 战斗结果处理节点复用上一帧截图
after_battle_result中复用self.last_screenshot来判断点击“再来一次按钮”或“退出关卡按钮”,与上游WaitBattleResult刚结束时的 UI 状态是一致的,避免了额外截图,逻辑上也保持不变,这里改动是合理的。src/sr_od/sr_map/operations/choose_special_point.py (1)
35-79: 确认该节点的 last_screenshot 每轮都会被正确刷新这里从
self.screenshot()改为使用self.last_screenshot,和本次 PR "减少冗余截图"的目标是一致的,整体逻辑看起来与原先等价且少了一次截图 IO。需要确认的一点是,这个起始节点上
@operation_node的screenshot_before_round默认值/配置:
- 如果该节点在每一轮
check_screen调用前都会由框架自动截图并写入last_screenshot,那现在的实现是安全的;- 如果默认并不会在每轮前截图(例如默认是
False,或在别处显式把这个节点的screenshot_before_round关掉),那这里的last_screenshot可能是上一节点甚至上一轮的画面,极端情况下为None,后续crop_image/ OCR / 模板匹配都会出问题。建议你确认一下这个节点当前的装饰器配置,必要时可以显式加上
screenshot_before_round=True,或在框架层保证 start node 一定会刷新last_screenshot,以避免隐蔽回归。src/sr_od/sr_map/operations/choose_planet.py (1)
34-34: Verify screenshot freshness in retry loop before choosing planetChanging from
self.screenshot()toself.last_screenshotrequires confirming that the operation framework guarantees fresh screenshots in the following scenarios:
- At operation start:
last_screenshotmust be current when this start node first executes- Between retries: The screenshot must be refreshed before each retry attempt (up to 10 retries allowed), since the method performs screen state changes (clicks, drags) that require detecting updated visual state
Without verification that the framework updates
last_screenshotat these critical points, the method risks using stale screenshots for planet detection, causing incorrect navigation or retry exhaustion.Confirm the screenshot update mechanism in:
- Operation framework initialization before start nodes
- Retry loop execution between attempts
- Whether
screenshot_before_roundor similar mechanism appliessrc/sr_od/app/sim_uni/operations/sim_uni_enter_fight.py (1)
82-84: Verify thatoperation_nodeframework guarantees fresh screenshots before each round.This change replaces
self.screenshot()withself.last_screenshot, which aligns with the PR's goal of reducing redundant screenshots. However, this method uses the screenshot for critical real-time operations: game state detection (line 92-94), attack logic (line 103), and non-world state handling (line 107).Since the decorator does not specify
screenshot_before_round=False, the framework should automatically updateself.last_screenshotbefore the operation executes. Confirm that:
- The
operation_nodeframework guaranteeslast_screenshotis refreshed before each round by default- This guarantee applies to nodes with
is_start_node=True- No other
self.screenshot()calls remain in this method that would indicate inconsistent screenshot sourcingWithout this confirmation, the change risks using stale screenshot data for critical game state decisions.
src/sr_od/operations/cancel_mission_trace.py (1)
47-47: 验证操作节点间的截图更新时机将
self.screenshot()改为self.last_screenshot会影响截图的时效性。_cancel_trace方法需要基于上一个节点_try_open_mission点击后的屏幕状态来判断:
- 第48行:
is_normal_in_world检查是否仍在大世界- 第52行:
round_by_find_and_click_area查找并点击"停止追踪"按钮请确认操作框架在执行
_try_open_mission的点击操作后、进入_cancel_trace之前,会自动更新last_screenshot。如果last_screenshot保存的是点击前的旧截图,可能导致误判或找不到按钮。src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py (3)
146-189: 确认 Line 154 保留screenshot()的设计意图注意到
_detect_screen方法在 Line 154 仍然使用self.screenshot(),而不是self.last_screenshot。这与本次 PR 的整体方向不一致。由于该方法在 Line 152 先调用了
self._view_down()改变视角,因此 Line 154 需要获取视角调整后的新截图进行 YOLO 检测。如果是这个原因,当前实现是正确的。请确认这是有意为之,还是遗漏了修改。
43-52: Verify start nodelast_screenshotinitialization
before_routeis decorated as a start node (is_start_node=True). When first executed,self.last_screenshotmay not be initialized or may contain stale data from a previous operation. Confirm whether the operation framework automatically captures a screenshot before executing start nodes. If not, usinglast_screenshothere could causecheck_angle(screen)to fail with invalid or missing data.
70-87: 验证缓存截图对战斗检测的时效性影响在战斗场景中,使用
self.last_screenshot可能导致系统基于过期信息做出判断。特别是在快速变化的战斗环境中(如敌人移动、被锁定提示等),延迟可能影响检测准确性。建议确认:
- 操作框架是否在每轮执行前自动截图,确保
last_screenshot足够新鲜- 缓存截图的时间间隔是否会影响小地图红点检测和屏幕状态识别的准确性
- 如有必要,在装饰器中添加
screenshot_before_round=False以获取实时截图src/sr_od/app/sim_uni/operations/move_v1/move_to_next_level.py (3)
121-121: 确认循环执行中的截图刷新策略。此方法通过
round_wait()多次循环执行,期间涉及时间敏感的状态检测:
- Line 123: 战斗状态检测
- Line 155: 入口检测(视角旋转后需要新截图)
- Line 234: 交互提示检测(移动后需要实时状态)
如果
self.last_screenshot在每次 round 循环开始前未自动刷新,可能导致:
- 移动后交互提示已出现,但使用旧截图未能检测到
- 已进入战斗,但旧截图显示仍在大世界
- 视角旋转后入口已可见,但旧截图显示未找到入口
请确认操作框架在每次
round_wait()/round_retry()返回后重新执行节点前,是否会自动刷新self.last_screenshot。
261-261: 验证节点间截图的时效性。此节点在
_move_and_interact完成后执行,用于检测并点击精英层的确认按钮。使用self.last_screenshot需要确认:
- 节点切换时(从
_move_and_interact到_confirm)是否会自动刷新截图- Line 263 的 OCR 识别和点击操作依赖当前屏幕状态,使用过期截图可能导致识别失败
虽然此节点的重试机制(line 269)可以缓解问题,但如果截图未在节点开始时刷新,可能增加不必要的重试次数。
99-99: Verify thatself.last_screenshotis populated before start node execution.As a start node (
is_start_node=True), confirm the operation framework refreshesself.last_screenshotbefore executing this node. If the framework doesn't guarantee this, the cached screenshot may beNoneor stale, causing:
- Line 101: combat detection to fail or miss active combat state
- Line 112: mini map analysis to use incorrect data
Verify the timing guarantee in the operation framework's
operation_nodedecorator and round execution logic.src/sr_od/sr_map/operations/choose_region.py (3)
46-46: Verify thatlast_screenshotis properly refreshed on retry before using it in retry logic.This change replaces
self.screenshot()calls withself.last_screenshotin methods that use retry logic (round_retry()). The safety of this change depends on whether the operation framework captures a fresh screenshot before each retry attempt. Verify that the@operation_nodedecorator ensureslast_screenshotis updated to the current state whenround_retry()is called, especially in_choose_sub_regionwhich hasnode_max_retry_times=20and performs multiple UI interactions (clicks, scrolls, drags). Iflast_screenshotis not refreshed on retry, the logic may operate on stale screenshots.
194-220: 验证高频重试场景下截图更新的正确性。此方法允许最多 20 次重试,且包含多个会改变屏幕状态的 UI 交互(拖动地图、点击子区域入口)。关键问题:
- Line 196 的
_in_sub_region(screen)检测依赖当前屏幕状态,如果screen为旧截图会误判- Line 199 的地图匹配依赖当前地图位置,拖动后使用旧截图会计算错误偏移
- 基于错误偏移计算的点击坐标可能点击错误位置
需要验证操作节点在重试时的截图刷新机制,特别是
last_screenshot何时更新以及每次重试是否捕获新截图。
57-92: Verify screenshot refresh timing between operation retries.This method returns
round_retry(wait=1)after clicking (line 78) or scrolling (line 89). The concern is whether the framework captures a fresh screenshot before re-invoking this operation on the next cycle. Iflast_screenshotis stale, OCR on line 64 and region matching on lines 72–78 could read incorrect UI state, potentially causing wrong selections or infinite retries.Confirm with the operation framework that
last_screenshotis updated by the framework before each operation invocation, not reused across retry cycles.src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py (4)
179-213: 确认后的状态判断依赖最新截图该方法在点击确认后判断画面状态(line 185-192),需要准确识别当前是否仍在选择奇物页面(line 199),或已转换到其他状态(祝福、丢弃奇物等)。使用
last_screenshot可能无法捕捉到点击后的最新UI状态,导致:
- Line 199 误判为仍在选择奇物页面
- 错误地递减
curio_cnt_type(line 203)- 进入错误的控制流分支
建议验证在方法执行时
last_screenshot是否已更新为点击确认后的最新画面。
255-267: 起始节点的屏幕状态检测需要最新截图作为操作的起始节点,该方法使用
last_screenshot进行状态检测(line 262)。如果last_screenshot不是进入该操作时的最新截图,可能导致:
- 无法正确检测到丢弃奇物页面(line 262)
- 触发不必要的重试(line 267)
- 与
skip_first_screen_check优化逻辑冲突(line 258-260直接假设状态正确)需要确认起始节点执行时
last_screenshot是否已更新。
272-283: OCR识别依赖准确的截图该方法使用
last_screenshot进行奇物的OCR识别(通过_get_curio_pos在line 275调用),并基于识别结果计算点击位置(line 280)。使用过期的截图可能导致:
- OCR识别到错误的奇物名称
- 点击位置计算错误(尤其当
curio_cnt_type变化导致使用不同的RECT列表时)- 重试逻辑(line 270,从'确认'节点返回)中使用了错误的基准截图
这与 SimUniChooseCurio._choose_curio 存在相同的风险。
79-95: 验证last_screenshot的时效性该方法使用
self.last_screenshot替代了self.screenshot(),依赖缓存的截图进行屏幕状态检测(line 84)和OCR识别奇物(通过_get_curio_pos调用)。如果last_screenshot不是最新的,可能导致:
- 识别到错误的奇物
- 点击错误的位置
- 屏幕状态判断失败
请确认
@operation_node装饰器是否会在方法执行前自动更新last_screenshot,以保证截图的时效性。src/sr_od/challenge_mission/choose_support_in_team.py (6)
50-59: 代码看起来不错
click_support节点使用last_screenshot是合理的,因为它依赖于上一个节点的执行,框架应该已经在本轮开始时捕获了新截图。
90-99: 代码看起来不错
click_join节点使用last_screenshot是合理的,该节点在点击头像后执行,框架应该已经捕获了新截图。
146-155: 代码看起来不错
wait_at_last节点使用last_screenshot是合理的,作为终止节点,它在等待画面加载完成,框架应该在每轮重试时捕获新截图。
101-144: 保留了防御性代码,值得肯定
_get_character_pos方法在第 107 行保留了当screen参数为None时调用self.screenshot()的后备逻辑。虽然在正常流程中不会触发(因为调用时总是传入last_screenshot),但这是良好的防御性编程实践。
34-48: Screenshot availability in start nodes requires framework verificationThe concern about
last_screenshotavailability in the start node (is_start_node=Trueat line 39) cannot be verified without access to the operation framework implementation. The review question is valid: if the framework does not automatically capture and store a screenshot before executing start nodes, usingself.last_screenshotinstead ofself.screenshot()will cause recognition failures when the node first executes andlast_screenshotisNoneor stale.This requires confirmation that:
- The operation framework captures a screenshot before executing start nodes and stores it in
last_screenshot- OR the framework ensures
last_screenshotis properly initialized for start nodes before their executionWithout this guarantee, start node screenshots should use
self.screenshot()to ensure a fresh capture is available.
62-88: 验证拖动操作后的截图更新
click_avatar方法在第 81 行执行拖动操作来滚动支援角色列表,然后在第 82 行以wait=2进行重试。需要确认重试时框架是否会捕获新截图以识别滚动后的内容,以及last_screenshot在下一轮开始时是否会更新为拖动后的画面。如果重试时使用的仍是拖动前的旧截图,
_get_character_pos()调用将无法识别新滚动出来的角色。请检查round_retry()方法的实现和operation_node装饰器的执行逻辑,确认截图的更新时机。src/sr_od/app/sim_uni/operations/move_v2/sim_uni_move_to_next_level_v3.py (6)
103-103: 改动合理作为操作节点,使用
self.last_screenshot应该能获取到框架提供的最新截图,适合用于小地图角度分析。
132-132: 改动合理特征匹配依赖准确的屏幕状态,作为操作节点应该能获取到最新的截图。
156-163: 正确处理了截图时机第 156 行使用
self.last_screenshot获取初始屏幕状态是合理的。更重要的是,第 163 行在sleep(1)之后仍然保留了显式的self.screenshot()调用,这是正确的做法,因为休眠后屏幕状态已经发生变化,需要获取最新的截图。这体现了对截图时机的准确把握。
181-181: 改动合理移动前的交互词识别使用
self.last_screenshot是合理的,框架应该会在节点执行前提供最新截图。
321-321: 改动合理确认操作对时间敏感度较低,使用
self.last_screenshot是合理的。
74-74: Verify thatself.last_screenshotis guaranteed to be fresh at operation_node entryThis method relies on YOLO detection with accurate screen state. Confirm the operation_node framework updates
self.last_screenshotbefore each node execution to ensure detection accuracy remains unaffected.src/sr_od/operations/move/move_without_pos.py (1)
42-51: Verify thatlast_screenshotis valid when start node executesThe
_turnmethod is marked withis_start_node=True, designating it as the operation's entry point. The refactored code now usesself.last_screenshotinstead ofself.screenshot()for mini-map angle analysis, which directly affects turning direction accuracy.Confirm that the operation framework guarantees a fresh, valid screenshot before executing start nodes. If there is no such guarantee, refactor to explicitly call
self.screenshot()to ensure the mini-map analysis receives current screen state.src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py (1)
145-165: Verify the inconsistent parameter order inin_sim_uni_choose_blesscallsThe function is called with different parameter orders in the same file:
in_sim_uni_choose_bless(self.ctx, screen)atwait_not_in_bless(lines 145-165)in_sim_uni_choose_bless(screen, self.ctx.ocr)atfirst_waitThis inconsistency needs to be resolved by checking the actual function signature and ensuring all call sites use the correct parameter order and types. Update both calls to match the intended signature and the rest of the codebase.
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)的@operation_node都没有显式设置screenshot_before_round,按照当前基类实现默认是True,框架在每轮节点执行前会先自动截图并写入self.last_screenshot。在这种前提下,把节点内部的self.screenshot()替换为复用self.last_screenshot,只去掉了同一轮内的重复截图,对逻辑没有实质性改变,同时能减少一次屏幕抓取的开销。_detect_reward往往在_after_fight后执行,而_after_fight内部会调整视角;由于“识别沉浸奖励”节点自身也会在进入前自动截图,所以这里的last_screenshot应该是调整视角之后的画面,这一点与之前“在节点体内再手动self.screenshot()”的效果保持一致。- 小提醒(非阻塞):如果将来在单测或调试中有直接调用这些节点方法(绕过
Operation.execute()/ 节点调度)的用法,需要事先保证last_screenshot已经被填充,否则传入None给小地图/YOLO 相关函数可能会抛异常。现在的代码假设节点总是通过框架正常运行,这点可以在使用文档或测试里约定清楚即可。Also applies to: 55-72, 125-163
src/sr_od/operations/back_to_normal_world_plus.py (1)
26-108: 改用last_screenshot的前提假设需要确认这里改为直接使用
self.last_screenshot,能避免在节点内重复截屏,整体逻辑与之前一致,看起来是本 PR 期望的方向。唯一需要确认的一点是:当前 operation 框架是否在每一轮进入节点前,都会统一刷新一次
last_screenshot。如果没有统一刷新,而是依赖各节点自己调用self.screenshot(),那这次改动可能会在某些轮次上使用到过期画面,影响状态判断。建议你确认下基类
SrOperation/ 调度器对last_screenshot的维护策略,确保这一节点在每轮执行前都能拿到最新画面;如果是的,那这个改动就是安全的性能优化。src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_mm.py (1)
57-103: 使用last_screenshot与全局改动保持一致这里将
_execute_one_round内部的截屏改为复用self.last_screenshot,配合统一的截屏机制,可以减少重复 I/O,逻辑本身未改变。在前一个评论中已经提到:前提是框架在每轮进入节点前会刷新
last_screenshot。在该前提成立的情况下,这里改动是合理且推荐的。src/sr_od/app/sim_uni/operations/auto_run/reset_sim_uni_level.py (1)
32-45: 节点内复用last_screenshot合理
_temp_leave现在直接用self.last_screenshot做区域识别,配合统一截屏逻辑,可以避免节点内多余的screenshot()调用,成功/失败分支控制流均保持不变。在框架统一刷新
last_screenshot的前提下,这里改动没有风险。src/sr_od/sr_map/operations/choose_floor.py (1)
25-47: 选择楼层逻辑保持不变,仅复用缓存截图
check_screen改为使用self.last_screenshot,后续获取当前楼层、点击目标楼层、返回成功/重试的逻辑完全不变;在统一截屏机制下,这里只是去掉重复截屏,改动安全。src/sr_od/operations/wait/wait_in_world.py (1)
29-35: 等待主界面的状态判断改为复用last_screenshot这里用
self.last_screenshot判断是否进入大世界主界面,成功后等待wait_after_success,否则 1 秒后重试,控制流完全一致。结合统一截屏,这里去掉节点内的额外截屏是合理的。src/sr_od/app/world_patrol/world_patrol_enter_fight.py (1)
68-94: 进入战斗主循环改为使用缓存截图
run现在用self.last_screenshot作为本轮画面,后续状态机(大世界 / 战斗 / 未知)以及_try_attack/_handle_not_in_world的调用路径都未改动。只要调度器在每轮 node 调用前更新
last_screenshot,这里就是纯粹减少重复截屏的优化。src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_interact_by_detect.py (1)
68-85: 移动到交互目标节点改为复用最后一帧截图
move使用self.last_screenshot后,后续_check_interact_word、handle_in_world中的 OCR 与 YOLO 检测仍基于同一帧,逻辑顺序保持不变;interact_during_move分支的在/不在大世界判断也仍然可靠。在统一由框架刷新
last_screenshot的前提下,这里去掉显式self.screenshot()调用是合适的。src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_world.py (1)
83-115: 战败结算相关节点统一改为使用last_screenshot
battle_fail_exit、battle_fail_exit_confirm和click_empty三个节点都改为基于self.last_screenshot做一次性的区域查找并点击,success_wait/retry_wait等参数和返回语义完全没变。这与本 PR 其它位置的改法一致,可以避免节点内重复截屏,前提同样是调度器在每轮执行节点前会刷新
last_screenshot。src/sr_od/app/sim_uni/operations/sim_uni_exit.py (3)
37-37: 节点入口使用last_screenshot是合理的。在操作节点的起始检测中使用
last_screenshot是合理的优化,框架应该在节点执行前已经更新了截图。
70-82: 验证操作后截图是否及时更新。此方法在
open_menu后执行(wait=1秒),需要检测菜单打开后的画面。使用last_screenshot的前提是框架在前一个节点的wait完成后重新截图。如果
last_screenshot仍是菜单打开前的画面,将无法正确识别菜单选项。建议验证在
round_success(wait=1)后,下一个节点执行前框架是否更新last_screenshot。
86-93: 连续UI操作需要确保截图时效性。
click_confirm和click_empty方法依赖于前序操作完成后的最新画面。如果last_screenshot没有在节点切换时更新,可能导致:
- 识别不到新出现的确认对话框
- 点击位置基于旧画面而失效
Also applies to: 97-104
src/sr_od/operations/battle/start_fight_for_elite.py (1)
192-205: 战斗状态判断需要最新的屏幕状态。
_attack方法在使用秘技后执行,需要判断是否已进入战斗。使用last_screenshot存在时序风险:如果使用秘技后立即触发战斗,但
last_screenshot还是触发前的画面,会导致:
- 误判为"仍在大世界"
- 重复调用
initiate_attack()- 可能影响战斗流程
建议验证框架是否在节点切换时自动更新截图,特别是在战斗状态可能快速变化的场景。
src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (2)
20-33: 起始节点使用last_screenshot合理。作为起始节点,框架应该在执行前已更新截图,使用
last_screenshot是合理的优化。
36-46: UI交互流程依赖节点间的截图更新。
_check_reward和_claim_reward方法依次执行,每个方法都需要基于前一步操作后的最新画面。使用last_screenshot的前提是框架在节点切换时自动更新截图。如果框架行为符合预期,这个变更可以有效减少冗余截图。
建议验证节点切换时框架的截图更新机制,确保每个节点看到的是最新状态。
src/sr_od/app/sim_uni/operations/battle/sim_uni_fight_elite.py (2)
32-49: 敌人检测需要实时画面数据。
_check_enemy使用OCR和YOLO进行敌人检测,对截图时效性要求较高。如果last_screenshot不够新,可能导致:
- 敌人位置识别滞后
- 锁定状态检测延迟
- 影响战斗触发时机
建议确认框架在此节点执行前已更新截图。
58-68: 战斗进入判断的时效性风险。
_fight方法在使用秘技后执行,需要判断是否成功进入战斗。使用last_screenshot可能导致判断延迟,特别是在使用远程攻击角色时,战斗触发可能有延迟。src/sr_od/operations/team/choose_support.py (2)
40-50: UI识别节点使用last_screenshot合理。作为起始节点的画面识别,使用
last_screenshot是合理的优化。
52-74: 角色选择流程依赖截图更新机制。
choose_support和click_join构成了选择角色的完整流程。使用last_screenshot的前提是:
- 点击头像后,框架更新截图以显示入队按钮
- 节点切换时自动刷新画面状态
如果框架行为符合预期,这个变更可以减少不必要的截图操作。
建议验证UI交互流程中节点切换时的截图更新时机。
src/sr_od/app/nameless_honor/nameless_honor_app.py (1)
104-123: 奖励领取后的状态检测需要最新截图。
_check_screen_after_reward在奖励领取后执行,需要检测可能出现的选择奖励弹窗。使用last_screenshot存在时序风险:前一个节点
_claim_reward执行后等待2秒(success_wait=2),这期间画面可能发生变化(弹窗出现)。如果last_screenshot没有在等待后更新,将无法检测到新出现的UI元素。建议验证框架在
success_wait后、下一个节点执行前是否更新last_screenshot。src/sr_od/sr_map/operations/open_map.py (1)
21-21: Verify that theoperation_nodedecorator updateslast_screenshotbefore execution.The change to use
self.last_screenshotat line 21 in the check_screen method is a reasonable optimization for a start node. However, confirmation is needed that theoperation_nodedecorator (withis_start_node=True) guaranteeslast_screenshotis updated before the node executes, to ensure accurate state detection.src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_detect.py (1)
44-64: Verify whetherlast_screenshotis refreshed between operation iterations.This method is a long-running operation (
timeout_seconds=20) that continuously monitors screen state. The review concern is valid: if the framework captures the screenshot only once when the node starts, subsequent loop iterations throughround_retry()orround_wait()will operate on stale data, potentially missing:
- Real-time detection of being locked by enemies
- Current enemy positions
- Accurate movement decisions
This needs verification against the framework's operation lifecycle implementation to confirm whether
last_screenshotis automatically refreshed on each iteration or remains static throughout the operation's lifetime.src/sr_od/app/sim_uni/sim_uni_app.py (1)
81-88: 使用 last_screenshot 与节点预截图逻辑保持一致
_check_initial_screen在节点开始直接使用self.last_screenshot,结合operation_node默认的screenshot_before_round=True,等价于每轮只截一次图并在本轮内复用,行为与之前在函数内主动截图一致,同时符合本 PR 减少冗余截图的目标。src/sr_od/operations/store/buy_store_item.py (1)
32-42: 商店购买流程统一改用 last_screenshot,语义保持不变
choose_item/choose_buy_num/buy_confirm/click_empty四个节点都在方法开始读取一次self.last_screenshot,配合默认的screenshot_before_round=True,等价于每轮开始时截图一次并在节点内复用;这些方法在读取screen之前没有额外交互操作,因此与之前使用self.screenshot()的行为基本一致,只是去掉了重复截图调用。Also applies to: 66-69, 77-88, 96-98
src/sr_od/app/div_uni/operations/choose_oe_support.py (1)
36-38: 饰品支援选择流程改用 last_screenshot 合理
check_screen/click_support/choose_support均在节点开始读取self.last_screenshot,节点本身依然依赖默认的screenshot_before_round=True获取当前帧,因此只减少了多余的截图库调用;函数内部在使用screen前没有修改画面,round_by_find_area与ChooseSupport.click_avatar的识别时机与之前保持一致。Also applies to: 47-49, 58-62
src/sr_od/app/relic_salvage/relic_salvage_app.py (1)
29-31: 遗器分解流程多处改用 last_screenshot,与自动截图机制兼容“快速选择”“选择等级/弃置”“快速选择确认”“点击分解/确认”等节点都在一轮开始时直接使用
self.last_screenshot做区域匹配和点击,节点内只有一次点击操作,由框架在下一轮进入前重新截图,因此整体时序与之前在节点中主动截图保持一致,只是减少了冗余的截图调用。Also applies to: 36-40, 45-48, 57-59, 64-66, 71-73
src/sr_od/app/sim_uni/operations/event/sim_uni_reward.py (1)
44-68: 模拟宇宙沉浸奖励相关节点改用 last_screenshot,时序正确
_get_reward/_click_empty/_check_state都在节点开始使用self.last_screenshot进行画面识别,依赖框架在每轮进入节点前自动截图;点击领取奖励、点击空白关闭等操作发生后,下一节点会重新截图,因此各步骤的状态判断仍然基于最新一帧。本次仅去除了节点内部重复截图,对奖励上限判断和状态流转没有功能性影响。Also applies to: 94-101, 110-115
src/sr_od/operations/technique.py (1)
116-124: 秘技与快速恢复相关节点统一使用 last_screenshot,行为保持不变
UseTechnique._check_technique_point/CheckTechniquePoint.check依然在进入节点前由框架截图,然后用last_screenshot识别秘技点数和是否在大世界界面;UseTechnique._use仅在尚未出现对话框且需检查可用性时读取屏幕文字,之后才调用use_technique,不会读到被自身操作改变后的旧帧;_confirm/_wait_in_world_to_other以及FastRecover.use/wait_in_world/fail_check_screen在读取screen之前没有新的点击或拖动操作,仍然是一轮一截一用;总体来看,这些改动只是把原先在方法里的
self.screenshot()替换为对每轮自动截图的复用,在状态机逻辑和画面判断时机上与旧实现一致,同时减少了高频场景中的截图库调用。Also applies to: 132-135, 153-181, 196-210, 226-235, 263-266, 280-284, 294-301
src/sr_od/app/div_uni/operations/choose_oe_file.py (1)
33-43: 选择存档节点关闭自动截图并保留一次手动截图是合理的
check_screen/click_switch_file/wait_management_screen改为使用self.last_screenshot,依赖默认的screenshot_before_round=True,每轮只用框架自动截图一帧进行识别,去掉了函数内重复截图;choose_file显式设置screenshot_before_round=False,先根据配置点击目标档案并稍作等待,再手动调用一次self.screenshot(),随后所有“确认切换/已使用中”的识别都基于这张新截图,避免了在点击前后各截一次图的浪费,也保证了判断发生在 UI 更新之后;- 函数内所有使用
screen的地方都在这次手动截图之后执行,不会出现读取过期帧的情况。建议实际在游戏内分别测试 1~4 号档案以及“档案使用中”的分支,确认画面切换和按钮识别的时机与预期一致。
Also applies to: 52-55, 63-66, 69-97
src/sr_od/app/daily_training/daily_training_app.py (1)
70-85: 每日实训领取奖励改用 last_screenshot 与其他模块保持一致
claim_reward通过self.last_screenshot获取当前画面做“指南/每日实训”二级 UI 判断以及奖励按钮位置计算,依赖节点进入前的自动截图,不再在方法内额外截图;逻辑与原实现等价,同时与本 PR 在其他模块中的用法保持一致。src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.py (2)
44-47: 统一使用 last_screenshot 获取当前帧,避免重复截图before_route 和
_check_mm_icon都改为使用self.last_screenshot,且在读取screen之前没有移动/旋转等改动画面的操作,配合operation_node默认的screenshot_before_round=True,每轮仍然只基于最新一帧做角度与小地图识别,只是去掉了多余的self.screenshot()调用,行为是等价的。Also applies to: 63-76
92-101: _detect_screen 关闭前置截图与内部手动截图逻辑一致这里给
_detect_screen的装饰器加上screenshot_before_round=False,而函数内部在_view_down()之后再调用self.screenshot()获取screen,避免了一轮内“先自动截一张、再手动截一张”的浪费,同时保证用于 YOLO 检测的是视角调整后的画面,这个改动是合理的。src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_respite_route_v2.py (1)
37-40: before_route / _check_mm_icon 使用 last_screenshot 的改动是安全的这两个节点只是读取当前小地图和朝向,没有在读取
screen前做移动/转向等操作,且装饰器均使用默认screenshot_before_round=True,因此每轮进入节点前都会更新last_screenshot。直接复用self.last_screenshot可以减少一次重复截图,原有识别语义不变。Also applies to: 71-82
src/sr_od/app/sim_uni/operations/auto_run/sim_uni_wait_level_start.py (1)
36-49: check_screen 改用 last_screenshot 与重试机制契合作为起始节点并带有
node_max_retry_times,每轮进入时框架都会截一次图更新last_screenshot;这里直接复用self.last_screenshot来做状态判断即可,去掉内部额外的self.screenshot(),不会改变分支逻辑。src/sr_od/app/sim_uni/operations/bless/sim_uni_upgrade_bless.py (1)
45-57: 本类各节点统一改用 last_screenshot,符合操作节点截屏约定
check_left/check_can_upgrade/choose_bless/upgrade/click_empty均改为从self.last_screenshot获取screen,而这些节点在读取前都只是做状态识别和点击决定,没有先移动视角或触发会立刻刷新的动画;装饰器也沿用默认screenshot_before_round=True。因此每轮只会在进入节点前截一次图,OCR 与模板匹配仍基于当前帧,原有功能语义保持不变,同时去掉了多处重复的self.screenshot()调用。Also applies to: 75-77, 123-133, 141-150, 167-175
src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_level.py (1)
111-118: 楼层类型与路线匹配改用 last_screenshot,避免多余截图
_check_level_type和_check_route现在都直接使用self.last_screenshot来做楼层类型与小地图路线匹配,这两个节点在读取前没有进行移动或其他会改变画面的操作,并且节点装饰器仍使用默认screenshot_before_round=True。这样每轮识别仍基于最新一帧,只是省掉了函数内部的重复截屏,对匹配稳定性没有负面影响。Also applies to: 133-149
src/sr_od/app/sim_uni/operations/sim_uni_event.py (1)
61-66: SimUniEvent 中四处改用 last_screenshot,与事件状态机逻辑一致
_wait、_choose_opt_by_priority、_confirm和_check_after_confirm都改为使用self.last_screenshot作为当前帧,节点在读取screen前没有实际改动画面(只是更新了标志位),且装饰器保持默认screenshot_before_round=True。因此每轮事件识别、选项 OCR、确定按钮点击以及确定后的页面分流仍然基于同一帧画面,行为与之前一致,同时减少了多次重复截图。Also applies to: 77-90, 169-179, 242-247
src/sr_od/operations/enter_game/enter_game.py (1)
45-59: EnterGame 多处改用 last_screenshot,与登录状态判断流程兼容
check_screen、input_account_password以及choose_other_account都改为使用self.last_screenshot作为当前画面输入,这些节点在读取screen前没有进行新的点击或移动,且装饰器保持默认screenshot_before_round=True,所以每轮进入节点时都会拿到最新一帧。随后真正进入游戏前仍会重新截一张图传给round_by_find_and_click_area做最终按钮点击,整体登录与换号流程的语义不变,只是去掉了多余的self.screenshot()。Also applies to: 119-148, 161-163
src/sr_od/interastral_peace_guide/open_guide.py (2)
19-23: 确认起始节点的截图初始化作为起始节点(
is_start_node=True),该方法依赖self.last_screenshot进行画面识别。请确认操作框架在执行起始节点前会自动初始化last_screenshot,否则可能导致None引用错误。
46-52: 等待循环中使用缓存截图可能导致状态检测延迟该方法在等待加载循环中使用
self.last_screenshot检测 UI 是否已加载完成。如果last_screenshot未在每次重试前更新,将会检测到过时的屏幕状态,可能导致:
- 无法及时发现加载完成
- 等待时间不必要地延长
- 重试逻辑失效
请确认操作框架是否在每次节点重试执行前自动刷新
last_screenshot。src/sr_od/interastral_peace_guide/guide_transport.py (1)
48-71: 重试循环中的截图时效性问题该等待节点设置了最多20次重试(
node_max_retry_times=20),使用self.last_screenshot检测加载完成状态。如果每次重试时last_screenshot没有更新,会导致:
- 重复检测同一张过时截图
- 即使屏幕已加载完成也无法检测到
- 可能耗尽所有重试次数后失败
建议验证操作框架是否在每次重试前自动刷新截图,或考虑在关键等待节点使用
self.screenshot()获取实时状态。src/sr_od/interastral_peace_guide/guide_choose_category.py (2)
29-36: 等待画面加载时的截图更新机制该起始节点在等待画面加载时(最多重试5次)使用
self.last_screenshot检测当前UI状态。与其他文件中的类似等待循环一样,需要确认每次重试前截图是否更新,以避免重复检测过时的屏幕状态。
38-60: OCR 操作的截图新鲜度该方法使用
self.last_screenshot进行 OCR 识别和点击操作。虽然前置的wait_screen节点应该已确保屏幕稳定,但如果在两个节点之间存在状态变化(如动画、加载),可能影响识别准确性。建议验证节点间截图更新策略是否满足需求。src/sr_od/interastral_peace_guide/guide_check_power.py (1)
42-44: Verify screenshot freshness guarantees for OCR accuracyThe
check_powermethod relies onself.last_screenshotfor OCR-based detection of power and quantity values. Confirm whether:
- The
@operation_nodedecorator automatically refresheslast_screenshotbefore executing each node- The screen state remains stable between
choose_guide_tabcompletion andcheck_powerexecution
a2830ab to
ddac058
Compare
There was a problem hiding this 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/challenge_mission/use_trailblaze_power.py (1)
1-1: 移除未使用的PIL.ImageChops.screen导入,避免 F811 警告Ruff 报的 F811(“Redefinition of unused
screenfrom line 1”)来自这里:本文件中没有地方把PIL.ImageChops.screen当函数调用,screen只作为局部变量保存截图使用,因此这个导入是未使用且被后面的局部变量反复重定义。建议直接删除该导入,既能消掉 F811,也避免命名冲突:
-from PIL.ImageChops import screen如果以后确实需要
ImageChops.screen,再用别名导入(例如from PIL import ImageChops as _ImageChops)以避免和局部变量同名。
♻️ Duplicate comments (1)
src/sr_od/sr_map/operations/choose_planet.py (1)
34-34: 验证重试时的截图刷新机制(同样的问题)与
choose_special_point.py相同,此方法也从self.screenshot()改为self.last_screenshot,且包含重试逻辑(第 76 行)。特别关注第 71-76 行的逻辑:
- 当前屏幕未找到目标星球时,执行拖动操作滚动星球列表
- 然后返回
round_retry期望在下次迭代中看到不同的星球- 如果
last_screenshot在重试时未刷新,拖动后仍会看到相同的星球列表,导致重复无效拖动需要确认框架在重试前是否刷新
last_screenshot。
🧹 Nitpick comments (8)
src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_path.py (1)
55-60: 确认“确认命途”节点使用缓存截图不会引入时序问题
_confirm_path也改为使用self.last_screenshot,避免再次截图,本身是对 PR 目标一致的优化。但与上一个节点不同,这里直接做一次
round_by_find_and_click_area,没有额外的页面状态检查;它通常紧跟在“选择命途”之后,如果两节点之间 UI 有渐变/弹窗变化,而框架又没有在本节点开始前自动更新last_screenshot,就可能出现:
- 之前行为:
self.screenshot()拿到的是“确认命途”按钮已经出现后的最新画面。- 现在行为:沿用上一个节点的截图,按钮可能尚未出现,导致多次重试点击失败。
建议你在实际环境下验证一遍:在路径切换较慢、或窗口切出/切回等边缘情况下,这个节点依然能稳定识别并点击确认按钮。如果后续发现时序比较敏感,这里可以单独保守些继续用一次主动截图,或者在装饰器上显式要求本轮前必须截图。
src/sr_od/app/sim_uni/operations/sim_uni_exit.py (1)
71-82:click_exit使用上一轮截图,需要确认与菜单弹出时机的一致性这里不再主动截屏,而是依赖进入该节点前由装饰器更新的
last_screenshot。逻辑本身保持不变,area_list与点击流程也未改动。建议确认:
open_menu对应的operation_node没有设置screenshot_before_round=False,且状态机在从“打开菜单”跳转到“点击结算”前,会开启新一轮并完成截图;- 不存在中途额外等待或动画导致菜单完全展开晚于截图时刻的情况,否则可能会出现误判找不到区域。
如果上述流程在其它模块里已经统一调整过,可以在后续清理中顺带补一条注释说明依赖的是“当前轮截图”,方便以后维护。
src/sr_od/challenge_mission/choose_support_in_team.py (1)
61-89: 头像识别复用同一帧截图,行为更一致这里将
screen设为self.last_screenshot并传入_get_character_pos(screen):
- 头像定位与后续点击使用同一帧画面,比之前在
_get_character_pos里再单独截图更一致,也避免了单轮内的多次截图。- 当找不到角色并执行拖动后,下一轮重试时会重新进入节点(通常会重新截图并更新
last_screenshot),滚动后的画面也能被使用,流程上是自洽的。如果将来确认所有调用方都能保证传入
screen,可以考虑在_get_character_pos里移除内部self.screenshot()作为冗余兜底,但这属于后续小优化,不是本 PR 必须修改的内容。src/sr_od/challenge_mission/use_trailblaze_power.py (4)
103-124:confirm_after_click_challenge改用last_screenshot,需确保节点前会自动截图这里从
self.screenshot()改成了复用self.last_screenshot,逻辑上没变,但多了一个前置条件:进入本节点前,框架必须已经刷新过last_screenshot(通常是@operation_node默认的screenshot_before_round=True帮你调过一次截图)。如果以后有人在装饰器上加了
screenshot_before_round=False,这里就会拿到上一个节点的截图(比如“点击挑战”那一拍),有一定风险找不到刚弹出的对话框。建议:
- 确认当前这个节点的
operation_node没有关闭自动截图,且未来也不打算关;- 可选兜底:在
last_screenshot为空时退回到主动截图,增强鲁棒性,例如:- screen = self.last_screenshot + screen = self.last_screenshot or self.screenshot()
150-176:_after_start_challenge同样依赖装饰器刷新last_screenshot这里与上面的
confirm_after_click_challenge类似,从主动截图改为使用self.last_screenshot,可以减少一次截图,但前提是本节点开始前last_screenshot已被自动更新。同样建议:
- 确认该节点的
@operation_node(name='开始挑战后')没有配置screenshot_before_round=False;- 如果担心未来有人调整装饰器,可以考虑加一个
or self.screenshot()的兜底,保持行为稳定。
181-223: 战斗结果阶段last_screenshot的时效性需要确认这里
_wait_battle_result里仍然是主动self.screenshot()轮询状态,而_after_battle_result改成了使用self.last_screenshot:def _wait_battle_result(...): screen = self.screenshot() ... def _after_battle_result(...): screen = self.last_screenshot ...行为是否等价取决于框架流程:
- 如果进入
_after_battle_result前,operation_node会再自动截图一次并写回last_screenshot,那现在只是去掉了一次冗余截图,逻辑保持不变;- 如果该节点现在或将来配置
screenshot_before_round=False,那这里拿到的是_wait_battle_result最后一帧的截图,而不是“等待 1 秒后”的当前画面,存在 UI 动画尚未结束、按钮位置变化等小概率风险。建议:
- 明确
_after_battle_result的装饰器是否保证每轮进入前一定会刷新last_screenshot;- 如果希望更稳健,可以同样加兜底:
- screen = self.last_screenshot + screen = self.last_screenshot or self.screenshot()另外,从“减少冗余截图”的角度看,后续也可以评估
_wait_battle_result是否有机会改成依赖框架的自动截图,以进一步统一截图策略(非本次 PR 必做)。
224-241:confirm_after_challenge_again与首次确认逻辑一致,注意保持截图来源一致性这里也改为使用
self.last_screenshot,与confirm_after_click_challenge一致,有利于减少重复截图并统一写法。同样的注意点:
- 需要保证该节点在每轮执行前,
last_screenshot已由框架或上游节点刷新;- 如担心未来有人调整装饰器配置,建议加一行兜底逻辑以避免拿到过期截图:
- screen = self.last_screenshot + screen = self.last_screenshot or self.screenshot()整体逻辑(优先处理开拓力弹框,其次阵亡弹框,否则重试)保持不变,行为风险主要集中在截图时效性这一点上。
src/sr_od/app/assignments/assignments_app.py (1)
92-94: 点击空白区域继续复用 last_screenshot,建议顺带补充返回类型注解这里点击“委托-点击空白区域继续”时使用
self.last_screenshot作为输入,与前面几个节点风格统一;另外该方法目前没有-> OperationRoundResult标注,可以考虑补上以便类型检查和可读性更一致,例如:- def _click_empty(self): + def _click_empty(self) -> OperationRoundResult:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (62)
src/sr_od/app/assignments/assignments_app.py(3 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(1 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(1 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(3 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(4 hunks)src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py(2 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(2 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(1 hunks)src/sr_od/app/sim_uni/operations/sim_uni_event.py(4 hunks)src/sr_od/app/sim_uni/operations/sim_uni_exit.py(4 hunks)src/sr_od/app/sim_uni/sim_uni_app.py(1 hunks)src/sr_od/app/world_patrol/world_patrol_enter_fight.py(1 hunks)src/sr_od/challenge_mission/choose_support_in_team.py(5 hunks)src/sr_od/challenge_mission/use_trailblaze_power.py(4 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_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(1 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(3 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/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 due to trivial changes (1)
- src/sr_od/operations/team/check_team_members_in_world.py
🚧 Files skipped from review as they are similar to previous changes (36)
- src/sr_od/operations/technique.py
- src/sr_od/operations/store/buy_store_item.py
- src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_respite_route_v2.py
- src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_bless.py
- src/sr_od/operations/cancel_mission_trace.py
- src/sr_od/operations/move/move_without_pos.py
- src/sr_od/operations/move/move_directly.py
- src/sr_od/sr_map/operations/choose_region.py
- src/sr_od/operations/synthesize/synthesize.py
- src/sr_od/sr_map/operations/choose_floor.py
- src/sr_od/app/sim_uni/operations/curio/sim_uni_choose_curio.py
- src/sr_od/app/sim_uni/sim_uni_app.py
- src/sr_od/sr_map/operations/open_map.py
- src/sr_od/interastral_peace_guide/guide_check_power.py
- src/sr_od/app/sim_uni/operations/auto_run/reset_sim_uni_level.py
- src/sr_od/app/sim_uni/operations/sim_uni_event.py
- src/sr_od/operations/team/switch_member.py
- src/sr_od/app/sim_uni/operations/move_v1/move_to_next_level.py
- src/sr_od/operations/team/choose_support.py
- src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_mm.py
- src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py
- src/sr_od/operations/interact/move_interact.py
- src/sr_od/operations/enter_game/enter_game.py
- src/sr_od/interastral_peace_guide/open_guide.py
- src/sr_od/operations/battle/start_fight_for_elite.py
- src/sr_od/app/sim_uni/operations/bless/sim_uni_drop_bless.py
- src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_enemy_by_detect.py
- src/sr_od/app/sim_uni/operations/move_v2/sim_uni_move_to_next_level_v3.py
- src/sr_od/app/div_uni/operations/choose_oe_support.py
- src/sr_od/interastral_peace_guide/guide_transport.py
- src/sr_od/app/sim_uni/operations/sim_uni_enter_fight.py
- src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_elite_route_v2.py
- src/sr_od/operations/wait/wait_in_world.py
- src/sr_od/app/relic_salvage/relic_salvage_app.py
- src/sr_od/app/div_uni/operations/choose_oe_file.py
- src/sr_od/app/daily_training/daily_training_app.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/assignments/assignments_app.pysrc/sr_od/sr_map/operations/choose_special_point.pysrc/sr_od/operations/click_dialog_confirm.pysrc/sr_od/operations/enter_game/switch_account.pysrc/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.pysrc/sr_od/app/sim_uni/operations/event/sim_uni_reward.pysrc/sr_od/challenge_mission/use_trailblaze_power.pysrc/sr_od/app/echo_of_war/challenge_ehco_of_war.pysrc/sr_od/operations/back_to_normal_world_plus.pysrc/sr_od/operations/interact/catapult.pysrc/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.py
🧬 Code graph analysis (5)
src/sr_od/app/assignments/assignments_app.py (1)
src/one_dragon/base/operation/operation.py (2)
round_by_ocr_and_click(919-998)round_by_find_and_click_area(789-857)
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/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/catapult.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)
🪛 Ruff (0.14.7)
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)
🔇 Additional comments (38)
src/sr_od/app/world_patrol/world_patrol_enter_fight.py (1)
70-70: 使用last_screenshot的前置条件需要明确这里改为直接使用
self.last_screenshot,能减少重复截图调用,逻辑上与原先screen = self.screenshot()一致,改动本身是合理的。需要确认两点:
- 在每轮进入该
operation_node的run()之前,框架是否始终保证当前帧已经更新self.last_screenshot(尤其是首轮或从挂起恢复后的第一轮);- 若存在极端情况下
last_screenshot可能为None或旧帧,是否需要在此处做一个兜底,例如:screen = self.last_screenshot or self.screenshot()如果在基类里已经严格保证了非空且为最新帧,可在注释或文档中简单注明这一约定,以免后续维护者误用。
src/sr_od/operations/enter_game/switch_account.py (1)
27-27: 在节点上关闭回合前自动截图的影响需要业务上确认这里给
_back_to_login节点显式加上screenshot_before_round=False,结合函数内部在行 41 已经手动调用了一次self.screenshot(),可以确实减少一张冗余截图,逻辑上看起来是安全的。建议你再确认两点:
- 是否有地方依赖该节点“回合开始自动截图”的副作用(例如依赖回合前的
last_screenshot做统计/日志);- 与本 PR 其它改为使用
last_screenshot的节点在行为上是否保持一致(比如这里是否也有机会改为复用上一次截图,而不是再拍一张)。如果以上都确认无依赖,这个改动本身是可以接受的。
src/sr_od/app/sim_uni/operations/bless/sim_uni_choose_path.py (1)
33-53: 使用last_screenshot的前置条件需要确认这里从主动调用
self.screenshot()改成拿self.last_screenshot,整体逻辑(先校验页面,再 OCR 点击,再不成功时拖动重试)保持不变,减少了一次截图开销,这个方向是合理的。需要确认的一点是:对这个节点来说,
operation_node装饰器是否保证在每轮开始前都会刷新一次截图并写入last_screenshot(即默认screenshot_before_round=True,且本节点没有在别处被改成 False)。如果存在绕过该机制直接调用节点、或以后修改默认值的情况,这里可能会用到过期截图,导致误判“未在模拟宇宙命途页面”。建议:
- 确认当前框架行为 + 跑一遍实际流程验证该节点在多轮重试时
screen始终是最新的。- 如果以后考虑调整默认截图策略,可以在这类强依赖当前画面的节点上显式标注
screenshot_before_round=True以免被波及。src/sr_od/operations/interact/catapult.py (1)
57-71: 关闭自动截图以避免重复截图,逻辑保持不变这里通过在装饰器中显式设置
screenshot_before_round=False,关闭了框架在轮次开始前的自动截图,而方法内部仍然在time.sleep(3)之后主动调用self.screenshot()获取画面。这样既避免了一轮操作中进行两次截图,又保证截图发生在路径连线稳定之后,与原有业务逻辑预期一致,没有引入新的风险。整体改动是合理的。src/sr_od/app/sim_uni/operations/sim_uni_exit.py (3)
37-43: 入口节点改用last_screenshot的前提要确认生命周期这里改为直接使用
self.last_screenshot,从逻辑上符合“每轮只截一次图”的优化方向,state判定和后续分支也都仍然只依赖同一帧画面,没有新增逻辑风险。需要确认两点:
check_screen作为is_start_node=True的节点,其所在轮次仍然会在进入前由框架刷新last_screenshot;- 没有全局或配置层面对该节点关闭
screenshot_before_round,否则这里可能拿到None或上一次轮次的残留截图。如果这两点在基类/装饰器层面已经保证,就没问题。
91-93:click_confirm使用last_screenshot与重试机制配合良好这里改用
self.last_screenshot后,每次进入本节点依然只使用进入轮的那一帧图;遇到识别失败时,通过retry_wait=1和外层轮询机制重新进入节点时会获得新的截图,语义上与之前每次内部截屏等价。整体看与周边节点保持了一致的用法,
success_wait=6也给了足够时间等待确认框消失,没有明显风险。
102-104:click_empty的截图复用方式与其它节点保持一致同样改为使用
self.last_screenshot,结合success_wait=2, retry_wait=1的配置,识别失败时会通过新一轮刷新截图再尝试点击,行为与原先按需截屏接近但更节约资源。这块与
check_screen/click_confirm的用法已经统一,便于后续维护。src/sr_od/app/sim_uni/operations/bless/sim_uni_upgrade_bless.py (1)
45-45: 改用last_screenshot的前置条件需要确认这几处把
screen = self.screenshot()改为screen = self.last_screenshot,逻辑上是复用框架已经截好的图,避免重复截图,思路是对的,代码也保持了原有调用方式(仍然通过局部变量screen传给后续逻辑)。这里有两个前置条件建议你再确认一下:
last_screenshot的刷新时机
- 对于所有相关节点(尤其是起始节点
check_left,is_start_node=True),需要保证在节点执行前,框架已经统一截图并更新了self.last_screenshot。- 如果某个节点的
operation_node装饰器上显式设置了screenshot_before_round=False,那它再依赖last_screenshot时要确保上一轮或上一个节点的截图仍然是“当前界面”,否则可能会识别到旧画面。空值/异常场景
- 如果在某些异常分支(比如上游节点提前 return 或中途异常恢复)里,
last_screenshot可能没有被赋值或被清空,调用处会直接把None传给后续 OpenCV / OCR 逻辑,容易抛错。- 可以在基类或公共入口集中兜底(保证每轮一定会先截图一次),这样这里就不需要额外判空。
整体上,这个修改方向没问题,只要上述前置条件在当前框架下已经满足,合并风险就很小。
Also applies to: 75-75, 123-123, 141-141, 167-167
src/sr_od/challenge_mission/choose_support_in_team.py (4)
34-48: 起始节点直接使用last_screenshot,请确认生命周期保证这里从
self.screenshot()改为self.last_screenshot很符合「减少冗余截图」的目标,但wait_at_first是is_start_node=True的起始节点,完全依赖框架在本轮调用前已刷新好last_screenshot。如果某些场景下该节点前没有统一截图,last_screenshot可能为None或上一轮残留画面。建议你确认/回顾:
@operation_node的默认screenshot_before_round是否为True;- 如果在别处把本节点或上游节点的
screenshot_before_round设为False,是否还有其他路径更新last_screenshot。如果上述前提都能保证,这里的改动就没问题。
50-60: 点击支援复用缓存截图实现合理
click_support使用self.last_screenshot传入round_by_find_and_click_area,避免在节点内部再次截图,逻辑与前一个节点保持一致,也符合减少截图次数的目标,没有看到功能性风险。只要上一轮进入该节点前的
last_screenshot已由框架刷新,这段实现可以保留现状。
90-99: 点击入队节点对缓存截图的使用与前序节点保持一致
click_join同样改为使用self.last_screenshot传入round_by_find_and_click_area,与click_support的模式统一,减少了潜在的重复截图,逻辑上没有引入新的分支或状态。这段改动可以接受。
146-155: 尾节点使用last_screenshot检查队伍标题与整体方案一致
wait_at_last使用缓存的last_screenshot检查是否回到带「队伍标题」的界面,和首节点、其他节点的写法统一,能避免在收尾阶段多余截图。同样前提是框架在进入该节点前会更新
last_screenshot(或者明确你已经在其它地方关闭了自动截图并自行维护该字段),在此前提下这段实现没有明显问题。src/sr_od/app/sim_uni/operations/move_v1/sim_uni_move_to_interact_by_detect.py (1)
71-71: Verify screenshot cache freshness guaranteeThe change from
self.screenshot()toself.last_screenshotreduces redundant screenshot operations, but requires confirmation that the operation framework automatically updateslast_screenshotbefore each round invocation. Since the method's movement and interaction detection logic depends on accurate screen state (lines 74, 77, 108, 113), using a stale screenshot could cause incorrect movement decisions or missed interactions. Additionally, verify that the timing-sensitive logic at line 103 (now - self.start_move_time >= 2) remains accurate with cached screenshots rather than fresh captures.src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_event_route_v2.py (3)
63-63: 优化合理,减少冗余截图。此节点使用默认的
screenshot_before_round=True,框架会在执行前自动截图并更新last_screenshot,因此使用缓存的截图是安全且高效的。
92-100: 优秀的优化:避免无效截图。通过设置
screenshot_before_round=False跳过自动截图,然后在 Line 99 调整视角后,在 Line 100 手动截取新的屏幕画面。这避免了在视角调整前截取无效的截图,是一个合理的性能优化。
44-44: Verifylast_screenshotinitialization before start node execution.Using
self.last_screenshotin the start node (line 44) depends on the framework guaranteeing that this attribute is initialized before the first node executes. Although the decorator hasscreenshot_before_round=Trueby default, manual verification is needed to confirm that the framework actually populateslast_screenshotbefore executing the start node with this default behavior. If the framework does not initializelast_screenshotbefore the first node, this could result in an AttributeError at runtime.src/sr_od/app/sim_uni/operations/auto_run/sim_uni_wait_level_start.py (1)
36-69: 验证重试机制下的截图刷新策略。
check_screen方法作为起始节点且配置了最多 20 次重试,现在使用self.last_screenshot进行屏幕状态检测。这可能存在问题:
- 如果重试时
last_screenshot没有更新,所有 20 次重试都会基于同一张过时的截图进行状态判断- 屏幕状态检测决定了后续操作分支(祝福选择、奇物选择等),使用过时截图可能导致错误的流程判断
- 作为
is_start_node=True的起始节点,其截图来源的时效性尤为重要建议确认操作框架在节点重试时是否会自动刷新
last_screenshot。此问题与
sim_uni_run_world.py文件中的截图管理问题相关,可以通过同一个验证脚本进行检查。src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_world.py (1)
85-114: 验证截图缓存的时效性。这三个方法
battle_fail_exit、battle_fail_exit_confirm和click_empty现在都使用self.last_screenshot而不是实时截图。由于这些方法依赖准确的 UI 元素检测来完成战斗失败结算流程,需要确认:
@operation_node装饰器在每个节点执行前是否自动更新last_screenshot- 重试机制(
retry_wait参数)触发时是否会刷新截图- 如果使用了过时的截图,是否会导致
round_by_find_and_click_area无法找到目标区域src/sr_od/sr_map/operations/choose_special_point.py (1)
37-37: 验证重试时的截图刷新机制该方法从显式调用
self.screenshot()改为使用缓存的self.last_screenshot。由于该方法包含多个重试路径(第 58、79 行的round_retry)且最大重试次数为 10,需要确认@operation_node装饰器在每次重试前是否会自动刷新last_screenshot。如果框架在重试时不刷新截图,则:
- 方法执行拖动操作后(第 57、76 行),仍会使用旧截图进行后续判断
- 无法检测到 UI 状态变化,可能导致重试逻辑失效
- 可能陷入使用相同陈旧截图重试 10 次的循环
请验证
operation_node装饰器在重试时的截图捕获行为,以确认此更改是否安全。src/sr_od/app/div_uni/operations/ornamenet_extraction.py (4)
182-196: 使用缓存截图可接受,但需确保时效性。此方法根据战斗状态决定点击"退出关卡"还是"再来一次"按钮。使用
self.last_screenshot是可接受的,前提是操作框架在此节点执行前已捕获最新截图。
126-134: Verify screenshot behavior in operation framework before approving this change.The original review comment asserts that the operation framework automatically captures screenshots before each round (via
screenshot_before_rounddefault), making the switch fromself.screenshot()toself.last_screenshotsafe. However, this assumption cannot be verified without access to the operation framework's implementation.This is particularly critical for methods with retry logic (
wait_mission_loadedandwait_backwithnode_max_retry_times=20). Ifself.last_screenshotis not refreshed between retry attempts, the retry mechanism becomes ineffective for detecting state changes.Before approving these changes, confirm:
- The default value of
screenshot_before_roundin the@operation_nodedecorator- Whether screenshots are captured before each retry attempt, not just before the initial round
- For non-retry methods, whether the cache is guaranteed to be fresh from the current round
136-144: 需要验证重试操作的截图刷新机制。此方法是一个等待/轮询操作,配置了
node_max_retry_times=20。使用self.last_screenshot存在潜在风险:如果在重试之间不刷新截图,所有 20 次重试都会检查同一张陈旧的图像,导致轮询机制失效。确认以下内容:
operation_node装饰器的重试机制是否在每次重试前自动刷新截图self.last_screenshot属性在重试循环中的更新时机round_by_find_area方法是否会自动捕获新的截图
198-206: 重试操作中使用缓存截图需要验证框架行为。此方法配置了
node_max_retry_times=20,在重试场景下,需要确认self.last_screenshot是否在每次重试前自动更新。若截图未刷新,所有重试都会检查相同的陈旧图像,导致无法正确检测角色是否已返回大世界。请确认操作框架在重试循环中是否自动刷新截图。src/sr_od/app/sim_uni/operations/entry/sim_uni_claim_weekly_reward.py (1)
26-26: LGTM - 截图来源修改一致三个方法(
_wait_ui、_check_reward、_claim_reward)都统一使用self.last_screenshot作为截图来源,与整个 PR 的优化模式保持一致。这些方法通过@node_from形成操作链,假设装饰器会在每个节点执行前更新截图,这个修改是合理的。Also applies to: 38-38, 45-45
src/sr_od/operations/click_dialog_confirm.py (1)
24-26: LGTM - 简单操作的截图优化将对话框确认操作的截图来源改为
self.last_screenshot符合 PR 的优化目标,逻辑保持不变。src/sr_od/app/nameless_honor/nameless_honor_app.py (1)
105-110: LGTM - 奖励领取后的画面检查
_check_screen_after_reward方法使用self.last_screenshot来检查领取奖励后的画面状态,与 PR 的优化模式一致。该方法用于检测是否仍在无名勋礼界面或需要关闭弹窗。src/sr_od/interastral_peace_guide/guide_choose_category.py (1)
29-31: LGTM - 指南分类选择的截图优化
wait_screen和choose两个方法都改用self.last_screenshot,符合整体优化模式。这些方法用于画面等待和分类选择,使用缓存截图可以减少截图开销。Also applies to: 39-41
src/sr_od/app/sim_uni/operations/battle/sim_uni_fight_elite.py (1)
32-39: LGTM - 战斗检测的截图优化
_check_enemy和_fight方法改用self.last_screenshot进行敌人检测和战斗状态判断。这些是关键的战斗流程方法:
_check_enemy使用 OCR 和 YOLO 检测敌人_fight判断是否进入战斗画面修改与 PR 模式一致,假设装饰器保证截图时效性。
Also applies to: 59-61
src/sr_od/app/echo_of_war/challenge_ehco_of_war.py (2)
65-70: LGTM - 挑战流程中的截图优化四个方法(
after_click_challenge、after_click_start_challenge、_after_battle_result、after_challenge_again)改用self.last_screenshot来检查对话框和战斗结果。这些方法在点击操作后检查画面状态,使用缓存截图是合理的。Also applies to: 137-139, 172-177, 186-192
149-155: 注意:保留了新截图的使用
_wait_battle_result方法(第155行)仍然使用self.screenshot()获取新截图,而其他方法使用self.last_screenshot。这个差异应该是有意为之的,因为该方法需要主动等待战斗结果状态变化,必须获取最新的屏幕状态。src/sr_od/app/sim_uni/operations/event/sim_uni_reward.py (1)
42-44: LGTM - 沉浸奖励获取流程的截图优化三个方法(
_get_reward、_click_empty、_check_state)统一改用self.last_screenshot,形成完整的奖励领取节点链。这些方法分别负责:
- 获取奖励并进行 OCR 识别数字
- 点击空白处关闭
- 检查画面状态
使用缓存截图符合 PR 的优化目标,逻辑保持不变。
Also applies to: 88-94, 104-110
src/sr_od/operations/back_to_normal_world_plus.py (1)
26-28: Verify screenshot freshness incheck_screenmethodThe change from
self.screenshot()toself.last_screenshotaffects a critical screen state detection method. Confirm that the@operation_nodedecorator automatically captures or updatesself.last_screenshotbefore this method executes, ensuring the screenshot is current and not stale from a previous operation. This is important because withnode_max_retry_times=20, using an outdated screenshot could cause incorrect state detection and waste retry attempts.src/sr_od/app/sim_uni/operations/auto_run/sim_uni_run_level.py (2)
111-118: 改用 last_screenshot 避免重复截图,逻辑保持不变这里直接使用
self.last_screenshot作为楼层类型识别输入,在假定operation_node默认会在节点开始前刷新截图的前提下,与原先在节点内部调用self.screenshot()的语义一致,但少一次截图开销。后续如果对该节点调整screenshot_before_round配置,记得同时确认last_screenshot的更新来源即可。
133-149: 路线匹配同样复用 last_screenshot,提升一致性与性能
_check_route复用当前轮的self.last_screenshot做小地图裁剪和路线匹配,避免额外截屏,同时确保同一帧图像在整个匹配过程内被一致地使用,有利于结果稳定。只需在后续改动中注意不要关闭该节点前置截图而忘记其它截图来源。src/sr_od/app/assignments/assignments_app.py (4)
54-57: 选择专属材料改用 last_screenshot,OCR 行为保持一致这里将
screen改为读取self.last_screenshot并传给round_by_ocr_and_click,在节点开始前截图已刷新的前提下,等价于原先基于最新画面做 OCR,只是避免在节点内部重复截屏,符合本 PR 的目标。
62-68: 一键领取在查找与点击间复用同一帧截图,更稳定也更省开销
_claim_all先用screen = self.last_screenshot调用round_by_find_area,再在成功时用同一个screen调用round_by_find_and_click_area,确保“发现按钮”和“点击按钮”基于同一帧图像,减少因界面轻微变化导致状态不一致的可能,同时避免额外截屏。
73-75: 再次派遣改为显式传入 last_screenshot,一致性良好
assign_again直接将self.last_screenshot传入round_by_find_and_click_area,与同文件其它节点用法保持一致,也避免在 helper 内部再触发截图逻辑,符合减少冗余截图的目标。
80-87: 领取节点同样复用 last_screenshot,语义清晰
_claim中查找“委托-领取”并点击都基于self.last_screenshot,逻辑与使用最新屏幕判定按钮是否存在/点击的需求一致,同时避免多次截屏;成功/失败分支返回的状态也未改变。
There was a problem hiding this 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 (1)
src/sr_od/challenge_mission/choose_challenge_times.py (1)
27-44: 使用 last_screenshot 的重试语义需要再确认一下
choose()这里改为直接复用self.last_screenshot,对单轮执行来说可以避免多次截图,而且同一轮内_get_current_times/_click_plus/_click_minus共用同一张图,逻辑上是更一致的。
但结合node_max_retry_times=5,有两个点建议你确认:
- 重试时
@operation_node是否保证在每一轮开始前都会重新截图并更新last_screenshot?如果没有,每次重试都用同一张旧图,可能导致一直无法感知界面已变化。- 是否存在在同一轮内执行其他节点/操作改变 UI,再回到
choose()的情况?这种情况下也需要保证 last_screenshot 在回到本节点前被刷新。另外,原来的
screen: MatLike = ...类型注解现在去掉了问题不大,但如果你希望继续享受静态检查,可以考虑在类属性里给last_screenshot标注类型,或在这里保留一个显式注解(非必须)。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
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/nameless_honor/nameless_honor_app.py(6 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_start.py(3 hunks)src/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py(3 hunks)src/sr_od/app/support_character/support_character_app.py(2 hunks)src/sr_od/challenge_mission/choose_challenge_times.py(1 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/interastral_peace_guide/guid_choose_tab.py(1 hunks)src/sr_od/interastral_peace_guide/guide_choose_mission.py(2 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)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/sr_od/app/nameless_honor/nameless_honor_app.py
- src/sr_od/app/assignments/assignments_app.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/challenge_mission/click_challenge.pysrc/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.pysrc/sr_od/app/sim_uni/operations/entry/sim_uni_start.pysrc/sr_od/challenge_mission/click_start_challenge.pysrc/sr_od/app/sim_uni/operations/entry/choose_sim_uni_diff.pysrc/sr_od/app/claim_email/email_app.py
🧬 Code graph analysis (1)
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)
🔇 Additional comments (20)
src/sr_od/app/sim_uni/operations/entry/choose_sim_uni_num.py (1)
41-69: 复用last_screenshot的前置条件需要确认这里改为直接使用
self.last_screenshot,和本次 PR “减少重复截图、统一复用缓存屏幕”的思路一致,没有看到明显逻辑问题。有一个小点建议确认一下:
- 目前
choose()一进来就把screen传给common_screen_state.in_secondary_ui(...),而不像_get_current_num/_is_going那样在screen is None时兜底再截图。- 也就是说,这段代码假设在每个 round 开始之前,框架层已经保证
self.last_screenshot是最新且非空。如果框架的
@operation_node默认确实会在 round 开始前统一截图并写入last_screenshot,那这次改动是安全的;否则建议要么在这里对screen is None时兜底调用一次self.screenshot(),要么确保in_secondary_ui能安全处理screen=None的情况。整体上改动方向是对的,只是需要确认一下这一点以避免偶发的
None导致识别失败。src/sr_od/challenge_mission/click_start_challenge.py (1)
25-29: 使用last_screenshot替代即时截图的语义确认这里改为使用
self.last_screenshot,在默认operation_node会在轮次开始前自动截图并更新缓存的前提下,可以避免重复截图,逻辑上是等价且更高效的。需要你确认一下:在该节点执行前框架是否一定会更新last_screenshot(特别是作为is_start_node=True的节点时),以避免极端情况下拿到上一轮遗留的旧截图导致识别/点击失败。src/sr_od/challenge_mission/click_challenge.py (1)
24-27: 确认 last_screenshot 的刷新时机以避免使用过期截图这里从即时
self.screenshot()改为复用self.last_screenshot,在默认的@operation_node行为(每轮开始自动截图并更新last_screenshot)下应该是等价且更省性能的。
建议你再确认两点:
- 确认此节点所在流程中,本轮内不会在别处发生 UI 变化后才调用
click(),否则有可能点的是上一帧状态。- 确认没有在装饰器或基类层面把该节点的
screenshot_before_round关掉(比如通过全局配置覆盖),避免连续重试时一直用同一张旧截图。如果以上前提都满足,这个改动是安全且合理的。
src/sr_od/interastral_peace_guide/guid_choose_tab.py (1)
28-28: Verify thatlast_screenshotremains fresh across operation rounds.The change from
self.screenshot()toself.last_screenshotimproves performance by reusing the cached screenshot. However, this approach depends on the framework guarantee thatlast_screenshotis refreshed before each operation round executes. Since the@operation_nodedecorator does not explicitly setscreenshot_before_round=False, confirm that:
- The decorator automatically captures a fresh screenshot before invoking this method
- The cached
last_screenshotis updated at the appropriate time to ensure UI state checks on lines 30, 33, and 36 use current screen dataIf these guarantees are not provided by the framework, the UI detection logic may operate on stale screen state.
src/sr_od/app/claim_email/email_app.py (2)
45-51: 改用last_screenshot作为菜单识别输入整体是合理的这里直接复用
self.last_screenshot来做菜单项匹配,可以去掉多余的显式截图调用,逻辑上与“本轮开始前自动截图”是等价的,只要框架在进入节点前已经刷新了截图。
建议你再确认两点:
@operation_node的默认参数是否为screenshot_before_round=True,确保进入_click_email前一定会刷新last_screenshot;- 在极端情况下(例如异常恢复后)
last_screenshot不会为None,否则传入匹配函数可能会触发异常。
56-58: 在_claim中使用缓存截图也依赖节点前自动刷新,注意实际场景验证
_claim同样改为使用self.last_screenshot,考虑到上一个节点_click_email在成功时返回wait=1,再配合@operation_node的默认截图行为,这里拿到的应当是“进入收件箱界面后”的最新画面,从而避免多余截图,设计上是统一且合理的。
为了保险,建议在实际游戏中至少跑一遍不同语言 / 分辨率场景,确认“邮件-全部领取”在第一次进入该节点时识别和点击依旧稳定,没有出现因为截图时机变化导致的漏识或误点。src/sr_od/app/sim_uni/operations/entry/choose_sim_uni_diff.py (1)
38-52: Verify screenshot freshness for start nodes usinglast_screenshotThis method is marked as
is_start_node=True, meaning it executes at the start of an operation flow. Usingself.last_screenshotcarries timing risks:
- If the
operation_nodeframework does not auto-capture screenshots before executing start nodes,last_screenshotmay be stale from a previous operation- Stale screenshots would cause inaccurate UI state validation at lines 44-46, potentially causing incorrect behavior
- The retry mechanism (node_max_retry_times=5) cannot compensate if the screenshot remains outdated
Verify the framework's behavior:
- Does
operation_nodeauto-capture before each node execution?- For
is_start_node=Truenodes specifically, islast_screenshotguaranteed fresh?- Does the implementation add
screenshot_before_round=Falseparameter, or is explicitself.screenshot()needed?src/sr_od/app/sim_uni/operations/entry/sim_uni_start.py (3)
45-54: 改动符合 PR 目标。作为后续节点,使用
self.last_screenshot替代手动截图是合理的,减少了冗余的截图操作。逻辑流程保持不变。
56-69: 改动符合 PR 目标。使用
self.last_screenshot替代手动截图,与整个 PR 的优化方向一致。方法逻辑未改变,仍正确处理低等级确认流程。
28-43: Verify screenshot initialization for start node operation.This entry point is marked as
is_start_node=Trueand now depends onself.last_screenshotfor screen state detection. Confirm that the operation framework automatically captures a screenshot before invoking start nodes to ensurelast_screenshotis properly initialized and current at this execution point.This verification requires inspection of:
- The
@operation_nodedecorator implementation to confirm automatic screenshot capture behavior- The
SrOperationbase class initialization to verifylast_screenshotis set before the first node executes- Whether
screenshot_before_roundparameter or similar mechanism controls screenshot timingsrc/sr_od/app/sim_uni/operations/move_v2/sim_uni_run_combat_route_v2.py (3)
51-51: 优化得当:复用缓存截图此处改用
self.last_screenshot是正确的。由于该节点使用了默认的screenshot_before_round=True,框架会在执行方法前自动截图并存储到self.last_screenshot,直接复用可避免重复截图开销。
76-76: 优化得当:复用缓存截图此处改用
self.last_screenshot是正确的。尽管该节点有多个入口,但由于使用了默认的screenshot_before_round=True,框架会在每次调用前自动更新截图,因此复用缓存截图是安全且高效的。
145-154: 优化得当:精确控制截图时机此处设置
screenshot_before_round=False是正确的优化。由于该方法需要先调用_view_down()调整视角(第 152 行),然后在调整后截图(第 154 行),设置该参数可避免在视角调整前拍摄无用的截图,精准地消除了冗余截图开销。src/sr_od/interastral_peace_guide/guide_choose_mission.py (2)
31-38: Verify thatlast_screenshotis properly initialized before the start node executes.As a start node (
is_start_node=True), thewait_screenmethod now relies onself.last_screenshotinstead of callingself.screenshot()directly. Confirm that the framework guarantees the screenshot has been updated before this node executes, otherwise the state check may fail iflast_screenshotis uninitialized or stale.
40-55: Verify screenshot update timing in the retry mechanism.This method performs a drag operation (line 50) to change the interface state when the transport button is not found, then retries with a 2-second wait (line 52). If
self.last_screenshotis not updated after the drag operation, the retry will use the old screenshot from before the drag, preventing detection of newly appeared transport buttons.Confirm whether the framework automatically captures a fresh screenshot at the start of each retry round. If not, explicitly call
self.screenshot()after the drag operation or before returning fromround_retry()to ensure the next iteration sees the updated interface state.src/sr_od/operations/menu/click_phone_menu_item.py (1)
29-38: 滚动后使用缓存截图可能导致检测失败。在滚动菜单后(line 37),如果框架不自动更新
last_screenshot,第38行的round_retry会继续使用滚动前的旧截图进行下一轮检测,导致:
- 无法检测到滚动后新出现的菜单项
- 持续重试相同的过期画面数据,直到达到最大重试次数(10次)
- 操作失败率增加
这个场景比单纯的状态检查更关键,因为涉及用户交互(滚动)改变了UI状态。
请运行相同的验证脚本(见 open_phone_menu.py 的评论),特别关注在有UI交互操作(如滚动、点击)后,框架是否保证在下一轮重试前更新截图缓存。
src/sr_od/operations/interact/talk_interact.py (1)
37-49: OCR operations should use fresh screenshot data in dynamic dialog scenarios.When OCR is performed after UI interactions (click operations at lines 48+), ensure the screenshot data reflects the current dialog state. Consider verifying that
self.last_screenshotis refreshed before the OCR operation at line 43, especially after click actions that modify the dialog content.Additionally, restore the
MatLiketype annotation on line 39 for improved code clarity and maintainability.src/sr_od/operations/menu/open_phone_menu.py (1)
23-25: 验证截图缓存的更新时机。将截图源从
self.screenshot()改为self.last_screenshot可以减少冗余截图,但需要确保操作框架在每次节点执行(包括重试)前自动更新last_screenshot。如果使用过期的截图数据,可能导致:
- 无法正确识别菜单是否已打开
- 重试时使用相同的过期截图,导致重试逻辑失效
is_normal_in_world状态判断错误需要验证
operation_node装饰器的实现,确认:
last_screenshot是否在每轮执行前自动更新screenshot_before_round参数的默认行为node_max_retry_times=10时重试的截图更新机制src/sr_od/app/support_character/support_character_app.py (2)
49-55: 验证前序节点点击后截图是否已更新前一个节点
_click_ellipsis在第 43 行执行点击并等待 1 秒后,当前节点使用self.last_screenshot进行匹配。若@operation_node装饰器不会在节点执行前自动刷新屏幕截图,第 50 行的匹配逻辑将基于过时的屏幕数据,导致匹配失败或定位错误。请确认
@operation_node装饰器的实现是否会在每个节点开始前自动获取新的屏幕截图。
38-44: Verify@operation_nodedecorator behavior andlast_screenshotupdate timing.The optimization to use
self.last_screenshotinstead ofself.screenshot()appears reasonable, but requires confirmation that the@operation_nodedecorator automatically updatesself.last_screenshotbefore each node executes. Without this guarantee, line 38 may reference stale screen data from before the previous operation.Ensure that:
@operation_nodecaptures a fresh screenshot before the decorated method executesself.last_screenshotis populated and current when referenced at line 38- The screenshot remains valid through consecutive operation nodes
Summary by CodeRabbit
发布说明
✏️ Tip: You can customize this high-level summary in your review settings.