578 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			578 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
| #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
 | |
| 
 | |
| using System;
 | |
| using System.Linq;
 | |
| using UnityEngine;
 | |
| using Cysharp.Threading.Tasks.Internal;
 | |
| using System.Threading;
 | |
| 
 | |
| #if UNITY_2019_3_OR_NEWER
 | |
| using UnityEngine.LowLevel;
 | |
| using PlayerLoopType = UnityEngine.PlayerLoop;
 | |
| #else
 | |
| using UnityEngine.Experimental.LowLevel;
 | |
| using PlayerLoopType = UnityEngine.Experimental.PlayerLoop;
 | |
| #endif
 | |
| 
 | |
| #if UNITY_EDITOR
 | |
| using UnityEditor;
 | |
| #endif
 | |
| 
 | |
| namespace Cysharp.Threading.Tasks
 | |
| {
 | |
|     public static class UniTaskLoopRunners
 | |
|     {
 | |
|         public struct UniTaskLoopRunnerInitialization { };
 | |
|         public struct UniTaskLoopRunnerEarlyUpdate { };
 | |
|         public struct UniTaskLoopRunnerFixedUpdate { };
 | |
|         public struct UniTaskLoopRunnerPreUpdate { };
 | |
|         public struct UniTaskLoopRunnerUpdate { };
 | |
|         public struct UniTaskLoopRunnerPreLateUpdate { };
 | |
|         public struct UniTaskLoopRunnerPostLateUpdate { };
 | |
| 
 | |
|         // Last
 | |
| 
 | |
|         public struct UniTaskLoopRunnerLastInitialization { };
 | |
|         public struct UniTaskLoopRunnerLastEarlyUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastFixedUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastPreUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastPreLateUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastPostLateUpdate { };
 | |
| 
 | |
|         // Yield
 | |
| 
 | |
|         public struct UniTaskLoopRunnerYieldInitialization { };
 | |
|         public struct UniTaskLoopRunnerYieldEarlyUpdate { };
 | |
|         public struct UniTaskLoopRunnerYieldFixedUpdate { };
 | |
|         public struct UniTaskLoopRunnerYieldPreUpdate { };
 | |
|         public struct UniTaskLoopRunnerYieldUpdate { };
 | |
|         public struct UniTaskLoopRunnerYieldPreLateUpdate { };
 | |
|         public struct UniTaskLoopRunnerYieldPostLateUpdate { };
 | |
| 
 | |
|         // Yield Last
 | |
| 
 | |
|         public struct UniTaskLoopRunnerLastYieldInitialization { };
 | |
|         public struct UniTaskLoopRunnerLastYieldEarlyUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastYieldFixedUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastYieldPreUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastYieldUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastYieldPreLateUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastYieldPostLateUpdate { };
 | |
| 
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|         public struct UniTaskLoopRunnerTimeUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastTimeUpdate { };
 | |
|         public struct UniTaskLoopRunnerYieldTimeUpdate { };
 | |
|         public struct UniTaskLoopRunnerLastYieldTimeUpdate { };
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     public enum PlayerLoopTiming
 | |
|     {
 | |
|         Initialization = 0,
 | |
|         LastInitialization = 1,
 | |
| 
 | |
|         EarlyUpdate = 2,
 | |
|         LastEarlyUpdate = 3,
 | |
| 
 | |
|         FixedUpdate = 4,
 | |
|         LastFixedUpdate = 5,
 | |
| 
 | |
|         PreUpdate = 6,
 | |
|         LastPreUpdate = 7,
 | |
| 
 | |
|         Update = 8,
 | |
|         LastUpdate = 9,
 | |
| 
 | |
|         PreLateUpdate = 10,
 | |
|         LastPreLateUpdate = 11,
 | |
| 
 | |
|         PostLateUpdate = 12,
 | |
|         LastPostLateUpdate = 13,
 | |
| 
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|         // Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
 | |
|         TimeUpdate = 14,
 | |
|         LastTimeUpdate = 15,
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     [Flags]
 | |
|     public enum InjectPlayerLoopTimings
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// Preset: All loops(default).
 | |
|         /// </summary>
 | |
|         All =
 | |
|             Initialization | LastInitialization |
 | |
|             EarlyUpdate | LastEarlyUpdate |
 | |
|             FixedUpdate | LastFixedUpdate |
 | |
|             PreUpdate | LastPreUpdate |
 | |
|             Update | LastUpdate |
 | |
|             PreLateUpdate | LastPreLateUpdate |
 | |
|             PostLateUpdate | LastPostLateUpdate
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|             | TimeUpdate | LastTimeUpdate,
 | |
| #else
 | |
|             ,
 | |
| #endif
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Preset: All without last except LastPostLateUpdate.
 | |
|         /// </summary>
 | |
|         Standard =
 | |
|             Initialization |
 | |
|             EarlyUpdate |
 | |
|             FixedUpdate |
 | |
|             PreUpdate |
 | |
|             Update |
 | |
|             PreLateUpdate |
 | |
|             PostLateUpdate | LastPostLateUpdate
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|             | TimeUpdate
 | |
| #endif
 | |
|             ,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Preset: Minimum pattern, Update | FixedUpdate | LastPostLateUpdate
 | |
|         /// </summary>
 | |
|         Minimum =
 | |
|             Update | FixedUpdate | LastPostLateUpdate,
 | |
| 
 | |
|         // PlayerLoopTiming
 | |
| 
 | |
|         Initialization = 1,
 | |
|         LastInitialization = 2,
 | |
| 
 | |
|         EarlyUpdate = 4,
 | |
|         LastEarlyUpdate = 8,
 | |
| 
 | |
|         FixedUpdate = 16,
 | |
|         LastFixedUpdate = 32,
 | |
| 
 | |
|         PreUpdate = 64,
 | |
|         LastPreUpdate = 128,
 | |
| 
 | |
|         Update = 256,
 | |
|         LastUpdate = 512,
 | |
| 
 | |
|         PreLateUpdate = 1024,
 | |
|         LastPreLateUpdate = 2048,
 | |
| 
 | |
|         PostLateUpdate = 4096,
 | |
|         LastPostLateUpdate = 8192
 | |
| 
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|         ,
 | |
|         // Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
 | |
|         TimeUpdate = 16384,
 | |
|         LastTimeUpdate = 32768
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     public interface IPlayerLoopItem
 | |
|     {
 | |
|         bool MoveNext();
 | |
|     }
 | |
| 
 | |
|     public static class PlayerLoopHelper
 | |
|     {
 | |
|         static readonly ContinuationQueue ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);
 | |
|         static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);
 | |
| 
 | |
|         public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContext;
 | |
|         public static int MainThreadId => mainThreadId;
 | |
|         internal static string ApplicationDataPath => applicationDataPath;
 | |
| 
 | |
|         public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;
 | |
| 
 | |
|         static int mainThreadId;
 | |
|         static string applicationDataPath;
 | |
|         static SynchronizationContext unitySynchronizationContext;
 | |
|         static ContinuationQueue[] yielders;
 | |
|         static PlayerLoopRunner[] runners;
 | |
|         internal static bool IsEditorApplicationQuitting { get; private set; }
 | |
|         static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
 | |
|             bool injectOnFirst,
 | |
|             Type loopRunnerYieldType, ContinuationQueue cq,
 | |
|             Type loopRunnerType, PlayerLoopRunner runner)
 | |
|         {
 | |
| 
 | |
| #if UNITY_EDITOR
 | |
|             EditorApplication.playModeStateChanged += (state) =>
 | |
|             {
 | |
|                 if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.ExitingEditMode)
 | |
|                 {
 | |
|                     IsEditorApplicationQuitting = true;
 | |
|                     // run rest action before clear.
 | |
|                     if (runner != null)
 | |
|                     {
 | |
|                         runner.Run();
 | |
|                         runner.Clear();
 | |
|                     }
 | |
|                     if (cq != null)
 | |
|                     {
 | |
|                         cq.Run();
 | |
|                         cq.Clear();
 | |
|                     }
 | |
|                     IsEditorApplicationQuitting = false;
 | |
|                 }
 | |
|             };
 | |
| #endif
 | |
| 
 | |
|             var yieldLoop = new PlayerLoopSystem
 | |
|             {
 | |
|                 type = loopRunnerYieldType,
 | |
|                 updateDelegate = cq.Run
 | |
|             };
 | |
| 
 | |
|             var runnerLoop = new PlayerLoopSystem
 | |
|             {
 | |
|                 type = loopRunnerType,
 | |
|                 updateDelegate = runner.Run
 | |
|             };
 | |
| 
 | |
|             // Remove items from previous initializations.
 | |
|             var source = RemoveRunner(loopSystem, loopRunnerYieldType, loopRunnerType);
 | |
|             var dest = new PlayerLoopSystem[source.Length + 2];
 | |
| 
 | |
|             Array.Copy(source, 0, dest, injectOnFirst ? 2 : 0, source.Length);
 | |
|             if (injectOnFirst)
 | |
|             {
 | |
|                 dest[0] = yieldLoop;
 | |
|                 dest[1] = runnerLoop;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 dest[dest.Length - 2] = yieldLoop;
 | |
|                 dest[dest.Length - 1] = runnerLoop;
 | |
|             }
 | |
| 
 | |
|             return dest;
 | |
|         }
 | |
