Game UI ready
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
/// <summary>
|
||||
/// A handle to an EditorCoroutine, can be passed to <see cref="EditorCoroutineUtility">EditorCoroutineUtility</see> methods to control lifetime.
|
||||
/// </summary>
|
||||
public class EditorCoroutine
|
||||
{
|
||||
private struct YieldProcessor
|
||||
{
|
||||
enum DataType : byte
|
||||
{
|
||||
None = 0,
|
||||
WaitForSeconds = 1,
|
||||
EditorCoroutine = 2,
|
||||
AsyncOP = 3,
|
||||
}
|
||||
struct ProcessorData
|
||||
{
|
||||
public DataType type;
|
||||
public double targetTime;
|
||||
public object current;
|
||||
}
|
||||
|
||||
ProcessorData data;
|
||||
|
||||
public void Set(object yield)
|
||||
{
|
||||
if (yield == data.current)
|
||||
return;
|
||||
|
||||
var type = yield.GetType();
|
||||
var dataType = DataType.None;
|
||||
double targetTime = -1;
|
||||
|
||||
if(type == typeof(EditorWaitForSeconds))
|
||||
{
|
||||
targetTime = EditorApplication.timeSinceStartup + (yield as EditorWaitForSeconds).WaitTime;
|
||||
dataType = DataType.WaitForSeconds;
|
||||
}
|
||||
else if(type == typeof(EditorCoroutine))
|
||||
{
|
||||
dataType = DataType.EditorCoroutine;
|
||||
}
|
||||
else if(type == typeof(AsyncOperation) || type.IsSubclassOf(typeof(AsyncOperation)))
|
||||
{
|
||||
dataType = DataType.AsyncOP;
|
||||
}
|
||||
|
||||
data = new ProcessorData { current = yield, targetTime = targetTime, type = dataType };
|
||||
}
|
||||
|
||||
public bool MoveNext(IEnumerator enumerator)
|
||||
{
|
||||
var advance = data.type switch
|
||||
{
|
||||
DataType.WaitForSeconds => data.targetTime <= EditorApplication.timeSinceStartup,
|
||||
DataType.EditorCoroutine => (data.current as EditorCoroutine).m_IsDone,
|
||||
DataType.AsyncOP => (data.current as AsyncOperation).isDone,
|
||||
_ => data.current == enumerator.Current,//a IEnumerator or a plain object was passed to the implementation
|
||||
};
|
||||
if (advance)
|
||||
{
|
||||
data = default;// (ProcessorData);
|
||||
return enumerator.MoveNext();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal WeakReference m_Owner;
|
||||
IEnumerator m_Routine;
|
||||
YieldProcessor m_Processor;
|
||||
|
||||
bool m_IsDone;
|
||||
|
||||
internal EditorCoroutine(IEnumerator routine)
|
||||
{
|
||||
m_Owner = null;
|
||||
m_Routine = routine;
|
||||
EditorApplication.update += MoveNext;
|
||||
}
|
||||
|
||||
internal EditorCoroutine(IEnumerator routine, object owner)
|
||||
{
|
||||
m_Processor = new YieldProcessor();
|
||||
m_Owner = new WeakReference(owner);
|
||||
m_Routine = routine;
|
||||
EditorApplication.update += MoveNext;
|
||||
}
|
||||
|
||||
internal void MoveNext()
|
||||
{
|
||||
if (m_Owner != null && !m_Owner.IsAlive)
|
||||
{
|
||||
EditorApplication.update -= MoveNext;
|
||||
return;
|
||||
}
|
||||
|
||||
bool done = ProcessIEnumeratorRecursive(m_Routine);
|
||||
m_IsDone = !done;
|
||||
|
||||
if (m_IsDone)
|
||||
EditorApplication.update -= MoveNext;
|
||||
}
|
||||
|
||||
static readonly Stack<IEnumerator> kIEnumeratorProcessingStack = new Stack<IEnumerator>(32);
|
||||
private bool ProcessIEnumeratorRecursive(IEnumerator enumerator)
|
||||
{
|
||||
var root = enumerator;
|
||||
while(enumerator.Current as IEnumerator != null)
|
||||
{
|
||||
kIEnumeratorProcessingStack.Push(enumerator);
|
||||
enumerator = enumerator.Current as IEnumerator;
|
||||
}
|
||||
|
||||
//process leaf
|
||||
m_Processor.Set(enumerator.Current);
|
||||
var result = m_Processor.MoveNext(enumerator);
|
||||
|
||||
while (kIEnumeratorProcessingStack.Count > 1)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
result = kIEnumeratorProcessingStack.Pop().MoveNext();
|
||||
}
|
||||
else
|
||||
kIEnumeratorProcessingStack.Clear();
|
||||
}
|
||||
|
||||
if (kIEnumeratorProcessingStack.Count > 0 && !result && root == kIEnumeratorProcessingStack.Pop())
|
||||
{
|
||||
result = root.MoveNext();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void Stop()
|
||||
{
|
||||
m_Owner = null;
|
||||
m_Routine = null;
|
||||
EditorApplication.update -= MoveNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c1e3c1846518ae4da27dcaf08ef85f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
public static class EditorCoroutineUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts an <see cref ="EditorCoroutine">EditorCoroutine</see> with the specified owner object.
|
||||
/// If the garbage collector collects the owner object, while the resulting coroutine is still executing, the coroutine will stop running.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// int m_Updates = 0;
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// EditorCoroutineUtility.StartCoroutine(CountEditorUpdates(), this);
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator CountEditorUpdates()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// ++m_Updates;
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="routine"> IEnumerator to iterate over. </param>
|
||||
/// <param name="owner">Object owning the coroutine. </param>
|
||||
/// <remarks>
|
||||
/// Only types that don't inherit from <see cref="UnityEngine.Object">UnityEngine.Object</see> will get collected the next time the GC runs instead of getting null-ed immediately.
|
||||
/// </remarks>
|
||||
/// <returns>A handle to an <see cref="EditorCoroutine">EditorCoroutine</see>.</returns>
|
||||
public static EditorCoroutine StartCoroutine(IEnumerator routine, object owner)
|
||||
{
|
||||
return new EditorCoroutine(routine, owner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method starts an <see cref="EditorCoroutine">EditorCoroutine</see> without an owning object. The <see cref="EditorCoroutine">EditorCoroutine</see> runs until it completes or is canceled using <see cref="StopCoroutine(EditorCoroutine)">StopCoroutine</see>.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
/// using UnityEngine;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// EditorCoroutineUtility.StartCoroutineOwnerless(LogTimeSinceStartup());
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator LogTimeSinceStartup()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// Debug.LogFormat("Time since startup: {0} s", Time.realtimeSinceStartup);
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="routine"> Generator function to execute. </param>
|
||||
/// <returns>A handle to an <see cref="EditorCoroutine">EditorCoroutine.</see></returns>
|
||||
public static EditorCoroutine StartCoroutineOwnerless(IEnumerator routine)
|
||||
{
|
||||
return new EditorCoroutine(routine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately stop an <see cref="EditorCoroutine">EditorCoroutine</see>. This method is safe to call on an already completed <see cref="EditorCoroutine">EditorCoroutine</see>.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
/// using UnityEngine;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// EditorCoroutine m_LoggerCoroutine;
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// m_LoggerCoroutine = EditorCoroutineUtility.StartCoroutineOwnerless(LogRunning());
|
||||
/// }
|
||||
///
|
||||
/// void OnDisable()
|
||||
/// {
|
||||
/// EditorCoroutineUtility.StopCoroutine(m_LoggerCoroutine);
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator LogRunning()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// Debug.Log("Running");
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="coroutine">A handle to an <see cref="EditorCoroutine">EditorCoroutine.</see></param>
|
||||
public static void StopCoroutine(EditorCoroutine coroutine)
|
||||
{
|
||||
if (coroutine == null)
|
||||
{
|
||||
Serilog.Log.Warning("EditorCoroutine handle is null.");
|
||||
return;
|
||||
}
|
||||
coroutine.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3d162669c5693a47bf42827686f73d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
/// <summary>
|
||||
/// Suspends the <see cref="EditorCoroutine">EditorCoroutine</see> execution for the given amount of seconds, using unscaled time.
|
||||
/// The coroutine execution continues after the specified time has elapsed.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
///
|
||||
/// public class MyEditorWindow : EditorWindow
|
||||
/// {
|
||||
/// IEnumerator PrintEachSecond()
|
||||
/// {
|
||||
/// var waitForOneSecond = new EditorWaitForSeconds(1.0f);
|
||||
///
|
||||
/// while (true)
|
||||
/// {
|
||||
/// yield return waitForOneSecond;
|
||||
/// Debug.Log("Printing each second");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public class EditorWaitForSeconds
|
||||
{
|
||||
/// <summary>
|
||||
/// The time to wait in seconds.
|
||||
/// </summary>
|
||||
public float WaitTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a instruction object for yielding inside a generator function.
|
||||
/// </summary>
|
||||
/// <param name="time">The amount of time to wait in seconds.</param>
|
||||
public EditorWaitForSeconds(float time)
|
||||
{
|
||||
WaitTime = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d8612ff14468214aad7600138a50b79
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
public static class EditorWindowCoroutineExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Start an <see cref="EditorCoroutine">EditorCoroutine</see>, owned by the calling <see cref="EditorWindow">EditorWindow</see> instance.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// this.StartCoroutine(CloseWindowDelayed());
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator CloseWindowDelayed() //close the window after 1000 frames have elapsed
|
||||
/// {
|
||||
/// int count = 1000;
|
||||
/// while (count > 0)
|
||||
/// {
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// Close();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="routine"></param>
|
||||
/// <returns></returns>
|
||||
public static EditorCoroutine StartCoroutine(this EditorWindow window, IEnumerator routine)
|
||||
{
|
||||
return new EditorCoroutine(routine, window);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately stop an <see cref="EditorCoroutine">EditorCoroutine</see> that was started by the calling <see cref="EditorWindow"/> instance. This method is safe to call on an already completed <see cref="EditorCoroutine">EditorCoroutine</see>.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
/// using UnityEngine;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// EditorCoroutine coroutine;
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// coroutine = this.StartCoroutine(CloseWindowDelayed());
|
||||
/// }
|
||||
///
|
||||
/// private void OnDisable()
|
||||
/// {
|
||||
/// this.StopCoroutine(coroutine);
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator CloseWindowDelayed()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// Debug.Log("Running");
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="coroutine"></param>
|
||||
public static void StopCoroutine(this EditorWindow window, EditorCoroutine coroutine)
|
||||
{
|
||||
if(coroutine == null)
|
||||
{
|
||||
Serilog.Log.Warning("Provided EditorCoroutine handle is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(coroutine.m_Owner == null)
|
||||
{
|
||||
Serilog.Log.Error("The EditorCoroutine is ownerless. Please use EditorCoroutineEditor.StopCoroutine to terminate such coroutines.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!coroutine.m_Owner.IsAlive)
|
||||
return; //The EditorCoroutine's owner was already terminated execution will cease next time it is processed
|
||||
|
||||
var owner = coroutine.m_Owner.Target as EditorWindow;
|
||||
|
||||
if (owner == null || owner != null && owner != window)
|
||||
{
|
||||
Serilog.Log.Error("The EditorCoroutine is owned by another object: {0}.", coroutine.m_Owner.Target);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorCoroutineUtility.StopCoroutine(coroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64c15e0c4e36aa84193d4acb3c63afc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user