This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(CreateStruct))]
public class CreateStructDescriptor : UnitDescriptor<CreateStruct>
{
public CreateStructDescriptor(CreateStruct unit) : base(unit) { }
protected override string DefinedTitle()
{
if (BoltCore.Configuration.humanNaming)
{
return $"Create {unit.type.HumanName()}";
}
else
{
return $"new {unit.type.CSharpName()}";
}
}
protected override string DefinedShortTitle()
{
return BoltCore.Configuration.humanNaming ? "Create" : "new";
}
protected override string DefinedSurtitle()
{
return unit.type.DisplayName();
}
protected override string DefinedSummary()
{
return unit.type.Summary();
}
protected override EditorTexture DefinedIcon()
{
return unit.type.Icon();
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(CreateStruct))]
public class CreateStructOption : UnitOption<CreateStruct>
{
public CreateStructOption() : base() { }
public CreateStructOption(CreateStruct unit) : base(unit) { }
public Type structType { get; private set; }
protected override void FillFromUnit()
{
structType = unit.type;
base.FillFromUnit();
}
protected override string Label(bool human)
{
if (human)
{
return $"Create {structType.HumanName()} ()";
}
else
{
return $"new {structType.CSharpName()} ()";
}
}
protected override string Haystack(bool human)
{
if (human)
{
return $"{structType.HumanName()}: Create {structType.HumanName()}";
}
else
{
return $"new {structType.CSharpName()}";
}
}
public override string SearchResultLabel(string query)
{
return base.SearchResultLabel(query) + " ()";
}
protected override int Order()
{
return 0;
}
protected override string FavoriteKey()
{
return $"{structType.FullName}@create";
}
public override void Deserialize(UnitOptionRow row)
{
base.Deserialize(row);
structType = Codebase.DeserializeType(row.tag1);
}
public override UnitOptionRow Serialize()
{
var row = base.Serialize();
row.tag1 = Codebase.SerializeType(structType);
return row;
}
}
}

View File

@@ -0,0 +1,39 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(Expose))]
public class ExposeDescriptor : UnitDescriptor<Expose>
{
public ExposeDescriptor(Expose unit) : base(unit) { }
protected override string DefinedTitle()
{
return $"Expose {unit.type.DisplayName()}";
}
protected override string DefinedSurtitle()
{
return "Expose";
}
protected override string DefinedShortTitle()
{
return unit.type.DisplayName();
}
protected override EditorTexture DefinedIcon()
{
return unit.type.Icon();
}
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port is ValueOutput && unit.members.TryGetValue((ValueOutput)port, out Member member))
{
description.label = member.info.HumanName();
description.summary = member.info.Summary();
}
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(Expose))]
public class ExposeOption : UnitOption<Expose>
{
public ExposeOption() : base() { }
public ExposeOption(Expose unit) : base(unit)
{
sourceScriptGuids = UnitBase.GetScriptGuids(unit.type).ToHashSet();
}
public Type exposedType { get; private set; }
protected override string FavoriteKey()
{
return $"{exposedType.FullName}@expose";
}
protected override string Label(bool human)
{
return $"Expose {unit.type.SelectedName(human)}";
}
protected override bool ShowValueOutputsInFooter()
{
return false;
}
protected override void FillFromUnit()
{
exposedType = unit.type;
base.FillFromUnit();
}
public override void Deserialize(UnitOptionRow row)
{
base.Deserialize(row);
exposedType = Codebase.DeserializeType(row.tag1);
}
public override UnitOptionRow Serialize()
{
var row = base.Serialize();
row.tag1 = Codebase.SerializeType(exposedType);
return row;
}
}
}

View File

@@ -0,0 +1,20 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(GetMember))]
public class GetMemberDescriptor : MemberUnitDescriptor<GetMember>
{
public GetMemberDescriptor(GetMember unit) : base(unit) { }
protected override ActionDirection direction => ActionDirection.Get;
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port == unit.value)
{
description.summary = unit.member.info.Summary();
}
}
}
}

View File

@@ -0,0 +1,12 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(GetMember))]
public class GetMemberOption : MemberUnitOption<GetMember>
{
public GetMemberOption() : base() { }
public GetMemberOption(GetMember unit) : base(unit) { }
protected override ActionDirection direction => ActionDirection.Get;
}
}

View File

@@ -0,0 +1,77 @@
using System.Linq;
namespace Unity.VisualScripting
{
[Descriptor(typeof(InvokeMember))]
public class InvokeMemberDescriptor : MemberUnitDescriptor<InvokeMember>
{
public InvokeMemberDescriptor(InvokeMember unit) : base(unit) { }
protected override ActionDirection direction => ActionDirection.Any;
protected override string DefinedShortTitle()
{
if (member.isConstructor)
{
return BoltCore.Configuration.humanNaming ? "Create" : "new";
}
return base.DefinedShortTitle();
}
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
var documentation = member.info.Documentation();
if (port == unit.enter)
{
description.label = "Invoke";
description.summary = "The entry point to invoke the method.";
if (member.isGettable)
{
description.summary += " You can still get the return value without connecting this port.";
}
}
else if (port == unit.exit)
{
description.summary = "The action to call once the method has been invoked.";
}
else if (port == unit.result)
{
if (member.isGettable)
{
description.summary = documentation?.returns;
}
if (unit.supportsChaining && unit.chainable)
{
description.showLabel = true;
}
}
else if (port == unit.targetOutput)
{
if (member.isGettable)
{
description.showLabel = true;
}
}
else if (port is ValueInput && unit.inputParameters.ContainsValue((ValueInput)port))
{
var parameter = member.GetParameterInfos().Single(p => "%" + p.Name == port.key);
description.label = parameter.DisplayName();
description.summary = documentation?.ParameterSummary(parameter);
}
else if (port is ValueOutput && unit.outputParameters.ContainsValue((ValueOutput)port))
{
var parameter = member.GetParameterInfos().Single(p => "&" + p.Name == port.key);
description.label = parameter.DisplayName();
description.summary = documentation?.ParameterSummary(parameter);
}
}
}
}

View File

@@ -0,0 +1,34 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(InvokeMember))]
public class InvokeMemberOption : MemberUnitOption<InvokeMember>
{
public InvokeMemberOption() : base() { }
public InvokeMemberOption(InvokeMember unit) : base(unit) { }
protected override ActionDirection direction => ActionDirection.Any;
public override string SearchResultLabel(string query)
{
return base.SearchResultLabel(query) + $" ({unit.member.methodBase.DisplayParameterString(unit.member.targetType)})";
}
protected override string Label(bool human)
{
return base.Label(human) + $" ({unit.member.methodBase.SelectedParameterString(unit.member.targetType, human)})";
}
protected override string Haystack(bool human)
{
if (!human && member.isConstructor)
{
return base.Label(human);
}
else
{
return $"{targetType.SelectedName(human)}{(human ? ": " : ".")}{base.Label(human)}";
}
}
}
}

View File

@@ -0,0 +1,28 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(Literal))]
public class LiteralDescriptor : UnitDescriptor<Literal>
{
public LiteralDescriptor(Literal unit) : base(unit) { }
protected override string DefinedTitle()
{
return unit.type.DisplayName() + " Literal";
}
protected override string DefinedShortTitle()
{
return unit.type.DisplayName();
}
protected override string DefinedSummary()
{
return unit.type.Summary();
}
protected override EditorTexture DefinedIcon()
{
return unit.type.Icon();
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using UnityEngine;
namespace Unity.VisualScripting
{
[Inspector(typeof(Literal))]
public sealed class LiteralInspector : Inspector
{
public LiteralInspector(Metadata metadata) : base(metadata) { }
private Metadata typeMetadata => metadata[nameof(Literal.type)];
private Metadata valueMetadata => metadata[nameof(Literal.value)];
private Metadata typedValueMetadata => valueMetadata.Cast((Type)typeMetadata.value);
private bool hasType => typeMetadata.value != null;
protected override float GetHeight(float width, GUIContent label)
{
if (hasType)
{
return LudiqGUI.GetInspectorHeight(this, typedValueMetadata, width, label);
}
else
{
return LudiqGUI.GetInspectorHeight(this, typeMetadata, width, label);
}
}
protected override bool cacheHeight => false;
protected override void OnGUI(Rect position, GUIContent label)
{
if (hasType)
{
LudiqGUI.Inspector(typedValueMetadata, position, label);
}
else
{
LudiqGUI.Inspector(typeMetadata, position, label);
}
}
public override float GetAdaptiveWidth()
{
if (hasType)
{
return typedValueMetadata.Inspector().GetAdaptiveWidth();
}
else
{
return typeMetadata.Inspector().GetAdaptiveWidth();
}
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(Literal))]
public class LiteralOption : UnitOption<Literal>
{
public LiteralOption() : base() { }
public LiteralOption(Literal unit) : base(unit)
{
sourceScriptGuids = UnitBase.GetScriptGuids(unit.type).ToHashSet();
}
public Type literalType { get; private set; }
protected override void FillFromUnit()
{
literalType = unit.type;
base.FillFromUnit();
}
protected override string Label(bool human)
{
if (unit.value is UnityObject uo && !uo.IsUnityNull())
{
return UnityAPI.Await(() => uo.name);
}
return unit.type.SelectedName(human) + " Literal";
}
protected override EditorTexture Icon()
{
if (unit.value is UnityObject uo && !uo.IsUnityNull())
{
return uo.Icon();
}
return base.Icon();
}
protected override string FavoriteKey()
{
return $"{literalType.FullName}@literal";
}
public override void Deserialize(UnitOptionRow row)
{
base.Deserialize(row);
literalType = Codebase.DeserializeType(row.tag1);
}
public override UnitOptionRow Serialize()
{
var row = base.Serialize();
row.tag1 = Codebase.SerializeType(literalType);
return row;
}
}
}

View File

@@ -0,0 +1,56 @@
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
[Widget(typeof(Literal))]
public sealed class LiteralWidget : UnitWidget<Literal>
{
public LiteralWidget(FlowCanvas canvas, Literal unit) : base(canvas, unit) { }
protected override bool showHeaderAddon => unit.isDefined;
public override bool foregroundRequiresInput => true;
protected override float GetHeaderAddonWidth()
{
var adaptiveWidthAttribute = unit.type.GetAttribute<InspectorAdaptiveWidthAttribute>();
return Mathf.Min(metadata.Inspector().GetAdaptiveWidth(), adaptiveWidthAttribute?.width ?? Styles.maxSettingsWidth);
}
protected override float GetHeaderAddonHeight(float width)
{
return LudiqGUI.GetInspectorHeight(null, metadata, width, GUIContent.none);
}
public override void BeforeFrame()
{
base.BeforeFrame();
if (showHeaderAddon &&
GetHeaderAddonWidth() != headerAddonPosition.width ||
GetHeaderAddonHeight(headerAddonPosition.width) != headerAddonPosition.height)
{
Reposition();
}
}
protected override void DrawHeaderAddon()
{
using (LudiqGUIUtility.labelWidth.Override(75)) // For reflected inspectors / custom property drawers
using (Inspector.adaptiveWidth.Override(true))
{
EditorGUI.BeginChangeCheck();
LudiqGUI.Inspector(metadata, headerAddonPosition, GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
unit.EnsureDefined();
Reposition();
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting
{
[Analyser(typeof(MemberUnit))]
public class MemberUnitAnalyser : UnitAnalyser<MemberUnit>
{
public MemberUnitAnalyser(GraphReference reference, MemberUnit target) : base(reference, target) { }
protected override IEnumerable<Warning> Warnings()
{
foreach (var baseWarning in base.Warnings())
{
yield return baseWarning;
}
if (target.member != null && target.member.isReflected)
{
var obsoleteAttribute = target.member.info.GetAttribute<ObsoleteAttribute>();
if (obsoleteAttribute != null)
{
if (obsoleteAttribute.Message != null)
{
Debug.LogWarning($"\"{target.member.name}\" unit member is deprecated: {obsoleteAttribute.Message}");
yield return Warning.Caution("Deprecated: " + obsoleteAttribute.Message);
}
else
{
Debug.LogWarning($"\"{target.member.name}\" unit member is deprecated.");
yield return Warning.Caution($"Member {target.member.name} is deprecated.");
}
}
}
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Linq;
using Unity.VisualScripting.AssemblyQualifiedNameParser;
namespace Unity.VisualScripting
{
public abstract class MemberUnitDescriptor<TMemberUnit> : UnitDescriptor<TMemberUnit> where TMemberUnit : MemberUnit
{
protected MemberUnitDescriptor(TMemberUnit unit) : base(unit)
{
}
protected Member member => unit.member;
protected abstract ActionDirection direction { get; }
private string Name()
{
return unit.member.info.DisplayName(direction);
}
protected override string DefinedTitle()
{
return Name();
}
protected override string ErrorSurtitle(Exception exception)
{
if (member?.targetType != null)
{
return member.targetType.DisplayName();
}
else if (member?.targetTypeName != null)
{
try
{
var parsedName = new ParsedAssemblyQualifiedName(member.targetTypeName).TypeName.Split('.').Last();
if (BoltCore.Configuration.humanNaming)
{
return parsedName.Prettify();
}
else
{
return parsedName;
}
}
catch
{
return "Malformed Type Name";
}
}
else
{
return "Missing Type";
}
}
protected override string ErrorTitle(Exception exception)
{
if (!string.IsNullOrEmpty(member?.name))
{
if (BoltCore.Configuration.humanNaming)
{
return member.name.Prettify();
}
else
{
return member.name;
}
}
return base.ErrorTitle(exception);
}
protected override string DefinedShortTitle()
{
return Name();
}
protected override EditorTexture DefinedIcon()
{
return member.targetType.Icon();
}
protected override EditorTexture ErrorIcon(Exception exception)
{
if (member.targetType != null)
{
return member.targetType.Icon();
}
return base.ErrorIcon(exception);
}
protected override string DefinedSurtitle()
{
return member.targetType.DisplayName();
}
protected override string DefinedSummary()
{
return member.info.Summary();
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using UnityEngine;
namespace Unity.VisualScripting
{
public interface IMemberUnitOption : IUnitOption
{
Type targetType { get; }
Member member { get; }
Member pseudoDeclarer { get; }
}
public abstract class MemberUnitOption<TMemberUnit> : UnitOption<TMemberUnit>, IMemberUnitOption where TMemberUnit : MemberUnit
{
protected MemberUnitOption() : base() { }
protected MemberUnitOption(TMemberUnit unit) : base(unit)
{
sourceScriptGuids = UnitBase.GetScriptGuids(unit.member.targetType).ToHashSet();
}
private Member _member;
private Member _pseudoDeclarer;
public Member member
{
get => _member ?? unit.member;
set => _member = value;
}
public Member pseudoDeclarer
{
get => _pseudoDeclarer ?? member.ToPseudoDeclarer();
set => _pseudoDeclarer = value;
}
public bool isPseudoInherited => member == pseudoDeclarer;
protected abstract ActionDirection direction { get; }
public Type targetType { get; private set; }
protected override GUIStyle Style()
{
if (unit.member.isPseudoInherited)
{
return FuzzyWindow.Styles.optionWithIconDim;
}
return base.Style();
}
protected override string Label(bool human)
{
return unit.member.info.SelectedName(human, direction);
}
protected override string FavoriteKey()
{
return $"{member.ToUniqueString()}@{direction.ToString().ToLower()}";
}
protected override int Order()
{
if (member.isConstructor)
{
return 0;
}
return base.Order();
}
protected override string Haystack(bool human)
{
return $"{targetType.SelectedName(human)}{(human ? ": " : ".")}{Label(human)}";
}
protected override void FillFromUnit()
{
targetType = unit.member.targetType;
member = unit.member;
pseudoDeclarer = member.ToPseudoDeclarer();
base.FillFromUnit();
}
public override void Deserialize(UnitOptionRow row)
{
base.Deserialize(row);
targetType = Codebase.DeserializeType(row.tag1);
if (!string.IsNullOrEmpty(row.tag2))
{
member = Codebase.DeserializeMember(row.tag2);
}
if (!string.IsNullOrEmpty(row.tag3))
{
pseudoDeclarer = Codebase.DeserializeMember(row.tag3);
}
}
public override UnitOptionRow Serialize()
{
var row = base.Serialize();
row.tag1 = Codebase.SerializeType(targetType);
row.tag2 = Codebase.SerializeMember(member);
row.tag3 = Codebase.SerializeMember(pseudoDeclarer);
return row;
}
public override void OnPopulate()
{
// Members are late-reflected to speed up loading and search
// We only reflect them when we're just about to populate their node
// By doing it in OnPopulate instead of on-demand later, we ensure
// any error will be gracefully catched and shown as a warning by
// the fuzzy window
member.EnsureReflected();
pseudoDeclarer.EnsureReflected();
base.OnPopulate();
}
}
}

View File

@@ -0,0 +1,31 @@
#if PACKAGE_INPUT_SYSTEM_EXISTS
using System.Collections.Generic;
using Unity.VisualScripting.InputSystem;
using UnityEngine.InputSystem;
namespace Unity.VisualScripting
{
[Analyser(typeof(OnInputSystemEvent))]
public class OnInputSystemEventAnalyser : UnitAnalyser<OnInputSystemEvent>
{
public OnInputSystemEventAnalyser(GraphReference reference, OnInputSystemEvent target) : base(reference, target) {}
protected override IEnumerable<Warning> Warnings()
{
foreach (var baseWarning in base.Warnings())
yield return baseWarning;
if (target.InputActionChangeType == InputActionChangeOption.OnHold ||
target.InputActionChangeType == InputActionChangeOption.OnReleased)
{
if (Flow.CanPredict(target.InputAction, reference))
{
var inputAction = Flow.Predict<InputAction>(target.InputAction, reference);
if (inputAction.type == InputActionType.PassThrough)
yield return Warning.Caution($"Input action '{inputAction.name}' is of type 'Passthrough', which do not support 'On Hold' or 'On Released' events");
}
}
}
}
}
#endif

View File

@@ -0,0 +1,30 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SetMember))]
public class SetMemberDescriptor : MemberUnitDescriptor<SetMember>
{
public SetMemberDescriptor(SetMember unit) : base(unit) { }
protected override ActionDirection direction => ActionDirection.Set;
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port == unit.assign)
{
description.label = "Set";
description.summary = "The entry point to set the value.";
}
else if (port == unit.assigned)
{
description.label = "On Set";
description.summary = "The action to call once the value has been set.";
}
else if (port == unit.output)
{
description.summary = unit.member.info.Summary();
}
}
}
}

View File

@@ -0,0 +1,17 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(SetMember))]
public class SetMemberOption : MemberUnitOption<SetMember>
{
public SetMemberOption() : base() { }
public SetMemberOption(SetMember unit) : base(unit) { }
protected override ActionDirection direction => ActionDirection.Set;
protected override bool ShowValueOutputsInFooter()
{
return false;
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting
{
[Analyser(typeof(For))]
public class ForAnalyser : UnitAnalyser<For>
{
public ForAnalyser(GraphReference reference, For target)
: base(reference, target) { }
protected override IEnumerable<Warning> Warnings()
{
foreach (var baseWarning in base.Warnings())
{
yield return baseWarning;
}
if (unit.IsStepValueZero())
{
yield return Warning.Caution("The step value is 0. This will prevent the For unit to be executed or can cause an infinite loop.");
}
}
}
}

View File

@@ -0,0 +1,19 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(ForEach))]
public class ForEachDescriptor : UnitDescriptor<ForEach>
{
public ForEachDescriptor(ForEach unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (unit.dictionary && port == unit.currentItem)
{
description.label = "Value";
description.summary = "The value of the current item of the loop.";
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
namespace Unity.VisualScripting
{
[Descriptor(typeof(SelectOnEnum))]
public class SelectOnEnumDescriptor : UnitDescriptor<SelectOnEnum>
{
public SelectOnEnumDescriptor(SelectOnEnum unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
foreach (var branch in unit.branches)
{
if (branch.Value == port)
{
var enumValue = (Enum)branch.Key;
description.label = enumValue.DisplayName();
description.summary = $"The value to return if the enum has the value '{enumValue}'.";
}
}
}
}
}

View File

@@ -0,0 +1,34 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SelectOnFlow))]
public class SelectOnFlowDescriptor : UnitDescriptor<SelectOnFlow>
{
public SelectOnFlowDescriptor(SelectOnFlow unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
foreach (var branch in unit.branches)
{
if (port == branch.Key || port == branch.Value)
{
var index = int.Parse(port.key.PartAfter('_'));
var letter = ((char)('A' + index)).ToString();
description.label = letter;
if (port == branch.Key)
{
description.summary = $"Trigger to select the {letter} value.";
}
else if (port == branch.Value)
{
description.summary = $"The value to return if the {letter} control input is triggered.";
}
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SelectOnInteger))]
public class SelectOnIntegerDescriptor : SelectUnitDescriptor<int>
{
public SelectOnIntegerDescriptor(SelectOnInteger unit) : base(unit) { }
protected override string GetLabelForOption(int option)
{
return option.ToString();
}
}
}

View File

@@ -0,0 +1,18 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SelectOnString))]
public class SelectOnStringDescriptor : SelectUnitDescriptor<string>
{
public SelectOnStringDescriptor(SelectOnString unit) : base(unit) { }
protected override string GetLabelForOption(string option)
{
if (string.IsNullOrEmpty(option))
{
return "Null / Empty";
}
return $"\"{option}\"";
}
}
}

View File

@@ -0,0 +1,28 @@
namespace Unity.VisualScripting
{
public class SelectUnitDescriptor<T> : UnitDescriptor<SelectUnit<T>>
{
public SelectUnitDescriptor(SelectUnit<T> unit) : base(unit) { }
protected virtual string GetLabelForOption(T option)
{
return option.ToString();
}
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
foreach (var branch in unit.branches)
{
if (branch.Value == port)
{
var option = branch.Key;
description.label = GetLabelForOption(option);
description.summary = $"The value to return if the enum has the value {GetLabelForOption(option)}.";
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(Sequence))]
public class SequenceDescriptor : UnitDescriptor<Sequence>
{
public SequenceDescriptor(Sequence unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port is ControlOutput)
{
var index = unit.multiOutputs.IndexOf((ControlOutput)port);
if (index >= 0)
{
description.label = index.ToString();
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SwitchOnEnum))]
public class SwitchOnEnumDescriptor : UnitDescriptor<SwitchOnEnum>
{
public SwitchOnEnumDescriptor(SwitchOnEnum unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
foreach (var branch in unit.branches)
{
if (branch.Value == port)
{
var enumValue = branch.Key;
description.label = enumValue.DisplayName();
description.summary = $"The action to execute if the enum has the value '{enumValue}'.";
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SwitchOnInteger))]
public class SwitchOnIntegerDescriptor : SwitchUnitDescriptor<int>
{
public SwitchOnIntegerDescriptor(SwitchOnInteger unit) : base(unit) { }
protected override string GetLabelForOption(int option)
{
return option.ToString();
}
}
}

View File

@@ -0,0 +1,18 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(SwitchOnString))]
public class SwitchOnStringDescriptor : SwitchUnitDescriptor<string>
{
public SwitchOnStringDescriptor(SwitchOnString unit) : base(unit) { }
protected override string GetLabelForOption(string option)
{
if (string.IsNullOrEmpty(option))
{
return "Null / Empty";
}
return $"\"{option}\"";
}
}
}

View File

@@ -0,0 +1,28 @@
namespace Unity.VisualScripting
{
public class SwitchUnitDescriptor<T> : UnitDescriptor<SwitchUnit<T>>
{
public SwitchUnitDescriptor(SwitchUnit<T> unit) : base(unit) { }
protected virtual string GetLabelForOption(T option)
{
return option.ToString();
}
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
foreach (var branch in unit.branches)
{
if (branch.Value == port)
{
var option = branch.Key;
description.label = GetLabelForOption(option);
description.summary = $"The action to execute if the selector has the value {GetLabelForOption(option)}.";
}
}
}
}
}

View File

@@ -0,0 +1,109 @@
#if PACKAGE_INPUT_SYSTEM_EXISTS
using System.Linq;
using JetBrains.Annotations;
using Unity.VisualScripting.FullSerializer;
using Unity.VisualScripting.InputSystem;
using UnityEditor;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Unity.VisualScripting
{
[Inspector(typeof(InputAction))]
public class InputActionInspector : Inspector
{
private readonly GraphReference m_Reference;
private readonly OnInputSystemEvent m_InputSystemUnit;
public InputActionInspector(Metadata metadata, GraphReference reference, OnInputSystemEvent inputSystemUnit) : base(metadata)
{
m_Reference = reference;
m_InputSystemUnit = inputSystemUnit;
}
// Called by reflection from TypeUtility.Instantiate
[UsedImplicitly]
public InputActionInspector(Metadata metadata) : base(metadata)
{
}
protected override float GetHeight(float width, GUIContent label) => EditorGUIUtility.singleLineHeight;
public override float GetAdaptiveWidth()
{
return Mathf.Max(100, metadata.value is InputAction action && action.name != null
? (EditorStyles.popup.CalcSize(new GUIContent(action.name)).x + 1)
: 0);
}
protected override void OnGUI(Rect position, GUIContent label)
{
position = BeginLabeledBlock(metadata, position, label);
var togglePosition = position.VerticalSection(ref y, EditorGUIUtility.singleLineHeight);
if (m_InputSystemUnit == null)
{
EndBlock(metadata);
return;
}
var inputActionAsset = Flow.Predict<PlayerInput>(m_InputSystemUnit.Target, m_Reference)?.actions;
if (!inputActionAsset)
EditorGUI.LabelField(togglePosition, "No Actions found");
else
{
var value = metadata.value is InputAction ? (InputAction)metadata.value : default;
int currentIndex = -1;
if (value != null && value.id != default)
{
int i = 0;
foreach (var playerInputAction in inputActionAsset)
{
if (playerInputAction.id == value.id)
{
currentIndex = i;
break;
}
i++;
}
}
var displayedOptions = Enumerable.Repeat(new GUIContent("<None>"), 1).Concat(inputActionAsset.Select(a => new GUIContent(a.name))).ToArray();
var newIndex = EditorGUI.Popup(togglePosition, currentIndex + 1, displayedOptions);
if (EndBlock(metadata) || ActionTypeHasChanged(currentIndex, value))
{
metadata.RecordUndo();
if (newIndex == 0)
metadata.value = default;
else
{
var inputAction = inputActionAsset.ElementAt(newIndex - 1);
metadata.value =
InputAction_DirectConverter.MakeInputActionWithId(inputAction.id.ToString(),
inputAction.name, inputAction.expectedControlType, inputAction.type);
m_InputSystemUnit.Analyser(m_Reference).isDirty = true;
}
}
return;
}
EndBlock(metadata);
bool ActionTypeHasChanged(int currentIndex, InputAction value)
{
try
{
// getting the total action count would be expensive, as it would need to be computed everytime
return value?.type != inputActionAsset.ElementAt(currentIndex)?.type;
}
catch
{
return true;
}
}
}
}
}
#endif

View File

@@ -0,0 +1,52 @@
#if PACKAGE_INPUT_SYSTEM_EXISTS
using System;
using JetBrains.Annotations;
using Unity.VisualScripting.InputSystem;
namespace Unity.VisualScripting
{
[Widget(typeof(OnInputSystemEvent)), UsedImplicitly]
public class InputSystemWidget : UnitWidget<OnInputSystemEvent>
{
public InputSystemWidget(FlowCanvas canvas, OnInputSystemEvent unit) : base(canvas, unit)
{
inputActionInspectorConstructor = metadata => new InputActionInspector(metadata, reference, unit);
}
protected override NodeColorMix baseColor => NodeColor.Green;
private InputActionInspector nameInspector;
private Func<Metadata, InputActionInspector> inputActionInspectorConstructor;
public override Inspector GetPortInspector(IUnitPort port, Metadata metadata)
{
if (port == unit.InputAction)
{
InspectorProvider.instance.Renew(ref nameInspector, metadata, inputActionInspectorConstructor);
return nameInspector;
}
return base.GetPortInspector(port, metadata);
}
}
[Descriptor(typeof(OnInputSystemEvent)), UsedImplicitly]
public class OnInputSystemButtonDescriptor : UnitDescriptor<OnInputSystemEvent>
{
public OnInputSystemButtonDescriptor(OnInputSystemEvent unit) : base(unit) {}
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port == unit.Target)
description.summary =
"A player input component used to list available actions and find the referenced InputAction";
if (port == unit.InputAction)
description.summary =
"An input action, either from the linked player input component or directly connected";
}
}
}
#endif

