Browse Source

Cleanup in I/O

this commit also changes the way new sockets are added to always make them directly
except for Armature Link nodes.
Joseph Brandenburg 10 tháng trước cách đây
mục cha
commit
81ed53b133
1 tập tin đã thay đổi với 67 bổ sung133 xóa
  1. 67 133
      i_o.py

+ 67 - 133
i_o.py

@@ -9,6 +9,10 @@ from mathutils import  Vector
 
 from .base_definitions import NODES_REMOVED, SOCKETS_REMOVED
 
+add_inputs_bl_idnames = [
+    "UtilityDriver", "UtilityFCurve", "DeformerMorphTargetDeform",
+    "MantisSchemaGroup", "LinkArmature",
+    ]
 
 # this works but it is really ugly and probably quite inneficient
 # TODO: make hotkeys for export and import and reload from file
@@ -62,6 +66,52 @@ def fix_custom_parameter(n, property_definition, ):
     
     
 
+def get_socket_data(socket):
+    socket_data = {}
+    socket_data["name"] = socket.name
+    socket_data["bl_idname"] = socket.bl_idname
+    socket_data["is_output"] = socket.is_output
+    socket_data["is_multi_input"] = socket.is_multi_input
+
+    # if socket.bl_idname == 'TransformSpaceSocket':
+    #     prGreen(socket.default_value)
+    
+    # here is where we'll handle a socket_data'socket special data
+    if socket.bl_idname == "EnumMetaBoneSocket":
+        socket_data["bone"] = socket.bone
+    if socket.bl_idname in ["EnumMetaBoneSocket", "EnumMetaRigSocket", "EnumCurveSocket"]:
+        if sp := socket.get("search_prop"): # may be None
+            socket_data["search_prop"] = sp.name # this is an object.
+    #
+
+    # v = socket.get("default_value") # this doesn't seem to work, see below
+    if hasattr(socket, "default_value"):
+        v = socket.default_value
+    else:
+        v = None
+    v_type = type(v)
+    if v is None:
+        return socket_data # we don't need to store this.
+    if not is_jsonable(v):
+        v = tuple(v)
+    if not is_jsonable(v):
+        raise RuntimeError(f"Error serializing data in {socket.node.name}::{socket.name} for value of type {v_type}")
+    socket_data["default_value"] = v
+    # at this point we can get the custom parameter ui hints if we want
+    if not socket.is_output:
+        # try and get this data
+        if v := getattr(socket,'min', None):
+            socket_data["min"] = v
+        if v := getattr(socket,'max', None):
+            socket_data["max"] = v
+        if v := getattr(socket,'soft_min', None):
+            socket_data["soft_min"] = v
+        if v := getattr(socket,'soft_max', None):
+            socket_data["soft_max"] = v
+        if v := getattr(socket,'description', None):
+            socket_data["description"] = v
+    return socket_data
+    #
 
 def export_to_json(trees, path="", write_file=True, only_selected=False):
     # ignore these because they are either unrelated python stuff or useless or borked
@@ -182,68 +232,12 @@ def export_to_json(trees, path="", write_file=True, only_selected=False):
                     node_props[propname] = tuple(location_acc)
                     # this works!
 
-                    # n.parent = None
-                
-                # if propname == "location":
-                #     print (v, n.location)
-                # if parent:
-                #     n.parent = parent
-            # now we need to get the sockets...
-
-            # WHY IS THIS FUNCTION DEFINED IN THIS SCOPE?
-            def socket_data(s):
-                socket = {}
-                socket["name"] = s.name
-                socket["bl_idname"] = s.bl_idname
-                socket["is_output"] = s.is_output
-                socket["is_multi_input"] = s.is_multi_input
-
-                # if s.bl_idname == 'TransformSpaceSocket':
-                #     prGreen(s.default_value)
-                
-                # here is where we'll handle a socket's special data
-                if s.bl_idname == "EnumMetaBoneSocket":
-                    socket["bone"] = s.bone
-                if s.bl_idname in ["EnumMetaBoneSocket", "EnumMetaRigSocket", "EnumCurveSocket"]:
-                    if sp := s.get("search_prop"): # may be None
-                        socket["search_prop"] = sp.name # this is an object.
-                #
-
-                # v = s.get("default_value") # this doesn't seem to work, see below
-                if hasattr(s, "default_value"):
-                    v = s.default_value
-                else:
-                    v = None
-                v_type = type(v)
-                if v is None:
-                    return socket # we don't need to store this.
-                if not is_jsonable(v):
-                    v = tuple(v)
-                if not is_jsonable(v):
-                    raise RuntimeError(f"Error serializing data in {s.node.name}::{s.name} for value of type {v_type}")
-                socket["default_value"] = v
-                # at this point we can get the custom parameter ui hints if we want
-                if not s.is_output:
-                    # try and get this data
-                    if v := getattr(s,'min', None):
-                        socket["min"] = v
-                    if v := getattr(s,'max', None):
-                        socket["max"] = v
-                    if v := getattr(s,'soft_min', None):
-                        socket["soft_min"] = v
-                    if v := getattr(s,'soft_max', None):
-                        socket["soft_max"] = v
-                    if v := getattr(s,'description', None):
-                        socket["description"] = v
-                return socket
-                #
-
             for i, s in enumerate(n.inputs):
