Browse Source

Fix: Array-Type to Schema Array output fails

the problem:
array re-linking has to be solved to resolve dependencies,
but it needs to be wired at both ends.
however, we do not wire the output until it has been prepared
catch 22
so instead, we solve the array nodes as normal and then
wire the links they rerouted out of the array output

kind of confusing and complicated, and a very rare
edge case. I now desire very badly to refactor the data types
of the links in schema solve

having to deal with ui links, mantis dummy links, and mantis links
all together is terrible
Joseph Brandenburg 5 months ago
parent
commit
64250e4078
3 changed files with 36 additions and 8 deletions
  1. 4 0
      misc_nodes.py
  2. 3 1
      readtree.py
  3. 29 7
      schema_solve.py

+ 4 - 0
misc_nodes.py

@@ -148,6 +148,7 @@ def array_choose_relink(node, indices, array_input, output, ):
         for l in keep_links:
         for l in keep_links:
             new_link = l.from_node.outputs[l.from_socket].connect(to_node, link.to_socket)
             new_link = l.from_node.outputs[l.from_socket].connect(to_node, link.to_socket)
             array_link_init_hierarchy(new_link)
             array_link_init_hierarchy(new_link)
+            node.rerouted.append(new_link) # so I can access this in Schema Solve
         link.die()
         link.die()
 
 
 
 
@@ -623,6 +624,7 @@ class UtilityKDChoosePoint(MantisNode):
         self.outputs.init_sockets(outputs)
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.init_parameters()
         self.node_type = "UTILITY"
         self.node_type = "UTILITY"
+        self.rerouted=[]
 
 
     def bPrepare(self, bContext = None,):
     def bPrepare(self, bContext = None,):
         from mathutils import Vector
         from mathutils import Vector
@@ -661,6 +663,7 @@ class UtilityKDChooseXForm(MantisNode):
         self.outputs.init_sockets(outputs)
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.init_parameters()
         self.node_type = "UTILITY"
         self.node_type = "UTILITY"
+        self.rerouted=[]
 
 
     def bPrepare(self, bContext = None,):
     def bPrepare(self, bContext = None,):
         if len(self.hierarchy_dependencies)==0 and len(self.hierarchy_connections)==0 and \
         if len(self.hierarchy_dependencies)==0 and len(self.hierarchy_connections)==0 and \
@@ -1710,6 +1713,7 @@ class UtilityArrayGet(MantisNode):
         self.outputs.init_sockets(outputs)
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.init_parameters()
         self.node_type = "UTILITY"
         self.node_type = "UTILITY"
+        self.rerouted=[]
 
 
     def bPrepare(self, bContext = None,):
     def bPrepare(self, bContext = None,):
         if len(self.hierarchy_dependencies)==0 and len(self.hierarchy_connections)==0 and \
         if len(self.hierarchy_dependencies)==0 and len(self.hierarchy_connections)==0 and \

+ 3 - 1
readtree.py

