using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using UnityEditor; namespace io.github.hatayama.uLoopMCP { /// /// Timer-based asynchronous delay for Unity Editor /// Provides async/await support for time-based delays that work regardless of Unity Editor state /// public static class TimerDelay { /// /// Wait for the specified number of milliseconds /// /// Milliseconds to wait /// Cancellation token /// Awaitable task public static Task Wait(int milliseconds, CancellationToken cancellationToken = default) { if (milliseconds <= 0) { return Task.CompletedTask; } TaskCompletionSource tcs = new TaskCompletionSource(); Timer timer = null; timer = new Timer(_ => { timer?.Dispose(); timer = null; if (!cancellationToken.IsCancellationRequested) { tcs.SetResult(true); } else { tcs.SetCanceled(); } }, null, milliseconds, Timeout.Infinite); // Handle cancellation if (cancellationToken.CanBeCanceled) { cancellationToken.Register(() => { timer?.Dispose(); timer = null; tcs.TrySetCanceled(); }); } return tcs.Task; } /// /// Wait for the specified number of milliseconds, then execute action on main thread /// /// Milliseconds to wait /// Action to execute on main thread /// Cancellation token /// Awaitable task public static Task WaitThenExecuteOnMainThread(int milliseconds, Action action, CancellationToken cancellationToken = default) { if (action == null) throw new ArgumentNullException(nameof(action)); if (milliseconds <= 0) { EditorApplication.delayCall += () => action(); return Task.CompletedTask; } TaskCompletionSource tcs = new TaskCompletionSource(); Timer timer = null; timer = new Timer(_ => { timer?.Dispose(); timer = null; if (!cancellationToken.IsCancellationRequested) { EditorApplication.delayCall += () => { try { action(); tcs.SetResult(true); } catch (Exception ex) { tcs.SetException(ex); } }; } else { tcs.SetCanceled(); } }, null, milliseconds, Timeout.Infinite); // Handle cancellation if (cancellationToken.CanBeCanceled) { cancellationToken.Register(() => { timer?.Dispose(); timer = null; tcs.TrySetCanceled(); }); } return tcs.Task; } } }