Browse Source

Fix NodeGroupUpdate broken by NodeReroute mutation

Turns out, blender mutates the type of sockets in NodeReroute after
it detects a new socket_idname, and this seems to happen in a separate thread
or some sort of deffered way, maybe in node.update() of NodeReroute

So now I need to check to see if a node is a reroute before storing its socket
in the socket_map, otherwise it will fail to create the link.
Joseph Brandenburg 6 months ago
parent
commit
b81cb120d5
2 changed files with 41 additions and 9 deletions
  1. 9 2
      base_definitions.py
  2. 32 7
      utilities.py

+ 9 - 2
base_definitions.py

@@ -393,16 +393,23 @@ def node_group_update(node, force = False):
         for item in node.node_tree.interface.items_tree:
             if item.item_type != "SOCKET": continue
             if (item.in_out == 'INPUT' and update_input):
-                socket = relink_socket_map_add_socket(node, node.inputs, item)
                 if socket_map_in:
                     if item.identifier in socket_map_in.keys():
+                        socket = relink_socket_map_add_socket(node, node.inputs, item)
                         do_relink(node, socket, socket_map_in)
+                    else:
+                        prRed(item.identifier)
+                else:
+                    prGreen(item.identifier)
+                    socket = relink_socket_map_add_socket(node, node.inputs, item)
 
             if (item.in_out == 'OUTPUT' and update_output):
-                socket = relink_socket_map_add_socket(node, node.outputs, item)
                 if socket_map_out:
                     if item.identifier in socket_map_out.keys():
+                        socket = relink_socket_map_add_socket(node, node.outputs, item)
                         do_relink(node, socket, socket_map_out)
+                else:
+                    socket = relink_socket_map_add_socket(node, node.outputs, item)
                     
         # at this point there is no wildcard socket
         if socket_map_in and '__extend__' in socket_map_in.keys():

+ 32 - 7
utilities.py

@@ -91,17 +91,34 @@ def get_socket_maps(node, force=False):
     maps = [{}, {}]
     node_collection = ["inputs", "outputs"]
     links = ["from_socket", "to_socket"]
-    for collection, map, link in zip(node_collection, maps, links):
+    for collection, map, linked_socket in zip(node_collection, maps, links):
         for sock in getattr(node, collection):
             if sock.is_linked:
-                map[sock.identifier]=[ getattr(l, link) for l in sock.links ]
+                other_sockets = []
+                # HACK here because Blender will crash if the socket values in the NodeReroute
+                #  are mutated. Because this seems to happen in a deffered way, I can't account
+                #  for it except by checking the node later...
+                # TODO: The fact that I need this hack means I can probably solve this problem
+                #  for all node types in a safer way, since they may also be dynamic somehow
+                for l in sock.links:
+                    if "from" in linked_socket and l.from_node.bl_idname == "NodeReroute":
+                        other_sockets.append(l.from_node)
+                    elif "to" in linked_socket and l.to_node.bl_idname == "NodeReroute":
+                        other_sockets.append(l.to_node)
+                    else:
+                        other_sockets.append(getattr(l, linked_socket))
+                map[sock.identifier]= other_sockets
             elif hasattr(sock, "default_value"):
                 if sock.get("default_value") is not None:
                     val = sock['default_value']
-                    if val is None:
-                        raise RuntimeError(f"ERROR: Could not get socket data for socket of type: {sock.bl_idname}")
-                else:
-                    if not force: continue
+                elif sock.bl_idname == "EnumCurveSocket" and sock.get("default_value") is None:
+                    # HACK I need to add this special case because during file-load,
+                    #  this value is None and should not be altered until it is set once.
+                    continue
+                elif (val := sock.default_value) is not None:
+                    pass
+                elif not force:
+                    continue
                 map[sock.identifier]=val
             else:
                 from .socket_definitions import no_default_value
@@ -120,7 +137,7 @@ def do_relink(node, s, map, in_out='INPUT', parent_name = ''):
     if hasattr(node, "node_tree"):
         tree = node.node_tree
         interface_in_out=in_out
-    from bpy.types import NodeSocket
+    from bpy.types import NodeSocket, Node
     get_string = '__extend__'
     if s: get_string = s.identifier
     from .base_definitions import SchemaUINode
@@ -148,6 +165,14 @@ def do_relink(node, s, map, in_out='INPUT', parent_name = ''):
                     node.id_data.links.new(input=sub_val, output=s)
                 else:
                     node.id_data.links.new(input=s, output=sub_val)
+            if isinstance(sub_val, Node):
+                # this happens when it is a NodeReroute
+                if in_out =='INPUT':
+                    node.id_data.links.new(input=sub_val, output=node.inputs[0])
+                else:
+                    node.id_data.links.new(input=node.outputs[0], output=sub_val)
+            else:
+                raise RuntimeError("Unhandled case in do_relink()")
     elif get_string != "__extend__":
         if not s.is_output:
             try: