예제 #1
0
        // Note: This is currently only possible because all our InitializeOnLoad calls were in Core. If we ever
        // need to put something in Flow or State, we might need to move this entire class to a shared assembly that
        // references those assemblies.
        private static void DoInitializeOnLoadCalls()
        {
            if (!isVisualScriptingUsed)
            {
                return;
            }

            if (_initializeOnLoadExecuted)
            {
                return;
            }

            _initializeOnLoadExecuted = true;

            EditorDebugUtility.DeleteDebugLogFile();

            EditorPlatformUtility.InitializeActiveBuildTarget();

            EditorApplicationUtility.Initialize();

            EditorTimeUtility.Initialize();

            UnityAPI.Initialize();

            PackageEventListener.SubscribeToEvents();

            PluginContainer.InitializeOnLoad();

            XmlDocumentation.Initialize();
        }
예제 #2
0
        protected virtual void FillFromUnit()
        {
            unit.EnsureDefined();
            unitType = unit.GetType();

            labelHuman    = Label(true);
            haystackHuman = Haystack(true);

            labelProgrammer    = Label(false);
            haystackProgrammer = Haystack(false);

            category    = Category();
            order       = Order();
            favoriteKey = FavoriteKey();
            UnityAPI.Async(() => icon = Icon());

            showControlInputsInFooter  = ShowControlInputsInFooter();
            showControlOutputsInFooter = ShowControlOutputsInFooter();
            showValueInputsInFooter    = ShowValueInputsInFooter();
            showValueOutputsInFooter   = ShowValueOutputsInFooter();

            controlInputCount  = unit.controlInputs.Count;
            controlOutputCount = unit.controlOutputs.Count;
            valueInputTypes    = unit.valueInputs.Select(vi => vi.type).ToHashSet();
            valueOutputTypes   = unit.valueOutputs.Select(vo => vo.type).ToHashSet();

            filled = true;
        }
예제 #3
0
        public static void BackgroundWork()
        {
            var preloadedAssemblies = new List <Assembly>();

            preloadedAssemblies.AddRange(Codebase.settingsAssemblies);
            preloadedAssemblies.AddRange(Codebase.ludiqEditorAssemblies);

            for (var i = 0; i < preloadedAssemblies.Count; i++)
            {
                var assembly = preloadedAssemblies[i];
                ProgressUtility.DisplayProgressBar($"Documentation ({assembly.GetName().Name})...", null, (float)i / Codebase.settingsAssemblies.Count);
                var documentation = GetDocumentationUncached(assembly);


                lock (@lock)
                {
                    if (!LazyData.Value.documentations.ContainsKey(assembly))
                    {
                        LazyData.Value.documentations.Add(assembly, documentation);
                    }
                }
            }

            UnityAPI.Async(() =>
            {
                loaded = true;
                loadComplete?.Invoke();
            });
        }
예제 #4
0
        private static IEnumerable <string> GetModifiedScriptGuids()
        {
            var guids = new HashSet <string>();

            UnityAPI.AwaitForever(() =>
            {
                var databaseTimestamp = File.GetLastWriteTimeUtc(BoltFlow.Paths.unitOptions);

                foreach (var script in UnityEngine.Resources.FindObjectsOfTypeAll <MonoScript>())
                {
                    var path = AssetDatabase.GetAssetPath(script);
                    var guid = AssetDatabase.AssetPathToGUID(path);

                    // Skip built-in Unity plugins, which are referenced by full path
                    if (!path.StartsWith("Assets"))
                    {
                        continue;
                    }

                    var scriptTimestamp = File.GetLastWriteTimeUtc(Path.Combine(Paths.project, path));

                    if (scriptTimestamp > databaseTimestamp)
                    {
                        guids.Add(guid);
                    }
                }
            });

            return(guids);
        }
 public UnitCategoryOption(UnitCategory category)
 {
     value = category;
     label = category.name.Split('/').Last().Prettify();
     UnityAPI.Async(() => icon = BoltFlow.Icons.UnitCategory(category));
     parentOnly = true;
 }
예제 #6
0
 protected override string Label(bool human)
 {
     return(UnityAPI.Await(() =>
     {
         var macro = (UnityObject)unit.nest.macro;
         return macro != null ? macro.name : BoltFlowNameUtility.UnitTitle(unit.GetType(), false, false);
     }));
 }
예제 #7
0
 public EnumOption(Enum @enum)
 {
     value = @enum;
     label = @enum.HumanName();
     UnityAPI.Async(() => icon = @enum.Icon());
     documentation = @enum.Documentation();
     zoom = true;
 }
예제 #8
0
 public TypeOption(Type type)
 {
     value = type;
     label = type.DisplayName();
     UnityAPI.Async(() => icon = type.Icon());
     documentation             = type.Documentation();
     zoom = true;
 }
예제 #9
0
        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");
        }
        private static IEnumerable<IUnitOption> GetDynamicOptions()
        {
            var stateMacros = UnityAPI.Await(() => AssetUtility.GetAllAssetsOfType<StateGraphAsset>().ToArray());

            foreach (var stateUnit in stateMacros.Select(statemacro => new StateUnit(statemacro)))
            {
                yield return stateUnit.Option();
            }
        }
예제 #11
0
        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);
            }
        }
예제 #12
0
 public void Run(object assigner, object assignee)
 {
     if (requiresAPI)
     {
         UnityAPI.Async(() => _Run(assigner, assignee));
     }
     else
     {
         _Run(assigner, assignee);
     }
 }
예제 #13
0
        protected virtual void FillFromData()
        {
            unit.EnsureDefined();
            unitType = unit.GetType();
            UnityAPI.Async(() => icon = Icon());

            showControlInputsInFooter  = ShowControlInputsInFooter();
            showControlOutputsInFooter = ShowControlOutputsInFooter();
            showValueInputsInFooter    = ShowValueInputsInFooter();
            showValueOutputsInFooter   = ShowValueOutputsInFooter();

            filled = true;
        }
예제 #14
0
        private void EnsureConfig()
        {
            if (_vsCoreConfig != null)
            {
                return;
            }

            if (BoltCore.instance == null || BoltCore.Configuration == null)
            {
                UnityAPI.Initialize();
                PluginContainer.Initialize();
            }

            _vsCoreConfig = BoltCore.Configuration;
        }
예제 #15
0
        public void Validate()
        {
            if (isDirty)
            {
                isDirty = false;

                description.fallbackLabel = target.key.Filter(symbols: false, punctuation: false).Prettify();

                UnityAPI.Async(() => description.icon = GetIcon(target));

                target.unit?.Descriptor <IUnitDescriptor>().DescribePort(target, description);

                // No DescriptionAssignment is run, so we'll just always assume that the description changes.
                DescriptorProvider.instance.TriggerDescriptionChange(target);
            }
        }
예제 #16
0
        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();
                }
            }));
        }
예제 #17
0
        public static IEnumerable <IUnitOption> Subset(UnitOptionFilter filter, GraphReference reference)
        {
            lock (@lock)
            {
                if (options == null)
                {
                    Load();
                }

                var dynamicOptions    = UnityAPI.Await(() => GetDynamicOptions().ToHashSet());
                var contextualOptions = UnityAPI.Await(() => GetContextualOptions(reference).ToHashSet());

                return(LinqUtility.Concat <IUnitOption>(options, dynamicOptions, contextualOptions)
                       .Where((filter ?? UnitOptionFilter.Any).ValidateOption)
                       .ToArray());
            }
        }
예제 #18
0
        private static void UpdateTypeMappings()
        {
            using var profilerScope = ProfilingUtility.SampleBlock("UpdateTypeMappings");

            typesToGuids = new Dictionary <Type, HashSet <string> >();
            guidsToTypes = new Dictionary <string, HashSet <Type> >();

            UnityAPI.AwaitForever(() =>
            {
                foreach (var script in UnityEngine.Resources.FindObjectsOfTypeAll <MonoScript>())
                {
                    var type = script.GetClass();

                    // Skip scripts without types
                    if (type == null)
                    {
                        continue;
                    }

                    var path = AssetDatabase.GetAssetPath(script);
                    // Skip built-in Unity plugins, which are referenced by full path
                    if (!path.StartsWith("Assets"))
                    {
                        continue;
                    }

                    var guid = AssetDatabase.AssetPathToGUID(path);
                    // Add the GUID to the list, even if it doesn't have any type
                    if (!guidsToTypes.ContainsKey(guid))
                    {
                        guidsToTypes.Add(guid, new HashSet <Type>());
                    }

                    if (!typesToGuids.ContainsKey(type))
                    {
                        typesToGuids.Add(type, new HashSet <string>());
                    }

                    typesToGuids[type].Add(guid);
                    guidsToTypes[guid].Add(type);
                }
            });
        }
