"""Opens the saved fork and reports what a user would stumble over: missing images, absolute paths, what is hidden. blender -b --factory-startup models/M_Ship_v2_interior_season2.blend --python build/verify_file.py """ import json import os import bpy out = {"file": bpy.data.filepath, "objects": len(bpy.data.objects), "meshes": len(bpy.data.meshes), "materials": len(bpy.data.materials), "images": len(bpy.data.images)} missing, absolute, where = [], [], {} packed = 0 for img in bpy.data.images: if img.source != "FILE" or not img.filepath: continue p = bpy.path.abspath(img.filepath, library=img.library) if img.packed_file is not None: packed += 1 # (the ship file's own reference pictures and textures: inside the .blend) elif not os.path.isfile(p): missing.append(img.filepath) if not img.filepath.startswith("//") and img.packed_file is None: absolute.append(img.filepath) key = os.path.normpath(os.path.dirname(p)).split(os.sep) k = os.sep.join(key[:5]) where[k] = where.get(k, 0) + 1 out["images_missing"] = missing[:10] out["images_missing_count"] = len(missing) out["images_packed_in_the_file"] = packed out["images_with_absolute_path"] = absolute[:10] out["image_folders"] = where out["libraries"] = [(l.filepath, os.path.isfile(bpy.path.abspath(l.filepath))) for l in bpy.data.libraries] def walk(lc, depth=0, acc=None): acc = acc if acc is not None else [] acc.append((" " * depth + lc.name, len(lc.collection.objects), "EXCLUDED" if lc.exclude else "")) if depth < 2: for c in lc.children: walk(c, depth + 1, acc) return acc scene = bpy.data.scenes.get("M-Ship v2 | REFERENCE ASSET") or bpy.context.scene out["scene"] = scene.name out["collections"] = walk(scene.view_layers[0].layer_collection) out["mask_modifiers"] = [(o.name, m.name) for o in bpy.data.objects for m in o.modifiers if m.type == "MASK"] top = bpy.data.collections.get("10 INTERIOR | Season 2 layout") no_path = [o.name for o in top.all_objects if o.type == "MESH" and not o.data.get("ue_mesh") and not o.get("ue_decal_material") and not o.data.name.startswith(("SM_wlombbzdw", "SM_DockArm", "SK_DockArm", "WGT_DockArm", "DECAL_"))] out["layout_meshes_without_unreal_path (own parts)"] = no_path out["texts"] = [t.name for t in bpy.data.texts] out["unsaved_images"] = [i.name for i in bpy.data.images if i.is_dirty] print("VERIFY " + json.dumps(out))