19 Revize 8c370ad9f6 ... 55517c8d51

Autor SHA1 Zpráva Datum
  Brandenburg 55517c8d51 Merge branch 'custom_interface_classes' of http://git.nodespaghetti.club/ns/mantis into custom_interface_classes před 2 týdny
  Joseph Brandenburg b878eb1846 Initialize Tree with correct version number před 3 týdny
  Joseph Brandenburg 746b067dd8 Fix: make default values work with more socket types před 3 týdny
  Joseph Brandenburg 0602cbacb0 Fix: interface panel doesn't have an identifier před 3 týdny
  Joseph Brandenburg 7d01ff4e2e New Feature: Default Values for base tree před 3 týdny
  Joseph Brandenburg 06e784fb0b Fix: correct default value type for vectors před 3 týdny
  Joseph Brandenburg 6370d77155 Fix: default value disabled for Matrix před 3 týdny
  Joseph Brandenburg d7ff891f25 Disable "Connected To" feature před 3 týdny
  Joseph Brandenburg ff205ded04 Implement Custom Interface Classes před 3 týdny
  Joseph Brandenburg e40d0fdc9c initial versioning for new interface classes před 3 týdny
  Joseph Brandenburg 4845445001 fix: unbound local error when updating group interface před 3 týdny
  Joseph Brandenburg 37976aaffb update interface draw for correct UI and clarity před 3 týdny
  Joseph Brandenburg fa05172de2 Interface Classes set the multi and default value now před 3 týdny
  Joseph Brandenburg dbb1998052 Add Custom Interface Socket Types před 3 týdny
  Brandenburg aa15119835 Fix: Custom properties fail in Drivers před 3 týdny
  Brandenburg 1a642ea8bb Fix: DriverVariable fails when linked to non-xForm před 3 týdny
  Brandenburg 595c799eb8 cleanup: remove prints před 3 týdny
  Brandenburg 022e7e8952 IO: set Mantis Version on new tree immediately před 3 týdny
  Joseph Brandenburg 82d0d38a04 Cleanup: remove green color from visualize code před 3 týdny
3 změnil soubory, kde provedl 132 přidání a 124 odebrání
  1. 19 14
      drivers.py
  2. 43 42
      i_o.py
  3. 70 68
      misc_nodes.py

+ 19 - 14
drivers.py

@@ -68,7 +68,7 @@ def CreateDrivers(drivers):
         drv.type = driver["type"]
         if (expr := driver.get("expression")) and isinstance(expr, str):
             drv.expression = expr
-        
+
         fc.extrapolation = "CONSTANT"
         if (extrapolation_mode := driver.get("extrapolation")) in ("CONSTANT", "LINEAR"):
             fc.extrapolation = extrapolation_mode
@@ -76,12 +76,12 @@ def CreateDrivers(drivers):
             prRed(f"Extrapolation Mode in driver has incorrect data: {extrapolation_mode}")
 
         # logic for handling type can go here
-        
+
         # start by clearing
         while (len(drv.variables) > 0):
             v = drv.variables[0]
             dVar = drv.variables.remove(v)
-            
+
         for v in driver["vars"]:
             pose_bone = False
             bone = ''; target2bone = ''
@@ -93,40 +93,47 @@ def CreateDrivers(drivers):
                 vob = v["owner"].id_data
                 bone = v["owner"].name
             #
-            
+
             if "xForm 2" in v.keys() and v["xForm 2"]:
                 if (isinstance(v["xForm 2"], Object)):
                     target2ob = v["xForm 2"]
                 else:
                     target2ob = v["xForm 2"].id_data
                     target2bone = v["xForm 2"].name
-            
+
             dVar = drv.variables.new()
-            
-            
+
+
             dVar.name = v["name"]
             dVar.type = v["type"]
             #for now, assume this is always true:
             #dVar.targets[0].id_type = "OBJECT"
             #it's possible to use other datablocks, but this is not commonly done
             #actually, it looks like Blender figures this out for me.
-            
+
             dVar.targets[0].id = vob
             dVar.targets[0].bone_target = bone
             if len(dVar.targets) > 1:
                 dVar.targets[1].id = target2ob
                 dVar.targets[1].bone_target = target2bone
-            
+
             if (dVar.type == "TRANSFORMS"):
                 dVar.targets[0].transform_space = v["space"]
                 dVar.targets[0].transform_type = v["channel"]
             if (dVar.type == 'SINGLE_PROP'):
                 if pose_bone:
                     stub = "pose.bones[\""+v["owner"].name+"\"]"
