diff --git a/utils.py b/utils.py index 52eca86..0fc2b6e 100644 --- a/utils.py +++ b/utils.py @@ -16,6 +16,37 @@ def silence_puresky(): return removed +def _snapshot_fragile_sockets(obj, mod, iface): + """Snapshot Material/Object sockets before modifying any override. + + Writing to ANY mod[sid] on a GeoNode modifier can trigger Blender + to re-evaluate ALL library overrides on that modifier, wiping + Material and Object sockets back to their library defaults (NONE). + """ + 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] + 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 + if current is None and value is not None: + mod[sid] = value + restored += 1 + return restored + + def fix_lib_overrides(): fixed = 0 for obj in bpy.data.objects: @@ -28,14 +59,19 @@ def fix_lib_overrides(): continue ng = mod.node_group - name_to_sid = {} iface = getattr(ng, 'interface', None) - if iface and hasattr(iface, 'items_tree'): - for item in iface.items_tree: - if item.item_type == 'SOCKET' and item.in_out == 'INPUT': - name_to_sid[item.name] = (item.identifier, item.socket_type) + if not iface or not hasattr(iface, 'items_tree'): + continue - for item in (getattr(iface, 'items_tree', []) if iface else []): + # Snapshot fragile sockets BEFORE any writes + snapshot = _snapshot_fragile_sockets(obj, mod, iface) + + name_to_sid = {} + for item in iface.items_tree: + if item.item_type == 'SOCKET' and item.in_out == 'INPUT': + name_to_sid[item.name] = (item.identifier, item.socket_type) + + for item in iface.items_tree: if item.item_type != 'SOCKET' or item.in_out != 'INPUT': continue sid = item.identifier @@ -77,6 +113,14 @@ def fix_lib_overrides(): if "Reset Children" in name_to_sid: mod[name_to_sid["Reset Children"][0]] = True fixed += 1 + + # Restore any fragile sockets that got wiped + restored = _restore_fragile_sockets(mod, snapshot) + if restored: + print(f" [RESTORE] {obj.name}/{mod.name}: " + f"restored {restored} Material/Object sockets") + fixed += restored + return fixed