"""Grouper: a summary of the built file (read-only): objects, pivots, drivers (simple expressions?), sockets, collections. blender.exe -b Tender_Grouper.blend --python build/gr_dump.py -> build/checks/dump.json""" import bpy, os, json HERE = os.path.dirname(os.path.abspath(__file__)) os.makedirs(os.path.join(HERE, "checks"), exist_ok=True) out = {"objects": {}, "drivers": [], "root_props": {}, "collections": {}} root = bpy.data.objects["Grouper_Root"] for k in root.keys(): if not k.startswith("_"): out["root_props"][k] = root[k] for o in bpy.data.objects: if o.name.startswith(("SM_Grouper", "SOCKET_", "Grouper_Root")): out["objects"][o.name] = {"type": o.type, "location": [round(c, 4) for c in o.location], "rotation": [round(c, 4) for c in o.rotation_euler], "scale": [round(c, 4) for c in o.scale], "parent": o.parent.name if o.parent else None, "materials": [m.name for m in o.data.materials] if o.type == 'MESH' else None} if o.animation_data: for fc in o.animation_data.drivers: d = fc.driver out["drivers"].append({"object": o.name, "path": fc.data_path, "index": fc.array_index, "expression": d.expression, "simple": d.is_simple_expression, "valid": d.is_valid}) for c in bpy.data.collections: lc = bpy.context.view_layer.layer_collection.children.get(c.name) out["collections"][c.name] = {"objects": len(c.objects), "hidden_in_viewport": bool(lc.hide_viewport) if lc else None} json.dump(out, open(os.path.join(HERE, "checks", "dump.json"), "w"), indent=1) print("DUMP drivers", [(d["object"], d["expression"], d["simple"], d["valid"]) for d in out["drivers"]]) print("DUMP root", out["root_props"]) print("DUMP collections", out["collections"]) print("DUMP sockets", sorted(k for k in out["objects"] if k.startswith("SOCKET_"))) print("DUMP movers", {k: v["location"] for k, v in out["objects"].items() if k in ("SM_Grouper_Hatch", "SM_Grouper_Door_L", "SM_Grouper_Door_R", "SM_Grouper_Rotor", "SM_Grouper_Antenna")})