Ejemplo n.º 1
0
        /// <summary>
        /// Runs the Fiber one frame.
        /// Will dispose itself if requested.
        /// Returns if still running.
        /// </summary>
        public bool Update(YieldPhase inYieldUpdate = YieldPhase.None)
        {
            // We don't support recursive Fiber updates
            if (m_Executing)
            {
                return(true);
            }

            if (m_StackPosition < 0)
            {
                return(false);
            }

            if (m_Disposing || (!m_HostedByManager && !m_Host))
            {
                Dispose();
                return(false);
            }

            if (inYieldUpdate != YieldPhase.None && m_YieldFrameDelay > 0)
            {
                --m_YieldFrameDelay;
                return(true);
            }

            if (IsPaused() || m_UnityWait != null)
            {
                return(true);
            }

            if (m_YieldPhase != inYieldUpdate)
            {
                return(true);
            }

            if (inYieldUpdate != YieldPhase.None)
            {
                Manager.Fibers.RemoveFiberFromYieldList(this, m_YieldPhase);
                m_YieldPhase = YieldPhase.None;

                // If we're in a manual update, don't proceed from here
                if (m_UpdatePhase == RoutinePhase.Manual)
                {
                    return(true);
                }
            }

            // If we're a chained routine, just accept
            // the parent's delta time.
            if (!m_Chained)
            {
                ApplyDeltaTime();
            }
            else if (inYieldUpdate != YieldPhase.None)
            {
                m_RootFiber.ApplyDeltaTime();
            }

            if (m_WaitTime > 0)
            {
                m_WaitTime -= Manager.Frame.DeltaTime;
                if (m_WaitTime > 0)
                {
                    return(true);
                }

                // We don't modify delta time in the fixed update phase,
                // to preserve a consistent delta time within fixed update.
                if (m_UpdatePhase != RoutinePhase.FixedUpdate && inYieldUpdate != YieldPhase.WaitForFixedUpdate)
                {
                    Manager.Frame.DeltaTime += m_WaitTime;
                }

                m_WaitTime = 0;
            }

            bool bExecuteStack = true;

            while (bExecuteStack)
            {
                bExecuteStack = false;

                // Set this flag to prevent updating this routine mid-execution
                m_Executing = true;

                IEnumerator current    = m_Stack[m_StackPosition];
                bool        bMovedNext = false;

                if (Manager.HandleExceptions || m_HandleExceptions || (m_Chained && m_RootFiber.m_HandleExceptions))
                {
                    try
                    {
                        bMovedNext = current.MoveNext();
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);

                        Routine.ExceptionHandler exceptionHandler = m_OnException;
                        if (m_Chained)
                        {
                            exceptionHandler        = m_RootFiber.m_OnException;
                            m_RootFiber.m_Disposing = true;
                        }

                        if (exceptionHandler != null)
                        {
                            exceptionHandler(e);
                        }

                        m_Disposing = true;
                    }
                }
                else
                {
                    bMovedNext = current.MoveNext();
                }

                m_Executing = false;

                // Don't check for the object being destroyed.
                // Destroy won't go into effect until after
                // all the Fibers are done processing anyways.
                if (m_Disposing)
                {
                    Dispose();
                    return(false);
                }

                if (bMovedNext)
                {
                    object result = current.Current;
                    if (result == null)
                    {
                        return(true);
                    }

                    IntPtr resultType = result.GetType().TypeHandle.Value;

                    // Check all the easy-to-identify result types

                    if (resultType == TYPEHANDLE_INT)
                    {
                        m_WaitTime = (int)result;
                        return(true);
                    }

                    if (resultType == TYPEHANDLE_FLOAT)
                    {
                        m_WaitTime = (float)result;
                        return(true);
                    }

                    if (resultType == TYPEHANDLE_DOUBLE)
                    {
                        m_WaitTime = (float)(double)result;
                        return(true);
                    }

                    if (resultType == TYPEHANDLE_ROUTINE)
                    {
                        IEnumerator waitSequence = ((Routine)result).Wait();
                        if (waitSequence != null)
                        {
                            if (m_StackPosition == m_StackSize - 1)
                            {
                                Array.Resize(ref m_Stack, m_StackSize *= 2);
                            }
                            m_Stack[++m_StackPosition] = waitSequence;
                        }
                        return(true);
                    }

                    if (resultType == TYPEHANDLE_WWW)
                    {
                        // Disable obsolete WWW warning
                        #pragma warning disable 612, 618

                        m_UnityWait = Manager.Host.StartCoroutine(UnityWait((WWW)result));
                        return(true);

                        // Restore obsolete WWW warning
                        #pragma warning restore 612, 618
                    }

                    if (resultType == TYPEHANDLE_COMMAND)
                    {
                        Routine.Command c = (Routine.Command)result;
                        switch (c)
                        {
                        case Routine.Command.Pause:
                            Pause();
                            return(true);

                        case Routine.Command.Stop:
                            Stop();
                            Dispose();
                            return(false);

                        case Routine.Command.BreakAndResume:
                            m_Stack[m_StackPosition--] = null;
                            ((IDisposable)current).Dispose();
                            if (m_StackPosition < 0)
                            {
                                Dispose();
                                return(false);
                            }
                            bExecuteStack = true;
                            break;

                        case Routine.Command.Continue:
                            bExecuteStack = true;
                            break;
                        }

                        if (!bExecuteStack)
                        {
                            return(true);
                        }

                        continue;
                    }

                    if (resultType == TYPEHANDLE_DECORATOR)
                    {
                        RoutineDecorator decorator           = (RoutineDecorator)result;
                        IEnumerator      decoratedEnumerator = decorator.Enumerator;
                        bExecuteStack = (decorator.Flags & RoutineDecoratorFlag.Inline) != 0;

                        if (decoratedEnumerator != null)
                        {
                            // Check if we need to resize the stack
                            if (m_StackPosition == m_StackSize - 1)
                            {
                                Array.Resize(ref m_Stack, m_StackSize *= 2);
                            }
                            m_Stack[++m_StackPosition] = decorator;

                            CheckForNesting(decoratedEnumerator);
                        }

                        if (!bExecuteStack)
                        {
                            return(true);
                        }

                        continue;
                    }

                    // Check for yield timing changes

                    if (m_UpdatePhase != RoutinePhase.Manual)
                    {
                        bool bApplyYieldDelay = !Manager.IsUpdating(RoutinePhase.Manual) && inYieldUpdate == YieldPhase.None;

                        if (resultType == TYPEHANDLE_ROUTINEPHASE)
                        {
                            RoutinePhase phase = (RoutinePhase)result;

                            switch (phase)
                            {
                            case RoutinePhase.FixedUpdate:
                            {
                                Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForFixedUpdate);
                                Manager.Host.WaitForFixedUpdate();
                                m_YieldPhase      = YieldPhase.WaitForFixedUpdate;
                                m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.FixedUpdate && Manager.IsUpdating(RoutinePhase.FixedUpdate) ? 1 : 0;
                                return(true);
                            }

                            case RoutinePhase.LateUpdate:
                            {
                                Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForLateUpdate);
                                m_YieldPhase      = YieldPhase.WaitForLateUpdate;
                                m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.LateUpdate && Manager.IsUpdating(RoutinePhase.LateUpdate) ? 1 : 0;
                                return(true);
                            }

                            case RoutinePhase.Update:
                            {
                                Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForUpdate);
                                m_YieldPhase      = YieldPhase.WaitForUpdate;
                                m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.Update && Manager.IsUpdating(RoutinePhase.Update) ? 1 : 0;
                                return(true);
                            }

                            case RoutinePhase.CustomUpdate:
                            {
                                Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForCustomUpdate);
                                m_YieldPhase      = YieldPhase.WaitForCustomUpdate;
                                m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.CustomUpdate && Manager.IsUpdating(RoutinePhase.CustomUpdate) ? 1 : 0;
                                return(true);
                            }

                            case RoutinePhase.ThinkUpdate:
                            {
                                Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForThinkUpdate);
                                m_YieldPhase      = YieldPhase.WaitForThinkUpdate;
                                m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.ThinkUpdate && Manager.IsUpdating(RoutinePhase.ThinkUpdate) ? 1 : 0;
                                return(true);
                            }

                            case RoutinePhase.RealtimeUpdate:
                            {
                                Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForRealtimeUpdate);
                                m_YieldPhase      = YieldPhase.WaitForRealtimeUpdate;
                                m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.RealtimeUpdate && Manager.IsUpdating(RoutinePhase.RealtimeUpdate) ? 1 : 0;
                                return(true);
                            }

                            case RoutinePhase.Manual:
                            default:
                            {
                                // Yielding a manual will not do anything
                                return(true);
                            }
                            }
                        }

                        if (resultType == TYPEHANDLE_WAITFORENDOFFRAME)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForEndOfFrame);
                            m_YieldPhase      = YieldPhase.WaitForEndOfFrame;
                            m_YieldFrameDelay = 0;
                            return(true);
                        }

                        if (resultType == TYPEHANDLE_WAITFORFIXEDUPDATE)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForFixedUpdate);
                            Manager.Host.WaitForFixedUpdate();
                            m_YieldPhase      = YieldPhase.WaitForFixedUpdate;
                            m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.FixedUpdate && Manager.IsUpdating(RoutinePhase.FixedUpdate) ? 1 : 0;
                            return(true);
                        }

                        if (resultType == TYPEHANDLE_WAITFORLATEUPDATE)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForLateUpdate);
                            m_YieldPhase      = YieldPhase.WaitForLateUpdate;
                            m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.LateUpdate && Manager.IsUpdating(RoutinePhase.LateUpdate) ? 1 : 0;
                            return(true);
                        }

                        if (resultType == TYPEHANDLE_WAITFORUPDATE)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForUpdate);
                            m_YieldPhase      = YieldPhase.WaitForUpdate;
                            m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.Update && Manager.IsUpdating(RoutinePhase.Update) ? 1 : 0;
                            return(true);
                        }

                        if (resultType == TYPEHANDLE_WAITFORCUSTOMUPDATE)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForCustomUpdate);
                            m_YieldPhase      = YieldPhase.WaitForCustomUpdate;
                            m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.CustomUpdate && Manager.IsUpdating(RoutinePhase.CustomUpdate) ? 1 : 0;
                            return(true);
                        }

                        if (resultType == TYPEHANDLE_WAITFORTHINKUPDATE)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForThinkUpdate);
                            m_YieldPhase      = YieldPhase.WaitForThinkUpdate;
                            m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.ThinkUpdate && Manager.IsUpdating(RoutinePhase.ThinkUpdate) ? 1 : 0;
                            return(true);
                        }

                        if (resultType == TYPEHANDLE_WAITFORREALTIMEUPDATE)
                        {
                            Manager.Fibers.AddFiberToYieldList(this, YieldPhase.WaitForRealtimeUpdate);
                            m_YieldPhase      = YieldPhase.WaitForRealtimeUpdate;
                            m_YieldFrameDelay = bApplyYieldDelay && m_UpdatePhase == RoutinePhase.RealtimeUpdate && Manager.IsUpdating(RoutinePhase.RealtimeUpdate) ? 1 : 0;
                            return(true);
                        }
                    }

                    if (WAITFORSECONDS_BYPASS && resultType == TYPEHANDLE_WAITFORSECONDS)
                    {
                        m_WaitTime = (float)FIELD_WAITFORSECONDS_SECONDS.GetValue(result);
                        return(true);
                    }

                    // Check for the subclassable types

                    #if SUPPORTS_CUSTOMYIELDINSTRUCTION
                    CustomYieldInstruction customInstruction = result as CustomYieldInstruction;
                    if (customInstruction != null)
                    {
                        m_UnityWait = Manager.Host.StartCoroutine(UnityWait(customInstruction));
                        return(true);
                    }
                    #endif

                    YieldInstruction instruction = result as YieldInstruction;
                    if (instruction != null)
                    {
                        m_UnityWait = Manager.Host.StartCoroutine(UnityWait(instruction));
                        return(true);
                    }

                    IFuture future = result as IFuture;
                    if (future != null)
                    {
                        if (!future.IsDone())
                        {
                            IEnumerator waitSequence = future.Wait();
                            if (waitSequence != null)
                            {
                                if (m_StackPosition == m_StackSize - 1)
                                {
                                    Array.Resize(ref m_Stack, m_StackSize *= 2);
                                }
                                m_Stack[++m_StackPosition] = waitSequence;
                            }
                        }
                        return(true);
                    }

                    IEnumerator enumerator = result as IEnumerator;
                    if (enumerator != null)
                    {
                        // Check if we need to resize the stack
                        if (m_StackPosition == m_StackSize - 1)
                        {
                            Array.Resize(ref m_Stack, m_StackSize *= 2);
                        }
                        m_Stack[++m_StackPosition] = enumerator;

                        CheckForNesting(enumerator);

                        return(true);
                    }
                }
                else
                {
                    bExecuteStack = current is RoutineDecorator && (((RoutineDecorator)current).Flags & RoutineDecoratorFlag.Inline) != 0;
                    m_Stack[m_StackPosition--] = null;
                    ((IDisposable)current).Dispose();
                    if (m_StackPosition < 0)
                    {
                        Dispose();
                        return(false);
                    }
                }
            }

            return(true);
        }