| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- #Versioning Tasks
- # this will be the new versioning system, and will deprecate the old SOCKETS_ADDED and such
- from bpy.types import Node, NodeSocket
- from bpy.app import version as bpy_version
- from .utilities.utilities import (prRed, prGreen, prPurple, prWhite,
- prOrange,
- wrapRed, wrapGreen, wrapPurple, wrapWhite,
- wrapOrange,
- get_socket_maps, do_relink, )
- # CHECKLIST FOR DUMMIES:
- # Did you make sure to turn off and re-enable tree updates?
- # Did you restore connections to the node socket after changing things?
- # Did you test FUNCTIONALITY in your test rigs instead of just checking if the tree
- # would generate? CHANGED FUNCTIONALITY IS STILL A BUG!!
- # Did you make sure to toggle the is_updating flag for ANY node that is touched by
- # the edits you are doing to the current node (example: removing a socket causes
- # linked group and schema nodes to update)
- # (add more whenever a weird or difficult to debug problem occurs)
- # Did you check the update script on a tree that doesn't need it?
- # Did you use a >= when you should have used a > (or similar)?
- # Did you make sure that nodes with array inputs are sorting them properly?
- def version_upgrade_very_old(*args, **kwargs):
- node = kwargs['node']
- current_major_version = node.id_data.mantis_version[0]
- current_minor_version = node.id_data.mantis_version[1]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version > 11: return# minor version must be 12 or less
- # this is the old node update, very inneficient and strange and badly organized
- NODES_REMOVED=["xFormRootNode"]
- # Node bl_idname, # Socket Name
- SOCKETS_REMOVED=[("UtilityDriverVariable", "Transform Channel"),
- ("xFormRootNode","World Out"),
- ("UtilitySwitch","xForm"),
- ("LinkDrivenParameter", "Enable")]
- # Node Class #Prior bl_idname # prior name # new bl_idname # new name, # Multi
- SOCKETS_RENAMED=[ ("LinkDrivenParameter", "DriverSocket", "Driver", "FloatSocket", "Value", False),
- ("DeformerHook", "IntSocket", "Index", "UnsignedIntSocket", "Point Index", False),
- ("SchemaConstOutput", "IntSocket", "Expose when N==", "UnsignedIntSocket", "Expose at Index", False),]
- # NODE CLASS NAME IN_OUT SOCKET TYPE SOCKET NAME INDEX MULTI DEFAULT
- SOCKETS_ADDED=[("DeformerMorphTargetDeform", 'INPUT', 'BooleanSocket', "Use Shape Key", 1, False, False),
- ("DeformerMorphTargetDeform", 'INPUT', 'BooleanSocket', "Use Offset", 2, False, True),
- ("UtilityFCurve", 'INPUT', "eFCrvExtrapolationMode", "Extrapolation Mode", 0, False, 'CONSTANT'),
- ("LinkCopyScale", 'INPUT', "BooleanSocket", "Additive", 3, False, False),
- ("DeformerHook", 'INPUT', "FloatFactorSocket", "Influence",3, False, 1.0),
- ("DeformerHook", 'INPUT', "UnsignedIntSocket", "Spline Index", 2, False, 0),
- ("DeformerHook", 'INPUT', "BooleanSocket", "Auto-Bezier", 5, False, True),
- ("UtilityCompare", 'INPUT', "EnumCompareOperation", "Comparison", 0, False, 'EQUAL'),
- ("UtilityMatrixFromCurve", 'INPUT', "UnsignedIntSocket", "Spline Index", 1, False, 0),
- ("UtilityMatricesFromCurve", 'INPUT', "UnsignedIntSocket", "Spline Index", 1, False, 0),
- ("UtilityPointFromCurve", 'INPUT', "UnsignedIntSocket", "Spline Index", 1, False, 0),
- ("LinkCopyScale", 'INPUT', "FloatFactorSocket", "Power", 5, False, 1.0),
- ]
- rename_jobs = []
- node_tree = kwargs['node_tree']
- try:
- if node.bl_idname in NODES_REMOVED:
- print(f"INFO: removing node {node.name} of type {node.bl_idname} because it has been deprecated.")
- node.inputs.remove(socket)
- return
- for i, socket in enumerate(node.inputs.values()):
- if (node.bl_idname, socket.identifier) in SOCKETS_REMOVED:
- print(f"INFO: removing socket {socket.identifier} of node {node.name} of type {node.bl_idname} because it has been deprecated.")
- node.inputs.remove(socket)
- for old_class, old_bl_idname, old_name, new_bl_idname, new_name, multi in SOCKETS_RENAMED:
- if (node.bl_idname == old_class and socket.bl_idname == old_bl_idname and socket.name == old_name):
- rename_jobs.append((socket, i, new_bl_idname, new_name, multi))
- for i, socket in enumerate(node.outputs.values()):
- if (node.bl_idname, socket.identifier) in SOCKETS_REMOVED:
- print(f"INFO: removing socket {socket.identifier} of node {node.name} of type {node.bl_idname} because it has been deprecated.")
- node.outputs.remove(socket)
- for old_class, old_bl_idname, old_name, new_bl_idname, new_name, multi in SOCKETS_RENAMED:
- if (node.bl_idname == old_class and socket.bl_idname == old_bl_idname and socket.name == old_name):
- rename_jobs.append((socket, i, new_bl_idname, new_name, multi))
- for bl_idname, in_out, socket_type, socket_name, index, use_multi_input, default_val in SOCKETS_ADDED:
- if node.bl_idname != bl_idname:
- continue
- if in_out == 'INPUT' and node.inputs.get(socket_name) is None:
- print(f"INFO: adding socket \"{socket_name}\" of type {socket_type} to node {node.name} of type {node.bl_idname}.")
- s = node.inputs.new(socket_type, socket_name, use_multi_input=use_multi_input)
- try:
- s.default_value = default_val
- except AttributeError:
- pass # the socket is read-only
- node.inputs.move(len(node.inputs)-1, index)
- socket_map = None
- if rename_jobs:
- socket_maps = get_socket_maps(node)
- for socket, socket_index, new_bl_idname, new_name, multi in rename_jobs:
- old_id = socket.identifier
- print (f"Renaming socket {socket.identifier} to {new_name} in node {node.name}")
- if socket.is_output:
- index = 1
- in_out = "OUTPUT"
- node.outputs.remove(socket)
- s = node.outputs.new(new_bl_idname, new_name, identifier=new_name, use_multi_input=multi)
- node.outputs.move(len(node.outputs)-1, socket_index)
- socket_map = socket_maps[1]
- else:
- index = 0
- in_out = "INPUT"
- node.inputs.remove(socket)
- s = node.inputs.new(new_bl_idname, new_name, identifier=new_name, use_multi_input=multi)
- node.inputs.move(len(node.inputs)-1, socket_index)
- socket_map = socket_maps[0]
- socket_map[new_name] = socket_map[old_id]
- if new_name != old_id: del socket_map[old_id] # sometimes rename just changes the socket type or multi
- do_relink(node, s, socket_map)
- except Exception as e:
- prRed(f"Error updating version in node: {node.id_data.name}::{node.name}; see error:")
- print(e)
- def version_upgrade_bone_0_12_0_from_older(*args, **kwargs):
- # we need to check if it has an array collection input and a color input
- # then we need to solve each task
- node = kwargs['node']
- live_updates = node.id_data.do_live_update
- node.id_data.do_live_update = False
- current_major_version = node.id_data.mantis_version[0]
- current_minor_version = node.id_data.mantis_version[1]
- if current_major_version > 0: # major version must be 0
- return
- if current_minor_version >= 12: # minor version must be 11 or less
- return
- # sub version doesn't matter since any subversion of 11 should trigger this task
- collection_input_is_array = False
- try:
- collection_input_is_array = node.inputs['Bone Collection'].is_multi_input
- except KeyError: # I suppose this happens in very, very old trees
- pass # but it is extremely unlikely
- toggle_updating = []
- was_updating = {}
- try:
- if not collection_input_is_array: # it must be made into an array!
- prPurple(f"Updating \"Bone Collection\" Socket in {node.name}")
- from .utilities.utilities import get_socket_maps
- socket_maps = get_socket_maps(node)
- socket_map = socket_maps[0]
- for i, socket in enumerate(node.inputs):
- if socket.name == 'Bone Collection': break
- # Always guard socket removal in case of connection to e.g. schema
- for socket_name, links in socket_map.items():
- if isinstance(links, list):
- for link in links:
- if hasattr(link, 'node') and hasattr(link.node, 'is_updating'):
- toggle_updating.append(link.node)
- was_updating[link.node.name] = link.node.is_updating
- link.node.is_updating = True
- node.inputs.remove(socket)
- s = node.inputs.new('BoneCollectionSocket', 'Bone Collection',
- identifier='Bone Collection', use_multi_input=True)
- node.inputs.move(len(node.inputs)-1, i)
- do_relink(node, s, socket_map, in_out='INPUT')
- if node.inputs.get('Color') is None:
- prPurple(f"Adding \"Color\" Socket to {node.name}")
- s = node.inputs.new('ColorSetSocket', 'Color',)
- node.inputs.move(len(node.inputs)-1, 22)
- except Exception as e:
- prRed(f"Error updating version in node: {node.id_data.name}::{node.name}; see error:")
- print(e)
- finally:
- # Now we have to clean up by removing the unneeded sockets and repositioning.
- for other_node in toggle_updating:
- other_node.is_updating = was_updating[other_node.name]
- node.id_data.do_live_update = live_updates
- def up_0_12_1_add_inherit_color(*args, **kwargs):
- # add an inherit color input.
- node = kwargs['node']
- current_major_version = node.id_data.mantis_version[0]
- current_minor_version = node.id_data.mantis_version[1]
- current_sub_version = node.id_data.mantis_version[2]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version > 12: return# minor version must be 12 or less
- if current_minor_version == 12 and current_sub_version > 9: return # sub version must be 8 or less
- # I am having it do 8 or less because there was a bug in this function prior to 9
- # sub version doesn't matter since any subversion of 11 should trigger this task
- prPurple(f"Adding \"Inherit Color\" socket to {node.name}")
- try:
- inh_color = node.inputs.get('Inherit Color')
- if inh_color and inh_color.bl_idname != 'BooleanSocket':
- node.inputs.remove(inh_color)
- inh_color = None
- if inh_color is None:
- s = node.inputs.new('BooleanSocket', 'Inherit Color',)
- node.inputs.move(len(node.inputs)-1, 23)
- s.default_value=True
- except Exception as e:
- prRed(f"Error updating version in node: {node.id_data.name}::{node.name}; see error:")
- print(e)
- def up_0_12_13_add_widget_scale(*args, **kwargs):
- node = kwargs['node']
- current_major_version = node.id_data.mantis_version[0]
- current_minor_version = node.id_data.mantis_version[1]
- current_sub_version = node.id_data.mantis_version[2]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version > 12: return# minor version must be 12 or less
- if current_minor_version == 12 and current_sub_version > 12: return
- # sub version must be 12 or less
- prPurple(f"Adding \"Scale\" socket to {node.name}")
- try:
- scale = node.inputs.get('Scale')
- if scale is None:
- s = node.inputs.new('VectorScaleSocket', 'Scale',)
- s.default_value=[1.0,1.0,1.0]
- node.inputs.move(len(node.inputs)-1, 1)
- except Exception as e:
- prRed(f"Error updating version in node: {node.id_data.name}::{node.name}; see error:")
- print(e)
- def up_0_12_25_replace_floor_offset_type(*args, **kwargs):
- node = kwargs['node']
- current_major_version = node.id_data.mantis_version[0]
- current_minor_version = node.id_data.mantis_version[1]
- current_sub_version = node.id_data.mantis_version[2]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version > 12: return# minor version must be 12 or less
- if current_minor_version == 12 and current_sub_version > 24: return
- socket_maps = get_socket_maps(node)
- prPurple(f"Fixing \"Offset\" socket in {node.name}")
- try:
- offset = node.inputs["Offset"]
- node.inputs.remove(offset)
- s = node.inputs.new('FloatSocket', 'Offset',)
- node.inputs.move(len(node.inputs)-1, 2)
- do_relink(node, s, socket_maps[0])
- except Exception as e:
- prRed(f"Error updating version in node: {node.id_data.name}::{node.name}; see error:")
- print(e)
- def get_absolute_location(node): # using this for version compatibility
- location = node.location.copy() # FUTURE: deprecate old blenders and use absolute_location
- while(node.parent):
- node = node.parent
- location+= node.location
- return location
- def up_0_13_0_new_custom_prop_node(*args, **kwargs):
- tree, node = kwargs['node_tree'], kwargs['node']
- current_major_version = tree.mantis_version[0]
- if current_major_version > 0: return# major version must be 0
- current_minor_version = tree.mantis_version[1]
- if current_minor_version >= 13: return# minor version must be 12 or less
- remove_me, prop_nodes = [], []
- from .xForm_nodes_ui import xFormBoneNode
- socket_map_in, socket_map_out = get_socket_maps(node)
- if isinstance(node, xFormBoneNode):
- if node.inputs.get('Custom Properties'):
- return # already done here
- for custom_input in reversed(list(node.inputs)):
- if 'Parameter' not in custom_input.bl_idname:
- continue
- custom_prop_node = tree.nodes.new('UtilityCustomProperty')
- prop_type = None
- if custom_input.bl_idname == 'ParameterBoolSocket':
- prop_type = 'BOOL'
- custom_prop_node.inputs['Default (Bool)'].default_value = getattr(custom_input, "default_value")
- elif custom_input.bl_idname == 'ParameterIntSocket':
- prop_type = 'INT'
- custom_prop_node.inputs['Default (Int)'].default_value = int( getattr(custom_input, "default_value") )
- custom_prop_node.inputs['Min (Int)'].default_value = int( getattr(custom_input, "min") )
- custom_prop_node.inputs['Max (Int)'].default_value = int( getattr(custom_input, "max") )
- custom_prop_node.inputs['Soft Min (Int)'].default_value = int( getattr(custom_input, "soft_min") )
- custom_prop_node.inputs['Soft Max (Int)'].default_value = int( getattr(custom_input, "soft_max") )
- elif custom_input.bl_idname == 'ParameterFloatSocket':
- prop_type = 'FLOAT'
- custom_prop_node.inputs['Default (Float)'].default_value = getattr(custom_input, "default_value")
- custom_prop_node.inputs['Min (Float)'].default_value = getattr(custom_input, "min")
- custom_prop_node.inputs['Max (Float)'].default_value = getattr(custom_input, "max")
- custom_prop_node.inputs['Soft Min (Float)'].default_value = getattr(custom_input, "soft_min")
- custom_prop_node.inputs['Soft Max (Float)'].default_value = getattr(custom_input, "soft_max")
- elif custom_input.bl_idname == 'ParameterVectorSocket':
- prop_type = 'VECTOR'
- custom_prop_node.inputs['Default (Vector)'].default_value = getattr(custom_input, "default_value")
- try:
- custom_prop_node.inputs['Min (Float)'].default_value = getattr(custom_input, "min")
- custom_prop_node.inputs['Max (Float)'].default_value = getattr(custom_input, "max")
- custom_prop_node.inputs['Soft Min (Float)'].default_value = getattr(custom_input, "soft_min")
- custom_prop_node.inputs['Soft Max (Float)'].default_value = getattr(custom_input, "soft_max")
- except AttributeError: # I don't know if I just never implemented these or if it is version specific
- pass # anyways this isn't critical and should not trigger even a warning
- elif custom_input.bl_idname == 'ParameterStringSocket':
- prop_type = 'STRING'
- custom_prop_node.inputs['Default (String)'].default_value = getattr(custom_input, "default_value")
- custom_prop_node.inputs['Name'].default_value = custom_input.name
- custom_prop_node.inputs['Type'].default_value = prop_type
- prop_nodes.append(custom_prop_node)
- remove_me.append(custom_input)
- # now we need to relink things, because the custom property socket could have had an
- # input supplying the default value
- relink_value = socket_map_in.get(custom_input.identifier, None)
- if isinstance(relink_value, list): # this indicates it is a list of links
- # CRITICALLY, we need to force display update before doing this.
- custom_prop_node.display_update({}, None) # parsed_tree and context, not needed
- input_socket = None
- match prop_type:
- case 'BOOL':
- input_socket = "Default (Bool)"
- case 'INT':
- input_socket = "Default (Int)"
- case 'FLOAT':
- input_socket = "Default (Float)"
- case 'VECTOR':
- input_socket = "Default (Vector)"
- case 'STRING':
- input_socket = "Default (String)"
- case _: # Should never never happen
- raise RuntimeError("Unexpected Code Path Reached, this is a bug.")
- do_relink(custom_prop_node, custom_prop_node.inputs[input_socket],
- {input_socket:relink_value})
- while remove_me:
- custom_input = remove_me.pop()
- node.inputs.remove(custom_input)
- new_input = node.inputs.new("CustomPropSocket", "Custom Properties", use_multi_input=True)
- from mathutils import Vector
- for i, prop_node in enumerate(prop_nodes):
- tree.links.new(input=prop_node.outputs[0], output=new_input)
- prop_node.location = get_absolute_location(node)
- prop_node.location = prop_node.location - Vector((180, -260*i))
- prop_node.select = False # it is annoying to select them all by default
- else: # just need to add the socket.
- if node.inputs.get('Custom Properties'):
- return # already done here
- new_input = node.inputs.new("CustomPropSocket", "Custom Properties", use_multi_input=True)
- def schema_enable_custom_interface_types(*args, **kwargs):
- tree = kwargs['tree']
- current_major_version = tree.mantis_version[0]
- current_minor_version = tree.mantis_version[1]
- current_sub_version = tree.mantis_version[2]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version >= 13: return# minor version must be 12 or less
- # we need to set the new interface values on the schema interface stuff
- prGreen(f"Updating Schema tree {tree.name} to support new, improved UI!")
- tree.do_live_update = False
- for n in tree.nodes:
- if hasattr(n, "is_updating"):
- n.is_updating = True
- try:
- for item in tree.interface.items_tree:
- if item.item_type == 'PANEL':
- continue
- parent_name = 'Constant'
- if item.parent:
- parent_name=item.parent.name
- if hasattr(item, "is_array"):
- # if is_array exists we're in the custom interface class
- # so we'll assume the other attributes exist
- if parent_name == 'Array':
- item.is_array = True
- if parent_name == 'Connection':
- item.is_array = False
- item.is_connection=True
- item.connected_to=item.name
- # since heretofore it has been a requirement that the names match
- except Exception as e:
- prRed(f"Error updating version in tree: {tree.name}; see error:")
- print(e)
- finally:
- for n in tree.nodes:
- if hasattr(n, "is_updating"):
- n.is_updating = False
- tree.do_live_update = True
- def update_fcurve_and_armature_node_to_multi_socket(*args, **kwargs):
- from .base_definitions import SchemaUINode
- node = kwargs['node']
- live_updates = node.id_data.do_live_update
- node.id_data.do_live_update = False
- # First we have to get the socket maps and re-init the sockets
- convert_keys = {'UtilityFCurve' : [ 'Keyframe', ],
- 'LinkArmature' : [ 'Target', 'Weight', ], }
- # first test if we need to do the versioning
- if (socket := node.inputs.get(convert_keys[node.bl_idname][0]+'s')):
- if socket.is_multi_input: return
- else: # this will never happen, doesn't hurt to handle it
- node.inputs.remove(socket) # must be an array
- my_convert_keys = convert_keys[node.bl_idname]
- sockets_in, _sockets_out = get_socket_maps(node,)
- # NOTE IMPORTANT BUG INFO
- # I was using node.inputs.clear() here before unguarded...
- # this caused connected Schema nodes to update and mutate the socket map
- # which, in turn, connected the new socket to the wildcard and extended the schema
- # resulting in trees that fail to run. This was particularly bad because it was
- # so hard to debug (due to spooky action at a distance mutation)
- # So we have to mark the connected nodes as "updating" before we modify the tree.
- # TODO: should I just mark all nodes as updating during versioning?
- toggle_updating = []
- was_updating = {}
- for socket_name, links in sockets_in.items():
- if isinstance(links, list):
- for link in links:
- if hasattr(link, 'node') and hasattr(link.node, 'is_updating'):
- toggle_updating.append(link.node)
- was_updating[link.node.name] = link.node.is_updating
- link.node.is_updating = True
- socket_templates_original = node.socket_templates
- node.inputs.clear() # this is VERY DANGEROUS without the above
- add_me_sockets = [st for st in node.socket_templates if st.is_input == True]
- node.init_sockets(add_me_sockets)
- node.socket_templates = socket_templates_original
- try:
- new_sockets_in = {}
- for convert_key in my_convert_keys:
- for socket_name, links in sockets_in.items():
- if links is None: continue
- if convert_key+'.' in socket_name:
- if new_sockets_in.get(convert_key+'s'):
- # has to be in this order to come back alright.
- # assuming, that is, that the keys are sorted. they should be.
- new_sockets_in[convert_key+'s'] = sockets_in[socket_name] + new_sockets_in[convert_key+'s']
- else:
- new_sockets_in[convert_key+'s'] = sockets_in[socket_name]
- if new_sockets_in:
- do_relink(node, node.inputs[convert_key+'s'], new_sockets_in, in_out="INPUT",)
- for socket_name, links in sockets_in.items():
- proceed = True
- for convert_key in my_convert_keys:
- if convert_key in socket_name:
- proceed = False
- if proceed:
- do_relink(node, node.inputs[socket_name], sockets_in, in_out='INPUT')
- finally:
- # Now we have to clean up by removing the unneeded sockets and repositioning.
- for other_node in toggle_updating:
- other_node.is_updating = was_updating[other_node.name]
- node.id_data.do_live_update = live_updates
- # These BBone Scale-In, Scale-Out properties had the wrong defaults
- # now that they are implemented properly,
- # since they were not implemented before, we'll do all of them at once.
- # Normally it is wrong to set things directly like this, but they didn't
- # do anything before. Oh well.
- def fix_bbone_default_scale_in_and_out(*args, **kwargs):
- tree = kwargs['tree']
- current_major_version = tree.mantis_version[0]
- current_minor_version = tree.mantis_version[1]
- current_sub_version = tree.mantis_version[2]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version > 13: return# minor version must be 12 or less
- if current_minor_version == 13 and current_sub_version >= 5: return# sub version must be 4 or less
- prPurple(f"Fixing BBone Settings for {tree.name}")
- live_updates = tree.do_live_update
- tree.do_live_update = False
- bones = []
- for node in tree.nodes:
- if hasattr(node, 'is_updating'):
- node.is_updating = True
- if node.bl_idname == 'xFormBoneNode':
- bones.append(node)
- try:
- for bone_node in bones:
- bone_node.inputs['BBone Scale-In'].default_value = (1,1,1)
- bone_node.inputs['BBone Scale-Out'].default_value = (1,1,1)
- finally:
- for node in tree.nodes:
- if hasattr(node, 'is_updating'):
- node.is_updating = False
- tree.do_live_update = live_updates
- # New display features, Display Type, new Custom Object gizmo/pivot stuff
- def add_new_display_features_v0_13_5(*args, **kwargs):
- tree = kwargs['tree']
- current_major_version = tree.mantis_version[0]
- current_minor_version = tree.mantis_version[1]
- current_sub_version = tree.mantis_version[2]
- print(tree.mantis_version[:])
- if current_major_version > 0:return# major version must be 0
- if current_minor_version > 13: return# minor version must be 12 or less
- if current_minor_version == 13 and current_sub_version >= 5: return# sub version must be 4 or less
- prPurple(f"Adding new Display Features to {tree.name}")
- live_updates = tree.do_live_update
- tree.do_live_update = False
- live_updates = tree.do_live_update
- bones = []
- armatures = []
- for node in tree.nodes:
- if hasattr(node, 'is_updating'):
- node.is_updating = True
- if node.bl_idname == 'xFormBoneNode':
- bones.append(node)
- if node.bl_idname == 'xFormArmatureNode':
- armatures.append(node)
- try:
- for bone_node in bones:
- # we'll just try this...
- from .xForm_socket_templates import (BoneDisplayType,
- CustomObjectWireWidth,
- UseTransformAtCustomShape,
- UseTransformAroundCustomShape,
- xFormBoneSockets)
- input_templates = ( BoneDisplayType,
- CustomObjectWireWidth,
- UseTransformAroundCustomShape,
- UseTransformAtCustomShape, )
- bone_node.init_sockets(input_templates)
- bone_node.socket_templates = xFormBoneSockets
- for i, inp in enumerate(bone_node.inputs):
- if inp.name == 'Custom Object xForm Override':
- # As confusing as this is, it is the least terrible way to do this
- # We add the sockets to the end, then move them from the end to the right place
- bone_node.inputs.move(len(bone_node.inputs)-1, i+1)
- bone_node.inputs.move(len(bone_node.inputs)-1, i+2)
- bone_node.inputs.move(len(bone_node.inputs)-1, i+3)
- bone_node.inputs.move(len(bone_node.inputs)-1, i+4)
- break
-
- for armature_node in armatures:
- # we'll just try this...
- from .xForm_socket_templates import (ArmatureDisplayType,
- xFormArmatureSockets)
- input_templates = ( ArmatureDisplayType, )
- armature_node.init_sockets(input_templates)
- armature_node.socket_templates = xFormArmatureSockets
- for i, inp in enumerate(armature_node.inputs):
- if inp.name == 'Relationship':
- armature_node.inputs.move(len(armature_node.inputs)-1, i+1)
- break
- finally:
- for node in tree.nodes:
- if hasattr(node, 'is_updating'):
- node.is_updating = False
- tree.do_live_update = live_updates
- def up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix(*args, **kwargs):
- node = kwargs['node']
- if 'Mode' in node.inputs:
- return # done already
- tree = node.id_data
- current_major_version = tree.mantis_version[0]
- current_minor_version = tree.mantis_version[1]
- current_sub_version = tree.mantis_version[2]
- if current_major_version > 0: return# major version must be 0
- if current_minor_version >= 13: return# minor version must be 12 or less
- if current_minor_version == 13 and current_sub_version >= 5: return# sub version must be 4 or less
- live_updates = tree.do_live_update
- tree.do_live_update = False
- for other_node in tree.nodes:
- if hasattr(other_node, 'is_updating'):
- other_node.is_updating = True
- try:
- socket_templates = node.socket_templates
- if node.bl_idname == 'UtilityMatrixFromCurve':
- from .misc_nodes_socket_templates import (MatrixFromCurveMode,
- MatrixFromCurveFactor,
- MatrixFromCurveTailFactor, )
- input_templates = ( MatrixFromCurveMode, MatrixFromCurveFactor,
- MatrixFromCurveTailFactor, )
- node.init_sockets(input_templates)
- node.inputs.move(len(node.inputs)-3, 0) # move Mode to first place
- elif node.bl_idname == 'UtilityMatrixCompose':
- from .misc_nodes_socket_templates import (ComposeMatrixBoneLength,
- MatrixComposeMode,
- ComposeMatrixRotation,)
- input_templates = ( ComposeMatrixBoneLength, MatrixComposeMode,
- ComposeMatrixRotation,)
- node.init_sockets(input_templates)
- node.inputs.move(len(node.inputs)-1, 0) # These go in the top, so make em in order
- node.inputs.move(len(node.inputs)-1, 0) # and move 'em one at a time in reverse order
- node.socket_templates = socket_templates
- finally:
- for other_node in tree.nodes:
- if hasattr(other_node, 'is_updating'):
- other_node.is_updating = False
- tree.do_live_update = live_updates
- # versioning tasks that involve Blender versions rather than Mantis versions:
- error_description_4_5_0_LTS = 'There is a bug in Blender 4.5.0 LTS, that is why these sockets are blue.'\
- ' This will be fixed in future Blender versions.'
- def cleanup_4_5_0_LTS_interface_workaround(*args, **kwargs):
- # this is a function for cleaning up the workaround up above
- tree = kwargs['tree']
- if bpy_version == (4,5,0): return
- if not hasattr(tree, "interface_helper"): return
- import json
- try:
- interface_helper = json.loads(tree.interface_helper)
- except:
- return # this should mean it was never a problem to begin with.
- prPurple(f"Restoring Tree Interface for {tree.name}.")
- for interface_item in tree.interface.items_tree:
- if interface_item.item_type == 'PANEL': continue
- # now we need to restore the socket types, which are in the interface helper
- # keep the interface stuff around, I'll use it for marking arrays in the future
- int_info = interface_helper[interface_item.identifier]
- socket_type = int_info['bl_socket_idname']
- interface_item.socket_type = socket_type
- if interface_item.description == error_description_4_5_0_LTS:
- interface_item.description = ''
- versioning_tasks = [
- # node bl_idname task required keyword arguments
- (['ALL'], version_upgrade_very_old, ['node_tree', 'node'],),
- (['xFormBoneNode'], version_upgrade_bone_0_12_0_from_older, ['node'],),
- (['xFormBoneNode'], up_0_12_1_add_inherit_color, ['node'],),
- (['MantisTree', 'SchemaTree'], cleanup_4_5_0_LTS_interface_workaround, ['tree']),
- (['InputWidget'], up_0_12_13_add_widget_scale, ['node']),
- (['LinkFloor'], up_0_12_25_replace_floor_offset_type, ['node']),
- (['XFORM'], up_0_13_0_new_custom_prop_node, ['node', 'node_tree']),
- (['SchemaTree'], schema_enable_custom_interface_types, ['tree']),
- (['UtilityFCurve', 'LinkArmature'],
- update_fcurve_and_armature_node_to_multi_socket, ['node']),
- (['MantisTree', 'SchemaTree'], fix_bbone_default_scale_in_and_out, ['tree']),
- (['MantisTree', 'SchemaTree'], add_new_display_features_v0_13_5, ['tree']),
- (['UtilityMatrixFromCurve', 'UtilityMatrixCompose'],
- up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix,
- ['node',], ),
- ]
- # WORKAROUNDS for bugs should go here:
- # 4.5.0 LTS valid socket types bug:
- def workaround_4_5_0_interface_update(tree, name, in_out, sock_type, parent_name, do_parent=False):
- # TODO: dedupe this code from i_o.py
- prRed("There is a bug in Blender 4.5.0 regarding node-group interface sockets. Working around it.")
- sock = tree.interface.new_socket(name=name, in_out=in_out, socket_type="NodeSocketGeometry")
- import json
- interface_helper = {} # initialize it if it is empty
- if tree.interface_helper: # may be empty, check here
- interface_helper = json.loads(tree.interface_helper)
- error_message = error_description_4_5_0_LTS
- interface_helper[sock.identifier] = {
- 'name' : sock.name,
- 'identifier' : sock.identifier,
- 'in_out' : sock.in_out,
- 'socket_type' : sock_type,
- 'bl_socket_idname' : sock_type,
- 'mantis_socket_category' : parent_name,
- 'description' : error_message,
- }
- sock.description = error_message # this tells the user why the socket looks weird.
- tree.interface_helper = json.dumps(interface_helper)
- if do_parent and (parent := tree.interface.items_tree.get(parent_name)):
- tree.interface.move_to_parent(
- sock,
- parent,
- 0, # what to do here?
- )
- return sock
- def socket_add_workaround_for_4_5_0_LTS(item, socket_collection, multi):
- import json
- tree = item.id_data
- interface_helper = json.loads(tree.interface_helper)
- socket_info = interface_helper.get(item.identifier)
- if not socket_info: raise RuntimeError(f"There has been an error adding the socket {item.name}")
- s = socket_collection.new(
- type=socket_info['bl_socket_idname'],
- name=item.name, # in case the user has changed it
- identifier=item.identifier,
- use_multi_input=multi, )
- return s
|