magicciv/tools/sprite-generation/engine/installer.py
Claude Code 1b12cc3825 chore(tools): 🔧 Update build/test scripts in tools/ directory
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-03-25 22:48:52 -07:00

155 lines
6.7 KiB
Python

"""Copies approved sprites from the variants directory to the game assets directory."""
from __future__ import annotations
import shutil
from pathlib import Path
from engine.registry import SpriteRegistry
class SpriteInstaller:
def __init__(self, assets_dir: Path, registry: SpriteRegistry) -> None:
self.assets_dir = assets_dir
self.registry = registry
def install_approved(self, category: str | None = None, dry_run: bool = False) -> int:
"""Install all approved, uninstalled sprites. Returns count installed."""
entries = self.registry.get_approved_uninstalled(category)
count = 0
for sprite in entries:
sprite_id = sprite["id"]
install_path = sprite.get("install_path")
if not install_path:
continue
# Check if sprite-level has an approved variant (no dimension)
if sprite["status"] == "approved":
variants = self.registry.get_variants(sprite_id)
approved = [v for v in variants if v["is_approved"] and v["dimension_id"] is None]
if approved:
source = approved[0].get("processed_path")
if source and Path(source).exists():
dest = self.assets_dir / install_path
if dry_run:
print(f"[DRY RUN] Would install {install_path}")
else:
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, dest)
self.registry.mark_installed(sprite_id)
print(f"Installed {install_path}")
count += 1
# Handle approved dimensions
for dim in sprite.get("approved_dimensions", []):
dim_install = dim.get("install_path")
if not dim_install:
continue
if dim["status"] != "approved":
continue
dim_id = dim["id"]
approved_vid = dim.get("approved_variant_id")
if not approved_vid:
continue
dim_variants = self.registry.get_variants(sprite_id, dim_id)
approved = [v for v in dim_variants if v["id"] == approved_vid]
if not approved:
continue
source = approved[0].get("processed_path")
if not source or not Path(source).exists():
continue
dest = self.assets_dir / dim_install
if dry_run:
print(f"[DRY RUN] Would install {dim_install}")
else:
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, dest)
self.registry.mark_installed(sprite_id, dim_id)
print(f"Installed {dim_install}")
count += 1
return count
def install_one(self, sprite_id: str, dimension_id: int | None = None) -> Path | None:
"""Install a single sprite/dimension. Returns install path or None."""
sprite = self.registry.get_sprite(sprite_id)
if not sprite:
print(f"Sprite '{sprite_id}' not found")
return None
if dimension_id is not None:
dim = next((d for d in sprite["dimensions_list"] if d["id"] == dimension_id), None)
if not dim:
print(f"Dimension {dimension_id} not found for '{sprite_id}'")
return None
if dim["status"] not in ("approved", "installed"):
print(f"Dimension {dimension_id} is not approved (status: {dim['status']})")
return None
install_path = dim.get("install_path")
approved_vid = dim.get("approved_variant_id")
if not install_path or not approved_vid:
print(f"Dimension {dimension_id} has no install_path or approved variant")
return None
approved = [v for v in dim.get("variants", []) if v["id"] == approved_vid]
if not approved:
print(f"Approved variant {approved_vid} not found")
return None
source = approved[0].get("processed_path")
else:
if sprite["status"] not in ("approved", "installed"):
print(f"Sprite '{sprite_id}' is not approved (status: {sprite['status']})")
return None
install_path = sprite.get("install_path")
if not install_path:
print(f"Sprite '{sprite_id}' has no install_path")
return None
approved = [v for v in sprite.get("variants", []) if v["is_approved"]]
if not approved:
print(f"No approved variant for '{sprite_id}'")
return None
source = approved[0].get("processed_path")
if not source or not Path(source).exists():
print(f"Source file not found: {source}")
return None
dest = self.assets_dir / install_path
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(source, dest)
self.registry.mark_installed(sprite_id, dimension_id)
print(f"Installed {install_path}")
return dest
def uninstall(self, sprite_id: str, dimension_id: int | None = None) -> bool:
"""Remove an installed sprite, revert status to approved."""
sprite = self.registry.get_sprite(sprite_id)
if not sprite:
print(f"Sprite '{sprite_id}' not found")
return False
if dimension_id is not None:
dim = next((d for d in sprite["dimensions_list"] if d["id"] == dimension_id), None)
if not dim or dim["status"] != "installed":
print(f"Dimension {dimension_id} is not installed")
return False
install_path = dim.get("install_path")
if install_path:
dest = self.assets_dir / install_path
if dest.exists():
dest.unlink()
self.registry.update_dimension_status(dimension_id, "approved")
print(f"Uninstalled dimension {dimension_id} of '{sprite_id}'")
return True
if sprite["status"] != "installed":
print(f"Sprite '{sprite_id}' is not installed (status: {sprite['status']})")
return False
install_path = sprite.get("install_path")
if install_path:
dest = self.assets_dir / install_path
if dest.exists():
dest.unlink()
self.registry.update_sprite_status(sprite_id, "approved")
print(f"Uninstalled '{sprite_id}'")
return True