Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/game/screens/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
| 打开游戏 | [打开游戏.md](打开游戏.md) | 登录页(自动/手动登录多子态:验证码/账号密码/扫码/选区服);已建模 |
| 加载画面 | [加载画面.md](加载画面.md) | 通用加载画面(lore 轮换);screen_info 缺口 |
| 大世界 | [大世界.md](大世界.md) | Overworld 主画面(活动入口/任务/快捷键);已建模(is_precise) |
| 战斗画面 | [战斗画面.md](战斗画面.md) | 战斗实动作界面;唯一标识=攻击按钮模板(id_mark 无,框架走 is_normal_attack_btn_available);子态:默认/精英(BOSS血条)/限时(倒计时)/战斗结果 |
| 邮件 | [邮件.md](邮件.md) | 每日领取邮件附件(菜单→邮件);列表态 + 确认弹窗子态已建档 |
| 菜单-更多功能 | [菜单-更多功能.md](菜单-更多功能.md) | 菜单点「更多」;功能入口枢纽(预备编队/兑换码/登出);已建模 |
| 兑换码输入 | [兑换码输入.md](兑换码输入.md) | 兑换码输入框(菜单-更多功能→兑换码);screen_info 缺口;结果弹窗待补 |
Expand Down
89 changes: 89 additions & 0 deletions docs/game/screens/战斗画面.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
screen_name: 战斗画面
appears_in: [实战模拟室, 区域巡防, 专业挑战室, 恶名狩猎, 式舆防卫战, 迷失之地, 枯萎之都, 零号空洞]
last_updated: 2026-07-18
source_image: _1784380238240.png
---

# 战斗画面

## 何时出现 + 状态流转

进入任何副本/挑战后自动进入。退出条件:
- 敌人全灭 → **战斗结果**子态(完成/再来一次/退出/撤退/已达成/倒带)
- 按 esc / 点左上角 → **战斗-菜单**(暂停菜单)
- 角色全灭 → 失败结算

**子态**:
| 子态 | 入口 | 出口 |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
|---|---|---|
| 默认(普通战斗) | 进入副本 | 敌人全灭→战斗结果 / esc→战斗-菜单 |
| 精英怪(有BOSS血条) | 精英/Boss战开始 | 同上;右上角多BOSS血条 |
| 限时关卡 | 限时挑战开始 | 同上;右上角多倒计时 |
| 战斗结果 | 敌人全灭 | 点完成/再来一次/退出/撤退→下一画面 |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

## 识别特征(稳定锚点)

- **唯一稳定标识**:`按键-普通攻击` 模板(conf ~0.97)。其余 UI 元素(血条/计时/连携条/技能图标/角色头像)随角色、敌人、数值动态变化,**不可做标识**。
- **无 `id_mark: true`** → `is_precise=false`(非精确匹配)。
- **框架不靠 screen_name 精确匹配判战斗态**:直接调 `is_normal_attack_btn_available()`(攻击按钮模板在不在)→ 返回 `in_battle` bool。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

## 可交互元素

| 元素 | 类型 | 备注 |
|---|---|---|
| 按键-普通攻击 | template | 唯一稳定标识;战斗态判定锚点 |
| 按键-特殊攻击 | template | |
| 按键-终结技 | template | |
| 按键-交互 | template | 对话/拾取/交互 |
| 按键-切换角色 | template | |
| 按键-切换后援标记 | template | |
| 连携技-1 / 连携技-2 | template | 连携技选择 |
| 连携条 | template | 连携点数显示 |
| 菜单 | template | 左上角,点→战斗-菜单 |
| 标识-BOSS血条 | template | 精英/Boss战出现(右上角) |
| 式舆防卫战-倒计时 | template | 限时关卡出现(右上角) |
| 式舆防卫战-倒计时-精英 | template | 限时+精英同时出现 |
| 距离显示区域 | area | NPC距离检测区域 |
| 头像-3-1 / 3-2 / 3-3 / 2-2 | template | 角色头像位置(编队人数决定哪几个显示) |
| 战斗结果-完成 | text | 结算按钮 |
| 战斗结果-再来一次 | text | 重复挑战 |
| 战斗结果-撤退 | text | 放弃 |
| 战斗结果-退出 | text | 离开 |
| 战斗结果-已达成 | text | 特训目标达成 |
| 战斗结果-倒带 | text | 重播 |

