Files
AIGame/Tools/enemy_static_pipeline.py

63 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""P0 enemy (or companion, --kind Animal) static stage: Hunyuan high GLB -> 2000-tri XPbr bake -> Bundles/Characters/Enemy/{Name} -> static Prefab -> static audit.
Usage:
python Tools/enemy_static_pipeline.py Dashlet 0.5 # bake + install + SetupCharacter + AuditCharacterVisual
python Tools/enemy_static_pipeline.py Dashlet 0.5 --source Tools/output/enemy_3d/Dashlet/dashlet_forward.glb
New models must pass the project's +Z front check in Unity. Check rendered face/feet,
not just FBX axis_forward. Legacy assets can request --forward-z=-1 for audit views.
"""
from __future__ import annotations
import argparse
import json
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PROJECT = ROOT / "AIClient"
def run(cmd: list[str], cwd: Path = ROOT) -> str:
print("$", " ".join(cmd), flush=True)
done = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True, encoding="utf-8", errors="replace")
if done.returncode != 0:
raise SystemExit(f"failed ({done.returncode}): {' '.join(cmd)}\n{done.stdout[-2000:]}\n{done.stderr[-2000:]}")
return done.stdout
def unity(file: str, entry: str, args: list) -> str:
out = run(["unity", "command", "run_script", "--project-path", str(PROJECT), "--file", file, "--entry", entry,
"--args", json.dumps(args), "--timeout_ms", "90000", "--timeout", "120"], PROJECT)
if '"success":true' not in out.replace(" ", ""):
raise SystemExit(f"Unity {entry} failed:\n{out[-2000:]}")
return out
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("name")
ap.add_argument("height", type=float)
ap.add_argument("--source", type=Path)
ap.add_argument("--forward-z",type=int,choices=(-1,1),default=1,help="+1 is project +Z front; -1 audits an explicitly legacy -Z asset")
ap.add_argument("--kind", default="Enemy", choices=("Enemy", "Animal"), help="Animal installs a companion under Characters/Animal")
a = ap.parse_args()
low = a.name.lower()
tag = "enemy" if a.kind == "Enemy" else "companion"
source = a.source or Path(f"Tools/output/{tag}_3d/{a.name}/{low}.glb")
game = Path(f"Tools/output/{tag}_game/{low}_game")
stem = source.stem
run([sys.executable, "Tools/model_tools/model_lowpoly_bake.py", str(source), "-o", str(game), "--tris", "2000", "--size", "1024",
"--callback-file", str(game / "bake_status.json")])
run([sys.executable, "Tools/install_character_bundles.py", "-a", a.name, "--kind", a.kind, "-b", str(game / f"{stem}_xpbr")])
unity("AgentScripts/SetupCharacter.cs", "SetupCharacter.Run", [a.kind, a.name, a.height])
audit = ROOT / (f"Tools/output/enemy_characters/{a.name}/static_audit" if a.kind == "Enemy" else f"Tools/output/companions/{a.name}/static_audit")
unity("AgentScripts/AuditCharacterVisual.cs", "AuditCharacterVisual.Capture",
[f"Assets/Bundles/Characters/{a.kind}/{a.name}/{a.name}.prefab", str(audit).replace("\\", "/"), a.height,"",0,a.forward_z])
print((audit / "static_verification.txt").read_text(encoding="utf-8"))
if __name__ == "__main__":
main()