-                    if (hasattr( v["owner"], v["prop"] )):
+                    print (v['prop'], v['owner'].name)
+                    if v["prop"] in v["owner"].keys():
+                        print('a')
+                        dVar.targets[0].data_path = stub + brackets(v["prop"])
+                    elif (hasattr( v["owner"], v["prop"] )):
+                        print('b')
                         dVar.targets[0].data_path = stub + "."+ (v["prop"])
                     else:
-                        dVar.targets[0].data_path = stub + brackets(v["prop"])
+                        print('c')
+                        # raise RuntimeError
+
                 else:
                     if (hasattr( v["owner"], v["prop"] )):
                         dVar.targets[0].data_path = (v["prop"])
@@ -136,7 +143,7 @@ def CreateDrivers(drivers):
         kp = fc.keyframe_points
         for key in driver["keys"]:
             k = kp.insert(frame=key["co"][0], value = key["co"][1],)
-            
+
             k.interpolation     = key["interpolation"]
             if (key["interpolation"] == 'BEZIER'):
                 k.handle_left_type  = key["handle_left_type" ]
@@ -146,5 +153,3 @@ def CreateDrivers(drivers):
                 if (k.handle_right_type in ("ALIGNED", "VECTOR", "FREE")):
                     k.handle_right      = (k.co[0] + key["handle_right"][0], k.co[1] + key["handle_right"][1])
             k.type = key["type"]
-      
-      

+ 43 - 42
i_o.py

@@ -49,7 +49,7 @@ prop_ignore = [ "__dict__", "__doc__", "__module__", "__weakref__",# "name",
                 # these are in Bone
                 "socket_count", "display_bb_settings", "display_def_settings",
                 "display_ik_settings", "display_vp_settings",
-                ] 
+                ]
 # don't ignore: "bl_idname", "bl_label",
 # ignore the name, it's the dict - key for the node props
     # no that's stupid don't ignore the name good grief
@@ -127,7 +127,7 @@ def fix_custom_parameter(n, property_definition, ):
     if n.bl_idname in ['xFormNullNode', 'xFormBoneNode', 'xFormArmatureNode', 'xFormGeometryObjectNode',]:
         prop_name = property_definition["name"]
         prop_type = property_definition["bl_idname"]
-        
+
         if prop_type in ['ParameterBoolSocket', 'ParameterIntSocket', 'ParameterFloatSocket', 'ParameterVectorSocket' ]:
             # is it good to make both of them?
             input = n.inputs.new( prop_type, prop_name)
@@ -135,7 +135,7 @@ def fix_custom_parameter(n, property_definition, ):
             if property_definition["is_output"] == True:
                 return output
             return input
-    
+
     elif n.bl_idname in ['LinkArmature']:
         prop_name = property_definition["name"]
         prop_type = property_definition["bl_idname"]
@@ -173,7 +173,7 @@ def fix_custom_parameter(n, property_definition, ):
 # to see if a dependency is created by node connections.
 # TODO it remains to be seen if that is even a desirable behaviour.
 def scan_tree_for_objects(base_tree, current_tree):
-    # this should work 
+    # this should work
     armatures, curves    = set(), set()
     if current_tree == base_tree:
         scan_tree_dependencies(base_tree, curves, armatures,)
@@ -310,7 +310,7 @@ def get_curve_for_pack(object):
 
 def matrix_as_tuple(matrix):
     return ( matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
-             matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3], 
+             matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
              matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
              matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3], )
 
@@ -322,7 +322,7 @@ class metabone_data:
     matrix                : tuple[float] = field(default=()),
     parent                : str = field(default=''),
     length                : float = field(default=-1.0),
-    children              : list[str] = field(default_factory=[]), 
+    children              : list[str] = field(default_factory=[]),
 # keep it really simple for now. I'll add BBone and envelope later on
 # when I make them accessible from the meta-rig
 
@@ -361,7 +361,7 @@ def get_socket_data(socket, ignore_if_default=False):
     socket_data["bl_idname"] = socket.bl_idname
     socket_data["is_output"] = socket.is_output
     socket_data["is_multi_input"] = socket.is_multi_input
-    
+
     # here is where we'll handle a socket_data'socket special data
     if socket.bl_idname == "EnumMetaBoneSocket":
         socket_data["bone"] = socket.bone
@@ -454,7 +454,7 @@ def get_tree_data(tree):
     tree_info = {}
     for propname  in dir(tree):
         # if getattr(tree, propname):
-        #     pass  
+        #     pass
         if (propname in prop_ignore_tree) or ( callable(getattr(tree, propname)) ):
             continue
         v = getattr(tree, propname)
