예제 #1
0
        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);
            }
        }
예제 #2
0
        private AdvanceAction AdvanceCoroutine(CoroutineState executingCoroutine)
        {
            var coroutine = executingCoroutine.Coroutine;

            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(AdvanceAction.Complete);
                    }

                    try
                    {
                        isCompleted = !executingCoroutine.Enumerator.MoveNext();
                    }
                    catch (Exception ex)
                    {
                        coroutine.SignalException(ex);
                        return(AdvanceAction.Complete);
                    }

                    if (isCompleted)
                    {
                        coroutine.SignalComplete(false, null);
                        return(AdvanceAction.Complete);
                    }
                }

                IWaitObject newWait = executingCoroutine.Enumerator.Current;
                executingCoroutine.WaitForObject = newWait;

                // Special case null means wait to next frame
                if (newWait is WaitForSeconds waitForSeconds)
                {
                    // The wait object is set to null, we bypass it and use trigger instead
                    executingCoroutine.WaitForObject = null;
                    timerTrigger.AddTrigger(waitForSeconds.WaitTime, executingCoroutine);
                    return(AdvanceAction.MoveToWaitForTrigger);
                }

                if (newWait == null)
                {
                    return(AdvanceAction.Keep);
                }
                else if (newWait is ReturnValue retVal)
                {
                    coroutine.SignalComplete(true, retVal.Result);
                    return(AdvanceAction.Complete);
                }

                if (newWait is Coroutine newWaitCoroutine)
                {
                    // If we yield an unstarted coroutine, we add it to this scheduler!
                    if (newWaitCoroutine.Status == CoroutineStatus.WaitingForStart)
                    {
                        StartSubCoroutine(newWaitCoroutine, coroutine);

                        switch (newWaitCoroutine.Status)
                        {
                        case CoroutineStatus.CompletedWithException:
                            coroutine.SignalException(newWaitCoroutine.Exception);
                            return(AdvanceAction.Complete);

                        case CoroutineStatus.Cancelled:
                            coroutine.SignalException(new OperationCanceledException("Internal coroutine was cancelled"));
                            return(AdvanceAction.Complete);
                        }
                    }
                }

                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(
                        () =>
                    {
                        trigerredCoroutines.Enqueue(executingCoroutine);
                    });
                    return(AdvanceAction.MoveToWaitForTrigger);
                }

                return(AdvanceAction.Keep);
            }
        }
예제 #3
0
 public CustomWaitObjectCoroutine(IWaitObject waitObject)
 {
     this.waitObject = waitObject;
 }