You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

181 lines
4.8 KiB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace SUISS.Scheduling
  6. {
  7. public class UnityScheduler : IScheduler
  8. {
  9. [Obsolete("Use default constructor.")]
  10. public UnityScheduler(MonoBehaviour runner)
  11. {
  12. this._executorName = string.Format("__ScheduleExecutor{0}", UnityEngine.Random.Range(1000, 9999));
  13. this._executor = runner;
  14. }
  15. public UnityScheduler()
  16. {
  17. this._executorName = string.Format("__ScheduleExecutor{0}", UnityEngine.Random.Range(1000, 9999));
  18. this.CreateScheduleExecutor();
  19. }
  20. public ICoroutine StartCoroutine(IEnumerator<IYieldStatement> routine)
  21. {
  22. if (this._executor == null)
  23. {
  24. this.CreateScheduleExecutor();
  25. }
  26. if (!(this._executor != null))
  27. {
  28. UnityEngine.Debug.LogError(string.Format("The schedule executor backing this scheduler is null! Can't start {0}", routine));
  29. return null;
  30. }
  31. if (this._runningRoutines.Contains(routine))
  32. {
  33. throw new SchedulerException(string.Format("You are calling StartRoutine on a routine '{0}' that was already started.", routine));
  34. }
  35. this._runningRoutines.Add(routine);
  36. return new UnityScheduler.CoroutineWapper(routine, this);
  37. }
  38. private MonoBehaviour Executor
  39. {
  40. get
  41. {
  42. if (this._executor == null)
  43. {
  44. UnityEngine.Debug.LogError(string.Format("{0} is going to create a second GameObject to run coroutines! (Is the app quitting?) Any coroutines running before this may not have been completed! I hope you never see this error! :(", this));
  45. this.CreateScheduleExecutor();
  46. }
  47. return this._executor;
  48. }
  49. }
  50. private bool IsSupportedYieldable(object yieldable)
  51. {
  52. return yieldable == null || yieldable is AsyncOperation || yieldable is YieldInstruction;
  53. }
  54. private void CreateScheduleExecutor()
  55. {
  56. if (this._executor == null)
  57. {
  58. GameObject gameObject = GameObject.Find(this._executorName);
  59. if (gameObject == null)
  60. {
  61. gameObject = new GameObject();
  62. gameObject.name = this._executorName;
  63. UnityEngine.Object.DontDestroyOnLoad(gameObject);
  64. }
  65. this._executor = gameObject.GetComponent<MonoBehaviour>();
  66. if (this._executor == null)
  67. {
  68. this._executor = gameObject.AddComponent<UnityScheduler.UnitySchedulerMonoBehaviour>();
  69. }
  70. }
  71. }
  72. private void StopCoroutine(IEnumerator routine)
  73. {
  74. this._runningRoutines.Remove(routine);
  75. }
  76. private HashSet<IEnumerator> _runningRoutines = new HashSet<IEnumerator>();
  77. private MonoBehaviour _executor;
  78. private string _executorName;
  79. private class CoroutineWapper : ICoroutine, IYieldStatement
  80. {
  81. public CoroutineWapper(IEnumerator routine, UnityScheduler scheduler)
  82. {
  83. this._scheduler = scheduler;
  84. this._executor = this._scheduler.Executor;
  85. this._innerRoutine = routine;
  86. if (this._executor != null)
  87. {
  88. this._isRunning = true;
  89. this._coroutine = this._executor.StartCoroutine(this.Routine(routine));
  90. }
  91. }
  92. public void Stop()
  93. {
  94. if (this._isRunning && this._executor != null)
  95. {
  96. this._executor.StopCoroutine(this._coroutine);
  97. this._scheduler.StopCoroutine(this._innerRoutine);
  98. this._isRunning = false;
  99. }
  100. }
  101. public bool IsRunning
  102. {
  103. get
  104. {
  105. return this._isRunning && this._executor != null;
  106. }
  107. }
  108. public object UnityYieldable()
  109. {
  110. return this._coroutine;
  111. }
  112. public object UnityYieldable(MonoBehaviour runner)
  113. {
  114. return this._coroutine;
  115. }
  116. public object SUISSYieldable()
  117. {
  118. UnityEngine.Debug.LogError(string.Format("Coroutines started using the Unity scheduler should not be mixed with the SUISS Scheduler. {0}", this._innerRoutine));
  119. return null;
  120. }
  121. private IEnumerator Routine(IEnumerator routine)
  122. {
  123. while (routine.MoveNext())
  124. {
  125. object yielded = routine.Current;
  126. if (yielded == null)
  127. {
  128. yield return null;
  129. }
  130. else
  131. {
  132. if (yielded is IYieldStatement)
  133. {
  134. yielded = ((IYieldStatement)yielded).UnityYieldable(this._executor);
  135. }
  136. if (!this._scheduler.IsSupportedYieldable(yielded))
  137. {
  138. UnityEngine.Debug.LogWarning(string.Format("The coroutine '{0}' yielded '{1}' which is not supported by '{2}'!", this._innerRoutine, yielded ?? "null", this._scheduler));
  139. }
  140. yield return yielded;
  141. }
  142. }
  143. this._scheduler.StopCoroutine(this._innerRoutine);
  144. this._isRunning = false;
  145. yield break;
  146. }
  147. private Coroutine _coroutine;
  148. private bool _isRunning;
  149. private IEnumerator _innerRoutine;
  150. private UnityScheduler _scheduler;
  151. private MonoBehaviour _executor;
  152. }
  153. private class UnitySchedulerMonoBehaviour : MonoBehaviour
  154. {
  155. }
  156. }
  157. }