import bpy import os def silence_puresky(): removed = 0 for handler_list in [bpy.app.handlers.depsgraph_update_pre, bpy.app.handlers.depsgraph_update_post]: for h in handler_list[:]: if "puresky" in str(h).lower() or "PureSky" in str(h): try: handler_list.remove(h) removed += 1 except Exception: pass return removed def _snapshot_fragile_sockets(obj, mod, iface): """Snapshot Material/Object sockets before modifying any override.""" FRAGILE_TYPES = {'NodeSocketMaterial', 'NodeSocketObject'} snapshot = {} for item in iface.items_tree: if item.item_type != 'SOCKET' or item.in_out != 'INPUT': continue if item.socket_type not in FRAGILE_TYPES: continue sid = item.identifier if sid in mod and mod[sid] is not None: snapshot[sid] = mod[sid] # Debug output to verify we grab the material # print(f" [SNAPSHOT] {obj.name} -> {item.name}: {mod[sid]}") return snapshot def _restore_fragile_sockets(mod, snapshot): """Restore Material/Object sockets that got wiped by override re-eval.""" restored = 0 for sid, value in snapshot.items(): current = mod[sid] if sid in mod else None # Force restore if the current value no longer matches our snapshot if current != value: try: mod[sid] = value restored += 1 except Exception as e: print(f" [RESTORE FAILED] {sid}: {e}") return restored def fix_lib_overrides(): # Disabled as forcing "True" or "Index" onto generic modifier properties # destroys the library overrides and clears all material assignments. return 0 def fix_missing_images(): fixed = 0 for img in bpy.data.images: if img.source == 'FILE' and img.filepath: if getattr(img, "packed_file", None): continue abs_path = (bpy.path.abspath(img.filepath, library=img.library) if img.library else bpy.path.abspath(img.filepath)) if not os.path.exists(abs_path): img.source = 'GENERATED' img.generated_width = 8 img.generated_height = 8 img.generated_type = 'BLANK' img.generated_color = (1.0, 0.0, 1.0, 1.0) fixed += 1 return fixed def init_metal_gpu(): try: prefs = bpy.context.preferences.addons['cycles'].preferences prefs.compute_device_type = 'METAL' prefs.get_devices() for dev in prefs.devices: dev.use = True return True except Exception: return False def get_scenes(): return [s.name for s in bpy.data.scenes if not s.name.startswith("_") and s.name != "_Shots"]