using System;
using System.Collections.Generic;
namespace Fort23.Core
{
public enum TimerType
{
None,
Wait, // 等待
Count, // 次数
}
public class TimerEntity : Entity
{
public TimerType timerType;
///
/// 计时时间,毫秒
///
public long time;
///
/// 完成回调
///
public object callback1;
///
/// 次数
///
public int count;
///
/// 针对多次的,每次Hit回调
///
public object callback2;
[CustomMethod(CustomMethodType.Awake)]
public void Awake(TimerType timerType, long time, object callback1, int count, object callback2)
{
this.timerType = timerType;
this.time = time;
this.callback1 = callback1;
this.count = count;
this.callback2 = callback2;
}
[CustomMethod(CustomMethodType.Destroy)]
public void Destroy()
{
this.timerType = TimerType.None;
this.time = 0;
this.callback1 = null;
this.count = 0;
this.callback2 = null;
}
}
public class TimerComponent : Entity
{
public static TimerComponent Instance { get; set; }
///
/// key: time, value: timer id
///
private readonly MultiMap _timeID = new MultiMap();
private readonly Queue _timeOutTime = new Queue();
private readonly Queue _timeOutTimerIds = new Queue();
// 记录最小时间,不用每次都去MultiMap取第一个值
private long _minTime;
[CustomMethod(CustomMethodType.Awake)]
public void Awake()
{
Instance = this;
}
[CustomMethod(CustomMethodType.Update)]
public void Update()
{
if (this._timeID.Count == 0)
{
return;
}
long timeNow = TimeHelper.ServerNow();
if (timeNow < this._minTime)
{
return;
}
foreach (KeyValuePair> kv in this._timeID)
{
long k = kv.Key;
if (k > timeNow)
{
_minTime = k;
break;
}
this._timeOutTime.Enqueue(k);
}
// 2.找出失效时间对应的ID
while (this._timeOutTime.Count > 0)
{
long time = this._timeOutTime.Dequeue();
// 3.取出对应的TimerEntity执行逻辑
for (int i = 0; i < this._timeID[time].Count; i++)
{
TimerEntity timerEntity = this.GetChild(_timeID[time][i]);
if (timerEntity != null)
{
Run(timerEntity, time);
}
}
// foreach (long timerId in this._timeID[time])
// {
// TimerEntity timerEntity = this.GetChild(timerId);
// if (timerEntity != null)
// {
// Run(timerEntity, time);
// }
// }
this._timeID.Remove(time);
}
}
private void Run(TimerEntity timerEntity, long timestamp)
{
switch (timerEntity.timerType)
{
case TimerType.Wait:
{
CTask tcs = timerEntity.callback1 as CTask;
this.Remove(timerEntity.ID);
tcs.SetResult(true);
break;
}
case TimerType.Count:
{
if (timerEntity.count <= 1)
{
Action action = timerEntity.callback1 as Action;
this.Remove(timerEntity.ID);
action?.Invoke();
break;
}
else
{
long currTime = TimeHelper.ServerNow();
long tillTime = currTime - currTime % timestamp + timerEntity.time;
this.AddTimer(tillTime, timerEntity);
Action action = timerEntity.callback2 as Action;
action?.Invoke();
timerEntity.count--;
break;
}
}
}
}
private void AddTimer(long untillTime, TimerEntity timerEntity)
{
this._timeID.Add(untillTime, timerEntity.ID);
if (untillTime < this._minTime)
{
this._minTime = untillTime;
}
}
///
/// 等待1帧(因为实在下一次Update里面刷新,所以WaitAsync传的值小于一帧的间隔就可以)
///
///
public async CTask WaitFrameAsync()
{
return await WaitAsync(1);
}
///
/// 等待time毫秒
///
/// 毫秒
///
public async CTask WaitAsync(long time)
{
if (time == 0)
{
return true;
}
long tillTime = TimeHelper.ServerNow() + time;
CTask tcs = CTask.Create(false);
TimerEntity timerEntity = this.AddChild(TimerType.Wait, 0, tcs, 1, null, true);
this.AddTimer(tillTime, timerEntity);
return await tcs;
}
///
/// 等待到指定毫秒的时间戳
///
/// 毫秒
///
public async CTask WaitTillAsync(long untillTime)
{
if (TimeHelper.ServerNow() >= untillTime)
{
return true;
}
CTask tcs = CTask.Create();
TimerEntity timerEntity = this.AddChild(TimerType.Wait, 0, tcs, 1, null, true);
this.AddTimer(untillTime, timerEntity);
return await tcs;
}
///
///
///
/// 计时器Hit一次的时间(毫秒)
/// 全部count完成时候回调
/// 次数
/// 针对多次执行的Timer,每一次Hit时候的回调
/// ID, 可以通过Remove来手动中止Timer
public TimerEntity AddTimer(long time, Action action1, int count = 1, Action action2 = null)
{
TimerEntity timerEntity = this.AddChild(TimerType.Count, time, action1, count, action2, true);
this.AddTimer(TimeHelper.ServerNow() + time, timerEntity);
return timerEntity;
}
public void Remove(ref long id)
{
this.Remove(id);
id = 0;
}
public bool Remove(TimerEntity timerEntity)
{
if (timerEntity == null)
{
return false;
}
timerEntity.Dispose();
return true;
}
public bool Remove(long id)
{
if (id == 0)
{
return false;
}
TimerEntity timerEntity = this.GetChild(id);
return Remove(timerEntity);
}
}
}