using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if UNITY_5_5_OR_NEWER
using UnityEngine.Profiling;
#endif
// /////////////////////////////////////////////////////////////////////////////////////////
// More Effective Coroutines Pro
// v2.03.0
//
// This is an improved implementation of coroutines that boasts zero per-frame memory allocations,
// runs about twice as fast as Unity's built in coroutines and has a range of extra features.
//
// For manual, support, or upgrade guide visit http://trinary.tech/
//
// Created by Teal Rogers
// Trinary Software
// All rights preserved
// trinaryllc@gmail.com
// /////////////////////////////////////////////////////////////////////////////////////////
namespace MovementEffects
{
public class Timing : MonoBehaviour
{
public enum DebugInfoType
{
None,
SeperateCoroutines,
SeperateTags
}
///
/// The time between calls to SlowUpdate.
///
[Tooltip("How quickly the SlowUpdate segment ticks.")]
public float TimeBetweenSlowUpdateCalls = 1f / 7f;
///
/// The amount that each coroutine should be seperated inside the Unity profiler. NOTE: When the profiler window
/// is not open this value is ignored and all coroutines behave as if "None" is selected.
///
[Tooltip("How much data should be sent to the profiler window when it's open.")]
public DebugInfoType ProfilerDebugAmount = DebugInfoType.None;
///
/// Whether the manual timeframe should automatically trigger during the update segment.
///
[Tooltip("When using manual timeframe, should it run automatically after the update loop or only when TriggerManualTimframeUpdate is called.")]
public bool AutoTriggerManualTimeframe = true;
///
/// The number of coroutines that are being run in the Update segment.
///
[Tooltip("A count of the number of Update coroutines that are currently running."), Space(12)]
public int UpdateCoroutines;
///
/// The number of coroutines that are being run in the FixedUpdate segment.
///
[Tooltip("A count of the number of FixedUpdate coroutines that are currently running.")]
public int FixedUpdateCoroutines;
///
/// The number of coroutines that are being run in the LateUpdate segment.
///
[Tooltip("A count of the number of LateUpdate coroutines that are currently running.")]
public int LateUpdateCoroutines;
///
/// The number of coroutines that are being run in the SlowUpdate segment.
///
[Tooltip("A count of the number of SlowUpdate coroutines that are currently running.")]
public int SlowUpdateCoroutines;
///
/// The number of coroutines that are being run in the RealtimeUpdate segment.
///
[Tooltip("A count of the number of RealtimeUpdate coroutines that are currently running.")]
public int RealtimeUpdateCoroutines;
///
/// The number of coroutines that are being run in the EditorUpdate segment.
///
[Tooltip("A count of the number of EditorUpdate coroutines that are currently running.")]
public int EditorUpdateCoroutines;
///
/// The number of coroutines that are being run in the EditorSlowUpdate segment.
///
[Tooltip("A count of the number of EditorSlowUpdate coroutines that are currently running.")]
public int EditorSlowUpdateCoroutines;
///
/// The number of coroutines that are being run in the EndOfFrame segment.
///
[Tooltip("A count of the number of EndOfFrame coroutines that are currently running.")]
public int EndOfFrameCoroutines;
///
/// The number of coroutines that are being run in the ManualTimeframe segment.
///
[Tooltip("A count of the number of ManualTimeframe coroutines that are currently running.")]
public int ManualTimeframeCoroutines;
///
/// The time in seconds that the current segment has been running.
///
[HideInInspector]
public double localTime;
///
/// The time in seconds that the current segment has been running.
///
public static float LocalTime { get { return (float)Instance.localTime; } }
///
/// The amount of time in fractional seconds that elapsed between this frame and the last frame.
///
[HideInInspector]
public float deltaTime;
///
/// The amount of time in fractional seconds that elapsed between this frame and the last frame.
///
public static float DeltaTime { get { return Instance.deltaTime; } }
///
/// When defined, all errors from inside coroutines will be passed into this function instead of falling through to the Unity console.
///
public System.Action OnError;
///
/// When defined, this function will be called every time manual timeframe needs to be set. The last manual timeframe time is passed in, and
/// the new manual timeframe time needs to be returned. If this function is left as null, manual timeframe will be set to the current Time.time.
///
public System.Func SetManualTimeframeTime;
///
/// Used for advanced coroutine control.
///
public static System.Func, Timing, CoroutineHandle, IEnumerator> ReplacementFunction;
private bool _runningUpdate;
private bool _runningFixedUpdate;
private bool _runningLateUpdate;
private bool _runningRealtimeUpdate;
private bool _runningEditorUpdate;
private int _nextUpdateProcessSlot;
private int _nextLateUpdateProcessSlot;
private int _nextFixedUpdateProcessSlot;
private int _nextSlowUpdateProcessSlot;
private int _nextRealtimeUpdateProcessSlot;
private int _nextEditorUpdateProcessSlot;
private int _nextEditorSlowUpdateProcessSlot;
private int _nextEndOfFrameProcessSlot;
private int _nextManualTimeframeProcessSlot;
private double _lastUpdateTime;
private double _lastLateUpdateTime;
private double _lastFixedUpdateTime;
private double _lastSlowUpdateTime;
private double _lastRealtimeUpdateTime;
private double _lastEditorUpdateTime;
private double _lastEditorSlowUpdateTime;
private double _lastManualTimeframeTime;
private ushort _framesSinceUpdate;
private ushort _expansions = 1;
private byte _instanceID;
private bool _EOFPumpRan;
private readonly WaitForEndOfFrame _EOFWaitObject = new WaitForEndOfFrame();
private readonly Dictionary> _waitingTriggers = new Dictionary>();
private readonly Queue _exceptions = new Queue();
private readonly Dictionary _handleToIndex = new Dictionary();
private readonly Dictionary _indexToHandle = new Dictionary();
private readonly Dictionary _processTags = new Dictionary();
private readonly Dictionary> _taggedProcesses = new Dictionary>();
private readonly Dictionary _processLayers = new Dictionary();
private readonly Dictionary> _layeredProcesses = new Dictionary>();
private IEnumerator[] UpdateProcesses = new IEnumerator[InitialBufferSizeLarge];
private IEnumerator[] LateUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
private IEnumerator[] FixedUpdateProcesses = new IEnumerator[InitialBufferSizeMedium];
private IEnumerator[] SlowUpdateProcesses = new IEnumerator[InitialBufferSizeMedium];
private IEnumerator[] RealtimeUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
private IEnumerator[] EditorUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
private IEnumerator[] EditorSlowUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
private IEnumerator[] EndOfFrameProcesses = new IEnumerator[InitialBufferSizeSmall];
private IEnumerator[] ManualTimeframeProcesses = new IEnumerator[InitialBufferSizeSmall];
private volatile bool[] UpdatePaused = new bool[InitialBufferSizeLarge];
private volatile bool[] LateUpdatePaused = new bool[InitialBufferSizeSmall];
private volatile bool[] FixedUpdatePaused = new bool[InitialBufferSizeMedium];
private volatile bool[] SlowUpdatePaused = new bool[InitialBufferSizeMedium];
private volatile bool[] RealtimeUpdatePaused = new bool[InitialBufferSizeSmall];
private volatile bool[] EditorUpdatePaused = new bool[InitialBufferSizeSmall];
private volatile bool[] EditorSlowUpdatePaused = new bool[InitialBufferSizeSmall];
private volatile bool[] EndOfFramePaused = new bool[InitialBufferSizeSmall];
private volatile bool[] ManualTimeframePaused = new bool[InitialBufferSizeSmall];
private const ushort FramesUntilMaintenance = 64;
private const int ProcessArrayChunkSize = 64;
private const int InitialBufferSizeLarge = 256;
private const int InitialBufferSizeMedium = 64;
private const int InitialBufferSizeSmall = 8;
private static readonly Dictionary ActiveInstances = new Dictionary();
private static Timing _instance;
public static Timing Instance
{
get
{
if (_instance == null || !_instance.gameObject)
{
GameObject instanceHome = GameObject.Find("Movement Effects");
System.Type movementType =
System.Type.GetType("MovementEffects.Movement, MovementOverTime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
if (instanceHome == null)
{
instanceHome = new GameObject { name = "Movement Effects" };
DontDestroyOnLoad(instanceHome);
if (movementType != null)
instanceHome.AddComponent(movementType);
_instance = instanceHome.AddComponent();
}
else
{
if (movementType != null && instanceHome.GetComponent(movementType) == null)
instanceHome.AddComponent(movementType);
_instance = instanceHome.GetComponent() ?? instanceHome.AddComponent();
}
}
return _instance;
}
set { _instance = value; }
}
void Awake()
{
if (_instance == null)
_instance = this;
else
deltaTime = Instance.deltaTime;
_instanceID = 0x01;
while (ActiveInstances.ContainsKey(_instanceID))
_instanceID++;
if (_instanceID == 0x20)
{
GameObject.Destroy(gameObject);
throw new System.OverflowException("You are only allowed 31 instances of MEC at one time.");
}
ActiveInstances.Add(_instanceID, this);
}
void OnDestroy()
{
if (_instance == this)
_instance = null;
ActiveInstances.Remove(_instanceID);
}
void OnEnable()
{
if (_nextEditorUpdateProcessSlot > 0 || _nextEditorSlowUpdateProcessSlot > 0)
OnEditorStart();
if (_nextEndOfFrameProcessSlot > 0)
RunCoroutineSingletonOnInstance(_EOFPumpWatcher(), "MEC_EOFPumpWatcher");
}
void Update()
{
if (_lastSlowUpdateTime + TimeBetweenSlowUpdateCalls < ThreadSafeElapsedTime.GetElapsedSecondsSinceStartUp() && _nextSlowUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.SlowUpdate };
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextSlowUpdateProcessSlot; coindex.i++)
{
if (!SlowUpdatePaused[coindex.i] && SlowUpdateProcesses[coindex.i] != null && !(localTime < SlowUpdateProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine (Slow Update), " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag"))
: "Processing Coroutine (Slow Update)");
}
try
{
if (!SlowUpdateProcesses[coindex.i].MoveNext())
{
SlowUpdateProcesses[coindex.i] = null;
}
else if (SlowUpdateProcesses[coindex.i] != null && float.IsNaN(SlowUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
SlowUpdateProcesses[coindex.i] = null;
}
else
{
SlowUpdateProcesses[coindex.i] = ReplacementFunction(SlowUpdateProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
SlowUpdateProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
}
if (_nextRealtimeUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.RealtimeUpdate };
_runningRealtimeUpdate = true;
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextRealtimeUpdateProcessSlot; coindex.i++)
{
if (!RealtimeUpdatePaused[coindex.i] && RealtimeUpdateProcesses[coindex.i] != null && !(localTime < RealtimeUpdateProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine (Realtime Update), " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag"))
: "Processing Coroutine (Realtime Update)");
}
try
{
if (!RealtimeUpdateProcesses[coindex.i].MoveNext())
{
RealtimeUpdateProcesses[coindex.i] = null;
}
else if (RealtimeUpdateProcesses[coindex.i] != null && float.IsNaN(RealtimeUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
RealtimeUpdateProcesses[coindex.i] = null;
}
else
{
RealtimeUpdateProcesses[coindex.i] = ReplacementFunction(RealtimeUpdateProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
RealtimeUpdateProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
_runningRealtimeUpdate = false;
}
if (_nextUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.Update };
_runningUpdate = true;
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextUpdateProcessSlot; coindex.i++)
{
if (!UpdatePaused[coindex.i] && UpdateProcesses[coindex.i] != null && !(localTime < UpdateProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag")) : "Processing Coroutine");
}
try
{
if (!UpdateProcesses[coindex.i].MoveNext())
{
UpdateProcesses[coindex.i] = null;
}
else if (UpdateProcesses[coindex.i] != null && float.IsNaN(UpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
UpdateProcesses[coindex.i] = null;
}
else
{
UpdateProcesses[coindex.i] = ReplacementFunction(UpdateProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
UpdateProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
_runningUpdate = false;
}
if (AutoTriggerManualTimeframe)
{
TriggerManualTimeframeUpdate();
}
else
{
if (++_framesSinceUpdate > FramesUntilMaintenance)
{
_framesSinceUpdate = 0;
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.BeginSample("Maintenance Task");
RemoveUnused();
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
if (_exceptions.Count > 0)
throw _exceptions.Dequeue();
}
}
void FixedUpdate()
{
if (_nextFixedUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.FixedUpdate };
_runningFixedUpdate = true;
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextFixedUpdateProcessSlot; coindex.i++)
{
if (!FixedUpdatePaused[coindex.i] && FixedUpdateProcesses[coindex.i] != null && !(localTime < FixedUpdateProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag")) : "Processing Coroutine");
}
try
{
if (!FixedUpdateProcesses[coindex.i].MoveNext())
{
FixedUpdateProcesses[coindex.i] = null;
}
else if (FixedUpdateProcesses[coindex.i] != null && float.IsNaN(FixedUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
FixedUpdateProcesses[coindex.i] = null;
}
else
{
FixedUpdateProcesses[coindex.i] = ReplacementFunction(FixedUpdateProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
FixedUpdateProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
_runningFixedUpdate = false;
}
if (_exceptions.Count > 0)
throw _exceptions.Dequeue();
}
void LateUpdate()
{
if (_nextLateUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.LateUpdate };
_runningLateUpdate = true;
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextLateUpdateProcessSlot; coindex.i++)
{
if (!LateUpdatePaused[coindex.i] && LateUpdateProcesses[coindex.i] != null && !(localTime < LateUpdateProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag")) : "Processing Coroutine");
}
try
{
if (!LateUpdateProcesses[coindex.i].MoveNext())
{
LateUpdateProcesses[coindex.i] = null;
}
else if (LateUpdateProcesses[coindex.i] != null && float.IsNaN(LateUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
LateUpdateProcesses[coindex.i] = null;
}
else
{
LateUpdateProcesses[coindex.i] = ReplacementFunction(LateUpdateProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
LateUpdateProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
_runningLateUpdate = false;
}
if (_exceptions.Count > 0)
throw _exceptions.Dequeue();
}
///
/// This will trigger an update in the manual timeframe segment. If the AutoTriggerManualTimeframeDuringUpdate variable is set to true
/// then this function will be automitically called every Update, so you would normally want to set that variable to false before
/// calling this function yourself.
///
public void TriggerManualTimeframeUpdate()
{
if (_nextManualTimeframeProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.ManualTimeframe };
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextManualTimeframeProcessSlot; coindex.i++)
{
if (!ManualTimeframePaused[coindex.i] && ManualTimeframeProcesses[coindex.i] != null &&
!(localTime < ManualTimeframeProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine (Manual Timeframe), " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag"))
: "Processing Coroutine (Manual Timeframe)");
}
try
{
if (!ManualTimeframeProcesses[coindex.i].MoveNext())
{
ManualTimeframeProcesses[coindex.i] = null;
}
else if (ManualTimeframeProcesses[coindex.i] != null && float.IsNaN(ManualTimeframeProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
ManualTimeframeProcesses[coindex.i] = null;
}
else
{
ManualTimeframeProcesses[coindex.i] = ReplacementFunction(ManualTimeframeProcesses[coindex.i],
this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
ManualTimeframeProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
}
if (++_framesSinceUpdate > FramesUntilMaintenance)
{
_framesSinceUpdate = 0;
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.BeginSample("Maintenance Task");
RemoveUnused();
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
if (_exceptions.Count > 0)
throw _exceptions.Dequeue();
}
private bool OnEditorStart()
{
#if UNITY_EDITOR
if (EditorApplication.isPlayingOrWillChangePlaymode)
return false;
if (_lastEditorUpdateTime == 0d)
_lastEditorUpdateTime = EditorApplication.timeSinceStartup;
EditorApplication.update -= OnEditorUpdate;
EditorApplication.update += OnEditorUpdate;
return true;
#else
return false;
#endif
}
#if UNITY_EDITOR
private void OnEditorUpdate()
{
if (EditorApplication.isPlayingOrWillChangePlaymode)
{
for (int i = 0; i < _nextEditorUpdateProcessSlot; i++)
EditorUpdateProcesses[i] = null;
_nextEditorUpdateProcessSlot = 0;
for (int i = 0; i < _nextEditorSlowUpdateProcessSlot; i++)
EditorSlowUpdateProcesses[i] = null;
_nextEditorSlowUpdateProcessSlot = 0;
EditorApplication.update -= OnEditorUpdate;
_instance = null;
}
if (_lastEditorSlowUpdateTime + TimeBetweenSlowUpdateCalls < EditorApplication.timeSinceStartup && _nextEditorSlowUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.EditorSlowUpdate };
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextEditorSlowUpdateProcessSlot; coindex.i++)
{
if (!EditorSlowUpdatePaused[coindex.i] && EditorSlowUpdateProcesses[coindex.i] != null &&
!(EditorApplication.timeSinceStartup < EditorSlowUpdateProcesses[coindex.i].Current))
{
try
{
if (!EditorSlowUpdateProcesses[coindex.i].MoveNext())
{
EditorSlowUpdateProcesses[coindex.i] = null;
}
else if (EditorSlowUpdateProcesses[coindex.i] != null && float.IsNaN(EditorSlowUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
EditorSlowUpdateProcesses[coindex.i] = null;
}
else
{
EditorSlowUpdateProcesses[coindex.i] = ReplacementFunction(EditorSlowUpdateProcesses[coindex.i],
this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
EditorSlowUpdateProcesses[coindex.i] = null;
}
}
}
}
if (_nextEditorUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.EditorUpdate };
_runningEditorUpdate = true;
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextEditorUpdateProcessSlot; coindex.i++)
{
if (!EditorUpdatePaused[coindex.i] && EditorUpdateProcesses[coindex.i] != null &&
!(EditorApplication.timeSinceStartup < EditorUpdateProcesses[coindex.i].Current))
{
try
{
if (!EditorUpdateProcesses[coindex.i].MoveNext())
{
EditorUpdateProcesses[coindex.i] = null;
}
else if (EditorUpdateProcesses[coindex.i] != null && float.IsNaN(EditorUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
EditorUpdateProcesses[coindex.i] = null;
}
else
{
EditorUpdateProcesses[coindex.i] = ReplacementFunction(EditorUpdateProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
EditorUpdateProcesses[coindex.i] = null;
}
}
}
_runningEditorUpdate = false;
}
if (++_framesSinceUpdate > FramesUntilMaintenance)
{
_framesSinceUpdate = 0;
EditorRemoveUnused();
}
if (_exceptions.Count > 0)
throw _exceptions.Dequeue();
}
#endif
private IEnumerator _EOFPumpWatcher()
{
while (_nextEndOfFrameProcessSlot > 0)
{
if (!_EOFPumpRan)
base.StartCoroutine(_EOFPump());
_EOFPumpRan = false;
yield return 0f;
}
_EOFPumpRan = false;
}
private System.Collections.IEnumerator _EOFPump()
{
while (_nextEndOfFrameProcessSlot > 0)
{
yield return _EOFWaitObject;
ProcessIndex coindex = new ProcessIndex { seg = Segment.EndOfFrame };
_EOFPumpRan = true;
UpdateTimeValues(coindex.seg);
for (coindex.i = 0; coindex.i < _nextEndOfFrameProcessSlot; coindex.i++)
{
if (!EndOfFramePaused[coindex.i] && EndOfFrameProcesses[coindex.i] != null && !(localTime < EndOfFrameProcesses[coindex.i].Current))
{
if (ProfilerDebugAmount != DebugInfoType.None)
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(coindex) ? "layer " + _processLayers[coindex] : "no layer") +
(_processTags.ContainsKey(coindex) ? ", tag " + _processTags[coindex] : ", no tag")) : "Processing Coroutine");
}
try
{
if (!EndOfFrameProcesses[coindex.i].MoveNext())
{
EndOfFrameProcesses[coindex.i] = null;
}
else if (EndOfFrameProcesses[coindex.i] != null && float.IsNaN(EndOfFrameProcesses[coindex.i].Current))
{
if (ReplacementFunction == null)
{
EndOfFrameProcesses[coindex.i] = null;
}
else
{
EndOfFrameProcesses[coindex.i] = ReplacementFunction(EndOfFrameProcesses[coindex.i], this, _indexToHandle[coindex]);
ReplacementFunction = null;
coindex.i--;
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
EndOfFrameProcesses[coindex.i] = null;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
}
}
private void RemoveUnused()
{
var waitTrigsEnum = _waitingTriggers.GetEnumerator();
while (waitTrigsEnum.MoveNext())
{
if (waitTrigsEnum.Current.Value.Count == 0)
{
_waitingTriggers.Remove(waitTrigsEnum.Current.Key);
waitTrigsEnum = _waitingTriggers.GetEnumerator();
continue;
}
if (_handleToIndex.ContainsKey(waitTrigsEnum.Current.Key) && CoindexIsNull(_handleToIndex[waitTrigsEnum.Current.Key]))
{
CloseWaitingProcess(waitTrigsEnum.Current.Key);
waitTrigsEnum = _waitingTriggers.GetEnumerator();
}
}
ProcessIndex outer, inner;
outer.seg = inner.seg = Segment.Update;
for (outer.i = inner.i = 0; outer.i < _nextUpdateProcessSlot; outer.i++)
{
if (UpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
UpdateProcesses[inner.i] = UpdateProcesses[outer.i];
UpdatePaused[inner.i] = UpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextUpdateProcessSlot; outer.i++)
{
UpdateProcesses[outer.i] = null;
UpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
UpdateCoroutines = _nextUpdateProcessSlot = inner.i;
outer.seg = inner.seg = Segment.FixedUpdate;
for (outer.i = inner.i = 0; outer.i < _nextFixedUpdateProcessSlot; outer.i++)
{
if (FixedUpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
FixedUpdateProcesses[inner.i] = FixedUpdateProcesses[outer.i];
FixedUpdatePaused[inner.i] = FixedUpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextFixedUpdateProcessSlot; outer.i++)
{
FixedUpdateProcesses[outer.i] = null;
FixedUpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
FixedUpdateCoroutines = _nextFixedUpdateProcessSlot = inner.i;
outer.seg = inner.seg = Segment.LateUpdate;
for (outer.i = inner.i = 0; outer.i < _nextLateUpdateProcessSlot; outer.i++)
{
if (LateUpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
LateUpdateProcesses[inner.i] = LateUpdateProcesses[outer.i];
LateUpdatePaused[inner.i] = LateUpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextLateUpdateProcessSlot; outer.i++)
{
LateUpdateProcesses[outer.i] = null;
LateUpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
LateUpdateCoroutines = _nextLateUpdateProcessSlot = inner.i;
outer.seg = inner.seg = Segment.SlowUpdate;
for (outer.i = inner.i = 0; outer.i < _nextSlowUpdateProcessSlot; outer.i++)
{
if (SlowUpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
SlowUpdateProcesses[inner.i] = SlowUpdateProcesses[outer.i];
SlowUpdatePaused[inner.i] = SlowUpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextSlowUpdateProcessSlot; outer.i++)
{
SlowUpdateProcesses[outer.i] = null;
SlowUpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
SlowUpdateCoroutines = _nextSlowUpdateProcessSlot = inner.i;
outer.seg = inner.seg = Segment.RealtimeUpdate;
for (outer.i = inner.i = 0; outer.i < _nextRealtimeUpdateProcessSlot; outer.i++)
{
if (RealtimeUpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
RealtimeUpdateProcesses[inner.i] = RealtimeUpdateProcesses[outer.i];
RealtimeUpdatePaused[inner.i] = RealtimeUpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextRealtimeUpdateProcessSlot; outer.i++)
{
RealtimeUpdateProcesses[outer.i] = null;
RealtimeUpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
RealtimeUpdateCoroutines = _nextRealtimeUpdateProcessSlot = inner.i;
outer.seg = inner.seg = Segment.EndOfFrame;
for (outer.i = inner.i = 0; outer.i < _nextEndOfFrameProcessSlot; outer.i++)
{
if (EndOfFrameProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
EndOfFrameProcesses[inner.i] = EndOfFrameProcesses[outer.i];
EndOfFramePaused[inner.i] = EndOfFramePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextEndOfFrameProcessSlot; outer.i++)
{
EndOfFrameProcesses[outer.i] = null;
EndOfFramePaused[outer.i] = false;
RemoveGraffiti(outer);
}
EndOfFrameCoroutines = _nextEndOfFrameProcessSlot = inner.i;
outer.seg = inner.seg = Segment.ManualTimeframe;
for (outer.i = inner.i = 0; outer.i < _nextManualTimeframeProcessSlot; outer.i++)
{
if (ManualTimeframeProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
ManualTimeframeProcesses[inner.i] = ManualTimeframeProcesses[outer.i];
ManualTimeframePaused[inner.i] = ManualTimeframePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextManualTimeframeProcessSlot; outer.i++)
{
ManualTimeframeProcesses[outer.i] = null;
ManualTimeframePaused[outer.i] = false;
RemoveGraffiti(outer);
}
ManualTimeframeCoroutines = _nextManualTimeframeProcessSlot = inner.i;
}
private void EditorRemoveUnused()
{
var waitTrigsEnum = _waitingTriggers.GetEnumerator();
while (waitTrigsEnum.MoveNext())
{
if (_handleToIndex.ContainsKey(waitTrigsEnum.Current.Key) && CoindexIsNull(_handleToIndex[waitTrigsEnum.Current.Key]))
{
CloseWaitingProcess(waitTrigsEnum.Current.Key);
waitTrigsEnum = _waitingTriggers.GetEnumerator();
}
}
ProcessIndex outer, inner;
outer.seg = inner.seg = Segment.EditorUpdate;
for (outer.i = inner.i = 0; outer.i < _nextEditorUpdateProcessSlot; outer.i++)
{
if (EditorUpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
EditorUpdateProcesses[inner.i] = EditorUpdateProcesses[outer.i];
EditorUpdatePaused[inner.i] = EditorUpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextEditorUpdateProcessSlot; outer.i++)
{
EditorUpdateProcesses[outer.i] = null;
EditorUpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
EditorUpdateCoroutines = _nextEditorUpdateProcessSlot = inner.i;
outer.seg = inner.seg = Segment.EditorSlowUpdate;
for (outer.i = inner.i = 0; outer.i < _nextEditorSlowUpdateProcessSlot; outer.i++)
{
if (EditorSlowUpdateProcesses[outer.i] != null)
{
if (outer.i != inner.i)
{
EditorSlowUpdateProcesses[inner.i] = EditorSlowUpdateProcesses[outer.i];
EditorUpdatePaused[inner.i] = EditorUpdatePaused[outer.i];
MoveGraffiti(outer, inner);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextEditorSlowUpdateProcessSlot; outer.i++)
{
EditorSlowUpdateProcesses[outer.i] = null;
EditorSlowUpdatePaused[outer.i] = false;
RemoveGraffiti(outer);
}
EditorSlowUpdateCoroutines = _nextEditorSlowUpdateProcessSlot = inner.i;
}
///
/// Retrieves the MEC manager that corresponds to the supplied instance id.
///
/// The instance ID.
/// The manager, or null if not found.
public static Timing GetInstance(byte ID)
{
return ActiveInstances.ContainsKey(ID) ? ActiveInstances[ID] : null;
}
///
/// Run a new coroutine in the Update segment.
///
/// The new coroutine's handle.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment.
///
/// The new coroutine's handle.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, string tag)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment.
///
/// The new coroutine's handle.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, int layer)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment.
///
/// The new coroutine's handle.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, int layer, string tag)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, Segment timing)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, timing, null, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, Segment timing, string tag)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, timing, null, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, Segment timing, int layer)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, timing, layer, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, Segment timing, int layer, string tag)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine on this Timing instance in the Update segment.
///
/// The new coroutine's handle.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance in the Update segment.
///
/// The new coroutine's handle.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, string tag)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance in the Update segment.
///
/// The new coroutine's handle.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, int layer)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance in the Update segment.
///
/// The new coroutine's handle.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, int layer, string tag)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, Segment timing)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, timing, null, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, Segment timing, string tag)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, timing, null, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, Segment timing, int layer)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, timing, layer, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine on this Timing instance.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, Segment timing, int layer, string tag)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, string tag, bool overwrite = false)
{
if (_instance == null || coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(tag);
}
else if (_instance._taggedProcesses.ContainsKey(tag))
{
var indexEnum = _instance._taggedProcesses[tag].GetEnumerator();
if (indexEnum.MoveNext())
return _instance._indexToHandle[indexEnum.Current];
}
return _instance.RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(_instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// A layer to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, int layer, bool overwrite = false)
{
if (_instance == null || coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer);
}
else if (_instance._layeredProcesses.ContainsKey(layer))
{
var indexEnum = _instance._layeredProcesses[layer].GetEnumerator();
if (indexEnum.MoveNext())
return _instance._indexToHandle[indexEnum.Current];
}
return _instance.RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(_instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// A layer to attach to the coroutine, and to check for existing instances.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, int layer, string tag, bool overwrite = false)
{
if (_instance == null || coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer, tag);
return _instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instance._instanceID), true);
}
if (!_instance._taggedProcesses.ContainsKey(tag) || !_instance._layeredProcesses.ContainsKey(layer))
return _instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instance._instanceID), true);
var matchesEnum = _instance._taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_instance._processLayers.ContainsKey(matchesEnum.Current) && _instance._processLayers[matchesEnum.Current] == layer)
return _instance._indexToHandle[matchesEnum.Current];
return _instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instance._instanceID), true);
}
///
/// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// A layer to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment timing, int layer, bool overwrite = false)
{
if (_instance == null || coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer);
}
else if (_instance._layeredProcesses.ContainsKey(layer))
{
var indexEnum = _instance._layeredProcesses[layer].GetEnumerator();
if (indexEnum.MoveNext())
return _instance._indexToHandle[indexEnum.Current];
}
return _instance.RunCoroutineInternal(coroutine, timing, layer, null, new CoroutineHandle(_instance._instanceID), true);
}
///
/// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment timing, string tag, bool overwrite = false)
{
if (_instance == null || coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(tag);
}
else if (_instance._taggedProcesses.ContainsKey(tag))
{
var indexEnum = _instance._taggedProcesses[tag].GetEnumerator();
if (indexEnum.MoveNext())
return _instance._indexToHandle[indexEnum.Current];
}
return _instance.RunCoroutineInternal(coroutine, timing, null, tag, new CoroutineHandle(_instance._instanceID), true);
}
///
/// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// A layer to attach to the coroutine, and to check for existing instances.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment timing, int layer, string tag, bool overwrite = false)
{
if (_instance == null || coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer, tag);
return _instance.RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instance._instanceID), true);
}
if (!_instance._taggedProcesses.ContainsKey(tag) || !_instance._layeredProcesses.ContainsKey(layer))
return _instance.RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instance._instanceID), true);
var matchesEnum = _instance._taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_instance._processLayers.ContainsKey(matchesEnum.Current) && _instance._processLayers[matchesEnum.Current] == layer)
return _instance._indexToHandle[matchesEnum.Current];
return _instance.RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// A layer to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, int layer, bool overwrite = false)
{
if (coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer);
}
else if (_layeredProcesses.ContainsKey(layer))
{
var indexEnum = _layeredProcesses[layer].GetEnumerator();
if (indexEnum.MoveNext())
return _indexToHandle[indexEnum.Current];
}
return RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, string tag, bool overwrite = false)
{
if (coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(tag);
}
else if (_taggedProcesses.ContainsKey(tag))
{
var indexEnum = _taggedProcesses[tag].GetEnumerator();
if (indexEnum.MoveNext())
return _indexToHandle[indexEnum.Current];
}
return RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// A layer to attach to the coroutine, and to check for existing instances.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, int layer, string tag, bool overwrite = false)
{
if (coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer, tag);
return RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), true);
}
if (!_taggedProcesses.ContainsKey(tag) || !_layeredProcesses.ContainsKey(layer))
return RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), true);
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer)
return _indexToHandle[matchesEnum.Current];
return RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// A layer to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment timing, int layer, bool overwrite = false)
{
if (coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer);
}
else if (_layeredProcesses.ContainsKey(layer))
{
var indexEnum = _layeredProcesses[layer].GetEnumerator();
if (indexEnum.MoveNext())
return _indexToHandle[indexEnum.Current];
}
return RunCoroutineInternal(coroutine, timing, layer, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment timing, string tag, bool overwrite = false)
{
if (coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(tag);
}
else if (_taggedProcesses.ContainsKey(tag))
{
var indexEnum = _taggedProcesses[tag].GetEnumerator();
if (indexEnum.MoveNext())
return _indexToHandle[indexEnum.Current];
}
return RunCoroutineInternal(coroutine, timing, null, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// A layer to attach to the coroutine, and to check for existing instances.
/// A tag to attach to the coroutine, and to check for existing instances.
/// True will kill any pre-existing coroutines. False will only start this coroutine if none exist.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment timing, int layer, string tag, bool overwrite = false)
{
if (coroutine == null)
return new CoroutineHandle();
if (overwrite)
{
KillCoroutines(layer, tag);
return RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instanceID), true);
}
if (!_taggedProcesses.ContainsKey(tag) || !_layeredProcesses.ContainsKey(layer))
return RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instanceID), true);
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer)
return _indexToHandle[matchesEnum.Current];
return RunCoroutineInternal(coroutine, timing, layer, tag, new CoroutineHandle(_instanceID), true);
}
private CoroutineHandle RunCoroutineInternal(IEnumerator coroutine, Segment timing, int? layer, string tag, CoroutineHandle handle, bool prewarm)
{
ProcessIndex slot = new ProcessIndex { seg = timing };
if (_handleToIndex.ContainsKey(handle))
{
_indexToHandle.Remove(_handleToIndex[handle]);
_handleToIndex.Remove(handle);
}
switch (timing)
{
case Segment.Update:
if (_nextUpdateProcessSlot >= UpdateProcesses.Length)
{
IEnumerator[] oldProcArray = UpdateProcesses;
bool[] oldPausedArray = UpdatePaused;
UpdateProcesses = new IEnumerator[UpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
UpdatePaused = new bool[UpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
UpdateProcesses[i] = oldProcArray[i];
UpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextUpdateProcessSlot++;
UpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
if (!_runningUpdate && prewarm)
{
try
{
_runningUpdate = true;
SetTimeValues(slot.seg);
if (UpdateProcesses[slot.i] != null && !UpdateProcesses[slot.i].MoveNext())
{
UpdateProcesses[slot.i] = null;
}
else if (UpdateProcesses[slot.i] != null && float.IsNaN(UpdateProcesses[slot.i].Current))
{
if (ReplacementFunction == null)
{
UpdateProcesses[slot.i] = null;
}
else
{
UpdateProcesses[slot.i] = ReplacementFunction(UpdateProcesses[slot.i], this, _indexToHandle[slot]);
ReplacementFunction = null;
if (UpdateProcesses[slot.i] != null)
UpdateProcesses[slot.i].MoveNext();
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
UpdateProcesses[slot.i] = null;
}
finally
{
_runningUpdate = false;
}
}
return handle;
case Segment.FixedUpdate:
if (_nextFixedUpdateProcessSlot >= FixedUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = FixedUpdateProcesses;
bool[] oldPausedArray = FixedUpdatePaused;
FixedUpdateProcesses = new IEnumerator[FixedUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
FixedUpdatePaused = new bool[FixedUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
FixedUpdateProcesses[i] = oldProcArray[i];
FixedUpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextFixedUpdateProcessSlot++;
FixedUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
if (!_runningFixedUpdate && prewarm)
{
try
{
_runningFixedUpdate = true;
SetTimeValues(slot.seg);
if (FixedUpdateProcesses[slot.i] != null && !FixedUpdateProcesses[slot.i].MoveNext())
{
FixedUpdateProcesses[slot.i] = null;
}
else if (FixedUpdateProcesses[slot.i] != null && float.IsNaN(FixedUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction == null)
{
FixedUpdateProcesses[slot.i] = null;
}
else
{
FixedUpdateProcesses[slot.i] = ReplacementFunction(FixedUpdateProcesses[slot.i], this, _indexToHandle[slot]);
ReplacementFunction = null;
if (FixedUpdateProcesses[slot.i] != null)
FixedUpdateProcesses[slot.i].MoveNext();
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
FixedUpdateProcesses[slot.i] = null;
}
finally
{
_runningFixedUpdate = false;
}
}
return handle;
case Segment.LateUpdate:
if (_nextLateUpdateProcessSlot >= LateUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = LateUpdateProcesses;
bool[] oldPausedArray = LateUpdatePaused;
LateUpdateProcesses = new IEnumerator[LateUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
LateUpdatePaused = new bool[LateUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
LateUpdateProcesses[i] = oldProcArray[i];
LateUpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextLateUpdateProcessSlot++;
LateUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
if (!_runningLateUpdate && prewarm)
{
try
{
_runningLateUpdate = true;
SetTimeValues(slot.seg);
if (LateUpdateProcesses[slot.i] != null && !LateUpdateProcesses[slot.i].MoveNext())
{
LateUpdateProcesses[slot.i] = null;
}
else if (LateUpdateProcesses[slot.i] != null && float.IsNaN(LateUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction == null)
{
LateUpdateProcesses[slot.i] = null;
}
else
{
LateUpdateProcesses[slot.i] = ReplacementFunction(LateUpdateProcesses[slot.i],
this, _indexToHandle[slot]);
ReplacementFunction = null;
if (LateUpdateProcesses[slot.i] != null)
LateUpdateProcesses[slot.i].MoveNext();
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
LateUpdateProcesses[slot.i] = null;
}
finally
{
_runningLateUpdate = false;
}
}
return handle;
case Segment.SlowUpdate:
if (_nextSlowUpdateProcessSlot >= SlowUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = SlowUpdateProcesses;
bool[] oldPausedArray = SlowUpdatePaused;
SlowUpdateProcesses = new IEnumerator[SlowUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
SlowUpdatePaused = new bool[SlowUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
SlowUpdateProcesses[i] = oldProcArray[i];
SlowUpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextSlowUpdateProcessSlot++;
SlowUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
return handle;
case Segment.RealtimeUpdate:
if (_nextRealtimeUpdateProcessSlot >= RealtimeUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = RealtimeUpdateProcesses;
bool[] oldPausedArray = RealtimeUpdatePaused;
RealtimeUpdateProcesses = new IEnumerator[RealtimeUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
RealtimeUpdatePaused = new bool[RealtimeUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
RealtimeUpdateProcesses[i] = oldProcArray[i];
RealtimeUpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextRealtimeUpdateProcessSlot++;
RealtimeUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
if (!_runningRealtimeUpdate && prewarm)
{
try
{
_runningRealtimeUpdate = true;
SetTimeValues(slot.seg);
if (RealtimeUpdateProcesses[slot.i] != null && !RealtimeUpdateProcesses[slot.i].MoveNext())
{
RealtimeUpdateProcesses[slot.i] = null;
}
else if (RealtimeUpdateProcesses[slot.i] != null && float.IsNaN(RealtimeUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction == null)
{
RealtimeUpdateProcesses[slot.i] = null;
}
else
{
RealtimeUpdateProcesses[slot.i] = ReplacementFunction(RealtimeUpdateProcesses[slot.i],
this, _indexToHandle[slot]);
ReplacementFunction = null;
if (RealtimeUpdateProcesses[slot.i] != null)
RealtimeUpdateProcesses[slot.i].MoveNext();
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
RealtimeUpdateProcesses[slot.i] = null;
}
finally
{
_runningRealtimeUpdate = false;
}
}
return handle;
case Segment.EditorUpdate:
if (!OnEditorStart())
return new CoroutineHandle();
if (_nextEditorUpdateProcessSlot >= EditorUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = EditorUpdateProcesses;
bool[] oldPausedArray = EditorUpdatePaused;
EditorUpdateProcesses = new IEnumerator[EditorUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
EditorUpdatePaused = new bool[EditorUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
EditorUpdateProcesses[i] = oldProcArray[i];
EditorUpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextEditorUpdateProcessSlot++;
EditorUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
if (!_runningEditorUpdate && prewarm)
{
try
{
_runningEditorUpdate = true;
SetTimeValues(slot.seg);
if (EditorUpdateProcesses[slot.i] != null && !EditorUpdateProcesses[slot.i].MoveNext())
{
EditorUpdateProcesses[slot.i] = null;
}
else if (EditorUpdateProcesses[slot.i] != null && float.IsNaN(EditorUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction == null)
{
EditorUpdateProcesses[slot.i] = null;
}
else
{
EditorUpdateProcesses[slot.i] = ReplacementFunction(EditorUpdateProcesses[slot.i],
this, _indexToHandle[slot]);
ReplacementFunction = null;
if (EditorUpdateProcesses[slot.i] != null)
EditorUpdateProcesses[slot.i].MoveNext();
}
}
}
catch (System.Exception ex)
{
if (OnError == null)
_exceptions.Enqueue(ex);
else
OnError(ex);
EditorUpdateProcesses[slot.i] = null;
}
finally
{
_runningEditorUpdate = false;
}
}
return handle;
case Segment.EditorSlowUpdate:
if (!OnEditorStart())
return new CoroutineHandle();
if (_nextEditorSlowUpdateProcessSlot >= EditorSlowUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = EditorSlowUpdateProcesses;
bool[] oldPausedArray = EditorSlowUpdatePaused;
EditorSlowUpdateProcesses = new IEnumerator[EditorSlowUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
EditorSlowUpdatePaused = new bool[EditorSlowUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
EditorSlowUpdateProcesses[i] = oldProcArray[i];
EditorSlowUpdatePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextEditorSlowUpdateProcessSlot++;
EditorSlowUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
return handle;
case Segment.EndOfFrame:
if (_nextEndOfFrameProcessSlot >= EndOfFrameProcesses.Length)
{
IEnumerator[] oldProcArray = EndOfFrameProcesses;
bool[] oldPausedArray = EndOfFramePaused;
EndOfFrameProcesses = new IEnumerator[EndOfFrameProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
EndOfFramePaused = new bool[EndOfFrameProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
EndOfFrameProcesses[i] = oldProcArray[i];
EndOfFramePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextEndOfFrameProcessSlot++;
EndOfFrameProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
RunCoroutineSingletonOnInstance(_EOFPumpWatcher(), "MEC_EOFPumpWatcher");
return handle;
case Segment.ManualTimeframe:
if (_nextManualTimeframeProcessSlot >= ManualTimeframeProcesses.Length)
{
IEnumerator[] oldProcArray = ManualTimeframeProcesses;
bool[] oldPausedArray = ManualTimeframePaused;
ManualTimeframeProcesses = new IEnumerator[ManualTimeframeProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
ManualTimeframePaused = new bool[ManualTimeframeProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
ManualTimeframeProcesses[i] = oldProcArray[i];
ManualTimeframePaused[i] = oldPausedArray[i];
}
}
slot.i = _nextManualTimeframeProcessSlot++;
ManualTimeframeProcesses[slot.i] = coroutine;
if (null != tag)
AddTag(tag, slot);
if (layer.HasValue)
AddLayer((int)layer, slot);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
return handle;
default:
return new CoroutineHandle();
}
}
///
/// This will kill all coroutines running on the main MEC instance and reset the context.
///
/// The number of coroutines that were killed.
public static int KillCoroutines()
{
return _instance == null ? 0 : _instance.KillCoroutinesOnInstance();
}
///
/// This will kill all coroutines running on the current MEC instance and reset the context.
///
/// The number of coroutines that were killed.
public int KillCoroutinesOnInstance()
{
int retVal = _nextUpdateProcessSlot + _nextLateUpdateProcessSlot + _nextFixedUpdateProcessSlot + _nextSlowUpdateProcessSlot +
_nextRealtimeUpdateProcessSlot + _nextEditorUpdateProcessSlot + _nextEditorSlowUpdateProcessSlot +
_nextEndOfFrameProcessSlot + _nextManualTimeframeProcessSlot;
UpdateProcesses = new IEnumerator[InitialBufferSizeLarge];
UpdatePaused = new bool[InitialBufferSizeLarge];
UpdateCoroutines = 0;
_nextUpdateProcessSlot = 0;
LateUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
LateUpdatePaused = new bool[InitialBufferSizeSmall];
LateUpdateCoroutines = 0;
_nextLateUpdateProcessSlot = 0;
FixedUpdateProcesses = new IEnumerator[InitialBufferSizeMedium];
FixedUpdatePaused = new bool[InitialBufferSizeMedium];
FixedUpdateCoroutines = 0;
_nextFixedUpdateProcessSlot = 0;
SlowUpdateProcesses = new IEnumerator[InitialBufferSizeMedium];
SlowUpdatePaused = new bool[InitialBufferSizeMedium];
SlowUpdateCoroutines = 0;
_nextSlowUpdateProcessSlot = 0;
RealtimeUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
RealtimeUpdatePaused = new bool[InitialBufferSizeSmall];
RealtimeUpdateCoroutines = 0;
_nextRealtimeUpdateProcessSlot = 0;
EditorUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
EditorUpdatePaused = new bool[InitialBufferSizeSmall];
EditorUpdateCoroutines = 0;
_nextEditorUpdateProcessSlot = 0;
EditorSlowUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
EditorSlowUpdatePaused = new bool[InitialBufferSizeSmall];
EditorSlowUpdateCoroutines = 0;
_nextEditorSlowUpdateProcessSlot = 0;
EndOfFrameProcesses = new IEnumerator[InitialBufferSizeSmall];
EndOfFramePaused = new bool[InitialBufferSizeSmall];
EndOfFrameCoroutines = 0;
_nextEndOfFrameProcessSlot = 0;
ManualTimeframeProcesses = new IEnumerator[InitialBufferSizeSmall];
ManualTimeframePaused = new bool[InitialBufferSizeSmall];
ManualTimeframeCoroutines = 0;
_nextManualTimeframeProcessSlot = 0;
_processTags.Clear();
_taggedProcesses.Clear();
_processLayers.Clear();
_layeredProcesses.Clear();
_handleToIndex.Clear();
_indexToHandle.Clear();
_waitingTriggers.Clear();
_expansions = (ushort)((_expansions / 2) + 1);
ResetTimeCountOnInstance();
#if UNITY_EDITOR
EditorApplication.update -= OnEditorUpdate;
#endif
return retVal;
}
///
/// Kills all coroutines that have the given tag.
///
/// All coroutines with this tag will be killed.
/// The number of coroutines that were found and killed.
public static int KillCoroutines(string tag)
{
return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(tag);
}
///
/// Kills all coroutines that have the given tag.
///
/// All coroutines with this tag will be killed.
/// The number of coroutines that were found and killed.
public int KillCoroutinesOnInstance(string tag)
{
if (tag == null) return 0;
int numberFound = 0;
while (_taggedProcesses.ContainsKey(tag))
{
var matchEnum = _taggedProcesses[tag].GetEnumerator();
matchEnum.MoveNext();
if (CoindexKill(matchEnum.Current))
{
if (_waitingTriggers.ContainsKey(_indexToHandle[matchEnum.Current]))
CloseWaitingProcess(_indexToHandle[matchEnum.Current]);
numberFound++;
}
RemoveGraffiti(matchEnum.Current);
}
return numberFound;
}
///
/// Kills all coroutines on the given layer.
///
/// All coroutines on this layer will be killed.
/// The number of coroutines that were found and killed.
public static int KillCoroutines(int layer)
{
return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(layer);
}
///
/// Kills all coroutines on the given layer.
///
/// All coroutines on this layer will be killed.
/// The number of coroutines that were found and killed.
public int KillCoroutinesOnInstance(int layer)
{
int numberFound = 0;
while (_layeredProcesses.ContainsKey(layer))
{
var matchEnum = _layeredProcesses[layer].GetEnumerator();
matchEnum.MoveNext();
if (CoindexKill(matchEnum.Current))
{
if (_waitingTriggers.ContainsKey(_indexToHandle[matchEnum.Current]))
CloseWaitingProcess(_indexToHandle[matchEnum.Current]);
numberFound++;
}
RemoveGraffiti(matchEnum.Current);
}
return numberFound;
}
///
/// Kills all coroutines with the given tag on the given layer.
///
/// All coroutines on this layer with the given tag will be killed.
/// All coroutines with this tag on the given layer will be killed.
/// The number of coroutines that were found and killed.
public static int KillCoroutines(int layer, string tag)
{
return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(layer, tag);
}
///
/// Kills all coroutines with the given tag on the given layer.
///
/// All coroutines on this layer with the given tag will be killed.
/// All coroutines with this tag on the given layer will be killed.
/// The number of coroutines that were found and killed.
public int KillCoroutinesOnInstance(int layer, string tag)
{
if (tag == null)
return KillCoroutinesOnInstance(layer);
if (!_layeredProcesses.ContainsKey(layer) || !_taggedProcesses.ContainsKey(tag))
return 0;
int count = 0;
var indexesEnum = _taggedProcesses[tag].GetEnumerator();
while (indexesEnum.MoveNext())
{
if (CoindexIsNull(indexesEnum.Current) || !_layeredProcesses[layer].Contains(indexesEnum.Current) || !CoindexKill(indexesEnum.Current))
continue;
if (_waitingTriggers.ContainsKey(_indexToHandle[indexesEnum.Current]))
CloseWaitingProcess(_indexToHandle[indexesEnum.Current]);
count++;
RemoveGraffiti(indexesEnum.Current);
if (!_taggedProcesses.ContainsKey(tag) || !_layeredProcesses.ContainsKey(layer))
break;
indexesEnum = _taggedProcesses[tag].GetEnumerator();
}
return count;
}
///
/// Kills the instance of the coroutine handle if it exists.
///
/// The handle of the coroutine to kill.
/// The number of coroutines that were found and killed (0 or 1).
public static int KillCoroutines(CoroutineHandle handle)
{
return ActiveInstances.ContainsKey(handle.Key) ? GetInstance(handle.Key).KillCoroutinesOnInstance(handle) : 0;
}
///
/// Kills the instance of the coroutine handle on this Timing instance if it exists.
///
/// The handle of the coroutine to kill.
/// The number of coroutines that were found and killed (0 or 1).
public int KillCoroutinesOnInstance(CoroutineHandle handle)
{
bool foundOne = false;
if (_handleToIndex.ContainsKey(handle))
{
if (_waitingTriggers.ContainsKey(handle))
CloseWaitingProcess(handle);
foundOne = CoindexExtract(_handleToIndex[handle]) != null;
RemoveGraffiti(_handleToIndex[handle]);
}
return foundOne ? 1 : 0;
}
///
/// Use "yield return Timing.WaitForSeconds(time);" to wait for the specified number of seconds.
///
/// Number of seconds to wait.
public static float WaitForSeconds(float waitTime)
{
if (float.IsNaN(waitTime)) waitTime = 0f;
return LocalTime + waitTime;
}
///
/// Use "yield return timingInstance.WaitForSecondsOnInstance(time);" to wait for the specified number of seconds.
///
/// Number of seconds to wait.
public float WaitForSecondsOnInstance(float waitTime)
{
if (float.IsNaN(waitTime)) waitTime = 0f;
return (float)localTime + waitTime;
}
private void UpdateTimeValues(Segment segment)
{
switch (segment)
{
case Segment.Update:
deltaTime = Time.deltaTime;
_lastUpdateTime += deltaTime;
localTime = _lastUpdateTime;
return;
case Segment.LateUpdate:
deltaTime = Time.deltaTime;
_lastLateUpdateTime += deltaTime;
localTime = _lastLateUpdateTime;
return;
case Segment.FixedUpdate:
deltaTime = Time.deltaTime;
_lastFixedUpdateTime += deltaTime;
localTime = _lastFixedUpdateTime;
return;
case Segment.SlowUpdate:
if (_lastSlowUpdateTime == 0d)
deltaTime = TimeBetweenSlowUpdateCalls;
else
deltaTime = ThreadSafeElapsedTime.GetElapsedSecondsSinceStartUp() - (float)_lastSlowUpdateTime;
localTime = _lastSlowUpdateTime = ThreadSafeElapsedTime.GetElapsedSecondsSinceStartUp();
return;
case Segment.RealtimeUpdate:
deltaTime = Time.unscaledDeltaTime;
_lastRealtimeUpdateTime += deltaTime;
localTime = _lastRealtimeUpdateTime;
return;
#if UNITY_EDITOR
case Segment.EditorUpdate:
deltaTime = (float)(EditorApplication.timeSinceStartup - _lastEditorUpdateTime);
if (deltaTime > Time.maximumDeltaTime)
deltaTime = Time.maximumDeltaTime;
localTime = _lastEditorUpdateTime = EditorApplication.timeSinceStartup;
return;
case Segment.EditorSlowUpdate:
deltaTime = (float)(EditorApplication.timeSinceStartup - _lastEditorSlowUpdateTime);
localTime = _lastEditorSlowUpdateTime = EditorApplication.timeSinceStartup;
return;
#endif
case Segment.EndOfFrame:
deltaTime = Time.deltaTime;
localTime = _lastUpdateTime;
return;
case Segment.ManualTimeframe:
localTime = SetManualTimeframeTime == null ? Time.time : SetManualTimeframeTime(_lastManualTimeframeTime);
deltaTime = (float)(localTime - _lastManualTimeframeTime);
if (deltaTime > Time.maximumDeltaTime)
deltaTime = Time.maximumDeltaTime;
_lastManualTimeframeTime = localTime;
return;
}
}
private void SetTimeValues(Segment segment)
{
switch (segment)
{
case Segment.Update:
deltaTime = Time.deltaTime;
localTime = _lastUpdateTime;
return;
case Segment.LateUpdate:
deltaTime = Time.deltaTime;
localTime = _lastLateUpdateTime;
return;
case Segment.FixedUpdate:
deltaTime = Time.deltaTime;
localTime = _lastFixedUpdateTime;
return;
case Segment.SlowUpdate:
deltaTime = ThreadSafeElapsedTime.GetElapsedSecondsSinceStartUp() - (float)_lastSlowUpdateTime;
localTime = _lastSlowUpdateTime;
return;
case Segment.RealtimeUpdate:
deltaTime = Time.unscaledDeltaTime;
localTime = _lastRealtimeUpdateTime;
return;
#if UNITY_EDITOR
case Segment.EditorUpdate:
deltaTime = (float)(EditorApplication.timeSinceStartup - _lastEditorUpdateTime);
if (deltaTime > Time.maximumDeltaTime)
deltaTime = Time.maximumDeltaTime;
localTime = _lastEditorUpdateTime;
return;
case Segment.EditorSlowUpdate:
deltaTime = (float)(EditorApplication.timeSinceStartup - _lastEditorSlowUpdateTime);
localTime = _lastEditorSlowUpdateTime;
return;
#endif
case Segment.EndOfFrame:
deltaTime = Time.deltaTime;
localTime = _lastUpdateTime;
return;
case Segment.ManualTimeframe:
deltaTime = Time.deltaTime;
localTime = _lastManualTimeframeTime;
return;
}
}
private double GetSegmentTime(Segment segment)
{
switch (segment)
{
case Segment.Update:
return _lastUpdateTime;
case Segment.LateUpdate:
return _lastLateUpdateTime;
case Segment.FixedUpdate:
return _lastFixedUpdateTime;
case Segment.SlowUpdate:
return _lastSlowUpdateTime;
case Segment.RealtimeUpdate:
return _lastRealtimeUpdateTime;
case Segment.EditorUpdate:
return _lastEditorUpdateTime;
case Segment.EditorSlowUpdate:
return _lastEditorSlowUpdateTime;
case Segment.EndOfFrame:
return _lastUpdateTime;
case Segment.ManualTimeframe:
return _lastManualTimeframeTime;
default:
return 0d;
}
}
///
/// Resets the value of LocalTime to zero (only for the Update, LateUpdate, FixedUpdate, and RealtimeUpdate loops).
///
public void ResetTimeCountOnInstance()
{
localTime = 0d;
_lastUpdateTime = 0d;
_lastLateUpdateTime = 0d;
_lastFixedUpdateTime = 0d;
_lastRealtimeUpdateTime = 0d;
_EOFPumpRan = false;
}
///
/// This will pause all coroutines running on the current MEC instance until ResumeCoroutines is called.
///
/// The number of coroutines that were paused.
public static int PauseCoroutines()
{
return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance();
}
///
/// This will pause all coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// The number of coroutines that were paused.
public int PauseCoroutinesOnInstance()
{
int count = 0;
int i;
for (i = 0; i < _nextUpdateProcessSlot; i++)
{
if (!UpdatePaused[i] && UpdateProcesses[i] != null)
{
UpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextLateUpdateProcessSlot; i++)
{
if (!LateUpdatePaused[i] && LateUpdateProcesses[i] != null)
{
LateUpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextFixedUpdateProcessSlot; i++)
{
if (!FixedUpdatePaused[i] && FixedUpdateProcesses[i] != null)
{
FixedUpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextSlowUpdateProcessSlot; i++)
{
if (!SlowUpdatePaused[i] && SlowUpdateProcesses[i] != null)
{
SlowUpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextRealtimeUpdateProcessSlot; i++)
{
if (!RealtimeUpdatePaused[i] && RealtimeUpdateProcesses[i] != null)
{
RealtimeUpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextEditorUpdateProcessSlot; i++)
{
if (!EditorUpdatePaused[i] && EditorUpdateProcesses[i] != null)
{
EditorUpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextEditorSlowUpdateProcessSlot; i++)
{
if (!EditorSlowUpdatePaused[i] && EditorSlowUpdateProcesses[i] != null)
{
EditorSlowUpdatePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextEndOfFrameProcessSlot; i++)
{
if (!EndOfFramePaused[i] && EndOfFrameProcesses[i] != null)
{
EndOfFramePaused[i] = true;
count++;
}
}
for (i = 0; i < _nextManualTimeframeProcessSlot; i++)
{
if (!ManualTimeframePaused[i] && ManualTimeframeProcesses[i] != null)
{
ManualTimeframePaused[i] = true;
count++;
}
}
return count;
}
///
/// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called.
///
/// Any coroutines with a matching tag will be paused.
/// The number of coroutines that were paused.
public static int PauseCoroutines(string tag)
{
return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(tag);
}
///
/// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// Any coroutines with a matching tag will be paused.
/// The number of coroutines that were paused.
public int PauseCoroutinesOnInstance(string tag)
{
if (tag == null || !_taggedProcesses.ContainsKey(tag))
return 0;
int count = 0;
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (!CoindexIsNull(matchesEnum.Current) && !CoindexSetPause(matchesEnum.Current))
count++;
return count;
}
///
/// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called.
///
/// Any coroutines on the matching layer will be paused.
/// The number of coroutines that were paused.
public static int PauseCoroutines(int layer)
{
return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(layer);
}
///
/// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// Any coroutines on the matching layer will be paused.
/// The number of coroutines that were paused.
public int PauseCoroutinesOnInstance(int layer)
{
if (!_layeredProcesses.ContainsKey(layer))
return 0;
int count = 0;
var matchesEnum = _layeredProcesses[layer].GetEnumerator();
while (matchesEnum.MoveNext())
if (!CoindexIsNull(matchesEnum.Current) && !CoindexSetPause(matchesEnum.Current))
count++;
return count;
}
///
/// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called.
///
/// Any coroutines on the matching layer will be paused.
/// Any coroutines with a matching tag will be paused.
/// The number of coroutines that were paused.
public static int PauseCoroutines(int layer, string tag)
{
return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(layer, tag);
}
///
/// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// Any coroutines on the matching layer will be paused.
/// Any coroutines with a matching tag will be paused.
/// The number of coroutines that were paused.
public int PauseCoroutinesOnInstance(int layer, string tag)
{
if (tag == null)
return PauseCoroutinesOnInstance(layer);
if (!_taggedProcesses.ContainsKey(tag) || !_layeredProcesses.ContainsKey(layer))
return 0;
int count = 0;
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer
&& !CoindexIsNull(matchesEnum.Current) && !CoindexSetPause(matchesEnum.Current))
count++;
return count;
}
///
/// This will pause any matching coroutines until ResumeCoroutines is called.
///
/// The handle of the coroutine to pause.
/// The number of coroutines that were paused (0 or 1).
public static int PauseCoroutines(CoroutineHandle handle)
{
return ActiveInstances.ContainsKey(handle.Key) ? GetInstance(handle.Key).PauseCoroutinesOnInstance(handle) : 0;
}
///
/// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// The handle of the coroutine to pause.
/// The number of coroutines that were paused (0 or 1).
public int PauseCoroutinesOnInstance(CoroutineHandle handle)
{
return _handleToIndex.ContainsKey(handle) && !CoindexIsNull(_handleToIndex[handle]) && !CoindexSetPause(_handleToIndex[handle]) ? 1 : 0;
}
///
/// This resumes all coroutines on the current MEC instance if they are currently paused, otherwise it has
/// no effect.
///
/// The number of coroutines that were resumed.
public static int ResumeCoroutines()
{
return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance();
}
///
/// This resumes all coroutines on this MEC instance if they are currently paused, otherwise it has no effect.
///
/// The number of coroutines that were resumed.
public int ResumeCoroutinesOnInstance()
{
int count = 0;
int i;
for (i = 0; i < _nextUpdateProcessSlot; i++)
{
if (UpdatePaused[i] && UpdateProcesses[i] != null)
{
UpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextLateUpdateProcessSlot; i++)
{
if (LateUpdatePaused[i] && LateUpdateProcesses[i] != null)
{
LateUpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextFixedUpdateProcessSlot; i++)
{
if (FixedUpdatePaused[i] && FixedUpdateProcesses[i] != null)
{
FixedUpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextSlowUpdateProcessSlot; i++)
{
if (SlowUpdatePaused[i] && SlowUpdateProcesses[i] != null)
{
SlowUpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextRealtimeUpdateProcessSlot; i++)
{
if (RealtimeUpdatePaused[i] && RealtimeUpdateProcesses[i] != null)
{
RealtimeUpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextEditorUpdateProcessSlot; i++)
{
if (EditorUpdatePaused[i] && EditorUpdateProcesses[i] != null)
{
EditorUpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextEditorSlowUpdateProcessSlot; i++)
{
if (EditorSlowUpdatePaused[i] && EditorSlowUpdateProcesses[i] != null)
{
EditorSlowUpdatePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextEndOfFrameProcessSlot; i++)
{
if (EndOfFramePaused[i] && EndOfFrameProcesses[i] != null)
{
EndOfFramePaused[i] = false;
count++;
}
}
for (i = 0; i < _nextManualTimeframeProcessSlot; i++)
{
if (ManualTimeframePaused[i] && ManualTimeframeProcesses[i] != null)
{
ManualTimeframePaused[i] = false;
count++;
}
}
var waitingEnum = _waitingTriggers.GetEnumerator();
while (waitingEnum.MoveNext())
{
int listCount = 0;
var pausedList = waitingEnum.Current.Value.GetEnumerator();
while (pausedList.MoveNext())
{
if (_handleToIndex.ContainsKey(pausedList.Current.Handle) && !CoindexIsNull(_handleToIndex[pausedList.Current.Handle]))
{
CoindexSetPause(_handleToIndex[pausedList.Current.Handle]);
listCount++;
}
else
{
waitingEnum.Current.Value.Remove(pausedList.Current);
listCount = 0;
pausedList = waitingEnum.Current.Value.GetEnumerator();
}
}
count -= listCount;
}
return count;
}
///
/// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has no effect.
///
/// Any coroutines previously paused with a matching tag will be resumend.
/// The number of coroutines that were resumed.
public static int ResumeCoroutines(string tag)
{
return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(tag);
}
///
/// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect.
///
/// Any coroutines previously paused with a matching tag will be resumend.
/// The number of coroutines that were resumed.
public int ResumeCoroutinesOnInstance(string tag)
{
if (tag == null || !_taggedProcesses.ContainsKey(tag))
return 0;
int count = 0;
var indexesEnum = _taggedProcesses[tag].GetEnumerator();
while (indexesEnum.MoveNext())
if (!CoindexIsNull(indexesEnum.Current) && CoindexSetPause(indexesEnum.Current, false))
count++;
var waitingEnum = _waitingTriggers.GetEnumerator();
while (waitingEnum.MoveNext())
{
var pausedList = waitingEnum.Current.Value.GetEnumerator();
while (pausedList.MoveNext())
{
if (_handleToIndex.ContainsKey(pausedList.Current.Handle) && !CoindexIsNull(_handleToIndex[pausedList.Current.Handle])
&& !CoindexSetPause(_handleToIndex[pausedList.Current.Handle]))
count--;
}
}
return count;
}
///
/// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has
/// no effect.
///
/// Any coroutines previously paused on the matching layer will be resumend.
/// The number of coroutines that were resumed.
public static int ResumeCoroutines(int layer)
{
return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(layer);
}
///
/// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect.
///
/// Any coroutines previously paused on the matching layer will be resumend.
/// The number of coroutines that were resumed.
public int ResumeCoroutinesOnInstance(int layer)
{
if (!_layeredProcesses.ContainsKey(layer))
return 0;
int count = 0;
var indexesEnum = _layeredProcesses[layer].GetEnumerator();
while (indexesEnum.MoveNext())
if (!CoindexIsNull(indexesEnum.Current) && CoindexSetPause(indexesEnum.Current, false))
count++;
var waitingEnum = _waitingTriggers.GetEnumerator();
while (waitingEnum.MoveNext())
{
var pausedList = waitingEnum.Current.Value.GetEnumerator();
while (pausedList.MoveNext())
{
if (_handleToIndex.ContainsKey(pausedList.Current.Handle) && !CoindexIsNull(_handleToIndex[pausedList.Current.Handle])
&& !CoindexSetPause(_handleToIndex[pausedList.Current.Handle]))
count--;
}
}
return count;
}
///
/// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has
/// no effect.
///
/// Any coroutines previously paused on the matching layer will be resumend.
/// Any coroutines previously paused with a matching tag will be resumend.
/// The number of coroutines that were resumed.
public static int ResumeCoroutines(int layer, string tag)
{
return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(layer, tag);
}
///
/// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect.
///
/// Any coroutines previously paused on the matching layer will be resumend.
/// Any coroutines previously paused with a matching tag will be resumend.
/// The number of coroutines that were resumed.
public int ResumeCoroutinesOnInstance(int layer, string tag)
{
if (tag == null)
return ResumeCoroutinesOnInstance(layer);
if (!_layeredProcesses.ContainsKey(layer) || !_taggedProcesses.ContainsKey(tag))
return 0;
int count = 0;
var indexesEnum = _taggedProcesses[tag].GetEnumerator();
while (indexesEnum.MoveNext())
if (!CoindexIsNull(indexesEnum.Current) && _layeredProcesses[layer].Contains(indexesEnum.Current) &&
CoindexSetPause(indexesEnum.Current, false))
count++;
var waitingEnum = _waitingTriggers.GetEnumerator();
while (waitingEnum.MoveNext())
{
var pausedList = waitingEnum.Current.Value.GetEnumerator();
while (pausedList.MoveNext())
{
if (_handleToIndex.ContainsKey(pausedList.Current.Handle) && !CoindexIsNull(_handleToIndex[pausedList.Current.Handle])
&& !CoindexSetPause(_handleToIndex[pausedList.Current.Handle]))
count--;
}
}
return count;
}
///
/// This will resume any matching coroutines.
///
/// The handle of the coroutine to resume.
/// The number of coroutines that were resumed (0 or 1).
public static int ResumeCoroutines(CoroutineHandle handle)
{
return ActiveInstances.ContainsKey(handle.Key) ? GetInstance(handle.Key).ResumeCoroutinesOnInstance(handle) : 0;
}
///
/// This will resume any matching coroutines running on this MEC instance.
///
/// The handle of the coroutine to resume.
/// The number of coroutines that were resumed (0 or 1).
public int ResumeCoroutinesOnInstance(CoroutineHandle handle)
{
var waitingEnum = _waitingTriggers.GetEnumerator();
while (waitingEnum.MoveNext())
{
var pausedList = waitingEnum.Current.Value.GetEnumerator();
while (pausedList.MoveNext())
if (pausedList.Current.Handle == handle)
return 0;
}
return _handleToIndex.ContainsKey(handle) &&
!CoindexIsNull(_handleToIndex[handle]) && CoindexSetPause(_handleToIndex[handle], false) ? 1 : 0;
}
///
/// Returns the tag associated with the coroutine that the given handle points to, if it is running.
///
/// The handle to the coroutine.
/// The coroutine's tag, or null if there is no matching tag.
public static string GetTag(CoroutineHandle handle)
{
Timing inst = GetInstance(handle.Key);
return inst != null && inst._handleToIndex.ContainsKey(handle) && inst._processTags.ContainsKey(inst._handleToIndex[handle])
? inst._processTags[inst._handleToIndex[handle]] : null;
}
///
/// Returns the layer associated with the coroutine that the given handle points to, if it is running.
///
/// The handle to the coroutine.
/// The coroutine's layer as a nullable integer, or null if there is no matching layer.
public static int? GetLayer(CoroutineHandle handle)
{
Timing inst = GetInstance(handle.Key);
return inst != null && inst._handleToIndex.ContainsKey(handle) && inst._processLayers.ContainsKey(inst._handleToIndex[handle])
? inst._processLayers[inst._handleToIndex[handle]] : (int?)null;
}
///
/// Returns the segment that the coroutine with the given handle is running on.
///
/// The handle to the coroutine.
/// The coroutine's segment, or Segment.Invalid if it's not found.
public static Segment GetSegment(CoroutineHandle handle)
{
Timing inst = GetInstance(handle.Key);
return inst != null && inst._handleToIndex.ContainsKey(handle) ? inst._handleToIndex[handle].seg : Segment.Invalid;
}
///
/// Sets the coroutine that the handle points to to have the given tag.
///
/// The handle to the coroutine.
/// The new tag to assign, or null to clear the tag.
/// If set to false then the tag will not be changed if the coroutine has an existing tag.
/// Whether the tag was set successfully.
public static bool SetTag(CoroutineHandle handle, string newTag, bool overwriteExisting = true)
{
Timing inst = GetInstance(handle.Key);
if (inst == null || !inst._handleToIndex.ContainsKey(handle) || inst.CoindexIsNull(inst._handleToIndex[handle])
|| (!overwriteExisting && inst._processTags.ContainsKey(inst._handleToIndex[handle])))
return false;
if (newTag == null)
{
inst.RemoveTag(inst._handleToIndex[handle]);
return true;
}
if (inst._processTags.ContainsKey(inst._handleToIndex[handle]))
{
if (inst._taggedProcesses[inst._processTags[inst._handleToIndex[handle]]].Count <= 1)
inst._taggedProcesses.Remove(inst._processTags[inst._handleToIndex[handle]]);
else
inst._taggedProcesses[inst._processTags[inst._handleToIndex[handle]]].Remove(inst._handleToIndex[handle]);
inst._processTags[inst._handleToIndex[handle]] = newTag;
}
else
{
inst._processTags.Add(inst._handleToIndex[handle], newTag);
}
if (inst._taggedProcesses.ContainsKey(newTag))
inst._taggedProcesses[newTag].Add(inst._handleToIndex[handle]);
else
inst._taggedProcesses.Add(newTag, new HashSet { inst._handleToIndex[handle] });
return true;
}
///
/// Sets the coroutine that the handle points to to have the given layer.
///
/// The handle to the coroutine.
/// The new tag to assign.
/// If set to false then the tag will not be changed if the coroutine has an existing tag.
/// Whether the layer was set successfully.
public static bool SetLayer(CoroutineHandle handle, int newLayer, bool overwriteExisting = true)
{
Timing inst = GetInstance(handle.Key);
if (inst == null || !inst._handleToIndex.ContainsKey(handle) || inst.CoindexIsNull(inst._handleToIndex[handle])
|| (!overwriteExisting && inst._processLayers.ContainsKey(inst._handleToIndex[handle])))
return false;
if (inst._processLayers.ContainsKey(inst._handleToIndex[handle]))
{
if (inst._layeredProcesses[inst._processLayers[inst._handleToIndex[handle]]].Count <= 1)
inst._layeredProcesses.Remove(inst._processLayers[inst._handleToIndex[handle]]);
else
inst._layeredProcesses[inst._processLayers[inst._handleToIndex[handle]]].Remove(inst._handleToIndex[handle]);
inst._processLayers[inst._handleToIndex[handle]] = newLayer;
}
else
{
inst._processLayers.Add(inst._handleToIndex[handle], newLayer);
}
if (inst._layeredProcesses.ContainsKey(newLayer))
inst._layeredProcesses[newLayer].Add(inst._handleToIndex[handle]);
else
inst._layeredProcesses.Add(newLayer, new HashSet { inst._handleToIndex[handle] });
return true;
}
///
/// Sets the segment for the coroutine with the given handle.
///
/// The handle to the coroutine.
/// The new segment to run the coroutine in.
/// Whether the segment was set successfully.
public static bool SetSegment(CoroutineHandle handle, Segment newSegment)
{
Timing inst = GetInstance(handle.Key);
if (inst == null || !inst._handleToIndex.ContainsKey(handle) || inst.CoindexIsNull(inst._handleToIndex[handle]))
return false;
inst.RunCoroutineInternal(inst.CoindexExtract(inst._handleToIndex[handle]), newSegment, inst._processLayers.ContainsKey(inst._handleToIndex[handle])
? inst._processLayers[inst._handleToIndex[handle]] : (int?)null, inst._processTags.ContainsKey(inst._handleToIndex[handle])
? inst._processTags[inst._handleToIndex[handle]] : null, handle, false);
return true;
}
///
/// Sets the coroutine that the handle points to to have the given tag.
///
/// The handle to the coroutine.
/// Whether the tag was removed successfully.
public static bool RemoveTag(CoroutineHandle handle)
{
return SetTag(handle, null);
}
///
/// Sets the coroutine that the handle points to to have the given layer.
///
/// The handle to the coroutine.
/// Whether the layer was removed successfully.
public static bool RemoveLayer(CoroutineHandle handle)
{
Timing inst = GetInstance(handle.Key);
if (inst == null || !inst._handleToIndex.ContainsKey(handle) || inst.CoindexIsNull(inst._handleToIndex[handle]))
return false;
inst.RemoveLayer(inst._handleToIndex[handle]);
return true;
}
///
/// Tests to see if the handle you have points to a valid coroutine.
///
/// The handle to test.
/// Whether it's a valid coroutine.
public static bool IsRunning(CoroutineHandle handle)
{
Timing inst = GetInstance(handle.Key);
return inst != null && inst._handleToIndex.ContainsKey(handle) && !inst.CoindexIsNull(inst._handleToIndex[handle]);
}
///
/// Tests to see if the handle you have points to a paused coroutine.
///
/// The handle to test.
/// Whether it's a paused coroutine.
public static bool IsPaused(CoroutineHandle handle)
{
Timing inst = GetInstance(handle.Key);
return inst != null && inst._handleToIndex.ContainsKey(handle) && !inst.CoindexIsNull(inst._handleToIndex[handle]) &&
!inst.CoindexIsPaused(inst._handleToIndex[handle]);
}
private void AddTag(string tag, ProcessIndex coindex)
{
_processTags.Add(coindex, tag);
if (_taggedProcesses.ContainsKey(tag))
_taggedProcesses[tag].Add(coindex);
else
_taggedProcesses.Add(tag, new HashSet { coindex });
}
private void AddLayer(int layer, ProcessIndex coindex)
{
_processLayers.Add(coindex, layer);
if (_layeredProcesses.ContainsKey(layer))
_layeredProcesses[layer].Add(coindex);
else
_layeredProcesses.Add(layer, new HashSet { coindex });
}
private void RemoveTag(ProcessIndex coindex)
{
if (_processTags.ContainsKey(coindex))
{
if (_taggedProcesses[_processTags[coindex]].Count > 1)
_taggedProcesses[_processTags[coindex]].Remove(coindex);
else
_taggedProcesses.Remove(_processTags[coindex]);
_processTags.Remove(coindex);
}
}
private void RemoveLayer(ProcessIndex coindex)
{
if (_processLayers.ContainsKey(coindex))
{
if (_layeredProcesses[_processLayers[coindex]].Count > 1)
_layeredProcesses[_processLayers[coindex]].Remove(coindex);
else
_layeredProcesses.Remove(_processLayers[coindex]);
_processLayers.Remove(coindex);
}
}
private void RemoveGraffiti(ProcessIndex coindex)
{
if (_processLayers.ContainsKey(coindex))
{
if (_layeredProcesses[_processLayers[coindex]].Count > 1)
_layeredProcesses[_processLayers[coindex]].Remove(coindex);
else
_layeredProcesses.Remove(_processLayers[coindex]);
_processLayers.Remove(coindex);
}
if (_processTags.ContainsKey(coindex))
{
if (_taggedProcesses[_processTags[coindex]].Count > 1)
_taggedProcesses[_processTags[coindex]].Remove(coindex);
else
_taggedProcesses.Remove(_processTags[coindex]);
_processTags.Remove(coindex);
}
if (_indexToHandle.ContainsKey(coindex))
{
_handleToIndex.Remove(_indexToHandle[coindex]);
_indexToHandle.Remove(coindex);
}
}
private void MoveGraffiti(ProcessIndex coindexFrom, ProcessIndex coindexTo)
{
RemoveGraffiti(coindexTo);
int layer;
if (_processLayers.TryGetValue(coindexFrom, out layer))
{
_layeredProcesses[layer].Remove(coindexFrom);
_layeredProcesses[layer].Add(coindexTo);
_processLayers.Add(coindexTo, layer);
_processLayers.Remove(coindexFrom);
}
string tag;
if (_processTags.TryGetValue(coindexFrom, out tag))
{
_taggedProcesses[tag].Remove(coindexFrom);
_taggedProcesses[tag].Add(coindexTo);
_processTags.Add(coindexTo, tag);
_processTags.Remove(coindexFrom);
}
_handleToIndex[_indexToHandle[coindexFrom]] = coindexTo;
_indexToHandle.Add(coindexTo, _indexToHandle[coindexFrom]);
_indexToHandle.Remove(coindexFrom);
}
private IEnumerator CoindexExtract(ProcessIndex coindex)
{
IEnumerator retVal;
switch (coindex.seg)
{
case Segment.Update:
retVal = UpdateProcesses[coindex.i];
UpdateProcesses[coindex.i] = null;
return retVal;
case Segment.FixedUpdate:
retVal = FixedUpdateProcesses[coindex.i];
FixedUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.LateUpdate:
retVal = LateUpdateProcesses[coindex.i];
LateUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.SlowUpdate:
retVal = SlowUpdateProcesses[coindex.i];
SlowUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.RealtimeUpdate:
retVal = RealtimeUpdateProcesses[coindex.i];
RealtimeUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.EditorUpdate:
retVal = EditorUpdateProcesses[coindex.i];
EditorUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.EditorSlowUpdate:
retVal = EditorSlowUpdateProcesses[coindex.i];
EditorSlowUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.EndOfFrame:
retVal = EndOfFrameProcesses[coindex.i];
EndOfFrameProcesses[coindex.i] = null;
return retVal;
case Segment.ManualTimeframe:
retVal = ManualTimeframeProcesses[coindex.i];
ManualTimeframeProcesses[coindex.i] = null;
return retVal;
default:
return null;
}
}
private bool CoindexIsNull(ProcessIndex coindex)
{
switch (coindex.seg)
{
case Segment.Update:
return UpdateProcesses[coindex.i] == null;
case Segment.FixedUpdate:
return FixedUpdateProcesses[coindex.i] == null;
case Segment.LateUpdate:
return LateUpdateProcesses[coindex.i] == null;
case Segment.SlowUpdate:
return SlowUpdateProcesses[coindex.i] == null;
case Segment.RealtimeUpdate:
return RealtimeUpdateProcesses[coindex.i] == null;
case Segment.EditorUpdate:
return EditorUpdateProcesses[coindex.i] == null;
case Segment.EditorSlowUpdate:
return EditorSlowUpdateProcesses[coindex.i] == null;
case Segment.EndOfFrame:
return EndOfFrameProcesses[coindex.i] == null;
case Segment.ManualTimeframe:
return ManualTimeframeProcesses[coindex.i] == null;
default:
return true;
}
}
private IEnumerator CoindexPeek(ProcessIndex coindex)
{
switch (coindex.seg)
{
case Segment.Update:
return UpdateProcesses[coindex.i];
case Segment.FixedUpdate:
return FixedUpdateProcesses[coindex.i];
case Segment.LateUpdate:
return LateUpdateProcesses[coindex.i];
case Segment.SlowUpdate:
return SlowUpdateProcesses[coindex.i];
case Segment.RealtimeUpdate:
return RealtimeUpdateProcesses[coindex.i];
case Segment.EditorUpdate:
return EditorUpdateProcesses[coindex.i];
case Segment.EditorSlowUpdate:
return EditorSlowUpdateProcesses[coindex.i];
case Segment.EndOfFrame:
return EndOfFrameProcesses[coindex.i];
case Segment.ManualTimeframe:
return ManualTimeframeProcesses[coindex.i];
default:
return null;
}
}
private bool CoindexKill(ProcessIndex coindex)
{
bool retVal;
switch (coindex.seg)
{
case Segment.Update:
retVal = UpdateProcesses[coindex.i] != null;
UpdateProcesses[coindex.i] = null;
return retVal;
case Segment.FixedUpdate:
retVal = FixedUpdateProcesses[coindex.i] != null;
FixedUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.LateUpdate:
retVal = LateUpdateProcesses[coindex.i] != null;
LateUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.SlowUpdate:
retVal = SlowUpdateProcesses[coindex.i] != null;
SlowUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.RealtimeUpdate:
retVal = RealtimeUpdateProcesses[coindex.i] != null;
RealtimeUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.EditorUpdate:
retVal = UpdateProcesses[coindex.i] != null;
EditorUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.EditorSlowUpdate:
retVal = EditorSlowUpdateProcesses[coindex.i] != null;
EditorSlowUpdateProcesses[coindex.i] = null;
return retVal;
case Segment.EndOfFrame:
retVal = EndOfFrameProcesses[coindex.i] != null;
EndOfFrameProcesses[coindex.i] = null;
return retVal;
case Segment.ManualTimeframe:
retVal = ManualTimeframeProcesses[coindex.i] != null;
ManualTimeframeProcesses[coindex.i] = null;
return retVal;
default:
return false;
}
}
private bool CoindexSetPause(ProcessIndex coindex, bool newPausedState = true)
{
bool isPaused;
switch (coindex.seg)
{
case Segment.Update:
isPaused = UpdatePaused[coindex.i];
UpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.FixedUpdate:
isPaused = FixedUpdatePaused[coindex.i];
FixedUpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.LateUpdate:
isPaused = LateUpdatePaused[coindex.i];
LateUpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.SlowUpdate:
isPaused = SlowUpdatePaused[coindex.i];
SlowUpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.RealtimeUpdate:
isPaused = RealtimeUpdatePaused[coindex.i];
RealtimeUpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.EditorUpdate:
isPaused = EditorUpdatePaused[coindex.i];
EditorUpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.EditorSlowUpdate:
isPaused = EditorSlowUpdatePaused[coindex.i];
EditorSlowUpdatePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.EndOfFrame:
isPaused = EndOfFramePaused[coindex.i];
EndOfFramePaused[coindex.i] = newPausedState;
return isPaused;
case Segment.ManualTimeframe:
isPaused = ManualTimeframePaused[coindex.i];
ManualTimeframePaused[coindex.i] = newPausedState;
return isPaused;
default:
return false;
}
}
private bool CoindexIsPaused(ProcessIndex coindex)
{
switch (coindex.seg)
{
case Segment.Update:
return UpdatePaused[coindex.i];
case Segment.FixedUpdate:
return FixedUpdatePaused[coindex.i];
case Segment.LateUpdate:
return LateUpdatePaused[coindex.i];
case Segment.SlowUpdate:
return SlowUpdatePaused[coindex.i];
case Segment.RealtimeUpdate:
return RealtimeUpdatePaused[coindex.i];
case Segment.EditorUpdate:
return EditorUpdatePaused[coindex.i];
case Segment.EditorSlowUpdate:
return EditorSlowUpdatePaused[coindex.i];
case Segment.EndOfFrame:
return EndOfFramePaused[coindex.i];
case Segment.ManualTimeframe:
return ManualTimeframePaused[coindex.i];
default:
return false;
}
}
private void CoindexReplace(ProcessIndex coindex, IEnumerator replacement)
{
switch (coindex.seg)
{
case Segment.Update:
UpdateProcesses[coindex.i] = replacement;
return;
case Segment.FixedUpdate:
FixedUpdateProcesses[coindex.i] = replacement;
return;
case Segment.LateUpdate:
LateUpdateProcesses[coindex.i] = replacement;
return;
case Segment.SlowUpdate:
SlowUpdateProcesses[coindex.i] = replacement;
return;
case Segment.RealtimeUpdate:
RealtimeUpdateProcesses[coindex.i] = replacement;
return;
case Segment.EditorUpdate:
EditorUpdateProcesses[coindex.i] = replacement;
return;
case Segment.EditorSlowUpdate:
EditorSlowUpdateProcesses[coindex.i] = replacement;
return;
case Segment.EndOfFrame:
EndOfFrameProcesses[coindex.i] = replacement;
return;
case Segment.ManualTimeframe:
ManualTimeframeProcesses[coindex.i] = replacement;
return;
}
}
///
/// Use the command "yield return Timing.WaitUntilDone(otherCoroutine);" to pause the current
/// coroutine until otherCoroutine is done.
///
/// The coroutine to pause for.
//public static float WaitUntilDone(CoroutineHandle otherCoroutine)
//{
// return Instance.WaitUntilDoneOnInstance(otherCoroutine);
//}
/////
///// Use the command "yield return Timing.WaitUntilDone(otherCoroutine);" to pause the current
///// coroutine until otherCoroutine is done.
/////
///// The coroutine to pause for.
///// Post a warning to the console if no hold action was actually performed.
//public static float WaitUntilDone(CoroutineHandle otherCoroutine, bool warnOnIssue)
//{
// return Instance.WaitUntilDoneOnInstance(otherCoroutine, warnOnIssue);
//}
/////
///// Use the command "yield return timingInstance.WaitUntilDoneOnInstance(otherCoroutine);" to pause the current
///// coroutine until the otherCoroutine is done.
/////
///// The coroutine to pause for.
///// Post a warning to the console if no hold action was actually performed.
//public float WaitUntilDoneOnInstance(CoroutineHandle otherCoroutine, bool warnOnIssue = true)
//{
// if (_handleToIndex.ContainsKey(otherCoroutine))
// {
// if (CoindexIsNull(_handleToIndex[otherCoroutine]))
// return 0f;
// if (!_waitingTriggers.ContainsKey(otherCoroutine))
// {
// CoindexReplace(_handleToIndex[otherCoroutine], _StartWhenDone(otherCoroutine, CoindexPeek(_handleToIndex[otherCoroutine])));
// _waitingTriggers.Add(otherCoroutine, new HashSet());
// }
// ReplacementFunction = (coptr, instance, handle) =>
// {
// if (handle == otherCoroutine)
// {
// if (warnOnIssue)
// Debug.LogWarning("A coroutine attempted to wait for itself.");
// return coptr;
// }
// _waitingTriggers[otherCoroutine].Add(new ProcessData
// {
// Handle = handle,
// PauseTime = coptr.Current > GetSegmentTime(_handleToIndex[handle].seg)
// ? coptr.Current - (float)GetSegmentTime(_handleToIndex[handle].seg) : 0f
// });
// CoindexSetPause(_handleToIndex[handle]);
// return coptr;
// };
// return float.NaN;
// }
// if (warnOnIssue)
// Debug.LogWarning("WaitUntilDone cannot hold: The coroutine handle that was passed in is invalid.\n" + otherCoroutine);
// return 0f;
//}
private IEnumerator _StartWhenDone(CoroutineHandle handle, IEnumerator proc)
{
if (!_waitingTriggers.ContainsKey(handle)) yield break;
try
{
if (proc.Current > localTime)
yield return proc.Current;
while (proc.MoveNext())
yield return proc.Current;
}
finally
{
CloseWaitingProcess(handle);
}
}
private void CloseWaitingProcess(CoroutineHandle handle)
{
if (!_waitingTriggers.ContainsKey(handle)) return;
var tasksEnum = _waitingTriggers[handle].GetEnumerator();
_waitingTriggers.Remove(handle);
while (tasksEnum.MoveNext())
{
if (_handleToIndex.ContainsKey(tasksEnum.Current.Handle))
{
ProcessIndex coIndex = _handleToIndex[tasksEnum.Current.Handle];
//if (tasksEnum.Current.PauseTime > 0d)
//CoindexReplace(coIndex, _InjectDelay(CoindexPeek(coIndex), (float)(GetSegmentTime(coIndex.seg) + tasksEnum.Current.PauseTime)));
CoindexSetPause(coIndex, false);
}
}
}
private static IEnumerator _InjectDelay(IEnumerator proc, float returnAt)
{
yield return returnAt;
ReplacementFunction = delegate { return proc; };
yield return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(segment);" to switch this coroutine to
/// the given segment on the default instance.
///
/// The new segment to run in.
public static float SwitchCoroutine(Segment newSegment)
{
ReplacementFunction = (coptr, instance, handle) =>
{
ProcessIndex index = instance._handleToIndex[handle];
instance.RunCoroutineInternal(coptr, newSegment, instance._processLayers.ContainsKey(index) ? instance._processLayers[index] : (int?)null,
instance._processTags.ContainsKey(index) ? instance._processTags[index] : null, handle, false);
return null;
};
return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(segment, tag);" to switch this coroutine to
/// the given values.
///
/// The new segment to run in.
/// The new tag to apply, or null to remove this coroutine's tag.
public static float SwitchCoroutine(Segment newSegment, string newTag)
{
ReplacementFunction = (coptr, instance, handle) =>
{
ProcessIndex index = instance._handleToIndex[handle];
instance.RunCoroutineInternal(coptr, newSegment,
instance._processLayers.ContainsKey(index) ? instance._processLayers[index] : (int?)null, newTag, handle, false);
return null;
};
return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(segment, layer);" to switch this coroutine to
/// the given values.
///
/// The new segment to run in.
/// The new layer to apply.
public static float SwitchCoroutine(Segment newSegment, int newLayer)
{
ReplacementFunction = (coptr, instance, handle) =>
{
ProcessIndex index = instance._handleToIndex[handle];
instance.RunCoroutineInternal(coptr, newSegment, newLayer,
instance._processTags.ContainsKey(index) ? instance._processTags[index] : null, handle, false);
return null;
};
return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(segment, layer, tag);" to switch this coroutine to
/// the given values.
///
/// The new segment to run in.
/// The new layer to apply.
/// The new tag to apply, or null to remove this coroutine's tag.
public static float SwitchCoroutine(Segment newSegment, int newLayer, string newTag)
{
ReplacementFunction = (coptr, instance, handle) =>
{
instance.RunCoroutineInternal(coptr, newSegment, newLayer, newTag, handle, false);
return null;
};
return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(tag);" to switch this coroutine to
/// the given tag.
///
/// The new tag to apply, or null to remove this coroutine's tag.
public static float SwitchCoroutine(string newTag)
{
ReplacementFunction = (coptr, instance, handle) =>
{
instance.RemoveTag(instance._handleToIndex[handle]);
if (newTag != null)
instance.AddTag(newTag, instance._handleToIndex[handle]);
return coptr;
};
return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(layer);" to switch this coroutine to
/// the given layer.
///
/// The new layer to apply.
public static float SwitchCoroutine(int newLayer)
{
ReplacementFunction = (coptr, instance, handle) =>
{
instance.RemoveLayer(instance._handleToIndex[handle]);
instance.AddLayer(newLayer, instance._handleToIndex[handle]);
return coptr;
};
return float.NaN;
}
///
/// Use the command "yield return Timing.SwitchCoroutine(layer, tag);" to switch this coroutine to
/// the given tag.
///
/// The new layer to apply.
/// The new tag to apply, or null to remove this coroutine's tag.
public static float SwitchCoroutine(int newLayer, string newTag)
{
ReplacementFunction = (coptr, instance, handle) =>
{
instance.RemoveLayer(instance._handleToIndex[handle]);
instance.AddLayer(newLayer, instance._handleToIndex[handle]);
instance.RemoveTag(instance._handleToIndex[handle]);
if (newTag != null)
instance.AddTag(newTag, instance._handleToIndex[handle]);
return coptr;
};
return float.NaN;
}
/////
///// Use the command "yield return Timing.WaitUntilDone(wwwObject);" to pause the current
///// coroutine until the wwwObject is done.
/////
///// The www object to pause for.
//public static float WaitUntilDone(WWW wwwObject)
//{
// if(wwwObject == null || wwwObject.isDone) return 0f;
// ReplacementFunction = (coptr, instance, handle) => _StartWhenDone(wwwObject, coptr);
// return float.NaN;
//}
private static IEnumerator _StartWhenDone(WWW wwwObject, IEnumerator pausedProc)
{
while (!wwwObject.isDone)
yield return 0f;
ReplacementFunction = delegate { return pausedProc; };
yield return float.NaN;
}
/////
///// Use the command "yield return Timing.WaitUntilDone(operation);" to pause the current
///// coroutine until the operation is done.
/////
///// The operation variable returned.
//public static float WaitUntilDone(AsyncOperation operation)
//{
// if (operation == null || operation.isDone) return 0f;
// ReplacementFunction = (coptr, instance, handle) => _StartWhenDone(operation, coptr);
// return float.NaN;
//}
private static IEnumerator _StartWhenDone(AsyncOperation operation, IEnumerator pausedProc)
{
while (!operation.isDone)
yield return 0f;
ReplacementFunction = delegate { return pausedProc; };
yield return float.NaN;
}
#if !UNITY_4_6 && !UNITY_4_7 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2
///
/// Use the command "yield return Timing.WaitUntilDone(operation);" to pause the current
/// coroutine until the operation is done.
///
/// The operation variable returned.
//public static float WaitUntilDone(CustomYieldInstruction operation)
//{
// if (operation == null || !operation.keepWaiting) return 0f;
// ReplacementFunction = (coptr, instance, handle) => _StartWhenDone(operation, coptr);
// return float.NaN;
//}
private static IEnumerator _StartWhenDone(CustomYieldInstruction operation, IEnumerator pausedProc)
{
while (operation.keepWaiting)
yield return 0f;
ReplacementFunction = delegate { return pausedProc; };
yield return float.NaN;
}
#endif
///
/// Use the command "yield return Timing.WaitUntilTrue(evaluatorFunc);" to pause the current
/// coroutine until the evaluator function returns true.
///
/// The evaluator function.
public static float WaitUntilTrue(System.Func evaluatorFunc)
{
if (evaluatorFunc == null || evaluatorFunc()) return 0f;
ReplacementFunction = (coptr, instance, handle) => _StartWhenDone(evaluatorFunc, false, coptr);
return float.NaN;
}
///
/// Use the command "yield return Timing.WaitUntilFalse(evaluatorFunc);" to pause the current
/// coroutine until the evaluator function returns false.
///
/// The evaluator function.
public static float WaitUntilFalse(System.Func evaluatorFunc)
{
if (evaluatorFunc == null || !evaluatorFunc()) return 0f;
ReplacementFunction = (coptr, instance, handle) => _StartWhenDone(evaluatorFunc, true, coptr);
return float.NaN;
}
private static IEnumerator _StartWhenDone(System.Func evaluatorFunc, bool continueOn, IEnumerator pausedProc)
{
while (evaluatorFunc() == continueOn)
yield return 0f;
ReplacementFunction = delegate { return pausedProc; };
yield return float.NaN;
}
///
/// Calls the specified action after a specified number of seconds.
///
/// The number of seconds to wait before calling the action.
/// The action to call.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallDelayed(float delay, System.Action action)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._DelayedCall(delay, action));
}
///
/// Calls the specified action after a specified number of seconds.
///
/// The number of seconds to wait before calling the action.
/// The action to call.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallDelayedOnInstance(float delay, System.Action action)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_DelayedCall(delay, action));
}
private IEnumerator _DelayedCall(float delay, System.Action action)
{
yield return WaitForSecondsOnInstance(delay);
action();
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallPeriodically(float timeframe, float period, System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(timeframe, period, action, onDone), Segment.Update);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallPeriodicallyOnInstance(float timeframe, float period, System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(timeframe, period, action, onDone), Segment.Update);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallPeriodically(float timeframe, float period, System.Action action, Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(timeframe, period, action, onDone), timing);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallPeriodicallyOnInstance(float timeframe, float period, System.Action action, Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(timeframe, period, action, onDone), timing);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallContinuously(float timeframe, System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(timeframe, 0f, action, onDone), Segment.Update);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallContinuouslyOnInstance(float timeframe, System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(timeframe, 0f, action, onDone), Segment.Update);
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallContinuously(float timeframe, System.Action action, Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(timeframe, 0f, action, onDone), timing);
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// The number of seconds that this function should run.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallContinuouslyOnInstance(float timeframe, System.Action action, Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(timeframe, 0f, action, onDone), timing);
}
private IEnumerator _CallContinuously(float timeframe, float period, System.Action action, System.Action onDone)
{
double startTime = localTime;
while (localTime <= startTime + timeframe)
{
yield return WaitForSecondsOnInstance(period);
action();
}
if (onDone != null)
onDone();
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// A value that will be passed in to the supplied action each period.
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallPeriodically(T reference, float timeframe, float period,
System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(reference, timeframe, period, action, onDone), Segment.Update);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// A value that will be passed in to the supplied action each period.
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallPeriodicallyOnInstance(T reference, float timeframe, float period,
System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(reference, timeframe, period, action, onDone), Segment.Update);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// A value that will be passed in to the supplied action each period.
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallPeriodically(T reference, float timeframe, float period, System.Action action,
Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(reference, timeframe, period, action, onDone), timing);
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// A value that will be passed in to the supplied action each period.
/// The number of seconds that this function should run.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallPeriodicallyOnInstance(T reference, float timeframe, float period, System.Action action,
Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(reference, timeframe, period, action, onDone), timing);
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// A value that will be passed in to the supplied action each frame.
/// The number of seconds that this function should run.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallContinuously(T reference, float timeframe, System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(reference, timeframe, 0f, action, onDone), Segment.Update);
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// A value that will be passed in to the supplied action each frame.
/// The number of seconds that this function should run.
/// The action to call every frame.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallContinuouslyOnInstance(T reference, float timeframe, System.Action action, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(reference, timeframe, 0f, action, onDone), Segment.Update);
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// A value that will be passed in to the supplied action each frame.
/// The number of seconds that this function should run.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallContinuously(T reference, float timeframe, System.Action action,
Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(reference, timeframe, 0f, action, onDone), timing);
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// A value that will be passed in to the supplied action each frame.
/// The number of seconds that this function should run.
/// The action to call every frame.
/// The timing segment to run in.
/// An optional action to call when this function finishes.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallContinuouslyOnInstance(T reference, float timeframe, System.Action action,
Segment timing, System.Action onDone = null)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(reference, timeframe, 0f, action, onDone), timing);
}
private IEnumerator _CallContinuously(T reference, float timeframe, float period,
System.Action action, System.Action onDone = null)
{
double startTime = localTime;
while (localTime <= startTime + timeframe)
{
yield return WaitForSecondsOnInstance(period);
action(reference);
}
if (onDone != null)
onDone(reference);
}
private struct ProcessData : System.IEquatable
{
public CoroutineHandle Handle;
//public float PauseTime;
public bool Equals(ProcessData other)
{
return Handle == other.Handle;
}
public override bool Equals(object other)
{
if (other is ProcessData)
return Equals((ProcessData)other);
return false;
}
public override int GetHashCode()
{
return Handle.GetHashCode();
}
}
private struct ProcessIndex : System.IEquatable
{
public Segment seg;
public int i;
public bool Equals(ProcessIndex other)
{
return seg == other.seg && i == other.i;
}
public override bool Equals(object other)
{
if (other is ProcessIndex)
return Equals((ProcessIndex)other);
return false;
}
public static bool operator ==(ProcessIndex a, ProcessIndex b)
{
return a.seg == b.seg && a.i == b.i;
}
public static bool operator !=(ProcessIndex a, ProcessIndex b)
{
return a.seg != b.seg || a.i != b.i;
}
public override int GetHashCode()
{
return (((int)seg - 4) * (int.MaxValue / 7)) + i;
}
}
}
public enum Segment
{
Invalid = -1,
Update,
FixedUpdate,
LateUpdate,
SlowUpdate,
RealtimeUpdate,
EditorUpdate,
EditorSlowUpdate,
EndOfFrame,
ManualTimeframe
}
///
/// A handle for a MEC coroutine.
///
public struct CoroutineHandle : System.IEquatable
{
private static int _nextIndex;
private readonly int _id;
public byte Key { get { return (byte)(_id & 0x1F); } }
public CoroutineHandle(byte ind)
{
if (ind > 0x1F)
ind -= 0x1F;
_id = _nextIndex + ind;
_nextIndex += 0x20;
}
public bool Equals(CoroutineHandle other)
{
return _id == other._id;
}
public override bool Equals(object other)
{
if (other is CoroutineHandle)
return Equals((CoroutineHandle)other);
return false;
}
public static bool operator ==(CoroutineHandle a, CoroutineHandle b)
{
return a._id == b._id;
}
public static bool operator !=(CoroutineHandle a, CoroutineHandle b)
{
return a._id != b._id;
}
public override int GetHashCode()
{
return _id;
}
///
/// Get or set the corrosponding coroutine's tag. Null removes the tag or represents no tag assigned.
///
public string Tag
{
get { return Timing.GetTag(this); }
set { Timing.SetTag(this, value); }
}
///
/// Get or set the corrosponding coroutine's layer. Null removes the layer or represents no layer assigned.
///
public int? Layer
{
get { return Timing.GetLayer(this); }
set
{
if (value == null)
Timing.RemoveLayer(this);
else
Timing.SetLayer(this, (int)value);
}
}
///
/// Get or set the coorsponding coroutine's segment.
///
public Segment Segment
{
get { return Timing.GetSegment(this); }
set { Timing.SetSegment(this, value); }
}
///
/// Is true until the coroutine function ends or is killed. Setting this to false will kill the coroutine.
///
public bool IsRunning
{
get { return Timing.IsRunning(this); }
set { if (!value) Timing.KillCoroutines(this); }
}
///
/// Is true while the coroutine is paused (but not in a WaitUntilDone holding pattern). Setting this will pause and resume the coroutine.
///
public bool IsPaused
{
get { return Timing.IsPaused(this); }
set { if (value) Timing.PauseCoroutines(this); else Timing.ResumeCoroutines(this); }
}
}
}
public static class MECExtensionMethods
{
///
/// Adds a delay to the beginning of this coroutine.
///
/// The coroutine handle to act upon.
/// The number of seconds to delay this coroutine.
/// The modified coroutine handle.
public static IEnumerator Delay(this IEnumerator coroutine, float timeToDelay)
{
yield return MovementEffects.Timing.WaitForSeconds(timeToDelay);
while (coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Adds a delay to the beginning of this coroutine until a function returns true.
///
/// The coroutine handle to act upon.
/// The coroutine will be paused until this function returns true.
/// The modified coroutine handle.
public static IEnumerator Delay(this IEnumerator coroutine, System.Func condition)
{
while (!condition())
yield return 0f;
while (coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Adds a delay to the beginning of this coroutine until a function returns true.
///
/// The coroutine handle to act upon.
/// A variable that will be passed into the condition function each time it is tested.
/// The coroutine will be paused until this function returns true.
/// The modified coroutine handle.
public static IEnumerator Delay(this IEnumerator coroutine, T data, System.Func condition)
{
while (!condition(data))
yield return 0f;
while (coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Cancels this coroutine when the supplied game object is destroyed or made inactive.
///
/// The coroutine handle to act upon.
/// The GameObject to test.
/// The modified coroutine handle.
public static IEnumerator CancelWith(this IEnumerator coroutine, GameObject gameObject)
{
while (gameObject && gameObject.activeInHierarchy && coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Cancels this coroutine when the supplied game objects are destroyed or made inactive.
///
/// The coroutine handle to act upon.
/// The first GameObject to test.
/// The second GameObject to test
/// The modified coroutine handle.
public static IEnumerator CancelWith(this IEnumerator coroutine, GameObject gameObject1, GameObject gameObject2)
{
while (gameObject1 && gameObject1.activeInHierarchy && gameObject2 && gameObject2.activeInHierarchy && coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Cancels this coroutine when the supplied game objects are destroyed or made inactive.
///
/// The coroutine handle to act upon.
/// The first GameObject to test.
/// The second GameObject to test
/// The third GameObject to test.
/// The modified coroutine handle.
public static IEnumerator CancelWith(this IEnumerator coroutine,
GameObject gameObject1, GameObject gameObject2, GameObject gameObject3)
{
while (gameObject1 && gameObject1.activeInHierarchy && gameObject2 && gameObject2.activeInHierarchy &&
gameObject3 && gameObject3.activeInHierarchy && coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Cancels this coroutine when the supplied function returns false.
///
/// The coroutine handle to act upon.
/// The test function. True for continue, false to stop.
/// The modified coroutine handle.
public static IEnumerator CancelWith(this IEnumerator coroutine, System.Func condition)
{
if (condition == null) yield break;
while (condition() && coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Runs the supplied coroutine immediately after this one.
///
/// The coroutine handle to act upon.
/// The coroutine to run next.
/// The modified coroutine handle.
public static IEnumerator Append(this IEnumerator coroutine, IEnumerator nextCoroutine)
{
while (coroutine.MoveNext())
yield return coroutine.Current;
if (nextCoroutine != null)
while (nextCoroutine.MoveNext())
yield return nextCoroutine.Current;
}
///
/// Runs the supplied function immediately after this coroutine finishes.
///
/// The coroutine handle to act upon.
/// The action to run after this coroutine finishes.
/// The modified coroutine handle.
public static IEnumerator Append(this IEnumerator coroutine, System.Action onDone)
{
while (coroutine.MoveNext())
yield return coroutine.Current;
if (onDone != null)
onDone();
}
///
/// Runs the supplied coroutine immediately before this one.
///
/// The coroutine handle to act upon.
/// The coroutine to run first.
/// The modified coroutine handle.
public static IEnumerator Prepend(this IEnumerator coroutine, IEnumerator lastCoroutine)
{
if (lastCoroutine != null)
while (lastCoroutine.MoveNext())
yield return lastCoroutine.Current;
while (coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Runs the supplied function immediately before this coroutine starts.
///
/// The coroutine handle to act upon.
/// The action to run before this coroutine starts.
/// The modified coroutine handle.
public static IEnumerator Prepend(this IEnumerator coroutine, System.Action onStart)
{
if (onStart != null)
onStart();
while (coroutine.MoveNext())
yield return coroutine.Current;
}
///
/// Combines the this coroutine with another and runs them in a combined handle.
///
/// The coroutine handle to act upon.
/// The coroutine handle to combine.
/// The modified coroutine handle.
public static IEnumerator Superimpose(this IEnumerator coroutineA, IEnumerator coroutineB)
{
return Superimpose(coroutineA, coroutineB, MovementEffects.Timing.Instance);
}
///
/// Combines the this coroutine with another and runs them in a combined handle.
///
/// The coroutine handle to act upon.
/// The coroutine handle to combine.
/// The timing instance that this will be run in, if not the default instance.
/// The modified coroutine handle.
public static IEnumerator Superimpose(this IEnumerator coroutineA, IEnumerator coroutineB, MovementEffects.Timing instance)
{
while (coroutineA != null || coroutineB != null)
{
if (coroutineA != null && !(instance.localTime < coroutineA.Current) && !coroutineA.MoveNext())
coroutineA = null;
if (coroutineB != null && !(instance.localTime < coroutineB.Current) && !coroutineB.MoveNext())
coroutineB = null;
if ((coroutineA != null && float.IsNaN(coroutineA.Current)) || (coroutineB != null && float.IsNaN(coroutineB.Current)))
yield return float.NaN;
else if (coroutineA != null && coroutineB != null)
yield return coroutineA.Current < coroutineB.Current ? coroutineA.Current : coroutineB.Current;
else if (coroutineA == null && coroutineB != null)
yield return coroutineB.Current;
else if (coroutineA != null)
yield return coroutineA.Current;
}
}
///
/// Uses the passed in function to change the return values of this coroutine.
///
/// The coroutine handle to act upon.
/// A function that takes the current return value and returns the new return.
/// The modified coroutine handle.
public static IEnumerator Hijack(this IEnumerator coroutine, System.Func newReturn)
{
if (newReturn == null) yield break;
while (coroutine.MoveNext())
yield return newReturn(coroutine.Current);
}
}