v0.2.0: relations preview, item shop, abilities, overlay recommend, GSI enhancements
- Add relations/item/abilities preview (serve_relations.py + web/relations/) - Add fetch scripts: hero_items, item_shop, items_meta, hero_abilities, ability_videos, patches, stratz, matchups, portraits - Add overlay.py (role tags + Top-3 cyan marks), recommend.py - Add http_utils.py, loc_format.py, hero_tags.py, item_fears.py - GSI: full payload JSONL dump, foreground window detection - Drop real template library; CDN-only matching - Update docs: CHANGELOG 0.2.0, DESIGN config table, AGENTS module table - .gitignore: exclude large regenerable assets (icons/portraits/videos)
This commit is contained in:
@@ -22,15 +22,15 @@ import json
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from common import ROOT
|
||||
from common import HEROES_JSON
|
||||
|
||||
ATTR_ORDER = ("str", "agi", "int", "all")
|
||||
|
||||
|
||||
def hero_table() -> list[dict]:
|
||||
table = json.loads((ROOT / "heroes.json").read_text(encoding="utf-8"))
|
||||
table = json.loads(HEROES_JSON.read_text(encoding="utf-8"))
|
||||
if table and "attr" not in table[0]:
|
||||
raise SystemExit("heroes.json predates grid support - rerun fetch_cdn_templates.py")
|
||||
raise SystemExit(f"{HEROES_JSON.name} predates grid support - rerun fetch_cdn_templates.py")
|
||||
return table
|
||||
|
||||
|
||||
@@ -151,24 +151,30 @@ def read_grid(img: np.ndarray, cfg: dict | None = None) -> dict:
|
||||
table = hero_table()
|
||||
grid = detect_grid(img, cfg)
|
||||
if grid is None:
|
||||
return {"ok": False, "reason": "no grid detected", "unavailable": []}
|
||||
return {"ok": False, "reason": "no grid detected", "unavailable": [], "cells": {}}
|
||||
|
||||
layout = build_layout(grid, table)
|
||||
if layout is None:
|
||||
return {"ok": False, "reason": "grid shape does not fit the roster", "unavailable": []}
|
||||
return {"ok": False, "reason": "grid shape does not fit the roster", "unavailable": [], "cells": {}}
|
||||
if len(layout) != len(table):
|
||||
return {"ok": False,
|
||||
"reason": f"placed {len(layout)} of {len(table)} heroes",
|
||||
"unavailable": []}
|
||||
"unavailable": [], "cells": {}}
|
||||
|
||||
cut = cfg.get("grid", {}).get("unavailable_std", 26.0)
|
||||
scored = {key: cell_contrast(img, grid, r, c) for (r, c), key in layout.items()}
|
||||
unavailable = sorted((k for k, s in scored.items() if s < cut), key=lambda k: scored[k])
|
||||
live = [s for s in scored.values() if s >= cut]
|
||||
cols, rows = grid["cols"], grid["rows"]
|
||||
cells = {
|
||||
key: {"x0": cols[c][0], "y0": rows[r][0], "x1": cols[c][1], "y1": rows[r][1]}
|
||||
for (r, c), key in layout.items()
|
||||
}
|
||||
return {
|
||||
"ok": True,
|
||||
"unavailable": unavailable,
|
||||
"grid": {"cols": len(grid["cols"]), "rows": len(grid["rows"])},
|
||||
"cells": cells,
|
||||
"grid": {"cols": len(cols), "rows": len(rows)},
|
||||
"margin": round(min(live) - max((scored[k] for k in unavailable), default=0.0), 1) if live and unavailable else None,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user