using System; using System.Collections.Concurrent; using System.Threading; using UnityEditor; using UnityEngine; namespace Unity.VisualScripting { [InitializeOnLoad] public static class UnityAPI { static UnityAPI() { UnityThread.thread = Thread.CurrentThread; UnityThread.editorAsync = Async; EditorApplicationUtility.onModeChange += () => queue = new ConcurrentQueue(); EditorApplication.update += ProcessDelegates; } private static readonly TimeSpan defaultTimeout = TimeSpan.FromSeconds(3); private static ConcurrentQueue queue = new ConcurrentQueue(); public static void ProcessDelegates() { while (queue.TryDequeue(out var action)) { try { action(); } catch (Exception ex) { Debug.LogException(ex); } } } public static void Async(Action action) { if (UnityThread.allowsAPI) { action(); return; } queue.Enqueue(action); } public static void Await(Action action) { Await(action, defaultTimeout); } public static void AwaitForever(Action action) { Await(action, null); } private static void Await(Action action, TimeSpan? timeout) { if (UnityThread.allowsAPI) { action(); return; } var are = new AutoResetEvent(false); Exception exception = null; queue.Enqueue(() => { try { action(); } catch (Exception ex) { exception = ex; } finally { are.Set(); } }); if (timeout.HasValue) { if (!are.WaitOne(timeout.Value)) { throw new TimeoutException("Time-out exceeded on Unity API thread action delegate. Potential deadlock."); } } else { are.WaitOne(); } if (exception != null) { throw exception; } } public static T Await(Func func) { return Await(func, defaultTimeout); } public static T AwaitForever(Func func) { return Await(func, null); } public static T Await(Func func, TimeSpan? timeout) { if (UnityThread.allowsAPI) { return func(); } var are = new AutoResetEvent(false); Exception exception = null; // Define as object for boxing object result = default(T); queue.Enqueue(() => { try { result = func(); } catch (Exception ex) { exception = ex; } finally { are.Set(); } }); if (timeout.HasValue) { if (!are.WaitOne(timeout.Value)) { throw new TimeoutException("Time-out exceeded on Unity API thread function delegate. Potential deadlock."); } } else { are.WaitOne(); } if (exception != null) { throw exception; } return (T)result; } } }