using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace SUISS.Scheduling { public class UnityScheduler : IScheduler { [Obsolete("Use default constructor.")] public UnityScheduler(MonoBehaviour runner) { this._executorName = string.Format("__ScheduleExecutor{0}", UnityEngine.Random.Range(1000, 9999)); this._executor = runner; } public UnityScheduler() { this._executorName = string.Format("__ScheduleExecutor{0}", UnityEngine.Random.Range(1000, 9999)); this.CreateScheduleExecutor(); } public ICoroutine StartCoroutine(IEnumerator routine) { if (this._executor == null) { this.CreateScheduleExecutor(); } if (!(this._executor != null)) { UnityEngine.Debug.LogError(string.Format("The schedule executor backing this scheduler is null! Can't start {0}", routine)); return null; } if (this._runningRoutines.Contains(routine)) { throw new SchedulerException(string.Format("You are calling StartRoutine on a routine '{0}' that was already started.", routine)); } this._runningRoutines.Add(routine); return new UnityScheduler.CoroutineWapper(routine, this); } private MonoBehaviour Executor { get { if (this._executor == null) { 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)); this.CreateScheduleExecutor(); } return this._executor; } } private bool IsSupportedYieldable(object yieldable) { return yieldable == null || yieldable is AsyncOperation || yieldable is YieldInstruction; } private void CreateScheduleExecutor() { if (this._executor == null) { GameObject gameObject = GameObject.Find(this._executorName); if (gameObject == null) { gameObject = new GameObject(); gameObject.name = this._executorName; UnityEngine.Object.DontDestroyOnLoad(gameObject); } this._executor = gameObject.GetComponent(); if (this._executor == null) { this._executor = gameObject.AddComponent(); } } } private void StopCoroutine(IEnumerator routine) { this._runningRoutines.Remove(routine); } private HashSet _runningRoutines = new HashSet(); private MonoBehaviour _executor; private string _executorName; private class CoroutineWapper : ICoroutine, IYieldStatement { public CoroutineWapper(IEnumerator routine, UnityScheduler scheduler) { this._scheduler = scheduler; this._executor = this._scheduler.Executor; this._innerRoutine = routine; if (this._executor != null) { this._isRunning = true; this._coroutine = this._executor.StartCoroutine(this.Routine(routine)); } } public void Stop() { if (this._isRunning && this._executor != null) { this._executor.StopCoroutine(this._coroutine); this._scheduler.StopCoroutine(this._innerRoutine); this._isRunning = false; } } public bool IsRunning { get { return this._isRunning && this._executor != null; } } public object UnityYieldable() { return this._coroutine; } public object UnityYieldable(MonoBehaviour runner) { return this._coroutine; } public object SUISSYieldable() { UnityEngine.Debug.LogError(string.Format("Coroutines started using the Unity scheduler should not be mixed with the SUISS Scheduler. {0}", this._innerRoutine)); return null; } private IEnumerator Routine(IEnumerator routine) { while (routine.MoveNext()) { object yielded = routine.Current; if (yielded == null) { yield return null; } else { if (yielded is IYieldStatement) { yielded = ((IYieldStatement)yielded).UnityYieldable(this._executor); } if (!this._scheduler.IsSupportedYieldable(yielded)) { UnityEngine.Debug.LogWarning(string.Format("The coroutine '{0}' yielded '{1}' which is not supported by '{2}'!", this._innerRoutine, yielded ?? "null", this._scheduler)); } yield return yielded; } } this._scheduler.StopCoroutine(this._innerRoutine); this._isRunning = false; yield break; } private Coroutine _coroutine; private bool _isRunning; private IEnumerator _innerRoutine; private UnityScheduler _scheduler; private MonoBehaviour _executor; } private class UnitySchedulerMonoBehaviour : MonoBehaviour { } } }