| 
 | |
|         static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
 | |
|         {
 | |
|             return loopSystem.subSystemList
 | |
|                 .Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType)
 | |
|                 .ToArray();
 | |
|         }
 | |
| 
 | |
|         static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
 | |
|         {
 | |
|             var loop = new PlayerLoopSystem
 | |
|             {
 | |
|                 type = typeof(UniTaskSynchronizationContext),
 | |
|                 updateDelegate = UniTaskSynchronizationContext.Run
 | |
|             };
 | |
| 
 | |
|             // Remove items from previous initializations.
 | |
|             var source = loopSystem.subSystemList
 | |
|                 .Where(ls => ls.type != typeof(UniTaskSynchronizationContext))
 | |
|                 .ToArray();
 | |
| 
 | |
|             var dest = new System.Collections.Generic.List<PlayerLoopSystem>(source);
 | |
| 
 | |
|             var index = dest.FindIndex(x => x.type.Name == "ScriptRunDelayedTasks");
 | |
|             if (index == -1)
 | |
|             {
 | |
|                 index = dest.FindIndex(x => x.type.Name == "UniTaskLoopRunnerUpdate");
 | |
|             }
 | |
| 
 | |
|             dest.Insert(index + 1, loop);
 | |
| 
 | |
|             return dest.ToArray();
 | |
|         }
 | |
