# Blender headless: probe a folder of FBX models for fighter-readiness. # Emits one JSON line per file: rig, bones, namespace, meshes, verts, # height, textures, action count. Re-runnable (skips nothing, cheap). # # Usage: Blender -b --python tools/assess_fbx.py -- --dir ~/Documents/fbxes --out report.jsonl import argparse import json import sys from pathlib import Path import bpy def parse_args(): argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [] ap = argparse.ArgumentParser() ap.add_argument("--dir", required=True) ap.add_argument("--out", required=True) return ap.parse_args(argv) args = parse_args() src = Path(args.dir).expanduser() out = Path(args.out).expanduser() results = [] for f in sorted(src.glob("*.fbx")): rec = {"file": f.name, "mb": round(f.stat().st_size / 1e6, 1)} bpy.ops.wm.read_factory_settings(use_empty=True) try: bpy.ops.import_scene.fbx(filepath=str(f)) except Exception as e: rec["error"] = str(e)[:80] results.append(rec) continue arms = [o for o in bpy.data.objects if o.type == "ARMATURE"] meshes = [o for o in bpy.data.objects if o.type == "MESH"] rec["arms"] = len(arms) rec["meshes"] = len(meshes) rec["verts"] = sum(len(m.data.vertices) for m in meshes) if arms: bones = arms[0].data.bones rec["bones"] = len(bones) rec["ns"] = "" for b in bones: if ":" in b.name: rec["ns"] = b.name.split(":")[0] break # world height import mathutils pts = [o.matrix_world @ mathutils.Vector(c) for o in meshes for c in o.bound_box] if pts: rec["h"] = round(max(p[2] for p in pts) - min(p[2] for p in pts), 2) rec["textured"] = any( n.type == "TEX_IMAGE" and n.image is not None for m in meshes for s in m.material_slots if s.material and s.material.use_nodes for n in s.material.node_tree.nodes) rec["actions"] = len(bpy.data.actions) results.append(rec) print("PROBED", f.name, "rig" if arms else "NORIG", flush=True) out.write_text("\n".join(json.dumps(r) for r in results)) print("WROTE", out, len(results), "records")