## 识别快照

### 1. 默认(普通战斗)(source_image: _1784380238240.png)

- **匹配画面**:`战斗画面` `is_precise=false`
- **匹配 area**:
| area_name | 类型 | conf |
|---|---|---|
| 按键-普通攻击 | template | 0.973 |
- **全量 OCR**:HP `10664/10664`、任务目标"完成专业挑战/通关时长不超过6分钟/3分钟"、`Space`(键位提示)。
- **右上角无BOSS血条/倒计时**(普通战斗)。

### 2. 精英怪(有BOSS血条)(source_image: _1784381316590.png)

- **匹配画面**:`战斗画面` `is_precise=false`
- **匹配 area**:
| area_name | 类型 | conf |
|---|---|---|
| 按键-普通攻击 | template | 0.976 |
| 标识-BOSS血条 | template | 0.981 |
- **全量 OCR**:HP `10664/10664`、倒计时 `00:10.88`(限时关卡)、`UPROAR`(敌人名)、`Space`。
- **右上角有BOSS血条 + 倒计时**(精英+限时同时出现)。

## 备注

- **id_mark 缺失(已知、可接受)**:battle.yml 中无 area 设 `id_mark: true`。框架走 `is_normal_attack_btn_available` 直查攻击按钮判战斗态,不依赖 screen_name 精确匹配。若需精确 screen 匹配,可给 `按键-普通攻击` 设 `id_mark: true`(当前不设也能工作)。
- **误匹配隐患**:`is_precise=false` → analyze_screen 可能误匹配到其他含攻击按钮模板的画面(如 `迷失之地-大世界` 的 `战斗-菜单` 模板)。不影响 app(app 用 area 直查),影响 analyze_screen 诊断。
- **vision 结果**(2026-07-18,analyze_image 编码 CDN URL):
- 布局:上方角色头像+血条+技能图标(菱形);中间战斗场景(角色/精英怪/建筑);下方操作按钮区。
- 右上角:绿色进度条("00")+ 计时器(00:10.99)+ 黄色圆形图标。
- 右下角按钮(从左到右):黑色圆形×2 → 紫色圆形(星形图案)→ 黄色圆形("M"图案)→ "E" → "Space"。
- 左上角:角色头像 + 血条(10664/10664)+ 技能图标 + "1000PTS"/"UPROAR"。
- 血条/倒计时:角色血条(左上)、精英怪血条(中上)、倒计时(右上)。
- **screen_info 文件**:`assets/game_data/screen_info/battle.yml`(screen_name: 战斗画面)。
73 changes: 73 additions & 0 deletions skills/zzz-od-dev-pr-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
name: zzz-od-dev-pr-review
description: 当要审查/验证一个 open PR 是否可合并时用。英文 review/verify a PR、check if mergeable、validate PR functionality、PR code review。
---

# PR 审查验证

审查一个 PR 时,按 L0→L4 逐级验证,每级有则记无则跳,最终给"可合并 / 可合并但有建议 / 需返工 / 无法验证(写明缺什么)"结论。
**先做 L1/L2(总做、不依赖环境),再按 PR 类型决定是否 L3/L4。** 游戏流程类 PR,L4 live 是硬性要求(不是可选项)。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

## 0. 准备:分支与基线(每个 PR 必做)

**原则:在"PR + 当前 main"的集成结果上审查,不在旧 base 上审。** PR 基于旧 main,旧 base 上审会漏集成问题(API 不兼容、被 main 改过的同文件、依赖 main 新加的文件等)。

