fix: protect Material/Object sockets from library override re-evaluation

When fix_lib_overrides() writes to any mod[sid] on a GeoNode modifier,
Blender can re-evaluate ALL library overrides on that modifier, wiping
Material and Object sockets back to their library defaults (NONE).

Fix: snapshot all fragile sockets (NodeSocketMaterial, NodeSocketObject)
before any modifications, then restore them if they got wiped.
This commit is contained in:
2026-06-02 22:54:56 +02:00
parent 074a590194
commit 5bf8f48db0

View File

@@ -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