Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,30 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Stops the execution of the current loop.
|
||||
/// </summary>
|
||||
[UnitTitle("Break Loop")]
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(13)]
|
||||
public class Break : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the break.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Operation);
|
||||
}
|
||||
|
||||
public ControlOutput Operation(Flow flow)
|
||||
{
|
||||
flow.BreakLoop();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b88f499ac51e4e2d8f1c0c092962494
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,60 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Caches the input so that all nodes connected to the output
|
||||
/// retrieve the value only once.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(15)]
|
||||
public sealed class Cache : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The moment at which to cache the value.
|
||||
/// The output value will only get updated when this gets triggered.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value to cache when the node is entered.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput input { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cached value, as it was the last time this node was entered.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Cached")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput output { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the value has been cached.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Store);
|
||||
input = ValueInput<object>(nameof(input));
|
||||
output = ValueOutput<object>(nameof(output));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(input, enter);
|
||||
Assignment(enter, output);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
private ControlOutput Store(Flow flow)
|
||||
{
|
||||
flow.SetValue(output, flow.GetValue(input));
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 25116eac09c45452aa611bfda069d229
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,127 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Loops between a first and last index at a specified step.
|
||||
/// </summary>
|
||||
[UnitTitle("For Loop")]
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(9)]
|
||||
public sealed class For : LoopUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// The index at which to start the loop (inclusive).
|
||||
/// </summary>
|
||||
[PortLabel("First")]
|
||||
[DoNotSerialize]
|
||||
public ValueInput firstIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The index at which to end the loop (exclusive).
|
||||
/// </summary>
|
||||
[PortLabel("Last")]
|
||||
[DoNotSerialize]
|
||||
public ValueInput lastIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value by which the index will be incremented (or decremented, if negative) after each loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput step { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current index of the loop.
|
||||
/// </summary>
|
||||
[PortLabel("Index")]
|
||||
[DoNotSerialize]
|
||||
public ValueOutput currentIndex { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
firstIndex = ValueInput(nameof(firstIndex), 0);
|
||||
lastIndex = ValueInput(nameof(lastIndex), 10);
|
||||
step = ValueInput(nameof(step), 1);
|
||||
currentIndex = ValueOutput<int>(nameof(currentIndex));
|
||||
base.Definition();
|
||||
|
||||
Requirement(firstIndex, enter);
|
||||
Requirement(lastIndex, enter);
|
||||
Requirement(step, enter);
|
||||
Assignment(enter, currentIndex);
|
||||
}
|
||||
|
||||
private int Start(Flow flow, out int currentIndex, out int lastIndex, out bool ascending)
|
||||
{
|
||||
var firstIndex = flow.GetValue<int>(this.firstIndex);
|
||||
lastIndex = flow.GetValue<int>(this.lastIndex);
|
||||
ascending = firstIndex <= lastIndex;
|
||||
currentIndex = firstIndex;
|
||||
flow.SetValue(this.currentIndex, currentIndex);
|
||||
|
||||
return flow.EnterLoop();
|
||||
}
|
||||
|
||||
private bool CanMoveNext(int currentIndex, int lastIndex, bool ascending)
|
||||
{
|
||||
if (ascending)
|
||||
{
|
||||
return currentIndex < lastIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return currentIndex > lastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveNext(Flow flow, ref int currentIndex)
|
||||
{
|
||||
currentIndex += flow.GetValue<int>(step);
|
||||
flow.SetValue(this.currentIndex, currentIndex);
|
||||
}
|
||||
|
||||
protected override ControlOutput Loop(Flow flow)
|
||||
{
|
||||
var loop = Start(flow, out int currentIndex, out int lastIndex, out bool ascending);
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
while (flow.LoopIsNotBroken(loop) && CanMoveNext(currentIndex, lastIndex, ascending))
|
||||
{
|
||||
flow.Invoke(body);
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
|
||||
MoveNext(flow, ref currentIndex);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
flow.ExitLoop(loop);
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
protected override IEnumerator LoopCoroutine(Flow flow)
|
||||
{
|
||||
var loop = Start(flow, out int currentIndex, out int lastIndex, out bool ascending);
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
while (flow.LoopIsNotBroken(loop) && CanMoveNext(currentIndex, lastIndex, ascending))
|
||||
{
|
||||
yield return body;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
|
||||
MoveNext(flow, ref currentIndex);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
flow.ExitLoop(loop);
|
||||
|
||||
yield return exit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 229c4f4c07f634aa4b36c2106d1d9aa5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,175 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Loops over each element of a collection.
|
||||
/// </summary>
|
||||
[UnitTitle("For Each Loop")]
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(10)]
|
||||
public class ForEach : LoopUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// The collection over which to loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput collection { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current index of the loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Index")]
|
||||
public ValueOutput currentIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the current item of the loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Key")]
|
||||
public ValueOutput currentKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current item of the loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Item")]
|
||||
public ValueOutput currentItem { get; private set; }
|
||||
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable("Dictionary")]
|
||||
[InspectorToggleLeft]
|
||||
public bool dictionary { get; set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
base.Definition();
|
||||
|
||||
if (dictionary)
|
||||
{
|
||||
collection = ValueInput<IDictionary>(nameof(collection));
|
||||
}
|
||||
else
|
||||
{
|
||||
collection = ValueInput<IEnumerable>(nameof(collection));
|
||||
}
|
||||
|
||||
currentIndex = ValueOutput<int>(nameof(currentIndex));
|
||||
|
||||
if (dictionary)
|
||||
{
|
||||
currentKey = ValueOutput<object>(nameof(currentKey));
|
||||
}
|
||||
|
||||
currentItem = ValueOutput<object>(nameof(currentItem));
|
||||
|
||||
Requirement(collection, enter);
|
||||
Assignment(enter, currentIndex);
|
||||
Assignment(enter, currentItem);
|
||||
|
||||
if (dictionary)
|
||||
{
|
||||
Assignment(enter, currentKey);
|
||||
}
|
||||
}
|
||||
|
||||
private int Start(Flow flow, out IEnumerator enumerator, out IDictionaryEnumerator dictionaryEnumerator, out int currentIndex)
|
||||
{
|
||||
if (dictionary)
|
||||
{
|
||||
dictionaryEnumerator = flow.GetValue<IDictionary>(collection).GetEnumerator();
|
||||
enumerator = dictionaryEnumerator;
|
||||
}
|
||||
else
|
||||
{
|
||||
enumerator = flow.GetValue<IEnumerable>(collection).GetEnumerator();
|
||||
dictionaryEnumerator = null;
|
||||
}
|
||||
|
||||
currentIndex = -1;
|
||||
|
||||
return flow.EnterLoop();
|
||||
}
|
||||
|
||||
private bool MoveNext(Flow flow, IEnumerator enumerator, IDictionaryEnumerator dictionaryEnumerator, ref int currentIndex)
|
||||
{
|
||||
var result = enumerator.MoveNext();
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (dictionary)
|
||||
{
|
||||
flow.SetValue(currentKey, dictionaryEnumerator.Key);
|
||||
flow.SetValue(currentItem, dictionaryEnumerator.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
flow.SetValue(currentItem, enumerator.Current);
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
|
||||
flow.SetValue(this.currentIndex, currentIndex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override ControlOutput Loop(Flow flow)
|
||||
{
|
||||
var loop = Start(flow, out var enumerator, out var dictionaryEnumerator, out var currentIndex);
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
try
|
||||
{
|
||||
while (flow.LoopIsNotBroken(loop) && MoveNext(flow, enumerator, dictionaryEnumerator, ref currentIndex))
|
||||
{
|
||||
flow.Invoke(body);
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
(enumerator as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
flow.ExitLoop(loop);
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
protected override IEnumerator LoopCoroutine(Flow flow)
|
||||
{
|
||||
var loop = Start(flow, out var enumerator, out var dictionaryEnumerator, out var currentIndex);
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
try
|
||||
{
|
||||
while (flow.LoopIsNotBroken(loop) && MoveNext(flow, enumerator, dictionaryEnumerator, ref currentIndex))
|
||||
{
|
||||
yield return body;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
(enumerator as IDisposable)?.Dispose();
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
flow.ExitLoop(loop);
|
||||
|
||||
yield return exit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d0be416aee80140f1b4dc427896bc8c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
[TypeIconPriority]
|
||||
public interface IBranchUnit : IUnit
|
||||
{
|
||||
ControlInput enter { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 92a833df7bb3f4742942d5608142400e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
[TypeIconPriority]
|
||||
public interface ISelectUnit : IUnit
|
||||
{
|
||||
ValueOutput selection { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc799370020064779b996a885f88819b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,57 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Branches flow by checking if a condition is true or false.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(0)]
|
||||
[RenamedFrom("Bolt.Branch")]
|
||||
[RenamedFrom("Unity.VisualScripting.Branch")]
|
||||
public sealed class If : Unit, IBranchUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the branch.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The condition to check.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput condition { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute if the condition is true.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("True")]
|
||||
public ControlOutput ifTrue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute if the condition is false.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("False")]
|
||||
public ControlOutput ifFalse { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
condition = ValueInput<bool>(nameof(condition));
|
||||
ifTrue = ControlOutput(nameof(ifTrue));
|
||||
ifFalse = ControlOutput(nameof(ifFalse));
|
||||
|
||||
Requirement(condition, enter);
|
||||
Succession(enter, ifTrue);
|
||||
Succession(enter, ifFalse);
|
||||
}
|
||||
|
||||
public ControlOutput Enter(Flow flow)
|
||||
{
|
||||
return flow.GetValue<bool>(condition) ? ifTrue : ifFalse;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fa98e01b870f4a3e9ee4ae8ee30b97b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,40 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class LoopUnit : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute after the loop has been completed or broken.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute at each loop.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput body { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInputCoroutine(nameof(enter), Loop, LoopCoroutine);
|
||||
exit = ControlOutput(nameof(exit));
|
||||
body = ControlOutput(nameof(body));
|
||||
|
||||
Succession(enter, body);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
protected abstract ControlOutput Loop(Flow flow);
|
||||
|
||||
protected abstract IEnumerator LoopCoroutine(Flow flow);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ee6f6e4db91f45afbbfa24798d7b346
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes an action only once, and a different action afterwards.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(14)]
|
||||
public sealed class Once : Unit, IGraphElementWithData
|
||||
{
|
||||
public sealed class Data : IGraphElementData
|
||||
{
|
||||
public bool executed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for the action.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to reset the once check.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlInput reset { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute the first time the unit is entered.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput once { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute subsequently.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput after { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
reset = ControlInput(nameof(reset), Reset);
|
||||
once = ControlOutput(nameof(once));
|
||||
after = ControlOutput(nameof(after));
|
||||
|
||||
Succession(enter, once);
|
||||
Succession(enter, after);
|
||||
}
|
||||
|
||||
public IGraphElementData CreateData()
|
||||
{
|
||||
return new Data();
|
||||
}
|
||||
|
||||
public ControlOutput Enter(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.executed)
|
||||
{
|
||||
data.executed = true;
|
||||
|
||||
return once;
|
||||
}
|
||||
else
|
||||
{
|
||||
return after;
|
||||
}
|
||||
}
|
||||
|
||||
public ControlOutput Reset(Flow flow)
|
||||
{
|
||||
flow.stack.GetElementData<Data>(this).executed = false;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ce34cee84b3684ac990325bd89f87e2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a value from a set by switching over an enum.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Select On Enum")]
|
||||
[UnitShortTitle("Select")]
|
||||
[UnitSubtitle("On Enum")]
|
||||
[UnitOrder(7)]
|
||||
[TypeIcon(typeof(ISelectUnit))]
|
||||
public sealed class SelectOnEnum : Unit, ISelectUnit
|
||||
{
|
||||
[DoNotSerialize]
|
||||
public Dictionary<object, ValueInput> branches { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value on which to select.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput selector { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The selected value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput selection { get; private set; }
|
||||
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable]
|
||||
[TypeFilter(Enums = true, Classes = false, Interfaces = false, Structs = false, Primitives = false)]
|
||||
public Type enumType { get; set; }
|
||||
|
||||
public override bool canDefine => enumType != null && enumType.IsEnum;
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
branches = new Dictionary<object, ValueInput>();
|
||||
|
||||
selection = ValueOutput(nameof(selection), Branch).Predictable();
|
||||
|
||||
selector = ValueInput(enumType, nameof(selector));
|
||||
|
||||
Requirement(selector, selection);
|
||||
|
||||
foreach (var valueByName in EnumUtility.ValuesByNames(enumType))
|
||||
{
|
||||
var enumValue = valueByName.Value;
|
||||
|
||||
if (branches.ContainsKey(enumValue))
|
||||
continue;
|
||||
|
||||
var branch = ValueInput<object>("%" + valueByName.Key).AllowsNull();
|
||||
|
||||
branches.Add(enumValue, branch);
|
||||
|
||||
Requirement(branch, selection);
|
||||
}
|
||||
}
|
||||
|
||||
public object Branch(Flow flow)
|
||||
{
|
||||
var selector = flow.GetValue(this.selector, enumType);
|
||||
|
||||
return flow.GetValue(branches[selector]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: faf9b20d93da1412c8a40afd3632646a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,72 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a value from a set by matching it with an input flow.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Select On Flow")]
|
||||
[UnitShortTitle("Select")]
|
||||
[UnitSubtitle("On Flow")]
|
||||
[UnitOrder(8)]
|
||||
[TypeIcon(typeof(ISelectUnit))]
|
||||
public sealed class SelectOnFlow : Unit, ISelectUnit
|
||||
{
|
||||
[SerializeAs(nameof(branchCount))]
|
||||
private int _branchCount = 2;
|
||||
|
||||
[DoNotSerialize]
|
||||
[Inspectable, UnitHeaderInspectable("Branches")]
|
||||
public int branchCount
|
||||
{
|
||||
get => _branchCount;
|
||||
set => _branchCount = Mathf.Clamp(value, 2, 10);
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
public Dictionary<ControlInput, ValueInput> branches { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when any selector is entered.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The selected value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput selection { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
branches = new Dictionary<ControlInput, ValueInput>();
|
||||
|
||||
selection = ValueOutput<object>(nameof(selection));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
for (int i = 0; i < branchCount; i++)
|
||||
{
|
||||
var branchValue = ValueInput<object>("value_" + i);
|
||||
var branchControl = ControlInput("enter_" + i, (flow) => Select(flow, branchValue));
|
||||
|
||||
Requirement(branchValue, branchControl);
|
||||
Assignment(branchControl, selection);
|
||||
Succession(branchControl, exit);
|
||||
|
||||
branches.Add(branchControl, branchValue);
|
||||
}
|
||||
}
|
||||
|
||||
public ControlOutput Select(Flow flow, ValueInput branchValue)
|
||||
{
|
||||
flow.SetValue(selection, flow.GetValue(branchValue));
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1dc7ac191c666468cab1db556cd6fa7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a value from a set by switching over an integer.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Select On Integer")]
|
||||
[UnitShortTitle("Select")]
|
||||
[UnitSubtitle("On Integer")]
|
||||
[UnitOrder(8)]
|
||||
public class SelectOnInteger : SelectUnit<int>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b892089634d44ff589ed38e55688715
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a value from a set by switching over a string.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Select On String")]
|
||||
[UnitShortTitle("Select")]
|
||||
[UnitSubtitle("On String")]
|
||||
[UnitOrder(7)]
|
||||
public class SelectOnString : SelectUnit<string>
|
||||
{
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable("Ignore Case")]
|
||||
[InspectorToggleLeft]
|
||||
public bool ignoreCase { get; set; }
|
||||
|
||||
protected override bool Matches(string a, string b)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a) && string.IsNullOrEmpty(b))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return string.Equals(a, b, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4945b8296ec5d4b6fad874116f9bc835
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,57 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a value from a set by checking if a condition is true or false.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Select")]
|
||||
[TypeIcon(typeof(ISelectUnit))]
|
||||
[UnitOrder(6)]
|
||||
public sealed class SelectUnit : Unit, ISelectUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// The condition to check.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput condition { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value to return if the condition is true.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("True")]
|
||||
public ValueInput ifTrue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value to return if the condition is false.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("False")]
|
||||
public ValueInput ifFalse { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The returned value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput selection { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
condition = ValueInput<bool>(nameof(condition));
|
||||
ifTrue = ValueInput<object>(nameof(ifTrue)).AllowsNull();
|
||||
ifFalse = ValueInput<object>(nameof(ifFalse)).AllowsNull();
|
||||
selection = ValueOutput(nameof(selection), Branch).Predictable();
|
||||
|
||||
Requirement(condition, selection);
|
||||
Requirement(ifTrue, selection);
|
||||
Requirement(ifFalse, selection);
|
||||
}
|
||||
|
||||
public object Branch(Flow flow)
|
||||
{
|
||||
return flow.GetValue(flow.GetValue<bool>(condition) ? ifTrue : ifFalse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4c159d9546a084c019e5b2d7610a0269
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,84 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[TypeIcon(typeof(ISelectUnit))]
|
||||
public abstract class SelectUnit<T> : Unit, ISelectUnit
|
||||
{
|
||||
// Using L<KVP> instead of Dictionary to allow null key
|
||||
[DoNotSerialize]
|
||||
public List<KeyValuePair<T, ValueInput>> branches { get; private set; }
|
||||
|
||||
[Inspectable, Serialize]
|
||||
public List<T> options { get; set; } = new List<T>();
|
||||
|
||||
/// <summary>
|
||||
/// The value on which to select.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput selector { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The output value to return if the selector doesn't match any other option.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput @default { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The selected value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput selection { get; private set; }
|
||||
|
||||
public override bool canDefine => options != null;
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
selection = ValueOutput(nameof(selection), Result).Predictable();
|
||||
|
||||
selector = ValueInput<T>(nameof(selector));
|
||||
|
||||
Requirement(selector, selection);
|
||||
|
||||
branches = new List<KeyValuePair<T, ValueInput>>();
|
||||
|
||||
foreach (var option in options)
|
||||
{
|
||||
var key = "%" + option;
|
||||
|
||||
if (!valueInputs.Contains(key))
|
||||
{
|
||||
var branch = ValueInput<object>(key).AllowsNull();
|
||||
branches.Add(new KeyValuePair<T, ValueInput>(option, branch));
|
||||
Requirement(branch, selection);
|
||||
}
|
||||
}
|
||||
|
||||
@default = ValueInput<object>(nameof(@default));
|
||||
|
||||
Requirement(@default, selection);
|
||||
}
|
||||
|
||||
protected virtual bool Matches(T a, T b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
public object Result(Flow flow)
|
||||
{
|
||||
var selector = flow.GetValue<T>(this.selector);
|
||||
|
||||
foreach (var branch in branches)
|
||||
{
|
||||
if (Matches(branch.Key, selector))
|
||||
{
|
||||
return flow.GetValue(branch.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return flow.GetValue(@default);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38ba506333a224b0da52d06c9c27e1f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,90 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes the output ports in order.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(13)]
|
||||
public sealed class Sequence : Unit
|
||||
{
|
||||
[SerializeAs(nameof(outputCount))]
|
||||
private int _outputCount = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for the sequence.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[Inspectable, InspectorLabel("Steps"), UnitHeaderInspectable("Steps")]
|
||||
public int outputCount
|
||||
{
|
||||
get => _outputCount;
|
||||
set => _outputCount = Mathf.Clamp(value, 1, 10);
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
public ReadOnlyCollection<ControlOutput> multiOutputs { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInputCoroutine(nameof(enter), Enter, EnterCoroutine);
|
||||
|
||||
var _multiOutputs = new List<ControlOutput>();
|
||||
|
||||
multiOutputs = _multiOutputs.AsReadOnly();
|
||||
|
||||
for (var i = 0; i < outputCount; i++)
|
||||
{
|
||||
var output = ControlOutput(i.ToString());
|
||||
|
||||
Succession(enter, output);
|
||||
|
||||
_multiOutputs.Add(output);
|
||||
}
|
||||
}
|
||||
|
||||
private ControlOutput Enter(Flow flow)
|
||||
{
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
foreach (var output in multiOutputs)
|
||||
{
|
||||
flow.Invoke(output);
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IEnumerator EnterCoroutine(Flow flow)
|
||||
{
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
foreach (var output in multiOutputs)
|
||||
{
|
||||
yield return output;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
}
|
||||
|
||||
public void CopyFrom(Sequence source)
|
||||
{
|
||||
base.CopyFrom(source);
|
||||
outputCount = source.outputCount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 82582c493d8314bf88bf4722c3c31443
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Branches flow by switching over an enum.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Switch On Enum")]
|
||||
[UnitShortTitle("Switch")]
|
||||
[UnitSubtitle("On Enum")]
|
||||
[UnitOrder(3)]
|
||||
[TypeIcon(typeof(IBranchUnit))]
|
||||
public sealed class SwitchOnEnum : Unit, IBranchUnit
|
||||
{
|
||||
[DoNotSerialize]
|
||||
public Dictionary<Enum, ControlOutput> branches { get; private set; }
|
||||
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable]
|
||||
[TypeFilter(Enums = true, Classes = false, Interfaces = false, Structs = false, Primitives = false)]
|
||||
public Type enumType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for the switch.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The enum value on which to switch.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput @enum { get; private set; }
|
||||
|
||||
public override bool canDefine => enumType != null && enumType.IsEnum;
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
branches = new Dictionary<Enum, ControlOutput>();
|
||||
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
|
||||
@enum = ValueInput(enumType, nameof(@enum));
|
||||
|
||||
Requirement(@enum, enter);
|
||||
|
||||
foreach (var valueByName in EnumUtility.ValuesByNames(enumType))
|
||||
{
|
||||
var enumName = valueByName.Key;
|
||||
var enumValue = valueByName.Value;
|
||||
|
||||
// Just like in C#, duplicate switch labels for the same underlying value is prohibited
|
||||
if (!branches.ContainsKey(enumValue))
|
||||
{
|
||||
var branch = ControlOutput("%" + enumName);
|
||||
|
||||
branches.Add(enumValue, branch);
|
||||
|
||||
Succession(enter, branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ControlOutput Enter(Flow flow)
|
||||
{
|
||||
var @enum = (Enum)flow.GetValue(this.@enum, enumType);
|
||||
|
||||
if (branches.ContainsKey(@enum))
|
||||
{
|
||||
return branches[@enum];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f68c152dd3e314e29908c4b2981fd3e1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Branches flow by switching over an integer.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Switch On Integer")]
|
||||
[UnitShortTitle("Switch")]
|
||||
[UnitSubtitle("On Integer")]
|
||||
[UnitOrder(5)]
|
||||
public class SwitchOnInteger : SwitchUnit<int>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e61d9bfa2304343f28849611c932a7ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Branches flow by switching over a string.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitTitle("Switch On String")]
|
||||
[UnitShortTitle("Switch")]
|
||||
[UnitSubtitle("On String")]
|
||||
[UnitOrder(4)]
|
||||
public class SwitchOnString : SwitchUnit<string>
|
||||
{
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable("Ignore Case")]
|
||||
[InspectorToggleLeft]
|
||||
public bool ignoreCase { get; set; }
|
||||
|
||||
protected override bool Matches(string a, string b)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a) && string.IsNullOrEmpty(b))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return string.Equals(a, b, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 45e0b31244d22469f891e908230c5ef8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,83 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[TypeIcon(typeof(IBranchUnit))]
|
||||
public abstract class SwitchUnit<T> : Unit, IBranchUnit
|
||||
{
|
||||
// Using L<KVP> instead of Dictionary to allow null key
|
||||
[DoNotSerialize]
|
||||
public List<KeyValuePair<T, ControlOutput>> branches { get; private set; }
|
||||
|
||||
[Inspectable, Serialize]
|
||||
public List<T> options { get; set; } = new List<T>();
|
||||
|
||||
/// <summary>
|
||||
/// The entry point for the switch.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value on which to switch.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput selector { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The branch to take if the input value does not match any other option.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput @default { get; private set; }
|
||||
|
||||
public override bool canDefine => options != null;
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
|
||||
selector = ValueInput<T>(nameof(selector));
|
||||
|
||||
Requirement(selector, enter);
|
||||
|
||||
branches = new List<KeyValuePair<T, ControlOutput>>();
|
||||
|
||||
foreach (var option in options)
|
||||
{
|
||||
var key = "%" + option;
|
||||
|
||||
if (!controlOutputs.Contains(key))
|
||||
{
|
||||
var branch = ControlOutput(key);
|
||||
branches.Add(new KeyValuePair<T, ControlOutput>(option, branch));
|
||||
Succession(enter, branch);
|
||||
}
|
||||
}
|
||||
|
||||
@default = ControlOutput(nameof(@default));
|
||||
Succession(enter, @default);
|
||||
}
|
||||
|
||||
protected virtual bool Matches(T a, T b)
|
||||
{
|
||||
return Equals(a, b);
|
||||
}
|
||||
|
||||
public ControlOutput Enter(Flow flow)
|
||||
{
|
||||
var selector = flow.GetValue<T>(this.selector);
|
||||
|
||||
foreach (var branch in branches)
|
||||
{
|
||||
if (Matches(branch.Key, selector))
|
||||
{
|
||||
return branch.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return @default;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 00656f383fee948f694c016f8cdcb404
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Throws an exception.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(16)]
|
||||
public sealed class Throw : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether a custom exception object should be specified manually.
|
||||
/// </summary>
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable("Custom")]
|
||||
[InspectorToggleLeft]
|
||||
public bool custom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The entry point to throw the exception.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The message of the exception.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput message { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The exception to throw.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput exception { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
if (custom)
|
||||
{
|
||||
enter = ControlInput(nameof(enter), ThrowCustom);
|
||||
exception = ValueInput<Exception>(nameof(exception));
|
||||
Requirement(exception, enter);
|
||||
}
|
||||
else
|
||||
{
|
||||
enter = ControlInput(nameof(enter), ThrowMessage);
|
||||
message = ValueInput(nameof(message), string.Empty);
|
||||
Requirement(message, enter);
|
||||
}
|
||||
}
|
||||
|
||||
private ControlOutput ThrowCustom(Flow flow)
|
||||
{
|
||||
throw flow.GetValue<Exception>(exception);
|
||||
}
|
||||
|
||||
private ControlOutput ThrowMessage(Flow flow)
|
||||
{
|
||||
throw new Exception(flow.GetValue<string>(message));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dcb6d6466a47741b7814e9bca56b1573
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,158 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Toggles the control flow with on and off triggers.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(18)]
|
||||
[UnitFooterPorts(ControlInputs = true, ControlOutputs = true)]
|
||||
public sealed class ToggleFlow : Unit, IGraphElementWithData
|
||||
{
|
||||
public class Data : IGraphElementData
|
||||
{
|
||||
public bool isOn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the toggle should start in the on state.
|
||||
/// </summary>
|
||||
[Serialize]
|
||||
[Inspectable]
|
||||
[UnitHeaderInspectable("Start On")]
|
||||
[InspectorToggleLeft]
|
||||
public bool startOn { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Entry point to the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to turn on the flow through the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("On")]
|
||||
public ControlInput turnOn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to turn off the flow through the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Off")]
|
||||
public ControlInput turnOff { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to toggle the flow through the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlInput toggle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered on entry if the flow is on.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("On")]
|
||||
public ControlOutput exitOn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered on entry if the flow is off.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Off")]
|
||||
public ControlOutput exitOff { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the flow gets turned on.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput turnedOn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the flow gets turned off.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput turnedOff { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the flow is currently on.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueOutput isOn { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
turnOn = ControlInput(nameof(turnOn), TurnOn);
|
||||
turnOff = ControlInput(nameof(turnOff), TurnOff);
|
||||
toggle = ControlInput(nameof(toggle), Toggle);
|
||||
|
||||
exitOn = ControlOutput(nameof(exitOn));
|
||||
exitOff = ControlOutput(nameof(exitOff));
|
||||
turnedOn = ControlOutput(nameof(turnedOn));
|
||||
turnedOff = ControlOutput(nameof(turnedOff));
|
||||
|
||||
isOn = ValueOutput(nameof(isOn), IsOn);
|
||||
|
||||
Succession(enter, exitOn);
|
||||
Succession(enter, exitOff);
|
||||
Succession(turnOn, turnedOn);
|
||||
Succession(turnOff, turnedOff);
|
||||
Succession(toggle, turnedOn);
|
||||
Succession(toggle, turnedOff);
|
||||
}
|
||||
|
||||
public IGraphElementData CreateData()
|
||||
{
|
||||
return new Data() { isOn = startOn };
|
||||
}
|
||||
|
||||
private bool IsOn(Flow flow)
|
||||
{
|
||||
return flow.stack.GetElementData<Data>(this).isOn;
|
||||
}
|
||||
|
||||
private ControlOutput Enter(Flow flow)
|
||||
{
|
||||
return IsOn(flow) ? exitOn : exitOff;
|
||||
}
|
||||
|
||||
private ControlOutput TurnOn(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (data.isOn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
data.isOn = true;
|
||||
|
||||
return turnedOn;
|
||||
}
|
||||
|
||||
private ControlOutput TurnOff(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.isOn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
data.isOn = false;
|
||||
|
||||
return turnedOff;
|
||||
}
|
||||
|
||||
private ControlOutput Toggle(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
data.isOn = !data.isOn;
|
||||
|
||||
return data.isOn ? turnedOn : turnedOff;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b468d76c18c2a410aa40c222a91eebb3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,158 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Toggles between two values with on and off triggers.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(19)]
|
||||
[UnitFooterPorts(ControlInputs = true, ControlOutputs = true)]
|
||||
public sealed class ToggleValue : Unit, IGraphElementWithData
|
||||
{
|
||||
public class Data : IGraphElementData
|
||||
{
|
||||
public bool isOn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the toggle should start in the on state.
|
||||
/// </summary>
|
||||
[Serialize]
|
||||
[Inspectable]
|
||||
[UnitHeaderInspectable("Start On")]
|
||||
[InspectorToggleLeft]
|
||||
public bool startOn { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to turn on the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("On")]
|
||||
public ControlInput turnOn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to turn off the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Off")]
|
||||
public ControlInput turnOff { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to toggle the state of the toggle.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlInput toggle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value to return if the toggle is on.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput onValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value to return if the toggle is off.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput offValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the flow gets turned on.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput turnedOn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the flow gets turned off.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput turnedOff { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the flow is currently on.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueOutput isOn { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the toggle selected depending on the state.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueOutput value { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
turnOn = ControlInput(nameof(turnOn), TurnOn);
|
||||
turnOff = ControlInput(nameof(turnOff), TurnOff);
|
||||
toggle = ControlInput(nameof(toggle), Toggle);
|
||||
|
||||
onValue = ValueInput<object>(nameof(onValue));
|
||||
offValue = ValueInput<object>(nameof(offValue));
|
||||
|
||||
turnedOn = ControlOutput(nameof(turnedOn));
|
||||
turnedOff = ControlOutput(nameof(turnedOff));
|
||||
|
||||
isOn = ValueOutput(nameof(isOn), IsOn);
|
||||
value = ValueOutput(nameof(value), Value);
|
||||
|
||||
Requirement(onValue, value);
|
||||
Requirement(offValue, value);
|
||||
Succession(turnOn, turnedOn);
|
||||
Succession(turnOff, turnedOff);
|
||||
Succession(toggle, turnedOn);
|
||||
Succession(toggle, turnedOff);
|
||||
}
|
||||
|
||||
public IGraphElementData CreateData()
|
||||
{
|
||||
return new Data() { isOn = startOn };
|
||||
}
|
||||
|
||||
private bool IsOn(Flow flow)
|
||||
{
|
||||
return flow.stack.GetElementData<Data>(this).isOn;
|
||||
}
|
||||
|
||||
private ControlOutput TurnOn(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (data.isOn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
data.isOn = true;
|
||||
|
||||
return turnedOn;
|
||||
}
|
||||
|
||||
private ControlOutput TurnOff(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.isOn)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
data.isOn = false;
|
||||
|
||||
return turnedOff;
|
||||
}
|
||||
|
||||
private ControlOutput Toggle(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
data.isOn = !data.isOn;
|
||||
|
||||
return data.isOn ? turnedOn : turnedOff;
|
||||
}
|
||||
|
||||
private object Value(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
return flow.GetValue(data.isOn ? onValue : offValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bf595eee981c54462b9b709712dd098f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles an exception if it occurs.
|
||||
/// </summary>
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(17)]
|
||||
[UnitFooterPorts(ControlOutputs = true)]
|
||||
public sealed class TryCatch : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the try-catch block.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to attempt.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput @try { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute if an exception is thrown.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput @catch { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute afterwards, regardless of whether there was an exception.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ControlOutput @finally { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The exception that was thrown in the try block.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueOutput exception { get; private set; }
|
||||
|
||||
[Serialize]
|
||||
[Inspectable, UnitHeaderInspectable]
|
||||
[TypeFilter(typeof(Exception), Matching = TypesMatching.AssignableToAll)]
|
||||
[TypeSet(TypeSet.SettingsAssembliesTypes)]
|
||||
public Type exceptionType { get; set; } = typeof(Exception);
|
||||
|
||||
public override bool canDefine => exceptionType != null && typeof(Exception).IsAssignableFrom(exceptionType);
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
@try = ControlOutput(nameof(@try));
|
||||
@catch = ControlOutput(nameof(@catch));
|
||||
@finally = ControlOutput(nameof(@finally));
|
||||
exception = ValueOutput(exceptionType, nameof(exception));
|
||||
|
||||
Assignment(enter, exception);
|
||||
Succession(enter, @try);
|
||||
Succession(enter, @catch);
|
||||
Succession(enter, @finally);
|
||||
}
|
||||
|
||||
public ControlOutput Enter(Flow flow)
|
||||
{
|
||||
if (flow.isCoroutine)
|
||||
{
|
||||
throw new NotSupportedException("Coroutines cannot catch exceptions.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
flow.Invoke(@try);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionType.IsInstanceOfType(ex))
|
||||
{
|
||||
flow.SetValue(exception, ex);
|
||||
flow.Invoke(@catch);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
flow.Invoke(@finally);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 76b0b46319dee4014a91956b9c12c7c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Loops as long as a given condition is true.
|
||||
/// </summary>
|
||||
[UnitTitle("While Loop")]
|
||||
[UnitCategory("Control")]
|
||||
[UnitOrder(11)]
|
||||
public class While : LoopUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// The condition to check at each iteration to determine whether the loop should continue.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput condition { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
base.Definition();
|
||||
|
||||
condition = ValueInput<bool>(nameof(condition));
|
||||
|
||||
Requirement(condition, enter);
|
||||
}
|
||||
|
||||
private int Start(Flow flow)
|
||||
{
|
||||
return flow.EnterLoop();
|
||||
}
|
||||
|
||||
private bool CanMoveNext(Flow flow)
|
||||
{
|
||||
return flow.GetValue<bool>(condition);
|
||||
}
|
||||
|
||||
protected override ControlOutput Loop(Flow flow)
|
||||
{
|
||||
var loop = Start(flow);
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
while (flow.LoopIsNotBroken(loop) && CanMoveNext(flow))
|
||||
{
|
||||
flow.Invoke(body);
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
flow.ExitLoop(loop);
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
protected override IEnumerator LoopCoroutine(Flow flow)
|
||||
{
|
||||
var loop = Start(flow);
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
|
||||
while (flow.LoopIsNotBroken(loop) && CanMoveNext(flow))
|
||||
{
|
||||
yield return body;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
|
||||
flow.ExitLoop(loop);
|
||||
|
||||
yield return exit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0db824a4c272f449289bfa24e1b40805
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue