从赛季数据到模板图库:深入解析 tft_fetch_assets.py和TFT 截图识别的资源构建链路

张开发
2026/4/13 22:59:17 15 分钟阅读

分享文章

从赛季数据到模板图库:深入解析 tft_fetch_assets.py和TFT 截图识别的资源构建链路
摘要在TFT 阵容顾问项目里tft_fetch_assets.py 不仅一个“下载图片”的脚本如果把整个项目串起来看该文件承担的是模板资源构建器的角色。它上游连接 tft_data_manager.py 生成的赛季数据下游直接服务 tft_screen_capture.py 的 OpenCV 模板匹配是截图识别链路里非常关键的一层。一. 从整个项目的运行流程理解tft_fetch_assets.py文件的作用tft_data_manager.py ↓ 生成 tft_champion_db.json / tft_item_db.json ↓ tft_fetch_assets.py ↓ 下载并标准化 tft_assets/champions/*.png 与 tft_assets/items/*.png ↓ tft_screen_capture.py ↓ 模板匹配识别英雄、装备、星级、站位 ↓ tft_converter.py / tft_web_ui.pytft_fetch_assets.py 并不是一个孤立的辅助脚本而是整个识别系统的“资源准备层”。它的核心职责如下1. 从本地赛季数据库中读取英雄和装备列表2. 从 DDragon 和 CommunityDragon 下载正确的 TFT 图片资源3. 统一命名与尺寸构建标准模板库4. 输出到 tft_assets/让后续识别模块可以直接加载二. 数据驱动的数据脚本我们项目的资源脚本没有采用直接写死列表的形式,如:CHAMPIONS [Draven, Leona, Braum] ITEMS [Deathblade, BlueBuff]这种写法短期看很方便但一到赛季更新就很难维护。tft_fetch_assets.py 采用的是更稳定的方案所有下载目标都来自 tft_data_manager.py 生成的 JSON 数据库。核心代码如下:def load_champion_db() - dict: p DB_DIR / tft_champion_db.json if not p.exists(): print(f ✗ 找不到 {p}请先运行: python tft_data_manager.py) return {} db json.loads(p.read_text(encodingutf-8)) print(f 英雄数据库: {len(db)} 个英雄 (来自 {p})) return db def load_item_db() - dict: p DB_DIR / tft_item_db.json if not p.exists(): print(f ✗ 找不到 {p}请先运行: python tft_data_manager.py) return {} db json.loads(p.read_text(encodingutf-8)) filtered {k: v for k, v in db.items() if _item_is_valid(k)} print(f 装备数据库: {len(filtered)} 个装备 (来自 {p}原始 {len(db)} 条已过滤)) return filtered我们在这段代码中采用了以下的工程思想脚本不负责定义资源而负责消费标准数据。这样做有两个直接好处1. 赛季更新时只需要先更新数据库资源下载逻辑基本不变2. 文件命名、业务 ID、模板库 key 可以天然保持一致三. 代码文件是如何获取上层数据的?在 tft_data_manager.py 里我们会从 CommunityDragon 或 DDragon 拉取赛季数据再整理成统一格式。例如英雄和装备数据会被整理成这样的字典结构champ_db[api] { id : api, short_id: short, name_en : c.get(name, short), cost : c.get(cost, 0), traits : traits, stats : c.get(stats, {}), } item_db[api] { id : api, name_en : item.get(name, api), desc : item.get(desc, ), unique : item.get(unique, False), composition: item.get(composition, []), }tft_fetch_assets.py 并不是随便抓图片而是基于上游已经整理好的标准业务主键 apiName 来抓图。例如1. 英雄模板最终会命名成 TFT16_Draven.png2. 装备模板最终会命名成 TFT_Item_Deathblade.png这和后面识别模块加载模板时使用的 key 是一一对应的。四. 采取双源回退的下载策略我们采用了如下的资源获取策略:优先 DDragon失败后回退 CommunityDragon。 下载策略按优先级 英雄: 1. DDragon /img/tft-champion/{apiName}.png 2. CommunityDragon /game/assets/characters/{lc_id}/hud/{lc_id}_square.*.png 装备: 1. DDragon /img/tft-item/{apiName}.png 2. CommunityDragon /game/assets/items/icons2d/{lc_id}.png 这个设计考虑了两个资源源站的不同特点1. DDragon 路径更稳定资源命名更规整2. CommunityDragon 更贴近游戏内部资源结构适合作为回退来源项目通过这样的下载策略构建了一条稳定的模板获取链路。核心代码如下:def fetch_champions(ver: str, failed_log: list): champ_db load_champion_db() if not champ_db: return out ASSETS_DIR / champions out.mkdir(parentsTrue, exist_okTrue) cdn fhttps://ddragon.leagueoflegends.com/cdn/{ver} for api_name, entry in champ_db.items(): dest out / f{api_name}.png if dest.exists() and dest.stat().st_size 500: continue short_id entry.get(short_id, api_name) data None for dd_name in _ddragon_champ_candidates(api_name, short_id): data dl(f{cdn}/img/tft-champion/{dd_name}.png) if data: break if not data: for url in _cdragon_champ_urls(api_name, short_id): data dl(url) if data: break if data: dest.write_bytes(resize_image(data, ICON_SIZE)) else: failed_log.append((champion, api_name, str(dest)))按数据库遍历英雄用业务 ID 构建模板文件名优先下载 DDragon 的 TFT 专属头像下载不到再回退 CommunityDragon。可以看到脚本使用的是 /img/tft-champion/而不是普通的 /img/champion/,这是因为普通英雄立绘和 TFT 游戏内实际头像风格并不一样模板匹配时必须保证模板和截图中的目标形态尽量一致。这个选择直接决定了后面的 OpenCV 匹配是否稳定。五. 对英雄名称做候选兼容实际使用第三方资源站时不仅需要考虑“有没有图”还要考虑“命名是否完全一致”。这里我们写了一个候选名函数:def _ddragon_champ_candidates(api_name: str, short_id: str) - List[str]: candidates [ api_name, fTFT_{short_id}, ] _CASE_FIXES { Chogath : ChoGath, Kaisa : KaiSa, Leblanc : LeBlanc, Monkeyking: Wukong, } lc short_id.lower() for dd, db in _CASE_FIXES.items(): if lc db.lower(): candidates.insert(0, fTFT16_{dd}) return candidates候选名函数的作用1. 兼容历史命名格式2. 兼容大小写差异3. 兼容某些特殊英雄的资源命名六. CommunityDragon 回退路径也做了兼容封装除了 DDragon 候选名脚本还把 CommunityDragon 的回退路径统一生成了出来def _cdragon_champ_urls(api_name: str, short_id: str) - List[str]: lc_tft ftft16_{short_id.lower()} lc_base short_id.lower() urls [] for lc in [lc_tft, lc_base]: base f{_CDN_CHARS}/{lc}/hud/{lc} urls [ f{base}_square.tft_set16.png, f{base}_square.png, f{base}_square.tft_set15.png, ] return urls七. 装备模板下载相比英雄装备数据更复杂所以脚本专门做了一层过滤def _item_is_valid(api_name: str) - bool: if _SKIP_RE.search(api_name): return False if api_name.startswith(TFT4_) and Ornn not in api_name: return False if api_name.startswith(TFT9_) and Ornn not in api_name: return False return api_name.startswith(( TFT_Item_, TFT5_Item_, TFT16_Item_, TFT16_TheDarkin, TFT4_Item_Ornn, TFT9_Item_Ornn, ))经过过滤,模板库只保留或许识别真正会用到的资源.八. 完整的命令行设计主入口部分支持这些命令:ap.add_argument(--champs, actionstore_true, help仅下载英雄头像) ap.add_argument(--items, actionstore_true, help仅下载装备图标) ap.add_argument(--verify, actionstore_true, help检查完整性) ap.add_argument(--list-missing, actionstore_true, help列出缺失文件) ap.add_argument(--version, defaultNone, help指定 DDragon 版本默认自动获取) ap.add_argument(--db-dir, default., helpJSON 数据库目录默认当前目录) ap.add_argument(--assets-dir, defaultNone, help模板输出目录默认 ./tft_assets)把资源构建流程工具化,让它可以反复执行,按需执行,校验执行.九. 总结tft_fetch_assets.py是一条面向截图识别的 TFT 模板资源构建流水线。具体实现了以下的功能1. 从标准数据库读取资源目标2. 通过双源策略下载正确素材3. 兼容命名差异与路径差异4. 标准化尺寸与输出结构5. 为 OpenCV 模板匹配准备可直接使用的模板库tft_fetch_assets.py 是一份资源构建脚本。它把“数据、下载、过滤、兼容、标准化、落盘、校验”这几个步骤组织成了一条完整链路让模板资源不再依赖人工维护把模板资源构建设计成一个可重复、可维护、可直接接入识别链路的过程。

更多文章