using ET; namespace KYFramework; [ObjectSystem] public class TimerComponentAwakeSystem : AwakeSystem { public override void Awake(TimerComponent self) { TimerComponent.Instance = self; } } [ObjectSystem] public class TimerComponentUpdateSystem : UpdateSystem { public override void Update(TimerComponent self) { if (self.TimeId.Count == 0) { return; } long timeNow = self.GetNow(); if (timeNow < self.minTime) { return; } foreach (KeyValuePair> kv in self.TimeId) { long k = kv.Key; if (k > timeNow) { self.minTime = k; break; } self.timeOutTime.Enqueue(k); } while (self.timeOutTime.Count > 0) { long time = self.timeOutTime.Dequeue(); var list = self.TimeId[time]; for (int i = 0; i < list.Count; ++i) { long timerId = list[i]; self.timeOutTimerIds.Enqueue(timerId); } self.TimeId.Remove(time); } while (self.timeOutTimerIds.Count > 0) { long timerId = self.timeOutTimerIds.Dequeue(); if (!self.timerActions.Remove(timerId, out TimerAction timerAction)) { continue; } self.Run(timerAction); } } } public static class TimerComponentSystem { public static long GetNow(this TimerComponent self) { return TimeHelper.ClientFrameTime(); } public static void Run(this TimerComponent self, TimerAction timerAction) { switch (timerAction.TimerClass) { case TimerClass.OnceTimer: { Game.EventSystem.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object }); timerAction.Recycle(); break; } case TimerClass.OnceWaitTimer: { ETTask tcs = timerAction.Object as ETTask; tcs.SetResult(); timerAction.Recycle(); break; } case TimerClass.RepeatedTimer: { long timeNow = self.GetNow(); timerAction.StartTime = timeNow; self.AddTimer(timerAction); Game.EventSystem.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object }); break; } } } private static void AddTimer(this TimerComponent self, TimerAction timer) { long tillTime = timer.StartTime + timer.Time; self.TimeId.Add(tillTime, timer.Id); self.timerActions.Add(timer.Id, timer); if (tillTime < self.minTime) { self.minTime = tillTime; } } public static bool Remove(this TimerComponent self, ref long id) { long i = id; id = 0; return self.Remove(i); } private static bool Remove(this TimerComponent self, long id) { if (id == 0) { return false; } if (!self.timerActions.Remove(id, out TimerAction timerAction)) { return false; } timerAction.Recycle(); return true; } public static async ETTask WaitTillAsync(this TimerComponent self, long tillTime, ETCancellationToken cancellationToken = null) { long timeNow = self.GetNow(); if (timeNow >= tillTime) { return; } ETTask tcs = ETTask.Create(true); TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.OnceWaitTimer, timeNow, tillTime - timeNow, 0, tcs); self.AddTimer(timer); long timerId = timer.Id; void CancelAction() { if (self.Remove(timerId)) { tcs.SetResult(); } } try { cancellationToken?.Add(CancelAction); await tcs; } finally { cancellationToken?.Remove(CancelAction); } } public static async ETTask WaitFrameAsync(this TimerComponent self, ETCancellationToken cancellationToken = null) { await self.WaitAsync(1, cancellationToken); } public static async ETTask WaitAsync(this TimerComponent self, long time, ETCancellationToken cancellationToken = null) { if (time == 0) { return; } long timeNow = self.GetNow(); ETTask tcs = ETTask.Create(true); TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.OnceWaitTimer, timeNow, time, 0, tcs); self.AddTimer(timer); long timerId = timer.Id; void CancelAction() { if (self.Remove(timerId)) { tcs.SetResult(); } } try { cancellationToken?.Add(CancelAction); await tcs; } finally { cancellationToken?.Remove(CancelAction); } } // 用这个优点是可以热更,缺点是回调式的写法,逻辑不连贯。WaitTillAsync不能热更,优点是逻辑连贯。 // wait时间短并且逻辑需要连贯的建议WaitTillAsync // wait时间长不需要逻辑连贯的建议用NewOnceTimer public static long NewOnceTimer(this TimerComponent self, long tillTime, int type, object args) { long timeNow = self.GetNow(); if (tillTime < timeNow) { Log.Error($"new once time too small: {tillTime}"); } TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.OnceTimer, timeNow, tillTime - timeNow, type, args); self.AddTimer(timer); return timer.Id; } public static long NewFrameTimer(this TimerComponent self, int type, object args) { return self.NewRepeatedTimerInner(100, type, args); } /// /// 创建一个RepeatedTimer /// private static long NewRepeatedTimerInner(this TimerComponent self, long time, int type, object args) { if (time < 100) { throw new Exception($"repeated timer < 100, timerType: time: {time}"); } long timeNow = self.GetNow(); TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.RepeatedTimer, timeNow, time, type, args); // 每帧执行的不用加到timerId中,防止遍历 self.AddTimer(timer); return timer.Id; } public static long NewRepeatedTimer(this TimerComponent self, long time, int type, object args) { if (time < 100) { Log.Error($"time too small: {time}"); return 0; } return self.NewRepeatedTimerInner(time, type, args); } private static long GetId(this TimerComponent self) { return ++self.idGenerator; } }