// Call this as you would call MonoBehaviour.StartCoroutine public SCoroutine StartCoroutine(IEnumerator ie) { var sc = new SCoroutine(); sc.Start(ie); runningCoroutines.Add(sc); return(sc); }
public void Start(IEnumerator routine) { ienumeratorStack.Clear(); ienumeratorStack.Push(routine); nestedCoroutine = null; yieldFrame = -1; Update(); }
// Execute a single step of the coroutine. Unity equivalent is the MoveNext you see in coroutine stack traces // Returns true if the coroutine should continue running public bool Update() { // This ensures yield return null waits a frame in all situations if (yieldFrame > Time.frameCount) { return(true); } // Do not continue with the IEnumerators until the last returned SCoroutine has finished running if (nestedCoroutine != null && nestedCoroutine.IsRunning()) { return(true); } nestedCoroutine = null; if (ienumeratorStack.Count > 0) { var ie = ienumeratorStack.Peek(); // The top of the stack is the currently executing IEnumerator if (ie.MoveNext()) // Execute IEnumerator until next yield (true) or break/end (false) { // ie.Current is what was yield returned in the IEnumerator object yielded = ie.Current; if (yielded is IEnumerator) { // Move to execute a nested IEnumerator ienumeratorStack.Push(yielded as IEnumerator); return(Update()); // Start nested IEnumerator execution without frame delay } else if (yielded is SCoroutine) { // Start waiting on a nested SCoroutine nestedCoroutine = yielded as SCoroutine; } else { // Yielding anything else (like null) causes execution to resume next frame yieldFrame = Time.frameCount + 1; } // TODO: Support Unity's YieldInstruction by starting a real coroutine and yielding it there // TODO: Add logic for custom yieldable objects here } else { ienumeratorStack.Pop(); return(Update()); // Immediately continue the previous IEnumerator in the stack without frame delay } return(true); } else { return(false); } }