1
0

6 Achegas febb181a66 ... 97aff31c86

Autor SHA1 Mensaxe Data
  nodespaghetti 97aff31c86 fix: selection sync error before execution hai 4 semanas
  nodespaghetti ddf732e7f6 Fix: Schema not setting interfac correctly hai 4 semanas
  nodespaghetti a18b3be4e0 fix selection sync error on empty graphs hai 4 semanas
  nodespaghetti 61a6e47f5f Overlay: Int/Float Support hai 4 semanas
  nodespaghetti 58fac0c637 Handle Quotes in overlay hai 4 semanas
  nodespaghetti d42fcb1ba7 fix: last commit used wrong node class hai 4 semanas
Modificáronse 5 ficheiros con 86 adicións e 33 borrados
  1. 47 10
      execution/readtree.py
  2. 1 1
      misc_nodes_ui.py
  3. 4 2
      timers.py
  4. 17 3
      utilities/utilities.py
  5. 17 17
      versioning.py

+ 47 - 10
execution/readtree.py

@@ -211,10 +211,16 @@ def data_from_tree(base_tree, tree_path, mContext, dummy_nodes, all_mantis_nodes
             data_from_tree(base_tree, tree_path+[mantis_node.ui_node], mContext, dummy_nodes, all_mantis_nodes, all_schema)
     return dummy_nodes, all_mantis_nodes, all_schema
 
+STRING_PADDING = 4
+overlay_valid_socket_types = [
+    "FloatSocket", "FloatPositiveSocket", "FloatFactorSocket",
+    "FloatAngleSocket", "UnsignedIntSocket", "IntSocket", "StringSocket",
+]
 # Do not use these input names as overlay keys:
 forbidden_key_names = ["",]
 forbidden_in_key_name = ['$',]
 def node_scan_overlays(node, socket_id,):
+    from ..utilities.node_common import GraphError
     interface_nodes = node.mContext.interface_nodes
     from ..utilities.utilities import get_ui_node
     ui_node = get_ui_node(node.ui_signature, node.base_tree)
@@ -242,6 +248,7 @@ def node_scan_overlays(node, socket_id,):
     # the my_interfaces list is sorted in REVERSE order of importance
     # Next, get all the overlay providers.
     name_to_id_map = {}
+    name_to_type_map = {} # Just for printing reasonable error messages
     overlay_keys = set()
     root_overlay_values = {}
     # First, we'll get the base tree's default inputs
@@ -249,38 +256,68 @@ def node_scan_overlays(node, socket_id,):
         if interface_item.item_type != "SOCKET": continue
         if interface_item.in_out != "INPUT": continue
         # NOTE this will need to change if overlays extend to other data types
-        if not hasattr(interface_item, "default_string"): continue
-        # NOTE that there may be duplicate names. Too bad!
-        root_overlay_values[interface_item.name] = interface_item.default_string
+        if hasattr(interface_item, "default_string"):
+            # NOTE that there may be duplicate names. Too bad!
+            root_overlay_values[interface_item.name] = interface_item.default_string
+        elif hasattr(interface_item, "default_int"):
+            root_overlay_values[interface_item.name] = str(interface_item.default_int).zfill(STRING_PADDING)
+        elif hasattr(interface_item, "default_float"):
+            root_overlay_values[interface_item.name] = str(interface_item.default_float).zfill(STRING_PADDING)
         overlay_keys.add(interface_item.name)
         name_to_id_map[interface_item.name] = None # don't worry about it
+        name_to_type_map[interface_item.name] = interface_item.bl_socket_idname
     for interface_node in interface_nodes.values():
         # problem: the interface node stores socket identifiers as keys
         # so in reality we need to get the group UI node and ask for its input names
         # if there is a duplicate name, too bad!
         group_ui_node = get_ui_node(interface_node.ui_signature[:-1], node.base_tree)
-        for input in group_ui_node.inputs:
-            if input.name in forbidden_key_names: continue
+        for interface_item in group_ui_node.node_tree.interface.items_tree:
+            if interface_item.item_type != 'SOCKET': continue
+            if interface_item.in_out != 'INPUT': continue
+            if interface_item.name in forbidden_key_names: continue
             for substr in forbidden_in_key_name:
-                if substr in input.name:
+                if substr in interface_item.name:
                     break
             else: # if we do not find a bad substr
-                name_to_id_map[input.name]=input.identifier
-                overlay_keys.add(input.name)
+                name_to_id_map[interface_item.name]=interface_item.identifier
+                name_to_type_map[interface_item.name] = interface_item.bl_socket_idname
+                overlay_keys.add(interface_item.name)
     # sort by reverse length so we find "CatsAndFrogs" before "Cats"
     overlay_keys = sorted(overlay_keys, key= lambda a :-1*len(a))
-    overlay_tries = value.split("$")
+    # First I need to break it into substrings based on quotation marks
+    from ..utilities.utilities import split_quoted_substrings_to_strings
+    quoted_substrings = split_quoted_substrings_to_strings(value)
+    overlay_tries = []
+    for quoted_substring in  quoted_substrings:
+        overlay_tries.extend(quoted_substring.split("$"))
     result = overlay_tries[0] # the 0th element is always before the split character
     # the reason for the difference between overlay_try and key is because
     #  we don't actually know if the $text part has a key in it
     for overlay_try in overlay_tries[1:]:
+        if not overlay_try: continue # some of these are empty
         overlay_resolved_value = "$" + overlay_try
         for key in overlay_keys:
             if key in overlay_try:
                 overlay_resolved_value = "$" + key
                 for interface in reversed(my_interfaces): # since this is reversed when we build it
                     if interface.inputs.get(actual_key := name_to_id_map.get(key)):
-                        overlay_resolved_value = overlay_try.replace(key, interface.evaluate_input(actual_key))
+                        overlay_value = None
+                        try:
+                            overlay_value = interface.evaluate_input(actual_key)
+                        except KeyError:
+                            if (socket_type := name_to_type_map.get(key) or 'NOT FOUND') in overlay_valid_socket_types:
+                                raise GraphError(f"Error: Variable {key} is not supported because it has "
+                                                 f"an invalid input in the node group: {interface.signature[:-1]}.")
+                            raise GraphError( f"Error: Variable {key} is not supported because it is "
+                                              f"type {socket_type}" )
+                            continue
+                            # NOTE that the above can also be caused by any BUG occuring in node group update
+                            # because it causes the interface to be invalid for the UI node that spawns the interface node.
+                        
+                        if isinstance(overlay_value, (float, int)):
+                            overlay_value = str(overlay_value).zfill(STRING_PADDING)
+                        assert (isinstance(overlay_value, str)), f"Error: Variable {key} is not supported because it is type {type(overlay_value)}"
+                        overlay_resolved_value = overlay_try.replace(key, overlay_value)
                         break
                 else: # we'll try the base tree
                     if base_tree_result := root_overlay_values.get(overlay_try):

+ 1 - 1
misc_nodes_ui.py

@@ -243,7 +243,7 @@ class UtilityMatrixFromCurve(Node, MantisMiscNode):
             elif mode == 'FACTOR' and template.category == 'factor':
                 self.inputs[template.name].hide=False
 
-class UtilityPointFromCurve(Node, MantisUINode):
+class UtilityPointFromCurve(Node, MantisMiscNode):
     """Gets a point from a curve."""
     bl_idname = "UtilityPointFromCurve"
     bl_label = "Point from Curve"

+ 4 - 2
timers.py

@@ -83,12 +83,14 @@ def timer_update_selection_sync():
                 if not space.path:
                     return SELECTION_POLL_RATE # empty tree
                 root_tree = space.path[0].node_tree
-                parsed_tree = root_tree.parsed_tree
-                tree_path = [path_item.node_tree for path_item in space.path]
                 if root_tree is None:
                     return SELECTION_POLL_RATE
                 if root_tree.bl_idname != 'MantisTree':
                     return SELECTION_POLL_RATE
+                tree_path = [path_item.node_tree for path_item in space.path]
+                if len(tree_path[-1].nodes) == 0:
+                    return SELECTION_POLL_RATE # empty graph
+                parsed_tree = root_tree.parsed_tree
                 active_ui_signature = (get_signature_from_space(tree_path[-1].nodes.active, space))
                 for n in tree_path[-1].nodes:
                     if n.bl_idname not in WATCH_FOR_SELECTION: continue

+ 17 - 3
utilities/utilities.py

@@ -100,6 +100,15 @@ def tree_from_mantis_node(sig, base_tree):
 def get_ui_node(sig, base_tree):
     return tree_from_mantis_node(sig, base_tree).nodes.get( sig[-1] )
 
+# Function for splitting up 
+def split_quoted_substrings_to_strings(text):
+    import re
+    pattern = r'''(?:"([^"]*)"|'([^']*)'|([^"']+))'''
+    substrings = [
+        next(group for group in match.groups() if group is not None)
+        for match in re.finditer(pattern, text)
+    ]
+    return substrings
 
 ##################################################################################################
 # groups and changing sockets -- this is used extensively by Schema.
@@ -306,9 +315,16 @@ def update_interface(interface, name, in_out, sock_type, parent_name):
             from ..versioning import workaround_4_5_0_interface_update
             socket = workaround_4_5_0_interface_update(tree=interface.id_data, name=name, in_out=in_out,
                                                        sock_type=sock_type, parent_name=parent_name, do_parent=True)
+        match parent_name:
+            case "Connection":
+                socket.is_connection=True
+            case "Array":
+                socket.is_array=True
+        
         if parent_name == 'Connection':
             in_out = 'OUTPUT' if in_out == 'INPUT' else 'INPUT' # flip this make sure connections always do both
-            interface.new_socket(name=name,in_out=in_out, socket_type=sock_type, parent=interface_parent)
+            other_socket = interface.new_socket(name=name,in_out=in_out, socket_type=sock_type, parent=interface_parent)
+            other_socket.is_connection = True
         return socket
     else:
         raise RuntimeError(wrapRed("Cannot add interface item to tree without specifying type."))
@@ -344,8 +360,6 @@ def relink_socket_map_add_socket(node, socket_collection, item,  in_out=None,):
                 s.default_value = default_value
             else: # TODO: make this work with color sets.
                 raise Warning("WARN: Not yet implemented: default values for color sets.")
-                
-
     if read_schema_type(item) == 'Array': s.display_shape = 'SQUARE_DOT'
     elif node.bl_idname in ['MantisSchemaGroup'] and read_schema_type(item) == 'Constant':
         s.display_shape='CIRCLE_DOT'

+ 17 - 17
versioning.py

@@ -523,20 +523,20 @@ def add_new_display_features_v0_13_5(*args, **kwargs):
                 node.is_updating = False
         tree.do_live_update = live_updates
 
-def up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix(*args, **kwargs):
-    node = kwargs['node']
-    node.is_updating = True
-    do_live_updates = node.id_data.do_live_updates
-    node.id_data.do_live_updates = False
-    # new re_init keyword should use socket template to automate the update.
-    prGreen("THIS ONE HERE")
-    print (node.id_data.name, node.name)
-    print (node.inputs.keys())
-    if "Mode" not in node.inputs.keys(): # just check here to see if it is needed.
-        prOrange("DOING THE THING BRO")
-        node.init_sockets(node.__class__.socket_templates, re_init=True)
-    node.id_data.do_live_updates = do_live_updates
-    node.is_updating = False
+# def up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix(*args, **kwargs):
+#     node = kwargs['node']
+#     node.is_updating = True
+#     do_live_updates = node.id_data.do_live_updates
+#     node.id_data.do_live_updates = False
+#     # new re_init keyword should use socket template to automate the update.
+#     prGreen("THIS ONE HERE")
+#     print (node.id_data.name, node.name)
+#     print (node.inputs.keys())
+#     if "Mode" not in node.inputs.keys(): # just check here to see if it is needed.
+#         prOrange("DOING THE THING BRO")
+#         node.init_sockets(node.__class__.socket_templates, re_init=True)
+#     node.id_data.do_live_updates = do_live_updates
+#     node.is_updating = False
 
 # versioning tasks that involve Blender versions rather than Mantis versions:
 error_description_4_5_0_LTS = 'There is a bug in Blender 4.5.0 LTS, that is why these sockets are blue.'\
@@ -576,9 +576,9 @@ versioning_tasks = [
            update_fcurve_and_armature_node_to_multi_socket, ['node']),
     (['MantisTree', 'SchemaTree'], fix_bbone_default_scale_in_and_out, ['tree']),
     (['MantisTree', 'SchemaTree'], add_new_display_features_v0_13_5, ['tree']),
-    (['UtilityMatrixFromCurve', 'UtilityMatrixCompose'],
-       up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix,
-     ['node',], ),
+    # (['UtilityMatrixFromCurve', 'UtilityMatrixCompose'],
+    #    up_0_13_5_modes_for_matrix_from_curve_and_compose_matrix,
+    #  ['node',], ),
 ]