| 
 | |
|         [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
 | |
|         static void Init()
 | |
|         {
 | |
|             // capture default(unity) sync-context.
 | |
|             unitySynchronizationContext = SynchronizationContext.Current;
 | |
|             mainThreadId = Thread.CurrentThread.ManagedThreadId;
 | |
|             try
 | |
|             {
 | |
|                 applicationDataPath = Application.dataPath;
 | |
|             }
 | |
|             catch { }
 | |
| 
 | |
| #if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
 | |
|             // When domain reload is disabled, re-initialization is required when entering play mode; 
 | |
|             // otherwise, pending tasks will leak between play mode sessions.
 | |
|             var domainReloadDisabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled &&
 | |
|                 UnityEditor.EditorSettings.enterPlayModeOptions.HasFlag(UnityEditor.EnterPlayModeOptions.DisableDomainReload);
 | |
|             if (!domainReloadDisabled && runners != null) return;
 | |
| #else
 | |
|             if (runners != null) return; // already initialized
 | |
| #endif
 | |
| 
 | |
|             var playerLoop =
 | |
| #if UNITY_2019_3_OR_NEWER
 | |
|                 PlayerLoop.GetCurrentPlayerLoop();
 | |
| #else
 | |
|                 PlayerLoop.GetDefaultPlayerLoop();
 | |
| #endif
 | |
| 
 | |
|             Initialize(ref playerLoop);
 | |
|         }
 | |
| 
 | |
| 
 | |
| #if UNITY_EDITOR
 | |
| 
 | |
|         [InitializeOnLoadMethod]
 | |
|         static void InitOnEditor()
 | |
|         {
 | |
|             // Execute the play mode init method
 | |
|             Init();
 | |
| 
 | |
|             // register an Editor update delegate, used to forcing playerLoop update
 | |
|             EditorApplication.update += ForceEditorPlayerLoopUpdate;
 | |
|         }
 | |
| 
 | |
|         private static void ForceEditorPlayerLoopUpdate()
 | |
|         {
 | |
|             if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
 | |
|             {
 | |
|                 // Not in Edit mode, don't interfere
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             // EditorApplication.QueuePlayerLoopUpdate causes performance issue, don't call directly.
 | |
|             // EditorApplication.QueuePlayerLoopUpdate();
 | |
| 
 | |
|             if (yielders != null)
 | |
|             {
 | |
|                 foreach (var item in yielders)
 | |
|                 {
 | |
|                     if (item != null) item.Run();
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (runners != null)
 | |
|             {
 | |
|                 foreach (var item in runners)
 | |
|                 {
 | |
|                     if (item != null) item.Run();
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             UniTaskSynchronizationContext.Run();
 | |
|         }
 | |
| 
 | |
| #endif
 | |
| 
 | |
|         private static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
 | |
|         {
 | |
|             for (int i = 0; i < playerLoopList.Length; i++)
 | |
|             {
 | |
|                 if (playerLoopList[i].type == systemType)
 | |
|                 {
 | |
|                     return i;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
 | |
|         }
 | |
| 
 | |
|         static void InsertLoop(PlayerLoopSystem[] copyList, InjectPlayerLoopTimings injectTimings, Type loopType, InjectPlayerLoopTimings targetTimings,
 | |
|             int index, bool injectOnFirst, Type loopRunnerYieldType, Type loopRunnerType, PlayerLoopTiming playerLoopTiming)
 | |
|         {
 | |
|             var i = FindLoopSystemIndex(copyList, loopType);
 | |
|             if ((injectTimings & targetTimings) == targetTimings)
 | |
|             {
 | |
|                 copyList[i].subSystemList = InsertRunner(copyList[i], injectOnFirst,
 | |
|                     loopRunnerYieldType, yielders[index] = new ContinuationQueue(playerLoopTiming),
 | |
|                     loopRunnerType, runners[index] = new PlayerLoopRunner(playerLoopTiming));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 copyList[i].subSystemList = RemoveRunner(copyList[i], loopRunnerYieldType, loopRunnerType);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopTimings injectTimings = InjectPlayerLoopTimings.All)
 | |
|         {
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|             yielders = new ContinuationQueue[16];
 | |
|             runners = new PlayerLoopRunner[16];
 | |
| #else
 | |
|             yielders = new ContinuationQueue[14];
 | |
|             runners = new PlayerLoopRunner[14];
 | |
| #endif
 | |
| 
 | |
|             var copyList = playerLoop.subSystemList.ToArray();
 | |
| 
 | |
|             // Initialization
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
 | |
|                 InjectPlayerLoopTimings.Initialization, 0, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), PlayerLoopTiming.Initialization);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
 | |
|                 InjectPlayerLoopTimings.LastInitialization, 1, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), PlayerLoopTiming.LastInitialization);
 | |
| 
 | |
|             // EarlyUpdate
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
 | |
|                 InjectPlayerLoopTimings.EarlyUpdate, 2, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), PlayerLoopTiming.EarlyUpdate);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
 | |
|                 InjectPlayerLoopTimings.LastEarlyUpdate, 3, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), PlayerLoopTiming.LastEarlyUpdate);
 | |
| 
 | |
|             // FixedUpdate
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
 | |
|                 InjectPlayerLoopTimings.FixedUpdate, 4, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), PlayerLoopTiming.FixedUpdate);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
 | |