-                socket = socket_data(s)
+                socket = get_socket_data(s)
                 socket["index"]=i
                 sockets[s.identifier] = socket
             for i, s in enumerate(n.outputs):
-                socket = socket_data(s)
+                socket = get_socket_data(s)
                 socket["index"]=i
                 sockets[s.identifier] = socket
             
@@ -285,8 +279,6 @@ def export_to_json(trees, path="", write_file=True, only_selected=False):
                 raise RuntimeError(wrapRed(f"Error saving index of socket: {problem}"))
             g, h = l.from_socket.name, l.to_socket.name
 
-            # print (f"{a}:{b} --> {c}:{d})")
-            # this data is good enough
             if base_tree:
                 if (only_selected and l.from_node.select) and (not l.to_node.select):
                     # handle an output in the tree
@@ -391,6 +383,7 @@ def export_to_json(trees, path="", write_file=True, only_selected=False):
             nodes["MANTIS_AUTOGEN_GROUP_OUTPUT"]=out_node
 
         export_data[tree.name] = (tree_info, tree_in_out, nodes, links,) # f_curves)
+    
     import json
 
     if not write_file:
@@ -412,13 +405,18 @@ def do_import_from_file(filepath, context):
     for tree in all_trees:
         tree.is_exporting = True
         tree.do_live_update = False
+    
+    def do_cleanup(tree):
+        tree.is_exporting = False
+        tree.do_live_update = True
+        tree.prevent_next_exec = True
 
     with open(filepath, 'r', encoding='utf-8') as f:
         data = json.load(f)
         do_import(data,context)
 
         for tree in all_trees:
-            tree.do_live_update = True
+            do_cleanup(tree)
 
         tree = bpy.data.node_groups[list(data.keys())[-1]]
         try:
@@ -429,9 +427,7 @@ def do_import_from_file(filepath, context):
     # otherwise:
     # repeat this because we left the with, this is bad and ugly but I don't care
     for tree in all_trees:
-        tree.is_exporting = False
-        tree.do_live_update = True
-        tree.prevent_next_exec = True
+            do_cleanup(tree)
     return {'CANCELLED'}
 
 def do_import(data, context):
@@ -490,7 +486,6 @@ def do_import(data, context):
         # Go BACK through and set the index/position now that all items exist.
         interface_sockets.sort(key=lambda a : a[1])
         for (socket, position) in interface_sockets:
-            print (socket.name, position)
             tree.interface.move(socket, position)
         
     # Now go and do nodes and links
@@ -558,36 +553,16 @@ def do_import(data, context):
                             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}):
-                                    bpy.ops.mantis.driver_node_add_variable()
-                                socket = n.inputs[int(s_val["index"])]
-                            elif n.bl_idname == "UtilityFCurve":
-                                with bpy.context.temp_override(**{'node':n}):
-                                    bpy.ops.mantis.fcurve_node_add_kf()
-                                socket = n.inputs[int(s_val["index"])]
-                            elif n.bl_idname == "MantisSchemaGroup":
+                            if n.bl_idname in add_inputs_bl_idnames:
                                 socket = n.inputs.new(s_val["bl_idname"], s_val["name"], identifier=s_id, use_multi_input=s_val["is_multi_input"])
-                                # for k,v in s_val.items():
-                                #     print(f"{k}:{v}")
-                                # print (s_id)
-                                # raise NotImplementedError(s_val["is_multi_input"])
                             elif n.bl_idname in ["NodeGroupOutput"]:
-                                # print (len(n.inputs), len(n.outputs))
-                                pass
-                            elif n.bl_idname == "LinkArmature":
-                                with bpy.context.temp_override(**{'node':n}):
-                                    bpy.ops.mantis.link_armature_node_add_target()
-                                socket = n.inputs[int(s_val["index"])]
-                            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)
+                                pass # this is dealt with separately
                             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 ['']
                         else: # most of the time
                             socket = n.inputs[int(s_val["index"])]
                 except IndexError:
@@ -596,14 +571,7 @@ def do_import(data, context):
                         is_output = "output" if {s_val["is_output"]} else "input"
                         prRed(s_val, type(s_val))
                         raise RuntimeError(is_output, n.name, s_val["name"], s_id, len(n.inputs))