- 用提交者分支(`gh pr checkout <n>`,拉的是 PR 当前 HEAD;不要用可能被本地 merge 污染的旧本地分支)。
- **先 `git merge origin/main`**:确保改动在当前代码上成立。老 PR 不 merge 可能缺文件 / 跑崩;merge 后才有"这个 PR 真能合、合了不崩"的判断基线。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- merge 冲突 → 见 §6(先解冲突再审,解的过程本身也暴露集成影响)。
- **审完再决定改不改**:看到 review comment(CodeRabbit / 人)不要先改代码——先在 merged 代码上审(理解改动 + 框架语义),再决定 comment 采纳(改)还是驳回(说明理由)。顺序:merge → 审 → 评 comment → 改。
- 每个 PR 开一个 notes,记:背景核实 / 改动合理性 / 每级验证结果 / 结论 / 给 reviewer 的要点。
- **测试仓对应**:每个 PR 检查 `zzz-od-test` 有无对应分支 + 截图 fixture;**没有则自己建**(`git -C zzz-od-test checkout -b <同名分支>` + 相关画面截图拷到 `screens/<画面名>/默认.png`)。测试改动走 `git -C zzz-od-test`(主仓 gitignore 会静默跳过)。
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

## 1. L0 分诊

前端 / CI / 纯 git 启动逻辑 → 一般 skip(记原因)。业务逻辑 / 画面识别 / 操作流程 → 继续。

## 2. L1 静态审查(总是做)

读 diff + 相关代码。查:逻辑错误、回归、死循环、资源泄漏、是否复用现有模式(Application / Operation / config / setting card)、类型注解、1080p 硬编码合理性。

**框架语义必查项**(任一错就运行时崩,逐条对照源码确认):
- **生命周期钩子 `after_operation_done` / `op_callback`**:在 success 和 fail 都会触发(在结果判断之外)。**必查**:若 PR 在此做了自定义清理(如 stop_xxx),该清理有**几个子步骤**?任一步骤抛异常的概率?若有异常风险 → **基类调用必须在 `finally` 里**(try 包自定义清理,finally 包基类清理),否则 run_record/notify/`APPLICATION_STOP` 等基类清理被跳过。这是"代码看着对但异常路径漏"的高发点,不要只看 happy path。
- **节点重试预算**:`round_wait` 重置 `node_retry_times`(无界),只有 `round_retry` 消耗、超 `node_max_retry_times`(默认 3)才 FAIL。审"删除大 `node_max_retry_times`"的重构时,确认主路径走 `round_wait`(否则默认 3 不够)。
- **`@operation_node` 装饰器**:只挂元数据、原样返回 func → 可直接调用被装饰方法;节点调度读元数据。删/改节点不影响直接调用。
- **`execute()` 重复调用安全**:每次开头全重置(节点图 + 重试计数 + `handle_init`)。retry 包 `execute` 的模式安全。
- **节点路由 `node_from(status=...)`**:契约从"抛异常"改"返回 None/默认值"时,**逐个消费方确认 None-safe**(否则只是把崩溃换地方)。`ignore_status` + `status` 组合决定路由,有疑义查匹配源码。

## 3. L2 背景核实

PR 描述 / 关联 issue 提到的游戏行为 / bug 是否属实?对 `assets/game_data/screen_info/`(画面模型)、`docs/game/`(玩法)、相关代码路径交叉验证。issue 标题/日志往往透露真实复现路径(如"某 app 复用同一 operation"会扩大影响范围)。

## 4. L3 离线运行(不改游戏状态)

- 用测试仓留档截图喂 `analyze_screen`,验画面识别 / OCR 是否如改动静称。
- **自定义 OCR / 识别管线**(颜色 mask + ROI 切分等):写脚本用项目 ctx 在截图上复刻该管线再断言(比整图默认 OCR 强,能抓串扰)。
- PR 自带测试:直接 `pytest` 跑。

## 5. L4 live 运行(游戏流程类 PR 硬性要求)

**想办法在游戏里验证**,优先可逆、低消耗路径:
- 导航到目标画面(`click_game` / 通用 op 如 GotoMenu)→ `capture_game_screen` / `analyze_screen` 在**实时截图**上验识别/行为。
- 避开消耗周限/体力/日限的动作与"停止托管"等不可逆按钮;导航类(菜单/仓库/快捷手册)对后台托管无害。
- **server 跑当前检出分支的代码**:要验某 PR 流程 → checkout(先 merge main)→ 经 daemon 重启 server → server 即该分支逻辑 → `run_operation` / `run_standalone_app` 驱动 + `get_run_status` 观察。
- 大世界等需解锁光标的画面,`click_game` 传 `pc_alt=true`;子画面/菜单 `false`。
- **沿途画面若 screen_info 未建模 → 顺便建档**(补 area/screen_info;走 `zzz-od-dev-screen-onboarding`)。
- 真无法 live(纯消耗且无低消耗切入 / 需特定账号或地区 / 需外部凭据)→ 明确标"无法 live 验证"并写明缺什么,**不要假装验过**。

