[Bf-blender-cvs] [dd5c352af5f] functions: More robust node tree update after changes

Jacques Lucke noreply at git.blender.org
Thu Apr 4 14:30:22 CEST 2019


Commit: dd5c352af5faec40a397e0897f35f363a03a0783
Author: Jacques Lucke
Date:   Thu Apr 4 14:26:20 2019 +0200
Branches: functions
https://developer.blender.org/rBdd5c352af5faec40a397e0897f35f363a03a0783

More robust node tree update after changes

This implements a tree wide synching procedure, that corrects
all invalid things it can find. Also, trees are updated in
the correct order, when they depend on each other.

===================================================================

M	release/scripts/startup/function_nodes/base.py
M	release/scripts/startup/function_nodes/declaration/pack_list.py
M	release/scripts/startup/function_nodes/declaration/tree_interface.py
M	release/scripts/startup/function_nodes/declaration/variadic.py
M	release/scripts/startup/function_nodes/function_tree.py
A	release/scripts/startup/function_nodes/graph.py
A	release/scripts/startup/function_nodes/inferencing.py
M	release/scripts/startup/function_nodes/nodes/function_input.py
M	release/scripts/startup/function_nodes/nodes/function_output.py
M	release/scripts/startup/function_nodes/socket_builder.py
A	release/scripts/startup/function_nodes/sync.py
A	release/scripts/startup/function_nodes/test_graph.py
A	release/scripts/startup/function_nodes/tree_data.py
D	release/scripts/startup/function_nodes/update.py

===================================================================

diff --git a/release/scripts/startup/function_nodes/base.py b/release/scripts/startup/function_nodes/base.py
index 011a9d2321f..e56fdc3eedb 100644
--- a/release/scripts/startup/function_nodes/base.py
+++ b/release/scripts/startup/function_nodes/base.py
@@ -12,25 +12,24 @@ class BaseTree:
             self.links.new(b, a)
 
     def update(self):
-        from . update import update_function_trees
-        update_function_trees()
+        from . sync import sync_trees_and_dependent_trees
+        if self.name in bpy.data.node_groups:
+            sync_trees_and_dependent_trees({self})
 
 
-class NodeStorage:
+class SocketValueStates:
     def __init__(self, node):
         self.node = node
-        builder = node.get_socket_builder()
-        self.socket_decl_map = builder.get_sockets_decl_map()
         self.input_value_storage = dict()
 
-    def store_socket_states(self):
+    def store_current(self):
         for socket in self.node.inputs:
             if not isinstance(socket, DataSocket):
                 continue
             storage_id = (socket.data_type, socket.identifier)
             self.input_value_storage[storage_id] = socket.get_state()
 
-    def try_restore_socket_states(self):
+    def try_load(self):
         for socket in self.node.inputs:
             if not isinstance(socket, DataSocket):
                 continue
@@ -39,15 +38,16 @@ class NodeStorage:
                 socket.restore_state(self.input_value_storage[storage_id])
 
 
-_storage_per_node = {}
+_decl_map_per_node = {}
+_socket_value_states_per_node = {}
 
 class BaseNode:
     search_terms = tuple()
     search_terms_only = False
 
     def init(self, context):
-        from . update import managed_update
-        with managed_update():
+        from . sync import skip_syncing
+        with skip_syncing():
             builder = self.get_socket_builder()
             builder.initialize_decls()
             builder.build()
@@ -59,52 +59,27 @@ class BaseNode:
         yield from cls.search_terms
 
     def refresh(self, context=None):
-        from . update import update_function_trees
-        self.rebuild_and_try_keep_state()
-        update_function_trees()
-
-    def rebuild_and_try_keep_state(self):
-        state = self._get_state()
-        self.rebuild()
-        self._try_set_state(state)
+        from . sync import sync_trees_and_dependent_trees
+        sync_trees_and_dependent_trees({self.tree})
+        pass
 
     def rebuild(self):
-        from . update import managed_update
+        from . sync import skip_syncing
+        with skip_syncing():
+            self.socket_value_states.store_current()
+            linkage_state = LinkageState(self)
 
-        self.storage.store_socket_states()
+            self.rebuild_fast()
 
-        with managed_update():
+            self.socket_value_states.try_load()
+            linkage_state.try_restore()
+
+    def rebuild_fast(self):
+        from . sync import skip_syncing
+        with skip_syncing():
             builder = self.get_socket_builder()
             builder.build()
-
-        self.storage.socket_decl_map = builder.get_sockets_decl_map()
-        self.storage.try_restore_socket_states()
-
-        self.on_rebuild_post()
-
-    def on_rebuild_post(self):
-        pass
-
-    def _get_state(self):
-        links_per_input = defaultdict(set)
-        links_per_output = defaultdict(set)
-
-        for link in self.tree.links:
-            if link.from_node == self:
-                links_per_output[link.from_socket.identifier].add(link.to_socket)
-            if link.to_node == self:
-                links_per_input[link.to_socket.identifier].add(link.from_socket)
-
-        return (links_per_input, links_per_output)
-
-    def _try_set_state(self, state):
-        tree = self.tree
-        for socket in self.inputs:
-            for from_socket in state[0][socket.identifier]:
-                tree.links.new(socket, from_socket)
-        for socket in self.outputs:
-            for to_socket in state[1][socket.identifier]:
-                tree.links.new(to_socket, socket)
+            _decl_map_per_node[self] = builder.get_sockets_decl_map()
 
     @property
     def tree(self):
@@ -186,14 +161,17 @@ class BaseNode:
     #########################
 
     @property
