2025-09-05 19:46:30 +08:00
|
|
|
using System;
|
2025-12-24 14:34:26 +08:00
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using Unity.IL2CPP.CompilerServices;
|
2025-09-05 19:46:30 +08:00
|
|
|
using UnityEngine;
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
namespace AlicizaX.Timer.Runtime
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
public delegate void TimerHandlerNoArgs();
|
2026-04-24 20:50:13 +08:00
|
|
|
internal delegate void TimerGenericInvoker(object handler, object arg);
|
2026-03-24 17:45:15 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
internal static class TimerGenericInvokerCache<T> where T : class
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
|
|
|
|
public static readonly TimerGenericInvoker Invoke = InvokeGeneric;
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private static void InvokeGeneric(object handler, object arg)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
((Action<T>)handler).Invoke((T)arg);
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
2026-04-24 20:50:13 +08:00
|
|
|
internal struct TimerInfo
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
|
|
|
|
public int TimerId;
|
2026-04-24 20:50:13 +08:00
|
|
|
public int Version;
|
|
|
|
|
public int QueueIndex;
|
|
|
|
|
public int ActiveIndex;
|
2025-09-05 19:46:30 +08:00
|
|
|
public float TriggerTime;
|
2026-04-24 20:50:13 +08:00
|
|
|
public float Duration;
|
|
|
|
|
public float RemainingTime;
|
|
|
|
|
public TimerHandlerNoArgs NoArgsHandler;
|
2026-03-24 17:45:15 +08:00
|
|
|
public TimerGenericInvoker GenericInvoker;
|
2026-04-24 20:50:13 +08:00
|
|
|
public object GenericHandler;
|
|
|
|
|
public object GenericArg;
|
2025-09-05 19:46:30 +08:00
|
|
|
public bool IsLoop;
|
|
|
|
|
public bool IsRunning;
|
|
|
|
|
public bool IsUnscaled;
|
2025-12-24 14:34:26 +08:00
|
|
|
public bool IsActive;
|
2026-03-16 20:52:55 +08:00
|
|
|
public byte HandlerType;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
public float CreationTime;
|
|
|
|
|
#endif
|
2025-12-24 14:34:26 +08:00
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2025-09-05 19:46:30 +08:00
|
|
|
public void Clear()
|
|
|
|
|
{
|
2026-03-24 17:45:15 +08:00
|
|
|
TimerId = 0;
|
2026-04-24 20:50:13 +08:00
|
|
|
QueueIndex = -1;
|
|
|
|
|
ActiveIndex = -1;
|
2026-03-24 17:45:15 +08:00
|
|
|
TriggerTime = 0f;
|
2026-04-24 20:50:13 +08:00
|
|
|
Duration = 0f;
|
|
|
|
|
RemainingTime = 0f;
|
|
|
|
|
NoArgsHandler = null;
|
2026-03-24 17:45:15 +08:00
|
|
|
GenericInvoker = null;
|
2026-04-24 20:50:13 +08:00
|
|
|
GenericHandler = null;
|
|
|
|
|
GenericArg = null;
|
2026-03-24 17:45:15 +08:00
|
|
|
IsLoop = false;
|
|
|
|
|
IsRunning = false;
|
|
|
|
|
IsUnscaled = false;
|
2025-09-05 19:46:30 +08:00
|
|
|
IsActive = false;
|
2026-04-24 20:50:13 +08:00
|
|
|
HandlerType = 0;
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
CreationTime = 0f;
|
|
|
|
|
#endif
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[UnityEngine.Scripting.Preserve]
|
2025-12-24 14:34:26 +08:00
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
2026-04-24 20:50:13 +08:00
|
|
|
internal sealed class TimerService : ServiceBase, ITimerService, IServiceTickable, ITimerServiceDebugView
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
private const int MAX_CAPACITY = 256;
|
|
|
|
|
private const int HANDLE_INDEX_BITS = 9;
|
|
|
|
|
private const int HANDLE_INDEX_MASK = MAX_CAPACITY - 1;
|
|
|
|
|
private const int HANDLE_VERSION_MASK = 0x3FFFFF;
|
|
|
|
|
private const float MINIMUM_DELAY = 0.0001f;
|
|
|
|
|
private const byte HANDLER_NO_ARGS = 0;
|
|
|
|
|
private const byte HANDLER_GENERIC = 1;
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
private const float LEAK_DETECTION_THRESHOLD = 300f;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private readonly TimerInfo[] _timerPool;
|
|
|
|
|
private readonly int[] _freeIndices;
|
|
|
|
|
private readonly int[] _activeIndices;
|
|
|
|
|
private readonly TimerQueue _scaledQueue;
|
|
|
|
|
private readonly TimerQueue _unscaledQueue;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
|
|
|
|
private int _freeCount;
|
2026-04-24 20:50:13 +08:00
|
|
|
private int _activeCount;
|
|
|
|
|
private int _peakActiveCount;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
private sealed class TimerQueue
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
private readonly TimerService _owner;
|
|
|
|
|
private readonly int[] _heap;
|
|
|
|
|
private int _count;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
public TimerQueue(TimerService owner)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
_owner = owner;
|
|
|
|
|
_heap = new int[MAX_CAPACITY];
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Add(int poolIndex)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _owner._timerPool[poolIndex];
|
|
|
|
|
int index = _count++;
|
|
|
|
|
_heap[index] = poolIndex;
|
|
|
|
|
timer.QueueIndex = index;
|
|
|
|
|
BubbleUp(index);
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
public void Remove(int poolIndex)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _owner._timerPool[poolIndex];
|
|
|
|
|
int index = timer.QueueIndex;
|
|
|
|
|
if ((uint)index >= (uint)_count)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
timer.QueueIndex = -1;
|
|
|
|
|
return;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
int lastIndex = --_count;
|
|
|
|
|
int lastPoolIndex = _heap[lastIndex];
|
|
|
|
|
timer.QueueIndex = -1;
|
|
|
|
|
|
|
|
|
|
if (index == lastIndex)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
_heap[index] = lastPoolIndex;
|
|
|
|
|
_owner._timerPool[lastPoolIndex].QueueIndex = index;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (!BubbleUp(index))
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
BubbleDown(index);
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
public void Advance(float currentTime)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
while (_count > 0)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = _heap[0];
|
|
|
|
|
ref TimerInfo timer = ref _owner._timerPool[poolIndex];
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (!timer.IsActive || !timer.IsRunning)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
RemoveRoot();
|
|
|
|
|
continue;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
if (timer.TriggerTime > currentTime)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RemoveRoot();
|
|
|
|
|
_owner.ProcessDueTimer(poolIndex, currentTime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
|
|
|
|
while (_count > 0)
|
|
|
|
|
{
|
|
|
|
|
int poolIndex = _heap[--_count];
|
|
|
|
|
_owner._timerPool[poolIndex].QueueIndex = -1;
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-03-24 17:45:15 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private void RemoveRoot()
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int rootPoolIndex = _heap[0];
|
|
|
|
|
int lastIndex = --_count;
|
|
|
|
|
_owner._timerPool[rootPoolIndex].QueueIndex = -1;
|
|
|
|
|
|
|
|
|
|
if (lastIndex <= 0)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
|
|
|
|
return;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2026-03-24 17:45:15 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int lastPoolIndex = _heap[lastIndex];
|
|
|
|
|
_heap[0] = lastPoolIndex;
|
|
|
|
|
_owner._timerPool[lastPoolIndex].QueueIndex = 0;
|
|
|
|
|
BubbleDown(0);
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private bool BubbleUp(int index)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
bool moved = false;
|
|
|
|
|
while (index > 0)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int parent = (index - 1) >> 1;
|
|
|
|
|
if (!Less(_heap[index], _heap[parent]))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Swap(index, parent);
|
|
|
|
|
index = parent;
|
|
|
|
|
moved = true;
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
return moved;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void BubbleDown(int index)
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int left = (index << 1) + 1;
|
|
|
|
|
if (left >= _count)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int right = left + 1;
|
|
|
|
|
int smallest = left;
|
|
|
|
|
if (right < _count && Less(_heap[right], _heap[left]))
|
|
|
|
|
{
|
|
|
|
|
smallest = right;
|
|
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (!Less(_heap[smallest], _heap[index]))
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
Swap(index, smallest);
|
|
|
|
|
index = smallest;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-25 10:50:14 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private bool Less(int leftPoolIndex, int rightPoolIndex)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo left = ref _owner._timerPool[leftPoolIndex];
|
|
|
|
|
ref TimerInfo right = ref _owner._timerPool[rightPoolIndex];
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (left.TriggerTime < right.TriggerTime)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return true;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (left.TriggerTime > right.TriggerTime)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return false;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
return left.TimerId < right.TimerId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void Swap(int leftIndex, int rightIndex)
|
|
|
|
|
{
|
|
|
|
|
int leftPoolIndex = _heap[leftIndex];
|
|
|
|
|
int rightPoolIndex = _heap[rightIndex];
|
|
|
|
|
|
|
|
|
|
_heap[leftIndex] = rightPoolIndex;
|
|
|
|
|
_heap[rightIndex] = leftPoolIndex;
|
|
|
|
|
|
|
|
|
|
_owner._timerPool[leftPoolIndex].QueueIndex = rightIndex;
|
|
|
|
|
_owner._timerPool[rightPoolIndex].QueueIndex = leftIndex;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 16:14:05 +08:00
|
|
|
public TimerService()
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
_timerPool = new TimerInfo[MAX_CAPACITY];
|
|
|
|
|
_freeIndices = new int[MAX_CAPACITY];
|
|
|
|
|
_activeIndices = new int[MAX_CAPACITY];
|
|
|
|
|
_scaledQueue = new TimerQueue(this);
|
|
|
|
|
_unscaledQueue = new TimerQueue(this);
|
|
|
|
|
|
|
|
|
|
_freeCount = MAX_CAPACITY;
|
|
|
|
|
for (int i = 0; i < MAX_CAPACITY; i++)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
|
|
|
|
_freeIndices[i] = i;
|
2026-04-24 20:50:13 +08:00
|
|
|
_timerPool[i].QueueIndex = -1;
|
|
|
|
|
_timerPool[i].ActiveIndex = -1;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public int AddTimer(TimerHandlerNoArgs callback, float time, bool isLoop = false, bool isUnscaled = false)
|
|
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
if (callback == null)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = AcquireTimerIndex();
|
|
|
|
|
if (poolIndex < 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
InitializeTimer(poolIndex, time, isLoop, isUnscaled);
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
timer.HandlerType = HANDLER_NO_ARGS;
|
|
|
|
|
timer.NoArgsHandler = callback;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
AddToActiveSet(poolIndex);
|
|
|
|
|
ScheduleTimer(poolIndex);
|
2025-12-24 14:34:26 +08:00
|
|
|
return timer.TimerId;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
public int AddTimer<T>(Action<T> callback, T arg, float time, bool isLoop = false, bool isUnscaled = false) where T : class
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
if (callback == null)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = AcquireTimerIndex();
|
|
|
|
|
if (poolIndex < 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
InitializeTimer(poolIndex, time, isLoop, isUnscaled);
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
timer.HandlerType = HANDLER_GENERIC;
|
|
|
|
|
timer.GenericInvoker = TimerGenericInvokerCache<T>.Invoke;
|
|
|
|
|
timer.GenericHandler = callback;
|
|
|
|
|
timer.GenericArg = arg;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
AddToActiveSet(poolIndex);
|
|
|
|
|
ScheduleTimer(poolIndex);
|
2025-12-24 14:34:26 +08:00
|
|
|
return timer.TimerId;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Stop(int timerId)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
if (poolIndex < 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
if (!timer.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (timer.QueueIndex >= 0)
|
|
|
|
|
{
|
|
|
|
|
GetQueue(timer.IsUnscaled).Remove(poolIndex);
|
|
|
|
|
float currentTime = GetCurrentTime(timer.IsUnscaled);
|
|
|
|
|
float remainingTime = timer.TriggerTime - currentTime;
|
|
|
|
|
timer.RemainingTime = remainingTime > MINIMUM_DELAY ? remainingTime : MINIMUM_DELAY;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
timer.RemainingTime = timer.IsLoop ? timer.Duration : MINIMUM_DELAY;
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
timer.IsRunning = false;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
public void Resume(int timerId)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
if (poolIndex < 0)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
if (timer.IsRunning)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
float delay = timer.RemainingTime > MINIMUM_DELAY ? timer.RemainingTime : MINIMUM_DELAY;
|
|
|
|
|
timer.TriggerTime = GetCurrentTime(timer.IsUnscaled) + delay;
|
|
|
|
|
timer.RemainingTime = 0f;
|
|
|
|
|
timer.IsRunning = true;
|
|
|
|
|
ScheduleTimer(poolIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool IsRunning(int timerId)
|
|
|
|
|
{
|
|
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
return poolIndex >= 0 && _timerPool[poolIndex].IsRunning;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
public float GetLeftTime(int timerId)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
if (poolIndex < 0)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return 0f;
|
|
|
|
|
}
|
2026-03-24 17:45:15 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
if (!timer.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
return timer.RemainingTime;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
float leftTime = timer.TriggerTime - GetCurrentTime(timer.IsUnscaled);
|
|
|
|
|
return leftTime > 0f ? leftTime : 0f;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
public void Restart(int timerId)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
if (poolIndex < 0)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
if (timer.QueueIndex >= 0)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
GetQueue(timer.IsUnscaled).Remove(poolIndex);
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
timer.TriggerTime = GetCurrentTime(timer.IsUnscaled) + timer.Duration;
|
|
|
|
|
timer.RemainingTime = 0f;
|
|
|
|
|
timer.IsRunning = true;
|
|
|
|
|
ScheduleTimer(poolIndex);
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
public void RemoveTimer(int timerId)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
if (poolIndex >= 0)
|
2026-03-24 17:45:15 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
ReleaseTimer(poolIndex);
|
2026-03-24 17:45:15 +08:00
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
void IServiceTickable.Tick(float deltaTime)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
_scaledQueue.Advance(Time.time);
|
|
|
|
|
_unscaledQueue.Advance(Time.unscaledTime);
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
protected override void OnInitialize()
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
protected override void OnDestroyService()
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
RemoveAllTimers();
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
public int Order => 0;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
void ITimerServiceDebugView.GetStatistics(out int activeCount, out int poolCapacity, out int peakActiveCount, out int freeCount)
|
|
|
|
|
{
|
|
|
|
|
activeCount = _activeCount;
|
|
|
|
|
poolCapacity = MAX_CAPACITY;
|
|
|
|
|
peakActiveCount = _peakActiveCount;
|
|
|
|
|
freeCount = _freeCount;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int ITimerServiceDebugView.GetAllTimers(TimerDebugInfo[] results)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
if (results == null || results.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int count = _activeCount < results.Length ? _activeCount : results.Length;
|
|
|
|
|
float currentTime = Time.time;
|
|
|
|
|
float currentUnscaledTime = Time.unscaledTime;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
FillDebugInfo(_activeIndices[i], ref results[i], currentTime, currentUnscaledTime);
|
|
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
return count;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
int ITimerServiceDebugView.GetStaleOneShotTimers(TimerDebugInfo[] results)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
if (results == null || results.Length == 0)
|
2025-12-25 10:50:14 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return 0;
|
2025-12-25 10:50:14 +08:00
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
int count = 0;
|
|
|
|
|
float realtimeSinceStartup = Time.realtimeSinceStartup;
|
|
|
|
|
float currentTime = Time.time;
|
|
|
|
|
float currentUnscaledTime = Time.unscaledTime;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
for (int i = 0; i < _activeCount && count < results.Length; i++)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
int poolIndex = _activeIndices[i];
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
if (timer.IsLoop)
|
2025-12-24 14:34:26 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
2026-03-24 17:45:15 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (realtimeSinceStartup - timer.CreationTime <= LEAK_DETECTION_THRESHOLD)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
2025-12-24 14:34:26 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
FillDebugInfo(poolIndex, ref results[count], currentTime, currentUnscaledTime);
|
|
|
|
|
count++;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2026-03-24 17:45:15 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
return count;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
#endif
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private int AcquireTimerIndex()
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
if (_freeCount <= 0)
|
2025-12-25 10:50:14 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return -1;
|
|
|
|
|
}
|
2026-03-24 17:45:15 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
return _freeIndices[--_freeCount];
|
|
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void InitializeTimer(int poolIndex, float time, bool isLoop, bool isUnscaled)
|
|
|
|
|
{
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
float duration = NormalizeDelay(time);
|
|
|
|
|
float currentTime = GetCurrentTime(isUnscaled);
|
|
|
|
|
|
|
|
|
|
int version = NextVersion(timer.Version);
|
|
|
|
|
timer.Version = version;
|
|
|
|
|
timer.TimerId = ComposeTimerId(poolIndex, version);
|
|
|
|
|
timer.TriggerTime = currentTime + duration;
|
|
|
|
|
timer.Duration = duration;
|
|
|
|
|
timer.RemainingTime = 0f;
|
|
|
|
|
timer.NoArgsHandler = null;
|
|
|
|
|
timer.GenericInvoker = null;
|
|
|
|
|
timer.GenericHandler = null;
|
|
|
|
|
timer.GenericArg = null;
|
|
|
|
|
timer.IsLoop = isLoop;
|
|
|
|
|
timer.IsRunning = true;
|
|
|
|
|
timer.IsUnscaled = isUnscaled;
|
|
|
|
|
timer.IsActive = true;
|
|
|
|
|
timer.HandlerType = HANDLER_NO_ARGS;
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
timer.CreationTime = Time.realtimeSinceStartup;
|
|
|
|
|
#endif
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void RemoveAllTimers()
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
while (_activeCount > 0)
|
|
|
|
|
{
|
|
|
|
|
ReleaseTimer(_activeIndices[_activeCount - 1]);
|
|
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
_scaledQueue.Clear();
|
|
|
|
|
_unscaledQueue.Clear();
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private void ProcessDueTimer(int poolIndex, float currentTime)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
if (!timer.IsActive)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool shouldRemoveAfterCallback = !timer.IsLoop;
|
|
|
|
|
|
|
|
|
|
switch (timer.HandlerType)
|
|
|
|
|
{
|
|
|
|
|
case HANDLER_NO_ARGS:
|
|
|
|
|
timer.NoArgsHandler();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HANDLER_GENERIC:
|
|
|
|
|
timer.GenericInvoker(timer.GenericHandler, timer.GenericArg);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!timer.IsActive)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (timer.QueueIndex >= 0)
|
|
|
|
|
{
|
2025-12-25 10:50:14 +08:00
|
|
|
return;
|
2026-04-24 20:50:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shouldRemoveAfterCallback)
|
|
|
|
|
{
|
|
|
|
|
ReleaseTimer(poolIndex);
|
|
|
|
|
}
|
|
|
|
|
else if (timer.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
timer.TriggerTime = currentTime + timer.Duration;
|
|
|
|
|
ScheduleTimer(poolIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void ScheduleTimer(int poolIndex)
|
|
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
2025-12-25 10:50:14 +08:00
|
|
|
if (!timer.IsActive || !timer.IsRunning)
|
2026-04-24 20:50:13 +08:00
|
|
|
{
|
2025-12-25 10:50:14 +08:00
|
|
|
return;
|
2026-04-24 20:50:13 +08:00
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (timer.QueueIndex >= 0)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
float currentTime = GetCurrentTime(timer.IsUnscaled);
|
|
|
|
|
if (timer.TriggerTime <= currentTime)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
timer.TriggerTime = currentTime + MINIMUM_DELAY;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
GetQueue(timer.IsUnscaled).Add(poolIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void ReleaseTimer(int poolIndex)
|
|
|
|
|
{
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
2025-12-25 10:50:14 +08:00
|
|
|
if (!timer.IsActive)
|
2026-04-24 20:50:13 +08:00
|
|
|
{
|
2025-12-25 10:50:14 +08:00
|
|
|
return;
|
2026-04-24 20:50:13 +08:00
|
|
|
}
|
2025-12-25 10:50:14 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
if (timer.QueueIndex >= 0)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
GetQueue(timer.IsUnscaled).Remove(poolIndex);
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
RemoveFromActiveSet(poolIndex);
|
|
|
|
|
timer.Clear();
|
|
|
|
|
_freeIndices[_freeCount++] = poolIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void AddToActiveSet(int poolIndex)
|
|
|
|
|
{
|
|
|
|
|
int position = _activeCount;
|
|
|
|
|
_activeIndices[position] = poolIndex;
|
|
|
|
|
_timerPool[poolIndex].ActiveIndex = position;
|
|
|
|
|
_activeCount = position + 1;
|
|
|
|
|
|
|
|
|
|
if (_activeCount > _peakActiveCount)
|
2025-09-05 19:46:30 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
_peakActiveCount = _activeCount;
|
2025-12-25 10:50:14 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private void RemoveFromActiveSet(int poolIndex)
|
2025-12-25 10:50:14 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
int position = timer.ActiveIndex;
|
|
|
|
|
if ((uint)position >= (uint)_activeCount)
|
2025-12-25 10:50:14 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int lastPosition = --_activeCount;
|
|
|
|
|
int lastPoolIndex = _activeIndices[lastPosition];
|
|
|
|
|
|
|
|
|
|
if (position != lastPosition)
|
|
|
|
|
{
|
|
|
|
|
_activeIndices[position] = lastPoolIndex;
|
|
|
|
|
_timerPool[lastPoolIndex].ActiveIndex = position;
|
2025-12-25 10:50:14 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
timer.ActiveIndex = -1;
|
2025-12-25 10:50:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2026-04-24 20:50:13 +08:00
|
|
|
private int GetPoolIndex(int timerId)
|
2025-12-25 10:50:14 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
if (timerId <= 0)
|
2025-12-25 10:50:14 +08:00
|
|
|
{
|
2026-04-24 20:50:13 +08:00
|
|
|
return -1;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
2026-04-24 20:50:13 +08:00
|
|
|
|
|
|
|
|
int poolIndex = (timerId & HANDLE_INDEX_MASK) - 1;
|
|
|
|
|
if ((uint)poolIndex >= MAX_CAPACITY)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
return timer.IsActive && timer.TimerId == timerId ? poolIndex : -1;
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private static int ComposeTimerId(int poolIndex, int version)
|
|
|
|
|
{
|
|
|
|
|
return (version << HANDLE_INDEX_BITS) | (poolIndex + 1);
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
2026-04-24 20:50:13 +08:00
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private static int NextVersion(int version)
|
|
|
|
|
{
|
|
|
|
|
version++;
|
|
|
|
|
if (version > HANDLE_VERSION_MASK)
|
|
|
|
|
{
|
|
|
|
|
version = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private static float NormalizeDelay(float time)
|
|
|
|
|
{
|
|
|
|
|
return time > MINIMUM_DELAY ? time : MINIMUM_DELAY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private static float GetCurrentTime(bool isUnscaled)
|
|
|
|
|
{
|
|
|
|
|
return isUnscaled ? Time.unscaledTime : Time.time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private TimerQueue GetQueue(bool isUnscaled)
|
|
|
|
|
{
|
|
|
|
|
return isUnscaled ? _unscaledQueue : _scaledQueue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
private void FillDebugInfo(int poolIndex, ref TimerDebugInfo info, float currentTime, float currentUnscaledTime)
|
|
|
|
|
{
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
float leftTime;
|
|
|
|
|
if (timer.IsRunning)
|
|
|
|
|
{
|
|
|
|
|
leftTime = timer.TriggerTime - (timer.IsUnscaled ? currentUnscaledTime : currentTime);
|
|
|
|
|
if (leftTime < 0f)
|
|
|
|
|
{
|
|
|
|
|
leftTime = 0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
leftTime = timer.RemainingTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info.TimerId = timer.TimerId;
|
|
|
|
|
info.LeftTime = leftTime;
|
|
|
|
|
info.Duration = timer.Duration;
|
|
|
|
|
info.IsLoop = timer.IsLoop;
|
|
|
|
|
info.IsRunning = timer.IsRunning;
|
|
|
|
|
info.IsUnscaled = timer.IsUnscaled;
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
info.CreationTime = timer.CreationTime;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
}
|
|
|
|
|
}
|