Live patch: add support for node property updates

This commit is contained in:
Moritz Brückner 2021-07-03 19:45:05 +02:00
parent 202138304a
commit 4387d774cc
73 changed files with 565 additions and 238 deletions

View file

@ -9,7 +9,7 @@ import armory.trait.physics.RigidBody;
class AddRigidBodyNode extends LogicNode { class AddRigidBodyNode extends LogicNode {
public var property0: String;//Shape public var property0: String;//Shape
public var property1: String;//Advanced public var property1: Bool;//Advanced
public var object: Object; public var object: Object;
public function new(tree: LogicTree) { public function new(tree: LogicTree) {
@ -38,8 +38,7 @@ class AddRigidBodyNode extends LogicNode {
var shape: Shape = 1; var shape: Shape = 1;
if(property1 == 'true') if (property1) {
{
margin = inputs[9].get(); margin = inputs[9].get();
marginLen = inputs[10].get(); marginLen = inputs[10].get();
linDamp = inputs[11].get(); linDamp = inputs[11].get();
@ -49,34 +48,29 @@ class AddRigidBodyNode extends LogicNode {
angVelThreshold = inputs[15].get(); angVelThreshold = inputs[15].get();
group = inputs[16].get(); group = inputs[16].get();
mask = inputs[17].get(); mask = inputs[17].get();
} }
if (object == null) return; if (object == null) return;
#if arm_physics #if arm_physics
var rb: RigidBody = object.getTrait(RigidBody); var rb: RigidBody = object.getTrait(RigidBody);
if((group < 0) || (group > 32)) group = 1; //Limiting max groups to 32 if ((group < 0) || (group > 32)) group = 1; //Limiting max groups to 32
if((mask < 0) || (mask > 32)) mask = 1; //Limiting max masks to 32 if ((mask < 0) || (mask > 32)) mask = 1; //Limiting max masks to 32
if(rb == null) if (rb == null) {
{
switch (property0){ switch (property0){
case "Box":
case 'Box':
shape = Box; shape = Box;
case 'Sphere': case "Sphere":
shape = Sphere; shape = Sphere;
case 'Capsule': case "Capsule":
shape = Capsule; shape = Capsule;
case 'Cone': case "Cone":
shape = Cone; shape = Cone;
case 'Cylinder': case "Cylinder":
shape = Cylinder; shape = Cylinder;
case 'Convex Hull': case "Convex Hull":
shape = ConvexHull; shape = ConvexHull;
case 'Mesh': case "Mesh":
shape = Mesh; shape = Mesh;
} }
@ -84,15 +78,14 @@ class AddRigidBodyNode extends LogicNode {
rb.animated = animated; rb.animated = animated;
rb.staticObj = ! active; rb.staticObj = ! active;
rb.isTriggerObject(trigger); rb.isTriggerObject(trigger);
if(property1 == 'true')
{ if (property1) {
rb.linearDamping = linDamp; rb.linearDamping = linDamp;
rb.angularDamping = angDamp; rb.angularDamping = angDamp;
if(margin) rb.collisionMargin = marginLen; if (margin) rb.collisionMargin = marginLen;
if(useDeactiv) { if (useDeactiv) {
rb.setUpDeactivation(true, linearVelThreshold, angVelThreshold, 0.0); rb.setUpDeactivation(true, linearVelThreshold, angVelThreshold, 0.0);
} }
} }
object.addTrait(rb); object.addTrait(rb);

View file

@ -3,7 +3,7 @@ package armory.logicnode;
class MathNode extends LogicNode { class MathNode extends LogicNode {
public var property0: String; // Operation public var property0: String; // Operation
public var property1: String; // Clamp public var property1: Bool; // Clamp
public function new(tree: LogicTree) { public function new(tree: LogicTree) {
super(tree); super(tree);
@ -80,8 +80,8 @@ class MathNode extends LogicNode {
} }
} }
// Clamp // Clamp
if (property1 == "true") r = r < 0.0 ? 0.0 : (r > 1.0 ? 1.0 : r); if (property1) r = r < 0.0 ? 0.0 : (r > 1.0 ? 1.0 : r);
return r; return r;
} }
} }

View file

@ -6,7 +6,7 @@ class MixNode extends LogicNode {
public var property0: String; // Type public var property0: String; // Type
public var property1: String; // Ease public var property1: String; // Ease
public var property2: String; // Clamp public var property2: Bool; // Clamp
var ease: Float->Float = null; var ease: Float->Float = null;
@ -50,7 +50,9 @@ class MixNode extends LogicNode {
var v2: Float = inputs[2].get(); var v2: Float = inputs[2].get();
var f = v1 + (v2 - v1) * ease(k); var f = v1 + (v2 - v1) * ease(k);
if (property2 == "true") f = f < 0 ? 0 : f > 1 ? 1 : f; // Clamp
if (property2) f = f < 0 ? 0 : f > 1 ? 1 : f;
return f; return f;
} }
} }

View file

@ -3,15 +3,14 @@ package armory.logicnode;
#if arm_physics #if arm_physics
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintAxis; import armory.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
#end #end
import iron.object.Object;
class PhysicsConstraintNode extends LogicNode { class PhysicsConstraintNode extends LogicNode {
public var property0: String;//Linear or Angular public var property0: String; //Linear or Angular
public var property1: String;//Axis public var property1: String; //Axis
public var property2: String;//Is a spring public var property2: Bool; //Is a spring
public var value1: Float;//Lower limit or Spring Stiffness public var value1: Float; //Lower limit or Spring Stiffness
public var value2: Float;//Upper limit or Spring Damping public var value2: Float; //Upper limit or Spring Damping
public var isAngular: Bool; public var isAngular: Bool;
public var axis: ConstraintAxis; public var axis: ConstraintAxis;
public var isSpring: Bool; public var isSpring: Bool;
@ -24,27 +23,13 @@ class PhysicsConstraintNode extends LogicNode {
value1 = inputs[0].get(); value1 = inputs[0].get();
value2 = inputs[1].get(); value2 = inputs[1].get();
if(property0 == 'Linear') { isAngular = property0 != "Linear";
isAngular = false; isSpring = property2;
}
else{
isAngular = true;
}
if(property2 == 'true'){
isSpring = true;
}
else {
isSpring = false;
}
switch (property1){ switch (property1){
case 'X': case "X": axis = X;
axis = X; case "Y": axis = Y;
case 'Y': case "Z": axis = Z;
axis = Y;
case 'Z':
axis = Z;
} }
return this; return this;

View file

@ -7,7 +7,7 @@ class VectorMixNode extends LogicNode {
public var property0: String; // Type public var property0: String; // Type
public var property1: String; // Ease public var property1: String; // Ease
public var property2: String; // Clamp public var property2: Bool; // Clamp
var v = new Vec4(); var v = new Vec4();
@ -57,7 +57,7 @@ class VectorMixNode extends LogicNode {
v.y = v1.y + (v2.y - v1.y) * f; v.y = v1.y + (v2.y - v1.y) * f;
v.z = v1.z + (v2.z - v1.z) * f; v.z = v1.z + (v2.z - v1.z) * f;
if (property2 == "true") v.clamp(0, 1); if (property2) v.clamp(0, 1);
return v; return v;
} }
} }

View file

@ -45,5 +45,15 @@ class LivePatch extends iron.Trait {
} }
toNode.inputs[toIndex] = new LogicNodeInput(fromNode, fromIndex); toNode.inputs[toIndex] = new LogicNodeInput(fromNode, fromIndex);
} }
public static function patchUpdateNodeProp(treeName: String, nodeName: String, propName: String, value: Dynamic) {
var tree = LogicTree.nodeTrees[treeName];
if (tree == null) return;
var node = tree.nodes[nodeName];
if (node == null) return;
Reflect.setField(node, propName, value);
}
#end #end
} }

View file

