117 lines
5.9 KiB
Markdown
117 lines
5.9 KiB
Markdown
# Einheiten: backend/tft/model/artifact.py
|
|
stand: f41ac76b5789
|
|
|
|
## backend/tft/model/artifact.py::craftable_items
|
|
beschreibung: Filtert aus den statischen Items die standardmäßig kombinierbaren Items heraus.
|
|
input: `static_items: dict` — vom Static-Datensatz abgeleitete Item-Definitionen
|
|
output: `list[str]` alphabetisch sortierter API-Namen kombinierbarer Items
|
|
entscheidungen:
|
|
- Spatula- und FryingPan-Komponenten schließen jedes Item mit einer Emblem-Komponente aus
|
|
beleg: "not set(comp) & SPATULA_COMPONENTS"
|
|
- Nur Items mit genau zwei Komponenten und gültigem API-Namenpräfix gelten als kombinierbar
|
|
beleg: "api.startswith(\"TFT_Item_\")"
|
|
- Das Ergebnis wird alphabetisch sortiert zurückgegeben
|
|
beleg: "return sorted(pool)"
|
|
kanten:
|
|
- ruft-auf: backend/tft/model/artifact.py::recipes
|
|
- ruft-auf: backend/tft/model/artifact.py::component_pool
|
|
- wird-genutzt-von: backend/tft/model/artifact.py::build
|
|
|
|
## backend/tft/model/artifact.py::recipes
|
|
beschreibung: Bildet die kombinierbaren Items auf einen sortierten Komponenten-Schlüssel ab.
|
|
input: `static_items: dict` — Item-Definitionen aus dem Static-Datensatz
|
|
output: `dict` mit `"CompA|CompB"`-Schlüssel und Item-API als Wert
|
|
entscheidungen:
|
|
- Der Komponenten-Schlüssel wird aus der sortierten Komponentenliste gebildet
|
|
beleg: "\"|\".join(sorted(static_items[api][\"composition\"]))"
|
|
- Nur kombinierbare Items fließen über `craftable_items` ein
|
|
beleg: "for api in craftable_items(static_items)"
|
|
kanten:
|
|
- ruft-auf: backend/tft/model/artifact.py::craftable_items
|
|
- wird-genutzt-von: backend/tft/model/artifact.py::build
|
|
|
|
## backend/tft/model/artifact.py::component_pool
|
|
beschreibung: Bestimmt den Pool an Basis-Komponenten, die häufig in Rezepten vorkommen.
|
|
input: `static_items: dict` — Item-Definitionen aus dem Static-Datensatz
|
|
output: `list[str]` sortierte Komponenten-API-Namen, die in mindestens drei Rezepten vorkommen
|
|
entscheidungen:
|
|
- Eine Komponente muss in mindestens drei Rezepten vorkommen, um in den Pool zu gelangen
|
|
beleg: "if n >= 3"
|
|
- Nur Komponenten aus kombinierbaren Items werden gezählt
|
|
beleg: "for api in craftable_items(static_items):"
|
|
kanten:
|
|
- ruft-auf: backend/tft/model/artifact.py::craftable_items
|
|
- wird-genutzt-von: backend/tft/model/artifact.py::build
|
|
|
|
## backend/tft/model/artifact.py::spell_dps_cap
|
|
beschreibung: Berechnet das 90. Perzentil der Spell-DPS aller Units auf 1 Stern ohne Items als Deckelwert.
|
|
input: `static: dict`, `roles: dict` — Static-Datensatz und Rollen-Klassifikation pro Unit
|
|
output: `float | None` mit dem 90.-Perzentil-Wert oder `None`, wenn keine Werte existieren
|
|
entscheidungen:
|
|
- Nur Spell-DPS-Werte größer als null gehen in die Berechnung ein
|
|
beleg: "if (p := statsheet.unit_stats("
|
|
- Bei fehlenden Werten wird `None` statt eines Default-Werts zurückgegeben
|
|
beleg: "return None"
|
|
- Die Auswahl erfolgt über das 90. Perzentil als relativer Spell-Deckel
|
|
beleg: "return values[int(len(values) * 0.9)]"
|
|
kanten:
|
|
- nutzt: backend/tft/model/statsheet.py::unit_stats
|
|
- wird-genutzt-von: backend/tft/model/artifact.py::build
|
|
|
|
## backend/tft/model/artifact.py::_augment_specs
|
|
beschreibung: Delegiert die Erzeugung der Augment-Spezifikationen an das Augment-Modul.
|
|
input: `static: dict` — Static-Datensatz mit Augment- und Unit-Definitionen
|
|
output: `dict` mit den aufgebauten Augment-Spezifikationen
|
|
entscheidungen:
|
|
- Die Augment- und Unit-Sektion des Static-Datensatzes wird an den Builder weitergereicht
|
|
beleg: "return build_specs(static[\"augments\"], static[\"units\"])"
|
|
kanten:
|
|
- ruft-auf: backend/tft/model/augments.py::build_specs
|
|
- wird-genutzt-von: backend/tft/model/artifact.py::build
|
|
|
|
## backend/tft/model/artifact.py::build
|
|
beschreibung: Baut das versionierte Analyse-Artefakt als Vertrag zwischen Pipeline und Simulation.
|
|
input: `static: dict`, `learned: dict | None`, `extra_meta: dict | None` — Roh-Daten plus optionale Ergänzungen
|
|
output: `dict` mit Meta-, Static-, Rollen-, Item- und Augment-Abschnitten des Artefakts
|
|
entscheidungen:
|
|
- Die Schemaversion wird als Top-Level-Konstante fixiert
|
|
beleg: "\"schema_version\": SCHEMA_VERSION,"
|
|
- Rollen werden über `baseline.classify_role` je Unit bestimmt
|
|
beleg: "api: baseline.classify_role(unit)"
|
|
- Ein leerer `augment_pool` signalisiert dem Sim die Nutzung aller geparsten Augments
|
|
beleg: "\"augment_pool\": [],"
|
|
kanten:
|
|
- ruft-auf: backend/tft/model/artifact.py::spell_dps_cap
|
|
- ruft-auf: backend/tft/model/artifact.py::craftable_items
|
|
- ruft-auf: backend/tft/model/artifact.py::component_pool
|
|
- ruft-auf: backend/tft/model/artifact.py::recipes
|
|
- ruft-auf: backend/tft/model/artifact.py::_augment_specs
|
|
- nutzt: backend/tft/model/baseline.py::classify_role
|
|
|
|
## backend/tft/model/artifact.py::save
|
|
beschreibung: Schreibt das gebaute Artefakt als JSON in das versionsspezifische Verzeichnis und aktualisiert den Latest-Pointer.
|
|
input: `artifact: dict` — das von `build` erzeugte Artefakt
|
|
output: `str` mit dem Pfad zur geschriebenen `analysis.json`
|
|
entscheidungen:
|
|
- Zielverzeichnis wird über Set-Nummer und Baudatum aus `paths.artifact_dir` bestimmt
|
|
beleg: "out_dir = paths.artifact_dir(set_number, build_date)"
|
|
- Das Verzeichnis wird inklusive Eltern bei Bedarf angelegt
|
|
beleg: "out_dir.mkdir(parents=True, exist_ok=True)"
|
|
- Der Latest-Pointer wird separat als kleine JSON-Datei geschrieben
|
|
beleg: "json.dumps({\"path\": str(out_path)})"
|
|
kanten:
|
|
- nutzt: backend/tft/paths.py::artifact_dir
|
|
- nutzt: backend/tft/paths.py::latest_artifact_pointer
|
|
|
|
## backend/tft/model/artifact.py::load
|
|
beschreibung: Lädt das aktuellste Artefakt für ein gegebenes Set über den Latest-Pointer.
|
|
input: `set_number: int` — die TFT-Set-Nummer
|
|
output: `dict` mit dem deserialisierten Artefakt aus der referenzierten `analysis.json`
|
|
entscheidungen:
|
|
- Ohne vorhandenen Pointer bricht der Aufruf mit einer Laufzeit-Anweisung ab
|
|
beleg: "raise SystemExit("
|
|
- Der tatsächliche Pfad wird aus dem Pointer-JSON gelesen, nicht aus dem Dateinamen abgeleitet
|
|
beleg: "path = json.loads(pointer.read_text())[\"path\"]"
|
|
kanten:
|
|
- nutzt: backend/tft/paths.py::latest_artifact_pointer
|