import json from typing import Any from ..labels.animal_sprite_library import ADMIN_SPRITE_LIBRARY from ..labels.sprite_library import PUBLIC_SPRITE_LIBRARY # Résolution RUNTIME (jeu jouable) : le catalogue COMPLET, quel que soit le # rôle du créateur — voir le plan "Bibliothèque de sprites animaux # CraftPix" (aucun filtrage par rôle au runtime, seulement à la galerie de # l'éditeur/l'écriture, voir routes/game/screens/screen_edit.py et # routes/elements/element_add.py). _SPRITE_LIBRARY = {**PUBLIC_SPRITE_LIBRARY, **ADMIN_SPRITE_LIBRARY} _DEFAULT_PERSONNAGE_DATA = {"source": "forge", "forge_character": "male-adventurer"} def resolve_personnage_data(el: dict[str, Any]) -> dict[str, Any]: """Décode attributes._personnage_data (voir set_personnage_data.py) en dict Python, jamais None — un attribut absent/corrompu retombe sur le défaut posé à la création (default_style_for_widget.py).""" raw = (el.get("attributes") or {}).get("_personnage_data") if not raw: return dict(_DEFAULT_PERSONNAGE_DATA) try: data = json.loads(raw) except (TypeError, ValueError): return dict(_DEFAULT_PERSONNAGE_DATA) return data if isinstance(data, dict) else dict(_DEFAULT_PERSONNAGE_DATA) def resolve_personnage_animations(el: dict[str, Any]) -> dict[str, list[str]]: """{nom_animation: [urls...]} pour cet élément personnage, quelle que soit sa source — Forge (SPRITE_LIBRARY) ou sprites propres au créateur (ses propres frames importées, voir personnage-panel.js).""" data = resolve_personnage_data(el) if data.get("source") == "custom": return data.get("animations") or {} character = _SPRITE_LIBRARY.get(data.get("forge_character") or "") return character["animations"] if character else {} def resolve_personnage_idle_frame(el: dict[str, Any]) -> str: """Première image de l'animation "idle" (ou, à défaut, de la première animation disponible) — utilisée pour le rendu serveur ET l'aperçu animé de l'éditeur, jamais vide tant qu'au moins une frame existe.""" animations = resolve_personnage_animations(el) frames = animations.get("idle") or (next(iter(animations.values())) if animations else None) return frames[0] if frames else ""