Skip to content

自动委托: 更快地点击跳过#2150

Open
JoshCai233 wants to merge 20 commits into
OneDragon-Anything:mainfrom
JoshCai233:极速自动点委托

Hidden character warning

The head ref may contain hidden characters: "\u6781\u901f\u81ea\u52a8\u70b9\u59d4\u6258"
Open

自动委托: 更快地点击跳过#2150
JoshCai233 wants to merge 20 commits into
OneDragon-Anything:mainfrom
JoshCai233:极速自动点委托

Conversation

@JoshCai233
Copy link
Copy Markdown
Contributor

@JoshCai233 JoshCai233 commented Mar 28, 2026

一直觉得自动委托点击延迟太高有点鸡肋,不如手动触发按键精灵宏迅速
火锅活动b对话太多了,就想着改一下
支持主线和支线
改善点击延迟并且减少误触

Summary by CodeRabbit

  • 新功能

    • 新增“空白画面等待”可调配置并在界面添加设置项。
    • 增加未知画面专用等待节点与玩法引导/新手教程识别,改进剧情后续处理顺序。
    • 引入最小选项点击间隔与前台快速点击模式,提升交互响应速度。
  • 修复 / 行为优化

    • 改进对话框检测:灰度先验筛查配合更稳健的 OCR 判断。
    • 优化选项点击策略:中心点处理、历史去重与重试避免重复选择。
    • 精化短信与主线剧情判定与返回逻辑,提高稳定性与鲁棒性。

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

更改委托助手对话/剧情控制流:起始节点改为“委托助手”;引入灰度掩码检测、低延迟点击路径与有界选项历史;新增教程检测与“未知画面”等待节点;更新屏幕区域定义与界面配置项(sleep_after_empty_screen)。

Changes

Cohort / File(s) Summary
对话/剧情逻辑
src/zzz_od/application/commission_assistant/commission_assistant_app.py
重构对话/剧情控制流:起始节点名改为 委托助手;新增/修改方法与节点(_do_dialog_click(check_center_words: bool=True)check_main_storycheck_game_tutorialsleep_after_empty_screen_func);引入有界 chosen_opt_history、标志位(withered_domain_initedis_skip_in_main_storydialog_clicked);调整点击优先级、灰度判定、重试与回退逻辑(含短信/剧情/教程顺序变更)。
配置与界面
src/zzz_od/application/commission_assistant/commission_assistant_config.py, src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py
新增配置项 sleep_after_empty_screen(float,默认 0.5)与常量 OPTION_CLICK_INTERVAL_MIN(0.1);界面由 Row 改为 Column,新增 sleep_after_empty_screen_opt 并在界面显示时绑定配置。
屏幕区域定义
assets/game_data/screen_info/_od_merged.yml, assets/game_data/screen_info/commission_assistant.yml
移除旧“对话框标题/右侧选项”识别字段,新增 对话框内容 区域(用于 OCR)并调整坐标,新增 玩法引导 区域(用于教程检测)。
控制器低延迟点击支持
src/one_dragon/base/controller/controller_base.py, src/one_dragon/base/controller/pc_controller_base.py
click API 中加入 low_delay: bool = FalsePcControllerBase 保存并在需要时临时覆盖 pyautogui.PAUSE,新增实例方法 win_click(..., low_delay=...),前台点击路径改为使用该方法以支持低延迟点击。
图像工具
src/one_dragon/utils/cv2_utils.py
新增工具函数 is_in_gray_mask(...):基于阈值与通道差异判断区域是否为灰/单色并返回布尔结果,记录置信度日志。
空洞事件检测小改
src/zzz_od/hollow_zero/event/hollow_event_utils.py
移除对 screen_utils.find_area(...)crop_first=False 参数调用。

Sequence Diagram(s)

sequenceDiagram
    participant App as CommissionAssistantApp
    participant OCR as OCR服务
    participant Clicker as 控制器(PcController)
    participant UI as 游戏界面

    App->>OCR: 检测 对话框内容 / 玩法引导 / 跳过 文本(色筛 + 灰度掩码)
    OCR-->>App: 返回识别结果
    alt 检测到“跳过”
        App->>Clicker: click(跳过位置, low_delay?)
        Clicker-->>UI: 执行跳过点击
        App->>App: 标记 is_skip_in_main_story;清空 chosen_opt_history
        App->>OCR: 检测 对话框确认
        App->>Clicker: click(对话框确认, low_delay?)
        Clicker-->>UI: 点击确认
    else 未检测到跳过
        App->>App: 调用 _do_dialog_click(check_center_words=True/False)
        App->>OCR: 识别右侧选项文字(可带 color_range)
        App->>App: 基于灰度判定决定是否点击中心或选项;使用 chosen_opt_history 避免重复
        App->>Clicker: click(目标, low_delay?)
        Clicker-->>UI: 执行点击
        alt 空屏或无进展
            App->>App: sleep_after_empty_screen_func(等待 self.config.sleep_after_empty_screen)
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • Usagi-wusaqi
  • ShadowLemoon