## 6. 冲突解决(merge origin/main 时)

- **看实际冲突再判断,别预设复杂**:很多"看似游戏流程"的冲突其实机械可解(注释 / import / 不同区域 additive)。
- 逻辑纠缠(同文件两侧都改核心)→ **先 live 建档该玩法**(搞清当前真实结构),再据此融合,不盲合。
- 解完必验证三连:`py_compile` + `ruff` + **`import` 冒烟**(import 比 compile 强,抓运行时导入/符号缺失)。

## 7. 结论与产出

每 PR 给明确结论 + reviewer 要点。性能 / 过程建议即便非阻塞也记(给 maintainer 决策)。
PR 收尾(处理 review comment、推到可合并)走 `zzz-od-dev-pr-finishing`;单条 review comment 处理走 `superpowers:receiving-code-review`。

## 通用原则

- **追源码确认,别照 description 行事**:框架语义(op_callback 触发时机、round_wait/retry 预算、路由匹配)以源码为准,PR description 可能省略。
- **删配置项/重构类**:grep 全量残留引用 + 确认迁移完备 + 测试仓同步检查。
- **巨型 PR**:抽查高风险模块(有测试的优先 L3 实跑),诚实标注未深审范围,建议拆分而非整体背书。
- **性能**:涉及热路径(战斗循环/OCR 推理)的改动,看锁粒度与阻塞——`Future.result()` 同步等、推理期持锁串行化,默认配置下影响所有用户时尤其要标。
58 changes: 58 additions & 0 deletions skills/zzz-od-dev-pr-review/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# design.md — zzz-od-dev-pr-review

## 为什么做这个 skill

项目痛点:PR 提交后**无人验证功能**(作者自测,review 多停留在代码层,功能没跑)。需要一个系统化的"审查 + 验证"方法论,让审查者不只看 diff,还核实背景、跑逻辑、验画面、给可合并结论。本 skill 沉淀这套方法论(从 30 个 open PR 的实操中提炼)。

## 定位与边界

- **管**:一个 PR 从"拿到分支"到"给可合并结论"的全流程(分诊 → 静态审查 → 背景核实 → 离线/ live 验证 → 冲突解决 → 结论)。
- **不管**:PR 收尾(处理 review comment / 推可合并 / checks)→ `zzz-od-dev-pr-finishing`;单条 review comment 处理 → `superpowers:receiving-code-review`;画面建模细节 → `zzz-od-dev-screen-onboarding`。
- 引用上述 skill 而非重复。

## 关键决策与理由

