com.alicizax.unity.framework/Runtime/Timer/TimerModule.cs
2025-09-08 10:10:14 +08:00

236 lines
7.8 KiB
C#

using System;
using System.Collections.Generic;
using AlicizaX;
using UnityEngine;
namespace AlicizaX.Timer.Runtime
{
public delegate void TimerHandler(params object[] args);
[Serializable]
internal 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<Timer> 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<int, Timer> _activeTimers = new Dictionary<int, Timer>();
private readonly Action<Timer> _processTimerDelegate;
private class TimeWheel
{
private readonly float _slotInterval; // 每个槽的时间间隔(秒)
private readonly int _slotCount; // 槽的数量
private readonly LinkedList<Timer>[] _slots;
private float _currentTime;
private int _currentSlotIndex;
public TimeWheel(float slotInterval, int slotCount)
{
_slotInterval = slotInterval;
_slotCount = slotCount;
_slots = new LinkedList<Timer>[slotCount];
for (int i = 0; i < slotCount; i++)
_slots[i] = new LinkedList<Timer>();
_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<Timer> 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<Timer> currentSlot = _slots[_currentSlotIndex];
LinkedListNode<Timer> currentNode = currentSlot.First;
while (currentNode != null)
{
LinkedListNode<Timer> 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<Timer>();
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;
}
}