NodeScript+ 导入了个 UI Extend
Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.NodeScript
|
||||
{
|
||||
// ==================== 图入口 ====================
|
||||
public class NodeStart : NodeBase
|
||||
{
|
||||
public Output<Signal> exec = new("Exec");
|
||||
public Output<GameElement> element = new("Element");
|
||||
[NonSerialized] public GameElement boundElement;
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
exec.SetValue(Signal.Default);
|
||||
element.SetValue(boundElement);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeEntry : NodeBase
|
||||
{
|
||||
public Output<Signal> exec = new("Exec");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
exec.SetValue(Signal.Default);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 统一多类型数学运算 ====================
|
||||
public class NodeMath : NodeBase
|
||||
{
|
||||
enum Op { Add, Subtract, Multiply, Divide }
|
||||
Op _op;
|
||||
|
||||
public InputAny a = new("A");
|
||||
public InputAny b = new("B") { IsFixedType = true };
|
||||
public OutputAny result = new("Result");
|
||||
|
||||
static readonly Dictionary<(Type, Op), Func<object, object, object>> _ops = new()
|
||||
{
|
||||
[(typeof(float), Op.Add)] = (x, y) => (float)x + (float)y,
|
||||
[(typeof(float), Op.Subtract)] = (x, y) => (float)x - (float)y,
|
||||
[(typeof(float), Op.Multiply)] = (x, y) => (float)x * (float)y,
|
||||
[(typeof(float), Op.Divide)] = (x, y) => (float)y != 0f ? (float)x / (float)y : 0f,
|
||||
|
||||
[(typeof(int), Op.Add)] = (x, y) => (int)x + (int)y,
|
||||
[(typeof(int), Op.Subtract)] = (x, y) => (int)x - (int)y,
|
||||
[(typeof(int), Op.Multiply)] = (x, y) => (int)x * (int)y,
|
||||
[(typeof(int), Op.Divide)] = (x, y) => (int)y != 0 ? (int)x / (int)y : 0,
|
||||
|
||||
[(typeof(Vector2), Op.Add)] = (x, y) => (Vector2)x + (Vector2)y,
|
||||
[(typeof(Vector2), Op.Subtract)] = (x, y) => (Vector2)x - (Vector2)y,
|
||||
[(typeof(Vector2), Op.Multiply)] = (x, y) => (Vector2)x * (float)y,
|
||||
[(typeof(Vector2), Op.Divide)] = (x, y) => (float)y != 0f ? (Vector2)x / (float)y : Vector2.zero,
|
||||
|
||||
[(typeof(Vector3), Op.Add)] = (x, y) => (Vector3)x + (Vector3)y,
|
||||
[(typeof(Vector3), Op.Subtract)] = (x, y) => (Vector3)x - (Vector3)y,
|
||||
[(typeof(Vector3), Op.Multiply)] = (x, y) => (Vector3)x * (float)y,
|
||||
[(typeof(Vector3), Op.Divide)] = (x, y) => (float)y != 0f ? (Vector3)x / (float)y : Vector3.zero,
|
||||
|
||||
[(typeof(Color), Op.Add)] = (x, y) => (Color)x + (Color)y,
|
||||
[(typeof(Color), Op.Subtract)] = (x, y) => (Color)x - (Color)y,
|
||||
[(typeof(Color), Op.Multiply)] = (x, y) => (Color)x * (float)y,
|
||||
|
||||
[(typeof(string), Op.Add)] = (x, y) => (string)x + (string)y,
|
||||
};
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui)
|
||||
{
|
||||
ui.Dropdown("Op", new[] { "+", "-", "*", "/" }, 0, i => _op = (Op)i);
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!a.IsConnected && !b.IsConnected) return LoopResult.Complete();
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var type = a.DataType ?? b.DataType ?? typeof(float);
|
||||
|
||||
// 单输入 → 直通
|
||||
if (!a.IsConnected) { result.SetValueRaw(SafeGet(b)); return LoopResult.Complete(); }
|
||||
if (!b.IsConnected) { result.SetValueRaw(SafeGet(a)); return LoopResult.Complete(); }
|
||||
|
||||
// 双输入 → LUT 运算
|
||||
var key = (type, _op);
|
||||
if (_ops.TryGetValue(key, out var func))
|
||||
result.SetValueRaw(func(SafeGet(a), SafeGet(b)));
|
||||
else
|
||||
result.SetValueRaw(SafeGet(a)); // fallback: 直通 a
|
||||
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
|
||||
static object SafeGet(InputAny input)
|
||||
{
|
||||
try { return input.GetValue(); }
|
||||
catch { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 分支 ====================
|
||||
public class NodeBranch : NodeBase
|
||||
{
|
||||
public Input<Signal> exec = new("Exec");
|
||||
public InputAny condition = new("Condition");
|
||||
public Output<Signal> trueOut = new("True");
|
||||
public Output<Signal> falseOut = new("False");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!exec.IsConnected) return LoopResult.Complete();
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
float cond = condition.IsConnected ? condition.GetValue<float>() : 0f;
|
||||
// int → float 兼容
|
||||
if (condition.DataType == typeof(int))
|
||||
cond = condition.GetValue<int>();
|
||||
|
||||
if (cond > 0f) trueOut.SetValue(Signal.Default);
|
||||
else falseOut.SetValue(Signal.Default);
|
||||
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== For 循环(多周期状态机,Rect 容器留待 Phase 4) ====================
|
||||
public class NodeForLoop : NodeBase
|
||||
{
|
||||
public Input<Signal> exec = new("Exec");
|
||||
public InputAny count = new("Count");
|
||||
public Output<Signal> loopBody = new("LoopBody");
|
||||
public Output<int> index = new("Index");
|
||||
public Output<Signal> completed = new("Completed");
|
||||
|
||||
int _current;
|
||||
int _total;
|
||||
bool _started;
|
||||
bool _waiting;
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!exec.IsConnected) return LoopResult.Complete();
|
||||
if (!_started && !EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
if (!_started)
|
||||
{
|
||||
_total = count.IsConnected ? count.GetValue<int>() : 0;
|
||||
_current = 0;
|
||||
_started = true;
|
||||
}
|
||||
|
||||
// 空转一周期让下游消费上一轮输出
|
||||
if (_waiting) { _waiting = false; return LoopResult.Wait(); }
|
||||
|
||||
if (_current < _total)
|
||||
{
|
||||
index.SetValue(_current);
|
||||
loopBody.SetValue(Signal.Default);
|
||||
_current++;
|
||||
_waiting = true;
|
||||
return LoopResult.Repeat();
|
||||
}
|
||||
|
||||
_started = false;
|
||||
completed.SetValue(Signal.Default);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== GameElement 操作 ====================
|
||||
public class NodeGameElement : NodeBase
|
||||
{
|
||||
public Input<Signal> exec = new("Exec");
|
||||
public Input<GameElement> RootNode = new("Root");
|
||||
public Input<GameElement> SourceNode = new("Source");
|
||||
public Output<GameElement> newElement = new("OutPut");
|
||||
public Output<Signal> completed = new("Done");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var root = RootNode.Value;
|
||||
var source = SourceNode.Value;
|
||||
if (source == null)
|
||||
{
|
||||
ElementFolder.GenerateElement("Folder(Cp)", Guid.NewGuid(), new List<string>(), true, RootNode.IsConnected ? root : null);
|
||||
}
|
||||
else if (root != null)
|
||||
{
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.CopyElement(source);
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.PasteElement(root);
|
||||
}
|
||||
completed.SetValue(Signal.Default);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeGetTransform : NodeBase
|
||||
{
|
||||
public Input<GameElement> element = new("Element");
|
||||
public Output<Vector3> position = new("Pos"), rotation = new("Rot"), scale = new("Scl");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
if (element.Value is IHaveTransformSubmodule ts)
|
||||
{
|
||||
position.SetValue(ts.transformSubmodule.originalPosition);
|
||||
rotation.SetValue(ts.transformSubmodule.originalEulerAngles);
|
||||
scale.SetValue(ts.transformSubmodule.originalScale);
|
||||
}
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeSetTransform : NodeBase
|
||||
{
|
||||
public Input<Signal> exec = new("Exec");
|
||||
public Input<GameElement> element = new("Element");
|
||||
public Input<Vector3> Pos = new("Pos"), Rot = new("Rot"), Scale = new("Scl");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
if (element.Value is IHaveTransformSubmodule ts)
|
||||
{
|
||||
if (Pos.IsConnected) { ts.transformSubmodule.originalPosition = Pos.Value; ts.transformSubmodule.positionDirtyMark = true; }
|
||||
if (Rot.IsConnected) { ts.transformSubmodule.originalEulerAngles = Rot.Value; ts.transformSubmodule.eulerAnglesDirtyMark = true; }
|
||||
if (Scale.IsConnected) { ts.transformSubmodule.originalScale = Scale.Value; ts.transformSubmodule.scaleDirtyMark = true; }
|
||||
}
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeChildByIndex : NodeBase
|
||||
{
|
||||
public Input<GameElement> parent = new("Parent");
|
||||
public int index;
|
||||
public Output<GameElement> child = new("Child");
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui) { ui.FloatField("Idx", 0, i => index = (int)i); }
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var p = parent.Value;
|
||||
if (p != null && index >= 0 && index < p.childElementList.Count)
|
||||
child.SetValue(p.childElementList[index]);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeChildCount : NodeBase
|
||||
{
|
||||
public Input<GameElement> parent = new("Parent");
|
||||
public Output<int> count = new("Count");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var p = parent.Value;
|
||||
count.SetValue(p != null ? p.childElementList.Count : 0);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da71a524cc8687941840c85db8590b1c
|
||||
@@ -0,0 +1,445 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.NodeScript
|
||||
{
|
||||
// ==================== 通用常量 ====================
|
||||
public class NodeConst : NodeBase
|
||||
{
|
||||
enum ValueType { Float, Int, Bool, Vector2, Vector3, Color }
|
||||
ValueType _type;
|
||||
|
||||
public float floatVal;
|
||||
public int intVal;
|
||||
public bool boolVal;
|
||||
public Vector2 vector2Val;
|
||||
public Vector3 vector3Val;
|
||||
public Color colorVal;
|
||||
|
||||
public OutputAny value = new("Value");
|
||||
|
||||
public override void InitConnectors()
|
||||
{
|
||||
base.InitConnectors();
|
||||
value.LockType(typeof(float));
|
||||
}
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui)
|
||||
{
|
||||
ui.TypeDropdown(new[] { "float", "int", "bool", "Vector2", "Vector3", "Color" }, 0, i =>
|
||||
{
|
||||
_type = (ValueType)i;
|
||||
Type t = _type switch
|
||||
{
|
||||
ValueType.Float => typeof(float),
|
||||
ValueType.Int => typeof(int),
|
||||
ValueType.Bool => typeof(bool),
|
||||
ValueType.Vector2 => typeof(Vector2),
|
||||
ValueType.Vector3 => typeof(Vector3),
|
||||
ValueType.Color => typeof(Color),
|
||||
_ => typeof(float),
|
||||
};
|
||||
value.LockType(t);
|
||||
});
|
||||
|
||||
switch (_type)
|
||||
{
|
||||
case ValueType.Float: ui.FloatField("F", 0f, v => floatVal = v); break;
|
||||
case ValueType.Int: ui.FloatField("I", 0f, v => intVal = (int)v); break;
|
||||
case ValueType.Bool: ui.Toggle("B", false, v => boolVal = v); break;
|
||||
case ValueType.Vector2: ui.FloatField("X", 0f, v => vector2Val.x = v); ui.FloatField("Y", 0f, v => vector2Val.y = v); break;
|
||||
case ValueType.Vector3: ui.FloatField("X", 0f, v => vector3Val.x = v); ui.FloatField("Y", 0f, v => vector3Val.y = v); ui.FloatField("Z", 0f, v => vector3Val.z = v); break;
|
||||
case ValueType.Color: ui.FloatField("R", 1f, v => colorVal.r = v); ui.FloatField("G", 1f, v => colorVal.g = v); ui.FloatField("B", 1f, v => colorVal.b = v); ui.FloatField("A", 1f, v => colorVal.a = v); break;
|
||||
}
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
object v = _type switch
|
||||
{
|
||||
ValueType.Float => floatVal,
|
||||
ValueType.Int => intVal,
|
||||
ValueType.Bool => boolVal,
|
||||
ValueType.Vector2 => vector2Val,
|
||||
ValueType.Vector3 => vector3Val,
|
||||
ValueType.Color => colorVal,
|
||||
_ => 0f,
|
||||
};
|
||||
value.SetValueRaw(v);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 通用拆分 ====================
|
||||
public class NodeSplit : NodeBase
|
||||
{
|
||||
public InputAny input = new("Input");
|
||||
public Output<float> x = new("X"), y = new("Y"), z = new("Z"), w = new("W");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!input.IsConnected) return LoopResult.Complete();
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var t = input.DataType;
|
||||
if (t == typeof(Vector2))
|
||||
{
|
||||
var v = input.GetValue<Vector2>();
|
||||
x.SetValue(v.x); y.SetValue(v.y);
|
||||
}
|
||||
else if (t == typeof(Vector3))
|
||||
{
|
||||
var v = input.GetValue<Vector3>();
|
||||
x.SetValue(v.x); y.SetValue(v.y); z.SetValue(v.z);
|
||||
}
|
||||
else if (t == typeof(Color))
|
||||
{
|
||||
var v = input.GetValue<Color>();
|
||||
x.SetValue(v.r); y.SetValue(v.g); z.SetValue(v.b); w.SetValue(v.a);
|
||||
}
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 通用合并 ====================
|
||||
public class NodeCombine : NodeBase
|
||||
{
|
||||
enum CombineType { Vector2, Vector3, Color }
|
||||
CombineType _type;
|
||||
|
||||
public Input<float> x = new("X"), y = new("Y"), z = new("Z"), w = new("W");
|
||||
public OutputAny output = new("Result");
|
||||
|
||||
public override void InitConnectors()
|
||||
{
|
||||
base.InitConnectors();
|
||||
output.LockType(typeof(Vector2));
|
||||
}
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui)
|
||||
{
|
||||
ui.TypeDropdown(new[] { "Vector2", "Vector3", "Color" }, 0, i =>
|
||||
{
|
||||
_type = (CombineType)i;
|
||||
Type t = _type == CombineType.Vector2 ? typeof(Vector2) : _type == CombineType.Vector3 ? typeof(Vector3) : typeof(Color);
|
||||
output.LockType(t);
|
||||
});
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
object v = _type switch
|
||||
{
|
||||
CombineType.Vector2 => new Vector2(x.Value, y.Value),
|
||||
CombineType.Vector3 => new Vector3(x.Value, y.Value, z.Value),
|
||||
CombineType.Color => new Color(x.Value, y.Value, z.Value, w.Value),
|
||||
_ => null,
|
||||
};
|
||||
output.SetValueRaw(v);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Lerp 线性插值 ====================
|
||||
public class NodeLerp : NodeBase
|
||||
{
|
||||
public InputAny a = new("A");
|
||||
public InputAny b = new("B");
|
||||
public InputAny t = new("T") { IsFixedType = true };
|
||||
public OutputAny result = new("Result");
|
||||
|
||||
public override void InitConnectors()
|
||||
{
|
||||
base.InitConnectors();
|
||||
t.LockType(typeof(float));
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var type = a.DataType ?? b.DataType ?? typeof(float);
|
||||
float factor = t.IsConnected ? Mathf.Clamp01(t.GetValue<float>()) : 0.5f;
|
||||
|
||||
object v = null;
|
||||
if (type == typeof(float))
|
||||
v = Mathf.Lerp(a.GetValue<float>(), b.GetValue<float>(), factor);
|
||||
else if (type == typeof(int))
|
||||
v = Mathf.RoundToInt(Mathf.Lerp(a.GetValue<int>(), b.GetValue<int>(), factor));
|
||||
else if (type == typeof(Vector2))
|
||||
v = Vector2.Lerp(a.GetValue<Vector2>(), b.GetValue<Vector2>(), factor);
|
||||
else if (type == typeof(Vector3))
|
||||
v = Vector3.Lerp(a.GetValue<Vector3>(), b.GetValue<Vector3>(), factor);
|
||||
else if (type == typeof(Color))
|
||||
v = Color.Lerp(a.GetValue<Color>(), b.GetValue<Color>(), factor);
|
||||
|
||||
result.SetValueRaw(v);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 比较运算 ====================
|
||||
public class NodeCompare : NodeBase
|
||||
{
|
||||
enum CmpOp { Equal, NotEqual, Greater, Less, GreaterOrEqual, LessOrEqual }
|
||||
CmpOp _op;
|
||||
|
||||
public InputAny a = new("A");
|
||||
public InputAny b = new("B");
|
||||
public Output<bool> result = new("Result");
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui)
|
||||
{
|
||||
ui.Dropdown("Op", new[] { "==", "!=", ">", "<", ">=", "<=" }, 0, i => _op = (CmpOp)i);
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var type = a.DataType ?? b.DataType ?? typeof(float);
|
||||
bool r = false;
|
||||
|
||||
if (type == typeof(float)) r = Compare(a.GetValue<float>(), b.GetValue<float>());
|
||||
else if (type == typeof(int)) r = Compare(a.GetValue<int>(), b.GetValue<int>());
|
||||
else if (type == typeof(string)) r = Compare(a.GetValue<string>(), b.GetValue<string>());
|
||||
|
||||
result.SetValue(r);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
|
||||
bool Compare<T>(T x, T y) where T : IComparable<T>
|
||||
{
|
||||
int c = x.CompareTo(y);
|
||||
return _op switch
|
||||
{
|
||||
CmpOp.Equal => c == 0,
|
||||
CmpOp.NotEqual => c != 0,
|
||||
CmpOp.Greater => c > 0,
|
||||
CmpOp.Less => c < 0,
|
||||
CmpOp.GreaterOrEqual => c >= 0,
|
||||
CmpOp.LessOrEqual => c <= 0,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 二选一 ====================
|
||||
public class NodeSelect : NodeBase
|
||||
{
|
||||
public InputAny condition = new("Cond");
|
||||
public InputAny trueValue = new("True");
|
||||
public InputAny falseValue = new("False");
|
||||
public OutputAny result = new("Result");
|
||||
|
||||
bool _manualCond;
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui)
|
||||
{
|
||||
ui.Toggle("Cond", false, v => _manualCond = v);
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
bool cond = condition.IsConnected ? condition.GetValue<bool>() : _manualCond;
|
||||
// int → bool 兼容
|
||||
if (!cond && condition.IsConnected && condition.DataType == typeof(int))
|
||||
cond = condition.GetValue<int>() != 0;
|
||||
|
||||
var src = cond ? trueValue : falseValue;
|
||||
result.SetValueRaw(src.GetValue());
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 万能赋值(反向写入) ====================
|
||||
public class NodeSet : NodeBase
|
||||
{
|
||||
public InputAny targetRef = new("TargetRef");
|
||||
public InputAny value = new("Value");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!targetRef.IsConnected) return LoopResult.Complete();
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
targetRef.WriteBack(value.GetValue());
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Variable<T> ====================
|
||||
public class Variable<T> { public T Value; }
|
||||
|
||||
public class NodeVariable<T> : NodeBase
|
||||
{
|
||||
public Variable<T> var = new();
|
||||
public Input<Signal> signal = new("Signal");
|
||||
public Input<T> set = new("Set");
|
||||
public Output<T> get = new("Value");
|
||||
|
||||
public override void InitConnectors()
|
||||
{
|
||||
base.InitConnectors();
|
||||
(get as Output<T>).SetWriteBack(v => var.Value = v);
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
// Signal 有连接时必须等待(循环体内等待触发)
|
||||
if (signal.IsConnected)
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
}
|
||||
|
||||
if (set.IsConnected)
|
||||
var.Value = set.Value;
|
||||
|
||||
get.SetValue(var.Value);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 调试 ====================
|
||||
public class NodeDebugLog : NodeBase
|
||||
{
|
||||
public Input<Signal> exec = new("Exec");
|
||||
public InputAny value = new("Value");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
Debug.Log($"[DebugLog] {NodeName}: {value.GetValue()}");
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeLog : NodeBase
|
||||
{
|
||||
public InputAny value = new("Value");
|
||||
public string prefix = "";
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
Debug.Log($"[NodeLog] {prefix}{value.GetValue()}");
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== List<T> ====================
|
||||
public class NodeList<T> : NodeBase
|
||||
{
|
||||
public Variable<List<T>> list = new() { Value = new List<T>() };
|
||||
public Output<List<T>> output = new("List");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
output.SetValue(list.Value);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeListAdd<T> : NodeBase
|
||||
{
|
||||
public Input<List<T>> list = new("List");
|
||||
public Input<T> item = new("Item");
|
||||
public Output<List<T>> output = new("List");
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var l = list.Value;
|
||||
if (l != null && item.IsConnected) { l.Add(item.Value); output.SetValue(l); }
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeListGet<T> : NodeBase
|
||||
{
|
||||
public Input<List<T>> list = new("List");
|
||||
public int index;
|
||||
public Output<T> element = new("Element");
|
||||
|
||||
public override void BuildUI(NodeUIBuilder ui) { ui.FloatField("Idx", 0, i => index = (int)i); }
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
var l = list.Value;
|
||||
if (l != null && index >= 0 && index < l.Count) element.SetValue(l[index]);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
public class NodeForEach : NodeBase
|
||||
{
|
||||
public Input<Signal> exec = new("Exec");
|
||||
public InputAny list = new("List");
|
||||
public Output<Signal> loopBody = new("LoopBody"), completed = new("Completed");
|
||||
public OutputAny current = new("Current");
|
||||
public OutputAny indexOut = new("Index");
|
||||
|
||||
System.Collections.IList _list;
|
||||
int _i;
|
||||
bool _started;
|
||||
bool _waiting;
|
||||
|
||||
public override void InitConnectors()
|
||||
{
|
||||
base.InitConnectors();
|
||||
indexOut.LockType(typeof(int));
|
||||
}
|
||||
|
||||
public override void OnTypePropagated(Type t)
|
||||
{
|
||||
base.OnTypePropagated(t);
|
||||
if (t != null && t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>))
|
||||
current.LockType(t.GetGenericArguments()[0]);
|
||||
}
|
||||
|
||||
public override LoopResult Loop()
|
||||
{
|
||||
if (!exec.IsConnected) return LoopResult.Complete();
|
||||
if (!_started && !EnsureInputsReady(out var hang)) return hang;
|
||||
|
||||
if (!_started)
|
||||
{
|
||||
_list = list.GetValue() as System.Collections.IList;
|
||||
if (_list == null || _list.Count == 0)
|
||||
{
|
||||
completed.SetValue(Signal.Default);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
_i = 0;
|
||||
_started = true;
|
||||
}
|
||||
|
||||
if (_waiting) { _waiting = false; return LoopResult.Wait(); }
|
||||
|
||||
if (_i < _list.Count)
|
||||
{
|
||||
indexOut.SetValueRaw(_i);
|
||||
current.SetValueRaw(_list[_i]);
|
||||
loopBody.SetValue(Signal.Default);
|
||||
_i++;
|
||||
_waiting = true;
|
||||
return LoopResult.Repeat();
|
||||
}
|
||||
|
||||
_started = false;
|
||||
completed.SetValue(Signal.Default);
|
||||
return LoopResult.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6d155dc132fc24448aa1896c024f9a6
|
||||
Reference in New Issue
Block a user