Ver código fonte

Repair asset library index from generated files

bang 2 semanas atrás
pai
commit
fd88547d4b
1 arquivos alterados com 99 adições e 1 exclusões
  1. 99 1
      server.py

+ 99 - 1
server.py

@@ -34,6 +34,7 @@ from urllib.parse import urlparse, parse_qs, unquote
 import pipeline
 import exporter
 import slot_workflow
+import spine_builder
 import providers
 import config
 
@@ -100,7 +101,104 @@ def _load_library(game):
     if not os.path.isfile(library_path):
         return {"game": game, "characters": [], "vfx": [], "ui": [], "ui_art": []}
     with open(library_path, encoding="utf-8") as f:
-        return json.load(f)
+        lib = json.load(f)
+    if _repair_library_index(game, lib):
+        with open(library_path, "w", encoding="utf-8") as f:
+            json.dump(lib, f, ensure_ascii=False, indent=2)
+    return lib
+
+
+def _spine_size_from_json(path):
+    try:
+        data = json.load(open(path, encoding="utf-8"))
+        sk = data.get("skeleton", {})
+        return int(round(sk.get("width") or 1000)), int(round(sk.get("height") or 1000))
+    except Exception:
+        return 1000, 1000
+
+
+def _image_size(path):
+    try:
+        from PIL import Image
+        with Image.open(path) as img:
+            return img.size
+    except Exception:
+        return 0, 0
+
+
+def _repair_library_index(game, lib):
+    """Index files that exist on disk but were not written to library.json.
+
+    This lets partial retry jobs become visible immediately even if a later
+    required task failed before the old library index was updated.
+    """
+    changed = False
+    base = os.path.join(OUT_ROOT, game)
+    manifest = _manifest_from_library(lib)
+    by_section = {
+        "characters": {x.get("id"): x for x in lib.get("characters", [])},
+        "ui_art": {x.get("id"): x for x in lib.get("ui_art", [])},
+        "vfx": {x.get("id"): x for x in lib.get("vfx", [])},
+        "ui": {x.get("id"): x for x in lib.get("ui", [])},
+    }
+
+    for c in manifest.get("characters", []):
+        cid = c.get("id")
+        if not cid or cid in by_section["characters"]:
+            continue
+        paths = [os.path.join(base, "characters", f"{cid}.{ext}") for ext in ("json", "atlas", "png")]
+        if all(os.path.isfile(p) for p in paths):
+            w, h = _spine_size_from_json(paths[0])
+            item = {
+                "id": cid,
+                "png": f"characters/{cid}.png",
+                "w": w, "h": h,
+                "type": c.get("type", "spine"),
+                "role": c.get("role", ""),
+                "animations": spine_builder.anim_data(c.get("animations", ["idle"])),
+                "files": [f"characters/{cid}.json", f"characters/{cid}.atlas", f"characters/{cid}.png"],
+            }
+            lib.setdefault("characters", []).append(item)
+            by_section["characters"][cid] = item
+            changed = True
+
+    for a in manifest.get("ui_art", []):
+        aid = a.get("id")
+        if not aid or aid in by_section["ui_art"]:
+            continue
+        path = os.path.join(base, "ui_art", f"{aid}.png")
+        if os.path.isfile(path):
+            w, h = _image_size(path)
+            item = {"id": aid, "file": f"ui_art/{aid}.png", "w": w, "h": h,
+                    "transparent": a.get("transparent", True)}
+            lib.setdefault("ui_art", []).append(item)
+            by_section["ui_art"][aid] = item
+            changed = True
+
+    for v in manifest.get("vfx", []):
+        vid = v.get("id")
+        if not vid or vid in by_section["vfx"]:
+            continue
+        path = os.path.join(base, "vfx", f"{vid}.particle.json")
+        if os.path.isfile(path):
+            cfg = json.load(open(path, encoding="utf-8"))
+            item = {"id": vid, "template": v.get("template"),
+                    "file": f"vfx/{vid}.particle.json", "config": cfg}
+            lib.setdefault("vfx", []).append(item)
+            by_section["vfx"][vid] = item
+            changed = True
+
+    ui_path = os.path.join(base, "ui", "TweenPresets.ts")
+    if os.path.isfile(ui_path):
+        for u in manifest.get("ui", []):
+            uid = u.get("id")
+            if uid and uid not in by_section["ui"]:
+                item = {"id": uid, "preset": u.get("preset"), "params": u.get("params", {})}
+                lib.setdefault("ui", []).append(item)
+                by_section["ui"][uid] = item
+                changed = True
+
+    return changed
 
 
 def _manifest_from_library(lib):