Jelajahi Sumber

Fix: Node Groups adding extra Interface sockets

also fix: node groups appear in the wrong place
also: Node Groups could cause an execution due to missing switches and checks
now the operator sets the is_exporting on all trees in path because any tree in the
path may trigger an update.
Joseph Brandenburg 9 bulan lalu
induk
melakukan
d4f31ed88c
5 mengubah file dengan 60 tambahan dan 69 penghapusan
  1. 1 25
      __init__.py
  2. 3 0
      base_definitions.py
  3. 1 1
      blender_manifest.toml
  4. 30 30
      i_o.py
  5. 25 13
      ops_nodegroup.py

+ 1 - 25
__init__.py

@@ -29,7 +29,6 @@ classLists = [module.TellClasses() for module in [
  i_o,
  schema_definitions,
 ]]
-# lol
 classLists.append( [GenerateMantisTree] )
 #
 classes = []
@@ -38,28 +37,6 @@ while (classLists):
 
 interface_classes = []
 from bpy import app
-# if app.version[0]  == 3:
-#     for cls in [cls for cls in socket_definitions.TellClasses() if issubclass(cls, NodeSocket)]:
-#         name = cls.__name__+"Interface"
-#         from bpy.types import NodeSocketInterface
-#         def default_draw_color(self, context,):
-#             return self.color
-#         def default_draw(self, context, layout):
-#             return
-#         interface = type(
-#                       name,
-#                       (NodeSocketInterface,),
-#                       {
-#                           "color"            : cls.color,
-#                           "draw_color"       : default_draw_color,
-#                           "draw"             : default_draw,
-#                           "bl_idname"        : name,
-#                           "bl_socket_idname" : cls.__name__,
-#                       },
-#                   )
-#         interface_classes.append(interface)
-
-#     classes.extend(interface_classes)
 
 import nodeitems_utils
 from nodeitems_utils import NodeCategory, NodeItem
@@ -207,8 +184,7 @@ def init_keymaps():
 
 addon_keymaps = []
 
-# handlers!
-#annoyingly these have to be persistent
+# handlers! these have to be persistent
 from bpy.app.handlers import persistent
 @persistent
 def update_handler(scene):

+ 3 - 0
base_definitions.py

@@ -165,6 +165,9 @@ def poll_node_tree(self, object):
 
 # TODO: try to check identifiers instead of name.
 def node_group_update(node):
+    if (node.id_data.do_live_update == False) or (node.id_data.is_executing == True):
+        return
+    # note: if (node.id_data.is_exporting == True) I need to be able to update so I can make links.
     toggle_update = node.id_data.do_live_update
     node.id_data.do_live_update = False
 

+ 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.1"
+version = "0.9.2"
 name = "Mantis"
 tagline = "Mantis is a rigging nodes toolkit"
 maintainer = "Nodespaghetti <josephbburg@protonmail.com>"

+ 30 - 30
i_o.py

@@ -102,34 +102,34 @@ def export_to_json(trees, path="", write_file=True, only_selected=False):
         #     pass
             
         
-        for sock in tree.interface.items_tree:
-            sock_data={}
-
-            if sock.item_type == 'PANEL':
-                sock_data["name"] = sock.name
-                sock_data["item_type"] = sock.item_type
-                sock_data["description"] = sock.description
-                sock_data["default_closed"] = sock.default_closed
-                tree_in_out[sock.name] = sock_data
-
-            # if it is a socket....
-            else:
-                sock_parent = None
-                if sock.parent:
-                    sock_parent = sock.parent.name
-                for propname  in dir(sock):
-                    if (propname in prop_ignore) or ( callable(v) ):
-                        continue
-                    if (propname == "parent"):
-                        sock_data[propname] = sock_parent
-                        continue
-                    v = getattr(sock, propname)
-                    if not is_jsonable( v ):
-                        raise RuntimeError(f"{propname}, {type(v)}")
-                    sock_data[propname] = v
-            
-                tree_in_out[sock.identifier] = sock_data
-
+        if not only_selected: # we'll handle this later with the links
+            for sock in tree.interface.items_tree:
+                sock_data={}
+
+                if sock.item_type == 'PANEL':
+                    sock_data["name"] = sock.name
+                    sock_data["item_type"] = sock.item_type
+                    sock_data["description"] = sock.description
+                    sock_data["default_closed"] = sock.default_closed
+                    tree_in_out[sock.name] = sock_data
+
+                # if it is a socket....
+                else:
+                    sock_parent = None
+                    if sock.parent:
+                        sock_parent = sock.parent.name
+                    for propname  in dir(sock):
+                        if (propname in prop_ignore) or ( callable(v) ):
+                            continue
+                        if (propname == "parent"):
+                            sock_data[propname] = sock_parent
+                            continue
+                        v = getattr(sock, propname)
+                        if not is_jsonable( v ):
+                            raise RuntimeError(f"{propname}, {type(v)}")
+                        sock_data[propname] = v
+                
+                    tree_in_out[sock.identifier] = sock_data
 
         nodes = {}
         for n in tree.nodes:
@@ -277,12 +277,12 @@ def export_to_json(trees, path="", write_file=True, only_selected=False):
                 if (only_selected and l.from_node.select) and (not l.to_node.select):
                     # handle an output in the tree
                     add_output_node=True
-                    if not (sock_name := unique_sockets_to.get(l.to_socket.node.name+l.to_socket.identifier)):
+                    if not (sock_name := unique_sockets_to.get(l.from_socket.node.name+l.from_socket.identifier)):
                         sock_name = l.to_socket.name; name_stub = sock_name
                         used_names = list(tree_in_out.keys()); i=0
                         while sock_name in used_names:
                             sock_name=name_stub+'.'+str(i).zfill(3); i+=1
-                        unique_sockets_to[l.to_socket.node.name+l.to_socket.identifier]=sock_name
+                        unique_sockets_to[l.from_socket.node.name+l.from_socket.identifier]=sock_name
 
                     out_sock = out_sockets.get(sock_name)
                     if not out_sock:

+ 25 - 13
ops_nodegroup.py

@@ -53,13 +53,15 @@ class MantisGroupNodes(Operator):
 
     def execute(self, context):
         base_tree=context.space_data.path[-1].node_tree
-        base_tree.is_exporting = True
+        for path_item in context.space_data.path:
+            path_item.node_tree.is_exporting = True
 
         from .i_o import export_to_json, do_import
         from random import random
         grp_name = "".join([chr(int(random()*30)+35) for i in range(20)])
         trees=[base_tree]
         selected_nodes=export_to_json(trees, write_file=False, only_selected=True)
+        # this snippet of confusing indirection edits the name of the base tree in the JSON data
         selected_nodes[base_tree.name][0]["name"]=grp_name
         do_import(selected_nodes, context)
 
@@ -72,16 +74,25 @@ class MantisGroupNodes(Operator):
         delete_me = []
         all_nodes_bounding_box=[Vector((float("inf"),float("inf"))), Vector((-float("inf"),-float("inf")))]
         for n in base_tree.nodes:
-            if n.select: 
-                if n.location.x < all_nodes_bounding_box[0].x:
-                    all_nodes_bounding_box[0].x = n.location.x
-                if n.location.y < all_nodes_bounding_box[0].y:
-                    all_nodes_bounding_box[0].y = n.location.y
+            if n.select:
+                node_loc = (0,0,0)
+                if bpy.app.version <= (4, 4):
+                    node_loc = n.location
+                    parent = n.parent
+                    while (parent): # accumulate parent offset
+                        node_loc += parent.location
+                        parent = parent.parent
+                else: # there is a new location_absolute property in 4.4
+                    node_loc = n.location_absolute
+                if node_loc.x < all_nodes_bounding_box[0].x:
+                    all_nodes_bounding_box[0].x = node_loc.x
+                if node_loc.y < all_nodes_bounding_box[0].y:
+                    all_nodes_bounding_box[0].y = node_loc.y
                 #
-                if n.location.x > all_nodes_bounding_box[1].x:
-                    all_nodes_bounding_box[1].x = n.location.x
-                if n.location.y > all_nodes_bounding_box[1].y:
-                    all_nodes_bounding_box[1].y = n.location.y
+                if node_loc.x > all_nodes_bounding_box[1].x:
+                    all_nodes_bounding_box[1].x = node_loc.x
+                if node_loc.y > all_nodes_bounding_box[1].y:
+                    all_nodes_bounding_box[1].y = node_loc.y
                 delete_me.append(n)
         grp_node = base_tree.nodes.new('MantisNodeGroup')
         grp_node.node_tree = bpy.data.node_groups[grp_name]
@@ -91,9 +102,9 @@ class MantisGroupNodes(Operator):
 
         grp_node.location = Vector((all_nodes_bounding_box[0].x+200, all_nodes_bounding_box[0].lerp(all_nodes_bounding_box[1], 0.5).y))
 
-
+        # for each node in the JSON
         for n in selected_nodes[base_tree.name][2].values():
-            for s in n["sockets"].values():
+            for s in n["sockets"].values(): # for each socket in the node
                 if source := s.get("source"):
                     prGreen (s["name"], source[0], source[1])
                     base_tree_node=base_tree.nodes.get(source[0])
@@ -115,7 +126,8 @@ class MantisGroupNodes(Operator):
         for n in delete_me: base_tree.nodes.remove(n)
         base_tree.nodes.active = grp_node
 
-        base_tree.is_exporting = False
+        for path_item in context.space_data.path:
+            path_item.node_tree.is_exporting = False
         grp_node.node_tree.name = "Group_Node.000"
         return {'FINISHED'}