Poem

🐰 轻点屏中影,字声随风行,
跳过轻如羽,选项不再循。
中央若静默,短歇半息停,
教程若现身,稳步再启程。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清晰准确地反映了PR的主要变更目标——优化自动委托模块中的跳过点击速度。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@JoshCai233 JoshCai233 marked this pull request as ready for review March 28, 2026 15:42
@JoshCai233 JoshCai233 changed the title 自动委托: 更快地点委托 自动委托: 更快地点击跳过 Mar 28, 2026
Copy link
Copy Markdown
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 397-400: The code unconditionally sets self.is_skip_in_main_story
= True after calling round_by_ocr_and_click_by_priority(['菜单','自动'], ...) which
treats clicking '自动' (used to exit auto-play) as entering the main-story skip
flow; change this so the flag is only set when the clicked button is actually
the menu/skip entry (e.g., check result.status == '菜单' before setting
self.is_skip_in_main_story) or alternatively record the last_clicked button
instead of a boolean; update the block around
round_by_ocr_and_click_by_priority, the check that sets is_skip_in_main_story,
and any logic that relies on it (including the following round_wait call) to use
the refined condition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d9485496-a848-4cf6-929a-3facac46e516

📥 Commits

Reviewing files that changed from the base of the PR and between 33c5f86 and d40dd12.

📒 Files selected for processing (1)
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py

Comment thread src/zzz_od/application/commission_assistant/commission_assistant_app.py Outdated
Copy link
Copy Markdown
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 113-117: The branch that handles the '对话框确认' detection currently
calls round_wait(result.status, wait=0) which can busy-loop if the dialog
persists; change the wait argument to a small non-zero delay (e.g., 0.03–0.1s)
to throttle polling and reduce CPU usage while keeping the same behavior. Locate
the call site where round_by_find_area(self.last_screenshot, '委托助手', '对话框确认',
crop_first=False) returns result and replace round_wait(result.status, wait=0)
with round_wait(result.status, wait=0.05) (or a similar small value) to resolve
the busy-polling risk.
- Around line 381-389: The OCR click uses round_by_ocr_and_click with
success_wait=0.1 but because its result isn't immediately returned the
success_wait isn't effective, and is_skip_in_main_story is cleared too early
before confirming the dialog; change the flow so that if
round_by_ocr_and_click(self.last_screenshot, '跳过', area=area, success_wait=0.1)
returns success you immediately honor its success_wait behavior (i.e., return or
await the wait) before proceeding, and only clear self.is_skip_in_main_story
after a successful confirmation click in
round_by_find_and_click_area(self.screenshot(), '委托助手', '对话框确认', ...);
specifically update the block handling result from round_by_ocr_and_click and
the subsequent use of round_by_find_and_click_area to preserve
is_skip_in_main_story until the confirmation succeeds and ensure success_wait is
applied.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 63cacb7e-1a8f-4a77-a08e-dfebd645ddf9

📥 Commits

Reviewing files that changed from the base of the PR and between d40dd12 and 5f8246e.

📒 Files selected for processing (1)
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py

Comment thread src/zzz_od/application/commission_assistant/commission_assistant_app.py Outdated
Comment thread src/zzz_od/application/commission_assistant/commission_assistant_app.py Outdated
Copy link
Copy Markdown
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 340-343: The call to ctx.ocr_service.get_ocr_result_map in
commission_assistant_app.py changed behavior by dropping the crop_first
parameter (so it now uses default True); restore consistent behavior with other
calls by explicitly passing crop_first=False (i.e., call
get_ocr_result_map(image=self.last_screenshot, rect=area.rect,
crop_first=False)) so ocr_result_map is produced the same way as the other sites
that set crop_first=False; update the call site where ocr_result_map is assigned
and run tests or verify OCR results to confirm intended behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9d1667a4-eb18-4400-b629-67258dabcca8

📥 Commits

Reviewing files that changed from the base of the PR and between 13a3726 and 149507f.

📒 Files selected for processing (1)
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py

@JoshCai233 JoshCai233 marked this pull request as draft March 29, 2026 07:48
@JoshCai233
Copy link
Copy Markdown
Contributor Author

还能优化。。我先测个几周看看

