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();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 优化2: 使用union结构存储不同类型的回调(零装箱)
|
|
|
|
|
|
[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
|
|
|
|
|
|
|
|
|
|
// 优化3: 使用字段而非object存储,避免装箱
|
2025-09-05 19:46:30 +08:00
|
|
|
|
public TimerHandler Handler;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
public TimerHandlerNoArgs HandlerNoArgs;
|
|
|
|
|
|
public Delegate HandlerGeneric; // 直接存储委托
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
public byte HandlerType; // 0=Handler, 1=NoArgs, 2=Generic<struct>, 3=Generic<class>
|
|
|
|
|
|
|
2025-09-05 19:46:30 +08:00
|
|
|
|
public object[] Args;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
public object GenericArg; // 存储泛型参数
|
2025-09-05 19:46:30 +08:00
|
|
|
|
|
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()
|
|
|
|
|
|
{
|
|
|
|
|
|
Handler = null;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
HandlerNoArgs = null;
|
|
|
|
|
|
HandlerGeneric = null;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
Args = null;
|
2025-12-24 14:34:26 +08:00
|
|
|
|
GenericArg = null;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
IsActive = false;
|
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)]
|
2025-09-05 19:46:30 +08:00
|
|
|
|
internal sealed class TimerModule : ITimerModule
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
// 优化4: 静态泛型缓存,避免每次调用时的类型检查
|
|
|
|
|
|
private static class GenericInvoker<T>
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public static void Invoke(Delegate callback, object arg)
|
|
|
|
|
|
{
|
|
|
|
|
|
((Action<T>)callback)((T)arg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private class HierarchicalTimeWheel
|
|
|
|
|
|
{
|
|
|
|
|
|
private const int SLOT_COUNT_LEVEL0 = 256;
|
|
|
|
|
|
private const int SLOT_COUNT_LEVEL1 = 64;
|
|
|
|
|
|
private const int SLOT_COUNT_LEVEL2 = 64;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly float _slotInterval;
|
|
|
|
|
|
private readonly TimeWheelLevel[] _levels;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
private float _currentTime;
|
|
|
|
|
|
|
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
|
|
|
|
{
|
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;
|
|
|
|
|
|
slotIndex = (_levels[0].CurrentSlot + totalSlots) % SLOT_COUNT_LEVEL0;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (totalSlots < SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1)
|
|
|
|
|
|
{
|
|
|
|
|
|
level = 1;
|
|
|
|
|
|
int level1Slots = totalSlots / SLOT_COUNT_LEVEL0;
|
|
|
|
|
|
slotIndex = (_levels[1].CurrentSlot + level1Slots) % SLOT_COUNT_LEVEL1;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
level = 2;
|
|
|
|
|
|
int level2Slots = totalSlots / (SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1);
|
|
|
|
|
|
slotIndex = (_levels[2].CurrentSlot + level2Slots) % SLOT_COUNT_LEVEL2;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
if ((_levels[0].CurrentSlot % SLOT_COUNT_LEVEL0) == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessLevel(1, pool, processTimer);
|
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
|
if ((_levels[0].CurrentSlot % (SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1)) == 0)
|
2025-09-05 19:46:30 +08:00
|
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
|
ProcessLevel(2, pool, processTimer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void ProcessLevel(int level, TimerInfo[] pool, Action<int> processTimer)
|
|
|
|
|
|
{
|
|
|
|
|
|
TimeWheelLevel wheelLevel = _levels[level];
|
|
|
|
|
|
wheelLevel.CurrentSlot = (wheelLevel.CurrentSlot + 1) % wheelLevel.SlotCount;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
|
int currentHead = wheelLevel.SlotHeads[wheelLevel.CurrentSlot];
|
|
|
|
|
|
wheelLevel.SlotHeads[wheelLevel.CurrentSlot] = -1;
|
|
|
|
|
|
|
|
|
|
|
|
int currentIndex = currentHead;
|
|
|
|
|
|
while (currentIndex != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
int nextIndex = pool[currentIndex].NextTimerIndex;
|
|
|
|
|
|
|
|
|
|
|
|
if (pool[currentIndex].IsActive && pool[currentIndex].IsRunning)
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void RemoveTimer(int poolIndex, TimerInfo[] pool)
|
|
|
|
|
|
{
|
|
|
|
|
|
ref TimerInfo timer = ref pool[poolIndex];
|
|
|
|
|
|
|
|
|
|
|
|
if (timer.PrevTimerIndex != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
pool[timer.PrevTimerIndex].NextTimerIndex = timer.NextTimerIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int level = 0; level < _levels.Length; level++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_levels[level].SlotHeads[timer.SlotIndex] == poolIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_levels[level].SlotHeads[timer.SlotIndex] = timer.NextTimerIndex;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-24 14:34:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (timer.NextTimerIndex != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
pool[timer.NextTimerIndex].PrevTimerIndex = timer.PrevTimerIndex;
|
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public TimerModule()
|
|
|
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
|
_timerPoolCapacity = 64;
|
|
|
|
|
|
_timerPool = new TimerInfo[_timerPoolCapacity];
|
|
|
|
|
|
_timerIdToPoolIndex = new int[1024];
|
|
|
|
|
|
_freeIndices = new int[_timerPoolCapacity];
|
|
|
|
|
|
_freeCount = _timerPoolCapacity;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < _timerPoolCapacity; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
_freeIndices[i] = i;
|
|
|
|
|
|
_timerPool[i].NextTimerIndex = -1;
|
|
|
|
|
|
_timerPool[i].PrevTimerIndex = -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_scaledTimeWheel = new HierarchicalTimeWheel(0.001f);
|
|
|
|
|
|
_unscaledTimeWheel = new HierarchicalTimeWheel(0.001f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[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;
|
|
|
|
|
|
timer.HandlerNoArgs = callback;
|
|
|
|
|
|
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;
|
|
|
|
|
|
timer.HandlerGeneric = callback; // 直接存储委托,无需包装
|
|
|
|
|
|
timer.GenericArg = arg; // struct会装箱一次,但只在添加时
|
|
|
|
|
|
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;
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return _freeIndices[--_freeCount];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void RegisterTimer(int timerId, int poolIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (timerId >= _timerIdToPoolIndex.Length)
|
|
|
|
|
|
{
|
|
|
|
|
|
Array.Resize(ref _timerIdToPoolIndex, _timerIdToPoolIndex.Length * 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_timerIdToPoolIndex[timerId] = poolIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private int GetPoolIndex(int timerId)
|
|
|
|
|
|
{
|
|
|
|
|
|
return timerId < _timerIdToPoolIndex.Length ? _timerIdToPoolIndex[timerId] : -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
if (poolIndex >= 0 && _timerPool[poolIndex].IsActive)
|
|
|
|
|
|
_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);
|
|
|
|
|
|
if (poolIndex >= 0 && _timerPool[poolIndex].IsActive)
|
|
|
|
|
|
_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);
|
|
|
|
|
|
return poolIndex >= 0 && _timerPool[poolIndex].IsActive && _timerPool[poolIndex].IsRunning;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public float GetLeftTime(int timerId)
|
|
|
|
|
|
{
|
|
|
|
|
|
int poolIndex = GetPoolIndex(timerId);
|
|
|
|
|
|
if (poolIndex < 0 || !_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);
|
|
|
|
|
|
if (poolIndex < 0 || !_timerPool[poolIndex].IsActive) return;
|
|
|
|
|
|
|
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
|
timer.TriggerTime = (timer.IsUnscaled ? Time.unscaledTime : Time.time) + timer.Interval;
|
|
|
|
|
|
|
|
|
|
|
|
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
|
|
|
|
|
|
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);
|
|
|
|
|
|
if (poolIndex < 0 || !_timerPool[poolIndex].IsActive) return;
|
|
|
|
|
|
|
|
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
|
|
|
|
|
timer.IsActive = false;
|
|
|
|
|
|
|
|
|
|
|
|
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
|
|
|
|
|
|
targetWheel.RemoveTimer(poolIndex, _timerPool);
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
|
|
|
|
|
_timerPool[i].Clear();
|
|
|
|
|
|
_freeIndices[_freeCount++] = i;
|
|
|
|
|
|
}
|
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-24 14:34:26 +08:00
|
|
|
|
_timerPool[poolIndex].Clear();
|
|
|
|
|
|
_freeIndices[_freeCount++] = poolIndex;
|
2025-09-05 19:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds)
|
|
|
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
|
_scaledTimeWheel.Advance(Time.time, _timerPool, ProcessTimer);
|
|
|
|
|
|
_unscaledTimeWheel.Advance(Time.unscaledTime, _timerPool, ProcessTimer);
|
2025-09-05 19:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-24 14:34:26 +08:00
|
|
|
|
// 优化7: 使用静态泛型分发,避免反射和类型检查
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void ProcessTimer(int poolIndex)
|
2025-09-05 19:46:30 +08:00
|
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
|
ref TimerInfo timer = ref _timerPool[poolIndex];
|
2025-09-05 19:46:30 +08:00
|
|
|
|
if (!timer.IsActive || !timer.IsRunning) return;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
case 2: // Generic<struct>
|
|
|
|
|
|
case 3: // Generic<class>
|
|
|
|
|
|
// 直接调用,利用JIT优化
|
|
|
|
|
|
((dynamic)timer.HandlerGeneric)?.Invoke((dynamic)timer.GenericArg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-09-05 19:46:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
2025-12-24 14:34:26 +08:00
|
|
|
|
Log.Error($"TimerInfo callback error: {e}");
|
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
|
|
|
|
|
|
{
|
|
|
|
|
|
RemoveTimer(timer.TimerId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IModule.Dispose() => RemoveAllTimer();
|
|
|
|
|
|
|
|
|
|
|
|
public int Priority => 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|