-
                 
-#                if propslist["bl_idname"] == "UtilityMetaRig":#and i == 0:
-#                    pass#prRed (i, s_id, s_val)
-#                if propslist["bl_idname"] == "UtilityMetaRig":# and i > 0:
-#                       prRed("Not Found: %s" % (s_id))
-#                       prOrange(propslist["sockets"][s_id])
-#                       socket = fix_custom_parameter(n, propslist["sockets"][s_id]
                 for s_p, s_v in s_val.items():
                     if s_p not in ["default_value"]:
                         if s_p == "search_prop" and n.bl_idname == 'UtilityMetaRig':
@@ -622,20 +590,15 @@ def do_import(data, context):
                     try:
                         setattr(socket, s_p , s_v)
                     except TypeError as e:
-                        prRed("Can't set socket due to type mismatch: ", socket, s_p, s_v)
+                        prRed("Can't set socket due to type mismatch: ", n.name, socket.name, s_p, s_v)
                         # raise e
                     except ValueError as e:
-                        prRed("Can't set socket due to type mismatch: ", socket, s_p, s_v)
+                        prRed("Can't set socket due to type mismatch: ", n.name,  socket.name, s_p, s_v)
                         # raise e
                     except AttributeError as e:
                         prWhite("Tried to write a read-only property, ignoring...")
                         prWhite(f"{socket.node.name}[{socket.name}].{s_p} is read only, cannot set value to {s_v}")
-                        # raise e
-                # not sure if this is true:
-                    # this can find properties that aren't node in/out
-                    # we should also be checking those above actually
-                # TODO:
-                # find out why "Bone hide" not being found
+
             for p, v in propslist.items():
                 if p == "sockets": # it's the sockets dict
                     continue
@@ -653,12 +616,6 @@ def do_import(data, context):
                 except Exception as e:
                     print (p)
                     raise e
-#        raise NotImplementedError
-
-        
-        
-#        for k,v in tree_sock_id_map.items():
-#            print (wrapGreen(k), "   ", wrapPurple(v))
         
         for l in links:
 
@@ -668,14 +625,6 @@ def do_import(data, context):
             name1=l[6]
             name2=l[7]
             
-            # prWhite(l[0], l[1], " --> ", l[2], l[3])
-            
-            # l has...
-            # node 1
-            # identifier 1
-            # node 2
-            # identifier 2
-            
             # if the from/to socket or node has been removed, continue
             from_node = tree.nodes.get(l[0])
             if not from_node:
@@ -702,8 +651,6 @@ def do_import(data, context):
             else: # we can raise a runtime error here actually
                 from_sock = None
                 
-                
-            
             to_node = tree.nodes[l[2]]
             if hasattr(to_node, "node_tree"):
                 try:
@@ -713,15 +660,9 @@ def do_import(data, context):
                     id2 = None
             elif to_node.bl_idname in ["NodeGroupOutput"]:
                 id2 = tree_sock_id_map.get(l[3])
-#                prPurple(to_node.name)
-#                for inp in to_node.inputs:
-#                    prPurple(inp.name, inp.identifier)
-#                prOrange (l[3], id2)
             elif to_node.bl_idname in ["SchemaArrayOutput", "SchemaConstOutput", "SchemaOutgoingConnection"]:
                 # try the index instead
                 id2 = to_node.inputs[l[5]].identifier
-                # try to get by name
-                #id2 = to_node.inputs[name2]
 
             for to_sock in to_node.inputs:
                 if to_sock.identifier == id2: break
@@ -738,6 +679,7 @@ def do_import(data, context):
                     prRed (f"Failed: {l[0]}:{l[1]} --> {l[2]}:{l[3]}")
                     prRed (f" got node: {from_node.name}, {to_node.name}")
                     prRed (f" got socket: {from_sock}, {to_sock}")
+                    prOrange(to_node.inputs.keys())
 
                     if from_sock is None:
                         prOrange ("Candidates...")
@@ -759,17 +701,10 @@ def do_import(data, context):
             if (n := tree.nodes.get(name)) and (p := tree.nodes.get(p)):
                 n.parent = p
             # otherwise the frame node is missing because it was not included in the data e.g. when grouping nodes.
-
+        
         tree.is_executing = False
         tree.do_live_update = True
         
-        # try:
-        #     tree=context.space_data.path[0].node_tree
-        #     tree.update_tree(context)
-        # except: #update tree can cause all manner of errors
-        #     pass
-
-
 
 
 
@@ -885,7 +820,6 @@ class MantisImportNodeTree(Operator, ImportHelper):
         maxlen=255,  # Max internal buffer length, longer would be clamped.
     )
 
-
     def execute(self, context):
         return do_import_from_file(self.filepath, context)