330 lines
10 KiB
C#
330 lines
10 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using AlicizaX.Runtime;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace AlicizaX.Timer.Runtime
|
|||
|
|
{
|
|||
|
|
public struct TimerInfo
|
|||
|
|
{
|
|||
|
|
public float Interval;
|
|||
|
|
public int Repeat;
|
|||
|
|
public float Elapsed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 定时器管理器
|
|||
|
|
/// </summary>
|
|||
|
|
[UnityEngine.Scripting.Preserve]
|
|||
|
|
internal sealed class TimerManager : ITimerManager
|
|||
|
|
{
|
|||
|
|
class TimerItem
|
|||
|
|
{
|
|||
|
|
public float Interval;
|
|||
|
|
public int Repeat;
|
|||
|
|
public Action<object> Callback;
|
|||
|
|
public object Param;
|
|||
|
|
|
|||
|
|
public float Elapsed;
|
|||
|
|
public bool Deleted;
|
|||
|
|
|
|||
|
|
public void Set(float interval, int repeat, Action<object> callback, object param)
|
|||
|
|
{
|
|||
|
|
this.Interval = interval;
|
|||
|
|
this.Repeat = repeat;
|
|||
|
|
this.Callback = callback;
|
|||
|
|
this.Param = param;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private readonly Dictionary<Action<object>, TimerItem> _items = new Dictionary<Action<object>, TimerItem>();
|
|||
|
|
private readonly Dictionary<Action<object>, TimerItem> _toAdd = new Dictionary<Action<object>, TimerItem>();
|
|||
|
|
private readonly List<TimerItem> _toRemove = new List<TimerItem>();
|
|||
|
|
private readonly List<TimerItem> _pool = new List<TimerItem>(100);
|
|||
|
|
|
|||
|
|
private static readonly object Locker = new object();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 是否触发回调异常
|
|||
|
|
/// </summary>
|
|||
|
|
public static bool CatchCallbackExceptions = false;
|
|||
|
|
|
|||
|
|
void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds)
|
|||
|
|
{
|
|||
|
|
lock (Locker)
|
|||
|
|
{
|
|||
|
|
Dictionary<Action<object>, TimerItem>.Enumerator enumerator;
|
|||
|
|
|
|||
|
|
if (_items.Count > 0)
|
|||
|
|
{
|
|||
|
|
enumerator = _items.GetEnumerator();
|
|||
|
|
while (enumerator.MoveNext())
|
|||
|
|
{
|
|||
|
|
TimerItem timerItem = enumerator.Current.Value;
|
|||
|
|
if (timerItem.Deleted)
|
|||
|
|
{
|
|||
|
|
_toRemove.Add(timerItem);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
timerItem.Elapsed += realElapseSeconds;
|
|||
|
|
if (timerItem.Elapsed < timerItem.Interval)
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
timerItem.Elapsed -= timerItem.Interval;
|
|||
|
|
if (timerItem.Elapsed < 0 || timerItem.Elapsed > 0.03f)
|
|||
|
|
timerItem.Elapsed = 0;
|
|||
|
|
|
|||
|
|
if (timerItem.Repeat > 0)
|
|||
|
|
{
|
|||
|
|
timerItem.Repeat--;
|
|||
|
|
if (timerItem.Repeat == 0)
|
|||
|
|
{
|
|||
|
|
timerItem.Deleted = true;
|
|||
|
|
_toRemove.Add(timerItem);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// var repeat = i.Repeat;
|
|||
|
|
if (timerItem.Callback != null)
|
|||
|
|
{
|
|||
|
|
if (CatchCallbackExceptions)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
timerItem.Callback(timerItem.Param);
|
|||
|
|
}
|
|||
|
|
catch (Exception e)
|
|||
|
|
{
|
|||
|
|
timerItem.Deleted = true;
|
|||
|
|
Debug.LogWarning("Timer: timer(internal=" + timerItem.Interval + ", repeat=" + timerItem.Repeat + ") callback error > " + e.Message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
timerItem.Callback(timerItem.Param);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
enumerator.Dispose();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
int len = _toRemove.Count;
|
|||
|
|
if (len > 0)
|
|||
|
|
{
|
|||
|
|
for (int k = 0; k < len; k++)
|
|||
|
|
{
|
|||
|
|
TimerItem i = _toRemove[k];
|
|||
|
|
if (i.Deleted && i.Callback != null)
|
|||
|
|
{
|
|||
|
|
_items.Remove(i.Callback);
|
|||
|
|
ReturnToPool(i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_toRemove.Clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_toAdd.Count > 0)
|
|||
|
|
{
|
|||
|
|
enumerator = _toAdd.GetEnumerator();
|
|||
|
|
while (enumerator.MoveNext())
|
|||
|
|
{
|
|||
|
|
_items.Add(enumerator.Current.Key, enumerator.Current.Value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
enumerator.Dispose();
|
|||
|
|
_toAdd.Clear();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void IModule.Dispose()
|
|||
|
|
{
|
|||
|
|
lock (Locker)
|
|||
|
|
{
|
|||
|
|
this._toRemove.Clear();
|
|||
|
|
this._toAdd.Clear();
|
|||
|
|
this._items.Clear();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 添加一个定时调用的任务
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="interval">间隔时间(以秒为单位)</param>
|
|||
|
|
/// <param name="repeat">重复次数(0 表示无限重复)</param>
|
|||
|
|
/// <param name="callback">要执行的回调函数</param>
|
|||
|
|
/// <param name="callbackParam">回调函数的参数(可选)</param>
|
|||
|
|
public void Add(float interval, int repeat, Action<object> callback, object callbackParam = null)
|
|||
|
|
{
|
|||
|
|
lock (Locker)
|
|||
|
|
{
|
|||
|
|
if (callback == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("timer callback is null, " + interval + "," + repeat);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
if (_items.TryGetValue(callback, out var t))
|
|||
|
|
{
|
|||
|
|
t.Set(interval, repeat, callback, callbackParam);
|
|||
|
|
t.Elapsed = 0;
|
|||
|
|
t.Deleted = false;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_toAdd.TryGetValue(callback, out t))
|
|||
|
|
{
|
|||
|
|
t.Set(interval, repeat, callback, callbackParam);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t = GetFromPool();
|
|||
|
|
t.Interval = interval;
|
|||
|
|
t.Repeat = repeat;
|
|||
|
|
t.Callback = callback;
|
|||
|
|
t.Param = callbackParam;
|
|||
|
|
_toAdd[callback] = t;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 添加一个只执行一次的任务
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="interval">间隔时间(以秒为单位)</param>
|
|||
|
|
/// <param name="callback">要执行的回调函数</param>
|
|||
|
|
/// <param name="callbackParam">回调函数的参数(可选)</param>
|
|||
|
|
public void AddOnce(float interval, Action<object> callback, object callbackParam = null)
|
|||
|
|
{
|
|||
|
|
Add(interval, 1, callback, callbackParam);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 添加一个每帧更新执行的任务
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="callback">要执行的回调函数</param>
|
|||
|
|
public void AddUpdate(Action<object> callback)
|
|||
|
|
{
|
|||
|
|
Add(0.001f, 0, callback);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 添加一个每帧更新执行的任务
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="callback">要执行的回调函数</param>
|
|||
|
|
/// <param name="callbackParam">回调函数的参数</param>
|
|||
|
|
public void AddUpdate(Action<object> callback, object callbackParam)
|
|||
|
|
{
|
|||
|
|
Add(0.001f, 0, callback, callbackParam);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检查指定的任务是否存在
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="callback">要检查的回调函数</param>
|
|||
|
|
/// <returns>存在返回 true,不存在返回 false</returns>
|
|||
|
|
public bool Exists(Action<object> callback)
|
|||
|
|
{
|
|||
|
|
lock (Locker)
|
|||
|
|
{
|
|||
|
|
if (_toAdd.ContainsKey(callback))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
if (_items.TryGetValue(callback, out var at))
|
|||
|
|
{
|
|||
|
|
return !at.Deleted;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 移除指定的任务
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="callback">要移除的回调函数</param>
|
|||
|
|
public void Remove(Action<object> callback)
|
|||
|
|
{
|
|||
|
|
lock (Locker)
|
|||
|
|
{
|
|||
|
|
if (_toAdd.TryGetValue(callback, out var t))
|
|||
|
|
{
|
|||
|
|
_toAdd.Remove(callback);
|
|||
|
|
ReturnToPool(t);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (_items.TryGetValue(callback, out t))
|
|||
|
|
{
|
|||
|
|
t.Deleted = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private TimerItem GetFromPool()
|
|||
|
|
{
|
|||
|
|
TimerItem t;
|
|||
|
|
int cnt = _pool.Count;
|
|||
|
|
if (cnt > 0)
|
|||
|
|
{
|
|||
|
|
t = _pool[cnt - 1];
|
|||
|
|
_pool.RemoveAt(cnt - 1);
|
|||
|
|
t.Deleted = false;
|
|||
|
|
t.Elapsed = 0;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
t = new TimerItem();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return t;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ReturnToPool(TimerItem t)
|
|||
|
|
{
|
|||
|
|
t.Callback = null;
|
|||
|
|
_pool.Add(t);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public int Priority
|
|||
|
|
{
|
|||
|
|
get => 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取所有正在运行的定时器的信息
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>一个列表,其中包含每个定时器的信息</returns>
|
|||
|
|
public List<TimerInfo> GetTimerInfos()
|
|||
|
|
{
|
|||
|
|
List<TimerInfo> timerInfos = new List<TimerInfo>();
|
|||
|
|
|
|||
|
|
lock (Locker)
|
|||
|
|
{
|
|||
|
|
foreach (var timerItem in _items.Values)
|
|||
|
|
{
|
|||
|
|
if (!timerItem.Deleted) // 确保定时器未被删除
|
|||
|
|
{
|
|||
|
|
timerInfos.Add(new TimerInfo
|
|||
|
|
{
|
|||
|
|
Interval = timerItem.Interval,
|
|||
|
|
Repeat = timerItem.Repeat,
|
|||
|
|
Elapsed = timerItem.Elapsed,
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return timerInfos;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|