com.alicizax.unity.framework/Runtime/Timer/TimerService.cs

678 lines
24 KiB
C#
Raw Permalink Normal View History

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;
2025-12-24 14:34:26 +08:00
namespace AlicizaX
2025-09-05 19:46:30 +08:00
{
public delegate void TimerHandler(params object[] args);
2025-12-24 14:34:26 +08:00
public delegate void TimerHandlerNoArgs();
2026-03-24 17:45:15 +08:00
internal delegate void TimerGenericInvoker(Delegate handler, object arg);
internal static class TimerGenericInvokerCache<T>
{
public static readonly TimerGenericInvoker Invoke = InvokeGeneric;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void InvokeGeneric(Delegate handler, object arg)
{
((Action<T>)handler)?.Invoke((T)arg);
}
}
2025-12-24 14:34:26 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct TimerInfo : IMemory
2025-09-05 19:46:30 +08:00
{
public int TimerId;
public float TriggerTime;
public float Interval;
2025-12-24 14:34:26 +08:00
2025-09-05 19:46:30 +08:00
public TimerHandler Handler;
2025-12-24 14:34:26 +08:00
public TimerHandlerNoArgs HandlerNoArgs;
2025-12-25 10:50:14 +08:00
public Delegate HandlerGeneric;
2026-03-24 17:45:15 +08:00
public TimerGenericInvoker GenericInvoker;
2025-12-24 14:34:26 +08:00
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
2025-09-05 19:46:30 +08:00
public object[] Args;
2025-12-25 10:50:14 +08:00
public object GenericArg;
2025-09-05 19:46:30 +08:00
2026-03-16 20:52:55 +08:00
public int Level;
2025-12-24 14:34:26 +08:00
public int SlotIndex;
public int NextTimerIndex;
public int PrevTimerIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2025-09-05 19:46:30 +08:00
public void Clear()
{
2026-03-24 17:45:15 +08:00
TimerId = 0;
TriggerTime = 0f;
Interval = 0f;
2025-09-05 19:46:30 +08:00
Handler = null;
2025-12-24 14:34:26 +08:00
HandlerNoArgs = null;
HandlerGeneric = null;
2026-03-24 17:45:15 +08:00
GenericInvoker = null;
IsLoop = false;
IsRunning = false;
IsUnscaled = false;
2025-09-05 19:46:30 +08:00
Args = null;
2025-12-24 14:34:26 +08:00
GenericArg = null;
2026-03-24 17:45:15 +08:00
HandlerType = 0;
2025-09-05 19:46:30 +08:00
IsActive = false;
2025-12-25 10:50:14 +08:00
Level = -1;
SlotIndex = -1;
2025-12-24 14:34:26 +08:00
NextTimerIndex = -1;
PrevTimerIndex = -1;
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-20 13:46:44 +08:00
internal sealed class TimerService : ServiceBase, ITimerService, IServiceTickable
2025-09-05 19:46:30 +08:00
{
2026-03-24 17:45:15 +08:00
private const float TimeWheelSlotInterval = 0.001f;
2025-09-05 19:46:30 +08:00
private int _curTimerId;
2025-12-24 14:34:26 +08:00
private HierarchicalTimeWheel _scaledTimeWheel;
private HierarchicalTimeWheel _unscaledTimeWheel;
private TimerInfo[] _timerPool;
private int[] _timerIdToPoolIndex;
private int _timerPoolCapacity;
private int[] _freeIndices;
private int _freeCount;
2025-12-25 10:50:14 +08:00
private int[] _pendingRemoveTimers;
private int _pendingRemoveCount;
2025-12-24 14:34:26 +08:00
private class HierarchicalTimeWheel
{
private const int SLOT_COUNT_LEVEL0 = 256;
private const int SLOT_COUNT_LEVEL1 = 64;
private const int SLOT_COUNT_LEVEL2 = 64;
2026-03-24 17:45:15 +08:00
private const int SLOT_MASK_LEVEL0 = SLOT_COUNT_LEVEL0 - 1;
private const int SLOT_MASK_LEVEL1 = SLOT_COUNT_LEVEL1 - 1;
private const int SLOT_MASK_LEVEL2 = SLOT_COUNT_LEVEL2 - 1;
2025-12-24 14:34:26 +08:00
private readonly float _slotInterval;
private readonly TimeWheelLevel[] _levels;
2025-09-05 19:46:30 +08:00
private float _currentTime;
2026-03-24 17:45:15 +08:00
private bool _isInitialized;
2025-09-05 19:46:30 +08:00
2025-12-24 14:34:26 +08:00
private class TimeWheelLevel
{
public readonly int[] SlotHeads;
public readonly int SlotCount;
public int CurrentSlot;
public TimeWheelLevel(int slotCount)
{
SlotCount = slotCount;
SlotHeads = new int[slotCount];
for (int i = 0; i < slotCount; i++)
SlotHeads[i] = -1;
}
}
public HierarchicalTimeWheel(float slotInterval)
2025-09-05 19:46:30 +08:00
{
_slotInterval = slotInterval;
2025-12-24 14:34:26 +08:00
_levels = new TimeWheelLevel[3];
_levels[0] = new TimeWheelLevel(SLOT_COUNT_LEVEL0);
_levels[1] = new TimeWheelLevel(SLOT_COUNT_LEVEL1);
_levels[2] = new TimeWheelLevel(SLOT_COUNT_LEVEL2);
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddTimer(int poolIndex, TimerInfo[] pool, float currentTime)
2025-09-05 19:46:30 +08:00
{
2026-03-24 17:45:15 +08:00
EnsureInitialized(currentTime);
2025-12-24 14:34:26 +08:00
ref TimerInfo timer = ref pool[poolIndex];
2025-09-05 19:46:30 +08:00
if (!timer.IsActive) return;
2025-12-24 14:34:26 +08:00
float delta = timer.TriggerTime - currentTime;
if (delta < 0) delta = 0;
2025-09-05 19:46:30 +08:00
2025-12-24 14:34:26 +08:00
int totalSlots = Mathf.FloorToInt(delta / _slotInterval);
int level = 0;
int slotIndex = 0;
if (totalSlots < SLOT_COUNT_LEVEL0)
2025-09-05 19:46:30 +08:00
{
2025-12-24 14:34:26 +08:00
level = 0;
2026-03-24 17:45:15 +08:00
slotIndex = (_levels[0].CurrentSlot + totalSlots) & SLOT_MASK_LEVEL0;
2025-12-24 14:34:26 +08:00
}
else if (totalSlots < SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1)
{
level = 1;
int level1Slots = totalSlots / SLOT_COUNT_LEVEL0;
2026-03-24 17:45:15 +08:00
slotIndex = (_levels[1].CurrentSlot + level1Slots) & SLOT_MASK_LEVEL1;
2025-12-24 14:34:26 +08:00
}
else
{
level = 2;
int level2Slots = totalSlots / (SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1);
2026-03-24 17:45:15 +08:00
slotIndex = (_levels[2].CurrentSlot + level2Slots) & SLOT_MASK_LEVEL2;
2025-09-05 19:46:30 +08:00
}
2025-12-25 10:50:14 +08:00
timer.Level = level;
2025-12-24 14:34:26 +08:00
timer.SlotIndex = slotIndex;
timer.NextTimerIndex = _levels[level].SlotHeads[slotIndex];
timer.PrevTimerIndex = -1;
2025-09-05 19:46:30 +08:00
2025-12-24 14:34:26 +08:00
if (_levels[level].SlotHeads[slotIndex] != -1)
{
pool[_levels[level].SlotHeads[slotIndex]].PrevTimerIndex = poolIndex;
}
_levels[level].SlotHeads[slotIndex] = poolIndex;
2025-09-05 19:46:30 +08:00
timer.IsRunning = true;
}
2025-12-24 14:34:26 +08:00
public void Advance(float currentTime, TimerInfo[] pool, Action<int> processTimer)
2025-09-05 19:46:30 +08:00
{
2026-03-24 17:45:15 +08:00
EnsureInitialized(currentTime);
2025-09-05 19:46:30 +08:00
float timeDelta = currentTime - _currentTime;
if (timeDelta <= 0) return;
int steps = Mathf.FloorToInt(timeDelta / _slotInterval);
2025-12-24 14:34:26 +08:00
for (int step = 0; step < steps; step++)
2025-09-05 19:46:30 +08:00
{
_currentTime += _slotInterval;
2025-12-24 14:34:26 +08:00
ProcessLevel(0, pool, processTimer);
2026-03-24 17:45:15 +08:00
if (_levels[0].CurrentSlot == 0)
2025-12-24 14:34:26 +08:00
{
ProcessLevel(1, pool, processTimer);
2026-03-24 17:45:15 +08:00
if (_levels[1].CurrentSlot == 0)
{
ProcessLevel(2, pool, processTimer);
}
2025-12-24 14:34:26 +08:00
}
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)]
private void EnsureInitialized(float currentTime)
{
if (_isInitialized)
{
return;
2025-12-24 14:34:26 +08:00
}
2026-03-24 17:45:15 +08:00
_currentTime = currentTime;
_isInitialized = true;
2025-12-24 14:34:26 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessLevel(int level, TimerInfo[] pool, Action<int> processTimer)
{
TimeWheelLevel wheelLevel = _levels[level];
2026-03-24 17:45:15 +08:00
if (level == 0)
{
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) & SLOT_MASK_LEVEL0;
}
else if (level == 1)
{
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) & SLOT_MASK_LEVEL1;
}
else
{
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) & SLOT_MASK_LEVEL2;
}
2025-09-05 19:46:30 +08:00
2025-12-24 14:34:26 +08:00
int currentHead = wheelLevel.SlotHeads[wheelLevel.CurrentSlot];
2026-03-16 20:52:55 +08:00
wheelLevel.SlotHeads[wheelLevel.CurrentSlot] = -1;
2025-12-24 14:34:26 +08:00
int currentIndex = currentHead;
while (currentIndex != -1)
{
2025-12-25 10:50:14 +08:00
ref TimerInfo timer = ref pool[currentIndex];
int nextIndex = timer.NextTimerIndex;
2025-12-24 14:34:26 +08:00
2025-12-25 10:50:14 +08:00
timer.NextTimerIndex = -1;
timer.PrevTimerIndex = -1;
2026-03-16 20:52:55 +08:00
timer.Level = -1;
2025-12-25 10:50:14 +08:00
if (timer.IsActive && timer.IsRunning)
2025-12-24 14:34:26 +08:00
{
if (level == 0)
{
processTimer(currentIndex);
}
else
2025-09-05 19:46:30 +08:00
{
2025-12-24 14:34:26 +08:00
AddTimer(currentIndex, pool, _currentTime);
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
}
2025-09-05 19:46:30 +08:00
2025-12-24 14:34:26 +08:00
currentIndex = nextIndex;
}
}
2025-12-25 10:50:14 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2025-12-24 14:34:26 +08:00
public void RemoveTimer(int poolIndex, TimerInfo[] pool)
{
2025-12-25 10:50:14 +08:00
if (poolIndex < 0 || poolIndex >= pool.Length)
return;
2025-12-24 14:34:26 +08:00
ref TimerInfo timer = ref pool[poolIndex];
2025-12-25 10:50:14 +08:00
if (timer.Level < 0 || timer.Level >= _levels.Length)
return;
int level = timer.Level;
int slotIndex = timer.SlotIndex;
if (slotIndex < 0 || slotIndex >= _levels[level].SlotCount)
return;
2025-12-24 14:34:26 +08:00
if (timer.PrevTimerIndex != -1)
{
2025-12-25 10:50:14 +08:00
if (timer.PrevTimerIndex < pool.Length)
{
pool[timer.PrevTimerIndex].NextTimerIndex = timer.NextTimerIndex;
}
2025-12-24 14:34:26 +08:00
}
else
{
2025-12-25 10:50:14 +08:00
_levels[level].SlotHeads[slotIndex] = timer.NextTimerIndex;
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
if (timer.NextTimerIndex != -1)
{
2025-12-25 10:50:14 +08:00
if (timer.NextTimerIndex < pool.Length)
{
pool[timer.NextTimerIndex].PrevTimerIndex = timer.PrevTimerIndex;
}
2025-12-24 14:34:26 +08:00
}
2025-12-25 10:50:14 +08:00
timer.Level = -1;
timer.SlotIndex = -1;
timer.NextTimerIndex = -1;
timer.PrevTimerIndex = -1;
2025-09-05 19:46:30 +08:00
}
}
public TimerService()
2025-09-05 19:46:30 +08:00
{
2025-12-24 14:34:26 +08:00
_timerPoolCapacity = 64;
_timerPool = new TimerInfo[_timerPoolCapacity];
_timerIdToPoolIndex = new int[1024];
_freeIndices = new int[_timerPoolCapacity];
_freeCount = _timerPoolCapacity;
2025-12-25 10:50:14 +08:00
_pendingRemoveTimers = new int[64];
_pendingRemoveCount = 0;
2025-12-24 14:34:26 +08:00
2026-03-24 17:45:15 +08:00
InitializeTimerIdMapping(_timerIdToPoolIndex, 0);
2025-12-24 14:34:26 +08:00
for (int i = 0; i < _timerPoolCapacity; i++)
{
_freeIndices[i] = i;
_timerPool[i].NextTimerIndex = -1;
_timerPool[i].PrevTimerIndex = -1;
2025-12-25 10:50:14 +08:00
_timerPool[i].Level = -1;
_timerPool[i].SlotIndex = -1;
2025-12-24 14:34:26 +08:00
}
2026-03-24 17:45:15 +08:00
_scaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
_unscaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
2025-12-24 14:34:26 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AddTimer(TimerHandlerNoArgs callback, float time, bool isLoop = false, bool isUnscaled = false)
{
int poolIndex = AcquireTimerFromPool();
ref TimerInfo timer = ref _timerPool[poolIndex];
timer.TimerId = ++_curTimerId;
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
timer.Interval = isLoop ? time : 0f;
2026-03-24 17:45:15 +08:00
timer.Handler = null;
2025-12-24 14:34:26 +08:00
timer.HandlerNoArgs = callback;
2026-03-24 17:45:15 +08:00
timer.HandlerGeneric = null;
timer.GenericInvoker = null;
2025-12-24 14:34:26 +08:00
timer.HandlerType = 1;
timer.IsLoop = isLoop;
timer.IsRunning = true;
timer.IsUnscaled = isUnscaled;
timer.IsActive = true;
timer.Args = null;
timer.GenericArg = null;
RegisterTimer(timer.TimerId, poolIndex);
HierarchicalTimeWheel targetWheel = isUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.AddTimer(poolIndex, _timerPool, isUnscaled ? Time.unscaledTime : Time.time);
return timer.TimerId;
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AddTimer<T>(Action<T> callback, T arg, float time, bool isLoop = false, bool isUnscaled = false)
2025-09-05 19:46:30 +08:00
{
2025-12-24 14:34:26 +08:00
int poolIndex = AcquireTimerFromPool();
ref TimerInfo timer = ref _timerPool[poolIndex];
timer.TimerId = ++_curTimerId;
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
timer.Interval = isLoop ? time : 0f;
2026-03-24 17:45:15 +08:00
timer.Handler = null;
timer.HandlerNoArgs = null;
2025-12-25 10:50:14 +08:00
timer.HandlerGeneric = callback;
2026-03-24 17:45:15 +08:00
timer.GenericInvoker = TimerGenericInvokerCache<T>.Invoke;
2025-12-25 10:50:14 +08:00
timer.GenericArg = arg;
2025-12-24 14:34:26 +08:00
timer.HandlerType = 2;
timer.IsLoop = isLoop;
timer.IsRunning = true;
timer.IsUnscaled = isUnscaled;
timer.IsActive = true;
timer.Args = null;
RegisterTimer(timer.TimerId, poolIndex);
HierarchicalTimeWheel targetWheel = isUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.AddTimer(poolIndex, _timerPool, isUnscaled ? Time.unscaledTime : Time.time);
return timer.TimerId;
}
public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args)
{
int poolIndex = AcquireTimerFromPool();
ref TimerInfo timer = ref _timerPool[poolIndex];
2025-09-05 19:46:30 +08:00
timer.TimerId = ++_curTimerId;
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
timer.Interval = isLoop ? time : 0f;
timer.Handler = callback;
2026-03-24 17:45:15 +08:00
timer.HandlerNoArgs = null;
timer.HandlerGeneric = null;
timer.GenericInvoker = null;
2025-12-24 14:34:26 +08:00
timer.HandlerType = 0;
2025-09-05 19:46:30 +08:00
timer.IsLoop = isLoop;
timer.IsRunning = true;
timer.IsUnscaled = isUnscaled;
timer.IsActive = true;
2025-12-24 14:34:26 +08:00
timer.Args = args;
timer.GenericArg = null;
RegisterTimer(timer.TimerId, poolIndex);
HierarchicalTimeWheel targetWheel = isUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.AddTimer(poolIndex, _timerPool, isUnscaled ? Time.unscaledTime : Time.time);
2025-09-05 19:46:30 +08:00
return timer.TimerId;
}
2025-12-24 14:34:26 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int AcquireTimerFromPool()
{
if (_freeCount > 0)
{
return _freeIndices[--_freeCount];
}
int oldCapacity = _timerPoolCapacity;
_timerPoolCapacity *= 2;
Array.Resize(ref _timerPool, _timerPoolCapacity);
Array.Resize(ref _freeIndices, _timerPoolCapacity);
for (int i = _timerPoolCapacity - 1; i >= oldCapacity; i--)
{
_freeIndices[_freeCount++] = i;
_timerPool[i].NextTimerIndex = -1;
_timerPool[i].PrevTimerIndex = -1;
2025-12-25 10:50:14 +08:00
_timerPool[i].Level = -1;
_timerPool[i].SlotIndex = -1;
2025-12-24 14:34:26 +08:00
}
return _freeIndices[--_freeCount];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RegisterTimer(int timerId, int poolIndex)
{
if (timerId >= _timerIdToPoolIndex.Length)
{
2026-03-24 17:45:15 +08:00
int oldLength = _timerIdToPoolIndex.Length;
int newLength = oldLength;
while (timerId >= newLength)
{
newLength *= 2;
}
Array.Resize(ref _timerIdToPoolIndex, newLength);
InitializeTimerIdMapping(_timerIdToPoolIndex, oldLength);
2025-12-24 14:34:26 +08:00
}
_timerIdToPoolIndex[timerId] = poolIndex;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetPoolIndex(int timerId)
{
2026-03-24 17:45:15 +08:00
if (timerId <= 0 || timerId >= _timerIdToPoolIndex.Length)
{
return -1;
}
int poolIndex = _timerIdToPoolIndex[timerId];
if ((uint)poolIndex >= (uint)_timerPool.Length)
{
return -1;
}
ref TimerInfo timer = ref _timerPool[poolIndex];
return timer.IsActive && timer.TimerId == timerId ? poolIndex : -1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void InitializeTimerIdMapping(int[] mapping, int startIndex)
{
for (int i = startIndex; i < mapping.Length; i++)
{
mapping[i] = -1;
}
2025-12-24 14:34:26 +08:00
}
2025-09-05 19:46:30 +08:00
public void Stop(int timerId)
{
2025-12-24 14:34:26 +08:00
int poolIndex = GetPoolIndex(timerId);
2025-12-25 10:50:14 +08:00
if (poolIndex >= 0 && poolIndex < _timerPool.Length && _timerPool[poolIndex].IsActive)
2025-12-24 14:34:26 +08:00
_timerPool[poolIndex].IsRunning = false;
2025-09-05 19:46:30 +08:00
}
public void Resume(int timerId)
{
2025-12-24 14:34:26 +08:00
int poolIndex = GetPoolIndex(timerId);
2025-12-25 10:50:14 +08:00
if (poolIndex >= 0 && poolIndex < _timerPool.Length && _timerPool[poolIndex].IsActive)
2025-12-24 14:34:26 +08:00
_timerPool[poolIndex].IsRunning = true;
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
public bool IsRunning(int timerId)
{
int poolIndex = GetPoolIndex(timerId);
2025-12-25 10:50:14 +08:00
return poolIndex >= 0 && poolIndex < _timerPool.Length &&
_timerPool[poolIndex].IsActive && _timerPool[poolIndex].IsRunning;
2025-12-24 14:34:26 +08:00
}
public float GetLeftTime(int timerId)
{
int poolIndex = GetPoolIndex(timerId);
2025-12-25 10:50:14 +08:00
if (poolIndex < 0 || poolIndex >= _timerPool.Length || !_timerPool[poolIndex].IsActive)
return 0;
2025-09-05 19:46:30 +08:00
2025-12-24 14:34:26 +08:00
ref TimerInfo timer = ref _timerPool[poolIndex];
return Mathf.Max(timer.TriggerTime - (timer.IsUnscaled ? Time.unscaledTime : Time.time), 0);
}
2025-09-05 19:46:30 +08:00
public void Restart(int timerId)
{
2025-12-24 14:34:26 +08:00
int poolIndex = GetPoolIndex(timerId);
2025-12-25 10:50:14 +08:00
if (poolIndex < 0 || poolIndex >= _timerPool.Length || !_timerPool[poolIndex].IsActive)
return;
2025-12-24 14:34:26 +08:00
ref TimerInfo timer = ref _timerPool[poolIndex];
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
2025-12-25 10:50:14 +08:00
targetWheel.RemoveTimer(poolIndex, _timerPool);
timer.TriggerTime = (timer.IsUnscaled ? Time.unscaledTime : Time.time) + timer.Interval;
2025-12-24 14:34:26 +08:00
targetWheel.AddTimer(poolIndex, _timerPool, timer.IsUnscaled ? Time.unscaledTime : Time.time);
2025-09-05 19:46:30 +08:00
}
public void RemoveTimer(int timerId)
{
2025-12-24 14:34:26 +08:00
int poolIndex = GetPoolIndex(timerId);
2025-12-25 10:50:14 +08:00
if (poolIndex < 0 || poolIndex >= _timerPool.Length || !_timerPool[poolIndex].IsActive)
return;
2025-12-24 14:34:26 +08:00
ref TimerInfo timer = ref _timerPool[poolIndex];
timer.IsActive = false;
2025-12-25 10:50:14 +08:00
if (timer.Level >= 0)
{
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.RemoveTimer(poolIndex, _timerPool);
}
2025-12-24 14:34:26 +08:00
ReleaseTimerToPool(poolIndex);
2025-09-05 19:46:30 +08:00
}
public void RemoveAllTimer()
{
2025-12-24 14:34:26 +08:00
for (int i = 0; i < _timerPoolCapacity; i++)
2025-09-05 19:46:30 +08:00
{
2025-12-24 14:34:26 +08:00
if (_timerPool[i].IsActive)
{
2026-03-24 17:45:15 +08:00
int timerId = _timerPool[i].TimerId;
if (timerId > 0 && timerId < _timerIdToPoolIndex.Length)
{
_timerIdToPoolIndex[timerId] = -1;
}
2025-12-24 14:34:26 +08:00
_timerPool[i].Clear();
_freeIndices[_freeCount++] = i;
}
2025-09-05 19:46:30 +08:00
}
2026-03-24 17:45:15 +08:00
_pendingRemoveCount = 0;
_scaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
_unscaledTimeWheel = new HierarchicalTimeWheel(TimeWheelSlotInterval);
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReleaseTimerToPool(int poolIndex)
2025-09-05 19:46:30 +08:00
{
2025-12-25 10:50:14 +08:00
if (poolIndex >= 0 && poolIndex < _timerPool.Length)
{
2026-03-24 17:45:15 +08:00
int timerId = _timerPool[poolIndex].TimerId;
if (timerId > 0 && timerId < _timerIdToPoolIndex.Length && _timerIdToPoolIndex[timerId] == poolIndex)
{
_timerIdToPoolIndex[timerId] = -1;
}
2025-12-25 10:50:14 +08:00
_timerPool[poolIndex].Clear();
if (_freeCount >= _freeIndices.Length)
{
Array.Resize(ref _freeIndices, _freeIndices.Length * 2);
}
_freeIndices[_freeCount++] = poolIndex;
}
2025-09-05 19:46:30 +08:00
}
void IServiceTickable.Tick(float deltaTime)
2025-09-05 19:46:30 +08:00
{
2025-12-24 14:34:26 +08:00
_scaledTimeWheel.Advance(Time.time, _timerPool, ProcessTimer);
_unscaledTimeWheel.Advance(Time.unscaledTime, _timerPool, ProcessTimer);
2025-12-25 10:50:14 +08:00
ProcessPendingRemovals();
2025-09-05 19:46:30 +08:00
}
2025-12-24 14:34:26 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessTimer(int poolIndex)
2025-09-05 19:46:30 +08:00
{
2025-12-25 10:50:14 +08:00
if (poolIndex < 0 || poolIndex >= _timerPool.Length)
return;
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)
return;
2025-09-05 19:46:30 +08:00
try
{
2025-12-24 14:34:26 +08:00
switch (timer.HandlerType)
{
case 0: // TimerHandler
timer.Handler?.Invoke(timer.Args);
break;
case 1: // NoArgs
timer.HandlerNoArgs?.Invoke();
break;
2025-12-25 10:50:14 +08:00
case 2: // Generic
2026-03-24 17:45:15 +08:00
timer.GenericInvoker?.Invoke(timer.HandlerGeneric, timer.GenericArg);
2025-12-24 14:34:26 +08:00
break;
}
2025-09-05 19:46:30 +08:00
}
catch (Exception e)
{
2025-12-25 10:50:14 +08:00
Log.Error($"Timer callback error: {e}");
2025-09-05 19:46:30 +08:00
}
2025-12-25 10:50:14 +08:00
if (!timer.IsActive)
return;
2025-09-05 19:46:30 +08:00
if (timer.IsLoop)
{
timer.TriggerTime += timer.Interval;
2025-12-24 14:34:26 +08:00
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.AddTimer(poolIndex, _timerPool, timer.IsUnscaled ? Time.unscaledTime : Time.time);
2025-09-05 19:46:30 +08:00
}
else
{
2025-12-25 10:50:14 +08:00
AddPendingRemoval(timer.TimerId);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AddPendingRemoval(int timerId)
{
if (_pendingRemoveCount >= _pendingRemoveTimers.Length)
{
Array.Resize(ref _pendingRemoveTimers, _pendingRemoveTimers.Length * 2);
}
_pendingRemoveTimers[_pendingRemoveCount++] = timerId;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessPendingRemovals()
{
for (int i = 0; i < _pendingRemoveCount; i++)
{
RemoveTimer(_pendingRemoveTimers[i]);
2025-09-05 19:46:30 +08:00
}
2025-12-25 10:50:14 +08:00
_pendingRemoveCount = 0;
2025-09-05 19:46:30 +08:00
}
protected override void OnInitialize() { }
protected override void OnDestroyService() => RemoveAllTimer();
2025-09-05 19:46:30 +08:00
public int Order => 0;
2025-09-05 19:46:30 +08:00
}
}