@@ -489,7 +489,7 @@ def get_interface_data(tree, tree_in_out):
                 bl_socket_idname = 'VectorSocket'
             elif bl_socket_idname == 'NodeSocketInt':
                 bl_socket_idname = 'IntSocket'
-            
+
             try:
                 socket_class = getattr(socket_definitions, bl_socket_idname)
             except AttributeError: # sometimes the class doesn't work.
@@ -524,7 +524,7 @@ def get_interface_data(tree, tree_in_out):
             else:
                 sock_data["socket_type"] = sock.bl_socket_idname
             tree_in_out[sock.identifier] = sock_data
-            
+
 
 def export_to_json(trees, base_tree=None, path="", write_file=True, only_selected=False, ):
     export_data = {}
@@ -532,7 +532,7 @@ def export_to_json(trees, base_tree=None, path="", write_file=True, only_selecte
         current_tree_is_base_tree = False
         if tree is trees[-1]:
             current_tree_is_base_tree = True
-        
+
         tree_info, tree_in_out = {}, {}
         tree_info = get_tree_data(tree)
         curves, metarig_data = {}, {}
@@ -558,7 +558,7 @@ def export_to_json(trees, base_tree=None, path="", write_file=True, only_selecte
             if only_selected and node.select == False:
                 continue
             nodes[node.name] = get_node_data(node)
-            
+
         links = []
         in_sockets, out_sockets = {}, {}
         unique_sockets_from, unique_sockets_to = {}, {}
@@ -587,7 +587,7 @@ def export_to_json(trees, base_tree=None, path="", write_file=True, only_selecte
             else:
                 problem = link.to_node.name + "::" + link.to_socket.name
                 raise RuntimeError(wrapRed(f"Error saving index of socket: {problem}"))
-            
+
             if current_tree_is_base_tree:
                 if (only_selected and link.from_node.select) and (not link.to_node.select):
                     # handle an output in the tree
@@ -670,7 +670,7 @@ def export_to_json(trees, base_tree=None, path="", write_file=True, only_selecte
                         sock_data["in_out"]="INPUT"
                         sock_data["index"]=in_sock["index"]
 
-                        
+
                         tree_in_out[sock_name] = sock_data
 
                     from_node_name=in_node.get("name")
@@ -690,8 +690,8 @@ def export_to_json(trees, base_tree=None, path="", write_file=True, only_selecte
                            to_input_index,
                            from_socket_name,
                            to_socket_name) ) # it's a tuple
-        
-        
+
+
         if add_input_node or add_output_node:
             all_nodes_bounding_box=[Vector((float("inf"),float("inf"))), Vector((-float("inf"),-float("inf")))]
             for n in nodes.values():
@@ -714,7 +714,7 @@ def export_to_json(trees, base_tree=None, path="", write_file=True, only_selecte
             nodes["MANTIS_AUTOGEN_GROUP_OUTPUT"]=out_node
 
         export_data[tree.name] = (tree_info, tree_in_out, nodes, links, curves, metarig_data,) # f_curves)
-    
+
     return export_data
 
 def write_json_data(data, path):
@@ -722,7 +722,7 @@ def write_json_data(data, path):
     with open(path, "w") as file:
         print(wrapWhite("Writing mantis tree data to: "), wrapGreen(file.name))
         file.write( json.dumps(data, indent = 4) )
-        
+
 def get_link_sockets(link, tree, tree_socket_id_map):
     from_node_name = link[0]
     from_socket_id = link[1]
@@ -759,7 +759,7 @@ def get_link_sockets(link, tree, tree_socket_id_map):
         id1 = tree_socket_id_map.get(from_socket_id)
     for from_sock in from_node.outputs:
         if from_sock.identifier == id1: break
-    else: 
+    else:
         from_sock = None
 
     id2 = to_socket_id
@@ -908,7 +908,7 @@ def do_import_from_file(filepath, context):
     for tree in all_trees:
         tree.is_exporting = True
         tree.do_live_update = False
-    
+
     def do_cleanup(tree):
         tree.is_exporting = False
         tree.do_live_update = True
@@ -954,6 +954,8 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
         tree_info = tree_data[0]
         tree_in_out = tree_data[1]
 
+        print (tree_info)
+
 
         # TODO: IMPORT THIS DATA HERE!!!
         try:
@@ -962,14 +964,12 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
         except IndexError: # shouldn't happen but maybe someone has an old file
             curves = {}
             armatures = {}
-        
+
         for curve_name, curve_data in curves.items():
             from .utilities import import_curve_data_to_object, import_metarig_data
             import_curve_data_to_object(curve_name, curve_data)
             for armature_name, armature_data in armatures.items():
                 import_metarig_data(armature_data)
-        
-
 
         # need to make a new tree; first, try to get it:
         tree = bpy.data.node_groups.get(tree_info["name"])
@@ -978,21 +978,22 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
             continue # already done here because the tree already exists.
         if tree is None:
             tree = bpy.data.node_groups.new(tree_info["name"], tree_info["bl_idname"])
+        tree.mantis_version = tree_info['mantis_version']
         tree.nodes.clear(); tree.links.clear(); tree.interface.clear()
         # this may be a bad bad thing to do without some kind of warning TODO TODO
         tree.is_executing = True
         tree.do_live_update = False
         trees.append(tree)
-        
+
         tree_sock_id_map = {}
         tree_sock_id_maps[tree.name] = tree_sock_id_map
-        
+
         interface_parent_me = {}
 
         # I need to guarantee that the interface items are in the right order.
         interface_sockets = [] # I'll just sort them afterwards so I hold them here.
         default_position=0 # We'll use this if the position attribute is not set when e.g. making groups.
-        
+
 
         for s_name, s_props in tree_in_out.items():
             if s_props["item_type"] == 'SOCKET':
@@ -1016,14 +1017,14 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
                     interface_parent_me[sock] = (panel, s_props["position"])
             else: # it's a panel
                 panel = tree.interface.new_panel(s_props["name"], description=s_props.get("description"), default_closed=s_props.get("default_closed"))
-    
+
         for socket, (panel, index) in interface_parent_me.items():
             tree.interface.move_to_parent(
                                     socket,
                                     tree.interface.items_tree.get(panel),
                                     index,
                                     )
-        
+
         # BUG this was screwing up the order of things
         # so I want to fix it and re-enable it
         if True:
@@ -1031,7 +1032,7 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
             interface_sockets.sort(key=lambda a : a[1])
             for (socket, position) in interface_sockets:
                 tree.interface.move(socket, position)
-        
+
     # Now go and do nodes and links
     for tree_name, tree_data in data.items():
         if tree_name in skip_trees:
@@ -1041,7 +1042,7 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
         tree_info = tree_data[0]
         nodes = tree_data[2]
         links = tree_data[3]
-        
+
         parent_me = []
 
         tree = bpy.data.node_groups.get(tree_info["name"])
@@ -1051,9 +1052,9 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
         trees.append(tree)
 
         tree_sock_id_map=tree_sock_id_maps[tree.name]
-        
+
         interface_parent_me = {}
-        
+
 #        from mantis.utilities import prRed, prWhite, prOrange, prGreen
         for name, propslist in nodes.items():
             bl_idname = propslist["bl_idname"]
@@ -1089,7 +1090,7 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
                                 "SchemaIncomingConnection",]:
                 n.update()
 
-            
+
             if sub_tree := propslist.get("node_tree"):
                 # now that I am doing multi-file exports, this is tricky
                 # we need to see if the tree exists and if not, recurse
@@ -1127,13 +1128,13 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
                          "sockets",
                          "inputs",
                          "outputs",
-                         "warning_propagation", 
+                         "warning_propagation",
                          "socket_idname"]:
                     continue
                 # will throw AttributeError if read-only
                 # will throw TypeError if wrong type...
                 if n.bl_idname == "NodeFrame" and p in ["width, height, location"]:
-                    continue 
+                    continue
                 if version  < (4,4,0) and p == 'location_absolute':
                     continue
                 if p == "parent" and v is not None:
@@ -1144,7 +1145,7 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
                 except Exception as e:
                     prRed (p)
                     raise e
-                
+
 
         for l in links:
             from_socket_name = l[6]
@@ -1168,16 +1169,16 @@ def do_import(data, context, search_multi_files=False, filepath='', skip_existin
                     raise RuntimeError
                 else:
                     prRed(f"Failed to add link in {tree.name}: {name1}:{from_socket_name}, {name2}:{to_socket_name}")
-            
+
             # if at this point it doesn't work... we need to fix
         for name, p in parent_me:
             if (n := tree.nodes.get(name)) and (p := tree.nodes.get(p)):
                 n.parent = p
             # otherwise the frame node is missing because it was not included in the data e.g. when grouping nodes.
-        
+
         tree.is_executing = False
         tree.do_live_update = True
-        
+
 
 def export_multi_file(trees : list,  base_tree, filepath : str, base_name :str) -> None:
     for t in trees:
@@ -1191,7 +1192,7 @@ def export_multi_file(trees : list,  base_tree, filepath : str, base_name :str)
                         clean_name(t.name)+'.rig'))
         write_json_data(export_data, os_path.join(directory,
                         clean_name(t.name)+'.rig'))
-        
+
 
 import bpy
 
@@ -1228,7 +1229,7 @@ class MantisExportNodeTreeSaveAs(Operator, ExportHelper):
         # we need to get the dependent trees from self.tree...
         # there is no self.tree
         # how do I choose a tree?
-        
+
         base_tree=context.space_data.path[-1].node_tree
         from .utilities import all_trees_in_tree
         trees = all_trees_in_tree(base_tree)[::-1]
@@ -1396,4 +1397,4 @@ class MantisReloadNodeTree(Operator):
 # todo:
 #  - export metarig and option to import it
 #  - same with controls
-#  - it would be nice to have a library of these that can be imported alongside the mantis graph
+#  - it would be nice to have a library of these that can be imported alongside the mantis graph

+ 70 - 68
misc_nodes.py

@@ -211,7 +211,7 @@ class SimpleInputNode(MantisNode):
 
 class InputFloat(SimpleInputNode):
     '''A node representing float input'''
-    
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = ["Float Input"]
@@ -220,16 +220,16 @@ class InputFloat(SimpleInputNode):
 
 class InputIntNode(SimpleInputNode):
     '''A node representing integer input'''
-    
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = ["Integer"]
         self.outputs.init_sockets(outputs)
         self.init_parameters()
-    
+
 class InputVector(SimpleInputNode):
     '''A node representing vector input'''
-    
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = [""]
@@ -238,7 +238,7 @@ class InputVector(SimpleInputNode):
 
 class InputBoolean(SimpleInputNode):
     '''A node representing boolean input'''
-    
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = [""]
@@ -252,31 +252,31 @@ class InputBooleanThreeTuple(SimpleInputNode):
         outputs = [""]
         self.outputs.init_sockets(outputs)
         self.init_parameters()
-    
+
 class InputRotationOrder(SimpleInputNode):
     '''A node representing string input for rotation order'''
-        
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = [""]
         self.outputs.init_sockets(outputs)
         self.init_parameters()
-    
+
 class InputTransformSpace(SimpleInputNode):
     '''A node representing string input for transform space'''
-        
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = [""]
         self.outputs.init_sockets(outputs)
         self.init_parameters()
-        
+
     def evaluate_input(self, input_name):
         return self.parameters[""]
-    
+
 class InputString(SimpleInputNode):
     '''A node representing string input'''
-        
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs = [""]
@@ -285,7 +285,7 @@ class InputString(SimpleInputNode):
 
 class InputMatrix(SimpleInputNode):
     '''A node representing axis-angle quaternion input'''
-        
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         outputs  = ["Matrix",]
@@ -294,7 +294,7 @@ class InputMatrix(SimpleInputNode):
 
 class InputThemeBoneColorSets(SimpleInputNode):
     '''A node representing the theme's colors'''
-        
+
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
         from .base_definitions import MantisSocketTemplate
@@ -319,7 +319,7 @@ class InputColorSetPallete(SimpleInputNode):
     '''A node representing the theme's colors'''
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)
-    
+
     def fill_parameters(self, ui_node=None):
         if not ui_node:
             from .utilities import get_node_prototype