@ -153,8 +153,7 @@ def send_event(event_id: str, opt_data: Any = None):
# This event is called twice for a connection but we only need # This event is called twice for a connection but we only need
# send it once # send it once
if node == link.from_node: if node == link.from_node:
node_tree = node.get_tree() tree_name = arm.node_utils.get_export_tree_name(node.get_tree())
tree_name = arm.node_utils.get_export_tree_name(node_tree)
# [1:] is used here because make_logic already uses that for # [1:] is used here because make_logic already uses that for
# node names if arm_debug is used # node names if arm_debug is used
@ -167,6 +166,18 @@ def send_event(event_id: str, opt_data: Any = None):
js = f'LivePatch.patchCreateNodeLink("{tree_name}", "{from_node_name}", "{to_node_name}", "{from_index}", "{to_index}");' js = f'LivePatch.patchCreateNodeLink("{tree_name}", "{from_node_name}", "{to_node_name}", "{from_index}", "{to_index}");'
write_patch(js) write_patch(js)
if event_id == 'ln_update_prop':
node: ArmLogicTreeNode
prop_name: str
node, prop_name = opt_data
tree_name = arm.node_utils.get_export_tree_name(node.get_tree())
node_name = arm.node_utils.get_export_node_name(node)[1:]
value = arm.node_utils.haxe_format_prop(node, prop_name)
js = f'LivePatch.patchUpdateNodeProp("{tree_name}", "{node_name}", "{prop_name}", {value});'
write_patch(js)
def on_operator(operator_id: str): def on_operator(operator_id: str):

View file

@ -1,6 +1,6 @@
import itertools import itertools
from collections import OrderedDict from collections import OrderedDict
from typing import Any, Generator, List, Optional, Type, Dict from typing import Any, Generator, List, Optional, Type
from typing import OrderedDict as ODict # Prevent naming conflicts from typing import OrderedDict as ODict # Prevent naming conflicts
import bpy.types import bpy.types
@ -8,7 +8,9 @@ from bpy.props import *
from nodeitems_utils import NodeItem from nodeitems_utils import NodeItem
import arm # we cannot import arm.livepatch here or we have a circular import import arm # we cannot import arm.livepatch here or we have a circular import
# Pass NodeReplacement forward to individual node modules that import arm_nodes # Pass custom property types and NodeReplacement forward to individual
# node modules that import arm_nodes
from arm.logicnode.arm_props import *
from arm.logicnode.replacement import NodeReplacement from arm.logicnode.replacement import NodeReplacement
import arm.node_utils import arm.node_utils
@ -52,6 +54,13 @@ class ArmLogicTreeNode(bpy.types.Node):
def get_tree(self): def get_tree(self):
return self.id_data return self.id_data
def on_prop_update(self, context: bpy.types.Context, prop_name: str):
"""Called if a property created with a function from the
arm_props module is changed. If the property has a custom update
function, it is called before `on_prop_update()`.
"""
arm.live_patch.send_event('ln_update_prop', (self, prop_name))
def insert_link(self, link: bpy.types.NodeLink): def insert_link(self, link: bpy.types.NodeLink):
"""Called on *both* nodes when a link between two nodes is created.""" """Called on *both* nodes when a link between two nodes is created."""
arm.live_patch.send_event('ln_insert_link', (self, link)) arm.live_patch.send_event('ln_insert_link', (self, link))

View file

