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