@@ -397,7 +397,7 @@ class UtilityMatrixFromCurve(MantisNode):
         self.parameters["Matrix"] = mat
         self.prepared = True
         self.executed = True
-    
+
     def bFinalize(self, bContext=None):
         cleanup_curve(self.evaluate_input("Curve"), self.base_tree.execution_id)
 
@@ -431,7 +431,7 @@ class UtilityPointFromCurve(MantisNode):
             p = data[spline_index][0][0] - curve.location
         self.parameters["Point"] = p
         self.prepared, self.executed = True, True
-    
+
     def bFinalize(self, bContext=None):
         cleanup_curve(self.evaluate_input("Curve"), self.base_tree.execution_id)
 
@@ -494,7 +494,7 @@ class UtilityMatricesFromCurve(MantisNode):
         self.prepared = True
         self.executed = True
         # prGreen(f"Matrices from curves took {time.time() - start_time} seconds.")
-    
+
     def bFinalize(self, bContext=None):
         import bpy
         curve_name = self.evaluate_input("Curve")
@@ -518,7 +518,7 @@ class UtilityNumberOfCurveSegments(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         curve_name = self.evaluate_input("Curve")
         curve = bpy_object_get_guarded( curve_name, self)
@@ -535,7 +535,7 @@ class UtilityNumberOfSplines(MantisNode):
         super().__init__(signature, base_tree, NumberOfSplinesSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         curve_name = self.evaluate_input("Curve")
         curve = bpy_object_get_guarded( curve_name, self)
@@ -596,7 +596,7 @@ class UtilityMatrixFromCurveSegment(MantisNode):
             m.translation = head - curve.location
             self.parameters["Matrix"] = m
         self.prepared, self.executed = True, True
-    
+
     def bFinalize(self, bContext=None):
         cleanup_curve(self.evaluate_input("Curve"), self.base_tree.execution_id)
 
@@ -605,7 +605,7 @@ class UtilityGetCurvePoint(MantisNode):
         super().__init__(signature, base_tree, GetCurvePointSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext=None):
         import bpy
         curve_name = self.evaluate_input("Curve")
@@ -630,7 +630,7 @@ class UtilityGetNearestFactorOnCurve(MantisNode):
         super().__init__(signature, base_tree, GetNearestFactorOnCurveSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         import bpy
         curve_name = self.evaluate_input("Curve")
@@ -764,14 +764,14 @@ class UtilityMetaRig(MantisNode):
         import bpy
         from mathutils import Matrix
         m = Matrix.Identity(4)
-        
+
         meta_rig  = self.evaluate_input("Meta-Armature")
         if meta_rig is None:
             raise RuntimeError("Invalid input for Meta-Armature.")
         meta_bone = self.evaluate_input("Meta-Bone")
         if meta_rig is None or meta_bone is None:
             raise RuntimeError("Invalid input for Meta-Bone.")
-        
+
         if meta_rig:
             if ( armOb := bpy.data.objects.get(meta_rig) ):
                 m = armOb.matrix_world
@@ -788,7 +788,7 @@ class UtilityMetaRig(MantisNode):
                 #     prRed("no bone for MetaRig node ", self)
         else:
             raise RuntimeError(wrapRed(f"No meta-rig input for MetaRig node {self}"))
-        
+
         self.parameters["Matrix"] = m
         self.prepared = True
         self.executed = True
@@ -814,7 +814,7 @@ class UtilityBoneProperties(SimpleInputNode):
 
     def fill_parameters(self, prototype=None):
         return
-        
+
 # TODO this should probably be moved to Links
 class UtilityDriverVariable(MantisNode):
     '''A node representing an armature object'''
@@ -838,23 +838,24 @@ class UtilityDriverVariable(MantisNode):
         self.init_parameters()
         self.node_type = "DRIVER" # MUST be run in Pose mode
         self.prepared = True
-    
+
     def reset_execution(self):
         super().reset_execution()
         # clear this to ensure there are no stale reference pointers
         self.parameters["Driver Variable"] = None
         self.prepared=True
-        
+
     def evaluate_input(self, input_name):
         if input_name == 'Property':
             if self.inputs.get('Property'):
                 if self.inputs['Property'].is_linked:
-                # get the name instead...
                     trace = trace_single_line(self, input_name)
-                    return trace[1].name # the name of the socket
+                    # CANNOT UNDERSTATE HOW CRITICAL THIS CHECK IS
+                    if trace[0][-1].node_type == 'XFORM':
+                        return trace[1].name # the name of the socket
             return self.parameters["Property"]
         return super().evaluate_input(input_name)
-        
+
     def GetxForm(self, index=1):
         trace = trace_single_line(self, "xForm 1" if index == 1 else "xForm 2")
         for node in trace[0]:
@@ -897,7 +898,7 @@ class UtilityDriverVariable(MantisNode):
             if self.evaluate_input("Property") == 'scale_average':
                 dVarChannel = "SCALE_AVG"
         if dVarChannel: v_type = "TRANSFORMS"
-        
+
         my_var = {
             "owner"         : xForm1, # will be filled in by Driver
             "prop"          : self.evaluate_input("Property"), # will be filled in by Driver
@@ -907,10 +908,11 @@ class UtilityDriverVariable(MantisNode):
             "xForm 1"       : xForm1,#self.GetxForm(index = 1),
             "xForm 2"       : xForm2,#self.GetxForm(index = 2),
             "channel"       : dVarChannel,}
-        
+
         self.parameters["Driver Variable"] = my_var
+        print (my_var['prop'])
         self.executed = True
-            
+
 class UtilityKeyframe(MantisNode):
     '''A node representing a keyframe for a F-Curve'''
 
@@ -958,7 +960,7 @@ class UtilityFCurve(MantisNode):
         self.node_type = "UTILITY"
         setup_custom_props(self)
         self.prepared = True
-    
+
     def reset_execution(self):
         super().reset_execution()
         self.prepared=True
@@ -984,7 +986,7 @@ class UtilityFCurve(MantisNode):
         keys.append(extrap_mode)
         self.parameters["fCurve"] = keys
         self.executed = True
-#TODO make the fCurve data a data class instead of a dict 
+#TODO make the fCurve data a data class instead of a dict
 
 class UtilityDriver(MantisNode):
     '''A node representing an armature object'''
@@ -1001,7 +1003,7 @@ class UtilityDriver(MantisNode):
         ]
         from .drivers import MantisDriver
         additional_parameters = {
-          "Driver":MantisDriver(), 
+          "Driver":MantisDriver(),
         }
         self.inputs.init_sockets(inputs)
         self.outputs.init_sockets(outputs)
@@ -1009,13 +1011,13 @@ class UtilityDriver(MantisNode):
         self.node_type = "DRIVER" # MUST be run in Pose mode
         setup_custom_props(self)
         self.prepared = True
-    
+
     def reset_execution(self):
         super().reset_execution()
         from .drivers import MantisDriver
         self.parameters["Driver"]=MantisDriver()
         self.prepared=True
-    
+
     def bRelationshipPass(self, bContext = None,):
         prepare_parameters(self)
         from .drivers import MantisDriver
@@ -1043,9 +1045,9 @@ class UtilityDriver(MantisNode):
                      "vars"          :  my_vars,
                      "keys"          :  keys[:-1],
                      "extrapolation" :  keys[-1] }
-        
+
         my_driver = MantisDriver(my_driver)
-        
+
         self.parameters["Driver"].update(my_driver)
         print("Initializing driver %s " % (wrapPurple(self.__repr__())) )
         self.executed = True
@@ -1065,7 +1067,7 @@ class UtilitySwitch(MantisNode):
         ]
         from .drivers import MantisDriver
         additional_parameters = {
-          "Driver":MantisDriver(), 
+          "Driver":MantisDriver(),
         }
         self.inputs.init_sockets(inputs)
         self.outputs.init_sockets(outputs)
