363 lines
16 KiB
C#
363 lines
16 KiB
C#
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<TimerEventInfo> _timeEventList = new List<TimerEventInfo>();
|
||
//记录心跳系统是否已经接收到心跳信息
|
||
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//公有函数
|
||
/// <summary>
|
||
/// 增加倒计时事件
|
||
/// </summary>
|
||
/// <param name="countDownTime 倒计时时间,单位秒"></param>
|
||
/// <param loop="是否循环,不循环就只会执行1次,循环就会循环倒计时"></param>
|
||
/// <param callBack="时间到时的回调函数,参数为计时器id"></param>
|
||
/// <returns>返回计时器ID,如果小于0表示添加失败</returns>
|
||
public int AddCountDownEvent(float countDownTime, bool loop, object param, Action<int, double, object> callBack)
|
||
{
|
||
if (countDownTime <= 0f)
|
||
return -1;
|
||
|
||
if (callBack == null)
|
||
return -1;
|
||
return AddTimerEvent(countDownTime, 0f, TimerEventType.CountDown, loop, param, callBack);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 增加小时时间戳计时器,每个小时到达指定时间时通知
|
||
/// </summary>
|
||
/// <param time="时间值,单位秒,每小时达到这个时间的时候通知,本时间必须小于1小时"></param>
|
||
/// <param loop="是否循环,不循环就只会执行1次,循环就会循环计时"></param>
|
||
/// <param callBack="时间到时的回调函数,参数为计时器id"></param>
|
||
/// <returns>返回计时器ID,如果小于0表示添加失败</returns>
|
||
public int AddTimeStampHourEvent(float time, float validTime, bool loop, object param, Action<int, double, object> callBack)
|
||
{
|
||
if (time <= 0f || time >= HOUR_SEC_COUNT)
|
||
return -1;
|
||
if (callBack == null)
|
||
return -1;
|
||
return AddTimerEvent(time, validTime, TimerEventType.TimeStampHour, loop, param, callBack);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 增加天时间戳计时器,每天到达指定时间时通知
|
||
/// </summary>
|
||
/// <param time="时间值,单位秒,每天达到这个时间的时候通知,本时间必须小于1天"></param>
|
||
/// <param loop="是否循环,不循环就只会执行1次,循环就会循环计时"></param>
|
||
/// <param callBack="时间到时的回调函数,参数为计时器id"></param>
|
||
/// <returns>返回计时器ID,如果小于0表示添加失败</returns>
|
||
public int AddTimeStampDayEvent(float time, float validTime, bool loop, object param, Action<int, double, object> callBack)
|
||
{
|
||
if (time <= 0f || time >= DAY_SEC_COUNT)
|
||
return -1;
|
||
if (callBack == null)
|
||
return -1;
|
||
return AddTimerEvent(time, validTime, TimerEventType.TimeStampDay, loop, param, callBack);
|
||
}
|
||
/// <summary>
|
||
/// 增加周时间戳计时器,每周到达指定时间时通知
|
||
/// </summary>
|
||
/// <param time="时间值,单位秒,每周达到这个时间的时候通知,本时间必须小于1周"></param>
|
||
/// <param loop="是否循环,不循环就只会执行1次,循环就会循环计时"></param>
|
||
/// <param callBack="时间到时的回调函数,参数为计时器id"></param>
|
||
/// <returns>返回计时器ID,如果小于0表示添加失败</returns>
|
||
public int AddTimeStampWeekEvent(float time, float validTime, bool loop, object param, Action<int, double, object> 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);
|
||
}
|
||
/// <summary>
|
||
/// 删除计时器
|
||
/// </summary>
|
||
/// <param name="id 计时器id"></param>
|
||
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<int, double, object> 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
|
||
}
|
||
}
|