### 1. "先 merge main 再审"是原则,不是可选步骤
- **决策**:每个 PR 必须先 `git merge origin/main`,在集成结果上审。
- **理由**:PR 基于旧 main,在旧 base 上审 = 审一个不存在的世界——漏 API 不兼容、被 main 改过的同文件、依赖 main 新加文件等问题。只有集成后的代码才是"这个 PR 合了实际长什么样"。
- **踩坑论据**:老 PR(#2300 等)缺 main 后加的 `server.py`,不 merge 直接在分支跑 server → `No module named` 崩;merge 后才正常。曾因没先 merge 就改代码被用户纠正——顺序必须 merge → 审 → 改,不能跳。

### 2. L0~L4 验证分级
- **决策**:分诊(L0)→ 静态(L1)→ 背景(L2)→ 离线(L3)→ live(L4),逐级有则记无则跳。
- **理由**:不同 PR 需要不同深度(纯框架代码 L1 够;画面识别要 L3;游戏流程要 L4)。分级避免一刀切(全做 L4 太重,只做 L1 不够)。
- **L1 总做**:代码层问题(逻辑错/回归/泄漏)任何 PR 都要查。
- **L4 对游戏流程类 PR 是硬性要求**:功能没在游戏里跑过 = 没验。但优先可逆低消耗路径(导航,不消耗周限/体力)。

### 3. 框架语义必查项
- **决策**:L1 里固定查 5 项框架语义(after_operation_done/op_callback 触发时机、round_wait vs round_retry 重试预算、@operation_node 装饰器行为、execute 重置、node_from 路由)。
- **理由**:这些是"代码看起来对但运行时崩"的高发点——错了不是 style 问题,是真崩/死循环/泄漏。逐条对照源码确认,别照 PR description 行事。
- **踩坑论据**:
- #2459 的 CodeRabbit comment 抓到了 `after_operation_done` 里 stop_auto_battle 抛异常会跳过基类清理 → 应 try/finally。我初轮 review 漏了这条(只做了 L1 表面审),说明框架语义要显式列出来查,不能靠"扫一眼"。
- #2503 删大 `node_max_retry_times=300` 看似回归,查源码发现主路径走 round_wait(无界)→ 安全。
- #2388 把"抛异常"改"返回 None",逐个消费方确认 None-safe(AppRunCard 本就 None-safe)→ 否则只是位移崩溃。

### 4. 冲突→建档→解
- **决策**:解 merge 冲突时,游戏流程类(同文件两侧改核心逻辑)要先 live 建档该玩法,理解当前真实结构再融合;框架/纯代码类直接解。
- **理由**:盲合游戏流程冲突会错配(不知道当前游戏画面/流程长什么样)。先建档(搞清现实)才能判断哪边对、怎么融。
- **踩坑论据**:#2300(charge_plan 三 PR 纠缠)——正是先 live 建档了 charge_plan 玩法(资源栏+道具处理),才正确融合了 #2300 的兑换以太电池与 main 的每日重置/双倍活动,没靠盲合。反例:曾预设"游戏流程冲突必复杂",实际看了发现很多是机械可解(注释/import/不同区域 additive)——别预设,看实际冲突。

### 5. live = 验证 + 熟悉游戏 + 顺路建档(三位一体)
- **决策**:live 进游戏不只是验 PR,沿途画面若未建档顺便补 screen_info。
- **理由**:live 过程天然接触真实画面,顺手建档成本最低、价值叠加。screen_info(.yml 机器模型)就是"建档"(本仓 docs/game/ 尚未建立人读约定)。

### 6. 解冲突后必做 import 冒烟
- **决策**:解完冲突除 py_compile + ruff,还要 `import` 冒烟(实际导入模块)。
- **理由**:py_compile 只查语法,import 抓运行时导入/符号缺失(合并后某侧删了符号另一侧还引用)。三连验证才稳。

## 落点

- 目录:根 `skills/zzz-od-dev-pr-review/`(跨工具源,提交共享)。
- 前缀:`zzz-od-dev-`(开发流程类)。
- junction:`.claude/skills/zzz-od-dev-pr-review` → 根 skills/(本地,不提交)。
- 结构:`SKILL.md`(方法论入口)+ `design.md`(本文件)。

## 与现有 skill 的关系

- `zzz-od-dev-pr-finishing`:PR 收尾(已开 PR 推可合并)。本 skill 是**收尾前的审查验证**;审完给结论,收尾走 pr-finishing。
- `zzz-od-dev-screen-onboarding`:画面建档。本 skill L4 live 时"顺路建档"引用它。
- `superpowers:writing-skills`:通用 skill 结构/frontmatter。本 skill 的项目特定部分(4 硬规范 + 落点)由 `zzz-od-dev-skill-guide` 管。
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,9 @@ def handle_resume(self, e=None):
self.ctx.auto_battle_context.resume_auto_battle()

def after_operation_done(self, result: OperationResult) -> None:
self.ctx.auto_battle_context.stop_auto_battle()
ZApplication.after_operation_done(self, result)
# try/finally 保证基类 after_operation_done 必跑(运行记录/通知/APPLICATION_STOP),
# 即便 stop_auto_battle(多步收尾)抛异常也不跳过(CodeRabbit review)。
try:
self.ctx.auto_battle_context.stop_auto_battle()
finally:
ZApplication.after_operation_done(self, result)
Loading