您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 

261 行
8.0 KiB

  1. using System;
  2. using UnityEngine;
  3. namespace Cysharp.Threading.Tasks.Internal
  4. {
  5. internal sealed class PlayerLoopRunner
  6. {
  7. const int InitialSize = 16;
  8. readonly PlayerLoopTiming timing;
  9. readonly object runningAndQueueLock = new object();
  10. readonly object arrayLock = new object();
  11. readonly Action<Exception> unhandledExceptionCallback;
  12. int tail = 0;
  13. bool running = false;
  14. IPlayerLoopItem[] loopItems = new IPlayerLoopItem[InitialSize];
  15. MinimumQueue<IPlayerLoopItem> waitQueue = new MinimumQueue<IPlayerLoopItem>(InitialSize);
  16. public PlayerLoopRunner(PlayerLoopTiming timing)
  17. {
  18. this.unhandledExceptionCallback = ex => Debug.LogException(ex);
  19. this.timing = timing;
  20. }
  21. public void AddAction(IPlayerLoopItem item)
  22. {
  23. lock (runningAndQueueLock)
  24. {
  25. if (running)
  26. {
  27. waitQueue.Enqueue(item);
  28. return;
  29. }
  30. }
  31. lock (arrayLock)
  32. {
  33. // Ensure Capacity
  34. if (loopItems.Length == tail)
  35. {
  36. Array.Resize(ref loopItems, checked(tail * 2));
  37. }
  38. loopItems[tail++] = item;
  39. }
  40. }
  41. public int Clear()
  42. {
  43. lock (arrayLock)
  44. {
  45. var rest = 0;
  46. for (var index = 0; index < loopItems.Length; index++)
  47. {
  48. if (loopItems[index] != null)
  49. {
  50. rest++;
  51. }
  52. loopItems[index] = null;
  53. }
  54. tail = 0;
  55. return rest;
  56. }
  57. }
  58. // delegate entrypoint.
  59. public void Run()
  60. {
  61. // for debugging, create named stacktrace.
  62. #if DEBUG
  63. switch (timing)
  64. {
  65. case PlayerLoopTiming.Initialization:
  66. Initialization();
  67. break;
  68. case PlayerLoopTiming.LastInitialization:
  69. LastInitialization();
  70. break;
  71. case PlayerLoopTiming.EarlyUpdate:
  72. EarlyUpdate();
  73. break;
  74. case PlayerLoopTiming.LastEarlyUpdate:
  75. LastEarlyUpdate();
  76. break;
  77. case PlayerLoopTiming.FixedUpdate:
  78. FixedUpdate();
  79. break;
  80. case PlayerLoopTiming.LastFixedUpdate:
  81. LastFixedUpdate();
  82. break;
  83. case PlayerLoopTiming.PreUpdate:
  84. PreUpdate();
  85. break;
  86. case PlayerLoopTiming.LastPreUpdate:
  87. LastPreUpdate();
  88. break;
  89. case PlayerLoopTiming.Update:
  90. Update();
  91. break;
  92. case PlayerLoopTiming.LastUpdate:
  93. LastUpdate();
  94. break;
  95. case PlayerLoopTiming.PreLateUpdate:
  96. PreLateUpdate();
  97. break;
  98. case PlayerLoopTiming.LastPreLateUpdate:
  99. LastPreLateUpdate();
  100. break;
  101. case PlayerLoopTiming.PostLateUpdate:
  102. PostLateUpdate();
  103. break;
  104. case PlayerLoopTiming.LastPostLateUpdate:
  105. LastPostLateUpdate();
  106. break;
  107. #if UNITY_2020_2_OR_NEWER
  108. case PlayerLoopTiming.TimeUpdate:
  109. TimeUpdate();
  110. break;
  111. case PlayerLoopTiming.LastTimeUpdate:
  112. LastTimeUpdate();
  113. break;
  114. #endif
  115. default:
  116. break;
  117. }
  118. #else
  119. RunCore();
  120. #endif
  121. }
  122. void Initialization() => RunCore();
  123. void LastInitialization() => RunCore();
  124. void EarlyUpdate() => RunCore();
  125. void LastEarlyUpdate() => RunCore();
  126. void FixedUpdate() => RunCore();
  127. void LastFixedUpdate() => RunCore();
  128. void PreUpdate() => RunCore();
  129. void LastPreUpdate() => RunCore();
  130. void Update() => RunCore();
  131. void LastUpdate() => RunCore();
  132. void PreLateUpdate() => RunCore();
  133. void LastPreLateUpdate() => RunCore();
  134. void PostLateUpdate() => RunCore();
  135. void LastPostLateUpdate() => RunCore();
  136. #if UNITY_2020_2_OR_NEWER
  137. void TimeUpdate() => RunCore();
  138. void LastTimeUpdate() => RunCore();
  139. #endif
  140. [System.Diagnostics.DebuggerHidden]
  141. void RunCore()
  142. {
  143. lock (runningAndQueueLock)
  144. {
  145. running = true;
  146. }
  147. lock (arrayLock)
  148. {
  149. var j = tail - 1;
  150. for (int i = 0; i < loopItems.Length; i++)
  151. {
  152. var action = loopItems[i];
  153. if (action != null)
  154. {
  155. try
  156. {
  157. if (!action.MoveNext())
  158. {
  159. loopItems[i] = null;
  160. }
  161. else
  162. {
  163. continue; // next i
  164. }
  165. }
  166. catch (Exception ex)
  167. {
  168. loopItems[i] = null;
  169. try
  170. {
  171. unhandledExceptionCallback(ex);
  172. }
  173. catch { }
  174. }
  175. }
  176. // find null, loop from tail
  177. while (i < j)
  178. {
  179. var fromTail = loopItems[j];
  180. if (fromTail != null)
  181. {
  182. try
  183. {
  184. if (!fromTail.MoveNext())
  185. {
  186. loopItems[j] = null;
  187. j--;
  188. continue; // next j
  189. }
  190. else
  191. {
  192. // swap
  193. loopItems[i] = fromTail;
  194. loopItems[j] = null;
  195. j--;
  196. goto NEXT_LOOP; // next i
  197. }
  198. }
  199. catch (Exception ex)
  200. {
  201. loopItems[j] = null;
  202. j--;
  203. try
  204. {
  205. unhandledExceptionCallback(ex);
  206. }
  207. catch { }
  208. continue; // next j
  209. }
  210. }
  211. else
  212. {
  213. j--;
  214. }
  215. }
  216. tail = i; // loop end
  217. break; // LOOP END
  218. NEXT_LOOP:
  219. continue;
  220. }
  221. lock (runningAndQueueLock)
  222. {
  223. running = false;
  224. while (waitQueue.Count != 0)
  225. {
  226. if (loopItems.Length == tail)
  227. {
  228. Array.Resize(ref loopItems, checked(tail * 2));
  229. }
  230. loopItems[tail++] = waitQueue.Dequeue();
  231. }
  232. }
  233. }
  234. }
  235. }
  236. }