View File

@@ -0,0 +1,46 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(Minimum<>))]
[Descriptor(typeof(Maximum<>))]
[Descriptor(typeof(Sum<>))]
[Descriptor(typeof(Average<>))]
[Descriptor(typeof(MergeDictionaries))]
[Descriptor(typeof(Formula))]
public class MultiInputUnitAlphabeticDescriptor : UnitDescriptor<IMultiInputUnit>
{
public MultiInputUnitAlphabeticDescriptor(IMultiInputUnit unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port is ValueInput)
{
var index = unit.multiInputs.IndexOf((ValueInput)port);
if (index >= 0)
{
description.label = ((char)('A' + index)).ToString();
}
}
}
}
[FuzzyOption(typeof(Minimum<>))]
[FuzzyOption(typeof(Maximum<>))]
[FuzzyOption(typeof(Sum<>))]
[FuzzyOption(typeof(Average<>))]
[FuzzyOption(typeof(MergeDictionaries))]
[FuzzyOption(typeof(Formula))]
public class MultiInputUnitAlphabeticOption : UnitOption<IMultiInputUnit>
{
public MultiInputUnitAlphabeticOption() : base() { }
public MultiInputUnitAlphabeticOption(IMultiInputUnit unit) : base(unit) { }
protected override bool ShowValueInputsInFooter()
{
return false;
}
}
}

View File

@@ -0,0 +1,38 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(CreateList))]
[Descriptor(typeof(MergeLists))]
public class MultiInputUnitNumericDescriptor : UnitDescriptor<IMultiInputUnit>
{
public MultiInputUnitNumericDescriptor(IMultiInputUnit unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port is ValueInput)
{
var index = unit.multiInputs.IndexOf((ValueInput)port);
if (index >= 0)
{
description.label = index.ToString();
}
}
}
}
[FuzzyOption(typeof(CreateList))]
[FuzzyOption(typeof(MergeLists))]
public class MultiInputUnitNumericOption : UnitOption<IMultiInputUnit>
{
public MultiInputUnitNumericOption() : base() { }
public MultiInputUnitNumericOption(IMultiInputUnit unit) : base(unit) { }
protected override bool ShowValueInputsInFooter()
{
return false;
}
}
}

View File

@@ -0,0 +1,40 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Unity.VisualScripting
{
[Analyser(typeof(GraphInput))]
public class GraphInputAnalyser : UnitAnalyser<GraphInput>
{
public GraphInputAnalyser(GraphReference reference, GraphInput unit) : base(reference, unit) { }
protected override IEnumerable<Warning> Warnings()
{
foreach (var baseWarning in base.Warnings())
{
yield return baseWarning;
}
if (unit.graph != null)
{
foreach (var definitionWarning in UnitPortDefinitionUtility.Warnings(unit.graph, LinqUtility.Concat<IUnitPortDefinition>(unit.graph.controlInputDefinitions, unit.graph.valueInputDefinitions)))
{
yield return definitionWarning;
}
var inputs = unit.graph.units.Where(u => u is GraphInput).ToList();
if (inputs.Count > 1)
{
var firstInput = inputs[0];
if (unit != firstInput)
{
var graphName = string.IsNullOrEmpty(unit.graph.title) ? nameof(SuperUnit) : unit.graph.title;
Debug.LogWarning($"Only one Input node can be used and will execute in {graphName}.");
yield return Warning.Caution("Only one Input node can be used and will execute.");
}
}
}
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Linq;
namespace Unity.VisualScripting
{
[Descriptor(typeof(GraphInput))]
public class GraphInputDescriptor : UnitDescriptor<GraphInput>
{
public GraphInputDescriptor(GraphInput unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
var definition = unit.graph.validPortDefinitions.OfType<IUnitInputPortDefinition>().SingleOrDefault(d => d.key == port.key);
if (definition != null)
{
description.label = definition.Label();
description.summary = definition.summary;
if (definition.hideLabel)
{
description.showLabel = false;
}
}
}
}
}

View File

@@ -0,0 +1,64 @@
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
[Inspector(typeof(GraphInput))]
public class GraphInputInspector : Inspector
{
public GraphInputInspector(Metadata metadata) : base(metadata) { }
private Metadata graphMetadata => metadata[nameof(GraphInput.graph)];
private Metadata controlInputDefinitionsMetadata => graphMetadata[nameof(FlowGraph.controlInputDefinitions)];
private Metadata valueInputDefinitionsMetadata => graphMetadata[nameof(FlowGraph.valueInputDefinitions)];
protected override float GetHeight(float width, GUIContent label)
{
var height = 0f;
if (graphMetadata.value != null)
{
height += GetControlInputDefinitionsHeight(width);
height += EditorGUIUtility.standardVerticalSpacing;
height += GetValueInputDefinitionsHeight(width);
}
return height;
}
protected override void OnGUI(Rect position, GUIContent label)
{
BeginLabeledBlock(metadata, position, label);
if (graphMetadata.value != null)
{
EditorGUI.BeginChangeCheck();
LudiqGUI.Inspector(controlInputDefinitionsMetadata, position.VerticalSection(ref y, GetControlInputDefinitionsHeight(position.width)));
y += EditorGUIUtility.standardVerticalSpacing;
LudiqGUI.Inspector(valueInputDefinitionsMetadata, position.VerticalSection(ref y, GetValueInputDefinitionsHeight(position.width)));
if (EditorGUI.EndChangeCheck())
{
((FlowGraph)graphMetadata.value).PortDefinitionsChanged();
}
}
EndBlock(metadata);
}
private float GetControlInputDefinitionsHeight(float width)
{
return LudiqGUI.GetInspectorHeight(this, controlInputDefinitionsMetadata, width);
}
private float GetValueInputDefinitionsHeight(float width)
{
return LudiqGUI.GetInspectorHeight(this, valueInputDefinitionsMetadata, width);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Unity.VisualScripting
{
[Widget(typeof(GraphInput))]
public sealed class GraphInputWidget : UnitWidget<GraphInput>
{
public GraphInputWidget(FlowCanvas canvas, GraphInput unit) : base(canvas, unit) { }
protected override NodeColorMix baseColor => NodeColorMix.TealReadable;
}
}

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;
namespace Unity.VisualScripting
{
[Analyser(typeof(GraphOutput))]
public class GraphOutputAnalyser : UnitAnalyser<GraphOutput>
{
public GraphOutputAnalyser(GraphReference reference, GraphOutput unit) : base(reference, unit) { }
protected override IEnumerable<Warning> Warnings()
{
foreach (var baseWarning in base.Warnings())
{
yield return baseWarning;
}
if (unit.graph != null)
{
foreach (var definitionWarning in UnitPortDefinitionUtility.Warnings(unit.graph, LinqUtility.Concat<IUnitPortDefinition>(unit.graph.controlOutputDefinitions, unit.graph.valueOutputDefinitions)))
{
yield return definitionWarning;
}
if (unit.graph.units.Count(unit => unit is GraphOutput) > 1)
{
yield return Warning.Caution("Multiple output units in the same graph. Only one of them will be used.");
}
}
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Linq;
namespace Unity.VisualScripting
{
[Descriptor(typeof(GraphOutput))]
public class GraphOutputDescriptor : UnitDescriptor<GraphOutput>
{
public GraphOutputDescriptor(GraphOutput unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
var definition = unit.graph.validPortDefinitions.OfType<IUnitOutputPortDefinition>().SingleOrDefault(d => d.key == port.key);
if (definition != null)
{
description.label = definition.Label();
description.summary = definition.summary;
if (definition.hideLabel)
{
description.showLabel = false;
}
}
}
}
}

View File

@@ -0,0 +1,64 @@
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
[Inspector(typeof(GraphOutput))]
public class GraphOutputInspector : Inspector
{
public GraphOutputInspector(Metadata metadata) : base(metadata) { }
private Metadata graphMetadata => metadata[nameof(GraphOutput.graph)];
private Metadata controlOutputDefinitionsMetadata => graphMetadata[nameof(FlowGraph.controlOutputDefinitions)];
private Metadata valueOutputDefinitionsMetadata => graphMetadata[nameof(FlowGraph.valueOutputDefinitions)];
protected override float GetHeight(float width, GUIContent label)
{
var height = 0f;
if (graphMetadata.value != null)
{
height += GetControlOutputDefinitionsHeight(width);
height += EditorGUIUtility.standardVerticalSpacing;
height += GetValueOutputDefinitionsHeight(width);
}
return height;
}
protected override void OnGUI(Rect position, GUIContent label)
{
BeginLabeledBlock(metadata, position, label);
if (graphMetadata.value != null)
{
EditorGUI.BeginChangeCheck();
LudiqGUI.Inspector(controlOutputDefinitionsMetadata, position.VerticalSection(ref y, GetControlOutputDefinitionsHeight(position.width)));
y += EditorGUIUtility.standardVerticalSpacing;
LudiqGUI.Inspector(valueOutputDefinitionsMetadata, position.VerticalSection(ref y, GetValueOutputDefinitionsHeight(position.width)));
if (EditorGUI.EndChangeCheck())
{
((FlowGraph)graphMetadata.value).PortDefinitionsChanged();
}
}
EndBlock(metadata);
}
private float GetControlOutputDefinitionsHeight(float width)
{
return LudiqGUI.GetInspectorHeight(this, controlOutputDefinitionsMetadata, width);
}
private float GetValueOutputDefinitionsHeight(float width)
{
return LudiqGUI.GetInspectorHeight(this, valueOutputDefinitionsMetadata, width);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Unity.VisualScripting
{
[Widget(typeof(GraphOutput))]
public sealed class GraphOutputWidget : UnitWidget<GraphOutput>
{
public GraphOutputWidget(FlowCanvas canvas, GraphOutput unit) : base(canvas, unit) { }
protected override NodeColorMix baseColor => NodeColorMix.TealReadable;
}
}

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
[Analyser(typeof(INesterUnit))]
public class NesterUnitAnalyser<TNesterUnit> : UnitAnalyser<TNesterUnit> where TNesterUnit : class, INesterUnit
{
public NesterUnitAnalyser(GraphReference reference, TNesterUnit unit) : base(reference, unit) { }
protected override IEnumerable<Warning> Warnings()
{
foreach (var baseWarning in base.Warnings())
{
yield return baseWarning;
}
if (unit.childGraph == null)
{
yield return Warning.Caution("Missing nested graph.");
}
if (unit.nest.hasBackgroundEmbed)
{
yield return Warning.Caution("Background embed graph detected.");
}
}
}
}

View File

@@ -0,0 +1,44 @@
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
[Descriptor(typeof(INesterUnit))]
public class NesterUnitDescriptor<TNesterUnit> : UnitDescriptor<TNesterUnit> where TNesterUnit : class, INesterUnit
{
public NesterUnitDescriptor(TNesterUnit unit) : base(unit) { }
[RequiresUnityAPI]
protected override string DefinedTitle()
{
return GraphNesterDescriptor.Title(unit);
}
[RequiresUnityAPI]
protected override string DefinedSummary()
{
return GraphNesterDescriptor.Summary(unit);
}
[RequiresUnityAPI]
protected override string DefinedShortTitle()
{
return DefinedTitle();
}
[RequiresUnityAPI]
protected override string DefinedSurtitle()
{
var hasCurrentTitle = !StringUtility.IsNullOrWhiteSpace(unit.nest.graph?.title);
var hasMacroTitle = unit.nest.source == GraphSource.Macro && (UnityObject)unit.nest.macro != null;
if (hasCurrentTitle || hasMacroTitle)
{
return unit.GetType().HumanName();
}
else
{
return null;
}
}
}
}

View File

@@ -0,0 +1,30 @@
using UnityEngine;
namespace Unity.VisualScripting
{
[Editor(typeof(INesterUnit))]
public class NesterUnitEditor : UnitEditor
{
public NesterUnitEditor(Metadata metadata) : base(metadata) { }
private Metadata nestMetadata => metadata[nameof(INesterUnit.nest)];
private Metadata graphMetadata => nestMetadata[nameof(IGraphNest.graph)];
protected override GraphReference headerReference => reference.ChildReference((INesterUnit)metadata.value, false);
protected override Metadata headerTitleMetadata => graphMetadata[nameof(IGraph.title)];
protected override Metadata headerSummaryMetadata => graphMetadata[nameof(IGraph.summary)];
protected override float GetInspectorHeight(float width)
{
return LudiqGUI.GetEditorHeight(this, nestMetadata, width);
}
protected override void OnInspectorGUI(Rect position)
{
LudiqGUI.Editor(nestMetadata, position);
}
}
}

View File

@@ -0,0 +1,32 @@
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(INesterUnit))]
public class NesterUnitOption<TNesterUnit> : UnitOption<TNesterUnit> where TNesterUnit : INesterUnit
{
public NesterUnitOption() : base() { }
public NesterUnitOption(TNesterUnit unit) : base(unit) { }
// TODO: Favoritable
public override bool favoritable => false;
protected override string Label(bool human)
{
return UnityAPI.Await(() =>
{
var macro = (UnityObject)unit.nest.macro;
if (macro != null)
{
return macro.name;
}
else
{
return unit.GetType().HumanName();
}
});
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public class NestrerUnitWidget<TNesterUnit> : UnitWidget<TNesterUnit>
where TNesterUnit : class, INesterUnit
{
public NestrerUnitWidget(FlowCanvas canvas, TNesterUnit unit) : base(canvas, unit) { }
protected override IEnumerable<DropdownOption> contextOptions
{
get
{
var childReference = reference.ChildReference(unit, false);
if (childReference != null)
{
yield return new DropdownOption((Action)(() => window.reference = childReference), "Open");
yield return new DropdownOption((Action)(() => GraphWindow.OpenTab(childReference)), "Open in new window");
}
foreach (var baseOption in base.contextOptions)
{
yield return baseOption;
}
}
}
protected override void OnDoubleClick()
{
if (unit.graph.zoom == 1)
{
var childReference = reference.ChildReference(unit, false);
if (childReference != null)
{
if (e.ctrlOrCmd)
{
GraphWindow.OpenTab(childReference);
}
else
{
window.reference = childReference;
}
}
e.Use();
}
else
{
base.OnDoubleClick();
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Linq;
namespace Unity.VisualScripting
{
[Descriptor(typeof(SuperUnit))]
public class SuperUnitDescriptor : NesterUnitDescriptor<SuperUnit>
{
public SuperUnitDescriptor(SuperUnit unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (unit.graph == null)
{
return;
}
var definition = unit.nest.graph.validPortDefinitions.SingleOrDefault(d => d.key == port.key);
if (definition != null)
{
description.label = definition.Label();
description.summary = definition.summary;
if (definition.hideLabel)
{
description.showLabel = false;
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Unity.VisualScripting
{
[Editor(typeof(SuperUnit))]
public sealed class SuperUnitEditor : NesterUnitEditor
{
public SuperUnitEditor(Metadata metadata) : base(metadata) { }
}
}

View File

@@ -0,0 +1,59 @@
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
[Widget(typeof(SuperUnit))]
public class SuperUnitWidget : NestrerUnitWidget<SuperUnit>, IDragAndDropHandler
{
public SuperUnitWidget(FlowCanvas canvas, SuperUnit unit) : base(canvas, unit) { }
protected override NodeColorMix baseColor
{
get
{
// TODO: Move to descriptor for optimization
using (var recursion = Recursion.New(1))
{
if (unit.nest.graph?.GetUnitsRecursive(recursion).OfType<IEventUnit>().Any() ?? false)
{
return NodeColor.Green;
}
}
return base.baseColor;
}
}
public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic;
public bool AcceptsDragAndDrop()
{
return DragAndDropUtility.Is<ScriptGraphAsset>() && FlowDragAndDropUtility.AcceptsScript(graph);
}
public void PerformDragAndDrop()
{
UndoUtility.RecordEditedObject("Drag & Drop Macro");
unit.nest.source = GraphSource.Macro;
unit.nest.macro = DragAndDropUtility.Get<ScriptGraphAsset>();
unit.nest.embed = null;
unit.Define();
GUI.changed = true;
}
public void UpdateDragAndDrop()
{
}
public void DrawDragAndDropPreview()
{
GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon());
}
public void ExitDragAndDrop()
{
}
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Linq;
namespace Unity.VisualScripting
{
public static class UnitPortDefinitionUtility
{
public static string Label(this IUnitPortDefinition definition)
{
return StringUtility.FallbackWhitespace(definition.label, definition.key?.Filter(symbols: false, punctuation: false).Prettify() ?? "?");
}
public static IEnumerable<Warning> Warnings(FlowGraph graph, IEnumerable<IUnitPortDefinition> definitions = null)
{
if (definitions == null)
{
definitions = LinqUtility.Concat<IUnitPortDefinition>(graph.controlInputDefinitions,
graph.controlOutputDefinitions,
graph.valueInputDefinitions,
graph.valueOutputDefinitions);
}
var hasDuplicate = definitions.DistinctBy(d => d.key).Count() != definitions.Count();
if (hasDuplicate)
{
yield return Warning.Caution("Some port definitions with non-unique keys are currently ignored.");
}
foreach (var definition in definitions)
{
if (!definition.isValid)
{
yield return InvalidWarning(definition);
}
}
}
public static Warning InvalidWarning(IUnitPortDefinition definition)
{
if (!StringUtility.IsNullOrWhiteSpace(definition.label))
{
return Warning.Caution($"{definition.GetType().HumanName().ToLower().FirstCharacterToUpper()} '{definition.label}' is not properly configured and is currently ignored.");
}
else
{
return Warning.Caution($"A {definition.GetType().HumanName().ToLower()} with incomplete configuration is currently ignored.");
}
}
}
}

View File

@@ -0,0 +1,18 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(WaitForFlow))]
public class WaitForFlowDescriptor : UnitDescriptor<WaitForFlow>
{
public WaitForFlowDescriptor(WaitForFlow unit) : base(unit) { }
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
if (port is ControlInput && unit.awaitedInputs.Contains((ControlInput)port))
{
description.showLabel = false;
}
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(GetVariable))]
public class GetVariableOption : UnifiedVariableUnitOption<GetVariable>
{
[Obsolete(Serialization.ConstructorWarning)]
public GetVariableOption() : base() { }
public GetVariableOption(VariableKind kind, string defaultName = null) : base(kind, defaultName) { }
protected override string NamedLabel(bool human)
{
return $"Get {name}";
}
protected override string UnnamedLabel(bool human)
{
return $"Get {kind} Variable";
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(IsVariableDefined))]
public class IsVariableDefinedOption : UnifiedVariableUnitOption<IsVariableDefined>
{
[Obsolete(Serialization.ConstructorWarning)]
public IsVariableDefinedOption() : base() { }
public IsVariableDefinedOption(VariableKind kind, string defaultName = null) : base(kind, defaultName) { }
protected override string NamedLabel(bool human)
{
return $"{kind} Has {name} Variable";
}
protected override string UnnamedLabel(bool human)
{
return $"{kind} Has Variable";
}
public override string SearchResultLabel(string query)
{
return SearchUtility.HighlightQuery(haystack, query);
}
}
}

View File

@@ -0,0 +1,20 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(GetVariableUnit))]
public class GetVariableUnitOption<TVariableUnit> : VariableUnitOption<TVariableUnit> where TVariableUnit : GetVariableUnit
{
public GetVariableUnitOption() : base() { }
public GetVariableUnitOption(TVariableUnit unit) : base(unit) { }
public override string Kind()
{
return base.Kind().TrimStart("Get ");
}
protected override string DefaultNameLabel()
{
return $"Get {unit.defaultName}";
}
}
}

View File

@@ -0,0 +1,20 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(IsVariableDefinedUnit))]
public class IsVariableDefinedUnitOption<TVariableUnit> : VariableUnitOption<TVariableUnit> where TVariableUnit : IsVariableDefinedUnit
{
public IsVariableDefinedUnitOption() : base() { }
public IsVariableDefinedUnitOption(TVariableUnit unit) : base(unit) { }
public override string Kind()
{
return base.Kind().TrimStart("Is ").TrimEnd(" Defined");
}
protected override string DefaultNameLabel()
{
return $"Is {unit.defaultName} Defined";
}
}
}

View File

@@ -0,0 +1,20 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(SetVariableUnit))]
public class SetVariableUnitOption<TVariableUnit> : VariableUnitOption<TVariableUnit> where TVariableUnit : SetVariableUnit
{
public SetVariableUnitOption() : base() { }
public SetVariableUnitOption(TVariableUnit unit) : base(unit) { }
public override string Kind()
{
return base.Kind().TrimStart("Set ");
}
protected override string DefaultNameLabel()
{
return $"Set {unit.defaultName}";
}
}
}

View File

@@ -0,0 +1,24 @@
#pragma warning disable 618
namespace Unity.VisualScripting
{
[Descriptor(typeof(VariableUnit))]
public class VariableUnitDescriptor<TVariableUnit> : UnitDescriptor<TVariableUnit> where TVariableUnit : VariableUnit
{
public VariableUnitDescriptor(TVariableUnit unit) : base(unit) { }
protected bool hasDefaultName => !string.IsNullOrEmpty(unit.defaultName);
protected override string DefinedSummary()
{
var summary = base.DefinedSummary();
if (hasDefaultName)
{
summary += $" (\"{unit.defaultName}\")";
}
return summary;
}
}
}

View File

@@ -0,0 +1,72 @@
#pragma warning disable 618
namespace Unity.VisualScripting
{
public interface IVariableUnitOption
{
string Kind();
}
public abstract class VariableUnitOption<TVariableUnit> : UnitOption<TVariableUnit>, IVariableUnitOption where TVariableUnit : VariableUnit
{
protected VariableUnitOption() : base() { }
protected VariableUnitOption(TVariableUnit unit) : base(unit) { }
protected bool hasDefaultName => !string.IsNullOrEmpty(unit.defaultName);
protected override string FavoriteKey()
{
return $"{unit.GetType().FullName}${unit.defaultName}";
}
private string DimmedKind()
{
return LudiqGUIUtility.DimString($" ({Kind()})");
}
public virtual string Kind()
{
return unit.GetType().HumanName();
}
protected virtual string DefaultNameLabel()
{
return unit.defaultName;
}
protected override string Label(bool human)
{
if (hasDefaultName)
{
return DefaultNameLabel() + DimmedKind();
}
else
{
return base.Label(human);
}
}
protected override string Haystack(bool human)
{
if (hasDefaultName)
{
return DefaultNameLabel();
}
return base.Haystack(human);
}
public override string SearchResultLabel(string query)
{
if (hasDefaultName)
{
return base.SearchResultLabel(query) + DimmedKind();
}
else
{
return base.SearchResultLabel(query);
}
}
}
}

View File

@@ -0,0 +1,12 @@
#pragma warning disable 618
namespace Unity.VisualScripting
{
[Widget(typeof(VariableUnit))]
public sealed class VariableUnitWidget : UnitWidget<VariableUnit>
{
public VariableUnitWidget(FlowCanvas canvas, VariableUnit unit) : base(canvas, unit) { }
protected override NodeColorMix baseColor => NodeColorMix.TealReadable;
}
}

View File

@@ -0,0 +1,23 @@
using System;
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(SetVariable))]
public class SetVariableOption : UnifiedVariableUnitOption<SetVariable>
{
[Obsolete(Serialization.ConstructorWarning)]
public SetVariableOption() : base() { }
public SetVariableOption(VariableKind kind, string defaultName = null) : base(kind, defaultName) { }
protected override string NamedLabel(bool human)
{
return $"Set {name}";
}
protected override string UnnamedLabel(bool human)
{
return $"Set {kind} Variable";
}
}
}

