Include logic parser
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
package arm.nodes;
|
||||
|
||||
import zui.Nodes;
|
||||
|
||||
class Logic {
|
||||
|
||||
static var nodes:Array<TNode>;
|
||||
static var links:Array<TNodeLink>;
|
||||
|
||||
static var parsed_nodes:Array<String> = null;
|
||||
static var parsed_labels:Map<String, String> = null;
|
||||
static var nodeMap:Map<String, LogicNode>;
|
||||
|
||||
public static var packageName = "arm.nodes.logic";
|
||||
|
||||
public static function getNode(id: Int): TNode {
|
||||
for (n in nodes) if (n.id == id) return n;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getLink(id: Int): TNodeLink {
|
||||
for (l in links) if (l.id == id) return l;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getInputLink(inp: TNodeSocket): TNodeLink {
|
||||
for (l in links) {
|
||||
if (l.to_id == inp.node_id) {
|
||||
var node = getNode(inp.node_id);
|
||||
if (node.inputs.length <= l.to_socket) return null;
|
||||
if (node.inputs[l.to_socket] == inp) return l;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getOutputLinks(out: TNodeSocket): Array<TNodeLink> {
|
||||
var res: Array<TNodeLink> = [];
|
||||
for (l in links) {
|
||||
if (l.from_id == out.node_id) {
|
||||
var node = getNode(out.node_id);
|
||||
if (node.outputs.length <= l.from_socket) continue;
|
||||
if (node.outputs[l.from_socket] == out) res.push(l);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static function safesrc(s:String):String {
|
||||
return StringTools.replace(s, ' ', '');
|
||||
}
|
||||
|
||||
static function node_name(node:TNode):String {
|
||||
var s = safesrc(node.name) + node.id;
|
||||
return s;
|
||||
}
|
||||
|
||||
static var tree:LogicTree;
|
||||
public static function parse(canvas:TNodeCanvas, onAdd = true):LogicTree {
|
||||
|
||||
nodes = canvas.nodes;
|
||||
links = canvas.links;
|
||||
|
||||
parsed_nodes = [];
|
||||
parsed_labels = new Map();
|
||||
nodeMap = new Map();
|
||||
var root_nodes = get_root_nodes(canvas);
|
||||
|
||||
tree = new LogicTree();
|
||||
if (onAdd) {
|
||||
tree.notifyOnAdd(function() {
|
||||
for (node in root_nodes) build_node(node);
|
||||
});
|
||||
}
|
||||
else {
|
||||
for (node in root_nodes) build_node(node);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
static function build_node(node:TNode):String {
|
||||
|
||||
// Get node name
|
||||
var name = node_name(node);
|
||||
|
||||
// Check if node already exists
|
||||
if (parsed_nodes.indexOf(name) != -1) {
|
||||
return name;
|
||||
}
|
||||
|
||||
parsed_nodes.push(name);
|
||||
|
||||
// Create node
|
||||
var v = createClassInstance(node.type, [tree]);
|
||||
nodeMap.set(name, v);
|
||||
|
||||
// Properties
|
||||
for (i in 0...5) {
|
||||
for (b in node.buttons) {
|
||||
if (b.name == 'property' + i) {
|
||||
Reflect.setProperty(v, b.name, b.data[b.default_value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create inputs
|
||||
var inp_node:LogicNode = null;
|
||||
var inp_from = 0;
|
||||
for (i in 0...node.inputs.length) {
|
||||
var inp = node.inputs[i];
|
||||
// Is linked - find node
|
||||
var l = getInputLink(inp);
|
||||
if (l != null) {
|
||||
var n = getNode(l.from_id);
|
||||
var socket = n.outputs[l.from_socket];
|
||||
inp_node = nodeMap.get(build_node(n));
|
||||
for (i in 0...n.outputs.length) {
|
||||
if (n.outputs[i] == socket) {
|
||||
inp_from = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not linked - create node with default values
|
||||
else {
|
||||
inp_node = build_default_node(inp);
|
||||
inp_from = 0;
|
||||
}
|
||||
// Add input
|
||||
v.addInput(inp_node, inp_from);
|
||||
}
|
||||
|
||||
// Create outputs
|
||||
for (out in node.outputs) {
|
||||
var outNodes:Array<LogicNode> = [];
|
||||
var ls = getOutputLinks(out);
|
||||
if (ls != null && ls.length > 0) {
|
||||
for (l in ls) {
|
||||
var n = getNode(l.to_id);
|
||||
var out_name = build_node(n);
|
||||
outNodes.push(nodeMap.get(out_name));
|
||||
}
|
||||
}
|
||||
// Not linked - create node with default values
|
||||
else {
|
||||
outNodes.push(build_default_node(out));
|
||||
}
|
||||
// Add outputs
|
||||
v.addOutputs(outNodes);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static function get_root_nodes(node_group:TNodeCanvas):Array<TNode> {
|
||||
var roots:Array<TNode> = [];
|
||||
for (node in node_group.nodes) {
|
||||
// if (node.bl_idname == 'NodeUndefined') {
|
||||
// arm.log.warn('Undefined logic nodes in ' + node_group.name)
|
||||
// return []
|
||||
// }
|
||||
var linked = false;
|
||||
for (out in node.outputs) {
|
||||
var ls = getOutputLinks(out);
|
||||
if (ls != null && ls.length > 0) {
|
||||
linked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!linked) { // Assume node with no connected outputs as roots
|
||||
roots.push(node);
|
||||
}
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
static function build_default_node(inp:TNodeSocket):LogicNode {
|
||||
|
||||
var v:LogicNode = null;
|
||||
|
||||
if (inp.type == 'OBJECT') {
|
||||
v = createClassInstance('ObjectNode', [tree, inp.default_value]);
|
||||
}
|
||||
else if (inp.type == 'ANIMACTION') {
|
||||
v = createClassInstance('StringNode', [tree, inp.default_value]);
|
||||
}
|
||||
else if (inp.type == 'VECTOR') {
|
||||
if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
|
||||
v = createClassInstance('VectorNode', [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2]]);
|
||||
}
|
||||
else if (inp.type == 'RGBA') {
|
||||
if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
|
||||
v = createClassInstance('ColorNode', [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2], inp.default_value[3]]);
|
||||
}
|
||||
else if (inp.type == 'RGB') {
|
||||
if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
|
||||
v = createClassInstance('ColorNode', [tree, inp.default_value[0], inp.default_value[1], inp.default_value[2]]);
|
||||
}
|
||||
else if (inp.type == 'VALUE') {
|
||||
v = createClassInstance('FloatNode', [tree, inp.default_value]);
|
||||
}
|
||||
else if (inp.type == 'INT') {
|
||||
v = createClassInstance('IntegerNode', [tree, inp.default_value]);
|
||||
}
|
||||
else if (inp.type == 'BOOLEAN') {
|
||||
v = createClassInstance('BooleanNode', [tree, inp.default_value]);
|
||||
}
|
||||
else if (inp.type == 'STRING') {
|
||||
v = createClassInstance('StringNode', [tree, inp.default_value]);
|
||||
}
|
||||
else { // ACTION, ARRAY
|
||||
v = createClassInstance('NullNode', [tree]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static function createClassInstance(className:String, args:Array<Dynamic>):Dynamic {
|
||||
var cname = Type.resolveClass(packageName + '.' + className);
|
||||
if (cname == null) return null;
|
||||
return Type.createInstance(cname, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package arm.nodes;
|
||||
|
||||
class LogicNode {
|
||||
|
||||
var tree:LogicTree;
|
||||
var inputs:Array<LogicNodeInput> = [];
|
||||
var outputs:Array<Array<LogicNode>> = [];
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
public function addInput(node:LogicNode, from:Int) {
|
||||
inputs.push(new LogicNodeInput(node, from));
|
||||
}
|
||||
|
||||
public function addOutputs(nodes:Array<LogicNode>) {
|
||||
outputs.push(nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this node is activated.
|
||||
* @param from impulse index
|
||||
*/
|
||||
function run(from:Int) {}
|
||||
|
||||
/**
|
||||
* Call to activate node connected to the output.
|
||||
* @param i output index
|
||||
*/
|
||||
function runOutput(i:Int) {
|
||||
if (i >= outputs.length) return;
|
||||
for (o in outputs[i]) {
|
||||
// Check which input activated the node
|
||||
for (j in 0...o.inputs.length) {
|
||||
if (o.inputs[j].node == this) {
|
||||
o.run(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@:allow(arm.nodes.LogicNodeInput)
|
||||
function get(from:Int):Dynamic { return this; }
|
||||
|
||||
@:allow(arm.nodes.LogicNodeInput)
|
||||
function set(value:Dynamic) { }
|
||||
}
|
||||
|
||||
class LogicNodeInput {
|
||||
|
||||
@:allow(arm.nodes.LogicNode)
|
||||
var node:LogicNode;
|
||||
var from:Int; // Socket index
|
||||
|
||||
public function new(node:LogicNode, from:Int) {
|
||||
this.node = node;
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
@:allow(arm.nodes.LogicNode)
|
||||
function get():Dynamic {
|
||||
return node.get(from);
|
||||
}
|
||||
|
||||
@:allow(arm.nodes.LogicNode)
|
||||
function set(value:Dynamic) {
|
||||
node.set(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package arm.nodes;
|
||||
|
||||
class LogicTree extends iron.Trait {
|
||||
|
||||
public var loopBreak = false; // Trigger break from loop nodes
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public function add() {}
|
||||
|
||||
var paused = false;
|
||||
|
||||
public function pause() {
|
||||
if (paused) return;
|
||||
paused = true;
|
||||
|
||||
if (_update != null) for (f in _update) iron.App.removeUpdate(f);
|
||||
if (_lateUpdate != null) for (f in _lateUpdate) iron.App.removeLateUpdate(f);
|
||||
}
|
||||
|
||||
public function resume() {
|
||||
if (!paused) return;
|
||||
paused = false;
|
||||
|
||||
if (_update != null) for (f in _update) iron.App.notifyOnUpdate(f);
|
||||
if (_lateUpdate != null) for (f in _lateUpdate) iron.App.notifyOnLateUpdate(f);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class BooleanNode extends LogicNode {
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import arm.ui.UITrait;
|
||||
import arm.ui.UIView2D;
|
||||
import arm.Tool;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class ColorNode extends LogicNode {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class FloatNode extends LogicNode {
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import iron.math.Vec4;
|
||||
|
||||
@:keep
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class IntegerNode extends LogicNode {
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import iron.math.Vec4;
|
||||
|
||||
@:keep
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class NullNode extends LogicNode {
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import iron.object.Object;
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class ObjectNode extends LogicNode {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import iron.math.Vec4;
|
||||
|
||||
@:keep
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
@:keep
|
||||
class StringNode extends LogicNode {
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import arm.ui.*;
|
||||
|
||||
@:keep
|
||||
class TimeNode extends LogicNode {
|
||||
|
||||
@@ -14,6 +10,6 @@ class TimeNode extends LogicNode {
|
||||
override function get(from:Int):Dynamic {
|
||||
if (from == 0) return iron.system.Time.time();
|
||||
else if (from == 1) return iron.system.Time.delta;
|
||||
else return UITrait.inst.brushTime;
|
||||
else return arm.ui.UITrait.inst.brushTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import iron.math.Vec4;
|
||||
|
||||
@:keep
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package arm.nodes.brush;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
import iron.math.Vec4;
|
||||
|
||||
@:keep
|
||||
|
||||
Reference in New Issue
Block a user