- 添加设置: 剧情专注模式开关、未识别到文字时等待时间
- 剧情模式跳过逻辑优化 (主要是主线)
- ocr之前先裁剪图片以减少开销
- 取消 round_by_find_and_click_area() 的点击前等待时间
- 进入剧情模式后, 不再点击未知画面
- 剧情模式顺带识别短信界面
@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from 20377c5 to a838a5b Compare March 29, 2026 19:59
@JoshCai233 JoshCai233 marked this pull request as ready for review March 30, 2026 13:30
Copy link
Copy Markdown
Contributor

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

Caution

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

⚠️ Outside diff range comments (1)
src/zzz_od/application/commission_assistant/commission_assistant_app.py (1)

200-216: ⚠️ Potential issue | 🟠 Major

潜在 Bug:所有选项被过滤后仍会调用 click(None)

当所有 OCR 识别到的选项都因历史记录检查(lines 200-203)被跳过时,to_click 将保持为 None。此时:

  • Line 214 会对 None 调用 click()
  • Line 215 会将 None 追加到历史记录
  • Line 216 会返回 True,但实际上没有点击任何选项
🐛 建议修复
         self.ctx.controller.click(to_click)
+        if to_click is None:
+            return False
         self.chosen_opt_history.append(to_choose_opt)
         return True

或者更清晰的写法:

-        self.ctx.controller.click(to_click)
-        self.chosen_opt_history.append(to_choose_opt)
-        return True
+        if to_click is not None:
+            self.ctx.controller.click(to_click)
+            self.chosen_opt_history.append(to_choose_opt)
+            return True
+        return False
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`
around lines 200 - 216, The loop can leave to_click/to_choose_opt as None when
all OCR options are skipped; update the method in commission_assistant_app.py to
check after the loop whether to_click is None and, if so, avoid calling
self.ctx.controller.click(None), avoid appending None to
self.chosen_opt_history, and return False (or an appropriate failure value)
instead of True; ensure the check occurs immediately before
self.ctx.controller.click(to_click) and uses the existing symbols
(self.chosen_opt_history, chosen_opt_history_max_len, is_same_opts, mr.data,
to_click, to_choose_opt, self.ctx.controller.click) so normal clicking and
history appending only happen when to_click is not None.
🧹 Nitpick comments (2)
src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py (1)

7-7: 未使用的导入:Column

Column 被导入但在此文件中未被使用,应移除该导入。

💡 建议修改
-from one_dragon_qt.widgets.column import Column
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py` at line
7, Remove the unused import Column from the top-level imports in this module:
delete the line importing Column (from one_dragon_qt.widgets.column import
Column) so the file no longer imports the unused symbol Column; verify no other
references to Column exist in functions or classes in this file (e.g., any usage
in UI setup or class methods) before committing.
src/zzz_od/application/commission_assistant/commission_assistant_app.py (1)

51-53: 缺少类型提示:chosen_opt_history

根据编码规范,所有属性应包含类型提示。

💡 建议修改
         self.chosen_opt_history_max_len: int = 8