@@ -137,8 +137,9 @@ def gen_node_containers(base_tree, current_tree, tree_path_names, all_nc, local_
         if ui_node.bl_idname in ["NodeGroupInput", "NodeGroupOutput"]:
         if ui_node.bl_idname in ["NodeGroupInput", "NodeGroupOutput"]:
             # we only want ONE dummy in/out per tree_path, so use the bl_idname to make a Dummy node
             # we only want ONE dummy in/out per tree_path, so use the bl_idname to make a Dummy node
             sig = (None, *tree_path_names, ui_node.bl_idname)
             sig = (None, *tree_path_names, ui_node.bl_idname)
+            ui_sig = (None, *tree_path_names, ui_node.name)
             if not local_nc.get(sig):
             if not local_nc.get(sig):
-                nc = DummyNode( signature=sig , base_tree=base_tree, prototype=ui_node )
+                nc = DummyNode( signature=sig , base_tree=base_tree, prototype=ui_node, ui_signature=ui_sig )
                 local_nc[sig] = nc; all_nc[sig] = nc; dummy_nodes[sig] = nc
                 local_nc[sig] = nc; all_nc[sig] = nc; dummy_nodes[sig] = nc
                 if ui_node.bl_idname in ["NodeGroupOutput"]:
                 if ui_node.bl_idname in ["NodeGroupOutput"]:
                     nc.reroute_links = reroute_links_grpout
                     nc.reroute_links = reroute_links_grpout
@@ -161,6 +162,7 @@ def gen_node_containers(base_tree, current_tree, tree_path_names, all_nc, local_
                     continue # already made
                     continue # already made
             nc = nc_cls( sig , base_tree)
             nc = nc_cls( sig , base_tree)
             local_nc[sig] = nc; all_nc[sig] = nc
             local_nc[sig] = nc; all_nc[sig] = nc
+            nc.ui_signature = (*nc.ui_signature[:-1], ui_node.name) # just to ensure it points to a real node.
         else:
         else:
             nc = None
             nc = None
             prRed(f"Can't make nc for.. {ui_node.bl_idname}")
             prRed(f"Can't make nc for.. {ui_node.bl_idname}")

+ 29 - 7
schema_solve.py

@@ -415,6 +415,13 @@ class SchemaSolver:
         from_node = frame_mantis_nodes[ (*self.autogen_path_names, from_name+self.index_str()) ]
         from_node = frame_mantis_nodes[ (*self.autogen_path_names, from_name+self.index_str()) ]
         connection = from_node.outputs[ui_link.from_socket.identifier].connect(node=to_node, socket=ui_link.to_socket.name)
         connection = from_node.outputs[ui_link.from_socket.identifier].connect(node=to_node, socket=ui_link.to_socket.name)
 
 
+    def handle_link_from_array_type_to_array_out(self, original_ui_link, dummy_link):
+        # this is so annoyingly specific lol
+        from_node = dummy_link.nc_from; from_socket_name=dummy_link.from_socket.name
+        for outgoing in self.array_output_connections[original_ui_link.to_socket.identifier]:
+            to_node = outgoing.to_node
+            connection = from_node.outputs[from_socket_name].connect(node=to_node, socket=outgoing.to_socket)
+
     # WTF is even happening here?? TODO BUG HACK
     # WTF is even happening here?? TODO BUG HACK
     def handle_link_to_array_output(self, frame_mantis_nodes, index, ui_link, to_ui_node, from_ui_node):# if this duplicated code works, dedupe!
     def handle_link_to_array_output(self, frame_mantis_nodes, index, ui_link, to_ui_node, from_ui_node):# if this duplicated code works, dedupe!
         to_node = self.schema_nodes[(*self.tree_path_names, to_ui_node.bl_idname)] # get it by [], we want a KeyError if this fails
         to_node = self.schema_nodes[(*self.tree_path_names, to_ui_node.bl_idname)] # get it by [], we want a KeyError if this fails
@@ -533,7 +540,6 @@ class SchemaSolver:
                             can_add_me=False
                             can_add_me=False
                             forbidden.add(nc) # forbid the parent, too
                             forbidden.add(nc) # forbid the parent, too
                             continue
                             continue
-                        prOrange(f"Adding dependency... {dep}")
                         unprepared.appendleft(dep)
                         unprepared.appendleft(dep)
                 if can_add_me:
                 if can_add_me:
                     unprepared.appendleft(nc) # just rotate them until they are ready.
                     unprepared.appendleft(nc) # just rotate them until they are ready.
@@ -560,7 +566,7 @@ class SchemaSolver:
                                         SchemaOutgoingConnection,
                                         SchemaOutgoingConnection,
                                         SchemaIncomingConnection,)
                                         SchemaIncomingConnection,)
         from .utilities import clear_reroutes, link_node_containers
         from .utilities import clear_reroutes, link_node_containers
-
+        from .base_definitions import array_output_types
         self.set_index_strings()
         self.set_index_strings()
         frame_mantis_nodes = {}
         frame_mantis_nodes = {}
 
 
@@ -627,6 +633,12 @@ class SchemaSolver:
                 if isinstance(from_ui_node, (MantisNodeGroup, SchemaGroup)):
                 if isinstance(from_ui_node, (MantisNodeGroup, SchemaGroup)):
                     self.handle_link_from_subschema_to_output(frame_mantis_nodes, ui_link, to_ui_node)
                     self.handle_link_from_subschema_to_output(frame_mantis_nodes, ui_link, to_ui_node)
                     # both links are desirable to create, so don't continue here
                     # both links are desirable to create, so don't continue here
