Browse Source

Add: First round of versioning code

This fix does some cleanup, adds basic versioning code, fixes I_O a bit, and makes a breaking change in Driver Variable to test if versioning is working. Added an on-load handler to do the version updates.
Now I can make breaking changes without breaking things! This is a big deal!
Joseph Brandenburg 8 tháng trước cách đây
mục cha
commit
593ab7cb6c
5 tập tin đã thay đổi với 98 bổ sung48 xóa
  1. 35 0
      __init__.py
  2. 12 2
      base_definitions.py
  3. 1 1
      blender_manifest.toml
  4. 28 6
      i_o.py
  5. 22 39
      nodes_generic.py

+ 35 - 0
__init__.py

@@ -15,6 +15,10 @@ from bpy.types import NodeSocket
 
 from .utilities import prRed
 
+MANTIS_VERSION_MAJOR=0
+MANTIS_VERSION_MINOR=9
+MANTIS_VERSION_SUB=4
+
 
 classLists = [module.TellClasses() for module in [
  link_definitions,
@@ -232,6 +236,36 @@ def execute_handler(scene):
                 node_tree.tree_valid = False
 
 
+@persistent
+def version_update_handler(filename):
+    from .base_definitions import NODES_REMOVED, SOCKETS_REMOVED
+    for node_tree in bpy.data.node_groups:
+        if node_tree.bl_idname in ["MantisTree", "SchemaTree"]:
+            if (node_tree.mantis_version[0] < MANTIS_VERSION_MAJOR) or \
+               (node_tree.mantis_version[1] < MANTIS_VERSION_MINOR) or \
+               (node_tree.mantis_version[2] < MANTIS_VERSION_SUB):
+                print (f"Updating tree {node_tree.name} to {MANTIS_VERSION_MAJOR}.{MANTIS_VERSION_MINOR}.{MANTIS_VERSION_SUB}")
+                node_tree.mantis_version[0] = MANTIS_VERSION_MAJOR
+                node_tree.mantis_version[1] = MANTIS_VERSION_MINOR
+                node_tree.mantis_version[2] = MANTIS_VERSION_SUB
+                for n in node_tree.nodes:
+                    if n.bl_idname in NODES_REMOVED:
+                        print(f"INFO: removing node {n.name} of type {n.bl_idname} because it has been deprecated.")
+                        n.inputs.remove(socket)
+                        continue
+                    for socket in n.inputs.values():
+                        if (n.bl_idname, socket.identifier) in SOCKETS_REMOVED:
+                            print(f"INFO: removing socket {socket.identifier} of node {n.name} of type {n.bl_idname} because it has been deprecated.")
+                            n.inputs.remove(socket)
+                    for socket in n.outputs.values():
+                        if (n.bl_idname, socket.identifier) in SOCKETS_REMOVED:
+                            print(f"INFO: removing socket {socket.identifier} of node {n.name} of type {n.bl_idname} because it has been deprecated.")
+                            n.outputs.remove(socket)
+                
+                
+
+
+
 
 def register():
     if bpy.app.version >= (4, 4):
@@ -257,6 +291,7 @@ def register():
     # add the handlers
     bpy.app.handlers.depsgraph_update_pre.append(update_handler)
     bpy.app.handlers.depsgraph_update_post.append(execute_handler)
+    bpy.app.handlers.load_post.append(version_update_handler)
 
 
     

+ 12 - 2
base_definitions.py

@@ -1,6 +1,7 @@
 #Mantis Nodes Base
 import bpy
-from bpy.props import BoolProperty, StringProperty, EnumProperty, CollectionProperty, IntProperty, PointerProperty, BoolVectorProperty
+from bpy.props import (BoolProperty, StringProperty, EnumProperty, CollectionProperty, \
+    IntProperty, IntVectorProperty, PointerProperty, BoolVectorProperty)
 from . import ops_nodegroup
 from bpy.types import NodeTree, Node, PropertyGroup, Operator, UIList, Panel
 
@@ -35,6 +36,7 @@ class MantisTree(NodeTree):
     is_executing:BoolProperty(default=False)
     is_exporting:BoolProperty(default=False)
     execution_id:StringProperty(default='')
+    mantis_version:IntVectorProperty(default=[0,9,2])
     
     parsed_tree={}
 
@@ -71,6 +73,7 @@ class MantisTree(NodeTree):
     def display_update(self, context):
         if self.is_exporting:
             return
+        self.is_executing = True
         current_tree = bpy.context.space_data.path[-1].node_tree
         for node in current_tree.nodes:
             if hasattr(node, "display_update"):
@@ -78,7 +81,7 @@ class MantisTree(NodeTree):
                     node.display_update(self.parsed_tree, context)
                 except Exception as e:
                     print("Node \"%s\" failed to update display with error: %s" %(wrapGreen(node.name), wrapRed(e)))
-                    # raise e
+        self.is_executing = False
         
         # TODO: deal with invalid links properly.
         #    - Non-hierarchy links should be ignored in the circle-check and so the links should be marked valid in such a circle
@@ -112,6 +115,8 @@ class SchemaTree(NodeTree):
     is_executing:BoolProperty(default=False)
     is_exporting:BoolProperty(default=False)
 
+    mantis_version:IntVectorProperty(default=[0,9,2])
+
     if bpy.app.version >= (3, 2):  # in 3.1 this can lead to a crash
         @classmethod
         def valid_socket_type(cls, socket_type: str):
@@ -337,6 +342,11 @@ class SchemaGroup(Node, MantisNode):
 
 
 
+NODES_REMOVED=["xFormRootNode"]
+SOCKETS_REMOVED=[("UtilityDriverVariable","Transform Channel"),
+                 ("xFormRootNode","World Out"),
+                 ("UtilitySwitch","xForm")]
+
 # replace names with bl_idnames for reading the tree and solving schemas.
 replace_types = ["NodeGroupInput", "NodeGroupOutput", "SchemaIncomingConnection",
                  "SchemaArrayInput", "SchemaConstInput", "SchemaConstOutput", "SchemaIndex",

+ 1 - 1
blender_manifest.toml

@@ -3,7 +3,7 @@ schema_version = "1.0.0"
 # Example of manifest file for a Blender extension
 # Change the values according to your extension
 id = "mantis"
-version = "0.9.3"
+version = "0.9.4"
 name = "Mantis"
 tagline = "Mantis is a rigging nodes toolkit"
 maintainer = "Nodespaghetti <josephbburg@protonmail.com>"

+ 28 - 6
i_o.py

@@ -7,7 +7,7 @@ from .utilities import (prRed, prGreen, prPurple, prWhite,
 
 from mathutils import  Vector
 
-
+from .base_definitions import NODES_REMOVED, SOCKETS_REMOVED
 
 
 # this works but it is really ugly and probably quite inneficient
@@ -485,8 +485,12 @@ def do_import(data, context):
         
 #        from mantis.utilities import prRed, prWhite, prOrange, prGreen
         for name, propslist in nodes.items():
-            n = tree.nodes.new(propslist["bl_idname"])
-            if propslist["bl_idname"] in ["DeformerMorphTargetDeform"]:
+            bl_idname = propslist["bl_idname"]
+            if bl_idname in NODES_REMOVED:
+                prWhite(f"INFO: Ignoring import of node {name} of type {bl_idname}; it has been removed.")
+                continue
+            n = tree.nodes.new(bl_idname)
+            if bl_idname in ["DeformerMorphTargetDeform"]:
                 n.inputs.remove(n.inputs[1]) # get rid of the wildcard
 
             if n.bl_idname in [ "SchemaArrayInput",
@@ -503,8 +507,15 @@ def do_import(data, context):
                 n.node_tree = bpy.data.node_groups.get(sub_tree)
                 from .base_definitions import node_group_update
                 node_group_update(n, force = True)
-
+            
+            sockets_removed = []
             for i, (s_id, s_val) in enumerate(propslist["sockets"].items()):
+                for socket_removed in SOCKETS_REMOVED:
+                    if n.bl_idname == socket_removed[0] and s_id == socket_removed[1]:
+                        prWhite(f"INFO: Ignoring import of socket {s_id}; it has been removed.")
+                        sockets_removed.append(s_val["index"])
+                        sockets_removed.sort()
+                        continue
                 try:
                     if s_val["is_output"]: # for some reason it thinks the index is a string?
                         # try:
@@ -513,6 +524,9 @@ def do_import(data, context):
                         else:
                             socket = n.outputs[int(s_val["index"])]
                     else:
+                        for removed_index in sockets_removed:
+                            if s_val["index"] > removed_index:
+                                s_val["index"]-=1
                         if s_val["index"] >= len(n.inputs):
                             if n.bl_idname == "UtilityDriver":
                                 with bpy.context.temp_override(**{'node':n}):
@@ -538,6 +552,9 @@ def do_import(data, context):
                             elif n.bl_idname == "DeformerMorphTargetDeform": # this one doesn't use an operator since I figure out how to do dynamic node stuff
                                 socket = n.inputs.new(s_val["bl_idname"], s_val["name"], identifier=s_id)
                             else:
+                                prWhite(n.name, s_val["name"], s_id)
+                                for k,v in propslist["sockets"].items():
+                                    print(k,v)
                                 prRed(s_val["index"], len(n.inputs))
                                 raise NotImplementedError(wrapRed(f"{n.bl_idname} needs to be handled in JSON load."))
                             # if n.bl_idname in ['']
@@ -614,13 +631,14 @@ def do_import(data, context):
 #            print (wrapGreen(k), "   ", wrapPurple(v))
         
         for l in links:
+
             id1 = l[1]
             id2 = l[3]
             #
             name1=l[6]
             name2=l[7]
             
-            prWhite(l[0], l[1], " --> ", l[2], l[3])
+            # prWhite(l[0], l[1], " --> ", l[2], l[3])
             
             # l has...
             # node 1
@@ -628,7 +646,11 @@ def do_import(data, context):
             # node 2
             # identifier 2
             
-            from_node = tree.nodes[l[0]]
+            # if the from/to socket or node has been removed, continue
+            from_node = tree.nodes.get(l[0])
+            if not from_node:
+                prWhite(f"INFO: cannot create link {l[0]}:{l[1]} -->  {l[2]}:{l[3]}")
+                continue
             if hasattr(from_node, "node_tree"): # now we have to map by name actually
                 try:
                     id1 = from_node.outputs[l[4]].identifier

+ 22 - 39
nodes_generic.py

@@ -345,9 +345,9 @@ class UtilityMetaRigNode(Node, MantisNode):
             self.inputs["Meta-Bone"].hide=True
         else:
             self.inputs["Meta-Bone"].hide=False
-        if self.inputs["Meta-Armature"].is_connected:
+        if self.inputs["Meta-Armature"].is_linked:
             self.inputs["Meta-Armature"].search_prop = None
-        if self.inputs["Meta-Bone"].is_connected:
+        if self.inputs["Meta-Bone"].is_linked:
             self.inputs["Meta-Bone"].search_prop = None
 
 class UtilityBonePropertiesNode(Node, MantisNode):
@@ -385,17 +385,13 @@ class UtilityDriverVariableNode(Node, MantisNode):
         self.inputs.new("EnumDriverVariableType", "Variable Type")                 # 0
         self.inputs.new("ParameterStringSocket", "Property")                       # 1
         self.inputs.new("IntSocket", "Property Index")                             # 2
-        self.inputs.new("EnumDriverVariableTransformChannel", "Transform Channel") # 3
-        self.inputs.new("EnumDriverVariableEvaluationSpace", "Evaluation Space")   # 4
-        self.inputs.new("EnumDriverRotationMode", "Rotation Mode")                 # 5
-        self.inputs.new("xFormSocket", "xForm 1")                                  # 6
-        self.inputs.new("xFormSocket", "xForm 2")                                  # 7
+        self.inputs.new("EnumDriverVariableEvaluationSpace", "Evaluation Space")   # 3
+        self.inputs.new("EnumDriverRotationMode", "Rotation Mode")                 # 4
+        self.inputs.new("xFormSocket", "xForm 1")                                  # 5
+        self.inputs.new("xFormSocket", "xForm 2")                                  # 6
         self.outputs.new("DriverVariableSocket", "Driver Variable")
         self.inputs[3].hide = True
         self.initialized = True
-        
-    # def update_on_socket_change(self, context):
-    #     self.update()
     
     def display_update(self, parsed_tree, context):
         from .base_definitions import get_signature_from_edited_tree
@@ -410,36 +406,31 @@ class UtilityDriverVariableNode(Node, MantisNode):
         if driver_type == 'SINGLE_PROP':
             self.inputs[1].hide = False
             self.inputs[2].hide = False
-            self.inputs[3].hide = True
+            self.inputs[3].hide = False
             self.inputs[4].hide = False
             self.inputs[5].hide = False
-            self.inputs[6].hide = False
-            self.inputs[7].hide = True
+            self.inputs[6].hide = True
         elif driver_type == 'LOC_DIFF':
             self.inputs[1].hide = True
             self.inputs[2].hide = True
             self.inputs[3].hide = True
             self.inputs[4].hide = True
-            self.inputs[5].hide = True
+            self.inputs[5].hide = False
             self.inputs[6].hide = False
-            self.inputs[7].hide = False
         elif driver_type == 'ROTATION_DIFF':
             self.inputs[1].hide = True
             self.inputs[2].hide = True
             self.inputs[3].hide = True
-            self.inputs[4].hide = True
+            self.inputs[4].hide = False
             self.inputs[5].hide = False
             self.inputs[6].hide = False
-            self.inputs[7].hide = False
         elif driver_type == 'TRANSFORMS':
             self.inputs[1].hide = True
             self.inputs[2].hide = True
             self.inputs[3].hide = False
             self.inputs[4].hide = False
             self.inputs[5].hide = False
-            self.inputs[6].hide = False
-            self.inputs[7].hide = True
-        self.inputs[3].hide = True
+            self.inputs[6].hide = True
     
 
 # TODO: make a way to edit the fCurve directly.
@@ -478,25 +469,17 @@ class UtilityDriverNode(Node, MantisNode):
         self.outputs.new("DriverSocket", "Driver")
         self.initialized = True
         
-    def update(self):
-        return
-        context = bpy.context
-        try:
-            tree = context.space_data.path[0].node_tree
-            proceed = True
-        except AttributeError:
-            proceed = False
-        if proceed:
-            from .f_nodegraph import (GetDownstreamXFormNodes, get_node_container)
-            if (node_container := get_node_container(self, context)[0]):
-                dType = node_container.evaluate_input("Driver Type")
-            else:
-                dType = self.inputs[0].default_value
-            
-            if dType == 'SCRIPTED':
-                self.inputs["Expression"].hide = False
-            else:
-                self.inputs["Expression"].hide = True
+    def display_update(self, parsed_tree, context):
+        if not self.inputs["Driver Type"].is_linked:
+            dType = self.inputs["Driver Type"].default_value
+        from .base_definitions import get_signature_from_edited_tree
+        nc = parsed_tree.get(get_signature_from_edited_tree(self, context))
+        if nc:
+            dType = nc.evaluate_input("Driver Type")
+        if dType == 'SCRIPTED':
+            self.inputs["Expression"].hide = False
+        else:
+            self.inputs["Expression"].hide = True
     
     def draw_buttons(self, context, layout):
         # return