using Thousandto.Code.Center; using Thousandto.Core.Base; using System; using System.Collections.Generic; namespace Thousandto.Code.Logic { //计时器事件系统 public class TimerEventSystem : BaseSystem { #region//常量 //每小时的秒数 public const float HOUR_SEC_COUNT = 60 * 60; //每天的秒数 public const float DAY_SEC_COUNT = HOUR_SEC_COUNT * 24; //每周的秒数 public const float WEEK_SEC_COUNT = DAY_SEC_COUNT * 7; #endregion #region//私有变量 //id计数器 private int _idCounter = 1; //计时器列表 private List _timeEventList = new List(); //记录心跳系统是否已经接收到心跳信息 private bool _receiveHeartMsg = false; //下一次跨天时间戳 private int _crossDayTime = -1; #endregion #region//初始化,反初始化 public void Initialize() { _receiveHeartMsg = false; _idCounter = 1; _crossDayTime = -1; } public void Uninitialize() { _receiveHeartMsg = false; _idCounter = 1; _timeEventList.Clear(); _crossDayTime = -1; } #endregion #region//公有函数 /// /// 增加倒计时事件 /// /// /// /// /// 返回计时器ID,如果小于0表示添加失败 public int AddCountDownEvent(float countDownTime, bool loop, object param, Action callBack) { if (countDownTime <= 0f) return -1; if (callBack == null) return -1; return AddTimerEvent(countDownTime, 0f, TimerEventType.CountDown, loop, param, callBack); } /// /// 增加小时时间戳计时器,每个小时到达指定时间时通知 /// /// /// /// /// 返回计时器ID,如果小于0表示添加失败 public int AddTimeStampHourEvent(float time, float validTime, bool loop, object param, Action callBack) { if (time <= 0f || time >= HOUR_SEC_COUNT) return -1; if (callBack == null) return -1; return AddTimerEvent(time, validTime, TimerEventType.TimeStampHour, loop, param, callBack); } /// /// 增加天时间戳计时器,每天到达指定时间时通知 /// /// /// /// /// 返回计时器ID,如果小于0表示添加失败 public int AddTimeStampDayEvent(float time, float validTime, bool loop, object param, Action callBack) { if (time <= 0f || time >= DAY_SEC_COUNT) return -1; if (callBack == null) return -1; return AddTimerEvent(time, validTime, TimerEventType.TimeStampDay, loop, param, callBack); } /// /// 增加周时间戳计时器,每周到达指定时间时通知 /// /// /// /// /// 返回计时器ID,如果小于0表示添加失败 public int AddTimeStampWeekEvent(float time, float validTime, bool loop, object param, Action callBack) { if (time <= 0f || time >= WEEK_SEC_COUNT) { UnityEngine.Debug.LogError("周活动时间有误:" + time + (time <= 0) + (time >= WEEK_SEC_COUNT)); return -1; } if (callBack == null) { UnityEngine.Debug.LogError("周活动callBack为空"); return -1; } return AddTimerEvent(time, validTime, TimerEventType.TimeStampWeek, loop, param, callBack); } /// /// 删除计时器 /// /// public void RemoveTimerEvent(int id) { for (int i = _timeEventList.Count - 1; i >= 0; --i) { if (_timeEventList[i].ID == id) { _timeEventList.RemoveAt(i); break; } } } #endregion #region//私有函数 protected override bool OnUpdate(float deltaTime) { var curHeart = GameCenter.HeartSystem.IsReceiveHeart; if (curHeart && !_receiveHeartMsg) { //判断如果第一次收到心跳消息,重新计算计时器 _receiveHeartMsg = true; for (int i = _timeEventList.Count - 1; i >= 0; --i) { CalculateExecuteTime(_timeEventList[i]); } _timeEventList.Sort(TimerSort); _crossDayTime = GetCrossDayTime((int)GameCenter.HeartSystem.ServerTime); } if (curHeart) { var serverTime = GameCenter.HeartSystem.ServerTime + GameCenter.HeartSystem.ServerZoneOffset; bool reSort = false; for (int i = _timeEventList.Count - 1; i >= 0; --i) { if(i >= _timeEventList.Count) { continue; } var timer = _timeEventList[i]; if (CheckTimer(timer, serverTime)) { if (timer.Loop) { //循环的计时器,需要重新排序 reSort = true; } else { _timeEventList.Remove(timer); } } else { break; } } if (reSort) { _timeEventList.Sort(TimerSort); } if (GameCenter.HeartSystem.ServerTime >= _crossDayTime) { _crossDayTime = GetCrossDayTime((int)GameCenter.HeartSystem.ServerTime); GameCenter.PushFixEvent(Global.LogicEventDefine.EID_EVENT_CROSSDAY); } } return base.OnUpdate(deltaTime); } private bool CheckTimer(TimerEventInfo timer, double serverTime) { if (serverTime >= timer.NextExecuteTime) { //已经超过了执行的时间,判断是否还在有效期内 var outTime = serverTime - timer.NextExecuteTime; if (outTime < timer.ValidTimeValue || timer.Type == TimerEventType.CountDown) { //还在有效期,执行事件 if (!timer.IsExecute) { timer.CallBack(timer.ID, timer.ValidTimeValue - outTime, timer.Param); } if (!timer.Loop) { timer.IsExecute = true; } } if (timer.Loop) { timer.IsExecute = false; switch (timer.Type) { case TimerEventType.CountDown: //下一次处理时间 timer.NextExecuteTime = serverTime + timer.TimeValue; break; case TimerEventType.TimeStampHour: { //下一次处理时间 DateTime curDateTime = new DateTime(1970, 1, 1, 0, 0, 0); long lTime = long.Parse(((ulong)serverTime).ToString() + "0000000"); TimeSpan toNow = new TimeSpan(lTime); curDateTime = curDateTime.Add(toNow); var hourStartTime = serverTime - curDateTime.Minute * 60 - curDateTime.Second; timer.NextExecuteTime = hourStartTime + HOUR_SEC_COUNT + timer.TimeValue; } break; case TimerEventType.TimeStampDay: { //下一次处理时间 DateTime curDateTime = new DateTime(1970, 1, 1, 0, 0, 0); long lTime = long.Parse(((ulong)serverTime).ToString() + "0000000"); TimeSpan toNow = new TimeSpan(lTime); curDateTime = curDateTime.Add(toNow); var dayStartSec = serverTime - curDateTime.Hour * HOUR_SEC_COUNT - curDateTime.Minute * 60 - curDateTime.Second; timer.NextExecuteTime = dayStartSec + DAY_SEC_COUNT + timer.TimeValue; } break; case TimerEventType.TimeStampWeek: { //下一次处理时间 DateTime curDateTime = new DateTime(1970, 1, 1, 0, 0, 0); long lTime = long.Parse(((ulong)serverTime).ToString() + "0000000"); TimeSpan toNow = new TimeSpan(lTime); curDateTime = curDateTime.Add(toNow); int dayOfWeek = (int)curDateTime.DayOfWeek; if (dayOfWeek == 0) { dayOfWeek = 6; } else { dayOfWeek -= 1; } var weekStartSec = serverTime - dayOfWeek * DAY_SEC_COUNT - curDateTime.Hour * HOUR_SEC_COUNT - curDateTime.Minute * 60 - curDateTime.Second; timer.NextExecuteTime = weekStartSec + WEEK_SEC_COUNT + timer.TimeValue; } break; } } return true; } return false; } //增加计时器统一函数 private int AddTimerEvent(float time, float validTime, TimerEventType type, bool loop, object param, Action callBack) { var timerInfo = new TimerEventInfo(); timerInfo.ID = ++_idCounter; timerInfo.Type = type; timerInfo.Loop = loop; timerInfo.TimeValue = time; timerInfo.ValidTimeValue = validTime; timerInfo.Param = param; timerInfo.AddedTime = GameCenter.HeartSystem.ServerTime + GameCenter.HeartSystem.ServerZoneOffset; timerInfo.CallBack = callBack; timerInfo.IsExecute = false; _timeEventList.Add(timerInfo); if (GameCenter.HeartSystem.IsReceiveHeart) { CalculateExecuteTime(timerInfo); _timeEventList.Sort(TimerSort); } return timerInfo.ID; } //计算下一次执行的时间 private void CalculateExecuteTime(TimerEventInfo timerInfo) { var serverTime = GameCenter.HeartSystem.ServerTime + GameCenter.HeartSystem.ServerZoneOffset; DateTime curDateTime = new DateTime(1970, 1, 1, 0, 0, 0); long lTime = long.Parse(((ulong)serverTime).ToString() + "0000000"); TimeSpan toNow = new TimeSpan(lTime); curDateTime = curDateTime.Add(toNow); switch (timerInfo.Type) { case TimerEventType.CountDown: timerInfo.NextExecuteTime = serverTime + timerInfo.TimeValue; break; case TimerEventType.TimeStampHour: { var hourStartTime = serverTime - curDateTime.Minute * 60 - curDateTime.Second; timerInfo.NextExecuteTime = hourStartTime + timerInfo.TimeValue; while ((timerInfo.NextExecuteTime + timerInfo.ValidTimeValue) < serverTime) { hourStartTime += HOUR_SEC_COUNT; timerInfo.NextExecuteTime = hourStartTime + timerInfo.TimeValue; } } break; case TimerEventType.TimeStampDay: { var dayStartSec = serverTime - curDateTime.Hour * HOUR_SEC_COUNT - curDateTime.Minute * 60 - curDateTime.Second; timerInfo.NextExecuteTime = dayStartSec + timerInfo.TimeValue; while ((timerInfo.NextExecuteTime + timerInfo.ValidTimeValue) < serverTime) { dayStartSec += DAY_SEC_COUNT; timerInfo.NextExecuteTime = dayStartSec + timerInfo.TimeValue; } } break; case TimerEventType.TimeStampWeek: { int dayOfWeek = (int)curDateTime.DayOfWeek; if (dayOfWeek == 0) { dayOfWeek = 6; } else { dayOfWeek -= 1; } var weekStartSec = serverTime - dayOfWeek * DAY_SEC_COUNT - curDateTime.Hour * HOUR_SEC_COUNT - curDateTime.Minute * 60 - curDateTime.Second; timerInfo.NextExecuteTime = weekStartSec + timerInfo.TimeValue; while ((timerInfo.NextExecuteTime + timerInfo.ValidTimeValue) < serverTime) { //已超时,换到下一周 weekStartSec += WEEK_SEC_COUNT; timerInfo.NextExecuteTime = weekStartSec + timerInfo.TimeValue; } } break; } } //排序函数 private int TimerSort(TimerEventInfo left, TimerEventInfo right) { //从后往前排 return right.NextExecuteTime.CompareTo(left.NextExecuteTime); } //获取跨天时间戳 private int GetCrossDayTime(int time) { var dataTime = new DateTime((long)time * 10000000L + 621356256000000000L); return (int)((new DateTime(dataTime.Year, dataTime.Month, dataTime.Day).Ticks - 621356256000000000L) / 10000000L) + 86400; } #endregion } }