예제 #19
0
        private static IEnumerable <string> GetDeletedScriptGuids()
        {
            if (!IsUnitOptionsBuilt())
            {
                return(Enumerable.Empty <string>());
            }

            using (NativeUtility.Module("sqlite3.dll"))
            {
                SQLiteConnection database = null;

                try
                {
                    HashSet <string> databaseGuids;

                    lock (@lock)
                    {
                        database = new SQLiteConnection(BoltFlow.Paths.unitOptions);

                        databaseGuids = database.Query <UnitOptionRow>($"SELECT DISTINCT {nameof(UnitOptionRow.sourceScriptGuids)} FROM {nameof(UnitOptionRow)}")
                                        .Select(row => row.sourceScriptGuids)
                                        .NotNull()
                                        .SelectMany(guids => guids.Split(','))
                                        .ToHashSet();
                    }

                    var assetGuids = UnityAPI.AwaitForever(() => UnityEngine.Resources
                                                           .FindObjectsOfTypeAll <MonoScript>()
                                                           .Where(script => script.GetClass() != null)
                                                           .Select(script => AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(script)))
                                                           .ToHashSet());

                    databaseGuids.ExceptWith(assetGuids);

                    return(databaseGuids);
                }
                finally
                {
                    database?.Close();
                }
            }
        }
예제 #20
0
        public static void Update()
        {
            if (!IsUnitOptionsBuilt())
            {
                Build();
                return;
            }

            lock (@lock)
            {
                using (ProfilingUtility.SampleBlock("Update Node Database"))
                {
                    using (NativeUtility.Module("sqlite3.dll"))
                    {
                        var progressTitle = "Updating node database...";

                        SQLiteConnection database = null;

                        try
                        {
                            VersionControlUtility.Unlock(BoltFlow.Paths.unitOptions);

                            var steps = 7f;
                            var step  = 0f;

                            ProgressUtility.DisplayProgressBar(progressTitle, "Connecting to database...", step++ / steps);

                            database = new SQLiteConnection(BoltFlow.Paths.unitOptions);

                            ProgressUtility.DisplayProgressBar(progressTitle, "Updating type mappings...", step++ / steps);

                            UpdateTypeMappings();

                            ProgressUtility.DisplayProgressBar(progressTitle, "Fetching modified scripts...", step++ / steps);

                            var modifiedScriptGuids = GetModifiedScriptGuids().Distinct().ToHashSet();

                            ProgressUtility.DisplayProgressBar(progressTitle, "Fetching deleted scripts...", step++ / steps);

                            var deletedScriptGuids = GetDeletedScriptGuids().Distinct().ToHashSet();

                            ProgressUtility.DisplayProgressBar(progressTitle, "Updating codebase...", step++ / steps);

                            var modifiedScriptTypes = modifiedScriptGuids.SelectMany(GetScriptTypes).ToArray();

                            UpdateCodebase(modifiedScriptTypes);

                            var outdatedScriptGuids = new HashSet <string>();
                            outdatedScriptGuids.UnionWith(modifiedScriptGuids);
                            outdatedScriptGuids.UnionWith(deletedScriptGuids);

                            ProgressUtility.DisplayProgressBar(progressTitle, "Removing outdated node options...", step++ / steps);

                            options?.RemoveWhere(option => outdatedScriptGuids.Overlaps(option.sourceScriptGuids));

                            // We want to use the database level WHERE here for speed,
                            // so we'll run multiple queries, one for each outdated script GUID.

                            foreach (var outdatedScriptGuid in outdatedScriptGuids)
                            {
                                foreach (var outdatedRowId in database.Table <UnitOptionRow>()
                                         .Where(row => row.sourceScriptGuids.Contains(outdatedScriptGuid))
                                         .Select(row => row.id))
                                {
                                    database.Delete <UnitOptionRow>(outdatedRowId);
                                }
                            }

                            ProgressUtility.DisplayProgressBar(progressTitle, "Converting codebase to node options...", step++ / steps);

                            var newOptions = new HashSet <IUnitOption>(modifiedScriptGuids.SelectMany(GetScriptTypes)
                                                                       .Distinct()
                                                                       .SelectMany(GetIncrementalOptions));

                            var rows = new HashSet <UnitOptionRow>();

                            float progress = 0;

                            foreach (var newOption in newOptions)
                            {
                                options?.Add(newOption);

                                try
                                {
                                    ProgressUtility.DisplayProgressBar(progressTitle, newOption.label, (step / steps) + ((1 / step) * (progress / newOptions.Count)));
                                    rows.Add(newOption.Serialize());
                                }
                                catch (Exception ex)
                                {
                                    Debug.LogError($"Failed to serialize option '{newOption.GetType()}'.\n{ex}");
                                }

                                progress++;
                            }

                            ProgressUtility.DisplayProgressBar(progressTitle, "Writing to database...", 1);

                            try
                            {
                                database.InsertAll(rows);
                            }
                            catch (Exception ex)
                            {
                                Debug.LogError($"Failed to write options to database.\n{ex}");
                            }

                            // Make sure the database is touched to the current date,
                            // even if we didn't do any change. This will avoid unnecessary
                            // analysis in future update checks.
                            File.SetLastWriteTimeUtc(BoltFlow.Paths.unitOptions, DateTime.UtcNow);
                        }
                        finally
                        {
                            database?.Close();
                            ProgressUtility.ClearProgressBar();
                            UnityAPI.Async(AssetDatabase.Refresh);
                            //ConsoleProfiler.Dump();
                        }
                    }
                }
            }
        }
        // Perforce and other VCS have a lock mechanism that usually
        // only makes the file writable once checked out. We need to
        // check them out before writing to them for auto-generated files.
        public static void Unlock(string path)
        {
            Ensure.That(nameof(path)).IsNotNull(path);

            UnityAPI.Await
            (
                () =>
            {
                // The API changed in 2019, adding a third optional ChangeSet parameter
                // which defaults to null but breaks the compiled signature below
                // Furthermore, we can't even so much as have the call in the body of this method,
                // or it will fail even if the if branch evaluates to false. So we

                if (File.Exists(path) && Provider.enabled && Provider.isActive && Provider.hasCheckoutSupport)
                {
                    try
                    {
                        var provider = typeof(Provider);

                        if (EditorApplicationUtility.unityVersion >= "2019.1.0")
                        {
                            var method = provider.GetMethods()
                                         .FirstOrDefault
                                         (
                                m => m.Name == "Checkout" &&
                                m.GetParameters().Length == 3 &&
                                m.GetParameters()[0].ParameterType == typeof(string) &&
                                m.GetParameters()[1].ParameterType == typeof(CheckoutMode)
                                         );

                            if (method == null)
                            {
                                throw new MissingMemberException(provider.FullName, "Checkout");
                            }

                            method.InvokeOptimized(null, PathUtility.FromProject(path), CheckoutMode.Both, null);
                        }
                        else
                        {
                            var method = provider.GetMethods()
                                         .FirstOrDefault
                                         (
                                m => m.Name == "Checkout" &&
                                m.GetParameters().Length == 2 &&
                                m.GetParameters()[0].ParameterType == typeof(string) &&
                                m.GetParameters()[1].ParameterType == typeof(CheckoutMode)
                                         );

                            if (method == null)
                            {
                                throw new MissingMemberException(provider.FullName, "Checkout");
                            }

                            method.InvokeOptimized(null, PathUtility.FromProject(path), CheckoutMode.Both);
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.LogWarning($"Failed to automatically checkout file from version control:\n{path}\n{ex}");
                    }
                }

                if (File.Exists(path))
                {
                    var info = new FileInfo(path);

                    if (info.IsReadOnly)
                    {
                        var sb = new StringBuilder();
                        sb.AppendLine($"File '{info.Name}' is read-only despite attempted checkout. Manually forcing to writable.");
                        sb.AppendLine($"This may cause version control issues. Please report the following debug information:");
                        sb.AppendLine($"File Exists: {File.Exists(path)}");
                        sb.AppendLine($"Provider.enabled: {Provider.enabled}");
                        sb.AppendLine($"Provider.isActive: {Provider.isActive}");
                        sb.AppendLine($"Provider.hasCheckoutSupport: {Provider.hasCheckoutSupport}");
                        Debug.LogWarning(sb.ToString());

                        info.IsReadOnly = false;
                    }
                }
            }
            );
        }
예제 #22
0
        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 (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);
            }
        }
예제 #23
0
 private void CacheEventLinesOnUnityThread()
 {
     UnityAPI.Async(CacheEventLines);
 }