-        self.chosen_opt_history: deque = deque(maxlen=self.chosen_opt_history_max_len)  # 如果一直卡在选择选项, 记录选择的对话选项历史记录
+        self.chosen_opt_history: deque[str | None] = deque(maxlen=self.chosen_opt_history_max_len)  # 如果一直卡在选择选项, 记录选择的对话选项历史记录
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`
around lines 51 - 53, Annotate the attribute self.chosen_opt_history with an
explicit type hint (e.g., Deque[Any] or Deque[str] depending on element type)
and update imports accordingly; for example, add "from typing import Deque, Any"
(or the specific element type) and change the attribute to chosen_opt_history:
Deque[Any] = deque(maxlen=self.chosen_opt_history_max_len) so the class
(commission_assistant_app / the attribute chosen_opt_history and
chosen_opt_history_max_len) follows the code style requiring typed attributes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 200-216: The loop can leave to_click/to_choose_opt as None when
all OCR options are skipped; update the method in commission_assistant_app.py to
check after the loop whether to_click is None and, if so, avoid calling
self.ctx.controller.click(None), avoid appending None to
self.chosen_opt_history, and return False (or an appropriate failure value)
instead of True; ensure the check occurs immediately before
self.ctx.controller.click(to_click) and uses the existing symbols
(self.chosen_opt_history, chosen_opt_history_max_len, is_same_opts, mr.data,
to_click, to_choose_opt, self.ctx.controller.click) so normal clicking and
history appending only happen when to_click is not None.

---

Nitpick comments:
In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 51-53: Annotate the attribute self.chosen_opt_history with an
explicit type hint (e.g., Deque[Any] or Deque[str] depending on element type)
and update imports accordingly; for example, add "from typing import Deque, Any"
(or the specific element type) and change the attribute to chosen_opt_history:
Deque[Any] = deque(maxlen=self.chosen_opt_history_max_len) so the class
(commission_assistant_app / the attribute chosen_opt_history and
chosen_opt_history_max_len) follows the code style requiring typed attributes.

In `@src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py`:
- Line 7: Remove the unused import Column from the top-level imports in this
module: delete the line importing Column (from one_dragon_qt.widgets.column
import Column) so the file no longer imports the unused symbol Column; verify no
other references to Column exist in functions or classes in this file (e.g., any
usage in UI setup or class methods) before committing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f541ef5-51f8-4ab0-a542-a712ef9a0695

📥 Commits

Reviewing files that changed from the base of the PR and between 149507f and a838a5b.

📒 Files selected for processing (3)
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py
  • src/zzz_od/application/commission_assistant/commission_assistant_config.py
  • src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py

@JoshCai233
Copy link
Copy Markdown
Contributor Author

还能优化。。我先测个几周看看

似乎没什么大问题了

@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from f722ce9 to fc929d8 Compare April 3, 2026 11:01
@JoshCai233 JoshCai233 marked this pull request as draft April 4, 2026 03:01
@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from a44c0ab to 6c9d009 Compare April 6, 2026 11:17
@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from 6c9d009 to 709b6ee Compare April 6, 2026 14:47
@JoshCai233 JoshCai233 marked this pull request as ready for review April 6, 2026 15:51
@JoshCai233
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Comment on lines +525 to +551
def win_click(self, pos: Point = None, press_time: float = 0, primary: bool = True, low_delay: bool = False):
"""点击鼠标。

Args:
pos: 屏幕坐标
press_time: 按住时间
primary: 是否点击鼠标主要按键(通常是左键)
low_delay: todo 去除按键延迟 (pyautogui几乎所有操作都有延迟, 默认为0.1s)
"""
btn = pyautogui.PRIMARY if primary else pyautogui.SECONDARY
if pos is None:
pos = get_current_mouse_pos()

if low_delay:
pyautogui.PAUSE = 0.001

def win_click(pos: Point = None, press_time: float = 0, primary: bool = True):
"""点击鼠标。
if press_time > 0:
# 处理点击延迟
pyautogui.moveTo(pos.x, pos.y)
pyautogui.mouseDown(button=btn)
time.sleep(press_time)
pyautogui.mouseUp(button=btn)
else:
pyautogui.click(pos.x, pos.y, button=btn)

Args:
pos: 屏幕坐标
press_time: 按住时间
primary: 是否点击鼠标主要按键(通常是左键)
"""
btn = pyautogui.PRIMARY if primary else pyautogui.SECONDARY
if pos is None:
pos = get_current_mouse_pos()
if press_time > 0:
pyautogui.moveTo(pos.x, pos.y)
pyautogui.mouseDown(button=btn)
time.sleep(press_time)
pyautogui.mouseUp(button=btn)
else:
pyautogui.click(pos.x, pos.y, button=btn)
if low_delay:
pyautogui.PAUSE = self.pyautogui_pause
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

这边对前台模式下点击鼠标的函数拓展了个参数 low_delay, 能够使点击的延迟小于0.1s.
但是这个函数很多人在用, 故目前没有改参数 press_time, 只加了个todo.
@ShadowLemoon 看看这样改是否合理

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@JoshCai233
Copy link
Copy Markdown
Contributor Author

@coderabbitai resume
@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 7, 2026

@JoshCai233 好的,正在恢复自动审查并开始对 PR #2150 进行审查!


🧠 Learnings used
Learnt from: JoshCai233
Repo: OneDragon-Anything/ZenlessZoneZero-OneDragon PR: 2150
File: src/zzz_od/application/commission_assistant/commission_assistant_app.py:394-397
Timestamp: 2026-03-28T16:08:41.924Z
Learning: 在 `src/zzz_od/application/commission_assistant/commission_assistant_app.py` 的 `story_mode()` 中,新代码(PR `#2150` 后)将 `StoryMode.SKIP` 的逻辑拆分为两段:先单独用 `round_by_ocr_and_click` 尝试点击"跳过";若未命中,再用 `round_by_ocr_and_click_by_priority(['菜单', '自动'], ...)` 兜底。在这个兜底路径中,点击"自动"的语义是:主线剧情中需要先点击"自动"按钮才能解锁"跳过"入口,并非"退出自动播放"。因此,命中"菜单"或"自动"后无条件将 `self.is_skip_in_main_story = True` 是正确行为,不需要区分 `result.status`。

Learnt from: Usagi-wusaqi
Repo: OneDragon-Anything/ZenlessZoneZero-OneDragon PR: 0
File: :0-0
Timestamp: 2025-11-02T14:24:09.448Z
Learning: 对于 OneDragon-Anything/ZenlessZoneZero-OneDragon 仓库,用户偏好审查关注实质性问题(逻辑错误、bug、性能问题等),避免花费时间在标点符号和注释格式等细枝末节的建议上。