@@ -1087,7 +1089,7 @@ class UtilitySwitch(MantisNode):
             if (node.__class__ in [xFormArmature, xFormBone]):
                 return node #this will fetch the first one, that's good!
         return None
-    
+
     def reset_execution(self):
         super().reset_execution()
         from .drivers import MantisDriver
@@ -1098,12 +1100,12 @@ class UtilitySwitch(MantisNode):
         #prepare_parameters(self)
         #prPurple ("Executing Switch Node")
         xForm = self.GetxForm()
-        if xForm : xForm = xForm.bGetObject() 
+        if xForm : xForm = xForm.bGetObject()
         if not xForm:
             raise RuntimeError("Could not evaluate xForm for %s" % self)
         from .drivers import MantisDriver
         my_driver ={ "owner" : None,
-                     "prop"  : None, # will be filled out in the node that uses the driver 
+                     "prop"  : None, # will be filled out in the node that uses the driver
                      "ind"   : -1, # same here
                      "type"  : "SCRIPTED",
                      "vars"  : [ { "owner" : xForm,
@@ -1118,13 +1120,13 @@ class UtilitySwitch(MantisNode):
                                    "type":"KEYFRAME",},],
                       "extrapolation": 'CONSTANT', }
         my_driver   ["expression"] = "a"
