|  | @@ -1,5 +1,5 @@
 | 
	
		
			
				|  |  |  from .node_container_common import *
 | 
	
		
			
				|  |  | -from bpy.types import Bone
 | 
	
		
			
				|  |  | +from bpy.types import Bone, NodeTree
 | 
	
		
			
				|  |  |  from .base_definitions import MantisNode, GraphError, MantisSocketTemplate, FLOAT_EPSILON
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def TellClasses():
 | 
	
	
		
			
				|  | @@ -32,9 +32,55 @@ def TellClasses():
 | 
	
		
			
				|  |  |               LinkDrivenParameter,
 | 
	
		
			
				|  |  |              ]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +# Socket Templates we will reuse:
 | 
	
		
			
				|  |  | +# inputs:
 | 
	
		
			
				|  |  | +InputRelationshipTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Input Relationship", is_input=True,  bl_idname='RelationshipSocket', )
 | 
	
		
			
				|  |  | +TargetTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Target", is_input=True,  bl_idname='xFormSocket', )
 | 
	
		
			
				|  |  | +Head_Tail_Template : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Head/Tail", is_input=True,  bl_idname='FloatFactorSocket',
 | 
	
		
			
				|  |  | +    default_value=1.0, blender_property='head_tail' )
 | 
	
		
			
				|  |  | +UseBBoneTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="UseBBone", is_input=True,  bl_idname='BooleanSocket',
 | 
	
		
			
				|  |  | +    default_value=False, blender_property='use_bbone_shape' )
 | 
	
		
			
				|  |  | +AxesTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Axes", is_input=True,  bl_idname='BooleanThreeTupleSocket',
 | 
	
		
			
				|  |  | +    default_value=[True, True, True], blender_property=['use_x', 'use_y', 'use_z'])
 | 
	
		
			
				|  |  | +AxesInvertTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Invert", is_input=True,  bl_idname='BooleanThreeTupleSocket',
 | 
	
		
			
				|  |  | +    default_value=[False, False, False], blender_property=['invert_x', 'invert_y', 'invert_z'])
 | 
	
		
			
				|  |  | +TargetSpaceTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Target Space", is_input=True,  bl_idname='TransformSpaceSocket',
 | 
	
		
			
				|  |  | +    default_value="WORLD", blender_property='target_space' )
 | 
	
		
			
				|  |  | +OwnerSpaceTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Owner Space", is_input=True,  bl_idname='TransformSpaceSocket',
 | 
	
		
			
				|  |  | +    default_value="WORLD", blender_property='owner_space' )
 | 
	
		
			
				|  |  | +InfluenceTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Influence", is_input=True,  bl_idname='FloatFactorSocket',
 | 
	
		
			
				|  |  | +    default_value=1.0, blender_property='influence')
 | 
	
		
			
				|  |  | +EnableTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Enable", is_input=True,  bl_idname='EnableSocket',
 | 
	
		
			
				|  |  | +    default_value=True, blender_property='mute')
 | 
	
		
			
				|  |  | +OffsetTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Offset", bl_idname='BooleanSocket', is_input=True,
 | 
	
		
			
				|  |  | +    default_value=False, blender_property='use_offset')
 | 
	
		
			
				|  |  | +# outputs:
 | 
	
		
			
				|  |  | +OutputRelationshipTemplate : MantisSocketTemplate = MantisSocketTemplate(
 | 
	
		
			
				|  |  | +    name="Output Relationship", is_input=False,  bl_idname='RelationshipSocket', )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +# set the name if it is available, otherwise just use the constraint's nice name
 | 
	
		
			
				|  |  | +set_constraint_name = lambda nc : nc.evaluate_input("Name") if nc.evaluate_input("Name") else nc.__class__.__name__
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class MantisLinkNode(MantisNode):
 | 
	
		
			
				|  |  | -    def __init__(self, signature, base_tree):
 | 
	
		
			
				|  |  | -        super().__init__(signature, base_tree)
 | 
	
		
			
				|  |  | +    def __init__(self, signature : tuple,
 | 
	
		
			
				|  |  | +                 base_tree : NodeTree,
 | 
	
		
			
				|  |  | +                 socket_templates : list[MantisSocketTemplate]=[]):
 | 
	
		
			
				|  |  | +        super().__init__(signature, base_tree, socket_templates)
 | 
	
		
			
				|  |  |          self.node_type = 'LINK'
 | 
	
		
			
				|  |  |          self.prepared = True
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -48,10 +94,14 @@ class MantisLinkNode(MantisNode):
 | 
	
		
			
				|  |  |              
 | 
	
		
			
				|  |  |          else:
 | 
	
		
			
				|  |  |              return super().evaluate_input(input_name)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -# set the name if it is available, otherwise just use the constraint's nice name
 | 
	
		
			
				|  |  | -set_constraint_name = lambda nc : nc.evaluate_input("Name") if nc.evaluate_input("Name") else nc.__class__.__name__
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    def gen_property_socket_map(self) -> dict:
 | 
	
		
			
				|  |  | +        props_sockets = super().gen_property_socket_map()
 | 
	
		
			
				|  |  | +        if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | +            del props_sockets['owner_space']
 | 
	
		
			
				|  |  | +        if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | +            del props_sockets['target_space']
 | 
	
		
			
				|  |  | +        return props_sockets
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #*#-------------------------------#++#-------------------------------#*#
 | 
	
		
			
				|  |  |  # L I N K   N O D E S
 | 
	
	
		
			
				|  | @@ -76,9 +126,7 @@ class LinkInherit(MantisLinkNode):
 | 
	
		
			
				|  |  |      '''A node representing inheritance'''
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      def __init__(self, signature, base_tree):
 | 
	
		
			
				|  |  | -        super().__init__(signature, base_tree)
 | 
	
		
			
				|  |  | -        self.inputs.init_sockets(LinkInheritSockets)
 | 
	
		
			
				|  |  | -        self.outputs.init_sockets(LinkInheritSockets)
 | 
	
		
			
				|  |  | +        super().__init__(signature, base_tree, LinkInheritSockets)
 | 
	
		
			
				|  |  |          self.init_parameters()
 | 
	
		
			
				|  |  |          self.set_traverse([('Parent', 'Inheritance')])
 | 
	
		
			
				|  |  |          self.executed = True
 | 
	
	
		
			
				|  | @@ -90,36 +138,32 @@ class LinkInherit(MantisLinkNode):
 | 
	
		
			
				|  |  |              if (node.node_type == 'XFORM'):
 | 
	
		
			
				|  |  |                  return node
 | 
	
		
			
				|  |  |          raise GraphError("%s is not connected to a downstream xForm" % self)
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +LinkCopyLocationSockets = [
 | 
	
		
			
				|  |  | +    InputRelationshipTemplate,
 | 
	
		
			
				|  |  | +    Head_Tail_Template,
 | 
	
		
			
				|  |  | +    UseBBoneTemplate,
 | 
	
		
			
				|  |  | +    AxesTemplate,
 | 
	
		
			
				|  |  | +    AxesInvertTemplate,
 | 
	
		
			
				|  |  | +    TargetSpaceTemplate,
 | 
	
		
			
				|  |  | +    OwnerSpaceTemplate,
 | 
	
		
			
				|  |  | +    OffsetTemplate,
 | 
	
		
			
				|  |  | +    InfluenceTemplate,
 | 
	
		
			
				|  |  | +    TargetTemplate,
 | 
	
		
			
				|  |  | +    EnableTemplate,
 | 
	
		
			
				|  |  | +    OutputRelationshipTemplate,
 | 
	
		
			
				|  |  | +]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class LinkCopyLocation(MantisLinkNode):
 | 
	
		
			
				|  |  |      '''A node representing Copy Location'''
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    def __init__(self, signature, base_tree):
 | 
	
		
			
				|  |  | -        super().__init__(signature, base_tree)
 | 
	
		
			
				|  |  | -        inputs = [
 | 
	
		
			
				|  |  | -            "Input Relationship",
 | 
	
		
			
				|  |  | -            "Head/Tail",
 | 
	
		
			
				|  |  | -            "UseBBone",
 | 
	
		
			
				|  |  | -            "Axes",
 | 
	
		
			
				|  |  | -            "Invert",
 | 
	
		
			
				|  |  | -            "Target Space",
 | 
	
		
			
				|  |  | -            "Owner Space",
 | 
	
		
			
				|  |  | -            "Offset",
 | 
	
		
			
				|  |  | -            "Influence",
 | 
	
		
			
				|  |  | -            "Target",
 | 
	
		
			
				|  |  | -            "Enable",
 | 
	
		
			
				|  |  | -        ]
 | 
	
		
			
				|  |  | +    def __init__(self, signature : tuple,
 | 
	
		
			
				|  |  | +                 base_tree : NodeTree,):
 | 
	
		
			
				|  |  | +        super().__init__(signature, base_tree, LinkCopyLocationSockets)
 | 
	
		
			
				|  |  |          additional_parameters = { "Name":None }
 | 
	
		
			
				|  |  | -        self.inputs.init_sockets(inputs)
 | 
	
		
			
				|  |  | -        self.outputs.init_sockets(["Output Relationship"])
 | 
	
		
			
				|  |  |          self.init_parameters(additional_parameters=additional_parameters)
 | 
	
		
			
				|  |  |          self.set_traverse([("Input Relationship", "Output Relationship")])
 | 
	
		
			
				|  |  |          
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  |      def GetxForm(self):
 | 
	
		
			
				|  |  |          return GetxForm(self)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -133,9 +177,7 @@ class LinkCopyLocation(MantisLinkNode):
 | 
	
		
			
				|  |  |          if constraint_name := self.evaluate_input("Name"):
 | 
	
		
			
				|  |  |              c.name = constraint_name
 | 
	
		
			
				|  |  |          self.bObject = c
 | 
	
		
			
				|  |  | -        custom_space_owner, custom_space_target = False, False
 | 
	
		
			
				|  |  |          if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | -            custom_space_owner=True
 | 
	
		
			
				|  |  |              c.owner_space='CUSTOM'
 | 
	
		
			
				|  |  |              xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
 | 
	
		
			
				|  |  |              if isinstance(xf, Bone):
 | 
	
	
		
			
				|  | @@ -143,66 +185,45 @@ class LinkCopyLocation(MantisLinkNode):
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  c.space_object=xf
 | 
	
		
			
				|  |  |          if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | -            custom_space_target=True
 | 
	
		
			
				|  |  |              c.target_space='CUSTOM'
 | 
	
		
			
				|  |  |              xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
 | 
	
		
			
				|  |  |              if isinstance(xf, Bone):
 | 
	
		
			
				|  |  |                  c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  c.space_object=xf
 | 
	
		
			
				|  |  | -        props_sockets = {
 | 
	
		
			
				|  |  | -        'use_offset'       : ("Offset", False),
 | 
	
		
			
				|  |  | -        'head_tail'       : ("Head/Tail", 0),
 | 
	
		
			
				|  |  | -        'use_bbone_shape' : ("UseBBone", False),
 | 
	
		
			
				|  |  | -        'invert_x'        : ( ("Invert", 0), False),
 | 
	
		
			
				|  |  | -        'invert_y'        : ( ("Invert", 1), False),
 | 
	
		
			
				|  |  | -        'invert_z'        : ( ("Invert", 2), False),
 | 
	
		
			
				|  |  | -        'use_x'           : ( ("Axes", 0), False),
 | 
	
		
			
				|  |  | -        'use_y'           : ( ("Axes", 1), False),
 | 
	
		
			
				|  |  | -        'use_z'           : ( ("Axes", 2), False),
 | 
	
		
			
				|  |  | -        'owner_space'     : ("Owner Space",  'WORLD'),
 | 
	
		
			
				|  |  | -        'target_space'    : ("Target Space", 'WORLD'),
 | 
	
		
			
				|  |  | -        'influence'       : ("Influence", 1),
 | 
	
		
			
				|  |  | -        'mute'            : ("Enable", True),
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if custom_space_owner: del props_sockets['owner_space']
 | 
	
		
			
				|  |  | -        if custom_space_target: del props_sockets['target_space']
 | 
	
		
			
				|  |  | -        #
 | 
	
		
			
				|  |  | +        props_sockets = self.gen_property_socket_map()
 | 
	
		
			
				|  |  |          evaluate_sockets(self, c, props_sockets)
 | 
	
		
			
				|  |  |          self.executed = True
 | 
	
		
			
				|  |  |          
 | 
	
		
			
				|  |  |      def bFinalize(self, bContext = None):
 | 
	
		
			
				|  |  |          finish_drivers(self)
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +LinkCopyRotationSockets = [
 | 
	
		
			
				|  |  | +    InputRelationshipTemplate,
 | 
	
		
			
				|  |  | +    MantisSocketTemplate(name='RotationOrder', bl_idname='RotationOrderSocket', is_input=True,
 | 
	
		
			
				|  |  | +                         default_value='AUTO', blender_property='euler_order'),
 | 
	
		
			
				|  |  | +    MantisSocketTemplate(name='Rotation Mix',  bl_idname='EnumRotationMix', is_input=True,
 | 
	
		
			
				|  |  | +                         default_value='REPLACE', blender_property='mix_mode'),
 | 
	
		
			
				|  |  | +    AxesTemplate,
 | 
	
		
			
				|  |  | +    AxesInvertTemplate,
 | 
	
		
			
				|  |  | +    TargetSpaceTemplate,
 | 
	
		
			
				|  |  | +    OwnerSpaceTemplate,
 | 
	
		
			
				|  |  | +    InfluenceTemplate,
 | 
	
		
			
				|  |  | +    TargetTemplate,
 | 
	
		
			
				|  |  | +    EnableTemplate,
 | 
	
		
			
				|  |  | +    OutputRelationshipTemplate,
 | 
	
		
			
				|  |  | +]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class LinkCopyRotation(MantisLinkNode):
 | 
	
		
			
				|  |  |      '''A node representing Copy Rotation'''
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      def __init__(self, signature, base_tree):
 | 
	
		
			
				|  |  | -        super().__init__(signature, base_tree)
 | 
	
		
			
				|  |  | -        inputs = [
 | 
	
		
			
				|  |  | -            "Input Relationship",
 | 
	
		
			
				|  |  | -            "RotationOrder",
 | 
	
		
			
				|  |  | -            "Rotation Mix",
 | 
	
		
			
				|  |  | -            "Axes",
 | 
	
		
			
				|  |  | -            "Invert",
 | 
	
		
			
				|  |  | -            "Target Space",
 | 
	
		
			
				|  |  | -            "Owner Space",
 | 
	
		
			
				|  |  | -            "Influence",
 | 
	
		
			
				|  |  | -            "Target",
 | 
	
		
			
				|  |  | -            "Enable",
 | 
	
		
			
				|  |  | -        ]
 | 
	
		
			
				|  |  | +        super().__init__(signature, base_tree, LinkCopyRotationSockets)
 | 
	
		
			
				|  |  |          additional_parameters = { "Name":None }
 | 
	
		
			
				|  |  | -        self.inputs.init_sockets(inputs)
 | 
	
		
			
				|  |  | -        self.outputs.init_sockets(["Output Relationship"])
 | 
	
		
			
				|  |  |          self.init_parameters(additional_parameters=additional_parameters)
 | 
	
		
			
				|  |  |          self.set_traverse([("Input Relationship", "Output Relationship")])
 | 
	
		
			
				|  |  |          
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  |      def GetxForm(self):
 | 
	
		
			
				|  |  |          return GetxForm(self)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -225,9 +246,7 @@ class LinkCopyRotation(MantisLinkNode):
 | 
	
		
			
				|  |  |          if constraint_name := self.evaluate_input("Name"):
 | 
	
		
			
				|  |  |              c.name = constraint_name
 | 
	
		
			
				|  |  |          self.bObject = c
 | 
	
		
			
				|  |  | -        custom_space_owner, custom_space_target = False, False
 | 
	
		
			
				|  |  |          if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | -            custom_space_owner=True
 | 
	
		
			
				|  |  |              c.owner_space='CUSTOM'
 | 
	
		
			
				|  |  |              xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
 | 
	
		
			
				|  |  |              if isinstance(xf, Bone):
 | 
	
	
		
			
				|  | @@ -235,58 +254,41 @@ class LinkCopyRotation(MantisLinkNode):
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  c.space_object=xf
 | 
	
		
			
				|  |  |          if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | -            custom_space_target=True
 | 
	
		
			
				|  |  |              c.target_space='CUSTOM'
 | 
	
		
			
				|  |  |              xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
 | 
	
		
			
				|  |  |              if isinstance(xf, Bone):
 | 
	
		
			
				|  |  |                  c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  c.space_object=xf
 | 
	
		
			
				|  |  | -        props_sockets = {
 | 
	
		
			
				|  |  | -        'euler_order' : ("RotationOrder", 'AUTO'),
 | 
	
		
			
				|  |  | -        'mix_mode'       : ("Rotation Mix", 'REPLACE'),
 | 
	
		
			
				|  |  | -        'invert_x'       : ( ("Invert", 0), False),
 | 
	
		
			
				|  |  | -        'invert_y'       : ( ("Invert", 1), False),
 | 
	
		
			
				|  |  | -        'invert_z'       : ( ("Invert", 2), False),
 | 
	
		
			
				|  |  | -        'use_x'          : ( ("Axes", 0), False),
 | 
	
		
			
				|  |  | -        'use_y'          : ( ("Axes", 1), False),
 | 
	
		
			
				|  |  | -        'use_z'          : ( ("Axes", 2), False),
 | 
	
		
			
				|  |  | -        'owner_space'    : ("Owner Space",  'WORLD'),
 | 
	
		
			
				|  |  | -        'target_space'   : ("Target Space", 'WORLD'),
 | 
	
		
			
				|  |  | -        'influence'      : ("Influence", 1),
 | 
	
		
			
				|  |  | -        'mute'            : ("Enable", True),
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if custom_space_owner: del props_sockets['owner_space']
 | 
	
		
			
				|  |  | -        if custom_space_target: del props_sockets['target_space']
 | 
	
		
			
				|  |  | -        #
 | 
	
		
			
				|  |  | +        props_sockets = self.gen_property_socket_map()
 | 
	
		
			
				|  |  |          evaluate_sockets(self, c, props_sockets)
 | 
	
		
			
				|  |  |          self.executed = True
 | 
	
		
			
				|  |  |              
 | 
	
		
			
				|  |  |      def bFinalize(self, bContext = None):
 | 
	
		
			
				|  |  |          finish_drivers(self)
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | +LinkCopyScaleSockets = [
 | 
	
		
			
				|  |  | +    InputRelationshipTemplate,
 | 
	
		
			
				|  |  | +    OffsetTemplate,
 | 
	
		
			
				|  |  | +    MantisSocketTemplate(name='Average', bl_idname = 'BooleanSocket', is_input=True,
 | 
	
		
			
				|  |  | +                         default_value=False, blender_property='use_make_uniform'),
 | 
	
		
			
				|  |  | +    MantisSocketTemplate(name='Additive', bl_idname = 'BooleanSocket', is_input=True,
 | 
	
		
			
				|  |  | +                         default_value=False, blender_property='use_add'),
 | 
	
		
			
				|  |  | +    AxesTemplate,
 | 
	
		
			
				|  |  | +    TargetSpaceTemplate,
 | 
	
		
			
				|  |  | +    OwnerSpaceTemplate,
 | 
	
		
			
				|  |  | +    InfluenceTemplate,
 | 
	
		
			
				|  |  | +    TargetTemplate,
 | 
	
		
			
				|  |  | +    EnableTemplate,
 | 
	
		
			
				|  |  | +    OutputRelationshipTemplate,
 | 
	
		
			
				|  |  | +]
 | 
	
		
			
				|  |  |          
 | 
	
		
			
				|  |  |  class LinkCopyScale(MantisLinkNode):
 | 
	
		
			
				|  |  |      '''A node representing Copy Scale'''
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      def __init__(self, signature, base_tree):
 | 
	
		
			
				|  |  | -        super().__init__(signature, base_tree)
 | 
	
		
			
				|  |  | -        inputs = [
 | 
	
		
			
				|  |  | -            "Input Relationship",
 | 
	
		
			
				|  |  | -            "Offset",
 | 
	
		
			
				|  |  | -            "Average",
 | 
	
		
			
				|  |  | -            "Additive",
 | 
	
		
			
				|  |  | -            "Axes",
 | 
	
		
			
				|  |  | -            "Target Space",
 | 
	
		
			
				|  |  | -            "Owner Space",
 | 
	
		
			
				|  |  | -            "Influence",
 | 
	
		
			
				|  |  | -            "Target",
 | 
	
		
			
				|  |  | -            "Enable",
 | 
	
		
			
				|  |  | -        ]
 | 
	
		
			
				|  |  | +        super().__init__(signature, base_tree, LinkCopyScaleSockets)
 | 
	
		
			
				|  |  |          additional_parameters = { "Name":None }
 | 
	
		
			
				|  |  | -        self.inputs.init_sockets(inputs)
 | 
	
		
			
				|  |  | -        self.outputs.init_sockets(["Output Relationship"])
 | 
	
		
			
				|  |  |          self.init_parameters(additional_parameters=additional_parameters)
 | 
	
		
			
				|  |  |          self.set_traverse([("Input Relationship", "Output Relationship")])
 | 
	
		
			
				|  |  |      
 | 
	
	
		
			
				|  | @@ -303,9 +305,7 @@ class LinkCopyScale(MantisLinkNode):
 | 
	
		
			
				|  |  |          if constraint_name := self.evaluate_input("Name"):
 | 
	
		
			
				|  |  |              c.name = constraint_name
 | 
	
		
			
				|  |  |          self.bObject = c
 | 
	
		
			
				|  |  | -        custom_space_owner, custom_space_target = False, False
 | 
	
		
			
				|  |  |          if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | -            custom_space_owner=True
 | 
	
		
			
				|  |  |              c.owner_space='CUSTOM'
 | 
	
		
			
				|  |  |              xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
 | 
	
		
			
				|  |  |              if isinstance(xf, Bone):
 | 
	
	
		
			
				|  | @@ -313,27 +313,13 @@ class LinkCopyScale(MantisLinkNode):
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  c.space_object=xf
 | 
	
		
			
				|  |  |          if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
 | 
	
		
			
				|  |  | -            custom_space_target=True
 | 
	
		
			
				|  |  |              c.target_space='CUSTOM'
 | 
	
		
			
				|  |  |              xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
 | 
	
		
			
				|  |  |              if isinstance(xf, Bone):
 | 
	
		
			
				|  |  |                  c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  c.space_object=xf
 | 
	
		
			
				|  |  | -        props_sockets = {
 | 
	
		
			
				|  |  | -        'use_offset'       : ("Offset", False),
 | 
	
		
			
				|  |  | -        'use_make_uniform' : ("Average", False),
 | 
	
		
			
				|  |  | -        'owner_space'      : ("Owner Space",  'WORLD'),
 | 
	
		
			
				|  |  | -        'target_space'     : ("Target Space", 'WORLD'),
 | 
	
		
			
				|  |  | -        'use_x'            : ( ("Axes", 0), False),
 | 
	
		
			
				|  |  | -        'use_y'            : ( ("Axes", 1), False),
 | 
	
		
			
				|  |  | -        'use_z'            : ( ("Axes", 2), False),
 | 
	
		
			
				|  |  | -        'influence'        : ("Influence", 1),
 | 
	
		
			
				|  |  | -        'mute'             : ("Enable", True),
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if custom_space_owner: del props_sockets['owner_space']
 | 
	
		
			
				|  |  | -        if custom_space_target: del props_sockets['target_space']
 | 
	
		
			
				|  |  | -        #
 | 
	
		
			
				|  |  | +        props_sockets = self.gen_property_socket_map()
 | 
	
		
			
				|  |  |          evaluate_sockets(self, c, props_sockets)   
 | 
	
		
			
				|  |  |          self.executed = True 
 | 
	
		
			
				|  |  |              
 |