using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; namespace Unity.HLODSystem.Utils { public class CustomCoroutine : IEnumerator { class AsyncOperationEnumerator : IEnumerator { private AsyncOperation m_operation; public AsyncOperationEnumerator(AsyncOperation operation) { m_operation = operation; } public bool MoveNext() { return m_operation.isDone == false; } public void Reset() { } public object Current { get { return null; } } } private Stack m_routineStack = new Stack(); private List m_branchList = new List(); public CustomCoroutine(IEnumerator routine) { m_routineStack.Push(routine); } public bool MoveNext() { while (m_routineStack.Count > 0) { IEnumerator coroutine = m_routineStack.Peek(); if (coroutine.MoveNext()) { object cur = Current; if (cur == null) { return true; } else if (cur is IEnumerator) { m_routineStack.Push(cur as IEnumerator); } else if (cur is AsyncOperation) { m_routineStack.Push(new AsyncOperationEnumerator(cur as AsyncOperation)); } else if (cur is BranchCoroutine) { var branch = cur as BranchCoroutine; m_branchList.Add(CoroutineRunner.RunCoroutine(branch.GetBranch())); } else if (cur is WaitForBranches) { m_routineStack.Push(WaitForBranchesImpl(cur as WaitForBranches)); } else { Debug.LogWarning("Not support yield instruction in CustomCoroutine. " + cur.GetType().Name); return true; } } else { m_routineStack.Pop(); } } return false; } public void Reset() { while (m_routineStack.Count > 1) m_routineStack.Pop(); m_routineStack.Peek().Reset(); } public object Current { get { return m_routineStack.Count > 0 ? m_routineStack.Peek().Current : null; } } private IEnumerator WaitForBranchesImpl(WaitForBranches obj) { IEnumerator[] branches = m_branchList.ToArray(); for (int i = 0; i < branches.Length; ++i) { yield return branches[i]; obj.OnProgress((float)i / (float)branches.Length); } } } //Editor is not support coroutine //so, if it run on editor, it have to run coroutine manually. public class CoroutineRunner : MonoBehaviour { public static IEnumerator RunCoroutine(IEnumerator coroutine) { return Run(coroutine); } #if UNITY_EDITOR private static List s_coroutines; [InitializeOnLoadMethod] private static void Setup() { s_coroutines = new List(); EditorApplication.update+= EditorUpdate; } private static void EditorUpdate() { for (int i = 0; i < s_coroutines.Count; ++i) { if (s_coroutines[i].MoveNext() == false) { s_coroutines.RemoveAt(i); i -= 1; } } } private static CustomCoroutine Run(IEnumerator routine) { var coroutine = new CustomCoroutine(routine); s_coroutines.Add(coroutine); return coroutine; } #else private static GameObject gameObjectInstance = null; private static IEnumerator Wrapping(Coroutine c) { yield return c; } private static IEnumerator Run(IEnumerator routine) { if (gameObjectInstance == null) { gameObjectInstance = new GameObject("Runner"); gameObjectInstance.hideFlags = HideFlags.HideAndDontSave; gameObjectInstance.AddComponent(); } var runner = gameObjectInstance.GetComponent(); var coroutine = runner.StartCoroutine(routine); return Wrapping(coroutine); } #endif } }