| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- from .utilities import (prRed, prGreen, prPurple, prWhite,
- prOrange,
- wrapRed, wrapGreen, wrapPurple, wrapWhite,
- wrapOrange,)
- from ..base_definitions import GraphError, NodeSocket, MantisNode
- from collections.abc import Callable
- # BE VERY CAREFUL
- # the x_containers files import * from this file
- # so all the top-level imports are carried over
- from bpy.app import version as bpy_version
- # Utility to print links nicely for end user.
- def print_link_list(links):
- ret_str = ""
- for link in links:
- ret_str+= link.__repr__() + '\n'
- return ret_str
- # I've moved this to a separate function because the trace functions
- # are kind of hard to understand and the cycle check breaks the flow
- # of the code.
- def detect_cycle_in_trace(link, link_circle):
- if link.is_hierarchy:
- if link in link_circle:
- raise GraphError( "There is a cycle in the following links:\n" +
- print_link_list(link_circle))
- link_circle.append(link)
- # NOTE this is a dupe of trace_single_line, and it must be used
- # at any time before the tree is parsed (to check for cycles)
- # I don't want or need to pay the performance cost to check this everywhere
- def trace_single_line_safe(mantis_node, input_name, link_index=0):
- # DO: refactor this for new link class
- """Traces a line to its input."""
- nodes = [mantis_node]
- # a test for cyclic connections
- link_circle = []
- # Trace a single line
- if (socket := mantis_node.inputs.get(input_name) ):
- while (socket.is_linked):
- link = socket.links[link_index]; link_index = 0
- # should throw an error if it is in the set
- if detect_cycle_in_trace(link, link_circle):
- return
- if (socket := link.from_node.outputs.get(link.from_socket)):
- nodes.append(socket.node)
- if socket.can_traverse:
- socket = socket.traverse_target
- else: # this is an output.
- break
- else:
- break
- return nodes, socket
- def trace_single_line(mantis_node, input_name, link_index=0):
- # DO: refactor this for new link class
- """Traces a line to its input."""
- nodes = [mantis_node]
- # a test for cyclic connections
- if (socket := mantis_node.inputs.get(input_name) ):
- while (socket.is_linked):
- link = socket.links[link_index]; link_index = 0
- if (socket := link.from_node.outputs.get(link.from_socket)):
- nodes.append(socket.node)
- if socket.can_traverse:
- socket = socket.traverse_target
- else: # this is an output.
- break
- else:
- break
- return nodes, socket
- def trace_single_line_up(mantis_node, output_name,):
- """I use this to get the xForm from a link node."""
- nodes = [mantis_node]
- if hasattr(mantis_node, "outputs"):
- # Trace a single line
- if (socket := mantis_node.outputs.get(output_name) ):
- while (socket.is_linked):
- # This is bad, but it's efficient for nodes that only expect
- # one path along the given line
- link = socket.links[0] # TODO: find out if this is wise.
- other = link.to_node.inputs.get(link.to_socket)
- if (other):
- socket = other
- if socket.can_traverse:
- socket = socket.traverse_target
- nodes.append(socket.node)
- else: # this is an input.
- nodes.append(socket.node)
- break
- else:
- break
- return nodes, socket
- def trace_line_up_branching(mantis_node : MantisNode, output_name : str,
- break_condition : Callable = lambda mantis_node : False):
- """ Returns all leaf nodes at the ends of branching lines from an output."""
- leaf_nodes = []
- if hasattr(mantis_node, "outputs"):
- # Trace a single line
- if (socket := mantis_node.outputs.get(output_name) ):
- check_sockets={socket}
- while (check_sockets):
- # This is bad, but it's efficient for nodes that only expect
- # one path along the given line
- socket = check_sockets.pop()
- for link in socket.links:
- other = link.to_node.inputs.get(link.to_socket)
- if (other):
- socket = other
- if break_condition(socket.node):
- leaf_nodes.append(socket.node)
- elif socket.is_input and socket.can_traverse:
- check_sockets.add(socket.traverse_target)
- else: # this is an input.
- leaf_nodes.append(socket.node)
- return leaf_nodes
- # For this, we basically just evaluate the driver once and use the result
- def find_driven_default_value(mantis_node, socket_name):
- from ..misc_nodes import UtilityDriver, UtilitySwitch
- from .utilities import get_ui_node
- xf_inputs_values_var_names = []
- node_line, _last_socket = trace_single_line(mantis_node, socket_name)
- driver_node = None
- driver_type = 'SUM'
- keys = [ (0, 0), (1, 1) ]
- for driver_node in node_line:
- if driver_node.node_type == 'DRIVER': break
- else: # it's not being driven
- return mantis_node.evaluate_input(socket_name)
-
- if isinstance(driver_node, UtilityDriver):
- driver_type = driver_node.evaluate_input("Driver Type")
- # then get the variables
- for i, input in enumerate(driver_node.inputs):
- # unicode for 'a'
- var_name = chr(i - 2 + 96)
- if i == 0 : continue # the Driver Type doesn't interest us
- elif i ==1 : continue # for now. we do need the fCurve
- else:
- if not input.is_linked: continue # nothing to do here
- var_node = input.links[0].from_node
- # NOTE: this var_node will not be prepared on time unless we sort the graph by depth
- # and it doesn't seem to be possible to do that without breaking drivers... so
- # HACK it's safe to do this, but VERY ugly and bad.
- if not var_node.prepared:
- var_node.bPrepare()
- # end HACK
- var_data = var_node.parameters["Driver Variable"]
- var_type = var_data['type']
- var_channel = var_data['channel']
- prop_name = None; value = None
- xf1 = var_node.GetxForm(index=1)
- match var_type:
- case "SINGLE_PROP":
- prop_name = var_node.evaluate_input("Property")
- # we'll get the property value in the next step
- case "TRANSFORMS":
- matrix1 = xf1.evaluate_input['Matrix']
- # Mantis ensures that these are identity at creation time
- if "LOC" in var_channel or "ROT" in var_channel:
- value = 0
- else: # Scale, defaults to 1
- value = 1
- case "ROTATION_DIFF":
- xf2 = var_node.GetxForm(index=2)
- matrix1 = xf1.evaluate_input['Matrix']
- matrix2 = xf2.evaluate_input['Matrix']
- value = matrix1.to_quaternion().rotation_difference(matrix2.to_quaternion()).angle
- case "LOC_DIFF":
- xf2 = var_node.GetxForm(index=2)
- matrix1 = xf1.evaluate_input['Matrix']
- matrix2 = xf2.evaluate_input['Matrix']
- value = (matrix1.to_translation() - matrix2.to_translation()).length
- case "CONTEXT_PROP":
- raise NotImplementedError("Mantis Does not yet support Context Property")
- pass
- xf_inputs_values_var_names.append((xf1, prop_name, value, var_name))
- # Now we'll get the keyframe points and sort them, too!
- if driver_node.inputs['fCurve'].is_linked:
- fCurve_node = driver_node.inputs['fCurve'].links[0].from_node
- extrapolation_mode = 'CONSTANT'
- keys = []
- if fCurve_node:
- extrapolation_mode = fCurve_node.evaluate_input("Extrapolation Mode")
- for l in fCurve_node.inputs['Keyframes'].links:
- key_node = l.from_node
- if key_node:
- keys.append( (key_node.evaluate_input("Frame"), key_node.evaluate_input("Value")) )
- keys = sorted( keys, key = lambda a : a[0]) # sort by the frame
- elif isinstance(driver_node, UtilitySwitch):
- # Reimplementing the GetxForm from the switch here
- # because it is faster to inline this and store the trace result
- trace = trace_single_line(driver_node, "Parameter" )
- for node in trace[0]:
- if node.node_type == 'XFORM':
- xf = node # reuse trace HERE
- prop_name = trace[1].name # saves us from tracing again.
- xf_inputs_values_var_names.append(( xf, prop_name, None, "a")); break
- else:
- raise RuntimeError(f"ERROR: Cannot Set the default of the driven value {socket_name} \n"
- f"in node {mantis_node}")
- # We're gonna assume the xForm is sorting these right
- # but we'll check the name if it is cheap
- default_values = {}
- for xf, prop_name, value, var_name in xf_inputs_values_var_names:
- i=0
- for output in xf.outputs:
- if 'xForm Out' == output.name: continue
- if output.name == prop_name: break
- i+=1
- node_line, _last_socket = trace_single_line(xf, "Custom Properties", i)
- custom_prop_node = node_line[-1]
- if value:
- default_values[var_name] = value; continue
- if prop_name:
- if custom_prop_node.evaluate_input("Name") == prop_name:
- custom_prop_type = custom_prop_node.evaluate_input("Type")
- default_prop_name = ""
- match custom_prop_type:
- case "BOOL":
- default_prop_name = 'Default (Bool)'
- case "FLOAT":
- default_prop_name = 'Default (Float)'
- case "INT":
- default_prop_name = 'Default (Int)'
- case _:
- raise RuntimeError(f"ERROR: Cannot Set the default of the driven value {socket_name} \n"
- f"in node {mantis_node}"
- f"Reason: Custom Property {prop_name} is not a valid type." )
- default_values[var_name] = float(custom_prop_node.evaluate_input(default_prop_name))
- else:
- raise RuntimeError(f"ERROR: failed to get proeprty {prop_name} for node {xf}, \n"
- f"cannot Set the default of the driven value {socket_name} \n"
- f"in node {mantis_node}"
- "Reason: Cannot Find Custom Property Node")
- frame = 0.0
- if default_values:
- match driver_type:
- case "AVERAGE":
- frame = sum(default_values.values())/len(default_values)
- case "SUM":
- frame = sum(default_values.values())
- case "MIN":
- frame = min(default_values.values())
- case "MAX":
- frame = max(default_values.values())
- case "SCRIPTED":
- raise NotImplementedError (f"ERROR: Cannot Set the default of the driven value {socket_name} \n"
- f"in node {mantis_node} \n"
- "Reason: Driver Expressions are not yet implemented.")
- # Now we apply the fCurve
- # For now, We'll assume LINEAR keys TODO: come back to this during Pose update!
- if len(keys) >= 2:
- previous_frame = None
- next_frame = None
- previous_value = None
- next_value = None
- for key in keys:
- if key[0] <= frame: previous_frame, previous_value = key
- if key[0] >= frame: next_frame, next_value = key
- if previous_frame is not None and next_frame is not None: break
- else: # if our frame is out-of-bounds we need a slope to extrapolate on.
- if previous_frame and not next_frame:
- next_frame, next_value = previous_frame, previous_value
- if extrapolation_mode == 'LINEAR':
- previous_frame, previous_value = keys[-2] # we need the second last key to extrapolate
- elif next_frame and not previous_frame:
- previous_frame, previous_value = next_frame, next_value
- if extrapolation_mode == 'LINEAR':
- next_frame, next_value = keys[1] # we need the second key to extrapolate
- else:
- raise RuntimeError (f"ERROR: Cannot Set the default of the driven value {socket_name} \n"
- f"in node {mantis_node} \n"
- "Reason: Cannot place value on driver fCurve.")
- if previous_frame == next_frame: # the frame is exactly on a key
- return previous_value
- # this is just a simple lerp because we are assuming the keys are linear for now
- result = previous_value + ((frame - previous_frame) / (next_frame - previous_frame)) * (next_value - previous_value)
- elif len(keys) ==1:
- result = key[1] # flat curve, take the value of the only key
- else:
- raise RuntimeError (f"ERROR: Cannot Set the default of the driven value {socket_name} \n"
- f"in node {mantis_node} \n"
- "Reason: Invalid fCurve has 0 keyframes")
- return result
-
- # this function exists to walk back to the first ancestor node of XFORM or LINK without
- # breaking the traverse behaviour which I still need for various reasons.
- def get_parent_xForm_info(mantis_node, socket_name = 'Relationship'):
- from ..mantis_dataclasses import xForm_info
- # we re-implement the trace logic here for performance.
- # because this kind of connection has traversal (for Links to find their children), we must
- # simply seek back to the first available xForm or Link and get its xForm info.\
- parent_node = None
- if (socket := mantis_node.inputs.get(socket_name) ):
- while (socket.is_linked):
- link = socket.links[0]
- if (socket := link.from_node.outputs.get(link.from_socket)):
- if socket.node.node_type in ['LINK', 'XFORM']:
- parent_node = socket.node; break
- if socket.can_traverse:
- socket = socket.traverse_target
- else: # this is an output.
- break
- else:
- break
- parent_xForm_info = None
- if parent_node:
- if parent_node.node_type == 'XFORM':
- parent_xForm_info = parent_node.parameters['xForm Out']
- else:
- if 'Output Relationship' in parent_node.parameters.keys():
- parent_xForm_info = parent_node.parameters['Output Relationship']
- else: # TODO refactor Inherit Node to have the same output as the other link nodes.
- parent_xForm_info = parent_node.parameters['Inheritance']
- if parent_xForm_info is None: parent_xForm_info = xForm_info() # default to empty
- return parent_xForm_info
- def setup_custom_property_inputs_outputs(mantis_node):
- from .utilities import get_ui_node
- if mantis_node.signature[0] == 'SCHEMA_AUTOGENERATED':
- from ..base_definitions import custom_props_types
- if mantis_node.__class__.__name__ not in custom_props_types:
- raise RuntimeError(wrapRed(f"Custom Properties not allowed for class {mantis_node.__class__.__name__}"))
- return
- else:
- ui_node = get_ui_node(mantis_node.ui_signature, mantis_node.base_tree)
- if ui_node:
- setup_custom_props_from_np(mantis_node, ui_node)
- else:
- prRed(f"Failed to setup custom properties for: {mantis_node.ui_signature}")
- def setup_custom_props_from_np(mantis_node, ui_node):
- for inp in ui_node.inputs:
- if inp.identifier == "__extend__": continue
- if not (inp.name in mantis_node.inputs.keys()) :
- socket = NodeSocket(is_input = True, name = inp.name, node = mantis_node,)
- mantis_node.inputs[inp.name] = socket
- mantis_node.parameters[inp.name] = None
- for attr_name in ["min", "max", "soft_min", "soft_max", "description"]:
- try:
- setattr(socket, attr_name, getattr(inp, attr_name))
- except AttributeError:
- pass
- for out in ui_node.outputs:
- if out.identifier == "__extend__": continue
- if not (out.name in mantis_node.outputs.keys()) :
- mantis_node.outputs[out.name] = NodeSocket(is_input = False, name = out.name, node = mantis_node,)
-
- def prepare_parameters(mantis_node):
- # some nodes add new parameters at runtime, e.g. Drivers
- # so we need to take that stuff from the mantis_nodes that have
- # been executed prior to this node.
- for s_name, sock in mantis_node.inputs.items():
- if not (sock.is_linked):
- continue
- if (sock.name in sock.links[0].from_node.parameters.keys()):
- mantis_node.parameters[s_name] = sock.links[0].from_node.parameters[sock.name]
- # should work, this is ugly.
- def check_for_driver(mantis_node, input_name, value_index = None, array_index = 0, combo_property=False):
- prop = mantis_node.evaluate_input(input_name, array_index)
- if (value_index is not None):
- try:
- prop = prop[value_index]
- except KeyError: # We'll try to use the driver for all three channels.
- pass
- # TODO an Index or Key error here should have a reasonable error message
- return (prop.__class__.__name__ == 'MantisDriver')
- def print_driver_item(mantis_node, b_object, original_prop):
- if mantis_node.node_type in ['LINK',]:
- printname = wrapOrange(b_object.id_data.name)
- elif mantis_node.node_type in ['XFORM',]:
- printname = wrapOrange(mantis_node.bGetObject().name)
- else:
- printname = wrapOrange(mantis_node)
- print("Adding driver %s to %s in %s" % (wrapPurple(original_prop), wrapWhite(mantis_node.signature[-1]), printname))
- # HACK This is the most hideous voodoo black magic fucntion in the entire program
- # but everything depends on it and it works
- def evaluate_sockets(mantis_node, b_object, props_sockets,):
- # this is neccesary because some things use dict properties for dynamic properties and setattr doesn't work
- def safe_setattr(ob, att_name, val):
- if ob.__class__.__name__ in ["NodesModifier"]:
- ob[att_name]=val
- elif b_object.__class__.__name__ in ["Key"]:
- if not val: val=0
- ob.key_blocks[att_name].value=val
- elif "]." in att_name:
- # it is of the form prop[int].prop2
- prop=att_name.split('[')[0]
- prop1=att_name.split('.')[1]
- get_index = int(att_name.split('[')[1][0])
- setattr(getattr(b_object, prop)[get_index], prop1, val)
- else:
- try:
- setattr(ob, att_name, val)
- except Exception as e:
- print ("ob, att_name, val")
- prRed(ob, att_name, val)
- raise e
- for prop, filler_item in props_sockets.items():
- if isinstance(filler_item, tuple):
- raise NotImplementedError(mantis_node)
- sock = filler_item.socket_name
- default = filler_item.default_value
- value_index = filler_item.value_index
- array_index = filler_item.array_index
- combo_property = filler_item.combo_property
- driver_key = (sock, value_index, array_index)
- if (check_for_driver(mantis_node, sock, value_index, array_index, combo_property)):
- original_prop = prop
- # TODO: deduplicate this terrible hack
- if ("." in prop) and not b_object.__class__.__name__ in ["Key"]: # this is a property of a property...
- sub_props = [b_object]
- while ("." in prop):
- split_prop = prop.split(".")
- prop = split_prop[1]
- sub_prop = (split_prop[0])
- if ("[" in sub_prop):
- sub_prop, sub_index = sub_prop.split("[")
- sub_prop_index = int(sub_index[0])
- sub_props.append(getattr(sub_props[-1], sub_prop)[sub_prop_index])
- else:
- sub_props.append(getattr(sub_props[-1], sub_prop))
- safe_setattr(sub_props[-1], prop, default)
- # this is really stupid
- else:
- safe_setattr(b_object, prop, default)
- print_driver_item( mantis_node, b_object, original_prop)
- if b_object.__class__.__name__ in ["NodesModifier"]:
- mantis_node.drivers[driver_key] = "[\""+original_prop+"\"]" # lol. It is a dict element not a "true" property
- elif b_object.__class__.__name__ in ["Key"]:
- mantis_node.drivers[driver_key] = "key_blocks[\""+original_prop+"\"].value"
- else:
- mantis_node.drivers[driver_key] = original_prop
- else: # here we can do error checking for the socket if needed
- if (value_index is not None):
- safe_setattr(b_object, prop, mantis_node.evaluate_input(sock)[value_index])
- else: # 'mute' is better than 'enabled'
- # UGLY HACK # because it is available in older
- if (prop == 'mute'): # Blenders.
- safe_setattr(b_object, prop, not bool(mantis_node.evaluate_input(sock)))
- elif (prop == 'hide'): # this will not cast it for me, annoying.
- safe_setattr(b_object, prop, bool(mantis_node.evaluate_input(sock)))
- else:
- try:
- # just wanna see if we are dealing with some collection
- # check hasattr in case it is one of those ["such-and-such"] props, and ignore those
- if hasattr(b_object, prop) and (not isinstance(getattr(b_object, prop), str)) and hasattr(getattr(b_object, prop), "__getitem__"):
- # prGreen("Doing the thing")
- for val_index, value in enumerate(mantis_node.evaluate_input(sock)):
- # assume this will work, both because val should have the right number of elements, and because this should be the right data type.
- from .drivers import MantisDriver
- if isinstance(value, MantisDriver):
- getattr(b_object,prop)[val_index] = default[val_index]
- print("Adding driver %s to %s in %s" % (wrapPurple(prop), wrapWhite(mantis_node.signature[-1]), mantis_node))
- try:
- mantis_node.drivers[sock].append((prop, val_index))
- except:
- mantis_node.drivers[sock] = [(prop, val_index)]
- else:
- getattr(b_object,prop)[val_index] = value
- else:
- safe_setattr(b_object, prop, mantis_node.evaluate_input(sock))
- except Exception as e:
- prRed(b_object, mantis_node, prop, sock, mantis_node.evaluate_input(sock))
- raise e
- def finish_driver(mantis_node, b_object, driver_item, prop):
- try:
- driver_sock = driver_item[0]; index = driver_item[1]; array_index =driver_item[2]
- except Exception as e:
- print (wrapGreen(mantis_node), wrapOrange(b_object), wrapRed(driver_item), wrapWhite(prop),)
- raise e
- driver_trace = trace_single_line(mantis_node, driver_sock, array_index)
- driver_provider, driver_socket = driver_trace[0][-1], driver_trace[1]
-
- combo_property = False
- # try to detect combo properties
- if mantis_node.socket_templates:
- for st in mantis_node.socket_templates:
- if st.name == driver_sock:
- if isinstance(st.blender_property, tuple):
- combo_property = True
- break
- if index is not None:
- try:
- driver = driver_provider.parameters[driver_socket.name][index].copy()
- except KeyError as e: # try single driver, it should still work fine.
- if combo_property:
- driver = driver_provider.parameters[driver_socket.name].copy()
- else:
- raise e
- # this is harmless and necessary for the weird ones where the property is a vector too
- if not combo_property:
- driver["ind"] = index
- else:
- driver = driver_provider.parameters[driver_socket.name].copy()
- if driver:
- socket_template = None
- if mantis_node.socket_templates:
- for socket_template in mantis_node.socket_templates:
- if socket_template.name == driver_sock: break
- if socket_template:
- if socket_template.is_animatable == False:
- raise RuntimeError(f"Driver is not allowed for {driver_sock} in node {mantis_node}")
- if ("." in prop) and mantis_node.__class__.__name__ != "DeformerMorphTargetDeform": # this is a property of a property...
- sub_props = [b_object]
- while ("." in prop):
- split_prop = prop.split(".")
- prop = split_prop[1]
- sub_prop = (split_prop[0])
- if ("[" in sub_prop):
- sub_prop, index = sub_prop.split("[")
- index = int(index[0])
- sub_props.append(getattr(sub_props[-1], sub_prop)[index])
- else:
- sub_props.append(getattr(sub_props[-1], sub_prop))
- driver["owner"] = sub_props[-1]
- elif mantis_node.node_type in ['XFORM',] and mantis_node.__class__.__name__ in ['xFormBone']:
- # TODO: I really shouldn't have to hardcode this. Look into better solutions.
- # NOTE: VERSIONING in Blender 5.0 we have to use pose bone for this, too.
- # default to pose bone, it's usually what we want
- bone_col = mantis_node.bGetParentArmature().pose.bones
- from ..xForm_socket_templates import attributes_shared_by_bone_and_pose_bone
- if socket_template.prop_owner_group == 'bone':
- bone_col = mantis_node.bGetParentArmature().data.bones
- # this is a little bit clumsy. TODO clean up here
- if prop in attributes_shared_by_bone_and_pose_bone:
- # we want to use the pose bone for this...only if it has a driver
- bone_col = mantis_node.bGetParentArmature().pose.bones
- driver["owner"] = bone_col[b_object] # we use "unsafe" brackets instead of get() because we want to see any errors that occur
- # HACK having special cases here is indicitave of a deeper problem that should be refactored
- elif mantis_node.__class__.__name__ in ['xFormCurvePin'] and \
- prop in ['offset_factor', 'forward_axis', 'up_axis']:
- driver["owner"] = b_object.constraints['Curve Pin']
- else:
- driver["owner"] = b_object
- driver["prop"] = prop
- return driver
- else:
- prOrange("Provider", driver_provider)
- prGreen("socket", driver_socket)
- print (index)
- prPurple(driver_provider.parameters[driver_socket.name])
- prRed("Failed to create driver for %s" % prop)
- return None
- def finish_drivers(mantis_node):
- drivers = []
- if not hasattr(mantis_node, "drivers"):
- return # HACK
- for driver_item, prop in mantis_node.drivers.items():
- b_objects = [mantis_node.bObject]
- if mantis_node.node_type == 'LINK':
- b_objects = mantis_node.bObject # this is already a list
- for b_object in b_objects:
- # Mutating the driver_item here is the WORST THING I HAVE EVER SEEN
- # HACK UGLY BUG TERRIBLE BAD CODE
- if isinstance(prop, list):
- for sub_item in prop:
- drivers.append(finish_driver(mantis_node, b_object, (driver_item, sub_item[1], 0), sub_item[0]))
- else:
- drivers.append(finish_driver(mantis_node, b_object, (driver_item, sub_item[1], 0), sub_item[0]))
- else:
- drivers.append(finish_driver(mantis_node, b_object, driver_item, prop))
- from .drivers import CreateDrivers
- CreateDrivers(drivers)
|