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; } }