Files
sephiria_inv_program/sephiria_inv/artifacts.py
Claude 2e23ad5d2f 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>
2026-05-14 09:36:49 +09:00

59 lines
1.7 KiB
Python

"""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)