Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

582 lignes
22 KiB

  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. using System;
  3. using System.Linq;
  4. using UnityEngine;
  5. using Cysharp.Threading.Tasks.Internal;
  6. using System.Threading;
  7. #if UNITY_2019_3_OR_NEWER
  8. using UnityEngine.LowLevel;
  9. using PlayerLoopType = UnityEngine.PlayerLoop;
  10. #else
  11. using UnityEngine.Experimental.LowLevel;
  12. using PlayerLoopType = UnityEngine.Experimental.PlayerLoop;
  13. #endif
  14. #if UNITY_EDITOR
  15. using UnityEditor;
  16. #endif
  17. namespace Cysharp.Threading.Tasks
  18. {
  19. public static class UniTaskLoopRunners
  20. {
  21. public struct UniTaskLoopRunnerInitialization { };
  22. public struct UniTaskLoopRunnerEarlyUpdate { };
  23. public struct UniTaskLoopRunnerFixedUpdate { };
  24. public struct UniTaskLoopRunnerPreUpdate { };
  25. public struct UniTaskLoopRunnerUpdate { };
  26. public struct UniTaskLoopRunnerPreLateUpdate { };
  27. public struct UniTaskLoopRunnerPostLateUpdate { };
  28. // Last
  29. public struct UniTaskLoopRunnerLastInitialization { };
  30. public struct UniTaskLoopRunnerLastEarlyUpdate { };
  31. public struct UniTaskLoopRunnerLastFixedUpdate { };
  32. public struct UniTaskLoopRunnerLastPreUpdate { };
  33. public struct UniTaskLoopRunnerLastUpdate { };
  34. public struct UniTaskLoopRunnerLastPreLateUpdate { };
  35. public struct UniTaskLoopRunnerLastPostLateUpdate { };
  36. // Yield
  37. public struct UniTaskLoopRunnerYieldInitialization { };
  38. public struct UniTaskLoopRunnerYieldEarlyUpdate { };
  39. public struct UniTaskLoopRunnerYieldFixedUpdate { };
  40. public struct UniTaskLoopRunnerYieldPreUpdate { };
  41. public struct UniTaskLoopRunnerYieldUpdate { };
  42. public struct UniTaskLoopRunnerYieldPreLateUpdate { };
  43. public struct UniTaskLoopRunnerYieldPostLateUpdate { };
  44. // Yield Last
  45. public struct UniTaskLoopRunnerLastYieldInitialization { };
  46. public struct UniTaskLoopRunnerLastYieldEarlyUpdate { };
  47. public struct UniTaskLoopRunnerLastYieldFixedUpdate { };
  48. public struct UniTaskLoopRunnerLastYieldPreUpdate { };
  49. public struct UniTaskLoopRunnerLastYieldUpdate { };
  50. public struct UniTaskLoopRunnerLastYieldPreLateUpdate { };
  51. public struct UniTaskLoopRunnerLastYieldPostLateUpdate { };
  52. #if UNITY_2020_2_OR_NEWER
  53. public struct UniTaskLoopRunnerTimeUpdate { };
  54. public struct UniTaskLoopRunnerLastTimeUpdate { };
  55. public struct UniTaskLoopRunnerYieldTimeUpdate { };
  56. public struct UniTaskLoopRunnerLastYieldTimeUpdate { };
  57. #endif
  58. }
  59. public enum PlayerLoopTiming
  60. {
  61. Initialization = 0,
  62. LastInitialization = 1,
  63. EarlyUpdate = 2,
  64. LastEarlyUpdate = 3,
  65. FixedUpdate = 4,
  66. LastFixedUpdate = 5,
  67. PreUpdate = 6,
  68. LastPreUpdate = 7,
  69. Update = 8,
  70. LastUpdate = 9,
  71. PreLateUpdate = 10,
  72. LastPreLateUpdate = 11,
  73. PostLateUpdate = 12,
  74. LastPostLateUpdate = 13,
  75. #if UNITY_2020_2_OR_NEWER
  76. // Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
  77. TimeUpdate = 14,
  78. LastTimeUpdate = 15,
  79. #endif
  80. }
  81. [Flags]
  82. public enum InjectPlayerLoopTimings
  83. {
  84. /// <summary>
  85. /// Preset: All loops(default).
  86. /// </summary>
  87. All =
  88. Initialization | LastInitialization |
  89. EarlyUpdate | LastEarlyUpdate |
  90. FixedUpdate | LastFixedUpdate |
  91. PreUpdate | LastPreUpdate |
  92. Update | LastUpdate |
  93. PreLateUpdate | LastPreLateUpdate |
  94. PostLateUpdate | LastPostLateUpdate
  95. #if UNITY_2020_2_OR_NEWER
  96. | TimeUpdate | LastTimeUpdate,
  97. #else
  98. ,
  99. #endif
  100. /// <summary>
  101. /// Preset: All without last except LastPostLateUpdate.
  102. /// </summary>
  103. Standard =
  104. Initialization |
  105. EarlyUpdate |
  106. FixedUpdate |
  107. PreUpdate |
  108. Update |
  109. PreLateUpdate |
  110. PostLateUpdate | LastPostLateUpdate
  111. #if UNITY_2020_2_OR_NEWER
  112. | TimeUpdate
  113. #endif
  114. ,
  115. /// <summary>
  116. /// Preset: Minimum pattern, Update | FixedUpdate | LastPostLateUpdate
  117. /// </summary>
  118. Minimum =
  119. Update | FixedUpdate | LastPostLateUpdate,
  120. // PlayerLoopTiming
  121. Initialization = 1,
  122. LastInitialization = 2,
  123. EarlyUpdate = 4,
  124. LastEarlyUpdate = 8,
  125. FixedUpdate = 16,
  126. LastFixedUpdate = 32,
  127. PreUpdate = 64,
  128. LastPreUpdate = 128,
  129. Update = 256,
  130. LastUpdate = 512,
  131. PreLateUpdate = 1024,
  132. LastPreLateUpdate = 2048,
  133. PostLateUpdate = 4096,
  134. LastPostLateUpdate = 8192
  135. #if UNITY_2020_2_OR_NEWER
  136. ,
  137. // Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
  138. TimeUpdate = 16384,
  139. LastTimeUpdate = 32768
  140. #endif
  141. }
  142. public interface IPlayerLoopItem
  143. {
  144. bool MoveNext();
  145. }
  146. public static class PlayerLoopHelper
  147. {
  148. static readonly ContinuationQueue ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);
  149. static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);
  150. public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContext;
  151. public static int MainThreadId => mainThreadId;
  152. internal static string ApplicationDataPath => applicationDataPath;
  153. public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;
  154. static int mainThreadId;
  155. static string applicationDataPath;
  156. static SynchronizationContext unitySynchronizationContext;
  157. static ContinuationQueue[] yielders;
  158. static PlayerLoopRunner[] runners;
  159. internal static bool IsEditorApplicationQuitting { get; private set; }
  160. static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
  161. bool injectOnFirst,
  162. Type loopRunnerYieldType, ContinuationQueue cq,
  163. Type loopRunnerType, PlayerLoopRunner runner)
  164. {
  165. #if UNITY_EDITOR
  166. EditorApplication.playModeStateChanged += (state) =>
  167. {
  168. if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.ExitingEditMode)
  169. {
  170. IsEditorApplicationQuitting = true;
  171. // run rest action before clear.
  172. if (runner != null)
  173. {
  174. runner.Run();
  175. runner.Clear();
  176. }
  177. if (cq != null)
  178. {
  179. cq.Run();
  180. cq.Clear();
  181. }
  182. IsEditorApplicationQuitting = false;
  183. }
  184. };
  185. #endif
  186. var yieldLoop = new PlayerLoopSystem
  187. {
  188. type = loopRunnerYieldType,
  189. updateDelegate = cq.Run
  190. };
  191. var runnerLoop = new PlayerLoopSystem
  192. {
  193. type = loopRunnerType,
  194. updateDelegate = runner.Run
  195. };
  196. // Remove items from previous initializations.
  197. var source = RemoveRunner(loopSystem, loopRunnerYieldType, loopRunnerType);
  198. var dest = new PlayerLoopSystem[source.Length + 2];
  199. Array.Copy(source, 0, dest, injectOnFirst ? 2 : 0, source.Length);
  200. if (injectOnFirst)
  201. {
  202. dest[0] = yieldLoop;
  203. dest[1] = runnerLoop;
  204. }
  205. else
  206. {
  207. dest[dest.Length - 2] = yieldLoop;
  208. dest[dest.Length - 1] = runnerLoop;
  209. }
  210. return dest;
  211. }
  212. static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
  213. {
  214. return loopSystem.subSystemList
  215. .Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType)
  216. .ToArray();
  217. }
  218. static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
  219. {
  220. var loop = new PlayerLoopSystem
  221. {
  222. type = typeof(UniTaskSynchronizationContext),
  223. updateDelegate = UniTaskSynchronizationContext.Run
  224. };
  225. // Remove items from previous initializations.
  226. var source = loopSystem.subSystemList
  227. .Where(ls => ls.type != typeof(UniTaskSynchronizationContext))
  228. .ToArray();
  229. var dest = new System.Collections.Generic.List<PlayerLoopSystem>(source);
  230. var index = dest.FindIndex(x => x.type.Name == "ScriptRunDelayedTasks");
  231. if (index == -1)
  232. {
  233. index = dest.FindIndex(x => x.type.Name == "UniTaskLoopRunnerUpdate");
  234. }
  235. dest.Insert(index + 1, loop);
  236. return dest.ToArray();
  237. }
  238. #if UNITY_2020_1_OR_NEWER
  239. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
  240. #else
  241. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
  242. #endif
  243. static void Init()
  244. {
  245. // capture default(unity) sync-context.
  246. unitySynchronizationContext = SynchronizationContext.Current;
  247. mainThreadId = Thread.CurrentThread.ManagedThreadId;
  248. try
  249. {
  250. applicationDataPath = Application.dataPath;
  251. }
  252. catch { }
  253. #if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
  254. // When domain reload is disabled, re-initialization is required when entering play mode;
  255. // otherwise, pending tasks will leak between play mode sessions.
  256. var domainReloadDisabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled &&
  257. UnityEditor.EditorSettings.enterPlayModeOptions.HasFlag(UnityEditor.EnterPlayModeOptions.DisableDomainReload);
  258. if (!domainReloadDisabled && runners != null) return;
  259. #else
  260. if (runners != null) return; // already initialized
  261. #endif
  262. var playerLoop =
  263. #if UNITY_2019_3_OR_NEWER
  264. PlayerLoop.GetCurrentPlayerLoop();
  265. #else
  266. PlayerLoop.GetDefaultPlayerLoop();
  267. #endif
  268. Initialize(ref playerLoop);
  269. }
  270. #if UNITY_EDITOR
  271. [InitializeOnLoadMethod]
  272. static void InitOnEditor()
  273. {
  274. // Execute the play mode init method
  275. Init();
  276. // register an Editor update delegate, used to forcing playerLoop update
  277. EditorApplication.update += ForceEditorPlayerLoopUpdate;
  278. }
  279. private static void ForceEditorPlayerLoopUpdate()
  280. {
  281. if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
  282. {
  283. // Not in Edit mode, don't interfere
  284. return;
  285. }
  286. // EditorApplication.QueuePlayerLoopUpdate causes performance issue, don't call directly.
  287. // EditorApplication.QueuePlayerLoopUpdate();
  288. if (yielders != null)
  289. {
  290. foreach (var item in yielders)
  291. {
  292. if (item != null) item.Run();
  293. }
  294. }
  295. if (runners != null)
  296. {
  297. foreach (var item in runners)
  298. {
  299. if (item != null) item.Run();
  300. }
  301. }
  302. UniTaskSynchronizationContext.Run();
  303. }
  304. #endif
  305. private static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
  306. {
  307. for (int i = 0; i < playerLoopList.Length; i++)
  308. {
  309. if (playerLoopList[i].type == systemType)
  310. {
  311. return i;
  312. }
  313. }
  314. throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
  315. }
  316. static void InsertLoop(PlayerLoopSystem[] copyList, InjectPlayerLoopTimings injectTimings, Type loopType, InjectPlayerLoopTimings targetTimings,
  317. int index, bool injectOnFirst, Type loopRunnerYieldType, Type loopRunnerType, PlayerLoopTiming playerLoopTiming)
  318. {
  319. var i = FindLoopSystemIndex(copyList, loopType);
  320. if ((injectTimings & targetTimings) == targetTimings)
  321. {
  322. copyList[i].subSystemList = InsertRunner(copyList[i], injectOnFirst,
  323. loopRunnerYieldType, yielders[index] = new ContinuationQueue(playerLoopTiming),
  324. loopRunnerType, runners[index] = new PlayerLoopRunner(playerLoopTiming));
  325. }
  326. else
  327. {
  328. copyList[i].subSystemList = RemoveRunner(copyList[i], loopRunnerYieldType, loopRunnerType);
  329. }
  330. }
  331. public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopTimings injectTimings = InjectPlayerLoopTimings.All)
  332. {
  333. #if UNITY_2020_2_OR_NEWER
  334. yielders = new ContinuationQueue[16];
  335. runners = new PlayerLoopRunner[16];
  336. #else
  337. yielders = new ContinuationQueue[14];
  338. runners = new PlayerLoopRunner[14];
  339. #endif
  340. var copyList = playerLoop.subSystemList.ToArray();
  341. // Initialization
  342. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
  343. InjectPlayerLoopTimings.Initialization, 0, true,
  344. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), PlayerLoopTiming.Initialization);
  345. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
  346. InjectPlayerLoopTimings.LastInitialization, 1, false,
  347. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), PlayerLoopTiming.LastInitialization);
  348. // EarlyUpdate
  349. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
  350. InjectPlayerLoopTimings.EarlyUpdate, 2, true,
  351. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), PlayerLoopTiming.EarlyUpdate);
  352. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
  353. InjectPlayerLoopTimings.LastEarlyUpdate, 3, false,
  354. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), PlayerLoopTiming.LastEarlyUpdate);
  355. // FixedUpdate
  356. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
  357. InjectPlayerLoopTimings.FixedUpdate, 4, true,
  358. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), PlayerLoopTiming.FixedUpdate);
  359. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
  360. InjectPlayerLoopTimings.LastFixedUpdate, 5, false,
  361. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), PlayerLoopTiming.LastFixedUpdate);
  362. // PreUpdate
  363. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
  364. InjectPlayerLoopTimings.PreUpdate, 6, true,
  365. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), PlayerLoopTiming.PreUpdate);
  366. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
  367. InjectPlayerLoopTimings.LastPreUpdate, 7, false,
  368. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), PlayerLoopTiming.LastPreUpdate);
  369. // Update
  370. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
  371. InjectPlayerLoopTimings.Update, 8, true,
  372. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), PlayerLoopTiming.Update);
  373. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
  374. InjectPlayerLoopTimings.LastUpdate, 9, false,
  375. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), PlayerLoopTiming.LastUpdate);
  376. // PreLateUpdate
  377. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
  378. InjectPlayerLoopTimings.PreLateUpdate, 10, true,
  379. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), PlayerLoopTiming.PreLateUpdate);
  380. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
  381. InjectPlayerLoopTimings.LastPreLateUpdate, 11, false,
  382. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), PlayerLoopTiming.LastPreLateUpdate);
  383. // PostLateUpdate
  384. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
  385. InjectPlayerLoopTimings.PostLateUpdate, 12, true,
  386. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), PlayerLoopTiming.PostLateUpdate);
  387. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
  388. InjectPlayerLoopTimings.LastPostLateUpdate, 13, false,
  389. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), PlayerLoopTiming.LastPostLateUpdate);
  390. #if UNITY_2020_2_OR_NEWER
  391. // TimeUpdate
  392. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
  393. InjectPlayerLoopTimings.TimeUpdate, 14, true,
  394. typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), PlayerLoopTiming.TimeUpdate);
  395. InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
  396. InjectPlayerLoopTimings.LastTimeUpdate, 15, false,
  397. typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), PlayerLoopTiming.LastTimeUpdate);
  398. #endif
  399. // Insert UniTaskSynchronizationContext to Update loop
  400. var i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
  401. copyList[i].subSystemList = InsertUniTaskSynchronizationContext(copyList[i]);
  402. playerLoop.subSystemList = copyList;
  403. PlayerLoop.SetPlayerLoop(playerLoop);
  404. }
  405. public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
  406. {
  407. var runner = runners[(int)timing];
  408. if (runner == null)
  409. {
  410. ThrowInvalidLoopTiming(timing);
  411. }
  412. runner.AddAction(action);
  413. }
  414. static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming)
  415. {
  416. throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming);
  417. }
  418. public static void AddContinuation(PlayerLoopTiming timing, Action continuation)
  419. {
  420. var q = yielders[(int)timing];
  421. if (q == null)
  422. {
  423. ThrowInvalidLoopTiming(timing);
  424. }
  425. q.Enqueue(continuation);
  426. }
  427. // Diagnostics helper
  428. #if UNITY_2019_3_OR_NEWER
  429. public static void DumpCurrentPlayerLoop()
  430. {
  431. var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
  432. var sb = new System.Text.StringBuilder();
  433. sb.AppendLine($"PlayerLoop List");
  434. foreach (var header in playerLoop.subSystemList)
  435. {
  436. sb.AppendFormat("------{0}------", header.type.Name);
  437. sb.AppendLine();
  438. if (header.subSystemList is null)
  439. {
  440. sb.AppendFormat("{0} has no subsystems!", header.ToString());
  441. sb.AppendLine();
  442. continue;
  443. }
  444. foreach (var subSystem in header.subSystemList)
  445. {
  446. sb.AppendFormat("{0}", subSystem.type.Name);
  447. sb.AppendLine();
  448. if (subSystem.subSystemList != null)
  449. {
  450. UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
  451. }
  452. }
  453. }
  454. UnityEngine.Debug.Log(sb.ToString());
  455. }
  456. public static bool IsInjectedUniTaskPlayerLoop()
  457. {
  458. var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
  459. foreach (var header in playerLoop.subSystemList)
  460. {
  461. if (header.subSystemList is null)
  462. {
  463. continue;
  464. }
  465. foreach (var subSystem in header.subSystemList)
  466. {
  467. if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
  468. {
  469. return true;
  470. }
  471. }
  472. }
  473. return false;
  474. }
  475. #endif
  476. }
  477. }