PlayerLoopHelper.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using System;
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEngine.LowLevel;
  5. using PlayerLoopType = UnityEngine.PlayerLoop;
  6. #if UNITY_EDITOR
  7. using UnityEditor;
  8. #endif
  9. namespace LitMotion
  10. {
  11. /// <summary>
  12. /// Types of PlayerLoop inserted for motion updates
  13. /// </summary>
  14. public static class LitMotionLoopRunners
  15. {
  16. public struct LitMotionInitialization { };
  17. public struct LitMotionEarlyUpdate { };
  18. public struct LitMotionFixedUpdate { };
  19. public struct LitMotionPreUpdate { };
  20. public struct LitMotionUpdate { };
  21. public struct LitMotionPreLateUpdate { };
  22. public struct LitMotionPostLateUpdate { };
  23. public struct LitMotionTimeUpdate { };
  24. }
  25. internal enum PlayerLoopTiming
  26. {
  27. Initialization = 0,
  28. EarlyUpdate = 1,
  29. FixedUpdate = 2,
  30. PreUpdate = 3,
  31. Update = 4,
  32. PreLateUpdate = 5,
  33. PostLateUpdate = 6,
  34. TimeUpdate = 7,
  35. }
  36. internal static class PlayerLoopHelper
  37. {
  38. public static event Action OnInitialization;
  39. public static event Action OnEarlyUpdate;
  40. public static event Action OnFixedUpdate;
  41. public static event Action OnPreUpdate;
  42. public static event Action OnUpdate;
  43. public static event Action OnPreLateUpdate;
  44. public static event Action OnPostLateUpdate;
  45. public static event Action OnTimeUpdate;
  46. static bool initialized;
  47. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
  48. static void Init()
  49. {
  50. #if UNITY_EDITOR
  51. var domainReloadDisabled = EditorSettings.enterPlayModeOptionsEnabled && EditorSettings.enterPlayModeOptions.HasFlag(EnterPlayModeOptions.DisableDomainReload);
  52. if (!domainReloadDisabled && initialized) return;
  53. #else
  54. if (initialized) return;
  55. #endif
  56. OnInitialization += static () => MotionDispatcher.Update(PlayerLoopTiming.Initialization);
  57. OnEarlyUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.EarlyUpdate);
  58. OnFixedUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.FixedUpdate);
  59. OnPreUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.PreUpdate);
  60. OnUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.Update);
  61. OnPreLateUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.PreLateUpdate);
  62. OnPostLateUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.PostLateUpdate);
  63. OnTimeUpdate += static () => MotionDispatcher.Update(PlayerLoopTiming.TimeUpdate);
  64. var playerLoop = PlayerLoop.GetCurrentPlayerLoop();
  65. Initialize(ref playerLoop);
  66. }
  67. public static void Initialize(ref PlayerLoopSystem playerLoop)
  68. {
  69. initialized = true;
  70. var newLoop = playerLoop.subSystemList.ToArray();
  71. InsertLoop(newLoop, typeof(PlayerLoopType.Initialization), typeof(LitMotionLoopRunners.LitMotionInitialization), static () => OnInitialization?.Invoke());
  72. InsertLoop(newLoop, typeof(PlayerLoopType.EarlyUpdate), typeof(LitMotionLoopRunners.LitMotionEarlyUpdate), static () => OnEarlyUpdate?.Invoke());
  73. InsertLoop(newLoop, typeof(PlayerLoopType.FixedUpdate), typeof(LitMotionLoopRunners.LitMotionFixedUpdate), static () => OnFixedUpdate?.Invoke());
  74. InsertLoop(newLoop, typeof(PlayerLoopType.PreUpdate), typeof(LitMotionLoopRunners.LitMotionPreUpdate), static () => OnPreUpdate?.Invoke());
  75. InsertLoop(newLoop, typeof(PlayerLoopType.Update), typeof(LitMotionLoopRunners.LitMotionUpdate), static () => OnUpdate?.Invoke());
  76. InsertLoop(newLoop, typeof(PlayerLoopType.PreLateUpdate), typeof(LitMotionLoopRunners.LitMotionPreLateUpdate), static () => OnPreLateUpdate?.Invoke());
  77. InsertLoop(newLoop, typeof(PlayerLoopType.PostLateUpdate), typeof(LitMotionLoopRunners.LitMotionPostLateUpdate), static () => OnPostLateUpdate?.Invoke());
  78. InsertLoop(newLoop, typeof(PlayerLoopType.TimeUpdate), typeof(LitMotionLoopRunners.LitMotionTimeUpdate), static () => OnTimeUpdate?.Invoke());
  79. playerLoop.subSystemList = newLoop;
  80. PlayerLoop.SetPlayerLoop(playerLoop);
  81. }
  82. static void InsertLoop(PlayerLoopSystem[] loopSystems, Type loopType, Type loopRunnerType, PlayerLoopSystem.UpdateFunction updateDelegate)
  83. {
  84. var i = FindLoopSystemIndex(loopSystems, loopType);
  85. ref var loop = ref loopSystems[i];
  86. loop.subSystemList = InsertRunner(loop.subSystemList, loopRunnerType, updateDelegate);
  87. }
  88. static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
  89. {
  90. for (int i = 0; i < playerLoopList.Length; i++)
  91. {
  92. if (playerLoopList[i].type == systemType)
  93. {
  94. return i;
  95. }
  96. }
  97. throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
  98. }
  99. static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem[] subSystemList, Type loopRunnerType, PlayerLoopSystem.UpdateFunction updateDelegate)
  100. {
  101. var source = subSystemList.Where(x => x.type != loopRunnerType).ToArray();
  102. var dest = new PlayerLoopSystem[source.Length + 1];
  103. Array.Copy(source, 0, dest, 1, source.Length);
  104. dest[0] = new PlayerLoopSystem
  105. {
  106. type = loopRunnerType,
  107. updateDelegate = updateDelegate
  108. };
  109. return dest;
  110. }
  111. }
  112. }