+                if from_ui_node.bl_idname in array_output_types:
+                    self.handle_link_from_subschema_to_output(frame_mantis_nodes, ui_link, to_ui_node)
+                    # this one wires links around - we need to finish connecting it to the output
+                    # before we can prepare it. Otherwise, it will send a link from *itself* instead of
+                    # rewiring one of its *inputs* to the next node.
+                    # We have to prep it, and then deal with the links between it and the array. pain.
                 links_to_output.append(ui_link)
                 links_to_output.append(ui_link)
                 continue
                 continue
             if isinstance(from_ui_node, SchemaArrayInputGet):
             if isinstance(from_ui_node, SchemaArrayInputGet):
@@ -675,7 +687,8 @@ class SchemaSolver:
             ui_link = links_to_output[i]
             ui_link = links_to_output[i]
             to_ui_node = ui_link.to_socket.node; from_ui_node = ui_link.from_socket.node
             to_ui_node = ui_link.to_socket.node; from_ui_node = ui_link.from_socket.node
             # ugly workaround here in a very painful edge case...
             # ugly workaround here in a very painful edge case...
-            if isinstance(from_ui_node, (MantisNodeGroup, SchemaGroup)):
+            if isinstance(from_ui_node, (MantisNodeGroup, SchemaGroup)) or\
+                                from_ui_node.bl_idname in array_output_types:
                 ui_link=self.spoof_link_for_subschema_to_output_edge_case(ui_link)
                 ui_link=self.spoof_link_for_subschema_to_output_edge_case(ui_link)
                 links_to_output[i] = ui_link
                 links_to_output[i] = ui_link
             from_name = get_link_in_out(ui_link)[0]
             from_name = get_link_in_out(ui_link)[0]
@@ -690,13 +703,22 @@ class SchemaSolver:
             else:
             else:
                 raise RuntimeError(" 671 there has been an error parsing the tree. Please report this as a bug.")
                 raise RuntimeError(" 671 there has been an error parsing the tree. Please report this as a bug.")
             self.prepare_nodes(unprepared) # prepare only the dependencies we need for this link
             self.prepare_nodes(unprepared) # prepare only the dependencies we need for this link
-            # and then handle the link by specific type.
-            if isinstance(from_ui_node, (MantisNodeGroup, SchemaGroup)):
-                ui_link=self.spoof_link_for_subschema_to_output_edge_case(ui_link)
+            # and handle the output by the specific type
             if isinstance(to_ui_node, (SchemaConstOutput, NodeGroupOutput)):
             if isinstance(to_ui_node, (SchemaConstOutput, NodeGroupOutput)):
                 self.handle_link_to_constant_output(frame_mantis_nodes, self.index, ui_link,  to_ui_node)
                 self.handle_link_to_constant_output(frame_mantis_nodes, self.index, ui_link,  to_ui_node)
             if isinstance(to_ui_node, SchemaArrayOutput):
             if isinstance(to_ui_node, SchemaArrayOutput):
-                self.handle_link_to_array_output(frame_mantis_nodes, self.index, ui_link, to_ui_node, from_ui_node)
+                if from_node.bl_idname in array_output_types:
+                    from .base_definitions import DummyLink
+                    for l in from_node.rerouted:
+                        new_link = DummyLink(
+                            from_socket=l.from_node.outputs[l.from_socket],
+                            to_socket=l.to_node.inputs[l.to_socket],
+                            nc_from=l.from_node, nc_to=l.to_node,
+                            multi_input_sort_id=l.multi_input_sort_id
+                        )
+                        self.handle_link_from_array_type_to_array_out(ui_link, new_link)
+                else:
+                    self.handle_link_to_array_output(frame_mantis_nodes, self.index, ui_link, to_ui_node, from_ui_node)
         return frame_mantis_nodes
         return frame_mantis_nodes
     
     
     def solve_nested_schema(self, schema_nc):
     def solve_nested_schema(self, schema_nc):