123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using UnityEngine;
- using UnityObject = UnityEngine.Object;
-
- namespace Unity.VisualScripting
- {
- public class UnitOptionTree : ExtensibleFuzzyOptionTree
- {
- #region Initialization
-
- public UnitOptionTree(GUIContent label) : base(label)
- {
- favorites = new Favorites(this);
-
- showBackgroundWorkerProgress = true;
- }
-
- public override IFuzzyOption Option(object item)
- {
- if (item is Namespace @namespace)
- {
- return new NamespaceOption(@namespace, true);
- }
-
- if (item is Type type)
- {
- return new TypeOption(type, true);
- }
-
- return base.Option(item);
- }
-
- public override void Prewarm()
- {
- filter = filter ?? UnitOptionFilter.Any;
-
- try
- {
- options = new HashSet<IUnitOption>(UnitBase.Subset(filter, reference));
- }
- catch (Exception ex)
- {
- Debug.LogError($"Failed to fetch node options for fuzzy finder (error log below).\nTry rebuilding the node options from '{UnitOptionUtility.GenerateUnitDatabasePath}'.\n\n{ex}");
- options = new HashSet<IUnitOption>();
- }
-
- typesWithMembers = new HashSet<Type>();
-
- foreach (var option in options)
- {
- if (option is IMemberUnitOption memberUnitOption && memberUnitOption.targetType != null)
- {
- typesWithMembers.Add(memberUnitOption.targetType);
- }
- }
- }
-
- private HashSet<IUnitOption> options;
-
- private HashSet<Type> typesWithMembers;
-
- #endregion
-
-
- #region Configuration
-
- public UnitOptionFilter filter { get; set; }
- public GraphReference reference { get; set; }
- public bool includeNone { get; set; }
- public bool surfaceCommonTypeLiterals { get; set; }
- public object[] rootOverride { get; set; }
-
- public FlowGraph graph => reference.graph as FlowGraph;
- public GameObject self => reference.self;
-
- public ActionDirection direction { get; set; } = ActionDirection.Any;
-
- #endregion
-
-
- #region Hierarchy
-
- private readonly FuzzyGroup enumsGroup = new FuzzyGroup("(Enums)", typeof(Enum).Icon());
- private readonly FuzzyGroup selfGroup = new FuzzyGroup("This", typeof(GameObject).Icon());
-
- private IEnumerable<UnitCategory> SpecialCategories()
- {
- yield return new UnitCategory("Codebase");
- yield return new UnitCategory("Events");
- yield return new UnitCategory("Variables");
- yield return new UnitCategory("Math");
- yield return new UnitCategory("Nesting");
- yield return new UnitCategory("Graphs");
- }
-
- public override IEnumerable<object> Root()
- {
- if (rootOverride != null && rootOverride.Length > 0)
- {
- foreach (var item in rootOverride)
- {
- yield return item;
- }
-
- yield break;
- }
-
- if (filter.CompatibleOutputType != null)
- {
- var outputType = filter.CompatibleOutputType;
-
- var outputTypeLiteral = options.FirstOrDefault(option => option is LiteralOption literalOption && literalOption.literalType == outputType);
-
- if (outputTypeLiteral != null)
- {
- yield return outputTypeLiteral;
- }
-
- HashSet<Type> noSurfaceConstructors = new HashSet<Type>()
- {
- typeof(string),
- typeof(object)
- };
-
- if (!noSurfaceConstructors.Contains(outputType))
- {
- var outputTypeConstructors = options.Where(option => option is InvokeMemberOption invokeMemberOption &&
- invokeMemberOption.targetType == outputType &&
- invokeMemberOption.unit.member.isConstructor);
-
- foreach (var outputTypeConstructor in outputTypeConstructors)
- {
- yield return outputTypeConstructor;
- }
- }
-
- if (outputType == typeof(bool))
- {
- foreach (var logicOperation in CategoryChildren(new UnitCategory("Logic")))
- {
- yield return logicOperation;
- }
- }
-
- if (outputType.IsNumeric())
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Scalar")))
- {
- yield return mathOperation;
- }
- }
-
- if (outputType == typeof(Vector2))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Vector 2")))
- {
- yield return mathOperation;
- }
- }
-
- if (outputType == typeof(Vector3))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Vector 3")))
- {
- yield return mathOperation;
- }
- }
-
- if (outputType == typeof(Vector4))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Vector 4")))
- {
- yield return mathOperation;
- }
- }
- }
-
- if (surfaceCommonTypeLiterals)
- {
- foreach (var commonType in EditorTypeUtility.commonTypes)
- {
- if (commonType == filter.CompatibleOutputType)
- {
- continue;
- }
-
- var commonTypeLiteral = options.FirstOrDefault(option => option is LiteralOption literalOption && literalOption.literalType == commonType);
-
- if (commonTypeLiteral != null)
- {
- yield return commonTypeLiteral;
- }
- }
- }
-
- if (filter.CompatibleInputType != null)
- {
- var inputType = filter.CompatibleInputType;
-
- if (!inputType.IsPrimitive && inputType != typeof(object))
- {
- yield return inputType;
- }
-
- if (inputType == typeof(bool))
- {
- yield return options.Single(o => o.UnitIs<If>());
- yield return options.Single(o => o.UnitIs<SelectUnit>());
- }
-
- if (inputType == typeof(bool) || inputType.IsNumeric())
- {
- foreach (var logicOperation in CategoryChildren(new UnitCategory("Logic")))
- {
- yield return logicOperation;
- }
- }
-
- if (inputType.IsNumeric())
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Scalar")))
- {
- yield return mathOperation;
- }
- }
-
- if (inputType == typeof(Vector2))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Vector 2")))
- {
- yield return mathOperation;
- }
- }
-
- if (inputType == typeof(Vector3))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Vector 3")))
- {
- yield return mathOperation;
- }
- }
-
- if (inputType == typeof(Vector4))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Math/Vector 4")))
- {
- yield return mathOperation;
- }
- }
-
- if (typeof(IEnumerable).IsAssignableFrom(inputType) && (inputType != typeof(string) && inputType != typeof(Transform)))
- {
- foreach (var mathOperation in CategoryChildren(new UnitCategory("Collections"), false))
- {
- yield return mathOperation;
- }
- }
-
- if (typeof(IList).IsAssignableFrom(inputType))
- {
- foreach (var listOperation in CategoryChildren(new UnitCategory("Collections/Lists")))
- {
- yield return listOperation;
- }
- }
-
- if (typeof(IDictionary).IsAssignableFrom(inputType))
- {
- foreach (var dictionaryOperation in CategoryChildren(new UnitCategory("Collections/Dictionaries")))
- {
- yield return dictionaryOperation;
- }
- }
- }
-
- if (filter.NoConnection)
- {
- yield return new StickyNoteOption();
- }
-
- if (UnityAPI.Await
- (
- () =>
- {
- if (self != null)
- {
- selfGroup.label = self.name;
- selfGroup.icon = self.Icon();
- return true;
- }
-
- return false;
- }
- )
- )
- {
- yield return selfGroup;
- }
-
- foreach (var category in options.Select(option => option.category?.root)
- .NotNull()
- .Concat(SpecialCategories())
- .Distinct()
- .OrderBy(c => c.name))
- {
- yield return category;
- }
-
- foreach (var extensionRootItem in base.Root())
- {
- yield return extensionRootItem;
- }
-
- if (filter.Self)
- {
- var self = options.FirstOrDefault(option => option.UnitIs<This>());
-
- if (self != null)
- {
- yield return self;
- }
- }
-
- foreach (var unit in CategoryChildren(null))
- {
- yield return unit;
- }
-
- if (includeNone)
- {
- yield return null;
- }
- }
-
- public override IEnumerable<object> Children(object parent)
- {
- if (parent is Namespace @namespace)
- {
- return NamespaceChildren(@namespace);
- }
- else if (parent is Type type)
- {
- return TypeChildren(type);
- }
- else if (parent == enumsGroup)
- {
- return EnumsChildren();
- }
- else if (parent == selfGroup)
- {
- return SelfChildren();
- }
- else if (parent is UnitCategory unitCategory)
- {
- return CategoryChildren(unitCategory);
- }
- else if (parent is VariableKind variableKind)
- {
- return VariableKindChildren(variableKind);
- }
- else
- {
- return base.Children(parent);
- }
- }
-
- private IEnumerable<object> SelfChildren()
- {
- yield return typeof(GameObject);
-
- // Self components can be null if no script is assigned to them
- // https://support.ludiq.io/forums/5-bolt/topics/817-/
- foreach (var selfComponentType in UnityAPI.Await(() => self.GetComponents<Component>().NotUnityNull().Select(c => c.GetType())))
- {
- yield return selfComponentType;
- }
- }
-
- private IEnumerable<object> CodebaseChildren()
- {
- foreach (var rootNamespace in typesWithMembers.Where(t => !t.IsEnum)
- .Select(t => t.Namespace().Root)
- .OrderBy(ns => ns.DisplayName(false))
- .Distinct())
- {
- yield return rootNamespace;
- }
-
- if (filter.Literals && options.Any(option => option is LiteralOption literalOption && literalOption.literalType.IsEnum))
- {
- yield return enumsGroup;
- }
- }
-
- private IEnumerable<object> MathChildren()
- {
- foreach (var mathMember in GetMembers(typeof(Mathf)).Where(option => !((MemberUnit)option.unit).member.requiresTarget))
- {
- yield return mathMember;
- }
- }
-
- private IEnumerable<object> TimeChildren()
- {
- foreach (var timeMember in GetMembers(typeof(Time)).Where(option => !((MemberUnit)option.unit).member.requiresTarget))
- {
- yield return timeMember;
- }
- }
-
- private IEnumerable<object> NestingChildren()
- {
- foreach (var nester in options.Where(option => option.UnitIs<IGraphNesterElement>() && ((IGraphNesterElement)option.unit).nest.macro == null)
- .OrderBy(option => option.label))
- {
- yield return nester;
- }
- }
-
- private IEnumerable<object> MacroChildren()
- {
- foreach (var macroNester in options.Where(option => option.UnitIs<IGraphNesterElement>() && ((IGraphNesterElement)option.unit).nest.macro != null)
- .OrderBy(option => option.label))
- {
- yield return macroNester;
- }
- }
-
- private IEnumerable<object> VariablesChildren()
- {
- yield return VariableKind.Flow;
- yield return VariableKind.Graph;
- yield return VariableKind.Object;
- yield return VariableKind.Scene;
- yield return VariableKind.Application;
- yield return VariableKind.Saved;
- }
-
- private IEnumerable<object> VariableKindChildren(VariableKind kind)
- {
- foreach (var variable in options.OfType<IUnifiedVariableUnitOption>()
- .Where(option => option.kind == kind)
- .OrderBy(option => option.name))
- {
- yield return variable;
- }
- }
-
- private IEnumerable<object> NamespaceChildren(Namespace @namespace)
- {
- foreach (var childNamespace in GetChildrenNamespaces(@namespace))
- {
- yield return childNamespace;
- }
-
- foreach (var type in GetNamespaceTypes(@namespace))
- {
- yield return type;
- }
- }
-
- private IEnumerable<Namespace> GetChildrenNamespaces(Namespace @namespace)
- {
- if (!@namespace.IsGlobal)
- {
- foreach (var childNamespace in typesWithMembers.Where(t => !t.IsEnum)
- .SelectMany(t => t.Namespace().AndAncestors())
- .Distinct()
- .Where(ns => ns.Parent == @namespace)
- .OrderBy(ns => ns.DisplayName(false)))
- {
- yield return childNamespace;
- }
- }
- }
-
- private IEnumerable<Type> GetNamespaceTypes(Namespace @namespace)
- {
- foreach (var type in typesWithMembers.Where(t => t.Namespace() == @namespace && !t.IsEnum)
- .OrderBy(t => t.DisplayName()))
- {
- yield return type;
- }
- }
-
- private IEnumerable<object> TypeChildren(Type type)
- {
- foreach (var literal in options.Where(option => option is LiteralOption literalOption && literalOption.literalType == type))
- {
- yield return literal;
- }
-
- foreach (var expose in options.Where(option => option is ExposeOption exposeOption && exposeOption.exposedType == type))
- {
- yield return expose;
- }
-
- if (type.IsStruct())
- {
- foreach (var createStruct in options.Where(option => option is CreateStructOption createStructOption && createStructOption.structType == type))
- {
- yield return createStruct;
- }
- }
-
- foreach (var member in GetMembers(type))
- {
- yield return member;
- }
- }
-
- private IEnumerable<IUnitOption> GetMembers(Type type)
- {
- foreach (var member in options.Where(option => option is IMemberUnitOption memberUnitOption && memberUnitOption.targetType == type && option.unit.canDefine)
- .OrderBy(option => BoltCore.Configuration.groupInheritedMembers && ((MemberUnit)option.unit).member.isPseudoInherited)
- .ThenBy(option => option.order)
- .ThenBy(option => option.label))
- {
- yield return member;
- }
- }
-
- private IEnumerable<object> EnumsChildren()
- {
- foreach (var literal in options.Where(option => option is LiteralOption literalOption && literalOption.literalType.IsEnum)
- .OrderBy(option => option.label))
- {
- yield return literal;
- }
- }
-
- private IEnumerable<object> CategoryChildren(UnitCategory category, bool subCategories = true)
- {
- if (category != null && subCategories)
- {
- foreach (var subCategory in options.SelectMany(option => option.category == null ? Enumerable.Empty<UnitCategory>() : option.category.AndAncestors())
- .Distinct()
- .Where(c => c.parent == category)
- .OrderBy(c => c.name))
- {
- yield return subCategory;
- }
- }
-
- foreach (var unit in options.Where(option => option.category == category)
- .Where(option => !option.unitType.HasAttribute<SpecialUnitAttribute>())
- .OrderBy(option => option.order)
- .ThenBy(option => option.label))
- {
- yield return unit;
- }
-
- if (category != null)
- {
- if (category.root.name == "Events")
- {
- foreach (var eventChild in EventsChildren(category))
- {
- yield return eventChild;
- }
- }
- else if (category.fullName == "Codebase")
- {
- foreach (var codebaseChild in CodebaseChildren())
- {
- yield return codebaseChild;
- }
- }
- else if (category.fullName == "Variables")
- {
- foreach (var variableChild in VariablesChildren())
- {
- yield return variableChild;
- }
- }
- else if (category.fullName == "Math")
- {
- foreach (var mathChild in MathChildren())
- {
- yield return mathChild;
- }
- }
- else if (category.fullName == "Time")
- {
- foreach (var timeChild in TimeChildren())
- {
- yield return timeChild;
- }
- }
- else if (category.fullName == "Nesting")
- {
- foreach (var nestingChild in NestingChildren())
- {
- yield return nestingChild;
- }
- }
- else if (category.fullName == "Graphs")
- {
- foreach (var macroChild in MacroChildren())
- {
- yield return macroChild;
- }
- }
- }
- }
-
- private IEnumerable<object> EventsChildren(UnitCategory category)
- {
- foreach (var unit in options.Where(option => option.UnitIs<IEventUnit>() && option.category == category)
- .OrderBy(option => option.order)
- .ThenBy(option => option.label))
- {
- yield return unit;
- }
- }
-
- #endregion
-
-
- #region Search
-
- public override bool searchable { get; } = true;
-
- public override IEnumerable<ISearchResult> SearchResults(string query, CancellationToken cancellation)
- {
- foreach (var typeResult in typesWithMembers.Cancellable(cancellation).OrderableSearchFilter(query, t => t.DisplayName()))
- {
- yield return typeResult;
- }
-
- foreach (var optionResult in options.Cancellable(cancellation)
- .OrderableSearchFilter(query, o => o.haystack, o => o.formerHaystack)
- .WithoutInheritedDuplicates(r => r.result, cancellation))
- {
- yield return optionResult;
- }
- }
-
- public override string SearchResultLabel(object item, string query)
- {
- if (item is Type type)
- {
- return TypeOption.SearchResultLabel(type, query);
- }
- else if (item is IUnitOption unitOption)
- {
- return unitOption.SearchResultLabel(query);
- }
- else
- {
- return base.SearchResultLabel(item, query);
- }
- }
-
- #endregion
-
-
- #region Favorites
-
- public override ICollection<object> favorites { get; }
-
- public override bool CanFavorite(object item)
- {
- return (item as IUnitOption)?.favoritable ?? false;
- }
-
- public override string FavoritesLabel(object item)
- {
- return SearchResultLabel(item, null);
- }
-
- public override void OnFavoritesChange()
- {
- BoltFlow.Configuration.Save();
- }
-
- private class Favorites : ICollection<object>
- {
- public Favorites(UnitOptionTree tree)
- {
- this.tree = tree;
- }
-
- private UnitOptionTree tree { get; }
-
- private IEnumerable<IUnitOption> options => tree.options.Where(option => BoltFlow.Configuration.favoriteUnitOptions.Contains(option.favoriteKey));
-
- public bool IsReadOnly => false;
-
- public int Count => BoltFlow.Configuration.favoriteUnitOptions.Count;
-
- public IEnumerator<object> GetEnumerator()
- {
- foreach (var option in options)
- {
- yield return option;
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public bool Contains(object item)
- {
- var option = (IUnitOption)item;
-
- return BoltFlow.Configuration.favoriteUnitOptions.Contains(option.favoriteKey);
- }
-
- public void Add(object item)
- {
- var option = (IUnitOption)item;
-
- BoltFlow.Configuration.favoriteUnitOptions.Add(option.favoriteKey);
- }
-
- public bool Remove(object item)
- {
- var option = (IUnitOption)item;
-
- return BoltFlow.Configuration.favoriteUnitOptions.Remove(option.favoriteKey);
- }
-
- public void Clear()
- {
- BoltFlow.Configuration.favoriteUnitOptions.Clear();
- }
-
- public void CopyTo(object[] array, int arrayIndex)
- {
- if (array == null)
- {
- throw new ArgumentNullException(nameof(array));
- }
-
- if (arrayIndex < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(arrayIndex));
- }
-
- if (array.Length - arrayIndex < Count)
- {
- throw new ArgumentException();
- }
-
- var i = 0;
-
- foreach (var item in this)
- {
- array[i + arrayIndex] = item;
- i++;
- }
- }
- }
-
- #endregion
- }
- }
|