@ -0,0 +1,267 @@
"""Custom bpy property creators for logic nodes. Please be aware that
the code in this file is usually run once at registration and not for
each individual node instance when it is created.
The functions for creating typed properties wrap the private __haxe_prop
function to allow for IDE autocompletion.
Some default parameters in the signature of functions in this module are
mutable (common Python pitfall, be aware of this!), but because they
don't get accessed later it doesn't matter here and we keep it this way
for parity with the Blender API.
"""
from typing import Any, Callable, Sequence, Union
import bpy
from bpy.props import *
# Property parameter name `set` shadows built-in type `set`
__set = set
def __haxe_prop(prop_type: Callable, prop_name: str, *args, **kwargs) -> Any:
"""Declares a logic node property as a property that will be
used ingame for a logic node."""
update_callback: Callable = kwargs.get('update', None)
if update_callback is None:
def wrapper(self: bpy.types.Node, context: bpy.types.Context):
self.on_prop_update(context, prop_name)
kwargs['update'] = wrapper
else:
def wrapper(self: bpy.types.Node, context: bpy.types.Context):
update_callback(self, context)
self.on_prop_update(context, prop_name)
kwargs['update'] = wrapper
# Tags are not allowed on classes other than bpy.types.ID or
# bpy.types.Bone, remove them here to prevent registration errors
if 'tags' in kwargs:
del kwargs['tags']
return prop_type(*args, **kwargs)
def HaxeBoolProperty(
prop_name: str,
*, # force passing further arguments as keywords, see PEP 3102
name: str = "",
description: str = "",
default=False,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
update=None,
get=None,
set=None
) -> 'bpy.types.BoolProperty':
"""Declares a new BoolProperty that has a counterpart with the given
prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(BoolProperty, **locals())
def HaxeBoolVectorProperty(
prop_name: str,
*,
name: str = "",
description: str = "",
default: list = (False, False, False),
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
size: int = 3,
update=None,
get=None,
set=None
) -> list['bpy.types.BoolProperty']:
"""Declares a new BoolVectorProperty that has a counterpart with the
given prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(BoolVectorProperty, **locals())
def HaxeCollectionProperty(
prop_name: str,
*,
type=None,
name: str = "",
description: str = "",
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set()
) -> 'bpy.types.CollectionProperty':
"""Declares a new CollectionProperty that has a counterpart with the
given prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(CollectionProperty, **locals())
def HaxeEnumProperty(
prop_name: str,
*,
items: Sequence,
name: str = "",
description: str = "",
default: Union[str, set[str]] = None,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
update=None,
get=None,
set=None
) -> 'bpy.types.EnumProperty':
"""Declares a new EnumProperty that has a counterpart with the given
prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(EnumProperty, **locals())
def HaxeFloatProperty(
prop_name: str,
*,
name: str = "",
description: str = "",
default=0.0,
min: float = -3.402823e+38,
max: float = 3.402823e+38,
soft_min: float = -3.402823e+38,
soft_max: float = 3.402823e+38,
step: int = 3,
precision: int = 2,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
unit: str = 'NONE',
update=None,
get=None,
set=None
) -> 'bpy.types.FloatProperty':
"""Declares a new FloatProperty that has a counterpart with the
given prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(FloatProperty, **locals())
def HaxeFloatVectorProperty(
prop_name: str,
*,
name: str = "",
description: str = "",
default: list = (0.0, 0.0, 0.0),
min: float = 'sys.float_info.min',
max: float = 'sys.float_info.max',
soft_min: float = 'sys.float_info.min',
soft_max: float = 'sys.float_info.max',
step: int = 3,
precision: int = 2,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
unit: str = 'NONE',
size: int = 3,
update=None,
get=None,
set=None
) -> list['bpy.types.FloatProperty']:
"""Declares a new FloatVectorProperty that has a counterpart with the
given prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(FloatVectorProperty, **locals())
def HaxeIntProperty(
prop_name: str,
*,
name: str = "",
description: str = "",
default=0,
min: int = -2**31,
max: int = 2**31 - 1,
soft_min: int = -2**31,
soft_max: int = 2**31 - 1,
step: int = 1,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
update=None,
get=None,
set=None
) -> 'bpy.types.IntProperty':
"""Declares a new IntProperty that has a counterpart with the given
prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(IntProperty, **locals())
def HaxeIntVectorProperty(
prop_name: str,
*,
name: str = "",
description: str = "",
default: list = (0, 0, 0),
min: int = -2**31,
max: int = 2**31 - 1,
soft_min: int = -2**31,
soft_max: int = 2**31 - 1,
step: int = 1,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
size: int = 3,
update=None,
get=None,
set=None
) -> list['bpy.types.IntProperty']:
"""Declares a new IntVectorProperty that has a counterpart with the given
prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(IntVectorProperty, **locals())
def HaxePointerProperty(
prop_name: str,
*,
type=None,
name: str = "",
description: str = "",
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
poll=None,
update=None
) -> 'bpy.types.PointerProperty':
"""Declares a new PointerProperty that has a counterpart with the
given prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(PointerProperty, **locals())
def RemoveHaxeProperty(cls, attr: str):
RemoveProperty(cls, attr)
def HaxeStringProperty(
prop_name: str,
*,
name: str = "",
description: str = "",
default: str = "",
maxlen: int = 0,
options: set = {'ANIMATABLE'},
override: set = set(),
tags: set = set(),
subtype: str = 'NONE',
update=None,
get=None,
set=None
) -> 'bpy.types.StringProperty':
"""Declares a new StringProperty that has a counterpart with the
given prop_name (Python and Haxe names must be identical for now).
"""
return __haxe_prop(StringProperty, **locals())

View file

@ -6,16 +6,19 @@ class OnCanvasElementNode(ArmLogicTreeNode):
bl_label = 'On Canvas Element' bl_label = 'On Canvas Element'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items=[('click', 'Click', 'Listen to mouse clicks'), items=[('click', 'Click', 'Listen to mouse clicks'),
('hover', 'Hover', 'Listen to mouse hover')], ('hover', 'Hover', 'Listen to mouse hover')],
name='Listen to', default='click') name='Listen to', default='click')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items=[('started', 'Started', 'Started'), items=[('started', 'Started', 'Started'),
('down', 'Down', 'Down'), ('down', 'Down', 'Down'),
('released', 'Released', 'Released')], ('released', 'Released', 'Released')],
name='Status', default='started') name='Status', default='started')
property2: EnumProperty( property2: HaxeEnumProperty(
'property2',
items=[('left', 'Left', 'Left mouse button'), items=[('left', 'Left', 'Left mouse button'),
('middle', 'Middle', 'Middle mouse button'), ('middle', 'Middle', 'Middle mouse button'),
('right', 'Right', 'Right mouse button')], ('right', 'Right', 'Right mouse button')],

View file

@ -11,7 +11,8 @@ class OnGamepadNode(ArmLogicTreeNode):
arm_section = 'gamepad' arm_section = 'gamepad'
arm_version = 2 arm_version = 2
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Down', 'Down', 'Down'), items = [('Down', 'Down', 'Down'),
('Started', 'Started', 'Started'), ('Started', 'Started', 'Started'),
('Released', 'Released', 'Released')], ('Released', 'Released', 'Released')],
@ -19,7 +20,8 @@ class OnGamepadNode(ArmLogicTreeNode):
# ('Moved Right', 'Moved Right', 'Moved Right'),], # ('Moved Right', 'Moved Right', 'Moved Right'),],
name='', default='Started') name='', default='Started')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('cross', 'cross / a', 'cross / a'), items = [('cross', 'cross / a', 'cross / a'),
('circle', 'circle / b', 'circle / b'), ('circle', 'circle / b', 'circle / b'),
('square', 'square / x', 'square / x'), ('square', 'square / x', 'square / x'),

View file

@ -11,13 +11,15 @@ class OnKeyboardNode(ArmLogicTreeNode):
arm_section = 'keyboard' arm_section = 'keyboard'
arm_version = 2 arm_version = 2
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Down', 'Down', 'Down'), items = [('Down', 'Down', 'Down'),
('Started', 'Started', 'Started'), ('Started', 'Started', 'Started'),
('Released', 'Released', 'Released')], ('Released', 'Released', 'Released')],
name='', default='Started') name='', default='Started')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('a', 'a', 'a'), items = [('a', 'a', 'a'),
('b', 'b', 'b'), ('b', 'b', 'b'),
('c', 'c', 'c'), ('c', 'c', 'c'),

View file

@ -11,13 +11,15 @@ class OnMouseNode(ArmLogicTreeNode):
arm_section = 'mouse' arm_section = 'mouse'
arm_version = 2 arm_version = 2
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Down', 'Down', 'Down'), items = [('Down', 'Down', 'Down'),
('Started', 'Started', 'Started'), ('Started', 'Started', 'Started'),
('Released', 'Released', 'Released'), ('Released', 'Released', 'Released'),
('Moved', 'Moved', 'Moved')], ('Moved', 'Moved', 'Moved')],
name='', default='Down') name='', default='Down')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('left', 'left', 'left'), items = [('left', 'left', 'left'),
('right', 'right', 'right'), ('right', 'right', 'right'),
('middle', 'middle', 'middle')], ('middle', 'middle', 'middle')],

View file

@ -11,7 +11,8 @@ class OnSurfaceNode(ArmLogicTreeNode):
arm_section = 'surface' arm_section = 'surface'
arm_version = 2 arm_version = 2
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Touched', 'Touched', 'Touched'), items = [('Touched', 'Touched', 'Touched'),
('Started', 'Started', 'Started'), ('Started', 'Started', 'Started'),
('Released', 'Released', 'Released'), ('Released', 'Released', 'Released'),

View file

@ -11,12 +11,13 @@ class OnVirtualButtonNode(ArmLogicTreeNode):
arm_section = 'virtual' arm_section = 'virtual'
arm_version = 2 arm_version = 2
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Down', 'Down', 'Down'), items = [('Down', 'Down', 'Down'),
('Started', 'Started', 'Started'), ('Started', 'Started', 'Started'),
('Released', 'Released', 'Released')], ('Released', 'Released', 'Released')],
name='', default='Started') name='', default='Started')
property1: StringProperty(name='', default='button') property1: HaxeStringProperty('property1', name='', default='button')
def init(self, context): def init(self, context):
super(OnVirtualButtonNode, self).init(context) super(OnVirtualButtonNode, self).init(context)

View file

@ -10,7 +10,7 @@ class OnEventNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
arm_section = 'custom' arm_section = 'custom'
property0: StringProperty(name='', default='') property0: HaxeStringProperty('property0', name='', default='')
def init(self, context): def init(self, context):
super(OnEventNode, self).init(context) super(OnEventNode, self).init(context)

View file

@ -10,7 +10,8 @@ class OnUpdateNode(ArmLogicTreeNode):
bl_idname = 'LNOnUpdateNode' bl_idname = 'LNOnUpdateNode'
bl_label = 'On Update' bl_label = 'On Update'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Update', 'Update', 'Update'), items = [('Update', 'Update', 'Update'),
('Late Update', 'Late Update', 'Late Update'), ('Late Update', 'Late Update', 'Late Update'),
('Physics Pre-Update', 'Physics Pre-Update', 'Physics Pre-Update')], ('Physics Pre-Update', 'Physics Pre-Update', 'Physics Pre-Update')],

View file

@ -15,7 +15,8 @@ class GamepadNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
arm_section = 'gamepad' arm_section = 'gamepad'
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('started', 'Started', 'The gamepad button starts to be pressed'), items = [('started', 'Started', 'The gamepad button starts to be pressed'),
('down', 'Down', 'The gamepad button is pressed'), ('down', 'Down', 'The gamepad button is pressed'),
('released', 'Released', 'The gamepad button stops being pressed')], ('released', 'Released', 'The gamepad button stops being pressed')],
@ -23,7 +24,8 @@ class GamepadNode(ArmLogicTreeNode):
# ('Moved Right', 'Moved Right', 'Moved Right'),], # ('Moved Right', 'Moved Right', 'Moved Right'),],
name='', default='down') name='', default='down')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('cross', 'cross / a', 'cross / a'), items = [('cross', 'cross / a', 'cross / a'),
('circle', 'circle / b', 'circle / b'), ('circle', 'circle / b', 'circle / b'),
('square', 'square / x', 'square / x'), ('square', 'square / x', 'square / x'),

View file

@ -7,13 +7,15 @@ class KeyboardNode(ArmLogicTreeNode):
arm_section = 'keyboard' arm_section = 'keyboard'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('started', 'Started', 'The keyboard button starts to be pressed'), items = [('started', 'Started', 'The keyboard button starts to be pressed'),
('down', 'Down', 'The keyboard button is pressed'), ('down', 'Down', 'The keyboard button is pressed'),
('released', 'Released', 'The keyboard button stops being pressed')], ('released', 'Released', 'The keyboard button stops being pressed')],
name='', default='down') name='', default='down')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('a', 'a', 'a'), items = [('a', 'a', 'a'),
('b', 'b', 'b'), ('b', 'b', 'b'),
('c', 'c', 'c'), ('c', 'c', 'c'),

View file

@ -7,13 +7,15 @@ class MouseNode(ArmLogicTreeNode):
arm_section = 'mouse' arm_section = 'mouse'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('started', 'Started', 'The mouse button startes to be pressed'), items = [('started', 'Started', 'The mouse button startes to be pressed'),
('down', 'Down', 'The mouse button is pressed'), ('down', 'Down', 'The mouse button is pressed'),
('released', 'Released', 'The mouse button stops being pressed'), ('released', 'Released', 'The mouse button stops being pressed'),
('moved', 'Moved', 'Moved')], ('moved', 'Moved', 'Moved')],
name='', default='down') name='', default='down')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('left', 'Left', 'Left mouse button'), items = [('left', 'Left', 'Left mouse button'),
('middle', 'Middle', 'Middle mouse button'), ('middle', 'Middle', 'Middle mouse button'),
('right', 'Right', 'Right mouse button')], ('right', 'Right', 'Right mouse button')],

View file

@ -14,7 +14,8 @@ class SetCursorStateNode(ArmLogicTreeNode):
arm_section = 'mouse' arm_section = 'mouse'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('hide locked', 'Hide Locked', 'The mouse cursor is hidden and locked'), items = [('hide locked', 'Hide Locked', 'The mouse cursor is hidden and locked'),
('hide', 'Hide', 'The mouse cursor is hidden'), ('hide', 'Hide', 'The mouse cursor is hidden'),
('lock', 'Lock', 'The mouse cursor is locked'), ('lock', 'Lock', 'The mouse cursor is locked'),

View file

@ -7,7 +7,8 @@ class SurfaceNode(ArmLogicTreeNode):
arm_section = 'surface' arm_section = 'surface'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('started', 'Started', 'The screen surface starts to be touched'), items = [('started', 'Started', 'The screen surface starts to be touched'),
('down', 'Down', 'The screen surface is touched'), ('down', 'Down', 'The screen surface is touched'),
('released', 'Released', 'The screen surface stops being touched'), ('released', 'Released', 'The screen surface stops being touched'),

View file

@ -7,12 +7,13 @@ class VirtualButtonNode(ArmLogicTreeNode):
arm_section = 'virtual' arm_section = 'virtual'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('started', 'Started', 'The virtual button starts to be pressed'), items = [('started', 'Started', 'The virtual button starts to be pressed'),
('down', 'Down', 'The virtual button is pressed'), ('down', 'Down', 'The virtual button is pressed'),
('released', 'Released', 'The virtual button stops being pressed')], ('released', 'Released', 'The virtual button stops being pressed')],
name='', default='down') name='', default='down')
property1: StringProperty(name='', default='button') property1: HaxeStringProperty('property1', name='', default='button')
def init(self, context): def init(self, context):
super(VirtualButtonNode, self).init(context) super(VirtualButtonNode, self).init(context)

View file

@ -20,7 +20,8 @@ class GateNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
min_inputs = 3 min_inputs = 3
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Equal', 'Equal', 'Equal'), items = [('Equal', 'Equal', 'Equal'),
('Almost Equal', 'Almost Equal', 'Almost Equal'), ('Almost Equal', 'Almost Equal', 'Almost Equal'),
('Greater', 'Greater', 'Greater'), ('Greater', 'Greater', 'Greater'),
@ -31,7 +32,7 @@ class GateNode(ArmLogicTreeNode):
('And', 'And', 'And')], ('And', 'And', 'And')],
name='', default='Equal', name='', default='Equal',
update=remove_extra_inputs) update=remove_extra_inputs)
property1: FloatProperty(name='Tolerance', description='Precision for float compare', default=0.0001) property1: HaxeFloatProperty('property1', name='Tolerance', description='Precision for float compare', default=0.0001)
def __init__(self): def __init__(self):
super(GateNode, self).__init__() super(GateNode, self).__init__()

View file

@ -18,7 +18,7 @@ class MaterialNode(ArmLogicTreeNode):
return self.property0.name return self.property0.name
return arm.utils.asset_name(bpy.data.materials[self.property0.name]) return arm.utils.asset_name(bpy.data.materials[self.property0.name])
property0: PointerProperty(name='', type=bpy.types.Material) property0: HaxePointerProperty('property0', name='', type=bpy.types.Material)
def init(self, context): def init(self, context):
super(MaterialNode, self).init(context) super(MaterialNode, self).init(context)

View file

@ -10,7 +10,8 @@ class CompareNode(ArmLogicTreeNode):
bl_idname = 'LNCompareNode' bl_idname = 'LNCompareNode'
bl_label = 'Compare' bl_label = 'Compare'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Equal', 'Equal', 'Equal'), items = [('Equal', 'Equal', 'Equal'),
('Almost Equal', 'Almost Equal', 'Almost Equal'), ('Almost Equal', 'Almost Equal', 'Almost Equal'),
('Greater', 'Greater', 'Greater'), ('Greater', 'Greater', 'Greater'),
@ -22,7 +23,7 @@ class CompareNode(ArmLogicTreeNode):
name='', default='Equal', name='', default='Equal',
update=remove_extra_inputs) update=remove_extra_inputs)
min_inputs = 2 min_inputs = 2
property1: FloatProperty(name='Tolerance', description='Precision for float compare', default=0.0001) property1: HaxeFloatProperty('property1', name='Tolerance', description='Precision for float compare', default=0.0001)
def __init__(self): def __init__(self):
super(CompareNode, self).__init__() super(CompareNode, self).__init__()

View file

@ -64,7 +64,8 @@ class MathNode(ArmLogicTreeNode):
self.inputs.remove(self.inputs.values()[-1]) self.inputs.remove(self.inputs.values()[-1])
self['property0'] = value self['property0'] = value
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Add', 'Add', 'Add'), items = [('Add', 'Add', 'Add'),
('Multiply', 'Multiply', 'Multiply'), ('Multiply', 'Multiply', 'Multiply'),
('Sine', 'Sine', 'Sine'), ('Sine', 'Sine', 'Sine'),
@ -92,11 +93,7 @@ class MathNode(ArmLogicTreeNode):
('Exponent', 'Exponent', 'Exponent')], ('Exponent', 'Exponent', 'Exponent')],
name='', default='Add', set=set_enum, get=get_enum) name='', default='Add', set=set_enum, get=get_enum)
@property property1: HaxeBoolProperty('property1', name='Clamp', default=False)
def property1(self):
return 'true' if self.property1_ else 'false'
property1_: BoolProperty(name='Clamp', default=False)
def __init__(self): def __init__(self):
array_nodes[str(id(self))] = self array_nodes[str(id(self))] = self
@ -109,7 +106,7 @@ class MathNode(ArmLogicTreeNode):
self.add_output('NodeSocketFloat', 'Result') self.add_output('NodeSocketFloat', 'Result')
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property1_') layout.prop(self, 'property1')
layout.prop(self, 'property0') layout.prop(self, 'property0')
# Many arguments: Add, Subtract, Multiply, Divide # Many arguments: Add, Subtract, Multiply, Divide
if (self.get_count_in(self.property0) == 0): if (self.get_count_in(self.property0) == 0):

View file

@ -155,8 +155,8 @@ class MathExpressionNode(ArmLogicTreeNode):
def get_exp(self): def get_exp(self):
return self.get('property0', 'a + b') return self.get('property0', 'a + b')
property0: StringProperty(name='', description='Expression (operation: +, -, *, /, ^, (, ), %)', set=set_exp, get=get_exp) property0: HaxeStringProperty('property0', name='', description='Expression (operation: +, -, *, /, ^, (, ), %)', set=set_exp, get=get_exp)
property1: BoolProperty(name='Clamp', default=False) property1: HaxeBoolProperty('property1', name='Clamp', default=False)
def __init__(self): def __init__(self):
array_nodes[str(id(self))] = self array_nodes[str(id(self))] = self

View file

@ -7,7 +7,8 @@ class MatrixMathNode(ArmLogicTreeNode):
arm_section = 'matrix' arm_section = 'matrix'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Multiply', 'Multiply', 'Multiply')], items = [('Multiply', 'Multiply', 'Multiply')],
name='', default='Multiply') name='', default='Multiply')

View file

@ -5,7 +5,8 @@ class MixNode(ArmLogicTreeNode):
bl_idname = 'LNMixNode' bl_idname = 'LNMixNode'
bl_label = 'Mix' bl_label = 'Mix'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Linear', 'Linear', 'Linear'), items = [('Linear', 'Linear', 'Linear'),
('Sine', 'Sine', 'Sine'), ('Sine', 'Sine', 'Sine'),
('Quad', 'Quad', 'Quad'), ('Quad', 'Quad', 'Quad'),
@ -19,18 +20,15 @@ class MixNode(ArmLogicTreeNode):
('Elastic', 'Elastic', 'Elastic'), ('Elastic', 'Elastic', 'Elastic'),
], ],
name='', default='Linear') name='', default='Linear')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('In', 'In', 'In'), items = [('In', 'In', 'In'),
('Out', 'Out', 'Out'), ('Out', 'Out', 'Out'),
('InOut', 'InOut', 'InOut'), ('InOut', 'InOut', 'InOut'),
], ],
name='', default='Out') name='', default='Out')
@property property2: HaxeBoolProperty('property2', name='Clamp', default=False)
def property2(self):
return 'true' if self.property2_ else 'false'
property2_: BoolProperty(name='Clamp', default=False)
def init(self, context): def init(self, context):
super(MixNode, self).init(context) super(MixNode, self).init(context)
@ -41,6 +39,6 @@ class MixNode(ArmLogicTreeNode):
self.add_output('NodeSocketFloat', 'Result') self.add_output('NodeSocketFloat', 'Result')
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property2_') layout.prop(self, 'property2')
layout.prop(self, 'property0') layout.prop(self, 'property0')
layout.prop(self, 'property1') layout.prop(self, 'property1')

View file

@ -7,7 +7,8 @@ class VectorMixNode(ArmLogicTreeNode):
arm_section = 'vector' arm_section = 'vector'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Linear', 'Linear', 'Linear'), items = [('Linear', 'Linear', 'Linear'),
('Sine', 'Sine', 'Sine'), ('Sine', 'Sine', 'Sine'),
('Quad', 'Quad', 'Quad'), ('Quad', 'Quad', 'Quad'),
@ -21,18 +22,15 @@ class VectorMixNode(ArmLogicTreeNode):
('Elastic', 'Elastic', 'Elastic'), ('Elastic', 'Elastic', 'Elastic'),
], ],
name='', default='Linear') name='', default='Linear')
property1: EnumProperty( property1: HaxeEnumProperty(
'property1',
items = [('In', 'In', 'In'), items = [('In', 'In', 'In'),
('Out', 'Out', 'Out'), ('Out', 'Out', 'Out'),
('InOut', 'InOut', 'InOut'), ('InOut', 'InOut', 'InOut'),
], ],
name='', default='Out') name='', default='Out')
@property property2: HaxeBoolProperty('property2', name='Clamp', default=False)
def property2(self):
return 'true' if self.property2_ else 'false'
property2_: BoolProperty(name='Clamp', default=False)
def init(self, context): def init(self, context):
super(VectorMixNode, self).init(context) super(VectorMixNode, self).init(context)
@ -43,7 +41,7 @@ class VectorMixNode(ArmLogicTreeNode):
self.add_output('NodeSocketVector', 'Result') self.add_output('NodeSocketVector', 'Result')
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property2_') layout.prop(self, 'property2')
layout.prop(self, 'property0') layout.prop(self, 'property0')
if self.property0 != 'Linear': if self.property0 != 'Linear':
layout.prop(self, 'property1') layout.prop(self, 'property1')

View file

@ -41,7 +41,7 @@ class QuaternionMathNode(ArmLogicTreeNode):
if (self.property0 == 'ToAxisAngle'): if (self.property0 == 'ToAxisAngle'):
self.add_output('NodeSocketFloat', 'To Axis Angle') # ToAxisAngle self.add_output('NodeSocketFloat', 'To Axis Angle') # ToAxisAngle
property1: BoolProperty(name='Separator Out', default=False, set=set_bool, get=get_bool) property1: HaxeBoolProperty('property1', name='Separator Out', default=False, set=set_bool, get=get_bool)
@staticmethod @staticmethod
def get_enum_id_value(obj, prop_name, value): def get_enum_id_value(obj, prop_name, value):
@ -132,7 +132,8 @@ class QuaternionMathNode(ArmLogicTreeNode):
self.add_output('NodeSocketFloat', 'Module') self.add_output('NodeSocketFloat', 'Module')
self['property0'] = value self['property0'] = value
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Add', 'Add', 'Add'), items = [('Add', 'Add', 'Add'),
('Subtract', 'Subtract', 'Subtract'), ('Subtract', 'Subtract', 'Subtract'),
('DotProduct', 'Dot Product', 'Dot Product'), ('DotProduct', 'Dot Product', 'Dot Product'),

View file

@ -10,12 +10,7 @@ class ScreenToWorldSpaceNode(ArmLogicTreeNode):
min_outputs = 2 min_outputs = 2
max_outputs = 8 max_outputs = 8
# Separator property0: HaxeBoolProperty('property0', name='Separator Out', default=False)
@property
def property0(self):
return True if self.property0_ else False
property0_: BoolProperty(name='Separator Out', default=False)
def init(self, context): def init(self, context):
super(ScreenToWorldSpaceNode, self).init(context) super(ScreenToWorldSpaceNode, self).init(context)
@ -26,8 +21,8 @@ class ScreenToWorldSpaceNode(ArmLogicTreeNode):
self.add_output('NodeSocketVector', 'Direction') self.add_output('NodeSocketVector', 'Direction')
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property0_') # Separator Out layout.prop(self, 'property0') # Separator Out
if self.property0_: if self.property0:
if len(self.outputs) < self.max_outputs: if len(self.outputs) < self.max_outputs:
self.outputs.remove(self.outputs.values()[-1]) # Direction vector self.outputs.remove(self.outputs.values()[-1]) # Direction vector
self.add_output('NodeSocketFloat', 'X') # World X self.add_output('NodeSocketFloat', 'X') # World X

View file

@ -42,7 +42,7 @@ class VectorMathNode(ArmLogicTreeNode):
if (self.property0 == 'Dot Product'): if (self.property0 == 'Dot Product'):
self.add_output('NodeSocketFloat', 'Scalar') # Scalar self.add_output('NodeSocketFloat', 'Scalar') # Scalar
property1: BoolProperty(name='Separator Out', default=False, set=set_bool, get=get_bool) property1: HaxeBoolProperty('property1', name='Separator Out', default=False, set=set_bool, get=get_bool)
@staticmethod @staticmethod
def get_enum_id_value(obj, prop_name, value): def get_enum_id_value(obj, prop_name, value):
@ -105,7 +105,8 @@ class VectorMathNode(ArmLogicTreeNode):
self.add_output('NodeSocketFloat', 'Length') self.add_output('NodeSocketFloat', 'Length')
self['property0'] = value self['property0'] = value
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Add', 'Add', 'Add'), items = [('Add', 'Add', 'Add'),
('Dot Product', 'Dot Product', 'Dot Product'), ('Dot Product', 'Dot Product', 'Dot Product'),
('Multiply', 'Multiply', 'Multiply'), ('Multiply', 'Multiply', 'Multiply'),

View file

@ -15,7 +15,7 @@ class CallGroupNode(ArmLogicTreeNode):
def property0(self): def property0(self):
return arm.utils.safesrc(bpy.data.worlds['Arm'].arm_project_package) + '.node.' + arm.utils.safesrc(self.property0_.name) return arm.utils.safesrc(bpy.data.worlds['Arm'].arm_project_package) + '.node.' + arm.utils.safesrc(self.property0_.name)
property0_: PointerProperty(name='Group', type=bpy.types.NodeTree) property0_: HaxePointerProperty('property0', name='Group', type=bpy.types.NodeTree)
def init(self, context): def init(self, context):
super(CallGroupNode, self).init(context) super(CallGroupNode, self).init(context)

View file

@ -6,7 +6,8 @@ class SetDebugConsoleSettings(ArmLogicTreeNode):
bl_label = 'Set Debug Console Settings' bl_label = 'Set Debug Console Settings'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('left', 'Anchor Left', 'Anchor debug console in the top left'), items = [('left', 'Anchor Left', 'Anchor debug console in the top left'),
('center', 'Anchor Center', 'Anchor debug console in the top center'), ('center', 'Anchor Center', 'Anchor debug console in the top center'),
('right', 'Anchor Right', 'Anchor the debug console in the top right')], ('right', 'Anchor Right', 'Anchor the debug console in the top right')],

View file

@ -9,7 +9,7 @@ class ExpressionNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
arm_section = 'haxe' arm_section = 'haxe'
property0: StringProperty(name='', default='') property0: HaxeStringProperty('property0', name='', default='')
def init(self, context): def init(self, context):
super(ExpressionNode, self).init(context) super(ExpressionNode, self).init(context)

View file

@ -15,7 +15,7 @@ class ScriptNode(ArmLogicTreeNode):
return bpy.data.texts[self.property0_].as_string() if self.property0_ in bpy.data.texts else '' return bpy.data.texts[self.property0_].as_string() if self.property0_ in bpy.data.texts else ''
property0_: StringProperty(name='Text', default='') property0_: HaxeStringProperty('property0', name='Text', default='')
def init(self, context): def init(self, context):
super(ScriptNode, self).init(context) super(ScriptNode, self).init(context)

View file

@ -7,7 +7,8 @@ class GetChildNode(ArmLogicTreeNode):
arm_section = 'relations' arm_section = 'relations'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('By Name', 'By Name', 'By Name'), items = [('By Name', 'By Name', 'By Name'),
('Contains', 'Contains', 'Contains'), ('Contains', 'Contains', 'Contains'),
('Starts With', 'Starts With', 'Starts With'), ('Starts With', 'Starts With', 'Starts With'),

View file

@ -9,7 +9,7 @@ class MeshNode(ArmLogicTreeNode):
bl_label = 'Mesh' bl_label = 'Mesh'
arm_version = 1 arm_version = 1
property0_get: PointerProperty(name='', type=bpy.types.Mesh) property0_get: HaxePointerProperty('property0_get', name='', type=bpy.types.Mesh)
def init(self, context): def init(self, context):
super(MeshNode, self).init(context) super(MeshNode, self).init(context)

View file

@ -9,7 +9,8 @@ class SetVisibleNode(ArmLogicTreeNode):
arm_section = 'props' arm_section = 'props'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('object', 'Object', 'All object componenets visibility'), items = [('object', 'Object', 'All object componenets visibility'),
('mesh', 'Mesh', 'Mesh visibility only'), ('mesh', 'Mesh', 'Mesh visibility only'),
('shadow', 'Shadow', 'Shadow visibility only'), ('shadow', 'Shadow', 'Shadow visibility only'),

View file

@ -6,7 +6,8 @@ class SpawnObjectByNameNode(ArmLogicTreeNode):
bl_label = 'Spawn Object By Name' bl_label = 'Spawn Object By Name'
arm_version = 1 arm_version = 1
property0: PointerProperty( property0: HaxePointerProperty(
'property0',
type=bpy.types.Scene, name='Scene', type=bpy.types.Scene, name='Scene',
description='The scene from which to take the object') description='The scene from which to take the object')

View file

@ -59,18 +59,16 @@ class AddRigidBodyNode(ArmLogicTreeNode):
further down.""" further down."""
self.update_sockets(context) self.update_sockets(context)
@property property1: HaxeBoolProperty(
def property1(self): 'property1',
return 'true' if self.property1_ else 'false'
property1_: BoolProperty(
name="Advanced", name="Advanced",
description="Show advanced options", description="Show advanced options",
default=False, default=False,
update=update_advanced update=update_advanced
) )
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Box', 'Box', 'Box'), items = [('Box', 'Box', 'Box'),
('Sphere', 'Sphere', 'Sphere'), ('Sphere', 'Sphere', 'Sphere'),
('Capsule', 'Capsule', 'Capsule'), ('Capsule', 'Capsule', 'Capsule'),
@ -122,5 +120,5 @@ class AddRigidBodyNode(ArmLogicTreeNode):
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, "property1_") layout.prop(self, "property1")
layout.prop(self, 'property0') layout.prop(self, 'property0')

View file

@ -124,7 +124,8 @@ class AddPhysicsConstraintNode(ArmLogicTreeNode):
self['property0'] = value self['property0'] = value
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Fixed', 'Fixed', 'Fixed'), items = [('Fixed', 'Fixed', 'Fixed'),
('Point', 'Point', 'Point'), ('Point', 'Point', 'Point'),
('Hinge', 'Hinge', 'Hinge'), ('Hinge', 'Hinge', 'Hinge'),

View file

@ -16,7 +16,8 @@ class OnContactNode(ArmLogicTreeNode):
arm_section = 'contact' arm_section = 'contact'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('begin', 'Begin', 'The contact between the rigid bodies begins'), items = [('begin', 'Begin', 'The contact between the rigid bodies begins'),
('overlap', 'Overlap', 'The contact between the rigid bodies is happening'), ('overlap', 'Overlap', 'The contact between the rigid bodies is happening'),
('end', 'End', 'The contact between the rigid bodies ends')], ('end', 'End', 'The contact between the rigid bodies ends')],

View file

@ -7,7 +7,8 @@ class OnContactArrayNode(ArmLogicTreeNode):
arm_section = 'contact' arm_section = 'contact'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('begin', 'Begin', 'The contact between the rigid bodies begins'), items = [('begin', 'Begin', 'The contact between the rigid bodies begins'),
('overlap', 'Overlap', 'The contact between the rigid bodies is happening'), ('overlap', 'Overlap', 'The contact between the rigid bodies is happening'),
('end', 'End', 'The contact between the rigid bodies ends')], ('end', 'End', 'The contact between the rigid bodies ends')],

View file

@ -10,7 +10,8 @@ class OnVolumeTriggerNode(ArmLogicTreeNode):
bl_label = 'On Volume Trigger' bl_label = 'On Volume Trigger'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('begin', 'Begin', 'The contact between the rigid bodies begins'), items = [('begin', 'Begin', 'The contact between the rigid bodies begins'),
('overlap', 'Overlap', 'The contact between the rigid bodies is happening'), ('overlap', 'Overlap', 'The contact between the rigid bodies is happening'),
('end', 'End', 'The contact between the rigid bodies ends')], ('end', 'End', 'The contact between the rigid bodies ends')],

View file

@ -26,32 +26,21 @@ class PhysicsConstraintNode(ArmLogicTreeNode):
def update_spring(self, context): def update_spring(self, context):
self.update_sockets(context) self.update_sockets(context)
property0: EnumProperty( property0: HaxeEnumProperty(
items = [('Linear', 'Linear', 'Linear'), 'property0',
('Angular', 'Angular', 'Angular')], items=[('Linear', 'Linear', 'Linear'),
('Angular', 'Angular', 'Angular')],
name='Type', default='Linear') name='Type', default='Linear')
@property
def property1(self):
if(self.property1_ == 'X'):
return 'X'
if(self.property1_ == 'Y'):
return 'Y'
if(self.property1_ == 'Z'):
return 'Z'
property1_: EnumProperty( property1: HaxeEnumProperty(
items = [('X', 'X', 'X'), 'property1',
('Y', 'Y', 'Y'), items=[('X', 'X', 'X'),
('Z', 'Z', 'Z')], ('Y', 'Y', 'Y'),
('Z', 'Z', 'Z')],
name='Axis', default='X') name='Axis', default='X')
@property property2: HaxeBoolProperty(
def property2(self): 'property2',
if(self.property2_):
return 'true' if self.property2_ else 'false'
property2_: BoolProperty(
name="Spring", name="Spring",
description="Is a spring constraint", description="Is a spring constraint",
default=False, default=False,
@ -66,14 +55,13 @@ class PhysicsConstraintNode(ArmLogicTreeNode):
self.add_input('NodeSocketFloat', 'Lower limit') self.add_input('NodeSocketFloat', 'Lower limit')
self.add_input('NodeSocketFloat', 'Upper limit') self.add_input('NodeSocketFloat', 'Upper limit')
self.add_output('NodeSocketShader', 'Constraint') self.add_output('NodeSocketShader', 'Constraint')
def update_sockets(self, context):
while (len(self.inputs) > 0): def update_sockets(self, context):
while len(self.inputs) > 0:
self.inputs.remove(self.inputs.values()[-1]) self.inputs.remove(self.inputs.values()[-1])
# Add dynamic input sockets # Add dynamic input sockets
if self.property2_: if self.property2:
self.add_input('NodeSocketFloat', 'Stiffness', 10.0) self.add_input('NodeSocketFloat', 'Stiffness', 10.0)
self.add_input('NodeSocketFloat', 'Damping', 0.5) self.add_input('NodeSocketFloat', 'Damping', 0.5)
else: else:
@ -82,6 +70,5 @@ class PhysicsConstraintNode(ArmLogicTreeNode):
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property0') layout.prop(self, 'property0')
layout.prop(self, 'property1_') layout.prop(self, 'property1')
layout.prop(self, 'property2_') layout.prop(self, 'property2')

View file

@ -7,7 +7,8 @@ class SetActivationStateNode(ArmLogicTreeNode):
bl_icon = 'NONE' bl_icon = 'NONE'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('inactive', 'Inactive', 'The rigid body simulation is deactivated'), items = [('inactive', 'Inactive', 'The rigid body simulation is deactivated'),
('active', 'Active', 'The rigid body simulation is activated'), ('active', 'Active', 'The rigid body simulation is activated'),
('always active', 'Always Active', 'The rigid body simulation is never deactivated'), ('always active', 'Always Active', 'The rigid body simulation is never deactivated'),

View file

@ -12,7 +12,8 @@ class VolumeTriggerNode(ArmLogicTreeNode):
arm_section = 'misc' arm_section = 'misc'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('begin', 'Begin', 'The contact between the rigid bodies begins'), items = [('begin', 'Begin', 'The contact between the rigid bodies begins'),
('overlap', 'Overlap', 'The contact between the rigid bodies is happening'), ('overlap', 'Overlap', 'The contact between the rigid bodies is happening'),
('end', 'End', 'The contact between the rigid bodies ends')], ('end', 'End', 'The contact between the rigid bodies ends')],

View file

@ -32,7 +32,8 @@ class ColorgradingSetGlobalNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
# TODO: RRESET FILE OPTION FOR THE BELOW # TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty( property0 : HaxeEnumProperty(
'property0',
items = [('RGB', 'RGB', 'RGB'), items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')], ('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node) name='Mode', default='Uniform', update=update_node)

View file

@ -32,7 +32,8 @@ class ColorgradingSetHighlightNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
# TODO: RRESET FILE OPTION FOR THE BELOW # TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('RGB', 'RGB', 'RGB'), items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')], ('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node) name='Mode', default='Uniform', update=update_node)

View file

@ -32,7 +32,8 @@ class ColorgradingSetMidtoneNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
# TODO: RRESET FILE OPTION FOR THE BELOW # TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('RGB', 'RGB', 'RGB'), items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')], ('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node) name='Mode', default='Uniform', update=update_node)

View file

@ -32,7 +32,8 @@ class ColorgradingSetShadowNode(ArmLogicTreeNode):
arm_version = 1 arm_version = 1
# TODO: RRESET FILE OPTION FOR THE BELOW # TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('RGB', 'RGB', 'RGB'), items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')], ('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node) name='Mode', default='Uniform', update=update_node)

View file

@ -5,7 +5,8 @@ class RpMSAANode(ArmLogicTreeNode):
bl_idname = 'LNRpMSAANode' bl_idname = 'LNRpMSAANode'
bl_label = 'Set MSAA Quality' bl_label = 'Set MSAA Quality'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('1', '1', '1'), items = [('1', '1', '1'),
('2', '2', '2'), ('2', '2', '2'),
('4', '4', '4'), ('4', '4', '4'),

View file

@ -5,7 +5,8 @@ class RpConfigNode(ArmLogicTreeNode):
bl_idname = 'LNRpConfigNode' bl_idname = 'LNRpConfigNode'
bl_label = 'Set Post Process Quality' bl_label = 'Set Post Process Quality'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('SSGI', 'SSGI', 'SSGI'), items = [('SSGI', 'SSGI', 'SSGI'),
('SSR', 'SSR', 'SSR'), ('SSR', 'SSR', 'SSR'),
('Bloom', 'Bloom', 'Bloom'), ('Bloom', 'Bloom', 'Bloom'),

View file

@ -21,7 +21,8 @@ class SetShaderUniformNode(ArmLogicTreeNode):
elif self.property0 in ('vec2', 'vec3', 'vec4'): elif self.property0 in ('vec2', 'vec3', 'vec4'):
self.add_input('NodeSocketVector', 'Vector') self.add_input('NodeSocketVector', 'Vector')
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('int', 'int', 'int'), items = [('int', 'int', 'int'),
('float', 'float', 'float'), ('float', 'float', 'float'),
('vec2', 'vec2', 'vec2'), ('vec2', 'vec2', 'vec2'),

View file

@ -5,7 +5,8 @@ class RpShadowQualityNode(ArmLogicTreeNode):
bl_idname = 'LNRpShadowQualityNode' bl_idname = 'LNRpShadowQualityNode'
bl_label = 'Set Shadows Quality' bl_label = 'Set Shadows Quality'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('High', 'High', 'High'), items = [('High', 'High', 'High'),
('Medium', 'Medium', 'Medium'), ('Medium', 'Medium', 'Medium'),
('Low', 'Low', 'Low') ('Low', 'Low', 'Low')

View file

@ -5,7 +5,8 @@ class RpSuperSampleNode(ArmLogicTreeNode):
bl_idname = 'LNRpSuperSampleNode' bl_idname = 'LNRpSuperSampleNode'
bl_label = 'Set SSAA Quality' bl_label = 'Set SSAA Quality'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('1', '1', '1'), items = [('1', '1', '1'),
('1.5', '1.5', '1.5'), ('1.5', '1.5', '1.5'),
('2', '2', '2'), ('2', '2', '2'),

View file

@ -12,7 +12,7 @@ class GroupNode(ArmLogicTreeNode):
arm_section = 'collection' arm_section = 'collection'
arm_version = 1 arm_version = 1
property0: PointerProperty(name='', type=bpy.types.Collection) property0: HaxePointerProperty('property0', name='', type=bpy.types.Collection)
def init(self, context): def init(self, context):
super(GroupNode, self).init(context) super(GroupNode, self).init(context)

View file

@ -9,7 +9,7 @@ class SceneNode(ArmLogicTreeNode):
bl_label = 'Scene' bl_label = 'Scene'
arm_version = 1 arm_version = 1
property0_get: PointerProperty(name='', type=bpy.types.Scene) property0_get: HaxePointerProperty('property0_get', name='', type=bpy.types.Scene)
def init(self, context): def init(self, context):
super(SceneNode, self).init(context) super(SceneNode, self).init(context)

View file

@ -28,7 +28,7 @@ class SpawnCollectionNode(ArmLogicTreeNode):
arm_section = 'collection' arm_section = 'collection'
arm_version = 1 arm_version = 1
property0: PointerProperty(name='Collection', type=bpy.types.Collection) property0: HaxePointerProperty('property0', name='Collection', type=bpy.types.Collection)
def init(self, context): def init(self, context):
super(SpawnCollectionNode, self).init(context) super(SpawnCollectionNode, self).init(context)

View file

@ -31,25 +31,30 @@ class PlaySoundNode(ArmLogicTreeNode):
bl_width_default = 200 bl_width_default = 200
arm_version = 1 arm_version = 1
property0: PointerProperty(name='', type=bpy.types.Sound) property0: HaxePointerProperty('property0', name='', type=bpy.types.Sound)
property1: BoolProperty( property1: HaxeBoolProperty(
'property1',
name='Loop', name='Loop',
description='Play the sound in a loop', description='Play the sound in a loop',
default=False) default=False)
property2: BoolProperty( property2: HaxeBoolProperty(
'property2',
name='Retrigger', name='Retrigger',
description='Play the sound from the beginning every time', description='Play the sound from the beginning every time',
default=False) default=False)
property3: BoolProperty( property3: HaxeBoolProperty(
'property3',
name='Use Custom Sample Rate', name='Use Custom Sample Rate',
description='If enabled, override the default sample rate', description='If enabled, override the default sample rate',
default=False) default=False)
property4: IntProperty( property4: HaxeIntProperty(
'property4',
name='Sample Rate', name='Sample Rate',
description='Set the sample rate used to play this sound', description='Set the sample rate used to play this sound',
default=44100, default=44100,
min=0) min=0)
property5: BoolProperty( property5: HaxeBoolProperty(
'property5',
name='Stream', name='Stream',
description='Stream the sound from disk', description='Stream the sound from disk',
default=False default=False

View file

@ -5,7 +5,8 @@ class CaseStringNode(ArmLogicTreeNode):
bl_idname = 'LNCaseStringNode' bl_idname = 'LNCaseStringNode'
bl_label = 'String Case' bl_label = 'String Case'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Upper Case', 'Upper Case', 'Upper Case'), items = [('Upper Case', 'Upper Case', 'Upper Case'),
('Lower Case', 'Lower Case', 'Lower Case'), ('Lower Case', 'Lower Case', 'Lower Case'),
], ],

View file

@ -5,7 +5,8 @@ class ContainsStringNode(ArmLogicTreeNode):
bl_idname = 'LNContainsStringNode' bl_idname = 'LNContainsStringNode'
bl_label = 'String Contains' bl_label = 'String Contains'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Contains', 'Contains', 'Contains'), items = [('Contains', 'Contains', 'Contains'),
('Starts With', 'Starts With', 'Starts With'), ('Starts With', 'Starts With', 'Starts With'),
('Ends With', 'Ends With', 'Ends With'), ('Ends With', 'Ends With', 'Ends With'),

View file

@ -8,7 +8,7 @@ class TraitNode(ArmLogicTreeNode):
bl_label = 'Trait' bl_label = 'Trait'
arm_version = 1 arm_version = 1
property0: StringProperty(name='', default='') property0: HaxeStringProperty('property0', name='', default='')
def init(self, context): def init(self, context):
super(TraitNode, self).init(context) super(TraitNode, self).init(context)

View file

@ -7,7 +7,8 @@ class GetWorldNode(ArmLogicTreeNode):
arm_section = 'rotation' arm_section = 'rotation'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Right', 'Right', 'The object right (X) direction'), items = [('Right', 'Right', 'The object right (X) direction'),
('Look', 'Look', 'The object look (Y) direction'), ('Look', 'Look', 'The object look (Y) direction'),
('Up', 'Up', 'The object up (Z) direction')], ('Up', 'Up', 'The object up (Z) direction')],

View file

@ -7,7 +7,8 @@ class LookAtNode(ArmLogicTreeNode):
arm_section = 'rotation' arm_section = 'rotation'
arm_version = 1 arm_version = 1
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('X', ' X', 'X'), items = [('X', ' X', 'X'),
('-X', '-X', '-X'), ('-X', '-X', '-X'),
('Y', ' Y', 'Y'), ('Y', ' Y', 'Y'),

View file

@ -40,10 +40,11 @@ class RotateObjectNode(ArmLogicTreeNode):
else: else:
layout.prop(self, 'property0') layout.prop(self, 'property0')
property0: EnumProperty( property0: HaxeEnumProperty(
items = [('Euler Angles', 'Euler Angles', 'Euler Angles'), 'property0',
('Angle Axies (Radians)', 'Angle Axies (Radians)', 'Angle Axies (Radians)'), items=[('Euler Angles', 'Euler Angles', 'Euler Angles'),
('Angle Axies (Degrees)', 'Angle Axies (Degrees)', 'Angle Axies (Degrees)'), ('Angle Axies (Radians)', 'Angle Axies (Radians)', 'Angle Axies (Radians)'),
('Quaternion', 'Quaternion', 'Quaternion')], ('Angle Axies (Degrees)', 'Angle Axies (Degrees)', 'Angle Axies (Degrees)'),
('Quaternion', 'Quaternion', 'Quaternion')],
name='', default='Euler Angles', name='', default='Euler Angles',
update = on_property_update) update=on_property_update)

View file

@ -33,7 +33,8 @@ class SetRotationNode(ArmLogicTreeNode):
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property0') layout.prop(self, 'property0')
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Euler Angles', 'Euler Angles', 'Euler Angles'), items = [('Euler Angles', 'Euler Angles', 'Euler Angles'),
('Angle Axies (Radians)', 'Angle Axies (Radians)', 'Angle Axies (Radians)'), ('Angle Axies (Radians)', 'Angle Axies (Radians)', 'Angle Axies (Radians)'),
('Angle Axies (Degrees)', 'Angle Axies (Degrees)', 'Angle Axies (Degrees)'), ('Angle Axies (Degrees)', 'Angle Axies (Degrees)', 'Angle Axies (Degrees)'),

View file

@ -31,7 +31,8 @@ class VectorFromTransformNode(ArmLogicTreeNode):
def draw_buttons(self, context, layout): def draw_buttons(self, context, layout):
layout.prop(self, 'property0') layout.prop(self, 'property0')
property0: EnumProperty( property0: HaxeEnumProperty(
'property0',
items = [('Right', 'Right', 'The transform right (X) direction'), items = [('Right', 'Right', 'The transform right (X) direction'),
('Look', 'Look', 'The transform look (Y) direction'), ('Look', 'Look', 'The transform look (Y) direction'),
('Up', 'Up', 'The transform up (Z) direction'), ('Up', 'Up', 'The transform up (Z) direction'),

View file

@ -158,26 +158,9 @@ def build_node(node: bpy.types.Node, f: TextIO) -> Optional[str]:
f.write(f'\t\tthis.nodes["{name[1:]}"] = {name};\n') f.write(f'\t\tthis.nodes["{name[1:]}"] = {name};\n')
# Properties # Properties
for i in range(0, 10): for prop_name in arm.node_utils.get_haxe_property_names(node):
prop_name = 'property' + str(i) + '_get' prop = arm.node_utils.haxe_format_prop(node, prop_name)
prop_found = hasattr(node, prop_name) f.write('\t\t' + name + '.' + prop_name + ' = ' + prop + ';\n')
if not prop_found:
prop_name = 'property' + str(i)
prop_found = hasattr(node, prop_name)
if prop_found:
prop = getattr(node, prop_name)
if isinstance(prop, str):
prop = '"' + str(prop) + '"'
elif isinstance(prop, bool):
prop = str(prop).lower()
elif hasattr(prop, 'name'): # PointerProperty
prop = '"' + str(prop.name) + '"'
else:
if prop is None:
prop = 'null'
else:
prop = str(prop)
f.write('\t\t' + name + '.property' + str(i) + ' = ' + prop + ';\n')
# Create inputs # Create inputs
for inp in node.inputs: for inp in node.inputs:
@ -284,23 +267,16 @@ def build_default_node(inp: bpy.types.NodeSocket):
if is_custom_socket: if is_custom_socket:
# ArmCustomSockets need to implement get_default_value() # ArmCustomSockets need to implement get_default_value()
default_value = inp.get_default_value() default_value = arm.node_utils.haxe_format_socket_val(inp.get_default_value())
if isinstance(default_value, str):
default_value = '"{:s}"'.format(default_value.replace('"', '\\"') )
inp_type = inp.arm_socket_type # any custom socket's `type` is "VALUE". might as well have valuable type information for custom nodes as well. inp_type = inp.arm_socket_type # any custom socket's `type` is "VALUE". might as well have valuable type information for custom nodes as well.
else: else:
if hasattr(inp, 'default_value'): if hasattr(inp, 'default_value'):
default_value = inp.default_value default_value = inp.default_value
else: else:
default_value = None default_value = None
if isinstance(default_value, str): default_value = arm.node_utils.haxe_format_socket_val(default_value)
default_value = '"{:s}"'.format(default_value.replace('"', '\\"') )
inp_type = inp.type inp_type = inp.type
# Don't write 'None' into the Haxe code
if default_value is None:
default_value = 'null'
if inp_type == 'VECTOR': if inp_type == 'VECTOR':
return f'new armory.logicnode.VectorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]})' return f'new armory.logicnode.VectorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]})'
elif inp_type == 'RGBA': elif inp_type == 'RGBA':

View file

@ -1,4 +1,4 @@
from typing import Type, Union from typing import Any, Generator, Type, Union
import bpy import bpy
from bpy.types import NodeSocket, NodeInputs, NodeOutputs from bpy.types import NodeSocket, NodeInputs, NodeOutputs
@ -83,6 +83,50 @@ def get_export_node_name(node: bpy.types.Node) -> str:
return '_' + arm.utils.safesrc(node.name) return '_' + arm.utils.safesrc(node.name)
def get_haxe_property_names(node: bpy.types.Node) -> Generator[str, None, None]:
"""Generator that yields the names of all node properties that have
a counterpart in the node's Haxe class.
"""
for i in range(0, 10):
prop_name = f'property{i}_get'
prop_found = hasattr(node, prop_name)
if not prop_found:
prop_name = f'property{i}'
prop_found = hasattr(node, prop_name)
if prop_found:
yield prop_name
def haxe_format_socket_val(socket_val: Any) -> str:
"""Formats a socket value to be valid Haxe syntax."""
if isinstance(socket_val, str):
socket_val = '"{:s}"'.format(socket_val.replace('"', '\\"'))
elif socket_val is None:
# Don't write 'None' into the Haxe code
socket_val = 'null'
return socket_val
def haxe_format_prop(node: bpy.types.Node, prop_name: str) -> str:
"""Formats a property value to be valid Haxe syntax."""
prop_value = getattr(node, prop_name)
if isinstance(prop_value, str):
prop_value = '"' + str(prop_value) + '"'
elif isinstance(prop_value, bool):
prop_value = str(prop_value).lower()
elif hasattr(prop_value, 'name'): # PointerProperty
prop_value = '"' + str(prop_value.name) + '"'
else:
if prop_value is None:
prop_value = 'null'
else:
prop_value = str(prop_value)
return prop_value
def nodetype_to_nodeitem(node_type: Type[bpy.types.Node]) -> NodeItem: def nodetype_to_nodeitem(node_type: Type[bpy.types.Node]) -> NodeItem:
"""Create a NodeItem from a given node class.""" """Create a NodeItem from a given node class."""
# Internal node types seem to have no bl_idname attribute # Internal node types seem to have no bl_idname attribute