Jelajahi Sumber

Update All Nodes to use Socket Templates

This commit ports all nodes (except dynamic nodes) to use socket templates.
As far as I can tell it works as a drop-in replacement without any bugs.
I'll need to test it a little more thoroughly to be 1000% sure.

My Stegosaurus test rig generates without errors, at least!
Joseph Brandenburg 1 bulan lalu
induk
melakukan
117e9a2ff8

+ 4 - 0
__init__.py

@@ -51,6 +51,10 @@ if environ.get("ENABLEVIS"):
     from .visualize import MantisVisualizeNode, MantisVisualizeOutput, MantisVisualizeTree
     classes.extend([MantisVisualizeTree, MantisVisualizeNode, MantisVisualizeOutput, ])
 
+DOERROR = False
+if environ.get("DOERROR"):
+    DOERROR = True
+
 import nodeitems_utils
 from nodeitems_utils import NodeCategory, NodeItem
 

+ 10 - 3
base_definitions.py

@@ -211,7 +211,6 @@ class SchemaTree(NodeTree):
             fix_reroute_colors(self)
 
 
-
 #TODO: do a better job explaining how MantisNode and MantisUINode relate.
 
 class MantisUINode:
@@ -220,6 +219,10 @@ class MantisUINode:
         MantisUINode objects will spawn one or more MantisNode objects when the graph is evaluated.
         The MantisNode objects will pull the data from the UI node and use it to generate the graph.
     """
+    # blender stuff, I'll need to split this into a mixin class later
+    bl_icon = 'NODE'
+    initialized : bpy.props.BoolProperty(default = False)
+    #
     mantis_node_library=''
     mantis_node_class_name=''
     mantis_class=None
@@ -268,8 +271,12 @@ class MantisUINode:
             )
             socket.hide= template.hide
             if template.category:
+                from . import DOERROR
                 # a custom property for the UI functions to use.
-                socket.category = template.category
+                if hasattr(socket, "category"):
+                    socket.category = template.category
+                elif DOERROR:
+                    print (f"WARN: socket type {socket.bl_idname} has no category attribute")
             if template.default_value is not None:
                 socket.default_value = template.default_value
                 # this can throw a TypeError - it is the caller's
@@ -302,7 +309,6 @@ class DeformerNode(MantisUINode):
     def poll(cls, ntree):
         return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
 
-
 def poll_node_tree(self, object):
     forbid = []
     context = bpy.context
@@ -1120,6 +1126,7 @@ class MantisNodeSocketCollection(dict):
             if isinstance(socket, str):
                 self[socket] = NodeSocket(is_input=self.is_input, name=socket, node=self.node)
             elif isinstance(socket, MantisSocketTemplate):
+                if socket.ui_only == True: continue # used in UI but not in generation
                 if socket.is_input != self.is_input: continue
                 self[socket.name] = NodeSocket(is_input=self.is_input, name=socket.name, node=self.node)
             else:

+ 2 - 35
deformer_nodes.py

@@ -81,31 +81,12 @@ class DeformerArmature(MantisDeformerNode):
     '''A node representing an armature deformer'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-            "Input Relationship",
-            "Armature Object",
-            "Blend Vertex Group",
-            "Invert Vertex Group",
-            "Preserve Volume",
-            "Use Multi Modifier",
-            "Use Envelopes",
-            "Use Vertex Groups",
-            "Skinning Method",
-            "Deformer",
-            "Copy Skin Weights From"
-        ]
-        outputs = [
-          "Deformer"
-        ]
-        self.outputs.init_sockets(outputs)
-        self.inputs.init_sockets(inputs)
+        super().__init__(signature, base_tree, DeformArmatureSockets)
         self.init_parameters(additional_parameters={"Name":None})
         self.set_traverse([("Deformer", "Deformer")])
         self.node_type = "LINK"
         self.prepared = True
 
-
     def GetxForm(self, socket="Deformer"):
         if socket == "Deformer":
             return super().GetxForm()
@@ -445,22 +426,8 @@ class DeformerHook(MantisDeformerNode):
 class DeformerMorphTarget(MantisDeformerNode):
     '''A node representing an armature deformer'''
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-            "Relative to",
-            "Object",
-            "Deformer",
-            "Vertex Group",
-        ]
-        outputs = [
-          "Deformer",
-          "Morph Target",
-        ]
-        # now set up the traverse target...
-        self.outputs.init_sockets(outputs)
-        self.inputs.init_sockets(inputs)
+        super().__init__(signature, base_tree, MorphTargetSockets)
         self.init_parameters(additional_parameters={"Name":None})
-        self.set_traverse([("Deformer", "Deformer")])
         self.node_type = "LINK"
         self.prepared = True
     

+ 11 - 36
deformer_nodes_ui.py

@@ -11,13 +11,13 @@ from .utilities import (prRed, prGreen, prPurple, prWhite, prOrange,
 def TellClasses():
     return [
              DeformerArmatureNode,
-             DeformerHook,
+             DeformerHook, #
              DeformerMorphTargetDeform,
              DeformerMorphTarget,
-             DeformerSurfaceDeform,
-             DeformerMeshDeform,
-             DeformerLatticeDeform,
-             DeformerSmoothCorrectiveDeform,
+             DeformerSurfaceDeform, # 
+             DeformerMeshDeform, #
+             DeformerLatticeDeform, #
+             DeformerSmoothCorrectiveDeform, #
            ]
 
 
@@ -37,25 +37,7 @@ class DeformerArmatureNode(Node, DeformerNode):
     mantis_node_class_name=bl_idname
 
     def init(self, context):
-        # self.inputs.new ("RelationshipSocket", "Input Relationship")
-        self.inputs.new('xFormSocket', "Armature Object")
-        self.inputs.new('StringSocket', "Blend Vertex Group")
-        # self.inputs.new('StringSocket', "Preserve Volume Vertex Group") #TODO figure out the right UX for automatic dual-quat blending
-        self.inputs.new('BooleanSocket', "Invert Vertex Group")
-        
-        self.inputs.new('BooleanSocket', "Preserve Volume")
-        # TODO: make the above controlled by a vertex group instead.
-        self.inputs.new('BooleanSocket', "Use Multi Modifier")# might just set this auto
-        self.inputs.new('BooleanSocket', "Use Envelopes")
-        self.inputs.new('BooleanSocket', "Use Vertex Groups")
-        
-        self.inputs.new("DeformerSocket", "Deformer")
-
-        s = self.inputs.new("xFormSocket", "Copy Skin Weights From")
-        s.hide = True
-        self.inputs.new("EnumSkinning", "Skinning Method")
-        
-        self.outputs.new('DeformerSocket', "Deformer")
+        self.init_sockets(DeformArmatureSockets)
         self.initialized = True
     
     def display_update(self, parsed_tree, context):
@@ -138,13 +120,9 @@ class DeformerMorphTargetDeform(Node, DeformerNode):
 
     def init(self, context):
         self.id_data.do_live_update = False
-        self.inputs.new('DeformerSocket', 'Deformer', )
-        self.inputs.new('BooleanSocket', 'Use Shape Key', )
-        s = self.inputs.new('BooleanSocket', 'Use Offset', )
-        s.default_value = True
-        self.inputs.new('WildcardSocket', '', identifier='__extend__')
-        self.outputs.new('DeformerSocket', "Deformer")
+        self.init_sockets(MorphTargetDeformSockets)
         self.update_morph_deformer()
+        self.id_data.do_live_update = True
 
     def update_morph_deformer(self, force=False):
         self.initialized = False
@@ -197,7 +175,8 @@ class DeformerMorphTargetDeform(Node, DeformerNode):
                 self.inputs["Use Shape Key"].default_value = False
 
 
-# TODO: there is no reason for this to be a separate node!
+# NOTE: in the past I considered jamming this into the above node
+#       as a dynamic node thing. Worth considering later, but it's fine.
 class DeformerMorphTarget(Node, DeformerNode):
     '''A node representing a single Morph Target'''
     bl_idname = 'DeformerMorphTarget'
@@ -208,11 +187,7 @@ class DeformerMorphTarget(Node, DeformerNode):
     mantis_node_class_name=bl_idname
 
     def init(self, context):
-        self.inputs.new('xFormSocket', "Relative to")
-        self.inputs.new('xFormSocket', "Object")
-        self.inputs.new('StringSocket', "Vertex Group")
-        self.outputs.new('MorphTargetSocket', "Morph Target")
-
+        self.init_sockets(MorphTargetSockets)
         self.initialized = True
 
 

+ 58 - 25
deformer_socket_templates.py

@@ -1,59 +1,92 @@
-from .mantis_dataclasses import MantisSocketTemplate as SockTemplate
+from .mantis_dataclasses import MantisSocketTemplate as ST
 from dataclasses import replace
 
 from .misc_nodes_socket_templates import SplineIndexTemplate
 
 
-Target = SockTemplate(name="Target", bl_idname='xFormSocket',
+Target = ST(name="Target", bl_idname='xFormSocket',
         is_input=True,
     )
 
+DeformArmatureSockets = [ 
+    ArmatureObject := replace(Target, name="Armature Object"),
+    BlendVertexGroup := ST(name="Blend Vertex Group", bl_idname="StringSocket", is_input=True),
+    InvertBlendVertexGroup := ST(name="Invert Vertex Group", bl_idname="BooleanSocket", is_input=True),
+    # QuatBlendVertexGroup := ST(name="Preserve Volume Vertex Group", bl_idname="StringSocket", is_input=True)
+    # ^ TODO figure out the right UX for automatic dual-quat blending
+    PreserveVolume := ST(name="Preserve Volume", bl_idname="BooleanSocket", is_input=True),
+    # ^ TODO: make the above controlled by a vertex group instead.
+    UseMultiModifier := ST(name="Use Multi Modifier", bl_idname="BooleanSocket", is_input=True), # might just set this auto
+    UseEnvelopes := ST(name="Use Envelopes", bl_idname="BooleanSocket", is_input=True, default_value=False),
+    UseVertexGroups := ST(name="Use Vertex Groups", bl_idname="BooleanSocket", is_input=True, default_value=True),
+    DeformerInput := ST(name="Deformer", bl_idname="DeformerSocket", is_input=True),
+    CopySkinWeightsFrom := ST(name="Copy Skin Weights From", bl_idname="xFormSocket", is_input=True, hide=True),
+    SkinningMethod := ST(name="Skinning Method", bl_idname="EnumSkinning", is_input=True),
+    DeformerOutput := ST(name="Deformer", bl_idname="DeformerSocket", is_input=False),
+
+]
+
 HookSockets= [
-    DeformerInput := SockTemplate(name="Deformer", bl_idname='DeformerSocket',
-        is_input=True,),
+    DeformerInput,
     HookTarget := replace(Target, name="Hook Target"),
     replace(SplineIndexTemplate,),
-    CurvePointIndex := SockTemplate(name="Point Index", bl_idname='UnsignedIntSocket',
+    CurvePointIndex := ST(name="Point Index", bl_idname='UnsignedIntSocket',
         is_input=True, default_value=0 ),
-    Influence := SockTemplate(name="Influence", bl_idname='FloatFactorSocket',
+    Influence := ST(name="Influence", bl_idname='FloatFactorSocket',
         is_input=True, default_value=1.0, blender_property='strength'),
-    HookDrivesRadius := SockTemplate(name="Affect Curve Radius", bl_idname='BooleanSocket',
+    HookDrivesRadius := ST(name="Affect Curve Radius", bl_idname='BooleanSocket',
         is_input=True, default_value=True,),
-    HookAutoBezier := SockTemplate(name="Auto-Bezier", bl_idname='BooleanSocket',
+    HookAutoBezier := ST(name="Auto-Bezier", bl_idname='BooleanSocket',
         is_input=True, default_value=True,),
-    DeformerOutput := SockTemplate(name="Deformer", bl_idname='DeformerSocket',
-        is_input=False,), 
+    DeformerOutput, 
+]
+
+#NOTE that this guy is a dynamic node so this is only its initial state.
+MorphTargetDeformSockets = [
+    DeformerInput,
+    UseShapeKey := ST(name="Use Shape Key", bl_idname="BooleanSocket", is_input=True),
+    UseOffset := ST(name="Use Offset", bl_idname="BooleanSocket", is_input=True, default_value=True),
+    Extend := ST(name="", bl_idname="WildcardSocket", is_input=True, identifier="__extend__", ui_only=True),
+    DeformerOutput,
+]
+
+
+MorphTargetSockets = [
+    RelativeTo := ST(name="Relative to", bl_idname="xFormSocket", is_input=True),
+    Object := ST(name="Object", bl_idname="xFormSocket", is_input=True),
+    VertexGroup := ST(name="Vertex Group", bl_idname="StringSocket", is_input=True),
+    MorphTarget := ST(name="Morph Target", bl_idname="MorphTargetSocket", is_input=False),
 ]
 
 SurfaceDeformSockets= [
     DeformerInput,
     SurfaceDeformTarget := replace(Target, name="Target",),
-    Falloff := SockTemplate(name="Falloff", bl_idname='FloatSocket',
+    Falloff := ST(name="Falloff", bl_idname='FloatSocket',
         is_input=True, default_value=4.0, blender_property="falloff", ),
     Strength := replace(Influence, name="Strength", bl_idname='FloatSocket',
         is_input=True, default_value=1.0, blender_property='strength'),
-    SparseBind := SockTemplate(name="Sparse Bind", bl_idname='BooleanSocket',
+    SparseBind := ST(name="Sparse Bind", bl_idname='BooleanSocket',
         is_input=True, default_value=False, blender_property="use_sparse_bind"),
-    VertexGroup := SockTemplate(name="Vertex Group", bl_idname='StringSocket',
+    VertexGroup := ST(name="Vertex Group", bl_idname='StringSocket',
         is_input=True, default_value="", blender_property="vertex_group"),
-    InvertVertexGroup := SockTemplate(name="Invert Vertex Group", bl_idname='BooleanSocket',
+    InvertVertexGroup := ST(name="Invert Vertex Group", bl_idname='BooleanSocket',
         is_input=True, default_value=False, blender_property="invert_vertex_group"),
-    EnableViewportTemplate := SockTemplate(
+    EnableViewportTemplate := ST(
         name="Enable in Viewport", is_input=True,  bl_idname='EnableSocket',
         default_value=True, blender_property='show_viewport'),
-    EnableRenderTemplate := SockTemplate(
+    EnableRenderTemplate := ST(
         name="Enable in Render", is_input=True,  bl_idname='BooleanSocket',
         default_value=True, blender_property='show_render'),
     DeformerOutput,
 ]
 
 MeshDeformSockets= [
-    DeformerInput := SockTemplate(name="Deformer", bl_idname='DeformerSocket',
+    DeformerInput := ST(name="Deformer", bl_idname='DeformerSocket',
         is_input=True,),
     MeshDeformTarget := replace(Target, name="Object",),
-    MeshDeformPrecision := SockTemplate(name="Precision", bl_idname='UnsignedIntSocket',
+    MeshDeformPrecision := ST(name="Precision", bl_idname='UnsignedIntSocket',
         is_input=True, default_value=4, blender_property="precision"),
-    DynamicBind := SockTemplate(name="Dynamic Bind", bl_idname='BooleanSocket',
+    DynamicBind := ST(name="Dynamic Bind", bl_idname='BooleanSocket',
         is_input=True, default_value=False, blender_property="use_dynamic_bind"),
     VertexGroup,
     InvertVertexGroup,
@@ -63,7 +96,7 @@ MeshDeformSockets= [
 ]
 
 LatticeDeformSockets = [
-    DeformerInput := SockTemplate(name="Deformer", bl_idname='DeformerSocket',
+    DeformerInput := ST(name="Deformer", bl_idname='DeformerSocket',
         is_input=True,),
     LatticeDeformTarget := replace(Target, name="Object",),
     Strength := replace(Strength, bl_idname='FloatFactorSocket',),
@@ -78,15 +111,15 @@ SmoothDeformSockets = [
     DeformerInput,
     Factor := replace(Influence, name="Factor", bl_idname='FloatSocket',
                         default_value=0.5, blender_property='factor'),
-    iterations := SockTemplate(name='Iterations', bl_idname="UnsignedIntSocket",
+    iterations := ST(name='Iterations', bl_idname="UnsignedIntSocket",
             is_input=True, default_value=4, blender_property='iterations'),
-    SmoothType :=SockTemplate(name="Smoothing Type", bl_idname="EnumCorrectiveSmoothTypeSocket", 
+    SmoothType :=ST(name="Smoothing Type", bl_idname="EnumCorrectiveSmoothTypeSocket", 
               is_input=True, blender_property="smooth_type" ),
-    PinBoundary := SockTemplate(name="Pin Boundary", bl_idname="BooleanSocket",
+    PinBoundary := ST(name="Pin Boundary", bl_idname="BooleanSocket",
             is_input=True, default_value=False, blender_property="use_pin_boundary"),
-    OnlySmooth := SockTemplate(name="Use Corrective Smooth", bl_idname="InvertedBooleanSocket",
+    OnlySmooth := ST(name="Use Corrective Smooth", bl_idname="InvertedBooleanSocket",
             is_input=True, default_value=True, blender_property="use_only_smooth"),
-    DeltaMushScale := SockTemplate(name="Corrective Smooth Scale", bl_idname="FloatSocket",
+    DeltaMushScale := ST(name="Corrective Smooth Scale", bl_idname="FloatSocket",
             is_input=True, default_value=1.0, blender_property="scale", category='corrective_smooth' ),
     VertexGroup,
     InvertVertexGroup,

+ 2 - 0
mantis_dataclasses.py

@@ -14,7 +14,9 @@ class MantisSocketTemplate():
     is_input         : bool = field(default=False)
     hide             : bool = field(default=False)
     use_multi_input  : bool = field(default=False)
+    ui_only          : bool = field(default=False)
     default_value    : Any = field(default=None)
+    # TODO: add versioning fields for Mantis, Blender version min/max
 
 @dataclass
 class xForm_info():

+ 8 - 42
math_nodes.py

@@ -1,5 +1,6 @@
 from .node_common import *
-from .base_definitions import MantisNode, NodeSocket
+from .base_definitions import MantisNode
+from .math_nodes_socket_templates import *
 
 def TellClasses():
     return [
@@ -53,19 +54,8 @@ class MathStaticInt(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Operation",
-          "Int A",
-          "Int B",
-        ]
-        outputs = [
-          "Result Int",
-        ]
-        additional_parameters = {}
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
-        self.init_parameters(additional_parameters=additional_parameters)
+        super().__init__(signature, base_tree, StaticIntSockets)
+        self.init_parameters()
         self.node_type = "UTILITY"
 
     def bPrepare(self, bContext = None,):
@@ -78,19 +68,8 @@ class MathStaticFloat(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Operation",
-          "Float A",
-          "Float B",
-        ]
-        outputs = [
-          "Result Float",
-        ]
-        additional_parameters = {}
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
-        self.init_parameters(additional_parameters=additional_parameters)
+        super().__init__(signature, base_tree, StaticFloatSockets)
+        self.init_parameters()
         self.node_type = "UTILITY"
 
     def bPrepare(self, bContext = None,):
@@ -103,21 +82,8 @@ class MathStaticVector(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Operation",
-          "Vector A",
-          "Vector B",
-          "Scalar A",
-        ]
-        outputs = [
-          "Result Vector",
-          "Result Float",
-        ]
-        additional_parameters = {}
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
-        self.init_parameters(additional_parameters=additional_parameters)
+        super().__init__(signature, base_tree, StaticVectorSockets)
+        self.init_parameters()
         self.node_type = "UTILITY"
 
     def bPrepare(self, bContext = None,):

+ 26 - 0
math_nodes_socket_templates.py

@@ -0,0 +1,26 @@
+from .base_definitions import MantisSocketTemplate as ST
+from dataclasses import replace
+
+
+StaticIntSockets = [
+    Operation := ST(name="Operation", bl_idname="MathFloatOperation", is_input=True),
+    IntA := ST(name="Int A", bl_idname="IntSocket", is_input=True),
+    IntB := ST(name="Int B", bl_idname="IntSocket", is_input=True),
+    ResultInt := ST(name="Result Int", bl_idname="IntSocket", is_input=False),
+]
+
+StaticFloatSockets = [
+    Operation,
+    FloatA := ST(name="Float A", bl_idname="FloatSocket", is_input=True),
+    FloatB := ST(name="Float B", bl_idname="FloatSocket", is_input=True),
+    ResultFloat := ST(name="Result Float", bl_idname="FloatSocket", is_input=False),
+]
+
+StaticVectorSockets = [
+    Operation := ST(name="Operation", bl_idname="MathVectorOperation", is_input=True),
+    VectorA := ST(name="Vector A", bl_idname="VectorSocket", is_input=True),
+    VectorB := ST(name="Vector B", bl_idname="VectorSocket", is_input=True),
+    ScalarA := ST(name="Scalar A", bl_idname="FloatSocket", is_input=True, hide=True),
+    ResultVector := ST(name="Result Vector", bl_idname="VectorSocket", is_input=False),
+    ResultFloat := ST(name="Result Float", bl_idname="FloatSocket", is_input=False, hide=True),
+]

+ 5 - 21
math_nodes_ui.py

@@ -7,17 +7,16 @@ from .utilities import (prRed, prGreen, prPurple, prWhite,
                               wrapOrange,)
 from .base_definitions import get_signature_from_edited_tree
 
+from .math_nodes_socket_templates import *
 
 def TellClasses():
     return [
      MathStaticInt,
      MathStaticFloatNode,
      MathStaticVectorNode,
-        ]
+    ]
 
 
-        
-
 class MathStaticInt(Node, MantisUINode):
     """A node that performs mathematical operations on float numbers as a preprocess step before generating the rig."""
     bl_idname = "MathStaticInt"
@@ -28,12 +27,8 @@ class MathStaticInt(Node, MantisUINode):
 
 
     def init(self, context):
-        self.inputs.new("MathFloatOperation", "Operation")
-        self.inputs.new("IntSocket", "Int A")
-        self.inputs.new("IntSocket", "Int B")
-        self.outputs.new("IntSocket", "Result Int")
+        self.init_sockets(StaticIntSockets)
         self.initialized = True
-    
 
     def display_update(self, parsed_tree, context):
         if context.space_data:
@@ -45,7 +40,6 @@ class MathStaticInt(Node, MantisUINode):
             else:
                 self.inputs["Int B"].hide = False
 
-# do... make the operations now
 class MathStaticFloatNode(Node, MantisUINode):
     """A node that performs mathematical operations on float numbers as a preprocess step before generating the rig."""
     bl_idname = "MathStaticFloat"
@@ -54,14 +48,9 @@ class MathStaticFloatNode(Node, MantisUINode):
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
 
-
     def init(self, context):
-        self.inputs.new("MathFloatOperation", "Operation")
-        self.inputs.new("FloatSocket", "Float A")
-        self.inputs.new("FloatSocket", "Float B")
-        self.outputs.new("FloatSocket", "Result Float")
+        self.init_sockets(StaticFloatSockets)
         self.initialized = True
-    
 
     def display_update(self, parsed_tree, context):
         if context.space_data:
@@ -82,12 +71,7 @@ class MathStaticVectorNode(Node, MantisUINode):
     mantis_node_class_name=bl_idname
     
     def init(self, context):
-        self.inputs.new("MathVectorOperation", "Operation")
-        self.inputs.new("VectorSocket", "Vector A")
-        self.inputs.new("VectorSocket", "Vector B")
-        h = self.inputs.new("FloatSocket", "Scalar A"); h.hide=True
-        self.outputs.new("VectorSocket", "Result Vector")
-        h = self.outputs.new("FloatSocket", "Result Float"); h.hide=True
+        self.init_sockets(StaticVectorSockets)
         self.initialized = True
 
     def display_update(self, parsed_tree, context):

+ 62 - 396
misc_nodes.py

@@ -214,83 +214,62 @@ class InputFloat(SimpleInputNode):
     '''A node representing float input'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = ["Float Input"]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputFloatSockets)
         self.init_parameters()
 
 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)
+        super().__init__(signature, base_tree, InputIntSockets)
         self.init_parameters()
 
 class InputVector(SimpleInputNode):
     '''A node representing vector input'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = [""]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputVectorSockets)
         self.init_parameters()
 
 class InputBoolean(SimpleInputNode):
     '''A node representing boolean input'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = [""]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputBooleanSockets)
         self.init_parameters()
 
 class InputBooleanThreeTuple(SimpleInputNode):
     '''A node representing a tuple of three booleans'''
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = [""]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputBooleanThreeTupleSockets)
         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)
+        super().__init__(signature, base_tree, InputRotationOrderSockets)
         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)
+        super().__init__(signature, base_tree, InputTransformSpaceSockets)
         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 = [""]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputStringSockets)
         self.init_parameters()
 
 class InputMatrix(SimpleInputNode):
     '''A node representing axis-angle quaternion input'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs  = ["Matrix",]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputMatrixSockets)
         self.init_parameters()
 
 class InputThemeBoneColorSets(SimpleInputNode):
@@ -554,16 +533,7 @@ class UtilityMatricesFromCurve(MantisNode):
 
 class UtilityNumberOfCurveSegments(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Curve"            ,
-          "Spline Index"     ,
-        ]
-        outputs = [
-          "Number of Segments" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, NumberOfCurveSegmentsSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -704,19 +674,7 @@ class UtilityGetNearestFactorOnCurve(MantisNode):
 
 class UtilityKDChoosePoint(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Reference Point"  ,
-          "Points"           ,
-          "Number to Find"   ,
-        ]
-        outputs = [
-          "Result Point"     ,
-          "Result Index"     ,
-          "Result Distance"  ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, KDChoosePointSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
         self.rerouted=[]
@@ -742,20 +700,7 @@ class UtilityKDChoosePoint(MantisNode):
 
 class UtilityKDChooseXForm(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Reference Point"      ,
-          "xForm Nodes"          ,
-          "Get Point Head/Tail"  ,
-          "Number to Find"       ,
-        ]
-        outputs = [
-          "Result xForm"     ,
-          "Result Index"     ,
-          "Result Distance"  ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, KDChooseXFormSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
         self.rerouted=[]
@@ -794,16 +739,7 @@ class UtilityMetaRig(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Meta-Armature" ,
-          "Meta-Bone"     ,
-        ]
-        outputs = [
-          "Matrix" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, MetaRigSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -845,19 +781,7 @@ class UtilityBoneProperties(SimpleInputNode):
     '''A node representing a bone's gettable properties'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = [
-            "matrix"        ,
-            "matrix_local"  ,
-            "matrix_basis"  ,
-            "head"          ,
-            "tail"          ,
-            "length"        ,
-            "rotation"      ,
-            "location"      ,
-            "scale"         ,
-        ]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, BonePropertiesSockets)
         self.init_parameters()
 
     def fill_parameters(self, ui_node=None):
@@ -868,21 +792,7 @@ class UtilityDriverVariable(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-            "Variable Type"   ,
-            "Property"       ,
-            "Property Index" ,
-            "Evaluation Space",
-            "Rotation Mode"   ,
-            "xForm 1"         ,
-            "xForm 2"         ,
-        ]
-        outputs = [
-          "Driver Variable",
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, DriverVariableSockets)
         self.init_parameters()
         self.node_type = "DRIVER" # MUST be run in Pose mode
         self.prepared = True
@@ -965,18 +875,11 @@ class UtilityKeyframe(MantisNode):
     '''A node representing a keyframe for a F-Curve'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Frame"   ,
-          "Value"   ,
-        ]
-        outputs = [
-          "Keyframe" ,
-        ]
+        super().__init__(signature, base_tree, KeyframeSockets)
         additional_parameters = {"Keyframe":{}}
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
         self.init_parameters( additional_parameters=additional_parameters)
+        # I think both of these are wrong.
+        # TODO: try UTILITY type and remove setup_custom_property stuff
         self.node_type = "DRIVER" # MUST be run in Pose mode
         setup_custom_property_inputs_outputs(self)
 
@@ -995,15 +898,7 @@ class UtilityFCurve(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-            "Extrapolation Mode",
-        ]
-        outputs = [
-          "fCurve",
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, FCurveSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
         setup_custom_property_inputs_outputs(self)
@@ -1040,21 +935,11 @@ class UtilityDriver(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Driver Type"   ,
-          "Expression"    ,
-          "fCurve"        ,
-        ]
-        outputs = [
-          "Driver",
-        ]
+        super().__init__(signature, base_tree, DriverSockets)
         from .drivers import MantisDriver
         additional_parameters = {
           "Driver":MantisDriver(),
         }
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
         self.init_parameters(additional_parameters=additional_parameters)
         self.node_type = "DRIVER" # MUST be run in Pose mode
         setup_custom_property_inputs_outputs(self)
@@ -1105,21 +990,11 @@ class UtilitySwitch(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = {
-          "Parameter"            ,
-          "Parameter Index"      ,
-          "Invert Switch"        ,
-        }
-        outputs = [
-          "Driver",
-        ]
+        super().__init__(signature, base_tree, SwitchSockets)
         from .drivers import MantisDriver
         additional_parameters = {
           "Driver":MantisDriver(),
         }
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
         self.init_parameters(additional_parameters=additional_parameters)
         self.node_type = "DRIVER" # MUST be run in Pose mode
         self.prepared = True
@@ -1191,17 +1066,7 @@ class UtilityCombineThreeBool(MantisNode):
     '''A node for combining three booleans into a boolean three-tuple'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "X"   ,
-          "Y"   ,
-          "Z"   ,
-        ]
-        outputs = [
-          "Three-Bool",
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, CombineThreeBoolSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1225,18 +1090,7 @@ class UtilityCombineVector(MantisNode):
     '''A node for combining three floats into a vector'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        super().__init__(signature, base_tree)
-        inputs = [
-          "X"   ,
-          "Y"   ,
-          "Z"   ,
-        ]
-        outputs = [
-          "Vector",
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, CombineVectorSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1260,17 +1114,7 @@ class UtilitySeparateVector(MantisNode):
     '''A node for separating a vector into three floats'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Vector"
-        ]
-        outputs = [
-          "X"   ,
-          "Y"   ,
-          "Z"   ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, SeparateVectorSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1284,16 +1128,7 @@ class UtilityCatStrings(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "String_1"   ,
-          "String_2"   ,
-        ]
-        outputs = [
-          "OutputString" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, CatStringsSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1393,15 +1228,7 @@ class InputExistingGeometryObject(MantisNode):
     '''A node representing an existing object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Name"  ,
-        ]
-        outputs = [
-          "Object" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputExistingGeometryObjectSockets)
         self.init_parameters()
         self.node_type = "XFORM"
 
@@ -1426,15 +1253,7 @@ class InputExistingGeometryData(MantisNode):
     '''A node representing existing object data'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Name"  ,
-        ]
-        outputs = [
-          "Geometry" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, InputExistingGeometrySockets)
         self.init_parameters()
         self.node_type = "UTILITY"
         self.prepared = True; self.executed = True
@@ -1457,6 +1276,8 @@ class InputExistingGeometryData(MantisNode):
 class UtilityDeclareCollections(MantisNode):
     '''A node to help manage bone collections'''
     def __init__(self, signature, base_tree):
+        # NOTE this one does not use socket template because it is special.
+        # The user creates all the sockets for this one.
         super().__init__(signature, base_tree)
         self.node_type = "UTILITY"
         self.prepared, self.executed = True, True
@@ -1537,15 +1358,7 @@ class UtilityCollectionHierarchy(MantisNode):
 class UtilityGeometryOfXForm(MantisNode):
     '''A node representing existing object data'''
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "xForm"  ,
-        ]
-        outputs = [
-          "Geometry" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, GeometryOfXFormSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
         self.prepared = True
@@ -1571,15 +1384,7 @@ class UtilityGeometryOfXForm(MantisNode):
 class UtilityNameOfXForm(MantisNode):
     '''A node representing existing object data'''
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "xForm"  ,
-        ]
-        outputs = [
-          "Name" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, NameOfXFormSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1596,15 +1401,7 @@ class UtilityGetBoneLength(MantisNode):
     '''A node to get the length of a bone matrix'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Bone Matrix" ,
-        ]
-        outputs = [
-          "Bone Length" ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, GetBoneLengthSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1620,16 +1417,7 @@ class UtilityPointFromBoneMatrix(MantisNode):
     '''A node representing an armature object'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Bone Matrix"   ,
-          "Head/Tail"     ,
-        ]
-        outputs = [
-          "Point"     ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, PointFromBoneMatrixSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1646,16 +1434,7 @@ class UtilitySetBoneLength(MantisNode):
     '''Sets the length of a Bone's matrix'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Bone Matrix"   ,
-          "Length"        ,
-        ]
-        outputs = [
-          "Bone Matrix"   ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, SetBoneLengthSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1675,16 +1454,7 @@ class UtilityMatrixSetLocation(MantisNode):
     '''Sets the location of a matrix'''
 
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Matrix"        ,
-          "Location"      ,
-        ]
-        outputs = [
-          "Matrix"        ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, MatrixSetLocationSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1701,15 +1471,7 @@ class UtilityMatrixSetLocation(MantisNode):
 class UtilityMatrixGetLocation(MantisNode):
     '''Gets the location of a matrix'''
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Matrix"        ,
-        ]
-        outputs = [
-          "Location"    ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, MatrixGetLocationSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1722,16 +1484,8 @@ class UtilityMatrixGetLocation(MantisNode):
 class UtilityMatrixFromXForm(MantisNode):
     """Returns the matrix of the given xForm node."""
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "xForm"        ,
-        ]
-        outputs = [
-          "Matrix"       ,
-        ]
+        super().__init__(signature, base_tree, MatrixFromXFormSockets)
         self.node_type = "UTILITY"
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
         self.init_parameters()
 
     def GetxForm(self):
@@ -1757,17 +1511,7 @@ class UtilityMatrixFromXForm(MantisNode):
 class UtilityAxesFromMatrix(MantisNode):
     """Returns the axes of the given matrix."""
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Matrix"       ,
-        ]
-        outputs = [
-          "X Axis"      ,
-          "Y Axis"      ,
-          "Z Axis"      ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, AxesFromMatrixSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1782,15 +1526,7 @@ class UtilityAxesFromMatrix(MantisNode):
 
 class UtilityBoneMatrixHeadTailFlip(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Bone Matrix"     ,
-        ]
-        outputs = [
-          "Bone Matrix"     ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, BoneMatrixHeadTailFlipSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1811,16 +1547,7 @@ class UtilityBoneMatrixHeadTailFlip(MantisNode):
 
 class UtilityMatrixTransform(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Matrix 1"   ,
-          "Matrix 2"   ,
-        ]
-        outputs = [
-          "Out Matrix"    ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, MatrixTransformSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1913,17 +1640,7 @@ class UtilityMatrixAlignRoll(MantisNode):
 
 class UtilityTransformationMatrix(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Operation"   ,
-          "Vector"      ,
-          "W"           ,
-        ]
-        outputs = [
-          "Matrix"    ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, TransformationMatrixSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -1945,22 +1662,12 @@ class UtilityTransformationMatrix(MantisNode):
 
 class UtilityIntToString(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Number"         ,
-          "Zero Padding"   ,
-        ]
-        outputs = [
-          "String"         ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, IntToStringSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
     def bPrepare(self, bContext = None,):
         number = self.evaluate_input("Number")
-
         zeroes = self.evaluate_input("Zero Padding")
         # I'm casting to int because I want to support any number, even though the node asks for int.
         self.parameters["String"] = str(int(number)).zfill(int(zeroes))
@@ -1968,17 +1675,7 @@ class UtilityIntToString(MantisNode):
 
 class UtilityArrayGet(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Index"           ,
-          "OoB Behaviour"   ,
-          "Array"           ,
-        ]
-        outputs = [
-          "Output"          ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, ArrayGetSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
         self.rerouted=[]
@@ -2006,15 +1703,7 @@ class UtilityArrayGet(MantisNode):
 
 class UtilityArrayLength(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Array"           ,
-        ]
-        outputs = [
-          "Length"          ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, UtilityArrayLengthSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -2024,16 +1713,7 @@ class UtilityArrayLength(MantisNode):
 
 class UtilitySetBoneMatrixTail(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = {
-          "Matrix"        ,
-          "Tail Location" ,
-        }
-        outputs = [
-          "Result"       ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, SetBoneMatrixTailSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -2045,26 +1725,6 @@ class UtilitySetBoneMatrixTail(MantisNode):
         self.parameters["Result"] = matrix_from_head_tail(matrix.translation, self.evaluate_input("Tail Location"))
         self.prepared = True; self.executed = True
 
-class UtilityPrint(MantisNode):
-    def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Input"         ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.init_parameters()
-        self.node_type = "UTILITY"
-
-    def bPrepare(self, bContext = None,):
-        if my_input := self.evaluate_input("Input"):
-            print("Preparation phase: ", wrapWhite(self), wrapGreen(my_input))
-        self.prepared = True
-
-    def bTransformPass(self, bContext = None,):
-        if my_input := self.evaluate_input("Input"):
-            print("Execution phase: ", wrapWhite(self), wrapGreen(my_input))
-        self.executed = True
-
 class UtilityCompare(MantisNode):
     def __init__(self, signature, base_tree):
         super().__init__(signature, base_tree, CompareSockets)
@@ -2100,17 +1760,7 @@ class UtilityCompare(MantisNode):
 
 class UtilityChoose(MantisNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-          "Condition"   ,
-          "A"           ,
-          "B"           ,
-        ]
-        outputs = [
-          "Result"      ,
-        ]
-        self.inputs.init_sockets(inputs)
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, ChooseSockets)
         self.init_parameters()
         self.node_type = "UTILITY"
 
@@ -2138,3 +1788,19 @@ class UtilityChoose(MantisNode):
             else:
                 raise GraphError(f"Choose Node {self} has incorrect types.")
         self.prepared = True; self.executed = True
+
+class UtilityPrint(MantisNode):
+    def __init__(self, signature, base_tree):
+        super().__init__(signature, base_tree, PrintSockets)
+        self.init_parameters()
+        self.node_type = "UTILITY"
+
+    def bPrepare(self, bContext = None,):
+        if my_input := self.evaluate_input("Input"):
+            print("Preparation phase: ", wrapWhite(self), wrapGreen(my_input))
+        self.prepared = True
+
+    def bTransformPass(self, bContext = None,):
+        if my_input := self.evaluate_input("Input"):
+            print("Execution phase: ", wrapWhite(self), wrapGreen(my_input))
+        self.executed = True

+ 382 - 90
misc_nodes_socket_templates.py

@@ -1,34 +1,64 @@
-from .mantis_dataclasses import MantisSocketTemplate as SockTemplate
+from .mantis_dataclasses import MantisSocketTemplate as ST
 from dataclasses import replace
 
-SplineIndexTemplate = SockTemplate(name="Spline Index",
+# reused templates
+SplineIndexTemplate = ST(name="Spline Index",
         bl_idname='UnsignedIntSocket', is_input=True, default_value=0,)
+FactorTemplate = ST(name="Factor", bl_idname='FloatFactorSocket', is_input=True,)
+MatrixOutput = ST( name="Matrix", is_input=False, bl_idname='MatrixSocket', )
+MatricesOutTemplate = replace(MatrixOutput, name='Matrices', use_multi_input=True)
+StringOutput = ST( name="String", is_input=False, bl_idname='StringSocket', )
+MatrixInput = replace(MatrixOutput, is_input=True)
+VectorOutput = ST(name="Vector", bl_idname="VectorSocket", is_input=False)
+VectorInput = replace(VectorOutput, is_input = True)
 
-InputWidgetSockets = [
-    WidgetName := SockTemplate(name='Name', is_input=True,
-        bl_idname="EnumWidgetLibrarySocket",),
-    Scale := SockTemplate(name='Scale', is_input=True,
-        bl_idname="VectorScaleSocket", default_value=(1.0, 1.0, 1.0)),
-    FlipAxes := SockTemplate(name='Flip Axes', is_input=True,
-        bl_idname="BooleanThreeTupleSocket",),
-    xFormOutput := SockTemplate(name='Widget',
-        bl_idname='xFormSocket',is_input=False),
+# input classes
+InputFloatSockets = [
+    FloatInput := ST(name='Float Input',
+        bl_idname='FloatSocket', is_input=False),
+]
+InputIntSockets = [
+    IntInput := ST(name='Integer',
+        bl_idname='IntSocket', is_input=False),
+]
+InputVectorSockets = [
+    replace(VectorOutput, name='',),
+]
+InputBooleanSockets = [
+    BoolInput := ST(name='',
+        bl_idname='BooleanSocket', is_input=False),
+]
+InputBooleanThreeTupleSockets = [
+    BoolThreeTupleInput := ST(name='',
+        bl_idname='BooleanThreeTupleSocket', is_input=False),
+]
+InputRotationOrderSockets = [
+    RotationOrderInput := ST(name='',
+        bl_idname='RotationOrderSocket', is_input=False),
+]
+InputTransformSpaceSockets = [
+    TransformSpaceInput := ST(name='',
+        bl_idname='TransformSpaceSocket', is_input=False),
+]
+InputStringSockets = [
+    StringInput := ST(name='', bl_idname='StringSocket',
+        is_input=False),
+]
+InputMatrixSockets = [
+    MatrixOutput
 ]
 
 MatrixFromCurveSockets=[
-    CurveTemplate := SockTemplate(name="Curve", bl_idname='EnumCurveSocket', 
+    CurveTemplate := ST(name="Curve", bl_idname='EnumCurveSocket', 
         is_input=True,),
     SplineIndexTemplate,
-    TotalDivisionsTemplate := SockTemplate(name="Total Divisions",
+    TotalDivisionsTemplate := ST(name="Total Divisions",
         bl_idname='UnsignedIntSocket', is_input=True, default_value=0,),
-    MatrixIndexTemplate := SockTemplate(name="Matrix Index",
+    MatrixIndexTemplate := ST(name="Matrix Index",
         bl_idname='UnsignedIntSocket', is_input=True, default_value=0,),
-    MatrixOutTemplate := SockTemplate(
-        name="Matrix", is_input=False,  bl_idname='MatrixSocket', ),
+    MatrixOutput,
 ]
 
-MatricesOutTemplate = replace(MatrixOutTemplate,
-        name='Matrices', use_multi_input=True)
 MatricesFromCurveSockets=MatrixFromCurveSockets.copy()
 MatricesFromCurveSockets[4] = MatricesOutTemplate
 MatricesFromCurveSockets.pop(3)
@@ -37,142 +67,404 @@ MatrixFromCurveSegmentSockets=[
     CurveTemplate,
     SplineIndexTemplate,
     SegmentIndexTemplate := replace(SplineIndexTemplate, name="Segment Index"),
-    MatrixOutTemplate,
+    MatrixOutput,
 ]
 
 PointFromCurveSockets=[
     CurveTemplate,
     SplineIndexTemplate,
-    FactorTemplate := SockTemplate(name="Factor", bl_idname='FloatFactorSocket', 
-        is_input=True,),
-    PointOutTemplate := SockTemplate(name="Point", bl_idname="VectorSocket",
+    FactorTemplate,
+    PointOutTemplate := ST(name="Point", bl_idname="VectorSocket",
         is_input=False, )
 ]
 
+NumberOfCurveSegmentsSockets = [
+    CurveTemplate,
+    SplineIndexTemplate,
+    NumberOfSegments := ST(name='Number of Segments',
+        bl_idname='UnsignedIntSocket', is_input=False),
+]
+
 GetCurvePointSockets=[
     CurveTemplate,
     SplineIndexTemplate,
-    IndexTemplate := SockTemplate(name="Index",
+    IndexTemplate := ST(name="Index",
         bl_idname='UnsignedIntSocket', is_input=True, default_value=0,),
-    OutputPointTemplate := SockTemplate(name="Point",
+    OutputPointTemplate := ST(name="Point",
         bl_idname='VectorSocket', is_input=False,),
-    OutputLeftHandleTemplate := SockTemplate(name="Left Handle",
+    OutputLeftHandleTemplate := ST(name="Left Handle",
         bl_idname='VectorSocket', is_input=False, hide=True),
-    OutputRightHandleTemplate := SockTemplate(name="Right Handle",
+    OutputRightHandleTemplate := ST(name="Right Handle",
         bl_idname='VectorSocket', is_input=False, hide=True),
 ]
 
 GetNearestFactorOnCurveSockets=[
     CurveTemplate,
     SplineIndexTemplate,
-    ReferencePointTemplate := SockTemplate(name="Reference Point",
+    ReferencePointTemplate := ST(name="Reference Point",
         bl_idname='VectorSocket', is_input=True,),
-    OutputFactorTemplate := SockTemplate(name="Factor",
+    OutputFactorTemplate := ST(name="Factor",
         bl_idname='FloatSocket', is_input=False,),
 ]
 
-MatrixInvertSockets=[
-    Matrix1Template := SockTemplate(
-    name="Matrix 1", is_input=True,  bl_idname='MatrixSocket', ),
-    MatrixOutTemplate,
+KDChoosePointSockets = [
+    ReferencePointTemplate,
+    PointsArray := ST(name="Points", bl_idname="VectorSocket",
+        use_multi_input=True,  is_input=True),
+    NumberToFind := ST(name='Number to Find',
+        bl_idname = "UnsignedIntSocket", default_value=1,  is_input=True),
+    ResultPoint :=ST(name='Result Point', bl_idname="VectorSocket",
+        is_input=False, ),
+    ResultIndex :=ST(name='Result Index',
+        bl_idname="UnsignedIntSocket", is_input=False, ),
+    ResultDistance :=ST(name='Result Distance',
+        bl_idname="FloatSocket", is_input=False, ),
 ]
 
-MatrixComposeSockets=[
-    XBasisVector := SockTemplate(
-    name="X Basis Vector", is_input=True,  bl_idname='VectorSocket', 
-        default_value = (1.0, 0.0, 0.0) ),
-    YBasisVector := replace(XBasisVector, name="Y Basis Vector",
-        default_value = (0.0, 1.0, 0.0) ),
-    ZBasisVector := replace(XBasisVector, name="Z Basis Vector",
-        default_value = (0.0, 0.0, 1.0) ),
-    Translation := replace(XBasisVector, name="Translation"),
-    MatrixOutTemplate,
+KDChooseXFormSockets = [
+    ReferencePointTemplate,
+    xFormsArray := ST(name="xForm Nodes", bl_idname="xFormSocket",
+        use_multi_input=True, is_input=True,),
+    GetPointHeadTail := ST(name="Get Point Head/Tail",
+        bl_idname = "FloatFactorSocket",  is_input=True,),
+    NumberToFind,
+    ResultxForm := ST(name='Result xForm', bl_idname='xFormSocket', is_input=False),
+    ResultIndex,
+    ResultDistance,
 ]
 
-MatrixAlignRollSockets=[
-    MatrixInTemplate := replace(Matrix1Template, name="Matrix"),
-    AlignVector := SockTemplate(name="Alignment Vector", is_input=True,
-       bl_idname='VectorSocket', default_value=(0.0,-1.0,0.0)),
-    MatrixOutTemplate,
+MetaRigSockets = [
+    MetaArmature := ST(name='Meta-Armature', bl_idname="EnumMetaRigSocket",
+        is_input = True, ),
+    MetaBone := ST(name='Meta-Bone', bl_idname="EnumMetaBoneSocket",
+        is_input = True, hide=True ),
+    MatrixOutput,
 ]
 
-CompareSockets = [
-    ComparisonOperation := SockTemplate( name='Comparison',
-            is_input=True, bl_idname="EnumCompareOperation",
-            default_value="EQUAL",),
-    WildcardATemplate := SockTemplate(
-        name="A", is_input=True,  bl_idname='WildcardSocket', ),
-    WildcardBTemplate := replace(WildcardATemplate, name="B"),
-    CompareOutputTemplate := SockTemplate(
-        name="Result", is_input=False, bl_idname="BooleanSocket",),
+BonePropertiesSockets = [
+    replace( StringOutput, name='matrix'),
+    replace( StringOutput, name='matrix_local'),
+    replace( StringOutput, name='matrix_basis'),
+    replace( StringOutput, name='head'),
+    replace( StringOutput, name='tail'),
+    replace( StringOutput, name='length'),
+    replace( StringOutput, name='rotation'),
+    replace( StringOutput, name='location'),
+    replace( StringOutput, name='scale'),
 ]
 
-NumberOfSplinesSockets=[
-    CurveTemplate,
-    NumberOfSplinesOut := SockTemplate(name="Number of Splines",
-        bl_idname='UnsignedIntSocket', is_input=False),
+DriverVariableSockets = [
+    VariableType := ST(name='Variable Type', bl_idname="EnumDriverVariableType", is_input=True),
+    Property := ST(name='Property', bl_idname="ParameterStringSocket", is_input=True),
+    PropertyIndex := ST(name='Property Index', bl_idname="IntSocket", is_input=True),
+    EvaluationSpace := ST(name='Evaluation Space', bl_idname="EnumDriverVariableEvaluationSpace", is_input=True,
+        hide = True,),
+    RotationMode := ST(name='Rotation Mode', bl_idname="EnumDriverRotationMode", is_input=True),
+    xForm1 := ST(name='xForm 1', bl_idname="xFormSocket", is_input=True),
+    xForm2 := ST(name='xForm 2', bl_idname="xFormSocket", is_input=True),
+    DriverVariable := ST(name='Driver Variable', bl_idname="DriverVariableSocket", is_input=False),
 ]
 
-CollectionJoinSockets = [
-    JoinCollections := SockTemplate(name='Collections', is_input=True,
-        bl_idname="BoneCollectionSocket", display_shape='SQUARE_DOT',
-        use_multi_input=True,),
-    CollectionDeclarationOutput := SockTemplate(name='Collection',
-        bl_idname="BoneCollectionSocket", is_input=False,)
+FCurveSockets = [
+    ExtrapolationMode := ST( name="Extrapolation Mode",
+        bl_idname="eFCrvExtrapolationMode", is_input=True),
+    fCurveOutput := ST(name="fCurve", bl_idname="FCurveSocket", is_input=False),
 ]
 
-CollectionHierarchySockets = [
-    ParentCollection := SockTemplate(name='Parent Collection', is_input=True,
-        bl_idname="BoneCollectionSocket",),
-    ChildCollection := SockTemplate(name='Child Collection', is_input=True,
-        bl_idname="BoneCollectionSocket",),
-    CollectionDeclarationOutput,
+DriverSockets = [
+    DriverType := ST(name="Driver Type", bl_idname="EnumDriverType", is_input=True),
+    FCurve := ST(name="fCurve", bl_idname="FCurveSocket", is_input=True),
+    Expression := ST(name="Expression", bl_idname="StringSocket", is_input=True),
+    DriverOutput := ST(name="Driver", bl_idname="DriverSocket", is_input=False),
 ]
 
+SwitchSockets = [
+    Parameter := ST(name="Parameter", bl_idname="ParameterStringSocket", is_input=True),
+    ParameterIndex := ST(name="Parameter Index", bl_idname="IntSocket", is_input=True),
+    InvertSwitch := ST(name="Invert Switch", bl_idname="BooleanSocket", is_input=True),
+    DriverOutput,
+]
+
+CombineThreeBoolSockets = [
+    AxisX := ST(name="X", bl_idname="BooleanSocket", is_input=True),
+    AxisY := replace(AxisX, name='Y'),
+    AxisZ := replace(AxisX, name='Z'),
+    ThreeBoolOutput := ST(name="Three-Bool", bl_idname="BooleanThreeTupleSocket", is_input=False),
+]
+
+CombineThreeBoolSockets = [
+    AxisX := ST(name="X", bl_idname="BooleanSocket", is_input=True),
+    AxisY := replace(AxisX, name='Y'),
+    AxisZ := replace(AxisX, name='Z'),
+    ThreeBoolOutput := ST(name="Three-Bool", bl_idname="BooleanThreeTupleSocket", is_input=False),
+]
+
+CombineVectorSockets = [
+    AxisX := replace(AxisX, bl_idname="FloatSocket", name='X'),
+    AxisY := replace(AxisY, bl_idname="FloatSocket", name='Y'),
+    AxisZ := replace(AxisZ, bl_idname="FloatSocket", name='Z'),
+    VectorOutput := ST(name="Vector", bl_idname="VectorSocket", is_input=False),
+]
+
+SeparateVectorSockets = [
+    Vector := ST(name="Vector", bl_idname="VectorSocket", is_input=True),
+    AxisXOutput := replace(AxisX, bl_idname="FloatSocket", is_input=False),
+    AxisYOutput := replace(AxisXOutput, name='Y'),
+    AxisZOutput := replace(AxisXOutput, name='Z'),
+]
+
+CatStringsSockets = [
+    String_1 := ST(name="String_1", bl_idname="StringSocket", is_input=True),
+    String_2 := replace(String_1, name="String_2"),
+    OutputString := ST(name="OutputString", bl_idname="StringSocket", is_input=False),
+]
+
+InputWidgetSockets = [
+    WidgetName := ST(name='Name', is_input=True,
+        bl_idname="EnumWidgetLibrarySocket",),
+    Scale := ST(name='Scale', is_input=True,
+        bl_idname="VectorScaleSocket", default_value=(1.0, 1.0, 1.0)),
+    FlipAxes := ST(name='Flip Axes', is_input=True,
+        bl_idname="BooleanThreeTupleSocket",),
+    xFormOutput := ST(name='Widget',
+        bl_idname='xFormSocket', is_input=False),
+]
+
+InputExistingGeometryObjectSockets = [
+    Name := ST(name="Name", bl_idname="StringSocket", is_input=True),
+    ObjectOutput := ST(name="Object", bl_idname="xFormSocket", is_input=False),
+]
+
+InputExistingGeometrySockets = [
+    Name,
+    GeometryOutput := ST(name="Geometry", bl_idname="GeometrySocket", is_input=False),
+]
 
 UtilityCustomPropertySockets = [
-    Name := SockTemplate(name='Name', is_input=True,
+    Name := ST(name='Name', is_input=True,
         bl_idname="StringSocket", category='general'),
     
-    CustomPropType := SockTemplate(name='Type', is_input=True,
+    CustomPropType := ST(name='Type', is_input=True,
         bl_idname="EnumCustomPropTypeSocket", category='general'),
     # Subtype - add this later
 
     # float properties
-    DefaultFloatValue := SockTemplate(name='Default (Float)', is_input=True,
+    DefaultFloatValue := ST(name='Default (Float)', is_input=True,
         bl_idname="FloatSocket",  category='float'),
-    Min := SockTemplate(name='Min (Float)', is_input=True,
+    Min := ST(name='Min (Float)', is_input=True,
         bl_idname="FloatSocket", category='float'),
-    Max := SockTemplate(name='Max (Float)', is_input=True,
+    Max := ST(name='Max (Float)', is_input=True,
         bl_idname="FloatSocket", category='float'),
-    SoftMin := SockTemplate(name='Soft Min (Float)', is_input=True,
+    SoftMin := ST(name='Soft Min (Float)', is_input=True,
         bl_idname="FloatSocket", category='float'),
-    SoftMax := SockTemplate(name='Soft Max (Float)', is_input=True,
+    SoftMax := ST(name='Soft Max (Float)', is_input=True,
         bl_idname="FloatSocket", category='float'),
     
     # bool properties
-    DefaultVectorValue := SockTemplate(name='Default (Bool)', is_input=True,
+    DefaultVectorValue := ST(name='Default (Bool)', is_input=True,
         bl_idname="BooleanSocket", hide=True, category='bool'),
     # int properties
-    DefaultIntValue := SockTemplate(name='Default (Int)', is_input=True,
+    DefaultIntValue := ST(name='Default (Int)', is_input=True,
         bl_idname="IntSocket", hide=True, category='int'),
-    IntMin := SockTemplate(name='Min (Int)', is_input=True,
+    IntMin := ST(name='Min (Int)', is_input=True,
         bl_idname="IntSocket", hide=True, category='int'),
-    IntMax := SockTemplate(name='Max (Int)', is_input=True,
+    IntMax := ST(name='Max (Int)', is_input=True,
         bl_idname="IntSocket", hide=True, category='int'),
-    IntSoftMin := SockTemplate(name='Soft Min (Int)', is_input=True,
+    IntSoftMin := ST(name='Soft Min (Int)', is_input=True,
         bl_idname="IntSocket", hide=True, category='int'),
-    IntSoftMax := SockTemplate(name='Soft Max (Int)', is_input=True,
+    IntSoftMax := ST(name='Soft Max (Int)', is_input=True,
         bl_idname="IntSocket", hide=True, category='int'),
     # vector properties
-    DefaultVectorValue := SockTemplate(name='Default (Vector)', is_input=True,
+    DefaultVectorValue := ST(name='Default (Vector)', is_input=True,
         bl_idname="VectorSocket", hide=True, category='vector'),
     # String Properties
-    DefaultStringValue := SockTemplate(name='Default (String)', is_input=True,
+    DefaultStringValue := ST(name='Default (String)', is_input=True,
         bl_idname="StringSocket", hide=True, category='string'),
     # general:
-    Description := SockTemplate(name='Description', is_input=True,
+    Description := ST(name='Description', is_input=True,
         bl_idname="StringSocket", category='general'),
-    PropertyDeclaration := SockTemplate(name='Custom Property',
+    PropertyDeclaration := ST(name='Custom Property',
         is_input=False, bl_idname="CustomPropSocket", category='general'),
-]
+]
+
+CollectionJoinSockets = [
+    JoinCollections := ST(name='Collections', is_input=True,
+        bl_idname="BoneCollectionSocket", display_shape='SQUARE_DOT',
+        use_multi_input=True,),
+    CollectionDeclarationOutput := ST(name='Collection',
+        bl_idname="BoneCollectionSocket", is_input=False,)
+]
+
+CollectionHierarchySockets = [
+    ParentCollection := ST(name='Parent Collection', is_input=True,
+        bl_idname="BoneCollectionSocket",),
+    ChildCollection := ST(name='Child Collection', is_input=True,
+        bl_idname="BoneCollectionSocket",),
+    CollectionDeclarationOutput,
+]
+
+GeometryOfXFormSockets = [
+    xForm := ST(name="xForm", bl_idname="xFormSocket", is_input=True),
+    GeometryOutput,
+]
+
+NameOfXFormSockets = [
+    xForm,
+    replace(Name, is_input=False),
+]
+
+GetBoneLengthSockets = [
+    BoneMatrix := ST(name="Bone Matrix", bl_idname="MatrixSocket", is_input=True),
+    BoneLength := ST(name="Bone Length", bl_idname="FloatSocket", is_input=False),
+]
+
+PointFromBoneMatrixSockets = [
+    replace(MatrixInput, name = "Bone Matrix",),
+    HeadTail := ST(name="Head/Tail", bl_idname = "FloatFactorSocket", is_input=True) ,
+    replace(VectorOutput, name="Point"),
+]
+
+SetBoneLengthSockets = [
+    replace(MatrixInput, name = "Bone Matrix"),
+    Length := ST(name="Length", bl_idname = "FloatSocket", is_input=True) ,
+    replace(MatrixOutput, name = "Bone Matrix"),
+]
+
+# there will eventually be inputs for e.g. key type, key handles, etc.
+# right now I am gonna hardcode LINEAR keyframes so I don't have to deal with anything else
+# TODO TODO TODO
+KeyframeSockets = [
+    # Interpolation := ST(name="Interpolation", bl_idname="EnumKeyframeInterpolationTypeSocket", is_input=True),
+    # LeftHandleType := ST(name="Left Handle Type", bl_idname="EnumKeyframeBezierHandleType", is_input=True),
+    # RightHandleType := ST(name="Right Handle Type", bl_idname="EnumKeyframeBezierHandleType", is_input=True),
+    # LeftHandleDistance := ST(name="Left Handle Distance", bl_idname="FloatSocket", is_input=True),
+    # LeftHandleValue := ST(name="Left Handle Value", bl_idname="FloatSocket", is_input=True),
+    # RightHandleFrame := ST(name="Right Handle Frame", bl_idname="FloatSocket", is_input=True),
+    # RightHandleValue := ST(name="Right Handle Value", bl_idname="FloatSocket", is_input=True),
+    Frame := ST(name="Frame", bl_idname="FloatSocket", is_input=True),
+    Value := ST(name="Value", bl_idname="FloatSocket", is_input=True),
+    Keyframe := ST(name="Keyframe", bl_idname="KeyframeSocket", is_input=False),
+]
+
+BoneMatrixHeadTailFlipSockets = [
+    replace(MatrixInput, name = "Bone Matrix",),
+    replace(MatrixOutput, name = "Bone Matrix"),
+]
+
+MatrixTransformSockets = [
+    Matrix1Template := ST( name="Matrix 1", is_input=True,
+        bl_idname='MatrixSocket', ),
+    Matrix2Template := replace(Matrix1Template, name = "Matrix 2"),
+    replace(MatrixOutput, name = "Out Matrix"),
+]
+
+MatrixInvertSockets=[
+    Matrix1Template,
+    MatrixOutput,
+]
+
+MatrixComposeSockets=[
+    XBasisVector := ST(
+    name="X Basis Vector", is_input=True,  bl_idname='VectorSocket', 
+        default_value = (1.0, 0.0, 0.0) ),
+    YBasisVector := replace(XBasisVector, name="Y Basis Vector",
+        default_value = (0.0, 1.0, 0.0) ),
+    ZBasisVector := replace(XBasisVector, name="Z Basis Vector",
+        default_value = (0.0, 0.0, 1.0) ),
+    Translation := replace(XBasisVector, name="Translation"),
+    MatrixOutput,
+]
+
+MatrixAlignRollSockets = [
+    MatrixInTemplate := replace(Matrix1Template, name="Matrix"),
+    AlignVector := ST(name="Alignment Vector", is_input=True,
+       bl_idname='VectorSocket', default_value=(0.0,-1.0,0.0)),
+    MatrixOutput,
+]
+
+MatrixSetLocationSockets = [
+    MatrixInput,
+    replace(VectorInput, name="Location"),
+    MatrixOutput,
+]
+
+MatrixGetLocationSockets = [
+    MatrixInput,
+    replace(VectorInput, is_input=False, name="Location"),
+]
+
+TransformationMatrixSockets = [
+    MatrixTransformOperation := ST(name="Operation",
+        bl_idname="MatrixTransformOperation", is_input=True),
+    Vector,
+    AxisW := replace(AxisX, name="W"),
+    MatrixOutput,
+]
+
+SetBoneMatrixTailSockets = [
+    MatrixInput,
+    replace(VectorInput, name="Tail Location"),
+    replace(MatrixOutput, name = "Result"),
+]
+
+MatrixFromXFormSockets = [
+    xForm,
+    MatrixOutput,
+]
+
+AxesFromMatrixSockets = [
+    MatrixInput,
+    replace(VectorOutput, name='X Axis',),
+    replace(VectorOutput, name='Y Axis',),
+    replace(VectorOutput, name='Z Axis',),
+]
+
+IntToStringSockets = [
+    Number := ST(name = 'Number', bl_idname = 'IntSocket',
+        is_input = True),
+    Number := ST(name = 'Zero Padding', bl_idname = 'IntSocket',
+        is_input = True),
+    StringOutput,
+]
+
+ArrayGetSockets = [
+    OoBBehaviour := ST(name="OoB Behaviour", bl_idname="EnumArrayGetOptions",
+        is_input=True),
+    Index := ST(name="Index", bl_idname="IntSocket", is_input=True),
+    Array := ST(name="Array", bl_idname="WildcardSocket", is_input=True,
+        use_multi_input=True, display_shape='SQUARE_DOT'),
+    WildcardOutput := ST(name="Output", bl_idname="WildcardSocket", is_input=False),
+]
+
+UtilityArrayLengthSockets = [
+    Array,
+    replace(NumberOfSegments, name="Length"),
+]
+
+CompareSockets = [
+    ComparisonOperation := ST( name='Comparison',
+            is_input=True, bl_idname="EnumCompareOperation",
+            default_value="EQUAL",),
+    WildcardATemplate := ST(
+        name="A", is_input=True,  bl_idname='WildcardSocket', ),
+    WildcardBTemplate := replace(WildcardATemplate, name="B"),
+    CompareOutputTemplate := ST(
+        name="Result", is_input=False, bl_idname="BooleanSocket",),
+]
+
+ChooseSockets = [
+    Condition := ST(name="Condition", bl_idname="BooleanSocket", is_input=True),
+    ChooseA := ST(name="A", bl_idname="WildcardSocket", is_input=True),
+    ChooseB := ST(name="B", bl_idname="WildcardSocket", is_input=True),
+    replace(WildcardOutput, name='Result'),
+]
+
+PrintSockets = [
+    replace(ChooseA, name='Input'),
+]
+
+NumberOfSplinesSockets=[
+    CurveTemplate,
+    NumberOfSplinesOut := ST(name="Number of Splines",
+        bl_idname='UnsignedIntSocket', is_input=False),
+]

File diff ditekan karena terlalu besar
+ 82 - 363
misc_nodes_ui.py


+ 5 - 13
schema_nodes.py

@@ -1,6 +1,8 @@
 from .node_common import *
 from math import pi, tau
-from .base_definitions import MantisNode, NodeSocket
+from .base_definitions import MantisNode
+
+from .schema_nodes_socket_templates import *
 
 def TellClasses():
     return [
@@ -47,12 +49,7 @@ class SchemaNode(MantisNode):
 
 class SchemaIndex(SchemaNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = [
-          "Index",
-          "Schema Length",
-        ]
-        self.outputs.init_sockets(outputs)
+        super().__init__(signature, base_tree, SchemaIndexSockets)
         self.init_parameters()
 
 class SchemaArrayInput(SchemaNode):
@@ -63,12 +60,7 @@ class SchemaArrayInput(SchemaNode):
 
 class SchemaArrayInputGet(SchemaNode):
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        inputs = [
-            "OoB Behaviour" ,
-            "Index"         ,
-        ]
-        self.inputs.init_sockets(inputs)
+        super().__init__(signature, base_tree, SchemaArrayInputGetSockets)
         schema_init_sockets(self, is_input=False, in_out='INPUT', category='Array')
 
 class SchemaArrayInputAll(SchemaNode):

+ 14 - 0
schema_nodes_socket_templates.py

@@ -0,0 +1,14 @@
+from .base_definitions import MantisSocketTemplate as ST
+from dataclasses import replace
+
+# NOTE most Schema nodes are fully dynamic, and the rest are
+#      mostly dynamic, so they don't use Socket Templates much.
+SchemaIndexSockets = [
+    Index := ST(name="Index", bl_idname="IntSocket", is_input=False),
+    SchemaLength := ST(name="Schema Length", bl_idname="IntSocket", is_input=False),
+]
+
+SchemaArrayInputGetSockets = [
+    OoBBehaviour := ST(name="OoB Behaviour", bl_idname="EnumArrayGetOptions", is_input=True),
+    Index := ST(name="Index", bl_idname="IntSocket", is_input=True),
+]

+ 3 - 4
schema_nodes_ui.py

@@ -10,6 +10,7 @@ from bpy.props import BoolProperty
 from .utilities import (get_socket_maps, relink_socket_map,
                         do_relink, read_schema_type)
 
+from .schema_nodes_socket_templates import *
 
 def TellClasses():
     return [
@@ -39,8 +40,7 @@ class SchemaIndex(Node, SchemaUINode):
     mantis_node_class_name=bl_idname
     
     def init(self, context):
-        self.outputs.new("IntSocket", "Index")
-        self.outputs.new("IntSocket", "Schema Length")
+        self.init_sockets(SchemaIndexSockets)
         self.initialized = True
 
 class SchemaArrayInput(Node, SchemaUINode):
@@ -118,8 +118,7 @@ class SchemaArrayInputGet(Node, SchemaUINode):
     mantis_node_class_name=bl_idname
 
     def init(self, context):
-        self.inputs.new('EnumArrayGetOptions', 'OoB Behaviour')
-        self.inputs.new("IntSocket", "Index")
+        self.init_sockets(SchemaArrayInputGetSockets)
         self.update()
 
     def update(self):

+ 4 - 73
xForm_nodes.py

@@ -236,85 +236,15 @@ class xFormArmature(xFormNode):
     def bGetObject(self, mode = ''):
         import bpy; return bpy.data.objects[self.parameters['xForm Out'].self_pose_name]
 
-bone_inputs= [
-         "Name",
-         "Rotation Order",
-         "Matrix",
-         "Relationship",
-         # IK settings
-         "IK Stretch",
-         "Lock IK",
-         "IK Stiffness",
-         "Limit IK",
-         "X Min",
-         "X Max",
-         "Y Min",
-         "Y Max",
-         "Z Min",
-         "Z Max",
-         # Visual stuff
-         "Bone Collection",
-         "Hide",
-         "Custom Object",
-         "Custom Object xForm Override",
-         "Custom Object Scale to Bone Length",
-         "Custom Object Wireframe",
-         "Custom Object Scale",
-         "Custom Object Translation",
-         "Custom Object Rotation",
-         "Color",
-         "Inherit Color",
-         # Deform Stuff
-         "Deform",
-         "Envelope Distance",
-         "Envelope Weight",
-         "Envelope Multiply",
-         "Envelope Head Radius",
-         "Envelope Tail Radius",
-         # BBone stuff:
-         "BBone Segments",
-         "BBone X Size",
-         "BBone Z Size",
-         "BBone HQ Deformation",
-         "BBone X Curve-In",
-         "BBone Z Curve-In",
-         "BBone X Curve-Out",
-         "BBone Z Curve-Out",
-         "BBone Roll-In",
-         "BBone Roll-Out",
-         "BBone Inherit End Roll",
-         "BBone Scale-In",
-         "BBone Scale-Out",
-         "BBone Ease-In",
-         "BBone Ease-Out",
-         "BBone Easing",
-         "BBone Start Handle Type",
-         "BBone Custom Start Handle",
-         "BBone Start Handle Scale",
-         "BBone Start Handle Ease",
-         "BBone End Handle Type",
-         "BBone Custom End Handle",
-         "BBone End Handle Scale",
-         "BBone End Handle Ease",
-         # locks
-         "Lock Location",
-         "Lock Rotation",
-         "Lock Scale",
-         "Custom Properties",
-]
 class xFormBone(xFormNode):
     '''A node representing a bone in an armature'''
     # DO: make a way to identify which armature this belongs to
     def __init__(self, signature, base_tree):
-        super().__init__(signature, base_tree)
-        outputs = [
-         "xForm Out",
-        ]
-        self.inputs.init_sockets(bone_inputs)
-        self.outputs.init_sockets(outputs)
-        self.socket_templates=xFormBoneSockets
+        super().__init__(signature, base_tree, xFormBoneSockets)
         # TODO: implement socket templates completely for Bone
         # currently it is waiting on BBone and refactoring/cleanup.
+        # the socket templates are being used now but not for mantis node execution.
+        # because of edit/pose/objcet bone this will be a bit complex
         self.init_parameters()
         self.set_traverse([("Relationship", "xForm Out")])
         setup_custom_property_inputs_outputs(self)
@@ -595,6 +525,7 @@ class xFormBone(xFormNode):
         evaluate_sockets(self, pb, props_sockets)
 
         # this could probably be moved to bTransformPass
+        # TODO VERSIONING: newer (5.0+ ?) Blenders need to use PoseBone for this
         props_sockets = {
             'hide'      : ("Hide", False),
             'show_wire' : ("Custom Object Wireframe", False),

+ 16 - 153
xForm_nodes_ui.py

@@ -132,93 +132,9 @@ def custom_prop_display_update(self, mantis_node = None):
             do_relink(self, socket, socket_map_out, in_out='OUTPUT')
 
 
-# I had chat gpt flip these so they may be a little innacurate
-# always visible
-main_names = {
-"Name":'StringSocket',
-"Rotation Order":'RotationOrderSocket',
-"Relationship":'RelationshipSocket',
-"Matrix":'MatrixSocket',}
-
-# IK SETTINGS
-ik_names = {
-"IK Stretch":'FloatFactorSocket',
-"Lock IK":'BooleanThreeTupleSocket',
-"IK Stiffness":'NodeSocketVector',
-"Limit IK":'BooleanThreeTupleSocket',
-"X Min":'NodeSocketFloatAngle',
-"X Max":'NodeSocketFloatAngle',
-"Y Min":'NodeSocketFloatAngle',
-"Y Max":'NodeSocketFloatAngle',
-"Z Min":'NodeSocketFloatAngle',
-"Z Max":'NodeSocketFloatAngle',
-}
-
-#display settings
-display_names = {
-"Bone Collection":'BoneCollectionSocket',
-"Custom Object":'xFormSocket',
-"Custom Object xForm Override":'xFormSocket',
-"Custom Object Scale to Bone Length":'BooleanSocket',
-"Custom Object Wireframe":'BooleanSocket',
-"Custom Object Scale":'VectorScaleSocket',
-"Custom Object Translation":'VectorSocket',
-"Custom Object Rotation":'VectorEulerSocket',
-"Color":'ColorSetSocket',
-"Inherit Color":'BooleanSocket',
-}
-
-# deform_names
-deform_names = {
-"Deform":'BooleanSocket',
-"Envelope Distance":'FloatPositiveSocket',
-"Envelope Weight":'FloatFactorSocket',
-"Envelope Multiply":'BooleanSocket',
-"Envelope Head Radius":'FloatPositiveSocket',
-"Envelope Tail Radius":'FloatPositiveSocket',
-}
-
-bbone_names = {
-    "BBone Segments":"IntSocket", # BONE
-    "BBone X Size":"FloatSocket", # BONE
-    "BBone Z Size":"FloatSocket", # BONE
-    # "bbone_mapping_mode":"StringSocket", <== BONE
-    "BBone HQ Deformation":"BooleanSocket", # BONE bbone_mapping_mode
-    "BBone X Curve-In":"FloatSocket", # BONE AND POSE
-    "BBone Z Curve-In":"FloatSocket", # BONE AND POSE
-    "BBone X Curve-Out":"FloatSocket", # BONE AND POSE
-    "BBone Z Curve-Out":"FloatSocket", # BONE AND POSE
-    "BBone Roll-In":"FloatSocket", # BONE AND POSE
-    "BBone Roll-Out":"FloatSocket", # BONE AND POSE
-    "BBone Inherit End Roll":"BooleanSocket", # BONE
-    "BBone Scale-In":"VectorSocket", # BONE AND POSE
-    "BBone Scale-Out":"VectorSocket", # BONE AND POSE
-    "BBone Ease-In":"FloatSocket", # BONE AND POSE
-    "BBone Ease-Out":"FloatSocket", # BONE AND POSE
-    "BBone Easing":"BooleanSocket", # BONE
-    "BBone Start Handle Type":"EnumBBoneHandleType", # BONE
-    "BBone Custom Start Handle":"StringSocket", # BONE
-    "BBone Start Handle Scale":"BooleanThreeTupleSocket", # BONE
-    "BBone Start Handle Ease":"BooleanSocket", # BONE
-    "BBone End Handle Type":"EnumBBoneHandleType", # BONE
-    "BBone Custom End Handle":"StringSocket", # BONE
-    "BBone End Handle Scale":"BooleanThreeTupleSocket", # BONE
-    "BBone End Handle Ease":"BooleanSocket", # BONE
-
-}
-
-other_names = {
-    "Lock Location":'BooleanThreeTupleSocket',
-    "Lock Rotation":'BooleanThreeTupleSocket',
-    "Lock Scale":'BooleanThreeTupleSocket',
-    "Hide":'HideSocket',
-}
-
 from mathutils import Color
 xFormColor = Color((0.093172, 0.047735, 0.028036)).from_scene_linear_to_srgb()
 
-
-
 class xFormBoneNode(Node, xFormNode):
     '''A node representing a Bone'''
     bl_idname = 'xFormBoneNode'
@@ -232,70 +148,17 @@ class xFormBoneNode(Node, xFormNode):
     socket_count : bpy.props.IntProperty()
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates = xFormBoneSockets
     
     def init(self, context):
-
-        for name, sock_type in main_names.items():
-            self.inputs.new(sock_type, name)
-
-        for name, sock_type in ik_names.items():
-            s = self.inputs.new(sock_type, name)
-            s.hide = True
-        
-        for name, sock_type in display_names.items():
-            if name == 'Bone Collection': # HACK because I am not using Socket Templates yet
-                s = self.inputs.new(sock_type, name, use_multi_input=True)
-            else:
-                s = self.inputs.new(sock_type, name)
-            if s.name in ['Custom Object', 'Bone Collection']:
-                continue
-            s.hide = True
-        
-        for name, sock_type in deform_names.items():
-            s = self.inputs.new(sock_type, name)
-            if s.name == 'Deform':
-                continue
-            s.hide = True
-        
-        for name, sock_type in bbone_names.items():
-            s = self.inputs.new(sock_type, name)
-            if s.name == "BBone Segments":
-                continue
-            s.hide = True
-
-        for name, sock_type in other_names.items():
-            self.inputs.new(sock_type, name)
-        # could probably simplify this further with iter_tools.chain() but meh
-
-        self.inputs.new("CustomPropSocket", "Custom Properties", use_multi_input=True)
-
+        self.init_sockets(self.__class__.socket_templates)
         self.socket_count = len(self.inputs)
-        #
-        self.outputs.new('xFormSocket', "xForm Out")
-
-
-        # set up some defaults...
-        self.inputs['Rotation Order'].default_value = "XYZ"
-        self.inputs['Lock Location'].default_value[0] = True
-        self.inputs['Lock Location'].default_value[1] = True
-        self.inputs['Lock Location'].default_value[2] = True
-        self.inputs['Lock Rotation'].default_value[0] = True
-        self.inputs['Lock Rotation'].default_value[1] = True
-        self.inputs['Lock Rotation'].default_value[2] = True
-        self.inputs['Lock Scale'].default_value[0] = True
-        self.inputs['Lock Scale'].default_value[1] = True
-        self.inputs['Lock Scale'].default_value[2] = True
-        self.inputs['Inherit Color'].default_value = True
-        
-        # color
         self.use_custom_color = True
         self.color = xFormColor
-        #
         self.initialized=True
     
     def draw_label(self): # this will prefer a user-set label, or return the evaluated name
         return main_draw_label(self)
-
         
     def display_update(self, parsed_tree, context):
         # let's setup the outputs for the custom properties:
@@ -319,20 +182,20 @@ class xFormBoneNode(Node, xFormNode):
                 except KeyError:
                     return # the tree isn't ready yet.
             
-            for name in ik_names.keys():
-                self.inputs[name].hide = not self.display_ik_settings
-            
-            for name in display_names.keys():
-                if name in ['Custom Object', 'Bone Collection']: continue
-                self.inputs[name].hide = not self.display_vp_settings
-            
-            for name in deform_names.keys():
-                if name in ['Deform']: continue
-                self.inputs[name].hide = not self.display_def_settings
-
-            for name in bbone_names.keys():
-                if name in ['BBone Segments']: continue
-                self.inputs[name].hide = not self.display_bb_settings
+            for template in self.socket_templates:
+                name = template.name
+                category = template.category
+                if category == "IK":
+                    self.inputs[name].hide = not self.display_ik_settings
+                if category == "Display":
+                    if name in ['Custom Object', 'Bone Collection']: continue
+                    self.inputs[name].hide = not self.display_vp_settings
+                if category == "Deform":
+                    if name in ['Deform']: continue
+                    self.inputs[name].hide = not self.display_def_settings
+                if category == "bbone":
+                    if name in ['BBone Segments']: continue
+                    self.inputs[name].hide = not self.display_bb_settings
 
 def object_displaty_update(self, parsed_tree, context):
     custom_prop_display_update(self)

+ 20 - 18
xForm_socket_templates.py

@@ -102,7 +102,7 @@ xFormBoneSockets = [
         blender_property=('lock_ik_x', 'lock_ik_y', 'lock_ik_z'),),
     IKStiffness := SockTemplate(
         name="IK Stiffness", is_input=True,  bl_idname='BooleanThreeTupleSocket',
-        default_value=(0, 0, 0), category='IK',
+        default_value=(False, False, False), category='IK',
         blender_property=('ik_stiffness_x', 'ik_stiffness_y', 'ik_stiffness_z')),
     IKLimit := SockTemplate(
         name="Limit IK", is_input=True,  bl_idname='BooleanThreeTupleSocket',
@@ -134,10 +134,10 @@ xFormBoneSockets = [
     CustomObjectScaleTemplate := SockTemplate(name="Custom Object Scale",
             is_input=True, bl_idname='VectorScaleSocket',
             category='Display', default_value=(1.0,1.0,1.0),),
-    CustomObjectScaleTemplate := SockTemplate(name="Custom Object Translation",
+    CustomObjectTranslationTemplate := SockTemplate(name="Custom Object Translation",
             is_input=True, bl_idname='VectorSocket',
             category='Display', default_value=(0.0,0.0,0.0),),
-    CustomObjectScaleTemplate := SockTemplate(name="Custom Object Rotation",
+    CustomObjectRotationTemplate := SockTemplate(name="Custom Object Rotation",
             is_input=True, bl_idname='VectorEulerSocket',
             category='Display', default_value=(0.0,0.0,0.0),),
     CustomColor := SockTemplate(name="Color",
@@ -151,7 +151,8 @@ xFormBoneSockets = [
         category='Deform', blender_property='use_deform', default_value=False,),
     EnvelopeDistanceTemplate := SockTemplate( name='Envelope Distance',
             bl_idname='FloatPositiveSocket', category='Deform',
-            blender_property='envelope_distance', default_value=0,),
+            blender_property='envelope_distance', default_value=0,
+            is_input=True,),
     EnvelopeWeightTemplate := replace(EnvelopeDistanceTemplate,
             name='Envelope Weight', bl_idname = 'FloatFactorSocket',
             blender_property='envelope_weight', default_value=1.0,),
@@ -168,8 +169,8 @@ xFormBoneSockets = [
         blender_property='bbone_segments', default_value=1 ),
     BBoneXSizeTemplate := replace(BBoneSegmentsTemplate, name='BBone X Size',
         bl_idname='FloatSocket', blender_property='bbone_x', default_value=0.0025, ),
-    BBoneYSizeTemplate := replace(BBoneXSizeTemplate, name='BBone Z Size',
-        blender_property='bbone_y', ),
+    BBoneZSizeTemplate := replace(BBoneXSizeTemplate, name='BBone Z Size',
+        blender_property='bbone_z', ),
     BBoneHQDeformation := replace(BBoneSegmentsTemplate, name='BBone HQ Deformation',
         bl_idname='BooleanSocket', blender_property='', default_value=None ),
     BBoneXCurveInTemplate := replace( BBoneXSizeTemplate, name="BBone X Curve-In",
@@ -184,37 +185,38 @@ xFormBoneSockets = [
     replace(BBoneXCurveInTemplate, name="BBone Roll-In", blender_property='bbone_rollin', ), # CURRENTLY UNIMPLEMENTED
     replace(BBoneXCurveInTemplate, name="BBone Roll-Out", blender_property='bbone_rollout', ), # CURRENTLY UNIMPLEMENTED
     replace(BBoneXCurveInTemplate, name="BBone Inherit End Roll",
-            bl_idname='BooleanSocket',), # CURRENTLY UNIMPLEMENTED
+            bl_idname='BooleanSocket', default_value=False,), # CURRENTLY UNIMPLEMENTED
     replace(BBoneXCurveInTemplate, name="BBone Scale-In",
-            bl_idname='VectorSocket',), # CURRENTLY DOESN'T WORK
+            bl_idname='VectorSocket', default_value=(0.0,0.0,0.0),), # CURRENTLY DOESN'T WORK
     replace(BBoneXCurveInTemplate, name="BBone Scale-Out",
-            bl_idname='VectorSocket',), # CURRENTLY DOESN'T WORK
+            bl_idname='VectorSocket', default_value=(0.0,0.0,0.0)), # CURRENTLY DOESN'T WORK
     replace(BBoneXCurveInTemplate, name="BBone Ease-In",), # CURRENTLY DOESN'T WORK
     replace(BBoneXCurveInTemplate, name="BBone Ease-Out",), # CURRENTLY DOESN'T WORK
     replace(BBoneXCurveInTemplate, name="BBone Easing",
-            bl_idname='BooleanSocket',), # CURRENTLY DOESN'T WORK
+            bl_idname='BooleanSocket', default_value=False,), # CURRENTLY DOESN'T WORK
     replace(BBoneXCurveInTemplate, name="BBone Start Handle Type",
             bl_idname="EnumBBoneHandleType",
-            blender_property='bbone_handle_type_start',),
+            blender_property='bbone_handle_type_start', default_value=None, ),
     replace(BBoneXCurveInTemplate, name="BBone Custom Start Handle",
             bl_idname="StringSocket",
-            blender_property='bbone_custom_handle_start',),
+            blender_property='bbone_custom_handle_start', default_value=None, ),
     replace(BBoneXCurveInTemplate, name="BBone Start Handle Scale",
             bl_idname="BooleanThreeTupleSocket",
-            blender_property='bbone_handle_use_scale_start',),
+            blender_property='bbone_handle_use_scale_start', default_value=None, ),
     replace(BBoneXCurveInTemplate, name="BBone Start Handle Ease",
-            bl_idname='BooleanSocket',),# CURRENTLY DOESN'T WORK),
+            bl_idname='BooleanSocket', default_value=False),# CURRENTLY DOESN'T WORK),
     replace(BBoneXCurveInTemplate, name="BBone End Handle Type",
             bl_idname="EnumBBoneHandleType",
-            blender_property='bbone_handle_type_end',),
+            blender_property='bbone_handle_type_end', default_value=None, ),
     replace(BBoneXCurveInTemplate, name="BBone Custom End Handle",
             bl_idname="StringSocket",
-            blender_property='bbone_custom_handle_end',),
+            blender_property='bbone_custom_handle_end', default_value=None, ),
     replace(BBoneXCurveInTemplate, name="BBone End Handle Scale",
             bl_idname="BooleanThreeTupleSocket",
-            blender_property='bbone_handle_use_scale_end',),
+            blender_property='bbone_handle_use_scale_end',
+            default_value= (False, False, False)),
     replace(BBoneXCurveInTemplate, name="BBone End Handle Ease",
-            bl_idname='BooleanSocket',),# CURRENTLY DOESN'T WORK),
+            bl_idname='BooleanSocket', default_value=False),# CURRENTLY DOESN'T WORK),
     # locks
     LockLocationTemplate := SockTemplate(name="Lock Location",
         is_input=True, bl_idname='BooleanThreeTupleSocket', category = 'lock',

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini