""" blender_compare_bones.py Usage: tooling/blender --background --python tooling/blender_compare_bones.py -- Compares bone names between two GLB/GLTF files. Reports missing or extra bones. """ import sys import bpy def get_bones(path: str) -> set: bpy.ops.wm.read_factory_settings(use_empty=True) bpy.ops.import_scene.gltf(filepath=path) for obj in bpy.context.scene.objects: if obj.type == 'ARMATURE': return {b.name for b in obj.data.bones} return set() if __name__ == "__main__": argv = sys.argv if "--" not in argv: print("Usage: tooling/blender --background --python tooling/blender_compare_bones.py -- ") sys.exit(1) args = argv[argv.index("--") + 1:] if len(args) < 2: print("ERROR: Need two GLB/GLTF paths.") sys.exit(1) path_a, path_b = args[0], args[1] print(f"Loading A: {path_a}") bones_a = get_bones(path_a) print(f"A has {len(bones_a)} bones") print(f"Loading B: {path_b}") bones_b = get_bones(path_b) print(f"B has {len(bones_b)} bones") only_in_a = bones_a - bones_b only_in_b = bones_b - bones_a shared = bones_a & bones_b print(f"Shared: {len(shared)}") if only_in_a: print(f"Only in A ({len(only_in_a)}):") for name in sorted(only_in_a): print(f" - {name}") if only_in_b: print(f"Only in B ({len(only_in_b)}):") for name in sorted(only_in_b): print(f" + {name}") if not only_in_a and not only_in_b: print("BONE_MATCH=OK") else: print("BONE_MATCH=MISMATCH")