123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- using UnityEngine;
- using System.Collections;
- using UnityEditor;
- using System.Collections.Generic;
- using System;
- using System.Reflection;
- namespace marijnz.EditorCoroutines
- {
- internal class EditorCoroutines
- {
- internal class EditorCoroutine
- {
- public ICoroutineYield currentYield = new YieldDefault();
- public IEnumerator routine;
- public string routineUniqueHash;
- public string ownerUniqueHash;
- public string MethodName = "";
- public int ownerHash;
- public string ownerType;
- public bool finished = false;
- public EditorCoroutine(IEnumerator routine, int ownerHash, string ownerType)
- {
- this.routine = routine;
- this.ownerHash = ownerHash;
- this.ownerType = ownerType;
- ownerUniqueHash = ownerHash + "_" + ownerType;
- if (routine != null)
- {
- string[] split = routine.ToString().Split('<', '>');
- if (split.Length == 3)
- {
- this.MethodName = split[1];
- }
- }
- routineUniqueHash = ownerHash + "_" + ownerType + "_" + MethodName;
- }
- public EditorCoroutine(string methodName, int ownerHash, string ownerType)
- {
- MethodName = methodName;
- this.ownerHash = ownerHash;
- this.ownerType = ownerType;
- ownerUniqueHash = ownerHash + "_" + ownerType;
- routineUniqueHash = ownerHash + "_" + ownerType + "_" + MethodName;
- }
- }
- public interface ICoroutineYield
- {
- bool IsDone(float deltaTime);
- }
- struct YieldDefault : ICoroutineYield
- {
- public bool IsDone(float deltaTime)
- {
- return true;
- }
- }
- struct YieldWaitForSeconds : ICoroutineYield
- {
- public float timeLeft;
- public bool IsDone(float deltaTime)
- {
- timeLeft -= deltaTime;
- return timeLeft < 0;
- }
- }
- struct YieldCustomYieldInstruction : ICoroutineYield
- {
- public CustomYieldInstruction customYield;
- public bool IsDone(float deltaTime)
- {
- return !customYield.keepWaiting;
- }
- }
- struct YieldWWW : ICoroutineYield
- {
- public WWW Www;
- public bool IsDone(float deltaTime)
- {
- return Www.isDone;
- }
- }
- struct YieldAsync : ICoroutineYield
- {
- public AsyncOperation asyncOperation;
- public bool IsDone(float deltaTime)
- {
- return asyncOperation.isDone;
- }
- }
- struct YieldNestedCoroutine : ICoroutineYield
- {
- public EditorCoroutine coroutine;
- public bool IsDone(float deltaTime)
- {
- return coroutine.finished;
- }
- }
- static EditorCoroutines instance = null;
- Dictionary<string, List<EditorCoroutine>> coroutineDict = new Dictionary<string, List<EditorCoroutine>>();
- List<List<EditorCoroutine>> tempCoroutineList = new List<List<EditorCoroutine>>();
- Dictionary<string, Dictionary<string, EditorCoroutine>> coroutineOwnerDict =
- new Dictionary<string, Dictionary<string, EditorCoroutine>>();
- DateTime previousTimeSinceStartup;
- /// <summary>Starts a coroutine.</summary>
- /// <param name="routine">The coroutine to start.</param>
- /// <param name="thisReference">Reference to the instance of the class containing the method.</param>
- public static EditorCoroutine StartCoroutine(IEnumerator routine, object thisReference)
- {
- CreateInstanceIfNeeded();
- return instance.GoStartCoroutine(routine, thisReference);
- }
- /// <summary>Starts a coroutine.</summary>
- /// <param name="methodName">The name of the coroutine method to start.</param>
- /// <param name="thisReference">Reference to the instance of the class containing the method.</param>
- public static EditorCoroutine StartCoroutine(string methodName, object thisReference)
- {
- return StartCoroutine(methodName, null, thisReference);
- }
- /// <summary>Starts a coroutine.</summary>
- /// <param name="methodName">The name of the coroutine method to start.</param>
- /// <param name="value">The parameter to pass to the coroutine.</param>
- /// <param name="thisReference">Reference to the instance of the class containing the method.</param>
- public static EditorCoroutine StartCoroutine(string methodName, object value, object thisReference)
- {
- MethodInfo methodInfo = thisReference.GetType()
- .GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- if (methodInfo == null)
- {
- Debug.LogError("Coroutine '" + methodName + "' couldn't be started, the method doesn't exist!");
- }
- object returnValue;
- if (value == null)
- {
- returnValue = methodInfo.Invoke(thisReference, null);
- }
- else
- {
- returnValue = methodInfo.Invoke(thisReference, new object[] {value});
- }
- if (returnValue is IEnumerator)
- {
- CreateInstanceIfNeeded();
- return instance.GoStartCoroutine((IEnumerator) returnValue, thisReference);
- }
- else
- {
- Debug.LogError("Coroutine '" + methodName + "' couldn't be started, the method doesn't return an IEnumerator!");
- }
- return null;
- }
- /// <summary>Stops all coroutines being the routine running on the passed instance.</summary>
- /// <param name="routine"> The coroutine to stop.</param>
- /// <param name="thisReference">Reference to the instance of the class containing the method.</param>
- public static void StopCoroutine(IEnumerator routine, object thisReference)
- {
- CreateInstanceIfNeeded();
- instance.GoStopCoroutine(routine, thisReference);
- }
- /// <summary>
- /// Stops all coroutines named methodName running on the passed instance.</summary>
- /// <param name="methodName"> The name of the coroutine method to stop.</param>
- /// <param name="thisReference">Reference to the instance of the class containing the method.</param>
- public static void StopCoroutine(string methodName, object thisReference)
- {
- CreateInstanceIfNeeded();
- instance.GoStopCoroutine(methodName, thisReference);
- }
- /// <summary>
- /// Stops all coroutines running on the passed instance.</summary>
- /// <param name="thisReference">Reference to the instance of the class containing the method.</param>
- public static void StopAllCoroutines(object thisReference)
- {
- CreateInstanceIfNeeded();
- instance.GoStopAllCoroutines(thisReference);
- }
- static void CreateInstanceIfNeeded()
- {
- if (instance == null)
- {
- instance = new EditorCoroutines();
- instance.Initialize();
- }
- }
- void Initialize()
- {
- previousTimeSinceStartup = DateTime.Now;
- EditorApplication.update += OnUpdate;
- }
- void GoStopCoroutine(IEnumerator routine, object thisReference)
- {
- GoStopActualRoutine(CreateCoroutine(routine, thisReference));
- }
- void GoStopCoroutine(string methodName, object thisReference)
- {
- GoStopActualRoutine(CreateCoroutineFromString(methodName, thisReference));
- }
- void GoStopActualRoutine(EditorCoroutine routine)
- {
- if (coroutineDict.ContainsKey(routine.routineUniqueHash))
- {
- coroutineOwnerDict[routine.ownerUniqueHash].Remove(routine.routineUniqueHash);
- coroutineDict.Remove(routine.routineUniqueHash);
- }
- }
- void GoStopAllCoroutines(object thisReference)
- {
- EditorCoroutine coroutine = CreateCoroutine(null, thisReference);
- if (coroutineOwnerDict.ContainsKey(coroutine.ownerUniqueHash))
- {
- foreach (var couple in coroutineOwnerDict[coroutine.ownerUniqueHash])
- {
- coroutineDict.Remove(couple.Value.routineUniqueHash);
- }
- coroutineOwnerDict.Remove(coroutine.ownerUniqueHash);
- }
- }
- EditorCoroutine GoStartCoroutine(IEnumerator routine, object thisReference)
- {
- if (routine == null)
- {
- Debug.LogException(new Exception("IEnumerator is null!"), null);
- }
- EditorCoroutine coroutine = CreateCoroutine(routine, thisReference);
- GoStartCoroutine(coroutine);
- return coroutine;
- }
- void GoStartCoroutine(EditorCoroutine coroutine)
- {
- if (!coroutineDict.ContainsKey(coroutine.routineUniqueHash))
- {
- List<EditorCoroutine> newCoroutineList = new List<EditorCoroutine>();
- coroutineDict.Add(coroutine.routineUniqueHash, newCoroutineList);
- }
- coroutineDict[coroutine.routineUniqueHash].Add(coroutine);
- if (!coroutineOwnerDict.ContainsKey(coroutine.ownerUniqueHash))
- {
- Dictionary<string, EditorCoroutine> newCoroutineDict = new Dictionary<string, EditorCoroutine>();
- coroutineOwnerDict.Add(coroutine.ownerUniqueHash, newCoroutineDict);
- }
- // If the method from the same owner has been stored before, it doesn't have to be stored anymore,
- // One reference is enough in order for "StopAllCoroutines" to work
- if (!coroutineOwnerDict[coroutine.ownerUniqueHash].ContainsKey(coroutine.routineUniqueHash))
- {
- coroutineOwnerDict[coroutine.ownerUniqueHash].Add(coroutine.routineUniqueHash, coroutine);
- }
- MoveNext(coroutine);
- }
- EditorCoroutine CreateCoroutine(IEnumerator routine, object thisReference)
- {
- return new EditorCoroutine(routine, thisReference.GetHashCode(), thisReference.GetType().ToString());
- }
- EditorCoroutine CreateCoroutineFromString(string methodName, object thisReference)
- {
- return new EditorCoroutine(methodName, thisReference.GetHashCode(), thisReference.GetType().ToString());
- }
- void OnUpdate()
- {
- float deltaTime = (float) (DateTime.Now.Subtract(previousTimeSinceStartup).TotalMilliseconds / 1000.0f);
- previousTimeSinceStartup = DateTime.Now;
- if (coroutineDict.Count == 0)
- {
- return;
- }
- tempCoroutineList.Clear();
- foreach (var pair in coroutineDict)
- tempCoroutineList.Add(pair.Value);
- for (var i = tempCoroutineList.Count - 1; i >= 0; i--)
- {
- List<EditorCoroutine> coroutines = tempCoroutineList[i];
- for (int j = coroutines.Count - 1; j >= 0; j--)
- {
- EditorCoroutine coroutine = coroutines[j];
- if (!coroutine.currentYield.IsDone(deltaTime))
- {
- continue;
- }
- if (!MoveNext(coroutine))
- {
- coroutines.RemoveAt(j);
- coroutine.currentYield = null;
- coroutine.finished = true;
- }
- if (coroutines.Count == 0)
- {
- coroutineDict.Remove(coroutine.ownerUniqueHash);
- }
- }
- }
- }
- static bool MoveNext(EditorCoroutine coroutine)
- {
- if (coroutine.routine.MoveNext())
- {
- return Process(coroutine);
- }
- return false;
- }
- // returns false if no next, returns true if OK
- static bool Process(EditorCoroutine coroutine)
- {
- object current = coroutine.routine.Current;
- if (current == null)
- {
- coroutine.currentYield = new YieldDefault();
- }
- else if (current is WaitForSeconds)
- {
- float seconds = float.Parse(GetInstanceField(typeof(WaitForSeconds), current, "m_Seconds").ToString());
- coroutine.currentYield = new YieldWaitForSeconds() {timeLeft = seconds};
- }
- else if (current is CustomYieldInstruction)
- {
- coroutine.currentYield = new YieldCustomYieldInstruction()
- {
- customYield = current as CustomYieldInstruction
- };
- }
- else if (current is WWW)
- {
- coroutine.currentYield = new YieldWWW {Www = (WWW) current};
- }
- else if (current is WaitForFixedUpdate || current is WaitForEndOfFrame)
- {
- coroutine.currentYield = new YieldDefault();
- }
- else if (current is AsyncOperation)
- {
- coroutine.currentYield = new YieldAsync {asyncOperation = (AsyncOperation) current};
- }
- else if (current is EditorCoroutine)
- {
- coroutine.currentYield = new YieldNestedCoroutine { coroutine= (EditorCoroutine) current};
- }
- else
- {
- Debug.LogException(
- new Exception("<" + coroutine.MethodName + "> yielded an unknown or unsupported type! (" + current.GetType() + ")"),
- null);
- coroutine.currentYield = new YieldDefault();
- }
- return true;
- }
- static object GetInstanceField(Type type, object instance, string fieldName)
- {
- BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
- FieldInfo field = type.GetField(fieldName, bindFlags);
- return field.GetValue(instance);
- }
- }
- }
|