v0.3.0: game-window picker + NCC recognition + artifacts + ?-merged
- window_capture.py: enumerate top-level windows (pygetwindow) and capture a specific one via PrintWindow PW_RENDERFULLCONTENT (works on non-focused windows). Linux falls back to mss region grab. - recognizer.py: replace MAE matcher with NCC over numpy vectors. Each rotatable slab generates 4 templates (0/90/180/270). Adds 248 artifact templates and an empty-cell heuristic (low mean/std-dev). Cells below confidence floor are tagged "unknown" — likely merged "?" boxes. - gui.py: new ScreenshotFrame with [게임 창 선택] button → window picker dialog → bbox crop → recognize → editable preview grid with per-cell CellEditor that handles slab / artifact / merged(?) / empty. Merged cells let user pick which two slabs got combined + a level. - artifacts.py + bundled _artifacts.json (248 entries from WhiteDog1004/sephiria) for matching and rendering. - renderer.py: factored CDN fetch into _fetch_image; added fetch_artifact_image(). - requirements.txt: + numpy, pygetwindow (Win), pywin32 (Win). - docker-build-cmd.sh: upgrade PyInstaller to 5.x inside cdrx container so numpy DLL manifest reads work. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
58
sephiria_inv/artifacts.py
Normal file
58
sephiria_inv/artifacts.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""Artifact catalog parsed from WhiteDog1004/sephiria's artifacts.json.
|
||||
|
||||
Each entry exposes the fields we actually need for icon matching and
|
||||
rendering: value (canonical key), Korean label, tier, and the CDN image URL.
|
||||
The full effect text / description is kept opaque — the matcher only cares
|
||||
about the image, and effects are not applied to the optimizer (slab effects
|
||||
only, per existing design).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from importlib import resources
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Artifact:
|
||||
value: str
|
||||
ko_label: str
|
||||
eng_label: str
|
||||
tier: str # common / advanced / rare / legend / solid
|
||||
image: str # CDN URL
|
||||
level: int # max level (0 = unique / non-leveling)
|
||||
|
||||
|
||||
def _load() -> List[Artifact]:
|
||||
try:
|
||||
text = resources.files(__package__).joinpath("_artifacts.json").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
except Exception:
|
||||
return []
|
||||
data = json.loads(text)
|
||||
out: List[Artifact] = []
|
||||
for row in data:
|
||||
if row.get("disabled"):
|
||||
continue
|
||||
out.append(
|
||||
Artifact(
|
||||
value=row["value"],
|
||||
ko_label=row.get("label_kor") or row["value"],
|
||||
eng_label=row.get("label_eng") or row["value"],
|
||||
tier=row.get("tier") or "common",
|
||||
image=row.get("image") or "",
|
||||
level=int(row.get("level") or 0),
|
||||
)
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
ARTIFACTS: List[Artifact] = _load()
|
||||
ARTIFACTS_BY_VALUE: Dict[str, Artifact] = {a.value: a for a in ARTIFACTS}
|
||||
|
||||
|
||||
def get(value: str) -> Optional[Artifact]:
|
||||
return ARTIFACTS_BY_VALUE.get(value)
|
||||
Reference in New Issue
Block a user