Improve InputMap and add nodes to it
This commit is contained in:
parent
14b18408aa
commit
919512fad0
24
Sources/armory/logicnode/GetInputMapKeyNode.hx
Normal file
24
Sources/armory/logicnode/GetInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,24 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class GetInputMapKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var inputMap = inputs[0].get();
|
||||
var key = inputs[1].get();
|
||||
|
||||
var k = InputMap.getInputMapKey(inputMap, key);
|
||||
|
||||
if (k != null) {
|
||||
if (from == 0) return k.scale;
|
||||
else if (from == 1) return k.deadzone;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
35
Sources/armory/logicnode/OnInputMapNode.hx
Normal file
35
Sources/armory/logicnode/OnInputMapNode.hx
Normal file
|
@ -0,0 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class OnInputMapNode extends LogicNode {
|
||||
|
||||
var inputMap: Null<InputMap>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
||||
tree.notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
function update() {
|
||||
var i = inputs[0].get();
|
||||
|
||||
inputMap = InputMap.getInputMap(i);
|
||||
|
||||
if (inputMap != null) {
|
||||
if (inputMap.started()) {
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
if (inputMap.released()) {
|
||||
runOutput(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (from == 2) return inputMap.value();
|
||||
else return inputMap.lastKeyPressed;
|
||||
}
|
||||
}
|
47
Sources/armory/logicnode/SetInputMapKeyNode.hx
Normal file
47
Sources/armory/logicnode/SetInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,47 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class SetInputMapKeyNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var inputMap = inputs[1].get();
|
||||
var key = inputs[2].get();
|
||||
var scale = inputs[3].get();
|
||||
var deadzone = inputs[4].get();
|
||||
var index = inputs[5].get();
|
||||
|
||||
var i = InputMap.getInputMap(inputMap);
|
||||
|
||||
if (i == null) {
|
||||
i = InputMap.addInputMap(inputMap);
|
||||
}
|
||||
|
||||
var k = InputMap.getInputMapKey(inputMap, key);
|
||||
|
||||
if (k == null) {
|
||||
switch(property0) {
|
||||
case "keyboard": k = i.addKeyboard(key, scale);
|
||||
case "mouse": k = i.addMouse(key, scale, deadzone);
|
||||
case "gamepad": {
|
||||
k = i.addGamepad(key, scale, deadzone);
|
||||
k.setIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
k.key = key;
|
||||
k.scale = scale;
|
||||
k.deadzone = deadzone;
|
||||
k.setIndex(index);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
|
@ -4,347 +4,209 @@ import kha.FastFloat;
|
|||
import iron.system.Input;
|
||||
|
||||
class InputMap {
|
||||
var commands = new Map<String, Null<Array<InputCommand>>>();
|
||||
|
||||
static var inputMaps(default, null) = new Map<String, InputMap>();
|
||||
|
||||
public var inputs(default, null) = new Array<InputMapKey>();
|
||||
public var lastKeyPressed(default, null) = "";
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function addKeyboard(config: String) {
|
||||
var command = new KeyboardCommand();
|
||||
return addCustomCommand(command, config);
|
||||
public static function getInputMap(inputMap: String): Null<InputMap> {
|
||||
if (inputMaps.exists(inputMap)) {
|
||||
return inputMaps[inputMap];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function addGamepad(config: String) {
|
||||
var command = new GamepadCommand();
|
||||
return addCustomCommand(command, config);
|
||||
public static function addInputMap(inputMap: String): InputMap {
|
||||
return inputMaps[inputMap] = new InputMap();
|
||||
}
|
||||
|
||||
public function addCustomCommand(command: InputCommand, config: String) {
|
||||
if (commands[config] == null) commands[config] = new Array<InputCommand>();
|
||||
commands[config].push(command);
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
class ActionMap extends InputMap {
|
||||
|
||||
public inline function started(config: String) {
|
||||
var started = false;
|
||||
|
||||
for (c in commands[config]) {
|
||||
if (c.started()) {
|
||||
started = true;
|
||||
break;
|
||||
public static function getInputMapKey(inputMap: String, key: String): Null<InputMapKey> {
|
||||
if (inputMaps.exists(inputMap)) {
|
||||
for (i in inputMaps[inputMap].inputs) {
|
||||
if (i.key == key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return started;
|
||||
return null;
|
||||
}
|
||||
|
||||
public inline function released(config: String) {
|
||||
var released = false;
|
||||
public function addKeyboard(key: String, scale: FastFloat = 1.0): InputMapKey {
|
||||
return addInput(new KeyboardKey(key, scale));
|
||||
}
|
||||
|
||||
for (c in commands[config]) {
|
||||
if (c.released()) {
|
||||
released = true;
|
||||
break;
|
||||
}
|
||||
public function addMouse(key: String, scale: FastFloat = 1.0, deadzone: FastFloat = 0.0): InputMapKey {
|
||||
return addInput(new MouseKey(key, scale, deadzone));
|
||||
}
|
||||
|
||||
public function addGamepad(key: String, scale: FastFloat = 1.0, deadzone: FastFloat = 0.0): InputMapKey {
|
||||
return addInput(new GamepadKey(key, scale, deadzone));
|
||||
}
|
||||
|
||||
public function addInput(input: InputMapKey): InputMapKey {
|
||||
inputs.push(input);
|
||||
return input;
|
||||
}
|
||||
|
||||
public function removeInput(input: InputMapKey): Bool {
|
||||
return inputs.remove(input);
|
||||
}
|
||||
|
||||
public function value(): FastFloat {
|
||||
var v = 0.0;
|
||||
|
||||
for (i in inputs) {
|
||||
v += i.value();
|
||||
}
|
||||
|
||||
return released;
|
||||
}
|
||||
}
|
||||
|
||||
class AxisMap extends InputMap {
|
||||
var scale: FastFloat = 1.0;
|
||||
|
||||
public inline function getAxis(config: String) {
|
||||
var axis = 0.0;
|
||||
|
||||
for (c in commands[config]) {
|
||||
var tempAxis = c.getAxis();
|
||||
|
||||
if (tempAxis != 0.0 && tempAxis != axis) {
|
||||
axis += tempAxis;
|
||||
scale = c.getScale();
|
||||
}
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
public inline function getScale() {
|
||||
return scale;
|
||||
}
|
||||
}
|
||||
|
||||
class InputCommand {
|
||||
var keys = new Array<String>();
|
||||
var modifiers = new Array<String>();
|
||||
var displacementKeys = new Array<String>();
|
||||
var displacementModifiers = new Array<String>();
|
||||
var deadzone: FastFloat = 0.0;
|
||||
var scale: FastFloat = 1.0;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function setKeys(keys: Array<String>) {
|
||||
return this.keys = keys;
|
||||
}
|
||||
|
||||
public function setMods(modifiers: Array<String>) {
|
||||
return this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
public function setDisplacementKeys(keys: Array<String>) {
|
||||
return displacementKeys = keys;
|
||||
}
|
||||
|
||||
public function setDisplacementMods(modifiers: Array<String>) {
|
||||
return displacementModifiers = modifiers;
|
||||
}
|
||||
|
||||
public function setDeadzone(deadzone: FastFloat) {
|
||||
return this.deadzone = deadzone;
|
||||
}
|
||||
|
||||
public function setScale(scale: FastFloat) {
|
||||
return this.scale = scale;
|
||||
}
|
||||
|
||||
public function getScale() {
|
||||
return scale;
|
||||
return v;
|
||||
}
|
||||
|
||||
public function started() {
|
||||
for (i in inputs) {
|
||||
if (i.started()) {
|
||||
lastKeyPressed = i.key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function released() {
|
||||
for (i in inputs) {
|
||||
if (i.released()) {
|
||||
lastKeyPressed = i.key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class InputMapKey {
|
||||
|
||||
public var key: String;
|
||||
public var scale: FastFloat;
|
||||
public var deadzone: FastFloat;
|
||||
|
||||
public function new(key: String, scale = 1.0, deadzone = 0.0) {
|
||||
this.key = key.toLowerCase();
|
||||
this.scale = scale;
|
||||
this.deadzone = deadzone;
|
||||
}
|
||||
|
||||
public function started(): Bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getAxis(): FastFloat {
|
||||
public function released(): Bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function value(): FastFloat {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
class KeyboardCommand extends InputCommand {
|
||||
var keyboard = Input.getKeyboard();
|
||||
var mouse = Input.getMouse();
|
||||
public function setIndex(index: Int) {}
|
||||
|
||||
public inline override function started() {
|
||||
for (k in keys) {
|
||||
if (keyboard.started(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
function evalDeadzone(value: FastFloat): FastFloat {
|
||||
var v = 0.0;
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
if (value > deadzone) {
|
||||
v = value - deadzone;
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (value < -deadzone) {
|
||||
v = value + deadzone;
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
if (mouse.started(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return v * scale;
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
for (k in keys) {
|
||||
if (keyboard.released(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
function evalPressure(value: FastFloat): FastFloat {
|
||||
var v = value - deadzone;
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
if (v > 0.0) {
|
||||
v /= (1.0 - deadzone);
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
v = 0.0;
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
if (mouse.released(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public inline override function getAxis() {
|
||||
var axis = 0.0;
|
||||
var movementX = mouse.movementX;
|
||||
var movementY = mouse.movementY;
|
||||
var wheelDelta = mouse.wheelDelta;
|
||||
|
||||
for (k in keys) {
|
||||
if (keyboard.down(k)) {
|
||||
axis++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (m in modifiers) {
|
||||
if (keyboard.down(m)) {
|
||||
axis --;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
switch (k) {
|
||||
case "moved x": if (movementX > deadzone) axis++;
|
||||
case "moved y": if (movementY > deadzone) axis--;
|
||||
case "wheel": if (wheelDelta < -deadzone) axis++;
|
||||
case "movement x": if (movementX > deadzone) return movementX - deadzone;
|
||||
case "movement y": if (movementY > deadzone) return movementY - deadzone;
|
||||
default: {
|
||||
if (mouse.down(k)) {
|
||||
axis ++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
switch (m) {
|
||||
case "moved x": if (movementX < -deadzone) axis--;
|
||||
case "moved y": if (movementY < -deadzone) axis++;
|
||||
case "wheel": if (wheelDelta > deadzone) axis--;
|
||||
case "movement x": if (movementX < -deadzone) return movementX + deadzone;
|
||||
case "movement y": if (movementY < -deadzone) return movementY + deadzone;
|
||||
default: {
|
||||
if (mouse.down(m)) {
|
||||
axis --;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return axis > 1 ? 1 : axis < -1 ? -1 : axis;
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
class GamepadCommand extends InputCommand {
|
||||
var gamepad = Input.getGamepad(0);
|
||||
class KeyboardKey extends InputMapKey {
|
||||
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
public inline override function started() {
|
||||
for (k in keys) {
|
||||
if (gamepad.started(k)) {
|
||||
for (m in modifiers) {
|
||||
if (gamepad.down(m) < deadzone) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return kb.started(key);
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
for (k in keys) {
|
||||
if (gamepad.released(k)) {
|
||||
for (m in modifiers) {
|
||||
if (gamepad.down(m) < deadzone) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return kb.released(key);
|
||||
}
|
||||
|
||||
public inline override function getAxis() {
|
||||
var axis = 0.0;
|
||||
var rsMovementX = gamepad.rightStick.movementX;
|
||||
var rsMovementY = gamepad.rightStick.movementY;
|
||||
var lsMovementX = gamepad.leftStick.movementX;
|
||||
var lsMovementY = gamepad.leftStick.movementY;
|
||||
var rtPressure = gamepad.down("r2") > 0.0 ? (gamepad.down("r2") - deadzone) / (1 - deadzone) : 0.0;
|
||||
var ltPressure = gamepad.down("l2") > 0.0 ? (gamepad.down("r2") - deadzone) / (1 - deadzone) : 0.0;
|
||||
|
||||
for (k in keys) {
|
||||
switch(k) {
|
||||
case "rtPressure": axis += rtPressure;
|
||||
case "ltPressure": axis += ltPressure;
|
||||
default: {
|
||||
if (gamepad.down(k) > deadzone) {
|
||||
axis++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (m in modifiers) {
|
||||
switch (m) {
|
||||
case "rtPressure": axis -= rtPressure;
|
||||
case "ltPressure": axis -= ltPressure;
|
||||
default: {
|
||||
if (gamepad.down(m) > deadzone) {
|
||||
axis--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
switch(k) {
|
||||
case "rs moved x": if (rsMovementX > deadzone) axis++;
|
||||
case "rs moved y": if (rsMovementY > deadzone) axis++;
|
||||
case "ls moved x": if (lsMovementX > deadzone) axis++;
|
||||
case "ls moved y": if (lsMovementY > deadzone) axis++;
|
||||
case "rs movement x": if (rsMovementX > deadzone) return rsMovementX - deadzone;
|
||||
case "rs movement y": if (rsMovementY > deadzone) return rsMovementY - deadzone;
|
||||
case "ls movement x": if (lsMovementX > deadzone) return lsMovementX - deadzone;
|
||||
case "ls movement y": if (lsMovementY > deadzone) return lsMovementY - deadzone;
|
||||
}
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
switch (m) {
|
||||
case "rs moved x": if (rsMovementX < -deadzone) axis--;
|
||||
case "rs moved y": if (rsMovementY < -deadzone) axis--;
|
||||
case "ls moved x": if (lsMovementX < -deadzone) axis--;
|
||||
case "ls moved y": if (lsMovementY < -deadzone) axis--;
|
||||
case "rs movement x": if (rsMovementX < -deadzone) return rsMovementX + deadzone;
|
||||
case "rs movement y": if (rsMovementY < -deadzone) return rsMovementY + deadzone;
|
||||
case "ls movement x": if (lsMovementX < -deadzone) return lsMovementX + deadzone;
|
||||
case "ls movement y": if (lsMovementY < -deadzone) return lsMovementY + deadzone;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return axis > 1 ? 1 : axis < -1 ? -1 : axis;
|
||||
public inline override function value(): FastFloat {
|
||||
return kb.down(key) ? scale : 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MouseKey extends InputMapKey {
|
||||
|
||||
var m = Input.getMouse();
|
||||
|
||||
public inline override function started() {
|
||||
return m.started(key);
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
return m.released(key);
|
||||
}
|
||||
|
||||
public override function value(): FastFloat {
|
||||
return switch (key) {
|
||||
case "movement x": evalDeadzone(m.movementX);
|
||||
case "movement y": evalDeadzone(m.movementY);
|
||||
case "wheel": evalDeadzone(m.wheelDelta);
|
||||
default: m.down(key) ? scale : 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GamepadKey extends InputMapKey {
|
||||
|
||||
var g = Input.getGamepad();
|
||||
|
||||
public inline override function started() {
|
||||
return g.started(key);
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
return g.released(key);
|
||||
}
|
||||
|
||||
public override function value(): FastFloat {
|
||||
return switch(key) {
|
||||
case "ls movement x": evalDeadzone(g.leftStick.movementX);
|
||||
case "ls movement y": evalDeadzone(g.leftStick.movementY);
|
||||
case "rs movement x": evalDeadzone(g.rightStick.movementX);
|
||||
case "rs movement y": evalDeadzone(g.rightStick.movementY);
|
||||
case "lt pressure": evalDeadzone(evalPressure(g.down("l2")));
|
||||
case "rt pressure": evalDeadzone(evalPressure(g.down("r2")));
|
||||
default: evalDeadzone(g.down(key));
|
||||
}
|
||||
}
|
||||
|
||||
public override function setIndex(index: Int) {
|
||||
g = Input.getGamepad(index);
|
||||
}
|
||||
}
|
||||
|
|
15
blender/arm/logicnode/input/LN_get_input_map_key.py
Normal file
15
blender/arm/logicnode/input/LN_get_input_map_key.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from arm.logicnode.arm_nodes import *
|
||||
|
||||
class GetInputMapKeyNode(ArmLogicTreeNode):
|
||||
"""Get key data if it exists in the input map."""
|
||||
bl_idname = 'LNGetInputMapKeyNode'
|
||||
bl_label = 'Get Input Map Key'
|
||||
arm_version = 1
|
||||
|
||||
def init(self, context):
|
||||
super(GetInputMapKeyNode, self).init(context)
|
||||
self.add_input('NodeSocketString', 'Input Map')
|
||||
self.add_input('NodeSocketString', 'Key')
|
||||
|
||||
self.add_output('NodeSocketFloat', 'Scale', default_value = 1.0)
|
||||
self.add_output('NodeSocketFloat', 'Deadzone')
|
16
blender/arm/logicnode/input/LN_on_input_map.py
Normal file
16
blender/arm/logicnode/input/LN_on_input_map.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from arm.logicnode.arm_nodes import *
|
||||
|
||||
class OnInputMapNode(ArmLogicTreeNode):
|
||||
"""Send a signal if any input map key is started or released."""
|
||||
bl_idname = 'LNOnInputMapNode'
|
||||
bl_label = 'On Input Map'
|
||||
arm_version = 1
|
||||
|
||||
def init(self, context):
|
||||
super(OnInputMapNode, self).init(context)
|
||||
self.add_input('NodeSocketString', 'Input Map')
|
||||
|
||||
self.add_output('ArmNodeSocketAction', 'Started')
|
||||
self.add_output('ArmNodeSocketAction', 'Released')
|
||||
self.add_output('NodeSocketFloat', 'Value')
|
||||
self.add_output('NodeSocketString', 'Key Pressed')
|
28
blender/arm/logicnode/input/LN_set_input_map_key.py
Normal file
28
blender/arm/logicnode/input/LN_set_input_map_key.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from arm.logicnode.arm_nodes import *
|
||||
|
||||
class SetInputMapKeyNode(ArmLogicTreeNode):
|
||||
"""Set input map key."""
|
||||
bl_idname = 'LNSetInputMapKeyNode'
|
||||
bl_label = 'Set Input Map Key'
|
||||
arm_version = 1
|
||||
|
||||
property0: EnumProperty(
|
||||
items = [('keyboard', 'Keyboard', 'Keyboard input'),
|
||||
('mouse', 'Mouse', 'Mouse input'),
|
||||
('gamepad', 'Gamepad', 'Gamepad input')],
|
||||
name='', default='keyboard')
|
||||
|
||||
def init(self, context):
|
||||
super(SetInputMapKeyNode, self).init(context)
|
||||
self.add_input('ArmNodeSocketAction', 'In')
|
||||
self.add_input('NodeSocketString', 'Input Map')
|
||||
self.add_input('NodeSocketString', 'Key')
|
||||
self.add_input('NodeSocketFloat', 'Scale', default_value=1.0)
|
||||
self.add_input('NodeSocketFloat', 'Deadzone')
|
||||
self.add_input('NodeSocketInt', 'Index')
|
||||
|
||||
self.add_output('ArmNodeSocketAction', 'Out')
|
||||
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
Loading…
Reference in a new issue