using System; using System.Collections; using System.Threading; using System.Threading.Tasks; using UnityEngine; namespace LitMotion { /// /// Provides methods for manipulating the motion entity pointed to by MotionHandle. /// public static class MotionHandleExtensions { /// /// Checks if a motion is currently playing. /// /// This motion handle /// True if motion is active, otherwise false. public static bool IsActive(this MotionHandle handle) { return MotionStorageManager.IsActive(handle); } /// /// Complete motion. /// /// This motion handle public static void Complete(this MotionHandle handle) { MotionStorageManager.CompleteMotion(handle); } /// /// Cancel motion. /// /// This motion handle public static void Cancel(this MotionHandle handle) { MotionStorageManager.CancelMotion(handle); } /// /// Add this motion handle to CompositeMotionHandle. /// /// This motion handle /// target CompositeMotionHandle public static MotionHandle AddTo(this MotionHandle handle, CompositeMotionHandle compositeMotionHandle) { compositeMotionHandle.Add(handle); return handle; } /// /// Link the motion lifecycle to the target object. /// /// This motion handle /// Target object public static MotionHandle AddTo(this MotionHandle handle, GameObject target) { GetOrAddComponent(target).Register(handle, LinkBehaviour.CancelOnDestroy); return handle; } /// /// Link the motion lifecycle to the target object. /// /// This motion handle /// Target object /// Link behaviour public static MotionHandle AddTo(this MotionHandle handle, GameObject target, LinkBehaviour linkBehaviour) { GetOrAddComponent(target).Register(handle, linkBehaviour); return handle; } /// /// Link the motion lifecycle to the target object. /// /// This motion handle /// Target object public static MotionHandle AddTo(this MotionHandle handle, Component target) { GetOrAddComponent(target.gameObject).Register(handle, LinkBehaviour.CancelOnDestroy); return handle; } /// /// Link the motion lifecycle to the target object. /// /// This motion handle /// Target object /// Link behaviour public static MotionHandle AddTo(this MotionHandle handle, Component target, LinkBehaviour linkBehaviour) { GetOrAddComponent(target.gameObject).Register(handle, linkBehaviour); return handle; } #if UNITY_2022_2_OR_NEWER /// /// Link the motion lifecycle to the target object. /// /// This motion handle /// Target object public static MotionHandle AddTo(this MotionHandle handle, MonoBehaviour target) { target.destroyCancellationToken.Register(() => { if (handle.IsActive()) handle.Cancel(); }, false); return handle; } #endif static TComponent GetOrAddComponent(GameObject target) where TComponent : Component { if (!target.TryGetComponent(out var component)) { component = target.AddComponent(); } return component; } /// /// Convert MotionHandle to IDisposable. /// /// This motion handle /// public static IDisposable ToDisposable(this MotionHandle handle) { return new MotionHandleDisposable(handle); } /// /// Wait for the motion to finish in a coroutine. /// /// This motion handle /// public static IEnumerator ToYieldInteraction(this MotionHandle handle) { while (handle.IsActive()) { yield return null; } } public static MotionAwaiter GetAwaiter(this MotionHandle handle) { return new MotionAwaiter(handle); } /// /// Convert motion handle to ValueTask. /// /// This motion handle /// CancellationToken /// public static ValueTask ToValueTask(this MotionHandle handle, CancellationToken cancellationToken = default) { if (!handle.IsActive()) return default; var source = ValueTaskMotionConfiguredSource.Create(handle, CancelBehaviour.CancelAndCancelAwait, cancellationToken, out var token); return new ValueTask(source, token); } /// /// Convert motion handle to ValueTask. /// /// This motion handle /// Behavior when canceling /// CancellationToken /// public static ValueTask ToValueTask(this MotionHandle handle, CancelBehaviour cancelBehaviour, CancellationToken cancellationToken = default) { if (!handle.IsActive()) return default; var source = ValueTaskMotionConfiguredSource.Create(handle, cancelBehaviour, cancellationToken, out var token); return new ValueTask(source, token); } #if UNITY_2023_1_OR_NEWER /// /// Convert motion handle to Awaitable. /// /// This motion handle /// CancellationToken /// public static Awaitable ToAwaitable(this MotionHandle handle, CancellationToken cancellationToken = default) { if (!handle.IsActive()) return AwaitableMotionConfiguredSource.CompletedSource.Awaitable; return AwaitableMotionConfiguredSource.Create(handle, CancelBehaviour.CancelAndCancelAwait, cancellationToken).Awaitable; } /// /// Convert motion handle to Awaitable. /// /// This motion handle /// Behavior when canceling /// CancellationToken /// public static Awaitable ToAwaitable(this MotionHandle handle, CancelBehaviour cancelBehaviour, CancellationToken cancellationToken = default) { if (!handle.IsActive()) return AwaitableMotionConfiguredSource.CompletedSource.Awaitable; return AwaitableMotionConfiguredSource.Create(handle, cancelBehaviour, cancellationToken).Awaitable; } #endif } internal sealed class MotionHandleDisposable : IDisposable { public MotionHandleDisposable(MotionHandle handle) => this.handle = handle; public readonly MotionHandle handle; public void Dispose() { if (handle.IsActive()) handle.Cancel(); } } }