-        
+
         my_driver = MantisDriver(my_driver)
     # this makes it so I can check for type later!
-        
+
         if self.evaluate_input("Invert Switch") == True:
             my_driver   ["expression"] = "1 - a"
-        
+
         # this way, regardless of what order things are handled, the
         #  driver is sent to the next node.
         # In the case of some drivers, the parameter may be sent out
@@ -1153,7 +1155,7 @@ class UtilityCombineThreeBool(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def reset_execution(self): # need to make sure any references are deleted
         super().reset_execution() # so we prepare the node again to reset them
         if self.parameters["Three-Bool"] is not None:
@@ -1195,7 +1197,7 @@ class UtilityCombineVector(MantisNode):
             for param in self.parameters["Vector"]:
                 if isinstance(param, dict):
                     self.prepared=False; break
-    
+
     def bPrepare(self, bContext = None,):
         #prPurple("Executing CombineVector Node")
         prepare_parameters(self)
@@ -1204,7 +1206,7 @@ class UtilityCombineVector(MantisNode):
           self.evaluate_input("Y"),
           self.evaluate_input("Z"), )
         self.prepared, self.executed = True, True
-  
+
 class UtilitySeparateVector(MantisNode):
     '''A node for separating a vector into three floats'''
 
@@ -1245,7 +1247,7 @@ class UtilityCatStrings(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         self.parameters["OutputString"] = self.evaluate_input("String_1")+self.evaluate_input("String_2")
         self.prepared, self.executed = True, True
@@ -1257,7 +1259,7 @@ class InputWidget(MantisNode):
         super().__init__(signature, base_tree, InputWidgetSockets)
         self.init_parameters()
         self.node_type = "XFORM"
-    
+
     def reset_execution(self):
         super().reset_execution()
         self.prepared=False
@@ -1332,10 +1334,10 @@ class InputWidget(MantisNode):
             flip_modifier["Socket_3"]=axes_flipped[1]
             flip_modifier["Socket_4"]=axes_flipped[2]
         self.prepared, self.executed = True, True
-    
+
     def bGetObject(self, mode=''):
         return self.bObject
-    
+
 # TODO move this to the Xform file
 class InputExistingGeometryObject(MantisNode):
     '''A node representing an existing object'''
@@ -1352,7 +1354,7 @@ class InputExistingGeometryObject(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "XFORM"
-    
+
     def reset_execution(self):
         super().reset_execution()
         self.prepared=False
@@ -1366,7 +1368,7 @@ class InputExistingGeometryObject(MantisNode):
             prRed(f"No object found with name {name} in {self}")
         self.bObject=ob
         self.prepared, self.executed = True, True
-    
+
     def bGetObject(self, mode=''):
         return self.bObject
 
@@ -1412,7 +1414,7 @@ class UtilityDeclareCollections(MantisNode):
     def reset_execution(self):
         super().reset_execution()
         self.prepared, self.executed = True, True
-    
+
     def fill_parameters(self, ui_node=None):
         if ui_node is None:
             from .utilities import get_node_prototype
@@ -1422,7 +1424,7 @@ class UtilityDeclareCollections(MantisNode):
         for out in ui_node.outputs:
             if not (out.name in self.outputs.keys()) :
                 templates.append(SockTemplate(name=out.name,
-                        identifier=out.identifier, is_input=False,))    
+                        identifier=out.identifier, is_input=False,))
         self.outputs.init_sockets(templates)
         # now we have our parameters, fill them. This is a little inefficient I guess.
         for out in ui_node.outputs:
