Files
eve_structure/webapp/services/blueprints.py
2025-08-27 18:55:45 +02:00

109 lines
3.3 KiB
Python

from __future__ import annotations
import csv
import os
import json
from typing import Optional, Dict
from flask import current_app
# Cache: "name in lowercase" -> type_id
_BP_NAME2ID: Dict[str, int] = {}
# Cache: product type id -> (product name)
_ID2NAME: Dict[int, str] = {}
# Optional benutzerdefinierte Überschreibungen
# Format: { "Structure Market Network": 123456, ... }
_USER_MAP: Dict[str, int] = {}
def _data_path(filename: str) -> str:
return os.path.join(current_app.root_path, "data", filename)
def _ensure_loaded() -> None:
"""Liest typeIDs.csv einmalig ein und baut schnelle Nachschlage-Maps auf."""
global _BP_NAME2ID, _ID2NAME, _USER_MAP
if _BP_NAME2ID and _ID2NAME:
return
# Benutzer-Overrides (optional)
try:
override = _data_path("blueprints.json")
if os.path.isfile(override):
with open(override, "r", encoding="utf-8") as f:
_USER_MAP = json.load(f) or {}
except Exception:
_USER_MAP = {}
csv_path = _data_path("typeIDs.csv")
if not os.path.isfile(csv_path):
return
try:
with open(csv_path, "r", encoding="utf-8", newline="") as f:
# Datei ist ;-separiert: id;name;group_id;iconID;graphicID
reader = csv.reader(f, delimiter=";")
header = next(reader, None) # "id;name;group_id;iconID;graphicID"
for row in reader:
if not row or len(row) < 2:
continue
try:
tid = int(row[0])
except Exception:
continue
name = (row[1] or "").strip()
if not name:
continue
_ID2NAME[tid] = name
key = name.lower()
# Merke auch die Blaupause separat (Name endet exakt auf " Blueprint")
if key.endswith(" blueprint"):
_BP_NAME2ID[key] = tid
except Exception:
# Map bleibt ggf. leer; Aufrufer bekommen dann None zurück
pass
def product_name_by_id(type_id: int) -> Optional[str]:
"""Gibt den Produktnamen zur TypeID zurück (aus typeIDs.csv)."""
_ensure_loaded()
return _ID2NAME.get(type_id)
def resolve_blueprint_id(product_name: str) -> Optional[int]:
"""
Ermittelt die Blueprint-TypeID zu einem *Produktnamen*.
Regeln:
1) Benutzer-Override (blueprints.json)
2) Exakter Treffer "<Produktname> Blueprint" in typeIDs.csv
3) Weicher Treffer (enthält Produktname & 'blueprint')
"""
if not product_name:
return None
_ensure_loaded()
# 1) User-Override
if product_name in _USER_MAP:
return int(_USER_MAP[product_name])
wanted_exact = f"{product_name} Blueprint".lower()
# 2) Exakter Treffer
if wanted_exact in _BP_NAME2ID:
return _BP_NAME2ID[wanted_exact]
# 3) Weiche Suche
prod_l = product_name.lower()
for k, tid in _BP_NAME2ID.items():
if prod_l in k and "blueprint" in k:
return tid
return None
def resolve_blueprint_id_by_product_id(product_type_id: int) -> Optional[int]:
"""Ermittelt die Blueprint-TypeID aus der *Produkt*-TypeID."""
name = product_name_by_id(int(product_type_id))
if not name:
return None
return resolve_blueprint_id(name)