TimerComponentSystem.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. using ET;
  2. namespace KYFramework;
  3. [ObjectSystem]
  4. public class TimerComponentAwakeSystem : AwakeSystem<TimerComponent>
  5. {
  6. public override void Awake(TimerComponent self)
  7. {
  8. TimerComponent.Instance = self;
  9. }
  10. }
  11. [ObjectSystem]
  12. public class TimerComponentUpdateSystem : UpdateSystem<TimerComponent>
  13. {
  14. public override void Update(TimerComponent self)
  15. {
  16. if (self.TimeId.Count == 0)
  17. {
  18. return;
  19. }
  20. long timeNow = self.GetNow();
  21. if (timeNow < self.minTime)
  22. {
  23. return;
  24. }
  25. foreach (KeyValuePair<long, List<long>> kv in self.TimeId)
  26. {
  27. long k = kv.Key;
  28. if (k > timeNow)
  29. {
  30. self.minTime = k;
  31. break;
  32. }
  33. self.timeOutTime.Enqueue(k);
  34. }
  35. while (self.timeOutTime.Count > 0)
  36. {
  37. long time = self.timeOutTime.Dequeue();
  38. var list = self.TimeId[time];
  39. for (int i = 0; i < list.Count; ++i)
  40. {
  41. long timerId = list[i];
  42. self.timeOutTimerIds.Enqueue(timerId);
  43. }
  44. self.TimeId.Remove(time);
  45. }
  46. while (self.timeOutTimerIds.Count > 0)
  47. {
  48. long timerId = self.timeOutTimerIds.Dequeue();
  49. if (!self.timerActions.Remove(timerId, out TimerAction timerAction))
  50. {
  51. continue;
  52. }
  53. self.Run(timerAction);
  54. }
  55. }
  56. }
  57. public static class TimerComponentSystem
  58. {
  59. public static long GetNow(this TimerComponent self)
  60. {
  61. return TimeHelper.ClientFrameTime();
  62. }
  63. public static void Run(this TimerComponent self, TimerAction timerAction)
  64. {
  65. switch (timerAction.TimerClass)
  66. {
  67. case TimerClass.OnceTimer:
  68. {
  69. Game.EventSystem.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object });
  70. timerAction.Recycle();
  71. break;
  72. }
  73. case TimerClass.OnceWaitTimer:
  74. {
  75. ETTask tcs = timerAction.Object as ETTask;
  76. tcs.SetResult();
  77. timerAction.Recycle();
  78. break;
  79. }
  80. case TimerClass.RepeatedTimer:
  81. {
  82. long timeNow = self.GetNow();
  83. timerAction.StartTime = timeNow;
  84. self.AddTimer(timerAction);
  85. Game.EventSystem.Invoke(timerAction.Type, new TimerCallback() { Args = timerAction.Object });
  86. break;
  87. }
  88. }
  89. }
  90. private static void AddTimer(this TimerComponent self, TimerAction timer)
  91. {
  92. long tillTime = timer.StartTime + timer.Time;
  93. self.TimeId.Add(tillTime, timer.Id);
  94. self.timerActions.Add(timer.Id, timer);
  95. if (tillTime < self.minTime)
  96. {
  97. self.minTime = tillTime;
  98. }
  99. }
  100. public static bool Remove(this TimerComponent self, ref long id)
  101. {
  102. long i = id;
  103. id = 0;
  104. return self.Remove(i);
  105. }
  106. private static bool Remove(this TimerComponent self, long id)
  107. {
  108. if (id == 0)
  109. {
  110. return false;
  111. }
  112. if (!self.timerActions.Remove(id, out TimerAction timerAction))
  113. {
  114. return false;
  115. }
  116. timerAction.Recycle();
  117. return true;
  118. }
  119. public static async ETTask WaitTillAsync(this TimerComponent self, long tillTime,
  120. ETCancellationToken cancellationToken = null)
  121. {
  122. long timeNow = self.GetNow();
  123. if (timeNow >= tillTime)
  124. {
  125. return;
  126. }
  127. ETTask tcs = ETTask.Create(true);
  128. TimerAction timer =
  129. TimerAction.Create(self.GetId(), TimerClass.OnceWaitTimer, timeNow, tillTime - timeNow, 0, tcs);
  130. self.AddTimer(timer);
  131. long timerId = timer.Id;
  132. void CancelAction()
  133. {
  134. if (self.Remove(timerId))
  135. {
  136. tcs.SetResult();
  137. }
  138. }
  139. try
  140. {
  141. cancellationToken?.Add(CancelAction);
  142. await tcs;
  143. }
  144. finally
  145. {
  146. cancellationToken?.Remove(CancelAction);
  147. }
  148. }
  149. public static async ETTask WaitFrameAsync(this TimerComponent self, ETCancellationToken cancellationToken = null)
  150. {
  151. await self.WaitAsync(1, cancellationToken);
  152. }
  153. public static async ETTask WaitAsync(this TimerComponent self, long time,
  154. ETCancellationToken cancellationToken = null)
  155. {
  156. if (time == 0)
  157. {
  158. return;
  159. }
  160. long timeNow = self.GetNow();
  161. ETTask tcs = ETTask.Create(true);
  162. TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.OnceWaitTimer, timeNow, time, 0, tcs);
  163. self.AddTimer(timer);
  164. long timerId = timer.Id;
  165. void CancelAction()
  166. {
  167. if (self.Remove(timerId))
  168. {
  169. tcs.SetResult();
  170. }
  171. }
  172. try
  173. {
  174. cancellationToken?.Add(CancelAction);
  175. await tcs;
  176. }
  177. finally
  178. {
  179. cancellationToken?.Remove(CancelAction);
  180. }
  181. }
  182. // 用这个优点是可以热更,缺点是回调式的写法,逻辑不连贯。WaitTillAsync不能热更,优点是逻辑连贯。
  183. // wait时间短并且逻辑需要连贯的建议WaitTillAsync
  184. // wait时间长不需要逻辑连贯的建议用NewOnceTimer
  185. public static long NewOnceTimer(this TimerComponent self, long tillTime, int type, object args)
  186. {
  187. long timeNow = self.GetNow();
  188. if (tillTime < timeNow)
  189. {
  190. Log.Error($"new once time too small: {tillTime}");
  191. }
  192. TimerAction timer =
  193. TimerAction.Create(self.GetId(), TimerClass.OnceTimer, timeNow, tillTime - timeNow, type, args);
  194. self.AddTimer(timer);
  195. return timer.Id;
  196. }
  197. public static long NewFrameTimer(this TimerComponent self, int type, object args)
  198. {
  199. return self.NewRepeatedTimerInner(100, type, args);
  200. }
  201. /// <summary>
  202. /// 创建一个RepeatedTimer
  203. /// </summary>
  204. private static long NewRepeatedTimerInner(this TimerComponent self, long time, int type, object args)
  205. {
  206. if (time < 100)
  207. {
  208. throw new Exception($"repeated timer < 100, timerType: time: {time}");
  209. }
  210. long timeNow = self.GetNow();
  211. TimerAction timer = TimerAction.Create(self.GetId(), TimerClass.RepeatedTimer, timeNow, time, type, args);
  212. // 每帧执行的不用加到timerId中,防止遍历
  213. self.AddTimer(timer);
  214. return timer.Id;
  215. }
  216. public static long NewRepeatedTimer(this TimerComponent self, long time, int type, object args)
  217. {
  218. if (time < 100)
  219. {
  220. Log.Error($"time too small: {time}");
  221. return 0;
  222. }
  223. return self.NewRepeatedTimerInner(time, type, args);
  224. }
  225. private static long GetId(this TimerComponent self)
  226. {
  227. return ++self.idGenerator;
  228. }
  229. }