using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace LitMotion
{
///
/// Provides functionality for tracking active motions.
///
public static class MotionTracker
{
public static bool EnableTracking = false;
public static bool EnableStackTrace = false;
public static IReadOnlyList Items => trackings;
static readonly List trackings = new(16);
public static void AddTracking(MotionHandle motionHandle, IMotionScheduler scheduler, int skipFrames = 3)
{
var state = TrackingState.Create();
(state.ValueType, state.OptionsType, state.AdapterType) = MotionStorageManager.GetMotionType(motionHandle);
state.Scheduler = scheduler;
state.CreationTime = DateTime.UtcNow;
#if UNITY_EDITOR
state.CreatedOnEditor = UnityEditor.EditorApplication.isPlaying;
#endif
if (EnableStackTrace) state.StackTrace = new StackTrace(skipFrames, true);
ref var callbackData = ref MotionStorageManager.GetMotionCallbackDataRef(motionHandle);
state.OriginalOnCompleteCallback = callbackData.OnCompleteAction;
callbackData.OnCompleteAction = state.OnCompleteDelegate;
state.OriginalOnCancelCallback = callbackData.OnCancelAction;
callbackData.OnCancelAction = state.OnCancelDelegate;
trackings.Add(state);
}
public static void Clear()
{
trackings.Clear();
}
public sealed class TrackingState
{
static readonly Stack pool = new(16);
TrackingState()
{
OnCompleteDelegate = OnComplete;
OnCancelDelegate = OnCancel;
}
public static TrackingState Create()
{
if (!pool.TryPop(out var state))
{
state = new();
}
return state;
}
public Type ValueType;
public Type OptionsType;
public Type AdapterType;
public IMotionScheduler Scheduler;
public DateTime CreationTime;
public StackTrace StackTrace;
public bool CreatedOnEditor;
public Action OriginalOnCompleteCallback;
public Action OriginalOnCancelCallback;
public readonly Action OnCompleteDelegate;
public readonly Action OnCancelDelegate;
void OnComplete()
{
try
{
OriginalOnCompleteCallback?.Invoke();
}
catch (Exception ex)
{
MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex);
}
Release();
}
void OnCancel()
{
try
{
OriginalOnCancelCallback?.Invoke();
}
catch (Exception ex)
{
MotionDispatcher.GetUnhandledExceptionHandler()?.Invoke(ex);
}
Release();
}
void Release()
{
trackings.Remove(this);
ValueType = default;
OptionsType = default;
AdapterType = default;
Scheduler = default;
CreationTime = default;
StackTrace = default;
CreatedOnEditor = default;
OriginalOnCompleteCallback = default;
OriginalOnCancelCallback = default;
pool.Push(this);
}
}
}
}