using System; using UnityEditor; namespace Nullframes.Intrigues.EDITOR.Utils { /// /// A lightweight routine executor for editor scripts that waits for a delay and/or a condition before executing an action. /// public sealed class IERoutine : IDisposable { private readonly Func< bool > waitUntil; private readonly Action callback; private readonly double nextExecutionTime; private bool isDisposed; public IERoutine(Action callback, float delay, Func< bool > waitUntil) { this.callback = callback ?? throw new ArgumentNullException(nameof( callback )); this.waitUntil = waitUntil; nextExecutionTime = EditorApplication.timeSinceStartup + delay; } public void Update() { if ( isDisposed ) return; double currentTime = EditorApplication.timeSinceStartup; if ( currentTime < nextExecutionTime ) return; if ( waitUntil == null || waitUntil.Invoke() ) { callback?.Invoke(); Dispose(); } } public void Dispose() { if ( isDisposed ) return; EditorApplication.update -= Update; isDisposed = true; } } public static class EditorRoutine { /// /// Starts a routine that waits for a specified delay before invoking the action. /// public static IERoutine StartRoutine(float delay, Action call) => CreateRoutine(new IERoutine(call, delay, null)); /// /// Starts a routine that waits until a condition is met before invoking the action. /// public static IERoutine StartRoutine(Func< bool > waitUntil, Action call) => CreateRoutine(new IERoutine(call, 0f, waitUntil)); /// /// Starts a routine that waits for both a delay and a condition before invoking the action. /// public static IERoutine StartRoutine(float delay, Func< bool > waitUntil, Action call) => CreateRoutine(new IERoutine(call, delay, waitUntil)); /// /// Starts a routine that waits for a condition and then a delay before invoking the action. /// public static IERoutine StartRoutine(Func< bool > waitUntil, float delay, Action call) => CreateRoutine(new IERoutine(call, delay, waitUntil)); /// /// Invokes the callback once on the next editor frame, similar to EditorApplication.delayCall. /// public static void CallNextFrame(Action callback) { if ( callback == null ) return; void OnUpdate() { EditorApplication.update -= OnUpdate; callback.Invoke(); } EditorApplication.update += OnUpdate; } /// /// Stops and disposes the specified routine if it is not null. /// public static void StopRoutine(IERoutine routine) { routine?.Dispose(); } private static IERoutine CreateRoutine(IERoutine routine) { EditorApplication.update += routine.Update; return routine; } } }