using System;
using System.Collections.Generic;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace SepCore.Timer
{
///
/// 通用定时器组件。
///
[DisallowMultipleComponent]
[AddComponentMenu("Game Main/Timer")]
public sealed class TimerComponent : GameFrameworkComponent
{
private readonly List _timerTasks = new List();
private bool _isPaused = false;
private bool _isUpdating = false;
private int _serialId = 0;
///
/// 获取当前定时任务数量。
///
public int Count => _timerTasks.Count;
///
/// 获取定时器是否暂停。
///
public bool IsPaused => _isPaused;
private void Update()
{
if (_isPaused)
{
return;
}
UpdateTasks(Time.deltaTime, Time.unscaledDeltaTime);
}
private void OnDestroy()
{
ClearAll();
}
///
/// 创建定时任务。
///
/// 定时任务描述。
/// 定时任务句柄。
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);
}
///
/// 创建一次性定时任务。
///
public TimerHandle ScheduleOnce(float delay, Action callback, object owner = null,
TimerTimeMode timeMode = TimerTimeMode.Scaled)
{
return Schedule(new TimerTask(delay, delay, 1, callback, owner, timeMode));
}
///
/// 创建循环定时任务,首次触发延迟等于循环间隔。
///
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);
}
///
/// 创建循环定时任务。
///
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));
}
///
/// 取消定时任务。
///
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;
}
///
/// 取消归属于指定对象的全部定时任务。
///
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;
}
///
/// 暂停所有定时任务。
///
public void Pause()
{
_isPaused = true;
}
///
/// 恢复所有定时任务。
///
public void Resume()
{
_isPaused = false;
}
///
/// 清理所有定时任务。
///
public void ClearAll()
{
if (!_isUpdating)
{
_timerTasks.Clear();
return;
}
for (int i = 0; i < _timerTasks.Count; i++)
{
_timerTasks[i].IsCancelled = true;
}
}
///
/// 获取所有活跃任务的快照(调试用)。
///
public TimerTaskSnapshot[] GetTaskSnapshots()
{
List snapshots = new List(_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();
}
///
/// 设置任务的循环间隔。
///
/// 任务句柄。
/// 新的间隔时间(秒)。
/// 是否根据新旧间隔的比例调整当前剩余时间。
/// 是否设置成功。
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;
}
///
/// 暂停单个任务。
///
/// 任务句柄。
/// 是否暂停成功。
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;
}
///
/// 恢复单个任务。
///
/// 任务句柄。
/// 是否恢复成功。
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;
}
///
/// 获取任务的剩余时间。
///
/// 任务句柄。
/// 剩余时间(秒),任务不存在返回 -1f。
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;
}
///
/// 获取任务的循环间隔。
///
/// 任务句柄。
/// 循环间隔(秒),任务不存在返回 -1f。
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;
}
///
/// 获取任务的剩余重复次数。
///
/// 任务句柄。
/// 剩余重复次数,任务不存在返回 -1。
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;
}
///
/// 重置任务的剩余时间。
///
/// 任务句柄。
/// 新的剩余时间(秒)。
/// 是否重置成功。
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;
}
///
/// 任务是否已暂停。
///
/// 任务句柄。
/// 任务是否已暂停,任务不存在返回 false。
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;
}
}
}
///
/// 定时任务快照(调试用)。
///
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;
}
}