|                 InjectPlayerLoopTimings.LastFixedUpdate, 5, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), PlayerLoopTiming.LastFixedUpdate);
 | |
| 
 | |
|             // PreUpdate
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
 | |
|                 InjectPlayerLoopTimings.PreUpdate, 6, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), PlayerLoopTiming.PreUpdate);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
 | |
|                 InjectPlayerLoopTimings.LastPreUpdate, 7, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), PlayerLoopTiming.LastPreUpdate);
 | |
| 
 | |
|             // Update
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
 | |
|                 InjectPlayerLoopTimings.Update, 8, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), PlayerLoopTiming.Update);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
 | |
|                 InjectPlayerLoopTimings.LastUpdate, 9, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), PlayerLoopTiming.LastUpdate);
 | |
| 
 | |
|             // PreLateUpdate
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
 | |
|                 InjectPlayerLoopTimings.PreLateUpdate, 10, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), PlayerLoopTiming.PreLateUpdate);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
 | |
|                 InjectPlayerLoopTimings.LastPreLateUpdate, 11, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), PlayerLoopTiming.LastPreLateUpdate);
 | |
| 
 | |
|             // PostLateUpdate
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
 | |
|                 InjectPlayerLoopTimings.PostLateUpdate, 12, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), PlayerLoopTiming.PostLateUpdate);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
 | |
