Explorar el Código

Fix: remove many instances of hardcoded node get

search ".link[0]" to find the rest of them and fix before release
for now, the matter of array sort id is much more pressing
Joseph Brandenburg hace 11 meses
padre
commit
24ce4568e5
Se han modificado 4 ficheros con 76 adiciones y 65 borrados
  1. 45 35
      link_nodes.py
  2. 2 2
      node_container_common.py
  3. 16 16
      readtree.py
  4. 13 12
      xForm_nodes.py

+ 45 - 35
link_nodes.py

@@ -53,7 +53,10 @@ class MantisLinkNode(MantisNode):
         if ('Target' in input_name) and input_name not in  ["Target Space", "Use Target Z"]:
             socket = self.inputs.get(input_name)
             if socket.is_linked:
-                return socket.links[0].from_node
+                node_line, _last_socket = trace_single_line(self, input_name, index)
+                for other_node in node_line:
+                    if other_node.node_type == 'XFORM':
+                        return other_node
             return None
 
         else:
@@ -61,28 +64,46 @@ class MantisLinkNode(MantisNode):
 
     def gen_property_socket_map(self) -> dict:
         props_sockets = super().gen_property_socket_map()
-        if (os := self.inputs.get("Owner Space")) and os.is_connected and os.links[0].from_node.node_type == 'XFORM':
-            del props_sockets['owner_space']
-        if (ts := self.inputs.get("Target Space")) and ts.is_connected and ts.links[0].from_node.node_type == 'XFORM':
-            del props_sockets['target_space']
+        if (os := self.inputs.get("Owner Space")) and os.is_connected:
+            node_line, _last_socket = trace_single_line(self, "Owner Space")
+            for other_node in node_line:
+                if other_node.node_type == 'XFORM':
+                    del props_sockets['owner_space']; break
+        if (ts := self.inputs.get("Target Space")) and ts.is_connected:
+            node_line, _last_socket = trace_single_line(self, "Target Space")
+            for other_node in node_line:
+                if other_node.node_type == 'XFORM':
+                    del props_sockets['target_space']; break
         return props_sockets
 
     def set_custom_space(self):
         for c in self.bObject:
