From 6d30bff36ead3309b0ec63a35013768d5c78e649 Mon Sep 17 00:00:00 2001 From: Durman Date: Sun, 14 Feb 2021 09:42:18 +0400 Subject: [PATCH 1/8] Add main node logic --- index.md | 1 + nodes/object_nodes/blender_data_list.py | 132 ++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 nodes/object_nodes/blender_data_list.py diff --git a/index.md b/index.md index 522652c5f1..615e1c3870 100644 --- a/index.md +++ b/index.md @@ -622,6 +622,7 @@ SvPointOnMeshNodeMK2 SvOBJRayCastNodeMK2 SvSCNRayCastNodeMK2 + SvBlenderDataListNode ## Scene SvObjectsNodeMK3 diff --git a/nodes/object_nodes/blender_data_list.py b/nodes/object_nodes/blender_data_list.py new file mode 100644 index 0000000000..852f19a6de --- /dev/null +++ b/nodes/object_nodes/blender_data_list.py @@ -0,0 +1,132 @@ +# This file is part of project Sverchok. It's copyrighted by the contributors +# recorded in the version control history of the file, available from +# its original location https://github.com/nortikin/sverchok/commit/master +# +# SPDX-License-Identifier: GPL3 +# License-Filename: LICENSE + +import bpy + +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.utils.handle_blender_data import BPYPointers +from sverchok.data_structure import fixed_iter, repeat_last, throttle_tree_update, updateNode + + +class SvBlenderDataPointers(bpy.types.PropertyGroup): + + def update(self, context): + pass + + __annotations__ = dict() + for enum in BPYPointers: + __annotations__[enum.name.lower()] = bpy.props.PointerProperty( + type=enum.value, update=lambda s, c: updateNode(c.node, c)) + + +class SvAddDataBlock(bpy.types.Operator): + bl_label = "Add data block" + bl_idname = "sverchok.add_data_block" + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + def execute(self, context): + node = context.node + node.blender_data.add() + return {'FINISHED'} + + +class SvRemoveDataBlock(bpy.types.Operator): + bl_label = "Remove data block" + bl_idname = "sverchok.remove_data_block" + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + item_index: bpy.props.IntProperty() + + def execute(self, context): + node = context.node + node.blender_data.remove(self.item_index) + updateNode(node, context) + return {'FINISHED'} + + +class SvMoveDataBlock(bpy.types.Operator): + bl_label = "Move data block" + bl_idname = "sverchok.move_data_block" + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + item_index: bpy.props.IntProperty() + up_direction: bpy.props.BoolProperty() + + def execute(self, context): + node = context.node + next_index = self.item_index + (-1 if self.up_direction else 1) + next_index = min(next_index, len(node.blender_data) - 1) + next_index = max(0, next_index) + node.blender_data.move(self.item_index, next_index) + updateNode(node, context) + return {'FINISHED'} + + +class UI_UL_SvBlenderDataList(bpy.types.UIList): + def draw_item(self, context, layout, node, item, icon, active_data, active_propname, index, flt_flag): + row = layout.row(align=True) + data_type = getattr(BPYPointers, node.data_type.upper()) + + row.prop_search(item, node.data_type, bpy.data, data_type.collection_name, text='') + + if node.edit_mode: + + up = row.operator(SvMoveDataBlock.bl_idname, text='', icon='TRIA_UP') + up.item_index = index + up.up_direction = True + + down = row.operator(SvMoveDataBlock.bl_idname, text='', icon='TRIA_DOWN') + down.item_index = index + down.up_direction = False + + remove = row.operator(SvRemoveDataBlock.bl_idname, text='', icon='REMOVE') + remove.item_index = index + + def draw_filter(self, context, layout): + pass + + +class SvBlenderDataListNode(SverchCustomTreeNode, bpy.types.Node): + """ + Triggers: list + Tooltip: + """ + bl_idname = 'SvBlenderDataListNode' + bl_label = 'Blender data' + bl_icon = 'ALIGN_TOP' + + data_type: bpy.props.EnumProperty(items=[(e.name.lower(), e.name, '') for e in BPYPointers], name='Type', + update=updateNode) + edit_mode: bpy.props.BoolProperty(name='Edit list') + blender_data: bpy.props.CollectionProperty(type=SvBlenderDataPointers) + selected: bpy.props.IntProperty() + + def sv_init(self, context): + self.outputs.new('SvObjectSocket', 'Object') # todo change label? + self.blender_data.add() + + def draw_buttons(self, context, layout): + col = layout.column() + col.prop(self, 'data_type') + row = col.row(align=True) + row.prop(self, 'edit_mode') + row.operator(SvAddDataBlock.bl_idname, text='+') + layout.template_list(UI_UL_SvBlenderDataList.__name__, "blender_data", self, "blender_data", self, "selected") + + def process(self): + self.outputs['Object'].sv_set( + [getattr(p, self.data_type) for p in self.blender_data if getattr(p, self.data_type)]) + + +classes = [ + SvBlenderDataPointers, + SvAddDataBlock, SvRemoveDataBlock, SvMoveDataBlock, # operators + UI_UL_SvBlenderDataList, + SvBlenderDataListNode] + + +register, unregister = bpy.utils.register_classes_factory(classes) From 2b718f025b9b4c61ad61e6de990a2806ba003af6 Mon Sep 17 00:00:00 2001 From: Durman Date: Sun, 14 Feb 2021 09:43:43 +0400 Subject: [PATCH 2/8] Add mapping of collection names for using in UI lists --- utils/handle_blender_data.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/utils/handle_blender_data.py b/utils/handle_blender_data.py index e14a387c61..ed1db98dbe 100644 --- a/utils/handle_blender_data.py +++ b/utils/handle_blender_data.py @@ -317,6 +317,24 @@ def collection(self): } return collections[self] + @property + def collection_name(self) -> str: + """Returns name of collection of current pointer""" + names = { + BPYPointers.OBJECT: 'objects', + BPYPointers.MESH: 'meshes', + BPYPointers.NODE_TREE: 'node_groups', + BPYPointers.MATERIAL: 'materials', + BPYPointers.COLLECTION: 'collections', + BPYPointers.TEXT: 'texts', + BPYPointers.LIGHT: 'lights', + BPYPointers.IMAGE: 'images', + BPYPointers.TEXTURE: 'textures', + BPYPointers.VECTOR_FONT: 'curves', + BPYPointers.GREASE_PENCIL: 'grease_pencils' + } + return names[self] + @property def type(self): """Return Blender type of the pointer""" From d63716e3069e2926f272261e0eb2dd48ec696cd8 Mon Sep 17 00:00:00 2001 From: Durman Date: Sun, 14 Feb 2021 11:05:26 +0400 Subject: [PATCH 3/8] refactoring of operations with the node list --- nodes/object_nodes/blender_data_list.py | 81 ++++++++++++------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/nodes/object_nodes/blender_data_list.py b/nodes/object_nodes/blender_data_list.py index 852f19a6de..9338707065 100644 --- a/nodes/object_nodes/blender_data_list.py +++ b/nodes/object_nodes/blender_data_list.py @@ -9,61 +9,56 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.utils.handle_blender_data import BPYPointers -from sverchok.data_structure import fixed_iter, repeat_last, throttle_tree_update, updateNode +from sverchok.data_structure import updateNode class SvBlenderDataPointers(bpy.types.PropertyGroup): - def update(self, context): - pass - __annotations__ = dict() for enum in BPYPointers: __annotations__[enum.name.lower()] = bpy.props.PointerProperty( type=enum.value, update=lambda s, c: updateNode(c.node, c)) -class SvAddDataBlock(bpy.types.Operator): - bl_label = "Add data block" - bl_idname = "sverchok.add_data_block" +class SvEditDataBlockList(bpy.types.Operator): + bl_label = "Edit data block list" + bl_idname = "sverchok.edit_data_block_list" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} - def execute(self, context): - node = context.node - node.blender_data.add() - return {'FINISHED'} - - -class SvRemoveDataBlock(bpy.types.Operator): - bl_label = "Remove data block" - bl_idname = "sverchok.remove_data_block" - bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + operations = ['add', 'remove', 'move_up', 'move_down', 'clear'] + operation: bpy.props.EnumProperty(items=[(i, i, '') for i in operations]) - item_index: bpy.props.IntProperty() + item_index: bpy.props.IntProperty() # required for some operations def execute(self, context): node = context.node - node.blender_data.remove(self.item_index) + + if self.operation == 'add': + node.blender_data.add() + elif self.operation == 'remove': + node.blender_data.remove(self.item_index) + elif self.operation == 'move_up': + next_index = max(0, self.item_index - 1) + node.blender_data.move(self.item_index, next_index) + elif self.operation == 'move_down': + next_index = min(self.item_index + 1, len(node.blender_data) - 1) + node.blender_data.move(self.item_index, next_index) + elif self.operation == 'clear': + node.blender_data.clear() + updateNode(node, context) return {'FINISHED'} -class SvMoveDataBlock(bpy.types.Operator): - bl_label = "Move data block" - bl_idname = "sverchok.move_data_block" - bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} +class SvDataBlockListOptions(bpy.types.Menu): + bl_idname = "OBJECT_MT_data_block_list_options" + bl_label = "Options" - item_index: bpy.props.IntProperty() - up_direction: bpy.props.BoolProperty() + def draw(self, context): + layout = self.layout - def execute(self, context): - node = context.node - next_index = self.item_index + (-1 if self.up_direction else 1) - next_index = min(next_index, len(node.blender_data) - 1) - next_index = max(0, next_index) - node.blender_data.move(self.item_index, next_index) - updateNode(node, context) - return {'FINISHED'} + op = layout.operator(SvEditDataBlockList.bl_idname, text='Clear the list') + op.operation = 'clear' class UI_UL_SvBlenderDataList(bpy.types.UIList): @@ -75,15 +70,16 @@ def draw_item(self, context, layout, node, item, icon, active_data, active_propn if node.edit_mode: - up = row.operator(SvMoveDataBlock.bl_idname, text='', icon='TRIA_UP') + up = row.operator(SvEditDataBlockList.bl_idname, text='', icon='TRIA_UP') + up.operation = 'move_up' up.item_index = index - up.up_direction = True - down = row.operator(SvMoveDataBlock.bl_idname, text='', icon='TRIA_DOWN') + down = row.operator(SvEditDataBlockList.bl_idname, text='', icon='TRIA_DOWN') + down.operation = 'move_down' down.item_index = index - down.up_direction = False - remove = row.operator(SvRemoveDataBlock.bl_idname, text='', icon='REMOVE') + remove = row.operator(SvEditDataBlockList.bl_idname, text='', icon='REMOVE') + remove.operation = 'remove' remove.item_index = index def draw_filter(self, context, layout): @@ -96,7 +92,7 @@ class SvBlenderDataListNode(SverchCustomTreeNode, bpy.types.Node): Tooltip: """ bl_idname = 'SvBlenderDataListNode' - bl_label = 'Blender data' + bl_label = 'Blender data list' bl_icon = 'ALIGN_TOP' data_type: bpy.props.EnumProperty(items=[(e.name.lower(), e.name, '') for e in BPYPointers], name='Type', @@ -114,7 +110,9 @@ def draw_buttons(self, context, layout): col.prop(self, 'data_type') row = col.row(align=True) row.prop(self, 'edit_mode') - row.operator(SvAddDataBlock.bl_idname, text='+') + op = row.operator(SvEditDataBlockList.bl_idname, text='+') + op.operation = 'add' + row.menu(SvDataBlockListOptions.bl_idname, icon='DOWNARROW_HLT', text="") layout.template_list(UI_UL_SvBlenderDataList.__name__, "blender_data", self, "blender_data", self, "selected") def process(self): @@ -124,7 +122,8 @@ def process(self): classes = [ SvBlenderDataPointers, - SvAddDataBlock, SvRemoveDataBlock, SvMoveDataBlock, # operators + SvEditDataBlockList, + SvDataBlockListOptions, UI_UL_SvBlenderDataList, SvBlenderDataListNode] From ed5840a348feec94a5b3dfc68f6e5da01bae4b7a Mon Sep 17 00:00:00 2001 From: Durman Date: Sun, 14 Feb 2021 11:22:31 +0400 Subject: [PATCH 4/8] add animation options --- nodes/object_nodes/blender_data_list.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nodes/object_nodes/blender_data_list.py b/nodes/object_nodes/blender_data_list.py index 9338707065..d624cac7b5 100644 --- a/nodes/object_nodes/blender_data_list.py +++ b/nodes/object_nodes/blender_data_list.py @@ -9,6 +9,7 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.utils.handle_blender_data import BPYPointers +from sverchok.utils.nodes_mixins.sv_animatable_nodes import SvAnimatableNode from sverchok.data_structure import updateNode @@ -56,10 +57,15 @@ class SvDataBlockListOptions(bpy.types.Menu): def draw(self, context): layout = self.layout + node = context.node op = layout.operator(SvEditDataBlockList.bl_idname, text='Clear the list') op.operation = 'clear' + layout.separator() + layout.prop(node, 'is_animatable') + layout.prop(node, 'refresh', toggle=False, icon='FILE_REFRESH') + class UI_UL_SvBlenderDataList(bpy.types.UIList): def draw_item(self, context, layout, node, item, icon, active_data, active_propname, index, flt_flag): @@ -86,7 +92,7 @@ def draw_filter(self, context, layout): pass -class SvBlenderDataListNode(SverchCustomTreeNode, bpy.types.Node): +class SvBlenderDataListNode(SvAnimatableNode, SverchCustomTreeNode, bpy.types.Node): """ Triggers: list Tooltip: From 424456a2217ad4fad6617c808a9b524f949b9cea Mon Sep 17 00:00:00 2001 From: Durman Date: Mon, 22 Feb 2021 15:00:54 +0400 Subject: [PATCH 5/8] move the node to `scene` category --- index.md | 2 +- nodes/{object_nodes => scene}/blender_data_list.py | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename nodes/{object_nodes => scene}/blender_data_list.py (100%) diff --git a/index.md b/index.md index 615e1c3870..e37df081d3 100644 --- a/index.md +++ b/index.md @@ -622,7 +622,6 @@ SvPointOnMeshNodeMK2 SvOBJRayCastNodeMK2 SvSCNRayCastNodeMK2 - SvBlenderDataListNode ## Scene SvObjectsNodeMK3 @@ -640,6 +639,7 @@ SvTimerNode --- SvDupliInstancesMK4 + SvBlenderDataListNode ## Objects SvVertexGroupNodeMK2 diff --git a/nodes/object_nodes/blender_data_list.py b/nodes/scene/blender_data_list.py similarity index 100% rename from nodes/object_nodes/blender_data_list.py rename to nodes/scene/blender_data_list.py From a6e574c4440e87e3ea82a5dde649117843d88f98 Mon Sep 17 00:00:00 2001 From: Durman Date: Tue, 23 Feb 2021 08:25:31 +0400 Subject: [PATCH 6/8] add new buttons for grabbing objects from scene --- nodes/scene/blender_data_list.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/nodes/scene/blender_data_list.py b/nodes/scene/blender_data_list.py index d624cac7b5..323a7578ae 100644 --- a/nodes/scene/blender_data_list.py +++ b/nodes/scene/blender_data_list.py @@ -26,7 +26,7 @@ class SvEditDataBlockList(bpy.types.Operator): bl_idname = "sverchok.edit_data_block_list" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} - operations = ['add', 'remove', 'move_up', 'move_down', 'clear'] + operations = ['add', 'remove', 'move_up', 'move_down', 'clear', 'get_selected', 'add_selected'] operation: bpy.props.EnumProperty(items=[(i, i, '') for i in operations]) item_index: bpy.props.IntProperty() # required for some operations @@ -46,10 +46,24 @@ def execute(self, context): node.blender_data.move(self.item_index, next_index) elif self.operation == 'clear': node.blender_data.clear() + elif self.operation == 'get_selected': + node.blender_data.clear() + self.add_selected(context, node.blender_data) + elif self.operation == 'add_selected': + self.add_selected(context, node.blender_data) updateNode(node, context) return {'FINISHED'} + def add_selected(self, context, collection): + depsgraph = context.evaluated_depsgraph_get() + for obj in context.editable_objects: + object_eval = obj.evaluated_get(depsgraph) + obj = object_eval.original + if obj.select_get(): + item = collection.add() + item.object = obj + class SvDataBlockListOptions(bpy.types.Menu): bl_idname = "OBJECT_MT_data_block_list_options" @@ -114,6 +128,11 @@ def sv_init(self, context): def draw_buttons(self, context, layout): col = layout.column() col.prop(self, 'data_type') + if self.data_type == 'object': + row = col.row(align=True) + row.label(text='Selected:') + row.operator(SvEditDataBlockList.bl_idname, text='Get').operation = 'get_selected' + row.operator(SvEditDataBlockList.bl_idname, text='Add').operation = 'add_selected' row = col.row(align=True) row.prop(self, 'edit_mode') op = row.operator(SvEditDataBlockList.bl_idname, text='+') From 2c291f87411f3b30ab25b9cbba76ac235abd262c Mon Sep 17 00:00:00 2001 From: Durman Date: Sat, 27 Feb 2021 08:23:01 +0400 Subject: [PATCH 7/8] fix bug of adding of not all selected objects --- nodes/scene/blender_data_list.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/nodes/scene/blender_data_list.py b/nodes/scene/blender_data_list.py index 323a7578ae..feb89b3ab8 100644 --- a/nodes/scene/blender_data_list.py +++ b/nodes/scene/blender_data_list.py @@ -55,14 +55,12 @@ def execute(self, context): updateNode(node, context) return {'FINISHED'} - def add_selected(self, context, collection): - depsgraph = context.evaluated_depsgraph_get() - for obj in context.editable_objects: - object_eval = obj.evaluated_get(depsgraph) - obj = object_eval.original - if obj.select_get(): - item = collection.add() - item.object = obj + @staticmethod + def add_selected(context, collection): + # if any bugs then you have probably using depsgraph here + for obj in context.selected_objects: + item = collection.add() + item.object = obj class SvDataBlockListOptions(bpy.types.Menu): From 7ce9efe34c1aae5c3e8416bfee3f95768cefbaae Mon Sep 17 00:00:00 2001 From: Durman Date: Sat, 27 Feb 2021 17:39:17 +0400 Subject: [PATCH 8/8] rough implementation of this idea https://github.com/nortikin/sverchok/pull/3903#issuecomment-785790167 --- core/__init__.py | 2 +- core/socket_data_containers.py | 109 +++++++++++++++++++++++++++++++++ core/sockets.py | 21 ++++++- 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 core/socket_data_containers.py diff --git a/core/__init__.py b/core/__init__.py index ec9632cbec..4ded09ed54 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -12,7 +12,7 @@ core_modules = [ "monad_properties", "sv_custom_exceptions", - "node_id_dict", "links", "sockets", + "node_id_dict", "links", "sockets", "socket_data_containers", "handlers", "update_system", "upgrade_nodes", "monad", "events", "node_group", "group_handlers" ] diff --git a/core/socket_data_containers.py b/core/socket_data_containers.py new file mode 100644 index 0000000000..98734efc09 --- /dev/null +++ b/core/socket_data_containers.py @@ -0,0 +1,109 @@ +# This file is part of project Sverchok. It's copyrighted by the contributors +# recorded in the version control history of the file, available from +# its original location https://github.com/nortikin/sverchok/commit/master +# +# SPDX-License-Identifier: GPL3 +# License-Filename: LICENSE + + +""" +The purpose of this module is to keep classes fo socket data containers +Usually such containers are just lists but in trick cases it requires more customization +""" + + +from typing import List, Union, Iterable + +import bpy +from sverchok.utils.handle_blender_data import BPYPointers + + +class SocketData: + """It should posses such method as 'copy', 'wrap', 'unwrap' and etc. later""" + + def get_data(self): + """This method will be called in socket.sv_get method""" + raise NotImplementedError(f'"get_data" method is not implemented in "{type(self).__name__}" class') + + def __len__(self): + """return number of objects for showing in socket names""" + raise NotImplementedError(f'"len" method is not implemented in "{type(self).__name__}" class') + + +class ObjectSocketData(SocketData): + """It will store meta information for refreshing links to given objects""" + + def __init__(self, data: list): + """Data is list of objects or list of lists of objects. Object can be all types of bpy.data""" + self._data = data + + # meta data of the same shape as input data + self._collection_names: Union[List[str], List[list]] = self._apply_func_it(self._get_col_name, data) + self._object_names: Union[List[str], List[list]] = self._apply_func_it(self._get_block_name, data) + + def get_data(self): + """It will refresh references to data if necessary""" + + def refresh_data(col_name, name): + # this potentially can be slow, solution could be create separate class for cashing searches + return getattr(bpy.data, col_name).get(name) + + def first_none_iter(it): + # should be moved somewhere + return first_none_iter(next(iter(it))) if isinstance(it, Iterable) else it + + # assume that either all blocks are invalid or none + if not self._is_valid_reference(first_none_iter(self._data)): + print('Outdated Object data detected - fixing') # todo remove + self._data = self._apply_func_its(refresh_data, self._collection_names, self._object_names) + + return self._data + + @staticmethod + def _get_col_name(block): + return BPYPointers.get_type(block.bl_rna).collection_name + + @staticmethod + def _get_block_name(block): + return block.name + + @staticmethod + def _is_valid_reference(obj) -> bool: + """Test of keeping valid references to a data block, should be moved in another location later""" + try: + obj.name # assume that all given data blocks has name property + return True + except ReferenceError: + return False + + def _apply_func_it(self, func, it: Iterable) -> list: + """Apply function to none iterable elements. Input shape is unchanged. + Should be moved in another module later""" + out = [] + for i in it: + if isinstance(i, Iterable): + out.append(self._apply_func_it(func, i)) + else: + out.append(func(i)) + return out + + def _apply_func_its(self, func, *its: Iterable) -> list: + """ + Apply function to none iterable elements. Input shape is unchanged. + Can get multiple iterables with the same shape. + func should have the same number of arguments as input iterables. + + Should be moved in another module later + _apply_func_its(lambda a, b: a + b, [1,[2,3],4], [5,[6,7],8]) + -> [6, [8, 10], 12] + """ + out = [] + for i in zip(*its): + if isinstance(i[0], Iterable) and not isinstance(i[0], str): + out.append(self._apply_func_its(func, *i)) + else: + out.append(func(*i)) + return out + + def __len__(self): + return len(self._data) diff --git a/core/sockets.py b/core/sockets.py index e4eb6e33c9..a833ecefe2 100644 --- a/core/sockets.py +++ b/core/sockets.py @@ -26,6 +26,7 @@ from sverchok.core.socket_data import ( SvGetSocketInfo, SvGetSocket, SvSetSocket, SvForgetSocket, SvNoDataError, sentinel) +from sverchok.core.socket_data_containers import ObjectSocketData from sverchok.data_structure import ( enum_item_4, @@ -253,6 +254,9 @@ def preprocess_input(self, data): return result def postprocess_output(self, data): + if not isinstance(data, (list, tuple)) \ + and any([self.use_flatten, self.use_simplify, self.use_graft, self.use_unwrap, self.use_wrap]): + raise NotImplementedError(f'Post processing is not supported for "{type(data).__name__}" class') result = data if self.use_flatten: result = self.do_flatten(data) @@ -396,7 +400,13 @@ def sv_get(self, default=sentinel, deepcopy=True, implicit_conversions=None): else: implicit_conversions = DEFAULT_CONVERSION - return self.convert_data(SvGetSocket(self, other, deepcopy), implicit_conversions, other) + data = self.convert_data(SvGetSocket(self, other, deepcopy), implicit_conversions, other) + + # in case if socket is using custom container + try: + return data.get_data() + except AttributeError: + return data prop_name = self.get_prop_name() if prop_name: @@ -600,6 +610,15 @@ def draw_property(self, layout, prop_origin=None, prop_name='default_property'): else: layout.prop_search(self, 'object_ref_pointer', bpy.data, 'objects', text=self.name) + def sv_set(self, data): + """ + This should solve problem of keeping references in valid state + The problem is that references to Blender data blocks can be outdated + The solution is refresh references if needed + For this reason some meta information should be stored in this method + """ + super().sv_set(ObjectSocketData(data)) + class SvFormulaSocket(NodeSocket, SvSocketCommon): bl_idname = "SvFormulaSocket"