|                 InjectPlayerLoopTimings.LastPostLateUpdate, 13, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), PlayerLoopTiming.LastPostLateUpdate);
 | |
| 
 | |
| #if UNITY_2020_2_OR_NEWER
 | |
|             // TimeUpdate
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
 | |
|                 InjectPlayerLoopTimings.TimeUpdate, 14, true,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), PlayerLoopTiming.TimeUpdate);
 | |
| 
 | |
|             InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
 | |
|                 InjectPlayerLoopTimings.LastTimeUpdate, 15, false,
 | |
|                 typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), PlayerLoopTiming.LastTimeUpdate);
 | |
| #endif
 | |
| 
 | |
|             // Insert UniTaskSynchronizationContext to Update loop
 | |
|             var i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
 | |
|             copyList[i].subSystemList = InsertUniTaskSynchronizationContext(copyList[i]);
 | |
| 
 | |
|             playerLoop.subSystemList = copyList;
 | |
|             PlayerLoop.SetPlayerLoop(playerLoop);
 | |
|         }
 | |
| 
 | |
|         public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
 | |
|         {
 | |
|             var runner = runners[(int)timing];
 | |
|             if (runner == null)
 | |
|             {
 | |
|                 ThrowInvalidLoopTiming(timing);
 | |
|             }
 | |
|             runner.AddAction(action);
 | |
|         }
 | |
| 
 | |
|         static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming)
 | |
|         {
 | |
|             throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming);
 | |
|         }
 | |
| 
 | |
|         public static void AddContinuation(PlayerLoopTiming timing, Action continuation)
 | |
|         {
 | |
|             var q = yielders[(int)timing];
 | |
|             if (q == null)
 | |
|             {
 | |
|                 ThrowInvalidLoopTiming(timing);
 | |
|             }
 | |
|             q.Enqueue(continuation);
 | |
|         }
 | |
| 
 | |
|         // Diagnostics helper
 | |
| 
 | |
| #if UNITY_2019_3_OR_NEWER
 | |
| 
 | |
|         public static void DumpCurrentPlayerLoop()
 | |
|         {
 | |
|             var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
 | |
| 
 | |
|             var sb = new System.Text.StringBuilder();
 | |
|             sb.AppendLine($"PlayerLoop List");
 | |
|             foreach (var header in playerLoop.subSystemList)
 | |
|             {
 | |
|                 sb.AppendFormat("------{0}------", header.type.Name);
 | |
|                 sb.AppendLine();
 | |
|                 
 | |
|                 if (header.subSystemList is null) 
 | |
|                 {
 | |
|                     sb.AppendFormat("{0} has no subsystems!", header.ToString());
 | |
|                     sb.AppendLine();
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 foreach (var subSystem in header.subSystemList)
 | |
|                 {
 | |
|                     sb.AppendFormat("{0}", subSystem.type.Name);
 | |
|                     sb.AppendLine();
 | |
| 
 | |
|                     if (subSystem.subSystemList != null)
 | |
|                     {
 | |
|                         UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             UnityEngine.Debug.Log(sb.ToString());
 | |
|         }
 | |
| 
 | |
|         public static bool IsInjectedUniTaskPlayerLoop()
 | |
|         {
 | |
|             var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
 | |
| 
 | |
|             foreach (var header in playerLoop.subSystemList)
 | |
|             {
 | |
|                 if (header.subSystemList is null) 
 | |
|                 { 
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 foreach (var subSystem in header.subSystemList)
 | |
|                 {
 | |
|                     if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
| #endif
 | |
| 
 | |
|     }
 | |
| }
 | |
| 
 |