-            if (os := self.inputs.get("Owner Space")) and os.is_connected and os.links[0].from_node.node_type == 'XFORM':
-                c.owner_space='CUSTOM'
-                xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
-                if isinstance(xf, Bone):
-                    c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
-                else:
-                    c.space_object=xf
-            if ts := self.inputs.get("Target_Space") and ts.is_connected and ts.links[0].from_node.node_type == 'XFORM':
-                c.target_space='CUSTOM'
-                xf = self.inputs["Target_Space Space"].links[0].from_node.bGetObject(mode="OBJECT")
-                if isinstance(xf, Bone):
-                    c.space_object=self.inputs["Target_Space Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
-                else:
-                    c.space_object=xf
+            if (os := self.inputs.get("Owner Space")) and os.is_connected:
+                node_line, _last_socket = trace_single_line(self, "Owner Space")
+                owner_space_target = None
+                for other_node in node_line:
+                    if other_node.node_type == 'XFORM':
+                        owner_space_target = other_node; break
+                if owner_space_target:
+                    c.owner_space='CUSTOM'
+                    xf = owner_space_target.bGetObject(mode="OBJECT")
+                    if isinstance(xf, Bone):
+                        c.space_object=owner_space_target.bGetParentArmature(); c.space_subtarget=xf.name
+                    else:
+                        c.space_object=xf
+            if (ts := self.inputs.get("Target Space")) and ts.is_connected:
+                node_line, _last_socket = trace_single_line(self, "Target Space")
+                target_space_target = None
+                for other_node in node_line:
+                    if other_node.node_type == 'XFORM':
+                        target_space_target = other_node; break
+                if target_space_target:
+                    c.target_space='CUSTOM'
+                    xf = target_space_target.bGetObject(mode="OBJECT")
+                    if isinstance(xf, Bone):
+                        c.space_object=target_space_target.bGetParentArmature(); c.space_subtarget=xf.name
+                    else:
+                        c.space_object=xf
 
     def GetxForm(nc, output_name="Output Relationship"):
         break_condition= lambda node : node.node_type=='XFORM'
@@ -205,20 +226,7 @@ class LinkCopyScale(MantisLinkNode):
             if constraint_name := self.evaluate_input("Name"):
                 c.name = constraint_name
             self.bObject.append(c)
-            if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
-                c.owner_space='CUSTOM'
-                xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
-                if isinstance(xf, Bone):
-                    c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
-                else:
-                    c.space_object=xf
-            if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
-                c.target_space='CUSTOM'
-                xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
-                if isinstance(xf, Bone):
-                    c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
-                else:
-                    c.space_object=xf
+            self.set_custom_space()
             props_sockets = self.gen_property_socket_map()
             evaluate_sockets(self, c, props_sockets)
         self.executed = True
@@ -804,7 +812,6 @@ class LinkArmature(MantisLinkNode):
                     weight_value=0
                 targets_weights[i]=weight_value
                 props_sockets["targets[%d].weight" % i] = (weight_input_name, 0)
-                # targets_weights.append({"weight":(weight_input_name, 0)})
             evaluate_sockets(self, c, props_sockets)
             for target, value in targets_weights.items():
                 c.targets[target].weight=value
@@ -829,8 +836,11 @@ class LinkSplineIK(MantisLinkNode):
             c = xf.bGetObject().constraints.new('SPLINE_IK')
             # set the spline - we need to get the right one
             spline_index = self.evaluate_input("Spline Index")
+            proto_curve = None
+            node_line, _last_socket = trace_single_line(self, "Target")
+            for other_node in node_line: # trace and get the input
+                if other_node.node_type == 'XFORM': proto_curve = other_node.bGetObject()
             from .utilities import get_extracted_spline_object
-            proto_curve = self.inputs['Target'].links[0].from_node.bGetObject()
             curve = get_extracted_spline_object(proto_curve, spline_index, self.mContext)
             # link it to the view layer
             if (curve.name not in bContext.view_layer.active_layer_collection.collection.objects):

+ 2 - 2
node_container_common.py

@@ -231,8 +231,8 @@ def evaluate_sockets(nc, b_object, props_sockets,):
 def finish_driver(nc, b_object, driver_item, prop):
     # prWhite(nc, prop)
     index = driver_item[1]; driver_sock = driver_item[0]
-    driver_trace = trace_single_line(nc, driver_sock)
-    driver_provider, driver_socket = driver_trace[0][-1], driver_trace[1]
+    node_line, last_socket = trace_single_line(nc, driver_sock)
+    driver_provider, driver_socket = node_line[-1], last_socket
     if index is not None:
         driver = driver_provider.parameters[driver_socket.name][index].copy()
         # this is harmless and necessary for the weird ones where the property is a vector too

+ 16 - 16
readtree.py

@@ -15,17 +15,20 @@ def grp_node_reroute_common(in_node, out_node, interface):
             from_node.outputs[from_socket].connect(
                 interface,in_node_input.name, sort_id = in_link.multi_input_sort_id)
             in_link.die()
-            init_connections(from_node)
     for out_node_output in out_node.outputs:
         while (out_node_output.links):
             out_link = out_node_output.links.pop()
             to_node = out_link.to_node; to_socket = out_link.to_socket
+            # LARGE CHALLENGE: handling sort id's when there are arrays of various kinds
+            # - going to an array as a single joined link (bundle) from the input
+            # - many single inputs going to an array
+            # - mixture of the two
+            # - we need to sort them by the ui_link's sort id and their own sort id, too
+            # I think I have to use multiple sort ID variables here. need to think.
             for l in interface.inputs[out_node_output.name].links:
                 interface.outputs[out_node_output.name].connect(
                     to_node, to_socket, sort_id = l.multi_input_sort_id)
             out_link.die()
-            init_dependencies(to_node)
-    init_dependencies(interface); init_connections(interface)
 
 def reroute_links_grp(group, all_nodes):
     from .internal_containers import GroupInterface
@@ -57,11 +60,14 @@ def insert_lazy_parents(nc):
     from .base_definitions import NodeLink
     inherit_nc = None
     if nc.inputs["Relationship"].is_connected:
-        link = nc.inputs["Relationship"].links[0]
-        from_nc = link.from_node
-        if from_nc.node_type in ["XFORM"] and link.from_socket in ["xForm Out"]:
+        from .node_container_common import trace_single_line
+        node_line, last_socket = trace_single_line(nc, 'Relationship')
+        for other_node in node_line:
+            if other_node.node_type == 'XFORM':
+                break
+        if other_node.node_type in ["XFORM"] and last_socket in ["xForm Out"]:
             inherit_nc = LinkInherit(("MANTIS_AUTOGENERATED", *nc.signature[1:], "LAZY_INHERIT"), nc.base_tree)
-            for from_link in from_nc.outputs["xForm Out"].links:
+            for from_link in other_node.outputs["xForm Out"].links:
                 if from_link.to_node == nc and from_link.to_socket == "Relationship":
                     break # this is it
             from_link.to_node = inherit_nc; from_link.to_socket="Parent"
@@ -70,15 +76,13 @@ def insert_lazy_parents(nc):
             links=[]
             while (nc.inputs["Relationship"].links):
                 to_link = nc.inputs["Relationship"].links.pop()
-                if to_link.from_node == from_nc and to_link.from_socket == "xForm Out":
+                if to_link.from_node == other_node and to_link.from_socket == "xForm Out":
                     continue # don't keep this one
                 links.append(to_link)
                 to_link.from_node.outputs[from_link.from_socket].is_linked=True
 
             nc.inputs["Relationship"].links=links
-            link=NodeLink(from_node=inherit_nc, from_socket="Inheritance", to_node=nc, to_socket="Relationship")
             inherit_nc.inputs["Parent"].links.append(from_link)
-
             inherit_nc.parameters = {
                                      "Parent":None,
                                      "Inherit Rotation":True,
@@ -86,8 +90,8 @@ def insert_lazy_parents(nc):
                                      "Connected":False,
                                     }
             # because the from node may have already been done.
-            init_connections(from_nc)
-            init_dependencies(from_nc)
+            init_connections(other_node)
+            init_dependencies(other_node)
             init_connections(inherit_nc)
             init_dependencies(inherit_nc)
     return inherit_nc
@@ -377,8 +381,6 @@ def parse_tree(base_tree, error_popups=False):
             dummy.reroute_links(dummy, all_mantis_nodes)
     prGreen(f"Pulling data from tree took {time.time() - data_start_time} seconds")
 
-    # base_tree.parsed_tree = all_mantis_nodes # for debugging
-
     start_time = time.time()
     solve_only_these = []; solve_only_these.extend(list(all_schema.values()))
     roots, array_nodes = [], []
@@ -661,7 +663,6 @@ def execute_tree(nodes, base_tree, context, error_popups = False):
                     raise e
                 execution_failed = True; break
 
-
         switch_mode(mode='OBJECT', objects=switch_me)
         # switch to pose mode here so that the nodes can use the final pose data
         # this will require them to update the depsgraph.
@@ -678,7 +679,6 @@ def execute_tree(nodes, base_tree, context, error_popups = False):
                     raise e
                 execution_failed = True; break
 
-
         # REST pose for deformer bind, so everything is in the rest position
         for ob in switch_me:
             ob.data.pose_position = 'REST'

+ 13 - 12
xForm_nodes.py

@@ -270,15 +270,16 @@ class xFormBone(xFormNode):
         from bpy.types import EditBone
         parent_nc = get_parent_node(self, type='LINK')
         node_lines, _last_socket = trace_single_line(parent_nc, 'Parent')
-        if node_lines[-1].node_type == 'XFORM':
-            parent = node_lines[-1].bGetObject(mode = 'EDIT')
-            if isinstance(parent, EditBone): # otherwise, no need to do anything.
-                eb.parent = parent
-                eb.use_connect = parent_nc.evaluate_input("Connected")
-                eb.use_inherit_rotation = parent_nc.evaluate_input("Inherit Rotation")
-                eb.inherit_scale = parent_nc.evaluate_input("Inherit Scale")
+        for other_node in node_lines:
+            if isinstance(other_node, (xFormArmature, xFormBone)):
+                parent = other_node.bGetObject(mode = 'EDIT'); break
         else:
             raise RuntimeError(wrapRed(f"Cannot set parent for node {self}"))
+        if isinstance(parent, EditBone): # otherwise, no need to do anything.
+            eb.parent = parent
+            eb.use_connect = parent_nc.evaluate_input("Connected")
+            eb.use_inherit_rotation = parent_nc.evaluate_input("Inherit Rotation")
+            eb.inherit_scale = parent_nc.evaluate_input("Inherit Scale")
 
 
     def bPrepare(self, bContext=None):
@@ -431,9 +432,6 @@ class xFormBone(xFormNode):
             try:
                 if (custom_handle := self.evaluate_input("BBone Custom Start Handle")):
                     b.bbone_custom_handle_start = self.bGetParentArmature().data.bones[custom_handle]
-                # hypothetically we should support xForm inputs.... but we won't do that for now
-                # elif custom_handle is None:
-                #     b.bbone_custom_handle_start = self.inputs["BBone Custom Start Handle"].links[0].from_node.bGetObject().name
                 if (custom_handle := self.evaluate_input("BBone Custom End Handle")):
                     b.bbone_custom_handle_end = self.bGetParentArmature().data.bones[custom_handle]
             except KeyError:
@@ -843,8 +841,11 @@ class xFormCurvePin(xFormNode):
         for socket_name in ["Curve Pin Factor", "Forward Axis","Up Axis",]:
             if self.inputs.get(socket_name) is None: continue # in case it has been bypassed
             if self.inputs[socket_name].is_linked:
-                link = self.inputs[socket_name].links[0]
-                driver = link.from_node
+                node_line, _last_socket = trace_single_line(self, socket_name)
+                driver = None
+                for other_node in node_line:
+                    if other_node.node_type == 'DRIVER':
+                        driver = other_node; break
                 if isinstance(driver, UtilityDriver):
                     prop_amount = driver.evaluate_input("Property")
                 elif isinstance(driver, UtilitySwitch):