com.alicizax.unity.framework/Runtime/Timer/TimerModule.cs
2025-12-24 14:34:26 +08:00

503 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.IL2CPP.CompilerServices;
using UnityEngine;
namespace AlicizaX
{
public delegate void TimerHandler(params object[] args);
public delegate void TimerHandlerNoArgs();
// 优化2: 使用union结构存储不同类型的回调零装箱
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct TimerInfo : IMemory
{
public int TimerId;
public float TriggerTime;
public float Interval;
// 优化3: 使用字段而非object存储避免装箱
public TimerHandler Handler;
public TimerHandlerNoArgs HandlerNoArgs;
public Delegate HandlerGeneric; // 直接存储委托
public bool IsLoop;
public bool IsRunning;
public bool IsUnscaled;
public bool IsActive;
public byte HandlerType; // 0=Handler, 1=NoArgs, 2=Generic<struct>, 3=Generic<class>
public object[] Args;
public object GenericArg; // 存储泛型参数
public int SlotIndex;
public int NextTimerIndex;
public int PrevTimerIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
Handler = null;
HandlerNoArgs = null;
HandlerGeneric = null;
Args = null;
GenericArg = null;
IsActive = false;
NextTimerIndex = -1;
PrevTimerIndex = -1;
}
}
[UnityEngine.Scripting.Preserve]
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
internal sealed class TimerModule : ITimerModule
{
private int _curTimerId;
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;
private float _currentTime;
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)
{
_slotInterval = slotInterval;
_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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddTimer(int poolIndex, TimerInfo[] pool, float currentTime)
{
ref TimerInfo timer = ref pool[poolIndex];
if (!timer.IsActive) return;
float delta = timer.TriggerTime - currentTime;
if (delta < 0) delta = 0;
int totalSlots = Mathf.FloorToInt(delta / _slotInterval);
int level = 0;
int slotIndex = 0;
if (totalSlots < SLOT_COUNT_LEVEL0)
{
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;
}
timer.SlotIndex = slotIndex;
timer.NextTimerIndex = _levels[level].SlotHeads[slotIndex];
timer.PrevTimerIndex = -1;
if (_levels[level].SlotHeads[slotIndex] != -1)
{
pool[_levels[level].SlotHeads[slotIndex]].PrevTimerIndex = poolIndex;
}
_levels[level].SlotHeads[slotIndex] = poolIndex;
timer.IsRunning = true;
}
public void Advance(float currentTime, TimerInfo[] pool, Action<int> processTimer)
{
float timeDelta = currentTime - _currentTime;
if (timeDelta <= 0) return;
int steps = Mathf.FloorToInt(timeDelta / _slotInterval);
for (int step = 0; step < steps; step++)
{
_currentTime += _slotInterval;
ProcessLevel(0, pool, processTimer);
if ((_levels[0].CurrentSlot % SLOT_COUNT_LEVEL0) == 0)
{
ProcessLevel(1, pool, processTimer);
}
if ((_levels[0].CurrentSlot % (SLOT_COUNT_LEVEL0 * SLOT_COUNT_LEVEL1)) == 0)
{
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;
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
{
AddTimer(currentIndex, pool, _currentTime);
}
}
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;
}
}
}
if (timer.NextTimerIndex != -1)
{
pool[timer.NextTimerIndex].PrevTimerIndex = timer.PrevTimerIndex;
}
}
}
public TimerModule()
{
_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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AddTimer<T>(Action<T> callback, T arg, 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.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];
timer.TimerId = ++_curTimerId;
timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time;
timer.Interval = isLoop ? time : 0f;
timer.Handler = callback;
timer.HandlerType = 0;
timer.IsLoop = isLoop;
timer.IsRunning = true;
timer.IsUnscaled = isUnscaled;
timer.IsActive = true;
timer.Args = args;
timer.GenericArg = null;
RegisterTimer(timer.TimerId, poolIndex);
HierarchicalTimeWheel targetWheel = isUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.AddTimer(poolIndex, _timerPool, isUnscaled ? Time.unscaledTime : Time.time);
return timer.TimerId;
}
[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;
}
public void Stop(int timerId)
{
int poolIndex = GetPoolIndex(timerId);
if (poolIndex >= 0 && _timerPool[poolIndex].IsActive)
_timerPool[poolIndex].IsRunning = false;
}
public void Resume(int timerId)
{
int poolIndex = GetPoolIndex(timerId);
if (poolIndex >= 0 && _timerPool[poolIndex].IsActive)
_timerPool[poolIndex].IsRunning = true;
}
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;
ref TimerInfo timer = ref _timerPool[poolIndex];
return Mathf.Max(timer.TriggerTime - (timer.IsUnscaled ? Time.unscaledTime : Time.time), 0);
}
public void Restart(int timerId)
{
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);
}
public void RemoveTimer(int timerId)
{
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);
}
public void RemoveAllTimer()
{
for (int i = 0; i < _timerPoolCapacity; i++)
{
if (_timerPool[i].IsActive)
{
_timerPool[i].Clear();
_freeIndices[_freeCount++] = i;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReleaseTimerToPool(int poolIndex)
{
_timerPool[poolIndex].Clear();
_freeIndices[_freeCount++] = poolIndex;
}
void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds)
{
_scaledTimeWheel.Advance(Time.time, _timerPool, ProcessTimer);
_unscaledTimeWheel.Advance(Time.unscaledTime, _timerPool, ProcessTimer);
}
// 优化7: 使用静态泛型分发,避免反射和类型检查
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessTimer(int poolIndex)
{
ref TimerInfo timer = ref _timerPool[poolIndex];
if (!timer.IsActive || !timer.IsRunning) return;
try
{
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;
}
}
catch (Exception e)
{
Log.Error($"TimerInfo callback error: {e}");
}
if (timer.IsLoop)
{
timer.TriggerTime += timer.Interval;
HierarchicalTimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel;
targetWheel.AddTimer(poolIndex, _timerPool, timer.IsUnscaled ? Time.unscaledTime : Time.time);
}
else
{
RemoveTimer(timer.TimerId);
}
}
void IModule.Dispose() => RemoveAllTimer();
public int Priority => 0;
}
}