Learnt from: Usagi-wusaqi
Repo: OneDragon-Anything/ZenlessZoneZero-OneDragon PR: 2083
File: src/zzz_od/application/commission_assistant/commission_assistant_app.py:376-384
Timestamp: 2026-03-14T15:57:27.675Z
Learning: 在 `src/zzz_od/application/commission_assistant/commission_assistant_app.py` 的 `story_mode` 方法中,`StoryMode.SKIP` 分支在调用 `round_by_ocr_and_click_by_priority` 并检查确认框后,若确认框未检测到则会继续执行 `_do_dialog_click()`。作者确认这不会造成干扰——游戏 UI 保证在该场景下落入 `_do_dialog_click()` 是安全的,无需提前 return 来阻止此行为。

Learnt from: kawayiYokami
Repo: OneDragon-Anything/ZenlessZoneZero-OneDragon PR: 2080
File: config/auto_battle_operation/连携-取消.sample.yml:12-17
Timestamp: 2026-03-07T12:12:37.101Z
Learning: In `config/auto_battle_operation/连携-取消.sample.yml` for OneDragon-Anything/ZenlessZoneZero-OneDragon, the trailing "按键-连携技-取消-按下" operations at the end of the sequence without corresponding "松开" are intentional. The design is to maintain a sustained held state (持续按下). The single "按键-连携技-取消-松开" in the middle is a brief release specifically to ensure subsequent presses can register (防止按不下), not to form complete independent click pulses. Do not flag missing "松开" for these trailing press operations.

Learnt from: kawayiYokami
Repo: OneDragon-Anything/ZenlessZoneZero-OneDragon PR: 1394
File: config/auto_battle_state_handler/速切模板-席德.sample.yml:44-53
Timestamp: 2025-09-05T10:15:55.306Z
Learning: For auto-battle configurations in ZenlessZoneZero-OneDragon, when using "按键-普通攻击-按下" followed by a wait period, the corresponding "按键-普通攻击-抬起" may not be necessary as the system likely handles key release automatically or has other mechanisms in place.

Learnt from: Usagi-wusaqi
Repo: OneDragon-Anything/ZenlessZoneZero-OneDragon PR: 2067
File: src/zzz_od/application/world_patrol/operation/transport_by_3d_map.py:359-361
Timestamp: 2026-03-05T05:01:13.014Z
Learning: 在 OneDragon-Anything/ZenlessZoneZero-OneDragon 仓库中,不要对代码注释中的任何问题(包括全角/半角符号、标点符号、格式、措辞等)提出审查反馈或建议。只关注实质性的逻辑问题、bug 和性能问题。
✅ Actions performed

