[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