-    def storage(self) -> NodeStorage:
-        if self not in _storage_per_node:
-            _storage_per_node[self] = NodeStorage(self)
-        return _storage_per_node[self]
+    def decl_map(self):
+        if self not in _decl_map_per_node:
+            builder = self.get_socket_builder()
+            _decl_map_per_node[self] = builder.get_sockets_decl_map()
+        return _decl_map_per_node[self]
 
     @property
-    def decl_map(self):
-        return self.storage.socket_decl_map
+    def socket_value_states(self):
+        if self not in _socket_value_states_per_node:
+            _socket_value_states_per_node[self] = SocketValueStates(self)
+        return _socket_value_states_per_node[self]
 
 
 
@@ -254,3 +232,26 @@ class DataSocket(BaseSocket):
     def draw_color(self, context, node):
         from . types import type_infos
         return type_infos.get_socket_color(self.data_type)
+
+
+class LinkageState:
+    def __init__(self, node):
+        self.node = node
+        self.tree = node.tree
+        self.links_per_input = defaultdict(set)
+        self.links_per_output = defaultdict(set)
+
+        for link in self.tree.links:
+            if link.from_node == node:
+                self.links_per_output[link.from_socket.identifier].add(link.to_socket)
+            if link.to_node == node:
+                self.links_per_input[link.to_socket.identifier].add(link.from_socket)
+
+    def try_restore(self):
+        tree = self.tree
+        for socket in self.node.inputs:
+            for from_socket in self.links_per_input[socket.identifier]:
+                tree.links.new(socket, from_socket)
+        for socket in self.node.outputs:
+            for to_socket in self.links_per_output[socket.identifier]:
+                tree.links.new(to_socket, socket)
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/declaration/pack_list.py b/release/scripts/startup/function_nodes/declaration/pack_list.py
index a3cd8855812..1c8418c38e5 100644
--- a/release/scripts/startup/function_nodes/declaration/pack_list.py
+++ b/release/scripts/startup/function_nodes/declaration/pack_list.py
@@ -96,7 +96,7 @@ class PackListDecl(SocketDeclBase):
         item.state = state
         item.identifier_prefix = str(uuid.uuid4())
 
-        self.node.rebuild_and_try_keep_state()
+        self.node.rebuild()
 
         identifier = item.identifier_prefix + self.identifier_suffix
         new_socket = self.node.find_socket(identifier, is_output)
@@ -108,6 +108,9 @@ class PackListDecl(SocketDeclBase):
     def get_collection(self):
         return getattr(self.node, self.prop_name)
 
+    def get_socket_name(self, socket, index):
+        return "Pack Input " + str(index)
+
     @classmethod
     def Property(cls):
         return CollectionProperty(type=PackListPropertyGroup)
@@ -140,7 +143,7 @@ class NewPackListInputOperator(bpy.types.Operator):
         item.state = "BASE"
         item.identifier_prefix = str(uuid.uuid4())
 
-        node.rebuild_and_try_keep_state()
+        node.refresh()
 
         return {'FINISHED'}
 
@@ -159,5 +162,5 @@ class RemovePackListInputOperator(bpy.types.Operator):
         node = tree.nodes[self.node_name]
         collection = getattr(node, self.prop_name)
         collection.remove(self.index)
-        node.rebuild_and_try_keep_state()
+        node.refresh()
         return {'FINISHED'}
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/declaration/tree_interface.py b/release/scripts/startup/function_nodes/declaration/tree_interface.py
index 3dba167858c..9b1a4be5e2f 100644
--- a/release/scripts/startup/function_nodes/declaration/tree_interface.py
+++ b/release/scripts/startup/function_nodes/declaration/tree_interface.py
@@ -36,17 +36,36 @@ class TreeInterfaceDecl(SocketDeclBase):
 
     def validate(self, sockets):
         if self.in_or_out == "IN":
-            data_types = [d.data_type for d in self.tree.iter_function_inputs()]
+            return self.validate_in(sockets)
         elif self.in_or_out == "OUT":
-            data_types = [d.data_type for d in self.tree.iter_function_outputs()]
+            return self.validate_out(sockets)
         else:
             assert False
 
-        if len(data_types) != len(sockets):
+    def validate_in(self, sockets):
+        params = list(self.tree.iter_function_inputs())
+        if len(params) != len(sockets):
             return False
-        for data_type, socket in zip(data_types, sockets):
-            if data_type != socket.data_type:
+
+        for param, socket in zip(params, sockets):
+            if param.data_type != socket.data_type:
+                return False
+            if param.name != socket.name:
+                return False
+
+        return True
+
+    def validate_out(self, sockets):
+        params = list(self.tree.iter_function_outputs())
+        if len(params) != len(sockets):
+            return False
+
+        for param, socket in zip(params, sockets):
+            if param.data_type != socket.data_type:
                 return False
+            if param.name != socket.name:
+                return False
+
         return True
 
     def amount(self):
diff --git a/release/scripts/startup/function_nodes/declaration/variadic.py b/release/scripts/startup/function_nodes/declaration/variadic.py
index b3d511081d4..ccc53ae433a 100644
--- a/release/scripts/startup/function_nodes/declaration/variadic.py
+++ b/release/scripts/startup/function_nodes/declaration/variadic.py
@@ -69,7 +69,7 @@ class AnyVariadicDecl(SocketDeclBase):
         is_output = own_socket.is_output
 
         item = self.add_item(connected_type, connected_socket.get_name(connected_node))
-        self.node.rebuild_and_try_keep_state()
+        self.node.rebuild()
 
         identifier = item.identifier_prefix + self.identifier_suffix
         new_socket = self.node.find_socket(identifier, is_output)
@@ -81,6 +8

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list