@@ -1439,7 +1441,7 @@ class UtilityCollectionJoin(MantisNode):
     def reset_execution(self):
         super().reset_execution()
         self.prepared, self.executed = False, False
-    
+
     def bPrepare(self, bContext = None,):
         if self.inputs['Collections'].links:
             bCol_groups = []
@@ -1607,7 +1609,7 @@ class UtilitySetBoneLength(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         from mathutils import Vector
         if matrix := self.evaluate_input("Bone Matrix"):
@@ -1636,7 +1638,7 @@ class UtilityMatrixSetLocation(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         from mathutils import Vector
         if matrix := self.evaluate_input("Matrix"):
@@ -1661,7 +1663,7 @@ class UtilityMatrixGetLocation(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-    
+
     def bPrepare(self, bContext = None,):
         from mathutils import Vector
         if matrix := self.evaluate_input("Matrix"):
@@ -1682,14 +1684,14 @@ class UtilityMatrixFromXForm(MantisNode):
         self.inputs.init_sockets(inputs)
         self.outputs.init_sockets(outputs)
         self.init_parameters()
-    
+
     def GetxForm(self):
         trace = trace_single_line(self, "xForm")
         for node in trace[0]:
             if (node.node_type == 'XFORM'):
                 return node
         raise GraphError("%s is not connected to an xForm" % self)
-        
+
     def bPrepare(self, bContext = None,):
         from mathutils import Vector, Matrix
         self.parameters["Matrix"] = Matrix.Identity(4)
@@ -1719,7 +1721,7 @@ class UtilityAxesFromMatrix(MantisNode):
         self.outputs.init_sockets(outputs)
         self.init_parameters()
         self.node_type = "UTILITY"
-        
+
     def bPrepare(self, bContext = None,):
         from mathutils import Vector
         if matrix := self.evaluate_input("Matrix"):
@@ -1859,7 +1861,7 @@ class UtilityMatrixAlignRoll(MantisNode):
         #  it directly from the Y axis, the normalized projection of the align
         #  axis, and their cross-product. That only nearly worked.
         # this calculation should not work better, but it does. Why?
-        
+
 class UtilityTransformationMatrix(MantisNode):
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree)