using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; using UnityEditor; using UnityEngine; namespace Unity.VisualScripting { [InitializeAfterPlugins] public static class BackgroundWorker { static BackgroundWorker() { queue = new ConcurrentQueue(); EditorApplication.delayCall += delegate { ClearProgress(); EditorApplication.update += DisplayProgress; new Thread(Work) { Name = "Background Worker" }.Start(); }; } private static readonly object @lock = new object(); private static bool clearProgress; private static int progressId = -1; private static readonly ConcurrentQueue queue; public static event Action tasks { add { Schedule(value); } remove { } } public static string progressLabel { get; private set; } public static float progressProportion { get; private set; } public static bool hasProgress => progressLabel != null; public static void Schedule(Action action) { queue.Enqueue(action); } private static void Work() { while (true) { if (queue.TryDequeue(out var task)) { var remaining = queue.Count + 1; ReportProgress($"{remaining} task{(queue.Count > 1 ? "s" : "")} remaining...", 0); try { task(); } catch (Exception ex) { EditorApplication.delayCall += () => Debug.LogException(ex); } finally { ClearProgress(); } } else { Thread.Sleep(100); } } } public static void ReportProgress(string title, float progress) { lock (@lock) { progressLabel = title; progressProportion = progress; } } public static void ClearProgress() { lock (@lock) { clearProgress = true; progressLabel = null; progressProportion = 0; } } private static void DisplayProgress() { lock (@lock) { if (clearProgress) { try { if (progressId != -1) { progressId = Progress.Remove(progressId); } } catch (Exception ex) { throw new UnityEditorInternalException(ex); } clearProgress = false; } if (progressLabel != null) { try { if (progressId == -1) { progressId = (int)Progress.Start("Ludiq Background Worker", progressLabel, Progress.Options.None, -1); } else { Progress.Report(progressId, progressProportion, progressLabel); } } catch (Exception ex) { throw new UnityEditorInternalException(ex); } } } } } }