UnityThread.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // https://stackoverflow.com/questions/41330771/use-unity-api-from-another-thread-or-call-a-function-in-the-main-thread
  2. #define ENABLE_UPDATE_FUNCTION_CALLBACK
  3. #define ENABLE_LATEUPDATE_FUNCTION_CALLBACK
  4. #define ENABLE_FIXEDUPDATE_FUNCTION_CALLBACK
  5. using System;
  6. using System.Collections;
  7. using UnityEngine;
  8. using System.Collections.Generic;
  9. public class UnityThread : MonoBehaviour
  10. {
  11. //our (singleton) instance
  12. private static UnityThread instance = null;
  13. ////////////////////////////////////////////////UPDATE IMPL////////////////////////////////////////////////////////
  14. //Holds actions received from another Thread. Will be coped to actionCopiedQueueUpdateFunc then executed from there
  15. private static List<System.Action> actionQueuesUpdateFunc = new List<Action>();
  16. //holds Actions copied from actionQueuesUpdateFunc to be executed
  17. List<System.Action> actionCopiedQueueUpdateFunc = new List<System.Action>();
  18. // Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frame
  19. private volatile static bool noActionQueueToExecuteUpdateFunc = true;
  20. ////////////////////////////////////////////////LATEUPDATE IMPL////////////////////////////////////////////////////////
  21. //Holds actions received from another Thread. Will be coped to actionCopiedQueueLateUpdateFunc then executed from there
  22. private static List<System.Action> actionQueuesLateUpdateFunc = new List<Action>();
  23. //holds Actions copied from actionQueuesLateUpdateFunc to be executed
  24. List<System.Action> actionCopiedQueueLateUpdateFunc = new List<System.Action>();
  25. // Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frame
  26. private volatile static bool noActionQueueToExecuteLateUpdateFunc = true;
  27. ////////////////////////////////////////////////FIXEDUPDATE IMPL////////////////////////////////////////////////////////
  28. //Holds actions received from another Thread. Will be coped to actionCopiedQueueFixedUpdateFunc then executed from there
  29. private static List<System.Action> actionQueuesFixedUpdateFunc = new List<Action>();
  30. //holds Actions copied from actionQueuesFixedUpdateFunc to be executed
  31. List<System.Action> actionCopiedQueueFixedUpdateFunc = new List<System.Action>();
  32. // Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frame
  33. private volatile static bool noActionQueueToExecuteFixedUpdateFunc = true;
  34. //Used to initialize UnityThread. Call once before any function here
  35. public static void initUnityThread(bool visible = false)
  36. {
  37. if (instance != null)
  38. {
  39. return;
  40. }
  41. if (Application.isPlaying)
  42. {
  43. // add an invisible game object to the scene
  44. GameObject obj = new GameObject("MainThreadExecuter");
  45. if (!visible)
  46. {
  47. obj.hideFlags = HideFlags.HideAndDontSave;
  48. }
  49. DontDestroyOnLoad(obj);
  50. instance = obj.AddComponent<UnityThread>();
  51. }
  52. }
  53. public void Awake()
  54. {
  55. DontDestroyOnLoad(gameObject);
  56. }
  57. //////////////////////////////////////////////COROUTINE IMPL//////////////////////////////////////////////////////
  58. #if (ENABLE_UPDATE_FUNCTION_CALLBACK)
  59. public static void executeCoroutine(IEnumerator action)
  60. {
  61. if (instance != null)
  62. {
  63. executeInUpdate(() => instance.StartCoroutine(action));
  64. }
  65. }
  66. ////////////////////////////////////////////UPDATE IMPL////////////////////////////////////////////////////
  67. public static void executeInUpdate(System.Action action)
  68. {
  69. if (action == null)
  70. {
  71. throw new ArgumentNullException("action");
  72. }
  73. lock (actionQueuesUpdateFunc)
  74. {
  75. actionQueuesUpdateFunc.Add(action);
  76. noActionQueueToExecuteUpdateFunc = false;
  77. }
  78. }
  79. public void Update()
  80. {
  81. if (noActionQueueToExecuteUpdateFunc)
  82. {
  83. return;
  84. }
  85. //Clear the old actions from the actionCopiedQueueUpdateFunc queue
  86. actionCopiedQueueUpdateFunc.Clear();
  87. lock (actionQueuesUpdateFunc)
  88. {
  89. //Copy actionQueuesUpdateFunc to the actionCopiedQueueUpdateFunc variable
  90. actionCopiedQueueUpdateFunc.AddRange(actionQueuesUpdateFunc);
  91. //Now clear the actionQueuesUpdateFunc since we've done copying it
  92. actionQueuesUpdateFunc.Clear();
  93. noActionQueueToExecuteUpdateFunc = true;
  94. }
  95. // Loop and execute the functions from the actionCopiedQueueUpdateFunc
  96. for (int i = 0; i < actionCopiedQueueUpdateFunc.Count; i++)
  97. {
  98. actionCopiedQueueUpdateFunc[i].Invoke();
  99. }
  100. }
  101. #endif
  102. ////////////////////////////////////////////LATEUPDATE IMPL////////////////////////////////////////////////////
  103. #if (ENABLE_LATEUPDATE_FUNCTION_CALLBACK)
  104. public static void executeInLateUpdate(System.Action action)
  105. {
  106. if (action == null)
  107. {
  108. throw new ArgumentNullException("action");
  109. }
  110. lock (actionQueuesLateUpdateFunc)
  111. {
  112. actionQueuesLateUpdateFunc.Add(action);
  113. noActionQueueToExecuteLateUpdateFunc = false;
  114. }
  115. }
  116. public void LateUpdate()
  117. {
  118. if (noActionQueueToExecuteLateUpdateFunc)
  119. {
  120. return;
  121. }
  122. //Clear the old actions from the actionCopiedQueueLateUpdateFunc queue
  123. actionCopiedQueueLateUpdateFunc.Clear();
  124. lock (actionQueuesLateUpdateFunc)
  125. {
  126. //Copy actionQueuesLateUpdateFunc to the actionCopiedQueueLateUpdateFunc variable
  127. actionCopiedQueueLateUpdateFunc.AddRange(actionQueuesLateUpdateFunc);
  128. //Now clear the actionQueuesLateUpdateFunc since we've done copying it
  129. actionQueuesLateUpdateFunc.Clear();
  130. noActionQueueToExecuteLateUpdateFunc = true;
  131. }
  132. // Loop and execute the functions from the actionCopiedQueueLateUpdateFunc
  133. for (int i = 0; i < actionCopiedQueueLateUpdateFunc.Count; i++)
  134. {
  135. actionCopiedQueueLateUpdateFunc[i].Invoke();
  136. }
  137. }
  138. #endif
  139. ////////////////////////////////////////////FIXEDUPDATE IMPL//////////////////////////////////////////////////
  140. #if (ENABLE_FIXEDUPDATE_FUNCTION_CALLBACK)
  141. public static void executeInFixedUpdate(System.Action action)
  142. {
  143. if (action == null)
  144. {
  145. throw new ArgumentNullException("action");
  146. }
  147. lock (actionQueuesFixedUpdateFunc)
  148. {
  149. actionQueuesFixedUpdateFunc.Add(action);
  150. noActionQueueToExecuteFixedUpdateFunc = false;
  151. }
  152. }
  153. public void FixedUpdate()
  154. {
  155. if (noActionQueueToExecuteFixedUpdateFunc)
  156. {
  157. return;
  158. }
  159. //Clear the old actions from the actionCopiedQueueFixedUpdateFunc queue
  160. actionCopiedQueueFixedUpdateFunc.Clear();
  161. lock (actionQueuesFixedUpdateFunc)
  162. {
  163. //Copy actionQueuesFixedUpdateFunc to the actionCopiedQueueFixedUpdateFunc variable
  164. actionCopiedQueueFixedUpdateFunc.AddRange(actionQueuesFixedUpdateFunc);
  165. //Now clear the actionQueuesFixedUpdateFunc since we've done copying it
  166. actionQueuesFixedUpdateFunc.Clear();
  167. noActionQueueToExecuteFixedUpdateFunc = true;
  168. }
  169. // Loop and execute the functions from the actionCopiedQueueFixedUpdateFunc
  170. for (int i = 0; i < actionCopiedQueueFixedUpdateFunc.Count; i++)
  171. {
  172. actionCopiedQueueFixedUpdateFunc[i].Invoke();
  173. }
  174. }
  175. #endif
  176. public void OnDisable()
  177. {
  178. if (instance == this)
  179. {
  180. instance = null;
  181. }
  182. }
  183. }