Host ability demos on Aliyun OSS instead of Pages bundles; add patches-page version label and top-right mailto link; improve spirit bear portrait export. Co-authored-by: Cursor <cursoragent@cursor.com>
157 lines
13 KiB
Markdown
157 lines
13 KiB
Markdown
# 协作说明(面向 AI 与贡献者)
|
||
|
||
本文件描述 **上分帝(Climperor)** 的职责边界、代码布局与修改注意点。
|
||
|
||
## 项目是什么
|
||
|
||
Windows 上的 Dota 2 **天梯选将识别**工具:用 GSI 感知选将阶段,截屏后对顶栏 10 格做 OpenCV 模板匹配,输出双方阵容与选将时间线。
|
||
|
||
- 中文名:上分帝
|
||
- 英文名 / 仓库目录:Climperor / `climperor`
|
||
- 模板来源:**仅** Steam CDN 官方头像(`templates/cdn/`)
|
||
- **已放弃** real 实拍模板库补充;不要再引入 `templates/real/` 或入库流水线
|
||
|
||
## 目录与模块
|
||
|
||
| 路径 | 职责 |
|
||
|------|------|
|
||
| `common.py` | 配置 IO、槽位几何、裁切、NCC 匹配、天梯遮罩、CDN 模板加载 |
|
||
| `recognize.py` | 单帧识别;`recognize_image()` 供会话复用 |
|
||
| `draft_session.py` | 整局选将跟踪、改判、皮肤规避策略 |
|
||
| `gsi_watch.py` / `gsi_setup.py` | GSI 监听与 cfg 安装 |
|
||
| `http_utils.py` | 所有 fetch 脚本共用的 HTTP 请求、图标下载、Valve datafeed 加载(统一 UA / 超时) |
|
||
| `fetch_patches.py` | 拉取近一年(默认 365 天,`--days`/`--since`)版本列表 + 逐版本 `patchnotes` 详情 → `data/patches.json`;构建 id→名称/图标的 `lookup` 并下载引用到的物品/技能图标(`--no-icons` 跳过;`--force` 重抓全量) |
|
||
| `fetch_cdn_templates.py` | 拉取 CDN 头像 + 生成 `data/heroes.json`(含基础属性/血蓝;保留已有 `aliases`) |
|
||
| `relations.py` | 定性克制/搭档边读写与名称解析 |
|
||
| `import_relations_xlsx.py` | 从选将笔记 xlsx 种子导入 `data/relations.json` |
|
||
| `fetch_stratz.py` | 拉取 STRATZ 对位优势 / 搭档协同 → `data/stratz_matchups.json` / `data/synergies.json`(需 token;`--mode matchups\|synergies`) |
|
||
| `fetch_matchups.py` | 拉取 OpenDota 对位优势 → `data/matchups.json`(供 `audit_relations.py` 交叉审计) |
|
||
| `audit_relations.py` | OpenDota+STRATZ 交叉审计 `relations.json`,列出缺失英雄 |
|
||
| `recommend.py` | 分路过滤;按克制/被克制/搭档边打分,输出 Top-3 |
|
||
| `serve_relations.py` | 游戏外关系/物品只读预览(`web/relations/`;改 `data/relations.json`) |
|
||
| `export_relations_site.py` | 导出关系预览为纯静态站点 → `dist/relations/`(data.json 快照 + 前端 + 图片;`SITE_VERSION` 常量与 `web/relations/config.js` 同步;`--ability-video-base` 写 `config.js` 指向 OSS 技能视频;`--with-videos` 可选本地拷贝视频,生产部署勿用) |
|
||
| `deploy_relations.py` | 一键部署关系预览静态站点到 Cloudflare Pages(导出 + 资产预检 + `wrangler` 直传 + 绑域名;默认 `--ability-video-base` 指向 `climperor` OSS;凭据经 keyzoo 注入或 env) |
|
||
| `_cf_status.py` | 只读查询 Cloudflare Pages 项目 / 部署 / 自定义域名状态(凭据经 keyzoo 注入) |
|
||
| `fetch_hero_portraits.py` | 拉取官网横版头像 → `assets/hero_portraits/`(关系预览) |
|
||
| `fetch_hero_items.py` | 拉取 OpenDota 热门装备 → `data/hero_items.json` + `assets/item_icons/` |
|
||
| `fetch_item_shop.py` | 官网商店 11 列目录(dota2.com.cn/itemscategory)+ 合成图 → `data/item_shop.json` + 图标 |
|
||
| `fetch_items_meta.py` | Valve/OpenDota 装备描述 → 机制标签 → `data/items_meta.json`(`%token%` 用 special_values 填数) |
|
||
| `loc_format.py` | Valve 文案共用:去 HTML、填充 `%token%` / `{s:token}` |
|
||
| `fetch_hero_abilities.py` | Valve herodata 技能/魔晶/神杖/天赋 + 驱散汇总 → `data/hero_abilities.json`;`has_scepter`/`has_shard` 只信 Valve 显式 flag,Valve 移除升级后残留的 `scepter_loc`/`shard_loc` 文案会被清空;逐级相同的 `cast_points`/`channel_times` 合并为单值(施法前摇/吟唱时间);可选 `--icons` / `--icons-only` 缓存 Steam CDN 技能图标 → `assets/ability_icons/`(先天用共用 `innate.png`,不拉 CDN) |
|
||
| `fetch_ability_videos.py` | 官网技能演示 webm/mp4(Steam CDN;限速)→ `assets/ability_videos/`;A 杖/魔晶赋予技能(`granted_by_scepter`/`granted_by_shard`)CDN 名用 `<hero>_aghanims_scepter`/`<hero>_aghanims_shard`,本地文件名仍用 ability key |
|
||
| `item_fears.py` | 规则推导「英雄怕的装备」→ `data/hero_item_fears.json` |
|
||
| `autocalibrate.py` / `calibrate.py` | ROI 自动 / 手动标定 |
|
||
| `capture.py` | 屏幕捕获 |
|
||
| `overlay.py` | 顶栏角色标签 + 选将网格左上角青标 Top-3(点击穿透) |
|
||
| `evaluate.py` | 按 `samples/labels.json` 批量评测 |
|
||
| `roles.py` / `grid.py` / `modes.py` | 位置字、禁用网格、模式字 |
|
||
| `config.json` | 相对坐标、阈值、GSI、recommend 参数 |
|
||
| `data/heroes.json` | 英雄表(id/key/attr/roles/aliases/abbr/tags + 基础属性/初始血蓝等;由 `fetch_cdn_templates.py` 生成) |
|
||
| `data/patches.json` | 近一年版本列表 + 逐版本详情(`patches`/`lookup`/`details`;由 `fetch_patches.py` 生成,预览版本页只读) |
|
||
| `data/relations.json` | 定性克制边 + 搭档边(可提交;手改 JSON,预览页只读) |
|
||
| `data/hero_grid_order.json` | 预览页四列网格顺序 |
|
||
| `data/hero_items.json` | 核心成品装备缓存(预览页只读;由 `fetch_hero_items.py` 生成) |
|
||
| `data/item_shop.json` | 商店 11 列目录(官网 basic/upgrade;由 `fetch_item_shop.py` 生成;物品页只读) |
|
||
| `data/items_meta.json` | 成品装备描述与机制标签(由 `fetch_items_meta.py` 生成) |
|
||
| `data/item_tag_overrides.json` | 装备标签手工加减(合并进 items_meta) |
|
||
| `data/hero_fear_overrides.json` | 英雄→害怕装备手工加减(合并进 item_fears) |
|
||
| `data/hero_abilities.json` | 英雄技能与机制汇总(由 `fetch_hero_abilities.py` 生成) |
|
||
| `data/hero_item_fears.json` | 英雄怕的装备(规则推导;预览「怕」行) |
|
||
| `web/relations/` | 关系只读预览页静态资源(`index.html` / `config.js` / `app.js` / `style.css` / `router.js`);`config.js` 含 `SITE_VERSION` 与 `ABILITY_VIDEO_BASE`;版本页底部显示 `v{SITE_VERSION}` |
|
||
| `web/relations/router.js` | Hash 路由:`parseHash` / `serializeHash` / `installRouter` / `syncStateToUrl`;状态↔URL 双向同步(顶层标签 / 英雄 + 子标签 / 物品 / 版本 / 标签筛选 / 搜索) |
|
||
| `templates/cdn/` | 全英雄 CDN 模板(需提交或由脚本生成) |
|
||
| `templates/roles/` / `templates/modes/` | 位置 / 模式辅助模板 |
|
||
| `assets/role_icons/` | Valve 选人筛选角色图标(`filter_*`,品红 chroma 去黑边) |
|
||
| `assets/hero_portraits/` | 官网横版头像(关系预览;默认 wide 面部构图,非匹配模板) |
|
||
| `assets/attr_icons/` | 官网主属性图标(力量/敏捷/智力/全才,关系预览用) |
|
||
| `assets/item_icons/` | Steam CDN 装备图标(关系预览常用装备) |
|
||
| `assets/item_cat_icons/` | 官网商店分类图标(`itemcat_*.png`,物品页列头) |
|
||
| `assets/ability_icons/` | Steam CDN 技能图标(关系预览;按需缓存);`innate.png` 先天共用图标;`talent_tree.png` 天赋树触发图标 |
|
||
| `assets/ui_icons/` | dota2.com.cn 通用 UI 图标(`cooldown.png` 等,技能详情底栏冷却图标) |
|
||
| `assets/ability_videos/` | 官网技能演示视频(webm/mp4;勿提交,由脚本拉取;线上由阿里云 OSS `climperor` 桶 `ability-video/` 前缀托管) |
|
||
|
||
运行时产物(**勿提交**,见 `.gitignore`):
|
||
|
||
- `samples/raw/<matchid>/` — GSI 会话截图与 `gsi.jsonl`;手动 `capture.py` 可写在 `raw/` 根下
|
||
- `preview/` — 标定 / sheet 预览
|
||
- `dist/` — 静态站点导出(`export_relations_site.py`)
|
||
- `results/` — 每局 JSON
|
||
- `failures/` — `--truth` 调试用错识裁切
|
||
- `data/matchups.json` / `synergies.json` / `stratz_matchups.json` / `relations_audit.json` 等 — 可再生成缓存与报告
|
||
- `assets/ability_videos/` — 官网技能演示(体积大,可再拉取)
|
||
|
||
## 数据流
|
||
|
||
```
|
||
Dota 2 GSI → gsi_watch.py (:3223)
|
||
→ 全量 payload → samples/raw/<matchid>/gsi.jsonl(可关)
|
||
→ DraftSession 轮询截屏 → samples/raw/<matchid>/
|
||
→ recognize_image (CDN 模板 + 可选天梯遮罩)
|
||
→ roles(分路字)/ grid(禁用 + 单元格)/ modes
|
||
→ recommend Top-3(data/relations.json 定性边,本人槽位只信 GSI)
|
||
→ overlay 角色标签 + 网格青标(可选)
|
||
→ results/draft_*.json + 终端时间线
|
||
```
|
||
|
||
## 技术约束(修改前必读)
|
||
|
||
- **合规**:仅 GSI + 屏幕截图;**禁止**读进程内存、注入、绕过 VAC。
|
||
- **GSI 范围**:普通玩家视角拿不到双方 pick;GSI 只作阶段触发、`team_slot`、本人 `hero`、本机 `accountid`/`steamid`。本人顶栏槽位**只信** GSI,不用截屏名字亮度猜测。
|
||
- **克制 / 搭档数据**:定性边存 `data/relations.json`(克制有向 + 搭档无向 + 理由),**不要**用胜率/场次表达机制克制,也**不要**写入 `data/heroes.json`。预览三视图:克制 / 被克制 / 搭档。
|
||
- **装备机制 / 怕的装备**:标签与技能汇总来自 Valve/OpenDota 自动抽取 + `item_tag_overrides.json`;`item_fears.py` 规则映射到英雄弱点。大段技能文案只进 `data/hero_abilities.json` / `items_meta.json`,**不要**塞进 `heroes.json`。本阶段仅关系预览展示,**不对局内出装推荐**。
|
||
- **模板策略**:只维护 CDN 层。皮肤问题用会话策略(选人可改判、决策 `allow_revise=False`、best 帧偏 HERO_SELECTION),不要为皮肤加模板库,也不要复活 real 双层库。
|
||
- **顶栏时机**:皮肤在**全员选完后**才上顶栏;本机进决策时别人可能还在选——须保持 `strategy_tail` 视觉,禁止「一进 STRATEGY 就永久停读」。
|
||
- **坐标**:一律相对坐标(相对屏幕高 / 相对中心),勿写死像素分辨率。
|
||
- **宁可不认,不可乱认**:`min_score` + `min_margin` 双门控;不确定就 `null`。
|
||
- **平台**:面向 Windows;截屏依赖无边框/窗口模式。
|
||
|
||
## 开发命令
|
||
|
||
```powershell
|
||
pip install -r requirements.txt
|
||
python fetch_cdn_templates.py
|
||
python import_relations_xlsx.py # 可选:从选将笔记 xlsx 导入关系
|
||
python fetch_hero_portraits.py # 官网横版头像(关系预览)
|
||
python fetch_hero_items.py # OpenDota 热门装备缓存(关系预览)
|
||
python fetch_item_shop.py # 商店分类目录(物品页)
|
||
python fetch_items_meta.py # 装备描述 + 机制标签
|
||
python fetch_hero_abilities.py # 英雄技能 / 驱散汇总
|
||
python fetch_hero_abilities.py --icons-only # 缓存技能图标到 assets/ability_icons/
|
||
python fetch_ability_videos.py # 官网技能演示(限速;默认 webm)
|
||
python item_fears.py # 英雄怕的装备
|
||
python fetch_patches.py # 近一年版本日志 + 详情(版本页)
|
||
python serve_relations.py # 浏览器只读预览 英雄关系 / 物品商店
|
||
python export_relations_site.py # 导出静态站点到 dist/relations/(可部署 Pages)
|
||
python export_relations_site.py --ability-video-base https://climperor.oss-cn-shanghai.aliyuncs.com
|
||
python deploy_relations.py # 部署 dist/relations 到 Cloudflare Pages(凭据经 keyzoo 注入或 env;默认 dota2.refining.dev;技能视频走 OSS)
|
||
python _cf_status.py # 只读查 CF Pages 部署 / 自定义域名状态
|
||
python gsi_setup.py --check
|
||
python gsi_watch.py --once
|
||
python recognize.py samples/raw/<帧>.png --sheet
|
||
python evaluate.py
|
||
```
|
||
|
||
## 修改原则
|
||
|
||
- 只改任务所需逻辑,避免无关重构与大范围格式化。
|
||
- 代码标识符、日志、错误信息、注释用**英文**;用户可见摘要可用中文。
|
||
- 改匹配阈值或裁切时,用 `evaluate.py` / 标注帧验证,并更新 `CHANGELOG.md` 与必要时的 `DESIGN.md`。
|
||
- 改 GSI cfg 时同步核对 `gsi_setup.py` 与 Dota `gamestate_integration` 目录。
|
||
- 改预览路由形态(URL 段 / query 参数 / 默认值)时同步 `web/relations/router.js`(`parseHash` / `serializeHash`)与 `app.js` 的 `applyPatch` 校验;新增可路由状态维度时在两处都加,并在 `syncStateToUrl` 调用点(含搜索 debounce)接好。Hash 路由不命中后端,`serve_relations.py` 无需改;`export_relations_site.py` 的导出文件列表须含 `router.js`。
|
||
- 改 `data/heroes.json` 结构时同步 `grid.py`(依赖 `attr` / `name_loc`);`roles` 供 `overlay.py` 使用;`aliases` 为中文口语/俗称(勿与 `name_loc` 重复),重跑 `fetch_cdn_templates.py` 会按 `key` 合并保留;`tags` 为中文定位(核心/辅助/…/幻象,由 `roles`+幻想系推导),仅关系预览筛选用;基础属性/血蓝等数值字段供关系预览详情条,勿塞机制文案。
|
||
- 发版关系预览时同步 bump `export_relations_site.py` 的 `SITE_VERSION`、`web/relations/config.js` 的同名变量,以及 `index.html` 里 `config.js`/`router.js`/`app.js` 的 `?v=` 缓存戳;并写 `CHANGELOG.md`。
|
||
- 不要重新引入 real 模板双层库、`cdn_penalty`、`build_library.py`。
|
||
|
||
## 文档分工
|
||
|
||
| 文件 | 内容 |
|
||
|------|------|
|
||
| `README.md` | 安装与操作手册 |
|
||
| `DESIGN.md` | 背景、选型、关键实测与决策记录 |
|
||
| `AGENTS.md` | 本文件:给协作者 / AI 的约束 |
|
||
| `CHANGELOG.md` | 面向用户的版本变更 |
|
||
|
||
## 与 dota2-hex
|
||
|
||
本仓库独立演进。并入或旁路对接时,仍须遵守 [dota2-hex/AGENTS.md](../dota2-hex/AGENTS.md) 的合规边界。
|