导入 TimerModule 计时器模块
This commit is contained in:
@@ -0,0 +1,622 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.Timer
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用定时器组件。
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Game Main/Timer")]
|
||||
public sealed class TimerComponent : GameFrameworkComponent
|
||||
{
|
||||
private readonly List<TimerTaskInfo> _timerTasks = new List<TimerTaskInfo>();
|
||||
private bool _isPaused = false;
|
||||
private bool _isUpdating = false;
|
||||
private int _serialId = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前定时任务数量。
|
||||
/// </summary>
|
||||
public int Count => _timerTasks.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 获取定时器是否暂停。
|
||||
/// </summary>
|
||||
public bool IsPaused => _isPaused;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_isPaused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateTasks(Time.deltaTime, Time.unscaledDeltaTime);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
ClearAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建定时任务。
|
||||
/// </summary>
|
||||
/// <param name="timerTask">定时任务描述。</param>
|
||||
/// <returns>定时任务句柄。</returns>
|
||||
public TimerHandle Schedule(TimerTask timerTask)
|
||||
{
|
||||
if (timerTask.Callback == null)
|
||||
{
|
||||
Log.Error("Timer task callback is invalid.");
|
||||
return TimerHandle.Invalid;
|
||||
}
|
||||
|
||||
if (timerTask.RepeatCount == 0)
|
||||
{
|
||||
return TimerHandle.Invalid;
|
||||
}
|
||||
|
||||
float delay = Mathf.Max(0f, timerTask.Delay);
|
||||
float interval = Mathf.Max(0f, timerTask.Interval);
|
||||
if (timerTask.RepeatCount != 1 && interval <= 0f)
|
||||
{
|
||||
Log.Error("Timer task interval must be greater than zero for repeated tasks.");
|
||||
return TimerHandle.Invalid;
|
||||
}
|
||||
|
||||
int id = GenerateSerialId();
|
||||
TimerTaskInfo taskInfo = new TimerTaskInfo(id, delay, interval, timerTask.RepeatCount,
|
||||
timerTask.TimeMode, timerTask.Owner, timerTask.Callback);
|
||||
_timerTasks.Add(taskInfo);
|
||||
return new TimerHandle(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一次性定时任务。
|
||||
/// </summary>
|
||||
public TimerHandle ScheduleOnce(float delay, Action callback, object owner = null,
|
||||
TimerTimeMode timeMode = TimerTimeMode.Scaled)
|
||||
{
|
||||
return Schedule(new TimerTask(delay, 0f, 1, callback, owner, timeMode));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建循环定时任务,首次触发延迟等于循环间隔。
|
||||
/// </summary>
|
||||
public TimerHandle ScheduleRepeat(float interval, Action callback, int repeatCount = -1, object owner = null,
|
||||
TimerTimeMode timeMode = TimerTimeMode.Scaled)
|
||||
{
|
||||
return ScheduleRepeat(interval, interval, callback, repeatCount, owner, timeMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建循环定时任务。
|
||||
/// </summary>
|
||||
public TimerHandle ScheduleRepeat(float delay, float interval, Action callback, int repeatCount = -1,
|
||||
object owner = null, TimerTimeMode timeMode = TimerTimeMode.Scaled)
|
||||
{
|
||||
return Schedule(new TimerTask(delay, interval, repeatCount, callback, owner, timeMode));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消定时任务。
|
||||
/// </summary>
|
||||
public bool Cancel(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = _timerTasks.Count - 1; i >= 0; i--)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id != handle.Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
taskInfo.IsCancelled = true;
|
||||
if (!_isUpdating)
|
||||
{
|
||||
_timerTasks.RemoveAt(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消归属于指定对象的全部定时任务。
|
||||
/// </summary>
|
||||
public int CancelByOwner(object owner)
|
||||
{
|
||||
if (owner == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = _timerTasks.Count - 1; i >= 0; i--)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (!ReferenceEquals(taskInfo.Owner, owner))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
taskInfo.IsCancelled = true;
|
||||
count++;
|
||||
if (!_isUpdating)
|
||||
{
|
||||
_timerTasks.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停所有定时任务。
|
||||
/// </summary>
|
||||
public void Pause()
|
||||
{
|
||||
_isPaused = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复所有定时任务。
|
||||
/// </summary>
|
||||
public void Resume()
|
||||
{
|
||||
_isPaused = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有定时任务。
|
||||
/// </summary>
|
||||
public void ClearAll()
|
||||
{
|
||||
if (!_isUpdating)
|
||||
{
|
||||
_timerTasks.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
_timerTasks[i].IsCancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有活跃任务的快照(调试用)。
|
||||
/// </summary>
|
||||
public TimerTaskSnapshot[] GetTaskSnapshots()
|
||||
{
|
||||
List<TimerTaskSnapshot> snapshots = new List<TimerTaskSnapshot>(_timerTasks.Count);
|
||||
foreach (TimerTaskInfo taskInfo in _timerTasks)
|
||||
{
|
||||
if (taskInfo.IsCancelled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
snapshots.Add(new TimerTaskSnapshot
|
||||
{
|
||||
Id = taskInfo.Id,
|
||||
RemainingTime = taskInfo.RemainingTime,
|
||||
Interval = taskInfo.Interval,
|
||||
RemainingRepeatCount = taskInfo.RemainingRepeatCount,
|
||||
TimeMode = taskInfo.TimeMode,
|
||||
Owner = taskInfo.Owner,
|
||||
CallbackMethod = $"{taskInfo.Callback.Method.DeclaringType?.Name}.{taskInfo.Callback.Method.Name}",
|
||||
HasError = taskInfo.HasError,
|
||||
IsPaused = taskInfo.IsPaused
|
||||
});
|
||||
}
|
||||
|
||||
return snapshots.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置任务的循环间隔。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <param name="newInterval">新的间隔时间(秒)。</param>
|
||||
/// <param name="adjustRemainingTime">是否根据新旧间隔的比例调整当前剩余时间。</param>
|
||||
/// <returns>是否设置成功。</returns>
|
||||
public bool SetInterval(TimerHandle handle, float newInterval, bool adjustRemainingTime = false)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id != handle.Id || taskInfo.IsCancelled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float safeInterval = Mathf.Max(0f, newInterval);
|
||||
if (adjustRemainingTime && taskInfo.Interval > 0f && safeInterval > 0f)
|
||||
{
|
||||
float ratio = safeInterval / taskInfo.Interval;
|
||||
taskInfo.RemainingTime *= ratio;
|
||||
}
|
||||
|
||||
taskInfo.Interval = safeInterval;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停单个任务。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <returns>是否暂停成功。</returns>
|
||||
public bool PauseTask(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id != handle.Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
taskInfo.IsPaused = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复单个任务。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <returns>是否恢复成功。</returns>
|
||||
public bool ResumeTask(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id != handle.Id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
taskInfo.IsPaused = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务的剩余时间。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <returns>剩余时间(秒),任务不存在返回 -1f。</returns>
|
||||
public float GetRemainingTime(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return -1f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id == handle.Id && !taskInfo.IsCancelled)
|
||||
{
|
||||
return taskInfo.RemainingTime;
|
||||
}
|
||||
}
|
||||
|
||||
return -1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务的循环间隔。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <returns>循环间隔(秒),任务不存在返回 -1f。</returns>
|
||||
public float GetInterval(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return -1f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id == handle.Id && !taskInfo.IsCancelled)
|
||||
{
|
||||
return taskInfo.Interval;
|
||||
}
|
||||
}
|
||||
|
||||
return -1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务的剩余重复次数。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <returns>剩余重复次数,任务不存在返回 -1。</returns>
|
||||
public int GetRemainingRepeatCount(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id == handle.Id && !taskInfo.IsCancelled)
|
||||
{
|
||||
return taskInfo.RemainingRepeatCount;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置任务的剩余时间。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <param name="newRemainingTime">新的剩余时间(秒)。</param>
|
||||
/// <returns>是否重置成功。</returns>
|
||||
public bool ResetRemainingTime(TimerHandle handle, float newRemainingTime)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id == handle.Id && !taskInfo.IsCancelled)
|
||||
{
|
||||
taskInfo.RemainingTime = Mathf.Max(0f, newRemainingTime);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务是否已暂停。
|
||||
/// </summary>
|
||||
/// <param name="handle">任务句柄。</param>
|
||||
/// <returns>任务是否已暂停,任务不存在返回 false。</returns>
|
||||
public bool IsTaskPaused(TimerHandle handle)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _timerTasks.Count; i++)
|
||||
{
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.Id == handle.Id && !taskInfo.IsCancelled)
|
||||
{
|
||||
return taskInfo.IsPaused;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateTasks(float scaledDeltaTime, float unscaledDeltaTime)
|
||||
{
|
||||
int taskCount = _timerTasks.Count;
|
||||
_isUpdating = true;
|
||||
for (int i = taskCount - 1; i >= 0; i--)
|
||||
{
|
||||
if (i >= _timerTasks.Count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TimerTaskInfo taskInfo = _timerTasks[i];
|
||||
if (taskInfo.IsCancelled || taskInfo.IsPaused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float deltaTime = taskInfo.TimeMode == TimerTimeMode.Unscaled ? unscaledDeltaTime : scaledDeltaTime;
|
||||
UpdateTask(taskInfo, deltaTime);
|
||||
}
|
||||
|
||||
_isUpdating = false;
|
||||
RemoveCancelledTasks();
|
||||
}
|
||||
|
||||
private void UpdateTask(TimerTaskInfo taskInfo, float deltaTime)
|
||||
{
|
||||
if (deltaTime <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
taskInfo.RemainingTime -= deltaTime;
|
||||
if (taskInfo.RemainingTime > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InvokeCallback(taskInfo);
|
||||
if (taskInfo.IsCancelled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (taskInfo.RemainingRepeatCount > 0)
|
||||
{
|
||||
taskInfo.RemainingRepeatCount--;
|
||||
}
|
||||
|
||||
if (taskInfo.RemainingRepeatCount == 0)
|
||||
{
|
||||
taskInfo.IsCancelled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
taskInfo.RemainingTime = taskInfo.Interval;
|
||||
}
|
||||
|
||||
private void InvokeCallback(TimerTaskInfo taskInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
taskInfo.Callback.Invoke();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
taskInfo.HasError = true;
|
||||
Log.Error("Timer task callback exception: {0}", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveCancelledTasks()
|
||||
{
|
||||
for (int i = _timerTasks.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (_timerTasks[i].IsCancelled)
|
||||
{
|
||||
_timerTasks.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GenerateSerialId()
|
||||
{
|
||||
_serialId++;
|
||||
if (_serialId <= 0)
|
||||
{
|
||||
_serialId = 1;
|
||||
}
|
||||
|
||||
return _serialId;
|
||||
}
|
||||
|
||||
private sealed class TimerTaskInfo
|
||||
{
|
||||
public TimerTaskInfo(int id, float delay, float interval, int repeatCount, TimerTimeMode timeMode,
|
||||
object owner, Action callback)
|
||||
{
|
||||
Id = id;
|
||||
RemainingTime = delay;
|
||||
Interval = interval;
|
||||
RemainingRepeatCount = repeatCount;
|
||||
TimeMode = timeMode;
|
||||
Owner = owner;
|
||||
Callback = callback;
|
||||
IsCancelled = false;
|
||||
IsPaused = false;
|
||||
}
|
||||
|
||||
public int Id
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public float RemainingTime
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float Interval
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int RemainingRepeatCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public TimerTimeMode TimeMode
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public object Owner
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public Action Callback
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public bool IsCancelled
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool IsPaused
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public bool HasError
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定时任务快照(调试用)。
|
||||
/// </summary>
|
||||
public struct TimerTaskSnapshot
|
||||
{
|
||||
public int Id;
|
||||
public float RemainingTime;
|
||||
public float Interval;
|
||||
public int RemainingRepeatCount;
|
||||
public TimerTimeMode TimeMode;
|
||||
public object Owner;
|
||||
public string CallbackMethod;
|
||||
public bool HasError;
|
||||
public bool IsPaused;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user