/// <summary> /// Sets up a Fiber to run with the given host and routine. /// </summary> public Routine Initialize(MonoBehaviour inHost, IEnumerator inStart, bool inChained) { if (Manager.DebugMode && !(inStart is IDisposable)) { throw new ArgumentException("IEnumerators must also implement IDisposable."); } m_Counter = (byte)(m_Counter == byte.MaxValue ? 1 : m_Counter + 1); m_Handle = (Routine)Table.GenerateID(Index, m_Counter); m_Host = inHost; m_HostIdentity = RoutineIdentity.Find(m_Host.gameObject); m_WaitTime = 0; m_UnityWait = null; m_Name = null; Priority = 0; m_GroupMask = ReferenceEquals(m_HostIdentity, null) ? 0 : 1 << m_HostIdentity.Group; // Chained routines are always hosted on the manager if (inChained) { m_Chained = m_HostedByManager = true; } if (!inChained && ReferenceEquals(inHost, Manager)) { m_HostedByManager = true; } if (!ReferenceEquals(m_HostIdentity, null)) { m_HasIdentity = true; } m_TimeScale = 1.0f; m_RootFunction = inStart; m_Stack[m_StackPosition = 0] = inStart; IRoutineEnumerator callback = inStart as IRoutineEnumerator; if (callback != null) { if (!callback.OnRoutineStart()) { ClearStack(); Stop(); } } return(m_Handle); }
/// <summary> /// Runs the Fiber one frame. /// Will dispose itself if requested. /// Returns if still running. /// </summary> public bool Run() { if ((uint)m_Handle == 0) { return(false); } if (m_Disposing || (!m_HostedByManager && !m_Host)) { Dispose(); return(false); } if (IsPaused() || m_UnityWait != null) { return(true); } ApplyDeltaTime(); if (m_WaitTime > 0) { m_WaitTime -= Manager.Frame.DeltaTime; if (m_WaitTime > 0) { return(true); } } IEnumerator current = m_Stack[m_StackPosition]; bool bMovedNext = current.MoveNext(); // 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_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) { m_UnityWait = Manager.Host.StartCoroutine(UnityWait((WWW)result)); return(true); } 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); } return(true); } // Check for the subclassable types CustomYieldInstruction customInstruction = result as CustomYieldInstruction; if (customInstruction != null) { m_UnityWait = Manager.Host.StartCoroutine(UnityWait(customInstruction)); return(true); } YieldInstruction instruction = result as YieldInstruction; if (instruction != null) { m_UnityWait = Manager.Host.StartCoroutine(UnityWait(instruction)); 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; IRoutineEnumerator callback = enumerator as IRoutineEnumerator; if (callback != null) { bool bContinue = callback.OnRoutineStart(); if (!bContinue) { Dispose(); } return(bContinue); } return(true); } } else { m_Stack[m_StackPosition--] = null; ((IDisposable)current).Dispose(); if (m_StackPosition < 0) { Dispose(); return(false); } } return(true); }