#if DEVELOPMENT_BUILD || UNITY_EDITOR
#define LITMOTION_DEBUG
#endif
using System;
using System.Collections;
using System.Runtime.CompilerServices;
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 valid.
///
/// This motion handle
/// True if motion is valid, otherwise false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsValid(this MotionHandle handle)
{
return MotionManager.IsValid(handle);
}
///
/// Checks if a motion is active.
///
/// This motion handle
/// True if motion is active, otherwise false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsActive(this MotionHandle handle)
{
return MotionManager.IsActive(handle);
}
///
/// Checks if a motion is currently playing.
///
/// This motion handle
/// True if motion is playing, otherwise false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPlaying(this MotionHandle handle)
{
return MotionManager.IsPlaying(handle);
}
///
/// Gets the debug name set for the MotionHandle. If not specified, returns the result of ToString().
///
/// This motion handle
/// Debug name
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetDebugName(this MotionHandle handle)
{
#if LITMOTION_DEBUG
return MotionManager.GetManagedDataRef(handle, false).DebugName ?? handle.ToString();
#else
return handle.ToString();
#endif
}
///
/// Preserves the MotionHandle so that it is not destroyed until Cancel() is explicitly called.
///
/// This motion handle
/// Returns itself for method chaining
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MotionHandle Preserve(this MotionHandle handle)
{
MotionManager.GetDataRef(handle).State.IsPreserved = true;
return handle;
}
///
/// Complete motion.
///
/// This motion handle
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Complete(this MotionHandle handle)
{
MotionManager.Complete(handle);
}
///
/// Attempt to complete the motion.
///
/// This motion handle
/// Returns true if the operation was successful.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryComplete(this MotionHandle handle)
{
return MotionManager.TryComplete(handle);
}
///
/// Cancel motion.
///
/// This motion handle
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Cancel(this MotionHandle handle)
{
MotionManager.Cancel(handle);
}
///
/// Attempt to cancel the motion.
///
/// This motion handle
/// Returns true if the operation was successful.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryCancel(this MotionHandle handle)
{
return MotionManager.TryCancel(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, LinkBehavior.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, LinkBehavior 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, LinkBehavior.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, LinkBehavior 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
/// Behavior when disposing
/// Disposable motion
public static IDisposable ToDisposable(this MotionHandle handle, DisposeBehavior disposeBehavior = DisposeBehavior.Cancel)
{
return new MotionHandleDisposable(handle, disposeBehavior);
}
///
/// Wait for the motion to finish in a coroutine.
///
/// This motion handle
///
public static IEnumerator ToYieldInstruction(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 = ValueTaskMotionTaskSource.Create(handle, CancelBehavior.Cancel, true, 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, CancelBehavior cancelBehavior, CancellationToken cancellationToken = default)
{
if (!handle.IsActive()) return default;
var source = ValueTaskMotionTaskSource.Create(handle, cancelBehavior, true, cancellationToken, out var token);
return new ValueTask(source, token);
}
///
/// Convert motion handle to ValueTask.
///
/// This motion handle
/// Behavior when canceling
/// Whether to link MotionHandle.Cancel() to task cancellation
/// CancellationToken
///
public static ValueTask ToValueTask(this MotionHandle handle, CancelBehavior cancelBehavior, bool cancelAwaitOnMotionCanceled, CancellationToken cancellationToken = default)
{
if (!handle.IsActive()) return default;
var source = ValueTaskMotionTaskSource.Create(handle, cancelBehavior, cancelAwaitOnMotionCanceled, 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 AwaitableMotionTaskSource.CompletedSource.Awaitable;
return AwaitableMotionTaskSource.Create(handle, CancelBehavior.Cancel, true, cancellationToken).Awaitable;
}
///
/// Convert motion handle to Awaitable.
///
/// This motion handle
/// Behavior when canceling
/// CancellationToken
///
public static Awaitable ToAwaitable(this MotionHandle handle, CancelBehavior cancelBehavior, CancellationToken cancellationToken = default)
{
if (!handle.IsActive()) return AwaitableMotionTaskSource.CompletedSource.Awaitable;
return AwaitableMotionTaskSource.Create(handle, cancelBehavior, true, cancellationToken).Awaitable;
}
///
/// Convert motion handle to Awaitable.
///
/// This motion handle
/// Behavior when canceling
/// Whether to link MotionHandle.Cancel() to task cancellation
/// CancellationToken
///
public static Awaitable ToAwaitable(this MotionHandle handle, CancelBehavior cancelBehavior, bool cancelAwaitOnMotionCanceled, CancellationToken cancellationToken = default)
{
if (!handle.IsActive()) return AwaitableMotionTaskSource.CompletedSource.Awaitable;
return AwaitableMotionTaskSource.Create(handle, cancelBehavior, cancelAwaitOnMotionCanceled, cancellationToken).Awaitable;
}
#endif
}
///
/// Specifies the behavior when the motion converted to IDisposable is disposed.
///
public enum DisposeBehavior
{
Cancel,
Complete,
}
internal sealed class MotionHandleDisposable : IDisposable
{
public MotionHandleDisposable(MotionHandle handle, DisposeBehavior disposeBehavior)
{
this.handle = handle;
this.disposeBehavior = disposeBehavior;
}
public readonly MotionHandle handle;
public readonly DisposeBehavior disposeBehavior;
public void Dispose()
{
switch (disposeBehavior)
{
case DisposeBehavior.Cancel:
handle.TryCancel();
break;
case DisposeBehavior.Complete:
handle.TryComplete();
break;
}
}
}
}