public static void DemoEditorCoroutines()
 {
     // adds a menu item to test the coroutine system.
     if (!Application.isPlaying)
     {
         // lets fire off the demo coroutine with a UI so we can see what its doing. We could also run it without a UI by using EditorCoroutineRunner.StartCoroutine(...)
         EditorCoroutineRunner.StartCoroutineWithUI(DemoCoroutiune(), "Lotte's Coroutine Demo", true);
     }
 }
        static IEnumerator DemoCoroutiune()
        {
            // You can code editor coroutines exactly like you would a normal unity coroutine
            Debug.Log("Step: 0");
            yield return(null);

            // all the normal return types that work with regular Unity coroutines should work here! for example lets wait for a second
            Debug.Log("Step: 1");
            yield return(new WaitForSeconds(1));

            // We can also yeild any type that extends Unitys CustomYieldInstruction class. here we are going to use EditorStatusUpdate. this allows us to yield and update the
            // editor coroutine UI at the same time!
            yield return(new EditorStatusUpdate("coroutine is running", 0.2f));

            // We can also yield to nested coroutines
            Debug.Log("Step: 2");

            yield return(EditorCoroutineRunner.StartCoroutine(DemoTwo()));

            EditorCoroutineRunner.UpdateUIProgressBar(0.35f); // we can use the UpdateUI helper methods to update the UI whenever, without yielding a EditorStatusUpdate
            yield return(DemoTwo());                          // it shouldnt matter how we start the nested coroutine, the editor runner can hadle it

            // we can even yield a UnityWebRequest object if we want to grab data from the internets!
            Debug.Log("Step: 3");

            // for example, lets as random.org to generate us a list of random numbers and shove it into the console
            var www = new UnityWebRequest("https://www.random.org/integers/?num=100&min=1&max=1000&col=1&base=10&col=5&format=plain&rnd=new");

            yield return(www);

            Debug.Log(www.ToString());

            EditorCoroutineRunner.UpdateUI("Half way!", 0.5f);
            yield return(new WaitForSeconds(1));

            // Finally lets do a long runnig task and split its updates over many frames to keep the editor responsive
            Debug.Log("Step: 4");
            var test = 1000;

            yield return(new WaitUntil(() => {
                test--;
                EditorCoroutineRunner.UpdateUI("Crunching Numbers: " + test, 0.5f + (((1000 - test) / 1000f) * 0.5f));
                return (test <= 0);
            }));

            Debug.Log("Done!!");
        }
        /// <summary>
        /// Send a Coroutine to be run on the main thread. See EditorDispatchActions for some common usecases.
        /// </summary>
        /// <param name="task">A coroutine to run on the main thread</param>
        /// <param name="showUI">if the Editor Corotine runner should run a progress UI</param>
        /// <returns>An AsyncDispatch that can be used to track if the coroutine has been dispatched & completed.</returns>
        public static AsyncDispatch Dispatch(IEnumerator task, bool showUI = false)
        {
            // you need this system for this to work! https://gist.github.com/LotteMakesStuff/16b5f2fc108f9a0201950c797d53cfbf
            lock (dispatchQueue) {
                AsyncDispatch dispatch = new AsyncDispatch();

                dispatchQueue.Enqueue(() =>
                {
                    if (showUI)
                    {
                        EditorCoroutineRunner.StartCoroutineWithUI(DispatchCorotine(task, dispatch), "Dispatcher task", false);
                    }
                    else
                    {
                        EditorCoroutineRunner.StartCoroutine(task);
                    }
                });

                return(dispatch);
            }
        }
        public void Tick()
        {
            if (coroutine != null)
            {
                // First check if we have been canceled by the UI. If so, we need to stop before doing any wait processing
                if (canceled)
                {
                    Stop();
                    return;
                }

                // Did the last Yield want us to wait?
                bool isWaiting = false;
                var  now       = DateTime.Now;
                if (current != null)
                {
                    if (currentType == typeof(WaitForSeconds))
                    {
                        // last yield was a WaitForSeconds. Lets update the timer.
                        var delta = now - lastUpdateTime;
                        timer -= (float)delta.TotalSeconds;

                        if (timer > 0.0f)
                        {
                            isWaiting = true;
                        }
                    }
                    else if (currentType == typeof(WaitForEndOfFrame) || currentType == typeof(WaitForFixedUpdate))
                    {
                        // These dont make sense in editor, so we will treat them the same as a null return...
                        isWaiting = false;
                    }
                    else if (currentType == typeof(UnityWebRequest))
                    {
                        // Web download request, lets see if its done!
                        var www = current as UnityWebRequest;
                        if (!www.isDone)
                        {
                            isWaiting = true;
                        }
                    }
                    else if (currentType.IsSubclassOf(typeof(CustomYieldInstruction)))
                    {
                        // last yield was a custom yield type, lets check its keepWaiting property and react to that
                        var yieldInstruction = current as CustomYieldInstruction;
                        if (yieldInstruction.keepWaiting)
                        {
                            isWaiting = true;
                        }
                    }
                    else if (currentType == typeof(EditorCoroutine))
                    {
                        // Were waiting on another coroutine to finish
                        var editorCoroutine = current as EditorCoroutine;
                        if (!editorCoroutine.HasFinished)
                        {
                            isWaiting = true;
                        }
                    }
                    else if (typeof(IEnumerator).IsAssignableFrom(currentType))
                    {
                        // if were just seeing an enumerator lets assume that were seeing a nested coroutine that has been passed in without calling start.. were start it properly here if we need to
                        if (nestedCoroutine == null)
                        {
                            nestedCoroutine = EditorCoroutineRunner.StartCoroutine(current as IEnumerator);
                            isWaiting       = true;
                        }
                        else
                        {
                            isWaiting = !nestedCoroutine.HasFinished;
                        }
                    }
                    else if (currentType == typeof(Coroutine))
                    {
                        // UNSUPPORTED
                        UnityEngine.Debug.LogError("Nested Coroutines started by Unity's defaut StartCoroutine method are not supported in editor! please use EditorCoroutineRunner.Start instead. Canceling.");
                        canceled = true;
                    }
                    else
                    {
                        // UNSUPPORTED
                        Debug.LogError("Unsupported yield (" + currentType + ") in editor coroutine!! Canceling.");
                        canceled = true;
                    }
                }
                lastUpdateTime = now;

                // have we been canceled?
                if (canceled)
                {
                    Stop();
                    return;
                }

                if (!isWaiting)
                {
                    // nope were good! tick the coroutine!
                    bool update = coroutine.MoveNext();

                    if (update)
                    {
                        // yup the coroutine returned true so its been ticked...

                        // lets see what it actually yielded
                        current = coroutine.Current;
                        if (current != null)
                        {
                            // is it a type we have to do extra processing on?
                            currentType = current.GetType();

                            if (currentType == typeof(WaitForSeconds))
                            {
                                // its a WaitForSeconds... lets use reflection to pull out how long the actual wait is for so we can process the wait
                                var       wait      = current as WaitForSeconds;
                                FieldInfo m_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.NonPublic | BindingFlags.Instance);
                                if (m_Seconds != null)
                                {
                                    timer = (float)m_Seconds.GetValue(wait);
                                }
                            }
                            else if (currentType == typeof(EditorStatusUpdate))
                            {
                                // Special case yield that wants to update the UI!
                                var updateInfo = current as EditorStatusUpdate;
                                if (updateInfo.HasLabelUpdate)
                                {
                                    Label = updateInfo.Label;
                                }
                                if (updateInfo.HasPercentUpdate)
                                {
                                    PercentComplete = updateInfo.PercentComplete;
                                }
                            }
                        }
                    }
                    else
                    {
                        // Coroutine returned false so its finally finished!!
                        Stop();
                    }
                }
            }
        }