Reviews resumed.


Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/one_dragon/base/controller/pc_controller_base.py`:
- Around line 525-551: In win_click, save the current global pyautogui.PAUSE
into a local variable at method start and, if you set pyautogui.PAUSE = 0.001
for low_delay, wrap the click logic in a try/finally where the finally always
restores pyautogui.PAUSE from that saved local value (do not restore from
self.pyautogui_pause); let any exceptions propagate after restoring so the
global pause is never left altered.

In `@src/one_dragon/utils/cv2_utils.py`:
- Around line 1263-1281: After calling crop_image(img, rect) add an immediate
empty-image guard: if the returned img has img.size == 0 then short-circuit and
return False (or the function's appropriate falsy/invalid result) to avoid
computing total, performing count/total and misclassifying out-of-bounds crops;
place this check right after the crop_image(...) call that assigns img and
crop_rect and before computing total/percent.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 264-266: The branch that calls
self.ctx.withered_domain.init_before_run() fails to set the guard flag, so
init_before_run() may run every cycle; after calling init_before_run() inside
the if not self.withered_domain_inited: block, set self.withered_domain_inited =
True (or the appropriate state flag) to mark initialization complete, ensuring
subsequent runs skip re-initialization; update any related teardown/reset logic
if needed to flip the flag when the domain should be reinitialized.
- Around line 228-230: The code appends to self.chosen_opt_history before
checking if to_click is None, causing None to be recorded and polluting
duplicate-suppression; move the append so it only runs after you confirm a real
click target (i.e., check to_click is not None first), updating the logic in the
method that uses chosen_opt_history / to_choose_opt / to_click to append only
when a valid to_click exists and the click action will proceed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3fbfd5d6-3d16-4820-a270-5f09fae3feb8

📥 Commits

Reviewing files that changed from the base of the PR and between 149507f and 709b6ee.

📒 Files selected for processing (9)
  • assets/game_data/screen_info/_od_merged.yml
  • assets/game_data/screen_info/commission_assistant.yml
  • src/one_dragon/base/controller/controller_base.py
  • src/one_dragon/base/controller/pc_controller_base.py
  • src/one_dragon/utils/cv2_utils.py
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py
  • src/zzz_od/application/commission_assistant/commission_assistant_config.py
  • src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py
  • src/zzz_od/hollow_zero/event/hollow_event_utils.py
💤 Files with no reviewable changes (1)
  • src/zzz_od/hollow_zero/event/hollow_event_utils.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/zzz_od/application/commission_assistant/commission_assistant_config.py
  • src/zzz_od/gui/view/game_assistant/commission_assistant_interface.py

Comment thread src/one_dragon/base/controller/pc_controller_base.py Outdated
Comment thread src/one_dragon/utils/cv2_utils.py Outdated
Comment thread src/zzz_od/application/commission_assistant/commission_assistant_app.py Outdated
Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (3)
src/one_dragon/utils/cv2_utils.py (1)

1263-1268: 已处理裁剪后空图检测,但存在未使用变量。

Line 1267-1268 的空图检测逻辑正确解决了潜在的除零问题。但 Line 1265 的 crop_rect 变量从未使用,应改为 _ 以符合 Python 惯例。

💡 建议修改
     # 裁剪图片
     if rect is not None:
-        img, crop_rect = crop_image(img, rect)
+        img, _ = crop_image(img, rect)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/one_dragon/utils/cv2_utils.py` around lines 1263 - 1268, The variable
crop_rect returned from crop_image in the block inside cv2_utils.py is never
used; update the unpacking to use a throwaway name (e.g., change "img, crop_rect
= crop_image(img, rect)" to "img, _ = crop_image(img, rect)") so it follows
Python conventions and avoids an unused-variable warning while keeping the
existing post-crop empty-image check (the code involving crop_image and the
subsequent img is None or img.size check should remain unchanged).
src/zzz_od/application/commission_assistant/commission_assistant_app.py (1)

149-149: 未使用变量 center_rect

裁剪结果的 center_rect 未被使用,建议改为 _ 占位符。

💡 建议修改
-            center_image, center_rect = cv2_utils.crop_image(self.last_screenshot, center_area.rect)
+            center_image, _ = cv2_utils.crop_image(self.last_screenshot, center_area.rect)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py` at
line 149, The variable center_rect returned from cv2_utils.crop_image is unused;
change the unpack to use a placeholder underscore to signal an intentionally
ignored value (e.g., replace "center_image, center_rect =
cv2_utils.crop_image(self.last_screenshot, center_area.rect)" with
"center_image, _ = cv2_utils.crop_image(self.last_screenshot,
center_area.rect)"), updating the occurrence in the method of
CommissionAssistantApp where self.last_screenshot and center_area.rect are
passed.
src/one_dragon/base/controller/pc_controller_base.py (1)

538-552: try/finally 已实现,但恢复值来源仍有风险。

异常安全已通过 try/finally 处理,这很好。但当前从 self.pyautogui_pause(初始化时保存的值)恢复,而非方法入口时保存的当前值。若运行期间 pyautogui.PAUSE 被其他代码修改,此处会覆盖那些调整。

💡 建议修改
     def win_click(self, pos: Point = None, press_time: float = 0, primary: bool = True, low_delay: bool = False):
         btn = pyautogui.PRIMARY if primary else pyautogui.SECONDARY
         if pos is None:
             pos = get_current_mouse_pos()

+        previous_pause = pyautogui.PAUSE
         if low_delay:
             pyautogui.PAUSE = 0.001

         try:
             if press_time > 0:
                 pyautogui.moveTo(pos.x, pos.y)
                 pyautogui.mouseDown(button=btn)
                 time.sleep(press_time)
                 pyautogui.mouseUp(button=btn)
             else:
                 pyautogui.click(pos.x, pos.y, button=btn)
         finally:
             if low_delay:
-                pyautogui.PAUSE = self.pyautogui_pause
+                pyautogui.PAUSE = previous_pause
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/one_dragon/base/controller/pc_controller_base.py` around lines 538 - 552,
The current finally block restores pyautogui.PAUSE from self.pyautogui_pause
which can overwrite any changes made by other code during this method's
execution; instead capture the current value of pyautogui.PAUSE at the start of
the method (e.g., orig_pause = pyautogui.PAUSE) before you change it when
low_delay is true, then in the finally restore pyautogui.PAUSE = orig_pause;
update the logic around the low_delay branch that sets pyautogui.PAUSE and the
finally that restores it, leaving self.pyautogui_pause untouched.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/one_dragon/base/controller/pc_controller_base.py`:
- Around line 538-552: The current finally block restores pyautogui.PAUSE from
self.pyautogui_pause which can overwrite any changes made by other code during
this method's execution; instead capture the current value of pyautogui.PAUSE at
the start of the method (e.g., orig_pause = pyautogui.PAUSE) before you change
it when low_delay is true, then in the finally restore pyautogui.PAUSE =
orig_pause; update the logic around the low_delay branch that sets
pyautogui.PAUSE and the finally that restores it, leaving self.pyautogui_pause
untouched.

In `@src/one_dragon/utils/cv2_utils.py`:
- Around line 1263-1268: The variable crop_rect returned from crop_image in the
block inside cv2_utils.py is never used; update the unpacking to use a throwaway
name (e.g., change "img, crop_rect = crop_image(img, rect)" to "img, _ =
crop_image(img, rect)") so it follows Python conventions and avoids an
unused-variable warning while keeping the existing post-crop empty-image check
(the code involving crop_image and the subsequent img is None or img.size check
should remain unchanged).

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Line 149: The variable center_rect returned from cv2_utils.crop_image is
unused; change the unpack to use a placeholder underscore to signal an
intentionally ignored value (e.g., replace "center_image, center_rect =
cv2_utils.crop_image(self.last_screenshot, center_area.rect)" with
"center_image, _ = cv2_utils.crop_image(self.last_screenshot,
center_area.rect)"), updating the occurrence in the method of
CommissionAssistantApp where self.last_screenshot and center_area.rect are
passed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 55ffde55-155f-4103-a3eb-38bba801260f

📥 Commits

Reviewing files that changed from the base of the PR and between 709b6ee and be00943.

📒 Files selected for processing (3)
  • src/one_dragon/base/controller/pc_controller_base.py
  • src/one_dragon/utils/cv2_utils.py
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (3)
src/one_dragon/utils/cv2_utils.py (1)

1240-1240: 参数缺少类型标注

thresholdrgb_diff_thresholdpercent_rate 参数虽然有默认值,但缺少显式类型标注。按照编码规范,所有函数参数都应包含类型提示。

💡 建议修改
-def is_in_gray_mask(img: MatLike, rect: Rect | None = None, threshold=55, rgb_diff_threshold=20, percent_rate=0.9) -> bool:
+def is_in_gray_mask(img: MatLike, rect: Rect | None = None, threshold: int = 55, rgb_diff_threshold: int = 20, percent_rate: float = 0.9) -> bool:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/one_dragon/utils/cv2_utils.py` at line 1240, The function is_in_gray_mask
is missing explicit type annotations for parameters threshold,
rgb_diff_threshold, and percent_rate; update the signature of is_in_gray_mask to
add types (use int for threshold and rgb_diff_threshold, float for percent_rate)
so it becomes def is_in_gray_mask(img: MatLike, rect: Rect | None = None,
threshold: int = 55, rgb_diff_threshold: int = 20, percent_rate: float = 0.9) ->
bool; ensure any references in the function body or its docstring remain
consistent with these types.
src/zzz_od/application/commission_assistant/commission_assistant_app.py (2)

53-54: 类型标注可以更精确

deque 的类型标注可以更具体,明确指定元素类型。

💡 建议修改
-        self.chosen_opt_history: deque = deque(maxlen=self.chosen_opt_history_max_len)
+        self.chosen_opt_history: deque[str] = deque(maxlen=self.chosen_opt_history_max_len)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`
around lines 53 - 54, The type annotation for chosen_opt_history is too generic;
make it specific by annotating the deque element type (e.g., deque[str] or
typing.Deque[str]) so callers and linters know what element type is stored.
Update the declaration that sets chosen_opt_history and its max len (symbols:
chosen_opt_history_max_len and chosen_opt_history) to use the concrete generic
type and import typing.Deque or use collections.deque[...] accordingly.

159-165: check_main_story() 每次调用都执行 OCR,可能影响性能

_do_dialog_click 中调用 check_main_story() 会触发一次 OCR 操作。如果 _do_dialog_click 被高频调用,可能会影响性能。但考虑到作者已经在 check_story_mode 中做了性能优化(使用 crop_first=True),此处也已使用了裁剪后的区域,影响应该可控。

如果后续发现性能瓶颈,可以考虑缓存 check_main_story() 的结果在当前截图周期内复用。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`
around lines 159 - 165, The call to check_main_story() inside _do_dialog_click
triggers OCR each time and can be cached for the current screenshot cycle;
implement a lightweight cache on the CommissionAssistantApp instance (e.g.,
attributes like _cached_check_main_story_result and
_cached_check_main_story_screenshot_id) and have check_main_story() or
_do_dialog_click check and reuse the cached result when self.last_screenshot (or
its unique id/hash/timestamp) hasn’t changed, and invalidate/update the cache
whenever a new screenshot is captured so subsequent _do_dialog_click calls in
the same cycle use the cached boolean instead of re-running OCR.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/one_dragon/utils/cv2_utils.py`:
- Line 1240: The function is_in_gray_mask is missing explicit type annotations
for parameters threshold, rgb_diff_threshold, and percent_rate; update the
signature of is_in_gray_mask to add types (use int for threshold and
rgb_diff_threshold, float for percent_rate) so it becomes def
is_in_gray_mask(img: MatLike, rect: Rect | None = None, threshold: int = 55,
rgb_diff_threshold: int = 20, percent_rate: float = 0.9) -> bool; ensure any
references in the function body or its docstring remain consistent with these
types.

In `@src/zzz_od/application/commission_assistant/commission_assistant_app.py`:
- Around line 53-54: The type annotation for chosen_opt_history is too generic;
make it specific by annotating the deque element type (e.g., deque[str] or
typing.Deque[str]) so callers and linters know what element type is stored.
Update the declaration that sets chosen_opt_history and its max len (symbols:
chosen_opt_history_max_len and chosen_opt_history) to use the concrete generic
type and import typing.Deque or use collections.deque[...] accordingly.
- Around line 159-165: The call to check_main_story() inside _do_dialog_click
triggers OCR each time and can be cached for the current screenshot cycle;
implement a lightweight cache on the CommissionAssistantApp instance (e.g.,
attributes like _cached_check_main_story_result and
_cached_check_main_story_screenshot_id) and have check_main_story() or
_do_dialog_click check and reuse the cached result when self.last_screenshot (or
its unique id/hash/timestamp) hasn’t changed, and invalidate/update the cache
whenever a new screenshot is captured so subsequent _do_dialog_click calls in
the same cycle use the cached boolean instead of re-running OCR.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3131dd42-ac6c-415a-8544-72c7e688f105

📥 Commits

Reviewing files that changed from the base of the PR and between be00943 and 19dcc8e.

📒 Files selected for processing (2)
  • src/one_dragon/utils/cv2_utils.py
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py

@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from 19dcc8e to c1415cd Compare April 7, 2026 12:01
Copy link
Copy Markdown
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/one_dragon/utils/cv2_utils.py`:
- Around line 1258-1260: The Returns docstring for function is_in_gray_mask is
incorrect (it says True means color and False means gray) — update the Returns
section to accurately state that the function returns a bool where True
indicates the image is in the gray mask (i.e., mostly black/white/gray) and
False indicates it is not; keep the return type as bool and adjust the Chinese
description to reflect this behavior so callers reading the docstring (and the
call site that uses if not cv2_utils.is_in_gray_mask(...): return False) are not
misled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7363a85c-c2f6-4ae8-bacd-1a4cbf1a9112

📥 Commits

Reviewing files that changed from the base of the PR and between 19dcc8e and c1415cd.

📒 Files selected for processing (2)
  • src/one_dragon/utils/cv2_utils.py
  • src/zzz_od/application/commission_assistant/commission_assistant_app.py

Comment thread src/one_dragon/utils/cv2_utils.py
@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from ef11403 to 5eb7b44 Compare April 8, 2026 13:04
@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from 5eb7b44 to 5ddaac4 Compare April 8, 2026 14:24
Copy link
Copy Markdown
Contributor

@Usagi-wusaqi Usagi-wusaqi left a comment

Choose a reason for hiding this comment

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

回归测试通过,其他没所谓

@ShadowLemoon
Copy link
Copy Markdown
Collaborator

pyautogui的那个延迟是什么情况?框架本身有pre_delay 考虑不改签名直接把pyautogui的延迟去掉

@JoshCai233
Copy link
Copy Markdown
Contributor Author

pyautogui的那个延迟是什么情况?框架本身有pre_delay 考虑不改签名直接把pyautogui的延迟去掉

因为这是工具类里面的公共函数,只改pyautogui的延迟的话可能会导致一些其他功能或者其他一条龙的功能(如果同步工具类的话)产生异常,于是我目前采取了添加屎山代码的方式并加一个todo,加一个todo也是提醒你们我在修改公共工具类的代码。
不过我刚看了一下,绝区零一条龙里面只有邦巢跳过的地方用了 长按延迟,修改pyautogui延迟对于绝区零一条龙来说倒是影响不大。
image

@JoshCai233 JoshCai233 force-pushed the 极速自动点委托 branch from 7ea0b2e to c0d179d Compare April 20, 2026 15:55
@JoshCai233
Copy link
Copy Markdown
Contributor Author

@ShadowLemoon

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.

3 participants