using System; using System.Collections.Generic; using AlicizaX; using UnityEngine; namespace AlicizaX.Timer.Runtime { public delegate void TimerHandler(params object[] args); [Serializable] public class Timer : IMemory { public int TimerId; public float TriggerTime; public float Interval; public TimerHandler Handler; public bool IsLoop; public bool IsRunning; public bool IsUnscaled; public bool IsActive; // 标记定时器是否有效 public object[] Args; public LinkedListNode Node; // 用于时间轮中的链表节点 public void Clear() { Handler = null; Args = null; Node = null; IsActive = false; } } [UnityEngine.Scripting.Preserve] internal sealed class TimerModule : ITimerModule { private int _curTimerId; private TimeWheel _scaledTimeWheel; private TimeWheel _unscaledTimeWheel; private readonly Dictionary _activeTimers = new Dictionary(); private readonly Action _processTimerDelegate; private class TimeWheel { private readonly float _slotInterval; // 每个槽的时间间隔(秒) private readonly int _slotCount; // 槽的数量 private readonly LinkedList[] _slots; private float _currentTime; private int _currentSlotIndex; public TimeWheel(float slotInterval, int slotCount) { _slotInterval = slotInterval; _slotCount = slotCount; _slots = new LinkedList[slotCount]; for (int i = 0; i < slotCount; i++) _slots[i] = new LinkedList(); _currentTime = 0f; _currentSlotIndex = 0; } public void AddTimer(Timer timer, float currentTime) { if (!timer.IsActive) return; float triggerTime = timer.TriggerTime; float delta = triggerTime - currentTime; if (delta < 0) { // 立即触发 delta = 0; } int slotsToAdvance = Mathf.FloorToInt(delta / _slotInterval); int targetSlot = (_currentSlotIndex + slotsToAdvance) % _slotCount; timer.Node = _slots[targetSlot].AddLast(timer); timer.IsRunning = true; } public void Advance(float currentTime, Action processTimer) { float timeDelta = currentTime - _currentTime; if (timeDelta <= 0) return; int steps = Mathf.FloorToInt(timeDelta / _slotInterval); for (int i = 0; i < steps; i++) { _currentSlotIndex = (_currentSlotIndex + 1) % _slotCount; _currentTime += _slotInterval; LinkedList currentSlot = _slots[_currentSlotIndex]; LinkedListNode currentNode = currentSlot.First; while (currentNode != null) { LinkedListNode nextNode = currentNode.Next; Timer timer = currentNode.Value; currentSlot.Remove(currentNode); if (timer.IsActive && timer.IsRunning) { processTimer(timer); } currentNode = nextNode; } } } } public TimerModule() { _scaledTimeWheel = new TimeWheel(1f, 60); _unscaledTimeWheel = new TimeWheel(1f, 60); _processTimerDelegate = ProcessTimer; // 初始化时创建委托一次 } public int AddTimer(TimerHandler callback, float time, bool isLoop = false, bool isUnscaled = false, params object[] args) { Timer timer = GetTimerFromPool(); timer.TimerId = ++_curTimerId; timer.TriggerTime = (isUnscaled ? Time.unscaledTime : Time.time) + time; timer.Interval = isLoop ? time : 0f; timer.Handler = callback; timer.IsLoop = isLoop; timer.IsRunning = true; timer.IsUnscaled = isUnscaled; timer.Args = args; timer.IsActive = true; _activeTimers.Add(timer.TimerId, timer); TimeWheel targetWheel = isUnscaled ? _unscaledTimeWheel : _scaledTimeWheel; targetWheel.AddTimer(timer, isUnscaled ? Time.unscaledTime : Time.time); return timer.TimerId; } public void Stop(int timerId) { if (_activeTimers.TryGetValue(timerId, out Timer timer)) timer.IsRunning = false; } public void Resume(int timerId) { if (_activeTimers.TryGetValue(timerId, out Timer timer)) timer.IsRunning = true; } public bool IsRunning(int timerId) => _activeTimers.TryGetValue(timerId, out Timer timer) && timer.IsRunning; public float GetLeftTime(int timerId) => _activeTimers.TryGetValue(timerId, out Timer timer) ? Mathf.Max(timer.TriggerTime - (timer.IsUnscaled ? Time.unscaledTime : Time.time), 0) : 0; public void Restart(int timerId) { if (_activeTimers.TryGetValue(timerId, out Timer timer)) { timer.TriggerTime = (timer.IsUnscaled ? Time.unscaledTime : Time.time) + timer.Interval; TimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel; targetWheel.AddTimer(timer, timer.IsUnscaled ? Time.unscaledTime : Time.time); } } public void RemoveTimer(int timerId) { if (_activeTimers.TryGetValue(timerId, out Timer timer)) { timer.IsActive = false; // 标记为无效 _activeTimers.Remove(timerId); ReturnTimerToPool(timer); } } public void RemoveAllTimer() { foreach (var timer in _activeTimers.Values) { timer.IsActive = false; ReturnTimerToPool(timer); } _activeTimers.Clear(); } private Timer GetTimerFromPool() => MemoryPool.Acquire(); private void ReturnTimerToPool(Timer timer) { MemoryPool.Release(timer); } void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds) { float scaledTime = Time.time; _scaledTimeWheel.Advance(scaledTime, _processTimerDelegate); float unscaledTime = Time.unscaledTime; _unscaledTimeWheel.Advance(unscaledTime, _processTimerDelegate); } private void ProcessTimer(Timer timer) { if (!timer.IsActive || !timer.IsRunning) return; try { timer.Handler?.Invoke(timer.Args); } catch (Exception e) { Log.Error($"Timer callback error: {e}"); } if (timer.IsLoop) { timer.TriggerTime += timer.Interval; TimeWheel targetWheel = timer.IsUnscaled ? _unscaledTimeWheel : _scaledTimeWheel; targetWheel.AddTimer(timer, timer.IsUnscaled ? Time.unscaledTime : Time.time); } else { RemoveTimer(timer.TimerId); } } void IModule.Dispose() => RemoveAllTimer(); public int Priority => 0; } }