View File

@@ -0,0 +1,13 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(UnifiedVariableUnit))]
public class UnifiedVariableUnitDescriptor<TVariableUnit> : UnitDescriptor<TVariableUnit> where TVariableUnit : UnifiedVariableUnit
{
public UnifiedVariableUnitDescriptor(TVariableUnit unit) : base(unit) { }
protected override EditorTexture DefinedIcon()
{
return BoltCore.Icons.VariableKind(unit.kind);
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
namespace Unity.VisualScripting
{
public interface IUnifiedVariableUnitOption : IUnitOption
{
VariableKind kind { get; }
string name { get; }
}
public abstract class UnifiedVariableUnitOption<TVariableUnit> : UnitOption<TVariableUnit>, IUnifiedVariableUnitOption where TVariableUnit : UnifiedVariableUnit
{
[Obsolete(Serialization.ConstructorWarning)]
protected UnifiedVariableUnitOption() : base() { }
protected UnifiedVariableUnitOption(VariableKind kind, string defaultName = null) : base()
{
this.kind = kind;
this.name = defaultName;
this.unit = (TVariableUnit)Activator.CreateInstance(typeof(TVariableUnit));
FillFromUnit();
}
public override void Deserialize(UnitOptionRow row)
{
base.Deserialize(row);
kind = (VariableKind)Enum.Parse(typeof(VariableKind), row.tag1);
name = row.tag2;
}
public override UnitOptionRow Serialize()
{
var row = base.Serialize();
row.tag1 = kind.ToString();
row.tag2 = name;
return row;
}
public string name { get; private set; }
public VariableKind kind { get; private set; }
public bool hasName => !string.IsNullOrEmpty(name);
protected override string FavoriteKey()
{
return $"{unit.GetType().FullName}${name}";
}
private string DimmedKind()
{
return LudiqGUIUtility.DimString($" ({kind})");
}
protected abstract string NamedLabel(bool human);
protected abstract string UnnamedLabel(bool human);
protected override string Label(bool human)
{
if (hasName)
{
return NamedLabel(human);
}
else
{
return UnnamedLabel(human);
}
}
public override string SearchResultLabel(string query)
{
if (hasName)
{
return base.SearchResultLabel(query) + DimmedKind();
}
else
{
return base.SearchResultLabel(query);
}
}
protected override EditorTexture Icon()
{
return BoltCore.Icons.VariableKind(kind);
}
public override void PreconfigureUnit(TVariableUnit unit)
{
unit.kind = kind;
if (hasName)
{
unit.name.SetDefaultValue(name);
}
unit.Define(); // Force redefine, because we changed the kind
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting
{
[Widget(typeof(UnifiedVariableUnit))]
public sealed class UnifiedVariableUnitWidget : UnitWidget<UnifiedVariableUnit>
{
public UnifiedVariableUnitWidget(FlowCanvas canvas, UnifiedVariableUnit unit) : base(canvas, unit)
{
nameInspectorConstructor = (metadata) => new VariableNameInspector(metadata, GetNameSuggestions);
}
protected override NodeColorMix baseColor => NodeColorMix.TealReadable;
private VariableNameInspector nameInspector;
private Func<Metadata, VariableNameInspector> nameInspectorConstructor;
public override Inspector GetPortInspector(IUnitPort port, Metadata metadata)
{
if (port == unit.name)
{
// This feels so hacky. The real holy grail here would be to support attribute decorators like Unity does.
InspectorProvider.instance.Renew(ref nameInspector, metadata, nameInspectorConstructor);
return nameInspector;
}
return base.GetPortInspector(port, metadata);
}
private IEnumerable<string> GetNameSuggestions()
{
return EditorVariablesUtility.GetVariableNameSuggestions(unit.kind, reference);
}
}
}

View File

@@ -0,0 +1,16 @@
namespace Unity.VisualScripting
{
[FuzzyOption(typeof(VariableKind))]
public class VariableKindOption : DocumentedOption<VariableKind>
{
public VariableKindOption(VariableKind kind)
{
value = kind;
label = kind.HumanName();
UnityAPI.Async(() => icon = BoltCore.Icons.VariableKind(kind));
documentation = kind.Documentation();
zoom = true;
parentOnly = true;
}
}
}