using System; using System.Collections; using System.Collections.Generic; using SUISS.Core; using SUISS.Core.Utilities; using UnityEngine; namespace SUISS.Scheduling { public class Scheduler : SingletonMonobehaviour, IComparer { private SortedDictionary Routines { get { if (this._routines == null) { this._routines = new SortedDictionary(this); } return this._routines; } } private void Update() { foreach (IEnumerator enumerator2 in new List(this.Routines.Keys)) { object obj = enumerator2.Current; if (obj != null) { if (obj is double) { if (Scheduler.TimeLeft(enumerator2) > 0.0) { break; } } else if (obj is AsyncOperation && !((AsyncOperation)obj).isDone) { continue; } } this.Execute(enumerator2); } } public int Compare(IEnumerator xEnum, IEnumerator yEnum) { object obj = xEnum.Current; object obj2 = yEnum.Current; if (obj == null || obj2 == null) { if (obj != null) { return 1; } if (obj2 != null) { return -1; } } else if (obj is double || obj2 is double) { if (!(obj is double)) { return -1; } if (!(obj2 is double)) { return 1; } double num = (double)obj; double num2 = (double)obj2; if (num < num2) { return -1; } if (num > num2) { return 1; } } if (!this._uniqueIdentifiers.ContainsKey(xEnum)) { this._uniqueIdentifiers[xEnum] = this._nextUniqueIdentifier++; } if (!this._uniqueIdentifiers.ContainsKey(yEnum)) { this._uniqueIdentifiers[yEnum] = this._nextUniqueIdentifier++; } return this._uniqueIdentifiers[xEnum] - this._uniqueIdentifiers[yEnum]; } public void StartRoutine(IEnumerator routine, GameObject go) { if (go != null) { this._gameObjects.Add(routine, go); this._debugInfo.Add(routine, string.Format("{0}: {1}", this.FullName(go), SUISS.Core.Utilities.StackTraceUtility.ExtractStackTrace())); } this.StartRoutine(routine); } private string FullName(GameObject go) { string text = string.Empty; Transform transform = go.transform; while (transform != null) { if (text.Length == 0) { text = transform.name; } else { text = string.Format("{0}/{1}", transform.name, text); } transform = transform.parent; } return text; } public void StartRoutine(IEnumerator routine) { if (this.Routines.ContainsKey(routine)) { throw new SchedulerException("You are calling StartRoutine on a routine that was already started."); } this.Routines.Add(routine, routine); this.Execute(routine); } public bool IsRunning(IEnumerator routine) { return this.Routines.ContainsKey(routine); } public void StopRoutine(IEnumerator routine) { bool leaf = this.Routines.Remove(routine); this.CleanupRoutine(routine, leaf, false); } [Obsolete("You are calling MonoBehaviour.StartCoroutine while you meant to use Scheduler.StartRoutine instead.", true)] public new void StartCoroutine(IEnumerator routine) { throw new InvalidOperationException("You are calling MonoBehaviour.StartCoroutine while you meant to use Scheduler.StartRoutine instead."); } [Obsolete("You are calling MonoBehaviour.StopCoroutine while you meant to use Scheduler.StopRoutine instead.", true)] public new void StopCoroutine(IEnumerator routine) { throw new InvalidOperationException("You are calling MonoBehaviour.StopCoroutine while you meant to use Scheduler.StopRoutine instead."); } public void ExecuteNextFrame(GameObject go, Action action) { this.StartRoutine(Scheduler.NextFrame(action), go); } public void ExecuteNextFrame(Action action) { this.StartRoutine(Scheduler.NextFrame(action)); } public IEnumerator ExecuteDelayed(Action action, float delaySeconds) { IEnumerator result; this.StartRoutine(result = Scheduler.Delayed(action, delaySeconds)); return result; } [Obsolete("This is nasty! Just keep track of your routines, and clean them up yourself.", false)] public void DestroyedGameObject(GameObject go) { IEnumerator enumerator; do { enumerator = null; foreach (KeyValuePair keyValuePair in this._gameObjects) { if (object.ReferenceEquals(keyValuePair.Value, go)) { enumerator = keyValuePair.Key; break; } } if (enumerator != null) { this.StopRoutine(enumerator); } } while (enumerator != null); } private void Execute(IEnumerator routine) { this.Routines.Remove(routine); GameObject gameObject = null; bool flag = false; if (this._gameObjects.TryGetValue(routine, out gameObject)) { if (gameObject != null) { flag = routine.MoveNext(); } else { string arg = "unknown"; try { arg = gameObject.name; } catch { } string arg2 = string.Empty; if (this._debugInfo.ContainsKey(routine)) { arg2 = "\n" + this._debugInfo[routine]; } UnityEngine.Debug.LogError(string.Format("Routine was still running on gameObject ({0}) that has been destroyed.{1}", arg, arg2)); } } else { flag = routine.MoveNext(); } if (flag) { object obj = routine.Current; if (obj is IEnumerator) { IEnumerator enumerator = (IEnumerator)obj; if (!this._parents.ContainsKey(enumerator)) { this._parents[enumerator] = new List(); } this._parents[enumerator].Add(routine); bool flag2 = this.IsRunning(enumerator); if (!flag2) { foreach (List list in this._parents.Values) { if (list.Contains(enumerator)) { flag2 = true; break; } } } if (!flag2) { this.Routines.Add(enumerator, enumerator); if (gameObject != null) { this._gameObjects.Add(enumerator, gameObject); this._debugInfo.Add(enumerator, string.Format("{0}: {1}", this.FullName(gameObject), SUISS.Core.Utilities.StackTraceUtility.ExtractStackTrace())); } this.Execute(enumerator); } else if (this._parents[enumerator].Count < 2) { UnityEngine.Debug.LogWarning("Child routine was already running, but it had no parent routines!"); } } else { if (this.Routines.ContainsKey(routine)) { UnityEngine.Debug.LogWarning(string.Format("Routine {0} with Current {1} is already in Routines as {2} with current {3}", new object[] { routine, routine.Current, this.Routines[routine], this.Routines[routine].Current })); } this.Routines.Add(routine, routine); } } else { this.CleanupRoutine(routine, true, true); } } private void CleanupRoutine(IEnumerator routine, bool leaf, bool executeParents) { this._gameObjects.Remove(routine); this._debugInfo.Remove(routine); this._uniqueIdentifiers.Remove(routine); if (leaf) { if (this._parents.ContainsKey(routine)) { List list = this._parents[routine]; this._parents.Remove(routine); foreach (IEnumerator enumerator2 in list) { this.Routines.Add(enumerator2, enumerator2); } if (executeParents) { foreach (IEnumerator routine2 in list) { this.Execute(routine2); } } } } else { IEnumerator enumerator4 = null; bool flag = false; foreach (IEnumerator enumerator6 in this._parents.Keys) { if (this._parents[enumerator6].Contains(routine)) { enumerator4 = enumerator6; if (this._parents[enumerator6].Count > 1) { this._parents[enumerator6].Remove(routine); } else { flag = true; } break; } } if (enumerator4 == null) { UnityEngine.Debug.LogWarning("Unable to find routine in _parents"); } else if (flag) { this._parents.Remove(enumerator4); bool leaf2 = this.Routines.Remove(enumerator4); this.CleanupRoutine(enumerator4, leaf2, false); } else { this.CleanupRoutine(routine, true, executeParents); } } } public static IEnumerator NextFrame(Action action) { if (action != null) { yield return null; action(); } yield break; } public static IEnumerator Delayed(Action action, float delaySeconds) { if (action != null) { yield return Timing.time + (double)delaySeconds; action(); } yield break; } public static double TimeLeft(IEnumerator routine) { object obj = routine.Current; if (obj == null) { return 1E-06; } if (obj is double) { return (double)obj - Timing.time; } UnityEngine.Debug.LogWarning(string.Format("TimeLeft requested on routine of which current (type {0}) is not a double", obj.GetType())); return 0.0; } private Dictionary _uniqueIdentifiers = new Dictionary(); private int _nextUniqueIdentifier; private SortedDictionary _routines; private Dictionary> _parents = new Dictionary>(); private Dictionary _gameObjects = new Dictionary(); private Dictionary _debugInfo = new Dictionary(); } }