test
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61c823205c2384c13b4d38c05194c1df
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a struct with its default initializer.
|
||||
/// </summary>
|
||||
[SpecialUnit]
|
||||
public sealed class CreateStruct : Unit
|
||||
{
|
||||
[Obsolete(Serialization.ConstructorWarning)]
|
||||
public CreateStruct() : base() { }
|
||||
|
||||
public CreateStruct(Type type) : base()
|
||||
{
|
||||
Ensure.That(nameof(type)).IsNotNull(type);
|
||||
|
||||
if (!type.IsStruct())
|
||||
{
|
||||
throw new ArgumentException($"Type {type} must be a struct.", nameof(type));
|
||||
}
|
||||
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
[Serialize]
|
||||
public Type type { get; internal set; }
|
||||
|
||||
// Shouldn't happen through normal use, but can happen
|
||||
// if deserialization fails to find the type
|
||||
// https://support.ludiq.io/communities/5/topics/1661-x
|
||||
public override bool canDefine => type != null;
|
||||
|
||||
/// <summary>
|
||||
/// The entry point to create the struct. You can
|
||||
/// still get the return value without connecting this port.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to call once the struct has been created.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The created struct.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput output { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
exit = ControlOutput(nameof(exit));
|
||||
output = ValueOutput(type, nameof(output), Create);
|
||||
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
private ControlOutput Enter(Flow flow)
|
||||
{
|
||||
flow.SetValue(output, Activator.CreateInstance(type));
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
private object Create(Flow flow)
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af2d94135152d4d9f8cbc7d76430b106
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes all members of the type.
|
||||
/// </summary>
|
||||
[SpecialUnit]
|
||||
public sealed class Expose : Unit, IAotStubbable
|
||||
{
|
||||
public Expose() : base() { }
|
||||
|
||||
public Expose(Type type) : base()
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
[Serialize, Inspectable, TypeFilter(Enums = false)]
|
||||
public Type type { get; set; }
|
||||
|
||||
[Serialize, Inspectable, UnitHeaderInspectable("Instance"), InspectorToggleLeft]
|
||||
public bool instance { get; set; } = true;
|
||||
|
||||
[Serialize, Inspectable, UnitHeaderInspectable("Static"), InspectorToggleLeft]
|
||||
public bool @static { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The instance of the exposed type.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
[NullMeansSelf]
|
||||
public ValueInput target { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public Dictionary<ValueOutput, Member> members { get; private set; }
|
||||
|
||||
public override bool canDefine => type != null;
|
||||
|
||||
public override IEnumerable<object> GetAotStubs(HashSet<object> visited)
|
||||
{
|
||||
if (members != null)
|
||||
{
|
||||
foreach (var member in members.Values)
|
||||
{
|
||||
if (member != null && member.isReflected)
|
||||
{
|
||||
yield return member.info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
members = new Dictionary<ValueOutput, Member>();
|
||||
|
||||
var requiresTarget = false;
|
||||
|
||||
foreach (var member in type.GetMembers()
|
||||
.Where(m => m is FieldInfo || m is PropertyInfo)
|
||||
.Select(m => m.ToManipulator(type))
|
||||
.DistinctBy(m => m.name) // To account for "new" duplicates
|
||||
.Where(Include)
|
||||
.OrderBy(m => m.requiresTarget ? 0 : 1)
|
||||
.ThenBy(m => m.order))
|
||||
{
|
||||
var memberPort = ValueOutput(member.type, member.name, (flow) => GetValue(flow, member));
|
||||
|
||||
if (member.isPredictable)
|
||||
{
|
||||
memberPort.Predictable();
|
||||
}
|
||||
|
||||
members.Add(memberPort, member);
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
requiresTarget = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresTarget)
|
||||
{
|
||||
target = ValueInput(type, nameof(target)).NullMeansSelf();
|
||||
|
||||
target.SetDefaultValue(type.PseudoDefault());
|
||||
|
||||
foreach (var member in members.Keys)
|
||||
{
|
||||
if (members[member].requiresTarget)
|
||||
{
|
||||
Requirement(target, member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool Include(Member member)
|
||||
{
|
||||
if (!instance && member.requiresTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!@static && !member.requiresTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!member.isPubliclyGettable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (member.info.HasAttribute<ObsoleteAttribute>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (member.isIndexer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pesky edit-mode only accessor that is only available in the editor,
|
||||
// yet isn't marked by any special attribute to indicate it.
|
||||
if (member.name == "runInEditMode" && member.declaringType == typeof(MonoBehaviour))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private object GetValue(Flow flow, Member member)
|
||||
{
|
||||
var target = member.requiresTarget ? flow.GetValue(this.target, member.targetType) : null;
|
||||
|
||||
return member.Get(target);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d81baa29b4461445b815939d80f9c3ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,74 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the value of a field or property via reflection.
|
||||
/// </summary>
|
||||
public sealed class GetMember : MemberUnit
|
||||
{
|
||||
public GetMember() { }
|
||||
|
||||
public GetMember(Member member) : base(member) { }
|
||||
|
||||
[DoNotSerialize]
|
||||
[MemberFilter(Fields = true, Properties = true, WriteOnly = false)]
|
||||
public Member getter
|
||||
{
|
||||
get
|
||||
{
|
||||
return member;
|
||||
}
|
||||
set
|
||||
{
|
||||
member = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput value { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
base.Definition();
|
||||
|
||||
value = ValueOutput(member.type, nameof(value), Value);
|
||||
|
||||
if (member.isPredictable)
|
||||
{
|
||||
value.Predictable();
|
||||
}
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
Requirement(target, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsMemberValid(Member member)
|
||||
{
|
||||
return member.isAccessor && member.isGettable;
|
||||
}
|
||||
|
||||
private object Value(Flow flow)
|
||||
{
|
||||
var target = member.requiresTarget ? flow.GetValue(this.target, member.targetType) : null;
|
||||
|
||||
return member.Get(target);
|
||||
}
|
||||
|
||||
#region Analytics
|
||||
|
||||
public override AnalyticsIdentifier GetAnalyticsIdentifier()
|
||||
{
|
||||
var aid = new AnalyticsIdentifier
|
||||
{
|
||||
Identifier = $"{member.targetType.FullName}.{member.name}(Get)",
|
||||
Namespace = member.targetType.Namespace
|
||||
};
|
||||
aid.Hashcode = aid.Identifier.GetHashCode();
|
||||
return aid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f67023a80a5b4f2b9fc4ab3f44105d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,458 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Invokes a method or a constructor via reflection.
|
||||
/// </summary>
|
||||
public sealed class InvokeMember : MemberUnit
|
||||
{
|
||||
public InvokeMember() : base() { }
|
||||
|
||||
public InvokeMember(Member member) : base(member) { }
|
||||
|
||||
private bool useExpandedParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the target should be output to allow for chaining.
|
||||
/// </summary>
|
||||
[Serialize]
|
||||
[InspectableIf(nameof(supportsChaining))]
|
||||
public bool chainable { get; set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public bool supportsChaining => member.requiresTarget;
|
||||
|
||||
[DoNotSerialize]
|
||||
[MemberFilter(Methods = true, Constructors = true)]
|
||||
public Member invocation
|
||||
{
|
||||
get { return member; }
|
||||
set { member = value; }
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public Dictionary<int, ValueInput> inputParameters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The target object used when setting the value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Target")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput targetOutput { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput result { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public Dictionary<int, ValueOutput> outputParameters { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
private int parameterCount;
|
||||
|
||||
[Serialize]
|
||||
List<string> parameterNames;
|
||||
|
||||
public override bool HandleDependencies()
|
||||
{
|
||||
if (!base.HandleDependencies())
|
||||
return false;
|
||||
|
||||
// Here we have a chance to do a bit of post processing after deserialization of this node has occured.
|
||||
|
||||
// In the past we did not serialize parameter names explicitly (only parameter types), however, if we have
|
||||
// exactly the same number of defaults as parameters, we happen to know what the original parameter names were.
|
||||
// Note there is one specific exception that must be handled carefully, the base class (MemberUnit) adds a
|
||||
// default value for the "target" (aka. the "this" instance) of the invocation; this does not correspond to
|
||||
// a real parameter member so it is excluded here when trying to reconstruct the missing parameter names.
|
||||
if (parameterNames == null && member.parameterTypes.Length == defaultValues.Count(d => d.Key != nameof(target)))
|
||||
{
|
||||
// Note that we strip the "%" prefix from the parameter name in the default values (the "%" denotes that
|
||||
// it is a parameter input)
|
||||
parameterNames = defaultValues
|
||||
.Where(d => d.Key != nameof(target))
|
||||
.Select(defaultValue => defaultValue.Key.Substring(1))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
base.Definition();
|
||||
|
||||
inputParameters = new Dictionary<int, ValueInput>();
|
||||
outputParameters = new Dictionary<int, ValueOutput>();
|
||||
useExpandedParameters = true;
|
||||
|
||||
enter = ControlInput(nameof(enter), Enter);
|
||||
exit = ControlOutput(nameof(exit));
|
||||
Succession(enter, exit);
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
Requirement(target, enter);
|
||||
}
|
||||
|
||||
if (supportsChaining && chainable)
|
||||
{
|
||||
targetOutput = ValueOutput(member.targetType, nameof(targetOutput));
|
||||
Assignment(enter, targetOutput);
|
||||
}
|
||||
|
||||
if (member.isGettable)
|
||||
{
|
||||
result = ValueOutput(member.type, nameof(result), Result);
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
Requirement(target, result);
|
||||
}
|
||||
}
|
||||
|
||||
var parameterInfos = member.GetParameterInfos().ToArray();
|
||||
|
||||
parameterCount = parameterInfos.Length;
|
||||
|
||||
bool needsParameterRemapping = false;
|
||||
for (int parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
|
||||
{
|
||||
var parameterInfo = parameterInfos[parameterIndex];
|
||||
|
||||
var parameterType = parameterInfo.UnderlyingParameterType();
|
||||
|
||||
if (!parameterInfo.HasOutModifier())
|
||||
{
|
||||
var inputParameterKey = "%" + parameterInfo.Name;
|
||||
|
||||
// Changes in parameter names are tolerated, use the old parameter naming for now and fix it later.
|
||||
if (parameterNames != null && parameterNames[parameterIndex] != parameterInfo.Name)
|
||||
{
|
||||
inputParameterKey = "%" + parameterNames[parameterIndex];
|
||||
needsParameterRemapping = true;
|
||||
}
|
||||
|
||||
var inputParameter = ValueInput(parameterType, inputParameterKey);
|
||||
|
||||
inputParameters.Add(parameterIndex, inputParameter);
|
||||
|
||||
inputParameter.SetDefaultValue(parameterInfo.PseudoDefaultValue());
|
||||
|
||||
if (parameterInfo.AllowsNull())
|
||||
{
|
||||
inputParameter.AllowsNull();
|
||||
}
|
||||
|
||||
Requirement(inputParameter, enter);
|
||||
|
||||
if (member.isGettable)
|
||||
{
|
||||
Requirement(inputParameter, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (parameterInfo.ParameterType.IsByRef || parameterInfo.IsOut)
|
||||
{
|
||||
var outputParameterKey = "&" + parameterInfo.Name;
|
||||
|
||||
// Changes in parameter names are tolerated, use the old parameter naming for now and fix it later.
|
||||
if (parameterNames != null && parameterNames[parameterIndex] != parameterInfo.Name)
|
||||
{
|
||||
outputParameterKey = "&" + parameterNames[parameterIndex];
|
||||
needsParameterRemapping = true;
|
||||
}
|
||||
|
||||
var outputParameter = ValueOutput(parameterType, outputParameterKey);
|
||||
|
||||
outputParameters.Add(parameterIndex, outputParameter);
|
||||
|
||||
Assignment(enter, outputParameter);
|
||||
|
||||
useExpandedParameters = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputParameters.Count > 5)
|
||||
{
|
||||
useExpandedParameters = false;
|
||||
}
|
||||
|
||||
if (parameterNames == null)
|
||||
{
|
||||
parameterNames = parameterInfos.Select(pInfo => pInfo.Name).ToList();
|
||||
}
|
||||
|
||||
if (needsParameterRemapping)
|
||||
{
|
||||
// Note, this will have no effect unless we are in an Editor context. This is okay since for runtime
|
||||
// purposes as it is actually fine to continue to use the old parameter names for the sake of setting up
|
||||
// connections and default values. The only reason it is interesting to update to the new parameter
|
||||
// names is for UI purposes.
|
||||
UnityThread.EditorAsync(PostDeserializeRemapParameterNames);
|
||||
}
|
||||
}
|
||||
|
||||
private void PostDeserializeRemapParameterNames()
|
||||
{
|
||||
var parameterInfos = member.GetParameterInfos().ToArray();
|
||||
|
||||
// Sanity check
|
||||
if (parameterNames?.Count != parameterInfos.Length)
|
||||
return;
|
||||
|
||||
// Check if any of the method parameter names have changed (Note: handling of parameter type changes is not
|
||||
// supported here, it is detected and handled elsewhere)
|
||||
List<(ValueInput port, ValueOutput[] connectedSources)> renamedInputs = null;
|
||||
List<(ValueOutput port, ValueInput[] connectedDestinations)> renamedOutputs = null;
|
||||
List<(string name, object value)> renamedDefaults = null;
|
||||
for (var i = 0; i < parameterInfos.Length; ++i)
|
||||
{
|
||||
var paramInfo = parameterInfos[i];
|
||||
var oldParamName = parameterNames[i];
|
||||
|
||||
if (paramInfo.Name != oldParamName)
|
||||
{
|
||||
// Phase 1 of parameter renaming: disconnect any nodes connected to affected ports, remove affected
|
||||
// ports from port definition, and remove any default values associated with affected ports.
|
||||
if (valueInputs.TryGetValue("%" + oldParamName, out var oldInput))
|
||||
{
|
||||
var connectionSources = oldInput.validConnections.Select(con => con.source).ToArray();
|
||||
foreach (var source in connectionSources)
|
||||
source.DisconnectFromValid(oldInput);
|
||||
|
||||
valueInputs.Remove(oldInput);
|
||||
|
||||
if (renamedInputs == null)
|
||||
renamedInputs = new List<(ValueInput, ValueOutput[])>(1);
|
||||
renamedInputs.Add((new ValueInput("%" + paramInfo.Name, paramInfo.ParameterType), connectionSources));
|
||||
|
||||
if (defaultValues.TryGetValue(oldInput.key, out var defaultValue))
|
||||
{
|
||||
defaultValues.Remove(oldInput.key);
|
||||
if (renamedDefaults == null)
|
||||
renamedDefaults = new List<(string, object)>(1);
|
||||
renamedDefaults.Add(("%" + paramInfo.Name, defaultValue));
|
||||
}
|
||||
}
|
||||
else if (valueOutputs.TryGetValue("&" + oldParamName, out var oldOutput))
|
||||
{
|
||||
var connectionDestinations = oldOutput.validConnections.Select(con => con.destination).ToArray();
|
||||
foreach (var destination in connectionDestinations)
|
||||
destination.DisconnectFromValid(oldOutput);
|
||||
|
||||
valueOutputs.Remove(oldOutput);
|
||||
|
||||
if (renamedOutputs == null)
|
||||
renamedOutputs = new List<(ValueOutput, ValueInput[])>(1);
|
||||
renamedOutputs.Add((new ValueOutput("&" + paramInfo.Name, paramInfo.ParameterType), connectionDestinations));
|
||||
}
|
||||
|
||||
parameterNames[i] = paramInfo.Name;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2 of parameter renaming: add renamed version of affected ports back to the port definition, reconnect
|
||||
// nodes back to those renamed ports, and redefine default values for those ports.
|
||||
if (renamedInputs != null)
|
||||
{
|
||||
foreach (var renamedInput in renamedInputs)
|
||||
{
|
||||
valueInputs.Add(renamedInput.port);
|
||||
foreach (var source in renamedInput.connectedSources)
|
||||
source.ConnectToValid(renamedInput.port);
|
||||
}
|
||||
if (renamedDefaults != null)
|
||||
{
|
||||
foreach (var renamedDefault in renamedDefaults)
|
||||
defaultValues[renamedDefault.name] = renamedDefault.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (renamedOutputs != null)
|
||||
{
|
||||
foreach (var renamedOutput in renamedOutputs)
|
||||
{
|
||||
valueOutputs.Add(renamedOutput.port);
|
||||
foreach (var destination in renamedOutput.connectedDestinations)
|
||||
destination.ConnectToValid(renamedOutput.port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (renamedInputs != null || renamedOutputs != null)
|
||||
{
|
||||
Define();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsMemberValid(Member member)
|
||||
{
|
||||
return member.isInvocable;
|
||||
}
|
||||
|
||||
private object Invoke(object target, Flow flow)
|
||||
{
|
||||
if (useExpandedParameters)
|
||||
{
|
||||
switch (inputParameters.Count)
|
||||
{
|
||||
case 0:
|
||||
|
||||
return member.Invoke(target);
|
||||
|
||||
case 1:
|
||||
|
||||
return member.Invoke(target,
|
||||
flow.GetConvertedValue(inputParameters[0]));
|
||||
|
||||
case 2:
|
||||
|
||||
return member.Invoke(target,
|
||||
flow.GetConvertedValue(inputParameters[0]),
|
||||
flow.GetConvertedValue(inputParameters[1]));
|
||||
|
||||
case 3:
|
||||
|
||||
return member.Invoke(target,
|
||||
flow.GetConvertedValue(inputParameters[0]),
|
||||
flow.GetConvertedValue(inputParameters[1]),
|
||||
flow.GetConvertedValue(inputParameters[2]));
|
||||
|
||||
case 4:
|
||||
|
||||
return member.Invoke(target,
|
||||
flow.GetConvertedValue(inputParameters[0]),
|
||||
flow.GetConvertedValue(inputParameters[1]),
|
||||
flow.GetConvertedValue(inputParameters[2]),
|
||||
flow.GetConvertedValue(inputParameters[3]));
|
||||
|
||||
case 5:
|
||||
|
||||
return member.Invoke(target,
|
||||
flow.GetConvertedValue(inputParameters[0]),
|
||||
flow.GetConvertedValue(inputParameters[1]),
|
||||
flow.GetConvertedValue(inputParameters[2]),
|
||||
flow.GetConvertedValue(inputParameters[3]),
|
||||
flow.GetConvertedValue(inputParameters[4]));
|
||||
|
||||
default:
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var arguments = new object[parameterCount];
|
||||
|
||||
for (int parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
|
||||
{
|
||||
if (inputParameters.TryGetValue(parameterIndex, out var inputParameter))
|
||||
{
|
||||
arguments[parameterIndex] = flow.GetConvertedValue(inputParameter);
|
||||
}
|
||||
}
|
||||
|
||||
var result = member.Invoke(target, arguments);
|
||||
|
||||
for (int parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
|
||||
{
|
||||
if (outputParameters.TryGetValue(parameterIndex, out var outputParameter))
|
||||
{
|
||||
flow.SetValue(outputParameter, arguments[parameterIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private object GetAndChainTarget(Flow flow)
|
||||
{
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
var target = flow.GetValue(this.target, member.targetType);
|
||||
|
||||
if (supportsChaining && chainable)
|
||||
{
|
||||
flow.SetValue(targetOutput, target);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private object Result(Flow flow)
|
||||
{
|
||||
var target = GetAndChainTarget(flow);
|
||||
|
||||
return Invoke(target, flow);
|
||||
}
|
||||
|
||||
private ControlOutput Enter(Flow flow)
|
||||
{
|
||||
var target = GetAndChainTarget(flow);
|
||||
|
||||
var result = Invoke(target, flow);
|
||||
|
||||
if (this.result != null)
|
||||
{
|
||||
flow.SetValue(this.result, result);
|
||||
}
|
||||
|
||||
return exit;
|
||||
}
|
||||
|
||||
#region Analytics
|
||||
|
||||
public override AnalyticsIdentifier GetAnalyticsIdentifier()
|
||||
{
|
||||
const int maxNumParameters = 5;
|
||||
var s = $"{member.targetType.FullName}.{member.name}";
|
||||
|
||||
if (member.parameterTypes != null)
|
||||
{
|
||||
s += "(";
|
||||
|
||||
for (var i = 0; i < member.parameterTypes.Length; ++i)
|
||||
{
|
||||
if (i >= maxNumParameters)
|
||||
{
|
||||
s += $"->{i}";
|
||||
break;
|
||||
}
|
||||
|
||||
s += member.parameterTypes[i].FullName;
|
||||
if (i < member.parameterTypes.Length - 1)
|
||||
s += ", ";
|
||||
}
|
||||
|
||||
s += ")";
|
||||
}
|
||||
|
||||
var aid = new AnalyticsIdentifier
|
||||
{
|
||||
Identifier = s,
|
||||
Namespace = member.targetType.Namespace
|
||||
};
|
||||
aid.Hashcode = aid.Identifier.GetHashCode();
|
||||
return aid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89f8cd8ccb56d4a84b7f84d9819c7ca6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[SpecialUnit]
|
||||
public abstract class MemberUnit : Unit, IAotStubbable
|
||||
{
|
||||
protected MemberUnit() : base() { }
|
||||
|
||||
protected MemberUnit(Member member) : this()
|
||||
{
|
||||
this.member = member;
|
||||
}
|
||||
|
||||
[Serialize]
|
||||
[MemberFilter(Fields = true, Properties = true, Methods = true, Constructors = true)]
|
||||
public Member member { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The target object.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
[NullMeansSelf]
|
||||
public ValueInput target { get; private set; }
|
||||
|
||||
public override bool canDefine => member != null;
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
member.EnsureReflected();
|
||||
|
||||
if (!IsMemberValid(member))
|
||||
{
|
||||
throw new NotSupportedException("The member type is not valid for this unit.");
|
||||
}
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
target = ValueInput(member.targetType, nameof(target));
|
||||
|
||||
target.SetDefaultValue(member.targetType.PseudoDefault());
|
||||
|
||||
if (typeof(UnityObject).IsAssignableFrom(member.targetType))
|
||||
{
|
||||
target.NullMeansSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool IsMemberValid(Member member);
|
||||
|
||||
public override void Prewarm()
|
||||
{
|
||||
if (member != null && member.isReflected)
|
||||
{
|
||||
member.Prewarm();
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<object> GetAotStubs(HashSet<object> visited)
|
||||
{
|
||||
if (member != null && member.isReflected)
|
||||
{
|
||||
yield return member.info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ba199e97bc1b4300b1fc168762de698
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,137 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the value of a field or property via reflection.
|
||||
/// </summary>
|
||||
public sealed class SetMember : MemberUnit
|
||||
{
|
||||
public SetMember() : base() { }
|
||||
|
||||
public SetMember(Member member) : base(member) { }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the target should be output to allow for chaining.
|
||||
/// </summary>
|
||||
[Serialize]
|
||||
[InspectableIf(nameof(supportsChaining))]
|
||||
public bool chainable { get; set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public bool supportsChaining => member.requiresTarget;
|
||||
|
||||
[DoNotSerialize]
|
||||
[MemberFilter(Fields = true, Properties = true, ReadOnly = false)]
|
||||
public Member setter
|
||||
{
|
||||
get => member;
|
||||
set => member = value;
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput assign { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Value")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput input { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Value")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput output { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The target object used when setting the value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Target")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput targetOutput { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput assigned { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
base.Definition();
|
||||
|
||||
assign = ControlInput(nameof(assign), Assign);
|
||||
assigned = ControlOutput(nameof(assigned));
|
||||
Succession(assign, assigned);
|
||||
|
||||
if (supportsChaining && chainable)
|
||||
{
|
||||
targetOutput = ValueOutput(member.targetType, nameof(targetOutput));
|
||||
Assignment(assign, targetOutput);
|
||||
}
|
||||
|
||||
output = ValueOutput(member.type, nameof(output));
|
||||
Assignment(assign, output);
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
Requirement(target, assign);
|
||||
}
|
||||
|
||||
input = ValueInput(member.type, nameof(input));
|
||||
Requirement(input, assign);
|
||||
|
||||
if (member.allowsNull)
|
||||
{
|
||||
input.AllowsNull();
|
||||
}
|
||||
|
||||
input.SetDefaultValue(member.type.PseudoDefault());
|
||||
}
|
||||
|
||||
protected override bool IsMemberValid(Member member)
|
||||
{
|
||||
return member.isAccessor && member.isSettable;
|
||||
}
|
||||
|
||||
private object GetAndChainTarget(Flow flow)
|
||||
{
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
var target = flow.GetValue(this.target, member.targetType);
|
||||
|
||||
if (supportsChaining && chainable)
|
||||
{
|
||||
flow.SetValue(targetOutput, target);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ControlOutput Assign(Flow flow)
|
||||
{
|
||||
var target = GetAndChainTarget(flow);
|
||||
|
||||
var value = flow.GetConvertedValue(input);
|
||||
|
||||
flow.SetValue(output, member.Set(target, value));
|
||||
|
||||
return assigned;
|
||||
}
|
||||
|
||||
#region Analytics
|
||||
|
||||
public override AnalyticsIdentifier GetAnalyticsIdentifier()
|
||||
{
|
||||
var aid = new AnalyticsIdentifier
|
||||
{
|
||||
Identifier = $"{member.targetType.FullName}.{member.name}(Set)",
|
||||
Namespace = member.targetType.Namespace,
|
||||
};
|
||||
aid.Hashcode = aid.Identifier.GetHashCode();
|
||||
return aid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 768b8c19797414a6fbb77c9bfeb87c81
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b0d8ccc2f7184e87956a482fb08d49b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,48 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Counts all items in a collection or enumeration.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections")]
|
||||
public sealed class CountItems : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The collection.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput collection { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of items contained in the collection.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput count { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
collection = ValueInput<IEnumerable>(nameof(collection));
|
||||
count = ValueOutput(nameof(count), Count);
|
||||
|
||||
Requirement(collection, count);
|
||||
}
|
||||
|
||||
public int Count(Flow flow)
|
||||
{
|
||||
var enumerable = flow.GetValue<IEnumerable>(collection);
|
||||
|
||||
if (enumerable is ICollection)
|
||||
{
|
||||
return ((ICollection)enumerable).Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
return enumerable.Cast<object>().Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33c6a89291fe4454fb69c9af968b6830
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe09e9cdabae047b9a8e6d245eec4ade
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,86 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an item to a dictionary.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitSurtitle("Dictionary")]
|
||||
[UnitShortTitle("Add Item")]
|
||||
[UnitOrder(2)]
|
||||
public sealed class AddDictionaryItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Dictionary")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput dictionaryInput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary with the added element.
|
||||
/// Note that the input dictionary is modified directly then returned.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Dictionary")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput dictionaryOutput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the item to add.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the item to add.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput value { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the item has been added.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Add);
|
||||
dictionaryInput = ValueInput<IDictionary>(nameof(dictionaryInput));
|
||||
key = ValueInput<object>(nameof(key));
|
||||
value = ValueInput<object>(nameof(value));
|
||||
dictionaryOutput = ValueOutput<IDictionary>(nameof(dictionaryOutput));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(dictionaryInput, enter);
|
||||
Requirement(key, enter);
|
||||
Requirement(value, enter);
|
||||
Assignment(enter, dictionaryOutput);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
private ControlOutput Add(Flow flow)
|
||||
{
|
||||
var dictionary = flow.GetValue<IDictionary>(dictionaryInput);
|
||||
var key = flow.GetValue<object>(this.key);
|
||||
var value = flow.GetValue<object>(this.value);
|
||||
|
||||
flow.SetValue(dictionaryOutput, dictionary);
|
||||
|
||||
dictionary.Add(key, value);
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48a1eaea1e4c144ebbf84144dac05f94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,69 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears all items from a dictionary.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitSurtitle("Dictionary")]
|
||||
[UnitShortTitle("Clear")]
|
||||
[UnitOrder(4)]
|
||||
[TypeIcon(typeof(RemoveDictionaryItem))]
|
||||
public sealed class ClearDictionary : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Dictionary")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput dictionaryInput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cleared dictionary.
|
||||
/// Note that the input dictionary is modified directly and then returned.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Dictionary")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput dictionaryOutput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the dictionary has been cleared.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Clear);
|
||||
dictionaryInput = ValueInput<IDictionary>(nameof(dictionaryInput));
|
||||
dictionaryOutput = ValueOutput<IDictionary>(nameof(dictionaryOutput));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(dictionaryInput, enter);
|
||||
Assignment(enter, dictionaryOutput);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
private ControlOutput Clear(Flow flow)
|
||||
{
|
||||
var dictionary = flow.GetValue<IDictionary>(dictionaryInput);
|
||||
|
||||
flow.SetValue(dictionaryOutput, dictionary);
|
||||
|
||||
dictionary.Clear();
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6183a2ad03a8e4636a2dc5cd3b8b7a7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an empty dictionary.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitOrder(-1)]
|
||||
[TypeIcon(typeof(IDictionary))]
|
||||
[RenamedFrom("Bolt.CreateDitionary")]
|
||||
public sealed class CreateDictionary : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The new empty dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput dictionary { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
dictionary = ValueOutput(nameof(dictionary), Create);
|
||||
}
|
||||
|
||||
public IDictionary Create(Flow flow)
|
||||
{
|
||||
return new AotDictionary();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9426860637f5474eb0c52493cdd32d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks whether a dictionary contains the specified key.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitSurtitle("Dictionary")]
|
||||
[UnitShortTitle("Contains Key")]
|
||||
[TypeIcon(typeof(IDictionary))]
|
||||
public sealed class DictionaryContainsKey : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput dictionary { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the list contains the item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput contains { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
dictionary = ValueInput<IDictionary>(nameof(dictionary));
|
||||
key = ValueInput<object>(nameof(key));
|
||||
contains = ValueOutput(nameof(contains), Contains);
|
||||
|
||||
Requirement(dictionary, contains);
|
||||
Requirement(key, contains);
|
||||
}
|
||||
|
||||
private bool Contains(Flow flow)
|
||||
{
|
||||
var dictionary = flow.GetValue<IDictionary>(this.dictionary);
|
||||
var key = flow.GetValue<object>(this.key);
|
||||
|
||||
return dictionary.Contains(key);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5302f3f2f10ec4408b355b4a2898b3dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a dictionary item with the specified key.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitSurtitle("Dictionary")]
|
||||
[UnitShortTitle("Get Item")]
|
||||
[UnitOrder(0)]
|
||||
[TypeIcon(typeof(IDictionary))]
|
||||
public sealed class GetDictionaryItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput dictionary { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput value { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
dictionary = ValueInput<IDictionary>(nameof(dictionary));
|
||||
key = ValueInput<object>(nameof(key));
|
||||
value = ValueOutput(nameof(value), Get);
|
||||
|
||||
Requirement(dictionary, value);
|
||||
Requirement(key, value);
|
||||
}
|
||||
|
||||
private object Get(Flow flow)
|
||||
{
|
||||
var dictionary = flow.GetValue<IDictionary>(this.dictionary);
|
||||
var key = flow.GetValue<object>(this.key);
|
||||
|
||||
return dictionary[key];
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a8e3e47147a543cfbfa969532386942
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,57 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Merges two or more dictionaries together.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the same key is found more than once, only the value
|
||||
/// of the first dictionary with this key will be used.
|
||||
/// </remarks>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitOrder(5)]
|
||||
public sealed class MergeDictionaries : MultiInputUnit<IDictionary>
|
||||
{
|
||||
/// <summary>
|
||||
/// The merged dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput dictionary { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
dictionary = ValueOutput(nameof(dictionary), Merge);
|
||||
|
||||
base.Definition();
|
||||
|
||||
foreach (var input in multiInputs)
|
||||
{
|
||||
Requirement(input, dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary Merge(Flow flow)
|
||||
{
|
||||
var dictionary = new AotDictionary();
|
||||
|
||||
for (var i = 0; i < inputCount; i++)
|
||||
{
|
||||
var inputDictionary = flow.GetValue<IDictionary>(multiInputs[i]);
|
||||
|
||||
var enumerator = inputDictionary.GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
if (!dictionary.Contains(enumerator.Key))
|
||||
{
|
||||
dictionary.Add(enumerator.Key, enumerator.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a81c0890f86e544d8bd52f3fab082ca7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,77 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Removes a dictionary item with a specified key.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitSurtitle("Dictionary")]
|
||||
[UnitShortTitle("Remove Item")]
|
||||
[UnitOrder(3)]
|
||||
public sealed class RemoveDictionaryItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Dictionary")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput dictionaryInput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary without the removed item.
|
||||
/// Note that the input dictionary is modified directly and then returned.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Dictionary")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput dictionaryOutput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the item to remove.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the item has been removed.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Remove);
|
||||
dictionaryInput = ValueInput<IDictionary>(nameof(dictionaryInput));
|
||||
dictionaryOutput = ValueOutput<IDictionary>(nameof(dictionaryOutput));
|
||||
key = ValueInput<object>(nameof(key));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(dictionaryInput, enter);
|
||||
Requirement(key, enter);
|
||||
Assignment(enter, dictionaryOutput);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
public ControlOutput Remove(Flow flow)
|
||||
{
|
||||
var dictionary = flow.GetValue<IDictionary>(dictionaryInput);
|
||||
var key = flow.GetValue<object>(this.key);
|
||||
|
||||
flow.SetValue(dictionaryOutput, dictionary);
|
||||
|
||||
dictionary.Remove(key);
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4a7c13c64f25473ea761f6e55d8aeed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,73 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the value of a dictionary item with the specified key.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Dictionaries")]
|
||||
[UnitSurtitle("Dictionary")]
|
||||
[UnitShortTitle("Set Item")]
|
||||
[UnitOrder(1)]
|
||||
[TypeIcon(typeof(IDictionary))]
|
||||
public sealed class SetDictionaryItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput dictionary { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key of the item to set.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value to assign to the item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput value { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the item has been assigned.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Set);
|
||||
dictionary = ValueInput<IDictionary>(nameof(dictionary));
|
||||
key = ValueInput<object>(nameof(key));
|
||||
value = ValueInput<object>(nameof(value));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(dictionary, enter);
|
||||
Requirement(key, enter);
|
||||
Requirement(value, enter);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
public ControlOutput Set(Flow flow)
|
||||
{
|
||||
var dictionary = flow.GetValue<IDictionary>(this.dictionary);
|
||||
var key = flow.GetValue<object>(this.key);
|
||||
var value = flow.GetValue<object>(this.value);
|
||||
|
||||
dictionary[key] = value;
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2c6916dd07ed47b7b77ccd07eea9fbe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,48 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the first item in a collection or enumeration.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections")]
|
||||
public sealed class FirstItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The collection.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput collection { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first item of the collection.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput firstItem { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
collection = ValueInput<IEnumerable>(nameof(collection));
|
||||
firstItem = ValueOutput(nameof(firstItem), First);
|
||||
|
||||
Requirement(collection, firstItem);
|
||||
}
|
||||
|
||||
public object First(Flow flow)
|
||||
{
|
||||
var enumerable = flow.GetValue<IEnumerable>(collection);
|
||||
|
||||
if (enumerable is IList)
|
||||
{
|
||||
return ((IList)enumerable)[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return enumerable.Cast<object>().First();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd9a980a91f9b49fd88a6e484b27d51e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,50 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the first item in a collection or enumeration.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections")]
|
||||
public sealed class LastItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The collection.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput collection { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last item of the collection.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput lastItem { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
collection = ValueInput<IEnumerable>(nameof(collection));
|
||||
lastItem = ValueOutput(nameof(lastItem), First);
|
||||
|
||||
Requirement(collection, lastItem);
|
||||
}
|
||||
|
||||
public object First(Flow flow)
|
||||
{
|
||||
var enumerable = flow.GetValue<IEnumerable>(collection);
|
||||
|
||||
if (enumerable is IList)
|
||||
{
|
||||
var list = (IList)enumerable;
|
||||
|
||||
return list[list.Count - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return enumerable.Cast<object>().Last();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28353851bd6d5454b81b70b6720cd8f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 595933039dbdb4e7ca040caec13d06de
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an item to a list.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Lists")]
|
||||
[UnitSurtitle("List")]
|
||||
[UnitShortTitle("Add Item")]
|
||||
[UnitOrder(2)]
|
||||
public sealed class AddListItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("List")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput listInput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list with the added element.
|
||||
/// Note that the input list is modified directly and then returned,
|
||||
/// except if it is an array, in which case a new array with
|
||||
/// the added element is returned instead.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("List")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput listOutput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The item to add.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput item { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the item has been added.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Add);
|
||||
listInput = ValueInput<IList>(nameof(listInput));
|
||||
item = ValueInput<object>(nameof(item));
|
||||
listOutput = ValueOutput<IList>(nameof(listOutput));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(listInput, enter);
|
||||
Requirement(item, enter);
|
||||
Assignment(enter, listOutput);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
public ControlOutput Add(Flow flow)
|
||||
{
|
||||
var list = flow.GetValue<IList>(listInput);
|
||||
var item = flow.GetValue<object>(this.item);
|
||||
|
||||
if (list is Array)
|
||||
{
|
||||
var resizableList = new ArrayList(list);
|
||||
resizableList.Add(item);
|
||||
flow.SetValue(listOutput, resizableList.ToArray(list.GetType().GetElementType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(item);
|
||||
|
||||
flow.SetValue(listOutput, list);
|
||||
}
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56f45147e53b74230964d1066cb73f72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears all items from a list.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Lists")]
|
||||
[UnitSurtitle("List")]
|
||||
[UnitShortTitle("Clear")]
|
||||
[UnitOrder(6)]
|
||||
[TypeIcon(typeof(RemoveListItem))]
|
||||
public sealed class ClearList : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("List")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput listInput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cleared list.
|
||||
/// Note that the input list is modified directly and then returned,
|
||||
/// except if it is an array, in which case a new empty array
|
||||
/// is returned instead.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("List")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput listOutput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the list has been cleared.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Clear);
|
||||
listInput = ValueInput<IList>(nameof(listInput));
|
||||
listOutput = ValueOutput<IList>(nameof(listOutput));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(listInput, enter);
|
||||
Assignment(enter, listOutput);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
public ControlOutput Clear(Flow flow)
|
||||
{
|
||||
var list = flow.GetValue<IList>(listInput);
|
||||
|
||||
if (list is Array)
|
||||
{
|
||||
flow.SetValue(listOutput, Array.CreateInstance(list.GetType().GetElementType(), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Clear();
|
||||
|
||||
flow.SetValue(listOutput, list);
|
||||
}
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 573496a789db44e01b6f7798f8b3f1f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,58 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a list from a number of item inputs.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Lists")]
|
||||
[UnitOrder(-1)]
|
||||
[TypeIcon(typeof(IList))]
|
||||
public sealed class CreateList : MultiInputUnit<object>
|
||||
{
|
||||
[DoNotSerialize]
|
||||
protected override int minInputCount => 0;
|
||||
|
||||
[InspectorLabel("Elements")]
|
||||
[UnitHeaderInspectable("Elements")]
|
||||
[Inspectable]
|
||||
public override int inputCount
|
||||
{
|
||||
get => base.inputCount;
|
||||
set => base.inputCount = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The created list.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput list { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
list = ValueOutput(nameof(list), Create);
|
||||
|
||||
base.Definition();
|
||||
|
||||
foreach (var input in multiInputs)
|
||||
{
|
||||
Requirement(input, list);
|
||||
}
|
||||
|
||||
InputsAllowNull();
|
||||
}
|
||||
|
||||
public IList Create(Flow flow)
|
||||
{
|
||||
var list = new AotList();
|
||||
|
||||
for (var i = 0; i < inputCount; i++)
|
||||
{
|
||||
list.Add(flow.GetValue<object>(multiInputs[i]));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82c04fa1c09e14266bb9608173918eac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the item at the specified index of a list.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Lists")]
|
||||
[UnitSurtitle("List")]
|
||||
[UnitShortTitle("Get Item")]
|
||||
[UnitOrder(0)]
|
||||
[TypeIcon(typeof(IList))]
|
||||
public sealed class GetListItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The list.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput list { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The zero-based index.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput index { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput item { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
list = ValueInput<IList>(nameof(list));
|
||||
index = ValueInput(nameof(index), 0);
|
||||
item = ValueOutput(nameof(item), Get);
|
||||
|
||||
Requirement(list, item);
|
||||
Requirement(index, item);
|
||||
}
|
||||
|
||||
public object Get(Flow flow)
|
||||
{
|
||||
var list = flow.GetValue<IList>(this.list);
|
||||
var index = flow.GetValue<int>(this.index);
|
||||
|
||||
return list[index];
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b91e5dc5313d448996aa5a5ef3879f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Inserts an item in a list at a specified index.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Lists")]
|
||||
[UnitSurtitle("List")]
|
||||
[UnitShortTitle("Insert Item")]
|
||||
[UnitOrder(3)]
|
||||
[TypeIcon(typeof(AddListItem))]
|
||||
public sealed class InsertListItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The entry point for the node.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("List")]
|
||||
[PortLabelHidden]
|
||||
public ValueInput listInput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list with the added element.
|
||||
/// Note that the input list is modified directly and then returned,
|
||||
/// except if it is an array, in which case a new array with
|
||||
/// the added element is returned instead.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("List")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput listOutput { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The zero-based index at which to insert the item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput index { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The item to insert.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
public ValueInput item { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to execute once the item has been inserted.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput(nameof(enter), Insert);
|
||||
listInput = ValueInput<IList>(nameof(listInput));
|
||||
item = ValueInput<object>(nameof(item));
|
||||
index = ValueInput(nameof(index), 0);
|
||||
listOutput = ValueOutput<IList>(nameof(listOutput));
|
||||
exit = ControlOutput(nameof(exit));
|
||||
|
||||
Requirement(listInput, enter);
|
||||
Requirement(item, enter);
|
||||
Requirement(index, enter);
|
||||
Assignment(enter, listOutput);
|
||||
Succession(enter, exit);
|
||||
}
|
||||
|
||||
public ControlOutput Insert(Flow flow)
|
||||
{
|
||||
var list = flow.GetValue<IList>(listInput);
|
||||
var index = flow.GetValue<int>(this.index);
|
||||
var item = flow.GetValue<object>(this.item);
|
||||
|
||||
if (list is Array)
|
||||
{
|
||||
var resizableList = new ArrayList(list);
|
||||
resizableList.Insert(index, item);
|
||||
flow.SetValue(listOutput, resizableList.ToArray(list.GetType().GetElementType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Insert(index, item);
|
||||
flow.SetValue(listOutput, list);
|
||||
}
|
||||
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f20b6488154d04514b542bc7dfec85b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks whether a list contains the specified item.
|
||||
/// </summary>
|
||||
[UnitCategory("Collections/Lists")]
|
||||
[UnitSurtitle("List")]
|
||||
[UnitShortTitle("Contains Item")]
|
||||
[TypeIcon(typeof(IList))]
|
||||
public sealed class ListContainsItem : Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The list.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput list { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput item { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the list contains the item.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput contains { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
list = ValueInput<IList>(nameof(list));
|
||||
item = ValueInput<object>(nameof(item));
|
||||
contains = ValueOutput(nameof(contains), Contains);
|
||||
|
||||
Requirement(list, contains);
|
||||
Requirement(item, contains);
|
||||
}
|
||||
|
||||
public bool Contains(Flow flow)
|
||||
{
|
||||
var list = flow.GetValue<IList>(this.list);
|
||||
var item = flow.GetValue<object>(this.item);
|
||||
|
||||
return list.Contains(item);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34e2bfd106c0445af9b35a016b5ffd0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user