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, 3=Generic 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 { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Invoke(Delegate callback, object arg) { ((Action)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 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 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(Action 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 case 3: // Generic // 直接调用,利用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; } }