public void Execute(Coroutine coroutine) { coroutine.SignalStarted(this, executionState, null); var ev = new StartCoroutineEvent(coroutine); eventQueue.Enqueue(ev); }
public void ExecuteImmediately(Coroutine coroutine) { if (updateThreadID == -1) { throw new CoroutineException("ExecuteImmediatelly not called from coroutine"); } if (updateThreadID != Thread.CurrentThread.ManagedThreadId) { throw new CoroutineException("ExecuteImmediatelly called from different scheduler than current coroutine"); } coroutine.SignalStarted(this, executionState, null); StartAndMakeFirstIteration(coroutine); }
private void StartSubCoroutine(Coroutine newWaitCoroutine, Coroutine spawner) { var internalState = CreateCoroutineState(newWaitCoroutine); newWaitCoroutine.SignalStarted(this, executionState, spawner); // We want to do evaluation to the first yield immediatelly var advanceAction = AdvanceCoroutine(internalState); switch (advanceAction) { case AdvanceAction.Keep: executingCoroutines.AddFirst(internalState); break; case AdvanceAction.MoveToWaitForTrigger: break; case AdvanceAction.Complete: break; } }
private bool AdvanceCoroutine(long coroutineID, Coroutine coroutine, IEnumerator <IWaitObject> iterator) { while (true) { // Execute the coroutine's next frame bool isCompleted; // We need to lock to ensure cancellation from source does not interfere with frame lock (coroutine.SyncRoot) { // Cancellation can come from outside, as well as completion if (coroutine.IsComplete) { return(true); } try { isCompleted = !iterator.MoveNext(); } catch (Exception ex) { coroutine.SignalException(ex); return(true); } if (isCompleted) { coroutine.SignalComplete(false, null); return(true); } } IWaitObject newWait = iterator.Current; // Special case null means wait to next frame if (newWait is WaitForSeconds waitForSeconds) { timerTrigger.AddTrigger(waitForSeconds.WaitTime, new ContinueCoroutineEvent(coroutineID)); return(false); } // Special case null means wait to next frame if (newWait == null) { eventQueue.EnqueueNextFrame(new ContinueCoroutineEvent(coroutineID)); return(false); } else if (newWait is ReturnValue retVal) { coroutine.SignalComplete(true, retVal.Result); return(true); } if (newWait is Coroutine newWaitCoroutine) { // If we yield an unstarted coroutine, we add it to this scheduler! if (newWaitCoroutine.Status == CoroutineStatus.WaitingForStart) { coroutine.SignalStarted(this, executionState, coroutine); StartAndMakeFirstIteration(newWaitCoroutine); switch (newWaitCoroutine.Status) { case CoroutineStatus.CompletedWithException: coroutine.SignalException(newWaitCoroutine.Exception); return(true); case CoroutineStatus.Cancelled: coroutine.SignalException(new OperationCanceledException("Internal coroutine was cancelled")); return(true); } } } if (newWait.IsComplete) { // If the wait object is complete, we continue immediatelly (yield does not split frames) continue; } // Check if we get notified for completion, otherwise polling is used if (newWait is IWaitObjectWithNotifyCompletion withCompletion) { withCompletion.RegisterCompleteSignal( () => { eventQueue.Enqueue(new ContinueCoroutineEvent(coroutineID)); }); } return(false); } }