fix: A bug and a crash.
The crash: When a linked loose socket was deleted, the link remained in the NodeLinkCache, and caused a crash when trying to ask the already-deleted socket for removal consent. We fixed this by reporting all socket removals to the node tree, so that links could be correctly removed independently of link-change calculation. The bug: The collection getter was cached improperly; Blender ID types can't just be saved like that. We need to search every time. Performance seems unaffected at first glance.main
parent
480679a3c0
commit
7f2bd2e752
7
TODO.md
7
TODO.md
|
@ -1,7 +1,7 @@
|
||||||
# Acute Tasks
|
# Acute Tasks
|
||||||
- [x] Implement Material Import for Maxim Data
|
- [x] Implement Material Import for Maxim Data
|
||||||
- [x] Implement Robust DataFlowKind for list-like / spectral-like composite types
|
- [x] Implement Robust DataFlowKind for list-like / spectral-like composite types
|
||||||
- [ ] Unify random node/socket caches.
|
- [x] Unify random node/socket caches.
|
||||||
- [ ] Finish the "Low-Hanging Fruit" Nodes
|
- [ ] Finish the "Low-Hanging Fruit" Nodes
|
||||||
- [ ] Move preview GN trees to the asset library.
|
- [ ] Move preview GN trees to the asset library.
|
||||||
|
|
||||||
|
@ -344,6 +344,10 @@
|
||||||
|
|
||||||
|
|
||||||
# Internal / Architecture
|
# Internal / Architecture
|
||||||
|
## IDEAS
|
||||||
|
- [ ] Socket "guarding" - let nodes influence the dynamic capabilities of sockets to prevent links (with a `self.report` explanation) to an output socket that won't yet produce a value.
|
||||||
|
- [ ] Prevents some uses of loose sockets (we want less loose sockets!)
|
||||||
|
|
||||||
## CRITICAL
|
## CRITICAL
|
||||||
- [ ] License header UI for MaxwellSimTrees, to clarify the AGPL-compatible potentially user-selected license that trees must be distributed under.
|
- [ ] License header UI for MaxwellSimTrees, to clarify the AGPL-compatible potentially user-selected license that trees must be distributed under.
|
||||||
- [ ] Document the node tree cache semantics thoroughly; it's a VERY nuanced piece of logic, and its invariants may not survive Blender versions / the author's working memory
|
- [ ] Document the node tree cache semantics thoroughly; it's a VERY nuanced piece of logic, and its invariants may not survive Blender versions / the author's working memory
|
||||||
|
@ -463,6 +467,7 @@ This is where we keep track of them for now.
|
||||||
- [ ] Cloud task socket loads folders before its node shows, which can be slow (and error prone if offline)
|
- [ ] Cloud task socket loads folders before its node shows, which can be slow (and error prone if offline)
|
||||||
- [ ] Dispersive fit is slow, which means lag on normal operations that rely on the fit result - fit computation should be integrated into the node, and the output socket should only appear when the fit is available.
|
- [ ] Dispersive fit is slow, which means lag on normal operations that rely on the fit result - fit computation should be integrated into the node, and the output socket should only appear when the fit is available.
|
||||||
- [ ] Numerical, Physical Constant is missing entries
|
- [ ] Numerical, Physical Constant is missing entries
|
||||||
|
- [ ] Numerical, Physical Constant is missing entries
|
||||||
|
|
||||||
BROKE NODES
|
BROKE NODES
|
||||||
- [ ] Numerical constant doesn't switch types
|
- [ ] Numerical constant doesn't switch types
|
||||||
|
|
|
@ -13,7 +13,6 @@ PREVIEW_COLLECTION_NAME = 'BLMaxwell Visible'
|
||||||
####################
|
####################
|
||||||
# - Global Collection Handling
|
# - Global Collection Handling
|
||||||
####################
|
####################
|
||||||
@functools.cache
|
|
||||||
def collection(collection_name: str, view_layer_exclude: bool) -> bpy.types.Collection:
|
def collection(collection_name: str, view_layer_exclude: bool) -> bpy.types.Collection:
|
||||||
# Init the "Managed Collection"
|
# Init the "Managed Collection"
|
||||||
# Ensure Collection exists (and is in the Scene collection)
|
# Ensure Collection exists (and is in the Scene collection)
|
||||||
|
|
|
@ -254,8 +254,8 @@ class MaxwellSimTree(bpy.types.NodeTree):
|
||||||
####################
|
####################
|
||||||
# - Update Methods
|
# - Update Methods
|
||||||
####################
|
####################
|
||||||
def sync_node_removed(self, node: bpy.types.Node):
|
def on_node_removed(self, node: bpy.types.Node):
|
||||||
"""Run by `Node.free()` when a node is being removed.
|
"""Run by `MaxwellSimNode.free()` when a node is being removed.
|
||||||
|
|
||||||
ONLY input socket links are removed from the NodeLink cache.
|
ONLY input socket links are removed from the NodeLink cache.
|
||||||
- `self.update()` handles link-removal from existing nodes.
|
- `self.update()` handles link-removal from existing nodes.
|
||||||
|
@ -275,6 +275,20 @@ class MaxwellSimTree(bpy.types.NodeTree):
|
||||||
self.node_link_cache.remove_link(link_ptr)
|
self.node_link_cache.remove_link(link_ptr)
|
||||||
self.node_link_cache.remove_sockets_by_link_ptr(link_ptr)
|
self.node_link_cache.remove_sockets_by_link_ptr(link_ptr)
|
||||||
|
|
||||||
|
def on_node_socket_removed(self, bl_socket: bpy.types.NodeSocket) -> None:
|
||||||
|
"""Run by `MaxwellSimNode._prune_inactive_sockets()` when a socket is being removed (but not the node).
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
bl_socket: The node socket that's about to be removed.
|
||||||
|
"""
|
||||||
|
# Compute About-To-Be-Freed Link Ptrs
|
||||||
|
link_ptrs = {link.as_pointer() for link in bl_socket.links}
|
||||||
|
|
||||||
|
if link_ptrs:
|
||||||
|
for link_ptr in link_ptrs:
|
||||||
|
self.node_link_cache.remove_link(link_ptr)
|
||||||
|
self.node_link_cache.remove_sockets_by_link_ptr(link_ptr)
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
"""Monitors all changes to the node tree, potentially responding with appropriate callbacks.
|
"""Monitors all changes to the node tree, potentially responding with appropriate callbacks.
|
||||||
|
|
||||||
|
|
|
@ -381,6 +381,7 @@ class MaxwellSimNode(bpy.types.Node):
|
||||||
|
|
||||||
A socket is considered "inactive" when it shouldn't be defined (per `self.active_socket_defs), but is present nonetheless.
|
A socket is considered "inactive" when it shouldn't be defined (per `self.active_socket_defs), but is present nonetheless.
|
||||||
"""
|
"""
|
||||||
|
node_tree = self.id_data
|
||||||
for direc in ['input', 'output']:
|
for direc in ['input', 'output']:
|
||||||
all_bl_sockets = self._bl_sockets(direc)
|
all_bl_sockets = self._bl_sockets(direc)
|
||||||
active_bl_socket_defs = self.active_socket_defs(direc)
|
active_bl_socket_defs = self.active_socket_defs(direc)
|
||||||
|
@ -400,6 +401,7 @@ class MaxwellSimNode(bpy.types.Node):
|
||||||
|
|
||||||
# Remove Sockets
|
# Remove Sockets
|
||||||
for bl_socket in bl_sockets_to_remove:
|
for bl_socket in bl_sockets_to_remove:
|
||||||
|
node_tree.on_node_socket_removed(bl_socket)
|
||||||
all_bl_sockets.remove(bl_socket)
|
all_bl_sockets.remove(bl_socket)
|
||||||
|
|
||||||
def _add_new_active_sockets(self):
|
def _add_new_active_sockets(self):
|
||||||
|
@ -964,7 +966,7 @@ class MaxwellSimNode(bpy.types.Node):
|
||||||
## The NodeTree keeps caches to for optimized event triggering.
|
## The NodeTree keeps caches to for optimized event triggering.
|
||||||
## However, ex. deleted nodes also deletes links, without cache update.
|
## However, ex. deleted nodes also deletes links, without cache update.
|
||||||
## By reporting that we're deleting the node, the cache stays happy.
|
## By reporting that we're deleting the node, the cache stays happy.
|
||||||
node_tree.sync_node_removed(self)
|
node_tree.on_node_removed(self)
|
||||||
|
|
||||||
# Invalidate Non-Persistent Cache
|
# Invalidate Non-Persistent Cache
|
||||||
## Prevents memory leak due to dangling cache entries for deleted nodes.
|
## Prevents memory leak due to dangling cache entries for deleted nodes.
|
||||||
|
|
|
@ -210,7 +210,6 @@ class MaxwellSimSocket(bpy.types.NodeSocket):
|
||||||
|
|
||||||
Returns a bool, whether or not the socket consents to the link change.
|
Returns a bool, whether or not the socket consents to the link change.
|
||||||
"""
|
"""
|
||||||
## TODO: Crash if deleting removing linked loose sockets.
|
|
||||||
if self.locked:
|
if self.locked:
|
||||||
return False
|
return False
|
||||||
if self.is_output:
|
if self.is_output:
|
||||||
|
|
Loading…
Reference in New Issue