// 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(); }
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; }
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(); }); }
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; }
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); })); }
public EnumOption(Enum @enum) { value = @enum; label = @enum.HumanName(); UnityAPI.Async(() => icon = @enum.Icon()); documentation = @enum.Documentation(); zoom = true; }
public TypeOption(Type type) { value = type; label = type.DisplayName(); UnityAPI.Async(() => icon = type.Icon()); documentation = type.Documentation(); zoom = true; }
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(); } }
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); } }
public void Run(object assigner, object assignee) { if (requiresAPI) { UnityAPI.Async(() => _Run(assigner, assignee)); } else { _Run(assigner, assignee); } }
protected virtual void FillFromData() { unit.EnsureDefined(); unitType = unit.GetType(); UnityAPI.Async(() => icon = Icon()); showControlInputsInFooter = ShowControlInputsInFooter(); showControlOutputsInFooter = ShowControlOutputsInFooter(); showValueInputsInFooter = ShowValueInputsInFooter(); showValueOutputsInFooter = ShowValueOutputsInFooter(); filled = true; }
private void EnsureConfig() { if (_vsCoreConfig != null) { return; } if (BoltCore.instance == null || BoltCore.Configuration == null) { UnityAPI.Initialize(); PluginContainer.Initialize(); } _vsCoreConfig = BoltCore.Configuration; }
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); } }
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(); } })); }
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()); } }
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); } }); }
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(); } } }
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; } } } ); }
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); } }
private void CacheEventLinesOnUnityThread() { UnityAPI.Async(CacheEventLines); }