forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
557
leenkx/blender/lnx/logicnode/tree_variables.py
Normal file
557
leenkx/blender/lnx/logicnode/tree_variables.py
Normal file
@ -0,0 +1,557 @@
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
|
||||
import lnx.log
|
||||
import lnx.make_state
|
||||
import lnx.node_utils
|
||||
import lnx.props_traits_props
|
||||
import lnx.utils
|
||||
import lnx.logicnode.lnx_nodes
|
||||
|
||||
if lnx.is_reload(__name__):
|
||||
lnx.log = lnx.reload_module(lnx.log)
|
||||
lnx.make_state = lnx.reload_module(lnx.make_state)
|
||||
lnx.node_utils = lnx.reload_module(lnx.node_utils)
|
||||
lnx.props_traits_props = lnx.reload_module(lnx.props_traits_props)
|
||||
lnx.utils = lnx.reload_module(lnx.utils)
|
||||
lnx.logicnode.lnx_nodes = lnx.reload_module(lnx.logicnode.lnx_nodes)
|
||||
else:
|
||||
lnx.enable_reload(__name__)
|
||||
|
||||
|
||||
class LNX_PT_Variables(bpy.types.Panel):
|
||||
bl_label = 'Tree Variables'
|
||||
bl_idname = 'LNX_PT_Variables'
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = 'Leenkx'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.space_data.tree_type == 'LnxLogicTreeType' and context.space_data.edit_tree
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
node = context.active_node
|
||||
if node is None or node.lnx_logic_id == '':
|
||||
layout.operator('lnx.variable_promote_node', icon='PLUS')
|
||||
else:
|
||||
layout.operator('lnx.variable_node_make_local', icon='TRIA_DOWN_BAR')
|
||||
|
||||
row = layout.row(align=True)
|
||||
col = row.column(align=True)
|
||||
|
||||
num_prop_rows = max(len(tree.lnx_treevariableslist), 6)
|
||||
col.template_list('LNX_UL_TreeVarList', '', tree, 'lnx_treevariableslist', tree, 'lnx_treevariableslist_index', rows=num_prop_rows)
|
||||
|
||||
col.operator('lnx.variable_assign_to_node', icon='NODE')
|
||||
|
||||
if len(tree.lnx_treevariableslist) > 0:
|
||||
selected_item = tree.lnx_treevariableslist[tree.lnx_treevariableslist_index]
|
||||
|
||||
col.separator()
|
||||
sub_row = col.row(align=True)
|
||||
sub_row.alignment = 'EXPAND'
|
||||
op = sub_row.operator('lnx.add_var_node')
|
||||
op.node_id = selected_item.name
|
||||
op.node_type = selected_item.node_type
|
||||
op = sub_row.operator('lnx.add_setvar_node')
|
||||
op.node_id = selected_item.name
|
||||
op.node_type = selected_item.node_type
|
||||
|
||||
col = row.column(align=True)
|
||||
col.enabled = len(tree.lnx_treevariableslist) > 1
|
||||
col.operator('lnx_treevariableslist.move_item', icon='TRIA_UP', text='').direction = 'UP'
|
||||
col.operator('lnx_treevariableslist.move_item', icon='TRIA_DOWN', text='').direction = 'DOWN'
|
||||
|
||||
if len(tree.lnx_treevariableslist) > 0:
|
||||
selected_item = tree.lnx_treevariableslist[tree.lnx_treevariableslist_index]
|
||||
|
||||
box = layout.box()
|
||||
box.label(text='Selected Variable:')
|
||||
master_node = lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin.get_master_node(tree, selected_item.name)
|
||||
master_node.draw_content(context, box)
|
||||
for inp in master_node.inputs:
|
||||
if hasattr(inp, 'draw'):
|
||||
inp.draw(context, box, master_node, inp.label if inp.label is not None else inp.name)
|
||||
|
||||
|
||||
class LNX_OT_TreeVariablePromoteNode(bpy.types.Operator):
|
||||
bl_idname = 'lnx.variable_promote_node'
|
||||
bl_label = 'New Var From Node'
|
||||
bl_description = 'Create a tree variable from the active node and promote it to a tree variable node'
|
||||
|
||||
var_name: StringProperty(
|
||||
name='Name',
|
||||
description='Name of the new tree variable',
|
||||
default='Untitled'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not lnx.logicnode.lnx_nodes.is_logic_node_edit_context(context):
|
||||
return False
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
if tree is None:
|
||||
return False
|
||||
|
||||
node = context.active_node
|
||||
if node is None or not node.bl_idname.startswith('LN'):
|
||||
return False
|
||||
|
||||
if not isinstance(node, lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin):
|
||||
return False
|
||||
|
||||
return node.lnx_logic_id == ''
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self, width=400)
|
||||
|
||||
def execute(self, context):
|
||||
node: lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin = context.active_node
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
|
||||
var_type = node.bl_idname
|
||||
var_item = LNX_PG_TreeVarListItem.create_new(tree, self.var_name, var_type)
|
||||
|
||||
node.is_master_node = True
|
||||
node.lnx_logic_id = var_item.name
|
||||
node.use_custom_color = True
|
||||
node.color = var_item.color
|
||||
|
||||
lnx.make_state.redraw_ui = True
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
row = layout.row()
|
||||
row.scale_y = 1.3
|
||||
row.activate_init = True
|
||||
row.prop(self, 'var_name')
|
||||
|
||||
|
||||
class LNX_OT_TreeVariableMakeLocalNode(bpy.types.Operator):
|
||||
bl_idname = 'lnx.variable_node_make_local'
|
||||
bl_label = 'Make Node Local'
|
||||
bl_description = (
|
||||
'Remove the reference to the tree variable from the active node. '
|
||||
'If the active node is the only node that links to the selected '
|
||||
'tree variable, the tree variable is removed'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not lnx.logicnode.lnx_nodes.is_logic_node_edit_context(context):
|
||||
return False
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
if tree is None:
|
||||
return False
|
||||
|
||||
node = context.active_node
|
||||
if node is None or not node.bl_idname.startswith('LN'):
|
||||
return False
|
||||
|
||||
if not isinstance(node, lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin):
|
||||
return False
|
||||
|
||||
return node.lnx_logic_id != ''
|
||||
|
||||
def execute(self, context):
|
||||
node: lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin = context.active_node
|
||||
node.make_local()
|
||||
node.color = [0.608, 0.608, 0.608] # default color
|
||||
node.use_custom_color = False
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class LNX_OT_TreeVariableVariableAssignToNode(bpy.types.Operator):
|
||||
bl_idname = 'lnx.variable_assign_to_node'
|
||||
bl_label = 'Assign To Node'
|
||||
bl_description = (
|
||||
'Assign the selected tree variable to the active variable node. '
|
||||
'The variable node must have the same type as the variable'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not lnx.logicnode.lnx_nodes.is_logic_node_edit_context(context):
|
||||
return False
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
if tree is None or len(tree.lnx_treevariableslist) == 0:
|
||||
return False
|
||||
|
||||
node = context.active_node
|
||||
if node is None or not node.bl_idname.startswith('LN'):
|
||||
return False
|
||||
|
||||
if not isinstance(node, lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin):
|
||||
return False
|
||||
|
||||
# Only assign variables to nodes of the correct type
|
||||
if node.bl_idname != tree.lnx_treevariableslist[tree.lnx_treevariableslist_index].node_type:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
node: lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin = context.active_node
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
|
||||
var_item = tree.lnx_treevariableslist[tree.lnx_treevariableslist_index]
|
||||
|
||||
# Make node local first to ensure the old tree variable (if
|
||||
# linked) is notified that the node is no longer linked
|
||||
if node.lnx_logic_id != var_item.name:
|
||||
node.make_local()
|
||||
|
||||
node.lnx_logic_id = var_item.name
|
||||
node.use_custom_color = True
|
||||
node.color = var_item.color
|
||||
lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin.synchronize(tree, node.lnx_logic_id)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class LNX_OT_TreeVariableListMoveItem(bpy.types.Operator):
|
||||
bl_idname = 'lnx_treevariableslist.move_item'
|
||||
bl_label = 'Move'
|
||||
bl_description = 'Move an item in the list'
|
||||
bl_options = {'UNDO', 'INTERNAL'}
|
||||
|
||||
direction: EnumProperty(
|
||||
items=(
|
||||
('UP', 'Up', ''),
|
||||
('DOWN', 'Down', '')
|
||||
)
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
index = tree.lnx_treevariableslist_index
|
||||
|
||||
max_index = len(tree.lnx_treevariableslist) - 1
|
||||
new_index = 0
|
||||
|
||||
if self.direction == 'UP':
|
||||
new_index = index - 1
|
||||
elif self.direction == 'DOWN':
|
||||
new_index = index + 1
|
||||
new_index = max(0, min(new_index, max_index))
|
||||
|
||||
tree.lnx_treevariableslist.move(index, new_index)
|
||||
tree.lnx_treevariableslist_index = new_index
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
|
||||
class LNX_OT_AddVarGetterNode(bpy.types.Operator):
|
||||
"""Add a node to get the value of the selected tree variable"""
|
||||
bl_idname = 'lnx.add_var_node'
|
||||
bl_label = 'Add Getter'
|
||||
bl_options = {'GRAB_CURSOR', 'BLOCKING'}
|
||||
|
||||
node_id: StringProperty()
|
||||
node_type: StringProperty()
|
||||
getter_node_ref = None
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not lnx.logicnode.lnx_nodes.is_logic_node_edit_context(context):
|
||||
return False
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
return tree is not None and len(tree.lnx_treevariableslist) > 0
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.modal_handler_add(self)
|
||||
self.execute(context)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, context, event):
|
||||
if event.type == 'MOUSEMOVE':
|
||||
self.getter_node_ref.location = context.space_data.cursor_location
|
||||
elif event.type == 'LEFTMOUSE': # Confirm
|
||||
return {'FINISHED'}
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def execute(self, context):
|
||||
self.getter_node_ref = self.create_getter_node(context, self.node_type, self.node_id)
|
||||
return {'FINISHED'}
|
||||
|
||||
@staticmethod
|
||||
def create_getter_node(context, node_type: str, node_id: str) -> lnx.logicnode.lnx_nodes.LnxLogicTreeNode:
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
nodes = context.space_data.path[-1].node_tree.nodes
|
||||
|
||||
node = nodes.new(node_type)
|
||||
node.location = context.space_data.cursor_location
|
||||
node.lnx_logic_id = node_id
|
||||
node.use_custom_color = True
|
||||
node.color = tree.lnx_treevariableslist[tree.lnx_treevariableslist_index].color
|
||||
|
||||
lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin.synchronize(tree, node.lnx_logic_id)
|
||||
|
||||
return node
|
||||
|
||||
|
||||
class LNX_OT_AddVarSetterNode(bpy.types.Operator):
|
||||
"""Add a node to set the value of the selected tree variable"""
|
||||
bl_idname = 'lnx.add_setvar_node'
|
||||
bl_label = 'Add Setter'
|
||||
bl_options = {'GRAB_CURSOR', 'BLOCKING'}
|
||||
|
||||
node_id: StringProperty()
|
||||
node_type: StringProperty()
|
||||
getter_node_ref = None
|
||||
setter_node_ref = None
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not lnx.logicnode.lnx_nodes.is_logic_node_edit_context(context):
|
||||
return False
|
||||
tree: bpy.types.NodeTree = context.space_data.path[-1].node_tree
|
||||
return tree is not None and len(tree.lnx_treevariableslist) > 0
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.modal_handler_add(self)
|
||||
self.execute(context)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, context, event):
|
||||
if event.type == 'MOUSEMOVE':
|
||||
self.setter_node_ref.location = context.space_data.cursor_location
|
||||
self.getter_node_ref.location[0] = context.space_data.cursor_location[0]
|
||||
self.getter_node_ref.location[1] = context.space_data.cursor_location[1] - self.setter_node_ref.height - 17
|
||||
elif event.type == 'LEFTMOUSE': # Confirm
|
||||
return {'FINISHED'}
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def execute(self, context):
|
||||
nodes = context.space_data.path[-1].node_tree.nodes
|
||||
|
||||
node = LNX_OT_AddVarGetterNode.create_getter_node(context, self.node_type, self.node_id)
|
||||
|
||||
setter_node = nodes.new('LNSetVariableNode')
|
||||
setter_node.location = context.space_data.cursor_location
|
||||
|
||||
links = context.space_data.path[-1].node_tree.links
|
||||
links.new(node.outputs[0], setter_node.inputs[1])
|
||||
|
||||
self.getter_node_ref = node
|
||||
self.setter_node_ref = setter_node
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class LNX_PG_TreeVarListItem(bpy.types.PropertyGroup):
|
||||
def _set_name(self, value: str):
|
||||
old_name = self._get_name()
|
||||
|
||||
tree = bpy.context.space_data.path[-1].node_tree
|
||||
lst = tree.lnx_treevariableslist
|
||||
|
||||
if value == '':
|
||||
# Don't allow empty variable names
|
||||
new_name = old_name
|
||||
else:
|
||||
new_name = lnx.utils.unique_name_in_lists(item_lists=[lst], name_attr='name', wanted_name=value, ignore_item=self)
|
||||
|
||||
self['_name'] = new_name
|
||||
|
||||
for node in tree.nodes:
|
||||
if node.lnx_logic_id == old_name:
|
||||
node.lnx_logic_id = new_name
|
||||
|
||||
def _get_name(self) -> str:
|
||||
return self.get('_name', 'Untitled')
|
||||
|
||||
def _update_color(self, context):
|
||||
space = context.space_data
|
||||
|
||||
# Can be None if color is set before tree is initialized (upon
|
||||
# updating old files to newer SDK for example)
|
||||
if space is not None:
|
||||
for node in space.path[-1].node_tree.nodes:
|
||||
if node.lnx_logic_id == self.name:
|
||||
node.use_custom_color = True
|
||||
node.color = self.color
|
||||
|
||||
name: StringProperty(
|
||||
name='Name',
|
||||
description='The name of this variable',
|
||||
default='Untitled',
|
||||
get=_get_name,
|
||||
set=_set_name
|
||||
)
|
||||
|
||||
node_type: StringProperty(
|
||||
name='Type',
|
||||
description='The type of this variable/the bl_idname of the node\'s that may use this variable',
|
||||
default='LNIntegerNode'
|
||||
)
|
||||
|
||||
color: FloatVectorProperty(
|
||||
name='Color',
|
||||
description='The color of the nodes that link to this tree variable',
|
||||
subtype='COLOR',
|
||||
default=[1.0, 1.0, 1.0],
|
||||
update=_update_color,
|
||||
size=3,
|
||||
min=0,
|
||||
max=1
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def create_new(cls, tree: bpy.types.NodeTree, item_name: str, item_type: str) -> 'LNX_PG_TreeVarListItem':
|
||||
lst = tree.lnx_treevariableslist
|
||||
|
||||
var_item: LNX_PG_TreeVarListItem = lst.add()
|
||||
var_item['_name'] = lnx.utils.unique_name_in_lists(
|
||||
item_lists=[lst], name_attr='name', wanted_name=item_name, ignore_item=var_item
|
||||
)
|
||||
var_item.node_type = item_type
|
||||
var_item.color = lnx.utils.get_random_color_rgb()
|
||||
|
||||
tree.lnx_treevariableslist_index = len(lst) - 1
|
||||
lnx.make_state.redraw_ui = True
|
||||
|
||||
return var_item
|
||||
|
||||
|
||||
class LNX_UL_TreeVarList(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item: LNX_PG_TreeVarListItem, icon, active_data, active_propname, index):
|
||||
node_type = lnx.utils.type_name_to_type(item.node_type).bl_label
|
||||
|
||||
row = layout.row(align=True)
|
||||
_row = row.row()
|
||||
_row.ui_units_x = 1.0
|
||||
_row.prop(item, 'color', text='')
|
||||
row.prop(item, 'name', text='', emboss=False)
|
||||
row.label(text=node_type)
|
||||
|
||||
|
||||
def on_update_node_logic_id(node: lnx.logicnode.lnx_nodes.LnxLogicTreeNode, context):
|
||||
node.on_logic_id_change()
|
||||
|
||||
|
||||
def node_compat_sdk2203():
|
||||
"""Replace old lnx_logic_id system with tree variable system."""
|
||||
for tree in bpy.data.node_groups:
|
||||
if tree.bl_idname == 'LnxLogicTreeType':
|
||||
# All tree variable nodes
|
||||
tv_nodes: dict[str, list[lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin]] = {}
|
||||
|
||||
# The type of the tree variable. If two types are found for
|
||||
# a logic ID and one is dynamic, assume it's a getter node.
|
||||
# Otherwise show a warning upon conflict, it was undefined
|
||||
# behaviour before anyway.
|
||||
tv_types: dict[str, str] = {}
|
||||
|
||||
# First pass: find all tree variable nodes and decide the
|
||||
# variable type in case of conflicts
|
||||
node: lnx.logicnode.lnx_nodes.LnxLogicTreeNode
|
||||
for node in list(tree.nodes):
|
||||
if node.lnx_logic_id != '':
|
||||
if not isinstance(node, lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin):
|
||||
lnx.log.warn(
|
||||
'While updating the file to the current SDK'
|
||||
f' version, the node {node.name} in tree'
|
||||
f' {tree.name} is no variable node but had'
|
||||
' a logic ID. The logic ID was reset to'
|
||||
' prevent undefined behaviour.'
|
||||
)
|
||||
node.lnx_logic_id = ''
|
||||
continue
|
||||
|
||||
if node.lnx_logic_id in tv_nodes:
|
||||
tv_nodes[node.lnx_logic_id].append(node)
|
||||
|
||||
# Check for getter nodes and type conflicts
|
||||
cur_type = tv_types[node.lnx_logic_id]
|
||||
if cur_type == 'LNDynamicNode':
|
||||
tv_types[node.lnx_logic_id] = node.bl_idname
|
||||
elif cur_type != node.bl_idname and node.bl_idname != 'LNDynamicNode':
|
||||
lnx.log.warn(
|
||||
'Found nodes of different types with the'
|
||||
' same logic ID while updating the file'
|
||||
' to the current SDK version (undefined'
|
||||
' behaviour).\n'
|
||||
f'\tConflicting types: {cur_type}, {node.bl_idname}\n'
|
||||
f'\tLogic ID: {node.lnx_logic_id}\n'
|
||||
f'\tNew type for both nodes: {cur_type}'
|
||||
)
|
||||
else:
|
||||
tv_nodes[node.lnx_logic_id] = [node]
|
||||
tv_types[node.lnx_logic_id] = node.bl_idname
|
||||
|
||||
# Second pass: add the tree variable and convert all found
|
||||
# tree var nodes to the correct type
|
||||
for logic_id in tv_nodes.keys():
|
||||
var_type = tv_types[logic_id]
|
||||
|
||||
var_item = LNX_PG_TreeVarListItem.create_new(tree, logic_id, var_type)
|
||||
|
||||
for node in tv_nodes[logic_id]:
|
||||
if node.bl_idname != var_type:
|
||||
newnode = tree.nodes.new(var_type)
|
||||
lnx.node_utils.copy_basic_node_props(from_node=node, to_node=newnode)
|
||||
|
||||
# Connect outputs as good as possible
|
||||
for i in range(min(len(node.outputs), len(newnode.outputs))):
|
||||
for out in node.outputs:
|
||||
for link in out.links:
|
||||
tree.links.new(newnode.outputs[i], link.to_socket)
|
||||
|
||||
tree.nodes.remove(node)
|
||||
node = newnode
|
||||
|
||||
# Hide sockets
|
||||
node.on_logic_id_change()
|
||||
|
||||
node.use_custom_color = True
|
||||
node.color = var_item.color
|
||||
|
||||
lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin.choose_new_master_node(tree, logic_id)
|
||||
|
||||
|
||||
def node_compat_sdk2209():
|
||||
# See https://github.com/leenkx3d/leenkx/pull/2538
|
||||
for tree in bpy.data.node_groups:
|
||||
if tree.bl_idname == "LnxLogicTreeType":
|
||||
for item in tree.lnx_treevariableslist:
|
||||
lnx.logicnode.lnx_nodes.LnxLogicVariableNodeMixin.synchronize(tree, item.name)
|
||||
|
||||
|
||||
__REG_CLASSES = (
|
||||
LNX_PT_Variables,
|
||||
LNX_OT_TreeVariableListMoveItem,
|
||||
LNX_OT_TreeVariableMakeLocalNode,
|
||||
LNX_OT_TreeVariableVariableAssignToNode,
|
||||
LNX_OT_TreeVariablePromoteNode,
|
||||
LNX_OT_AddVarGetterNode,
|
||||
LNX_OT_AddVarSetterNode,
|
||||
LNX_UL_TreeVarList,
|
||||
LNX_PG_TreeVarListItem,
|
||||
)
|
||||
__reg_classes, __unreg_classes = bpy.utils.register_classes_factory(__REG_CLASSES)
|
||||
|
||||
|
||||
def register():
|
||||
__reg_classes()
|
||||
|
||||
bpy.types.Node.lnx_logic_id = StringProperty(
|
||||
name='ID',
|
||||
description='Nodes with equal identifier share data',
|
||||
default='',
|
||||
update=on_update_node_logic_id
|
||||
)
|
||||
|
||||
bpy.types.NodeTree.lnx_treevariableslist = CollectionProperty(type=LNX_PG_TreeVarListItem)
|
||||
bpy.types.NodeTree.lnx_treevariableslist_index = IntProperty(name='Index for lnx_variableslist', default=0)
|
||||
|
||||
|
||||
def unregister():
|
||||
__unreg_classes()
|
Reference in New Issue
Block a user