using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Assertions;
#if UNITY_EDITOR
using UnityEditor;
#endif
#if UNITY_5_5_OR_NEWER
using UnityEngine.Profiling;
#endif
// /////////////////////////////////////////////////////////////////////////////////////////
// More Effective Coroutines Pro
// v3.08.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 MEC
{
public class Timing : MonoBehaviour
{
///
/// 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;
///
/// 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.
///
[System.NonSerialized]
public float localTime;
///
/// The time in seconds that the current segment has been running.
///
public static float LocalTime { get { return Instance.localTime; } }
///
/// The amount of time in fractional seconds that elapsed between this frame and the last frame.
///
[System.NonSerialized]
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, 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, CoroutineHandle, IEnumerator> ReplacementFunction;
///
/// This event fires just before each segment is run.
///
public static event System.Action OnPreExecute;
///
/// You can use "yield return Timing.WaitForOneFrame;" inside a coroutine function to go to the next frame.
///
public const float WaitForOneFrame = float.NegativeInfinity;
///
/// The main thread that (almost) everything in unity runs in.
///
public static System.Threading.Thread MainThread { get; private set; }
///
/// The handle of the current coroutine that is running.
///
public static CoroutineHandle CurrentCoroutine { get { return Instance.currentCoroutine; } }
///
/// The handle of the current coroutine that is running.
///
public CoroutineHandle currentCoroutine { get; private set; }
private static object _tmpRef;
private static int _tmpInt;
private static bool _tmpBool;
private static Segment _tmpSegment;
private static CoroutineHandle _tmpHandle;
private int _currentUpdateFrame;
private int _currentLateUpdateFrame;
private int _currentSlowUpdateFrame;
private int _currentRealtimeUpdateFrame;
private int _currentEndOfFrameFrame;
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 int _lastUpdateProcessSlot;
private int _lastLateUpdateProcessSlot;
private int _lastFixedUpdateProcessSlot;
private int _lastSlowUpdateProcessSlot;
private int _lastRealtimeUpdateProcessSlot;
#if UNITY_EDITOR
private int _lastEditorUpdateProcessSlot;
private int _lastEditorSlowUpdateProcessSlot;
#endif
private int _lastEndOfFrameProcessSlot;
private int _lastManualTimeframeProcessSlot;
private float _lastUpdateTime;
private float _lastLateUpdateTime;
private float _lastFixedUpdateTime;
private float _lastSlowUpdateTime;
private float _lastRealtimeUpdateTime;
#if UNITY_EDITOR
private float _lastEditorUpdateTime;
private float _lastEditorSlowUpdateTime;
#endif
private float _lastEndOfFrameTime;
private float _lastManualTimeframeTime;
private float _lastSlowUpdateDeltaTime;
private float _lastEditorUpdateDeltaTime;
private float _lastEditorSlowUpdateDeltaTime;
private float _lastManualTimeframeDeltaTime;
private ushort _framesSinceUpdate;
private ushort _expansions = 1;
[SerializeField, HideInInspector]
private byte _instanceID;
private bool _EOFPumpRan;
private static readonly Dictionary> Links = new Dictionary>();
private static readonly WaitForEndOfFrame EofWaitObject = new WaitForEndOfFrame();
private readonly Dictionary> _waitingTriggers = new Dictionary>();
private readonly HashSet _allWaiting = new HashSet();
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 bool[] UpdatePaused = new bool[InitialBufferSizeLarge];
private bool[] LateUpdatePaused = new bool[InitialBufferSizeSmall];
private bool[] FixedUpdatePaused = new bool[InitialBufferSizeMedium];
private bool[] SlowUpdatePaused = new bool[InitialBufferSizeMedium];
private bool[] RealtimeUpdatePaused = new bool[InitialBufferSizeSmall];
private bool[] EditorUpdatePaused = new bool[InitialBufferSizeSmall];
private bool[] EditorSlowUpdatePaused = new bool[InitialBufferSizeSmall];
private bool[] EndOfFramePaused = new bool[InitialBufferSizeSmall];
private bool[] ManualTimeframePaused = new bool[InitialBufferSizeSmall];
private bool[] UpdateHeld = new bool[InitialBufferSizeLarge];
private bool[] LateUpdateHeld = new bool[InitialBufferSizeSmall];
private bool[] FixedUpdateHeld = new bool[InitialBufferSizeMedium];
private bool[] SlowUpdateHeld = new bool[InitialBufferSizeMedium];
private bool[] RealtimeUpdateHeld = new bool[InitialBufferSizeSmall];
private bool[] EditorUpdateHeld = new bool[InitialBufferSizeSmall];
private bool[] EditorSlowUpdateHeld = new bool[InitialBufferSizeSmall];
private bool[] EndOfFrameHeld = new bool[InitialBufferSizeSmall];
private bool[] ManualTimeframeHeld = new bool[InitialBufferSizeSmall];
private CoroutineHandle _eofWatcherHandle;
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 Timing[] ActiveInstances = new Timing[16];
private static Timing _instance;
public static Timing Instance
{
get
{
if (_instance == null || !_instance.gameObject)
{
GameObject instanceHome = GameObject.Find("Timing Controller");
if(instanceHome == null)
{
instanceHome = new GameObject { name = "Timing Controller" };
#if UNITY_EDITOR
if(Application.isPlaying)
DontDestroyOnLoad(instanceHome);
#else
DontDestroyOnLoad(instanceHome);
#endif
}
_instance = instanceHome.GetComponent() ?? instanceHome.AddComponent();
_instance.InitializeInstanceID();
}
return _instance;
}
set { _instance = value; }
}
void OnDestroy()
{
if (_instance == this)
_instance = null;
}
void OnEnable()
{
if (MainThread == null)
MainThread = System.Threading.Thread.CurrentThread;
if (_nextEditorUpdateProcessSlot > 0 || _nextEditorSlowUpdateProcessSlot > 0)
OnEditorStart();
InitializeInstanceID();
if (_nextEndOfFrameProcessSlot > 0)
RunCoroutineSingletonOnInstance(_EOFPumpWatcher(), "MEC_EOFPumpWatcher", SingletonBehavior.Abort);
}
void OnDisable()
{
if (_instanceID < ActiveInstances.Length)
ActiveInstances[_instanceID] = null;
}
private void InitializeInstanceID()
{
if (ActiveInstances[_instanceID] == null)
{
if (_instanceID == 0x00)
_instanceID++;
for (; _instanceID <= 0x10; _instanceID++)
{
if (_instanceID == 0x10)
{
GameObject.Destroy(gameObject);
throw new System.OverflowException("You are only allowed 15 different contexts for MEC to run inside at one time.");
}
if (ActiveInstances[_instanceID] == null)
{
ActiveInstances[_instanceID] = this;
break;
}
}
}
}
void Update()
{
if (OnPreExecute != null)
OnPreExecute();
if (_lastSlowUpdateTime + TimeBetweenSlowUpdateCalls < Time.realtimeSinceStartup && _nextSlowUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.SlowUpdate };
if (UpdateTimeValues(coindex.seg))
_lastSlowUpdateProcessSlot = _nextSlowUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastSlowUpdateProcessSlot; coindex.i++)
{
try
{
if (!SlowUpdatePaused[coindex.i] && !SlowUpdateHeld[coindex.i] && SlowUpdateProcesses[coindex.i] != null && !(localTime < SlowUpdateProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine (Slow Update), " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine (Slow Update)");
}
if (!SlowUpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (SlowUpdateProcesses[coindex.i] != null && float.IsNaN(SlowUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
SlowUpdateProcesses[coindex.i] = ReplacementFunction(SlowUpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch(System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.SlowUpdate);");
}
}
}
if (_nextRealtimeUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.RealtimeUpdate };
if (UpdateTimeValues(coindex.seg))
_lastRealtimeUpdateProcessSlot = _nextRealtimeUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastRealtimeUpdateProcessSlot; coindex.i++)
{
try
{
if (!RealtimeUpdatePaused[coindex.i] && !RealtimeUpdateHeld[coindex.i] && RealtimeUpdateProcesses[coindex.i] != null && !(localTime < RealtimeUpdateProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine (Realtime Update), " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine (Realtime Update)");
}
if (!RealtimeUpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (RealtimeUpdateProcesses[coindex.i] != null && float.IsNaN(RealtimeUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
RealtimeUpdateProcesses[coindex.i] = ReplacementFunction(RealtimeUpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.RealtimeUpdate);");
}
}
}
if (_nextUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.Update };
if (UpdateTimeValues(coindex.seg))
_lastUpdateProcessSlot = _nextUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastUpdateProcessSlot; coindex.i++)
{
try
{
if (!UpdatePaused[coindex.i] && !UpdateHeld[coindex.i] && UpdateProcesses[coindex.i] != null && !(localTime < UpdateProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine");
}
if (!UpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (UpdateProcesses[coindex.i] != null && float.IsNaN(UpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
UpdateProcesses[coindex.i] = ReplacementFunction(UpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.Update);");
}
}
}
if (AutoTriggerManualTimeframe)
{
TriggerManualTimeframeUpdate();
}
else
{
if (++_framesSinceUpdate > FramesUntilMaintenance)
{
_framesSinceUpdate = 0;
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.BeginSample("Maintenance Task");
RemoveUnused();
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
currentCoroutine = default(CoroutineHandle);
}
void FixedUpdate()
{
if (OnPreExecute != null)
OnPreExecute();
if (_nextFixedUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.FixedUpdate };
if (UpdateTimeValues(coindex.seg))
_lastFixedUpdateProcessSlot = _nextFixedUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastFixedUpdateProcessSlot; coindex.i++)
{
try
{
if (!FixedUpdatePaused[coindex.i] && !FixedUpdateHeld[coindex.i] && FixedUpdateProcesses[coindex.i] != null && !(localTime < FixedUpdateProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine");
}
if (!FixedUpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (FixedUpdateProcesses[coindex.i] != null && float.IsNaN(FixedUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
FixedUpdateProcesses[coindex.i] = ReplacementFunction(FixedUpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.FixedUpdate);");
}
}
currentCoroutine = default(CoroutineHandle);
}
}
void LateUpdate()
{
if (OnPreExecute != null)
OnPreExecute();
if (_nextLateUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.LateUpdate };
if (UpdateTimeValues(coindex.seg))
_lastLateUpdateProcessSlot = _nextLateUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastLateUpdateProcessSlot; coindex.i++)
{
try
{
if (!LateUpdatePaused[coindex.i] && !LateUpdateHeld[coindex.i] && LateUpdateProcesses[coindex.i] != null && !(localTime < LateUpdateProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine");
}
if (!LateUpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (LateUpdateProcesses[coindex.i] != null && float.IsNaN(LateUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
LateUpdateProcesses[coindex.i] = ReplacementFunction(LateUpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.LateUpdate);");
}
}
currentCoroutine = default(CoroutineHandle);
}
}
///
/// 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 (OnPreExecute != null)
OnPreExecute();
if (_nextManualTimeframeProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.ManualTimeframe };
if (UpdateTimeValues(coindex.seg))
_lastManualTimeframeProcessSlot = _nextManualTimeframeProcessSlot;
for (coindex.i = 0; coindex.i < _lastManualTimeframeProcessSlot; coindex.i++)
{
try
{
if (!ManualTimeframePaused[coindex.i] && !ManualTimeframeHeld[coindex.i] && ManualTimeframeProcesses[coindex.i] != null &&
!(localTime < ManualTimeframeProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine (Manual Timeframe), " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine (Manual Timeframe)");
}
if (!ManualTimeframeProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (ManualTimeframeProcesses[coindex.i] != null && float.IsNaN(ManualTimeframeProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
ManualTimeframeProcesses[coindex.i] = ReplacementFunction(ManualTimeframeProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.ManualTimeframe);");
}
}
}
if (++_framesSinceUpdate > FramesUntilMaintenance)
{
_framesSinceUpdate = 0;
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.BeginSample("Maintenance Task");
RemoveUnused();
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
currentCoroutine = default(CoroutineHandle);
}
private bool OnEditorStart()
{
#if UNITY_EDITOR
if(EditorApplication.isPlayingOrWillChangePlaymode)
return false;
if (_lastEditorUpdateTime < 0.001)
_lastEditorUpdateTime = (float)EditorApplication.timeSinceStartup;
if (ActiveInstances[_instanceID] == null)
OnEnable();
EditorApplication.update -= OnEditorUpdate;
EditorApplication.update += OnEditorUpdate;
return true;
#else
return false;
#endif
}
#if UNITY_EDITOR
private void OnEditorUpdate()
{
if (OnPreExecute != null)
OnPreExecute();
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 };
if (UpdateTimeValues(coindex.seg))
_lastEditorSlowUpdateProcessSlot = _nextEditorSlowUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastEditorSlowUpdateProcessSlot; coindex.i++)
{
currentCoroutine = _indexToHandle[coindex];
try
{
if (!EditorSlowUpdatePaused[coindex.i] && !EditorSlowUpdateHeld[coindex.i] && EditorSlowUpdateProcesses[coindex.i] != null &&
!(EditorApplication.timeSinceStartup < EditorSlowUpdateProcesses[coindex.i].Current))
{
if (!EditorSlowUpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (EditorSlowUpdateProcesses[coindex.i] != null && float.IsNaN(EditorSlowUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
EditorSlowUpdateProcesses[coindex.i] = ReplacementFunction(EditorSlowUpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.EditorUpdate);");
}
}
}
if(_nextEditorUpdateProcessSlot > 0)
{
ProcessIndex coindex = new ProcessIndex { seg = Segment.EditorUpdate };
if (UpdateTimeValues(coindex.seg))
_lastEditorUpdateProcessSlot = _nextEditorUpdateProcessSlot;
for (coindex.i = 0; coindex.i < _lastEditorUpdateProcessSlot; coindex.i++)
{
currentCoroutine = _indexToHandle[coindex];
try
{
if (!EditorUpdatePaused[coindex.i] && !EditorUpdateHeld[coindex.i] && EditorUpdateProcesses[coindex.i] != null &&
!(EditorApplication.timeSinceStartup < EditorUpdateProcesses[coindex.i].Current))
{
if (!EditorUpdateProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (EditorUpdateProcesses[coindex.i] != null && float.IsNaN(EditorUpdateProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
EditorUpdateProcesses[coindex.i] = ReplacementFunction(EditorUpdateProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.EditorUpdate);");
}
}
}
if (++_framesSinceUpdate > FramesUntilMaintenance)
{
_framesSinceUpdate = 0;
EditorRemoveUnused();
}
currentCoroutine = default(CoroutineHandle);
}
#endif
private IEnumerator _EOFPumpWatcher()
{
while (_nextEndOfFrameProcessSlot > 0)
{
if(!_EOFPumpRan)
base.StartCoroutine(_EOFPump());
_EOFPumpRan = false;
yield return WaitForOneFrame;
}
_EOFPumpRan = false;
}
private System.Collections.IEnumerator _EOFPump()
{
while(_nextEndOfFrameProcessSlot > 0)
{
yield return EofWaitObject;
if (OnPreExecute != null)
OnPreExecute();
ProcessIndex coindex = new ProcessIndex { seg = Segment.EndOfFrame };
_EOFPumpRan = true;
if (UpdateTimeValues(coindex.seg))
_lastEndOfFrameProcessSlot = _nextEndOfFrameProcessSlot;
for(coindex.i = 0;coindex.i < _lastEndOfFrameProcessSlot;coindex.i++)
{
try
{
if (!EndOfFramePaused[coindex.i] && !EndOfFrameHeld[coindex.i] && EndOfFrameProcesses[coindex.i] != null && !(localTime < EndOfFrameProcesses[coindex.i].Current))
{
currentCoroutine = _indexToHandle[coindex];
if (ProfilerDebugAmount != DebugInfoType.None && _indexToHandle.ContainsKey(coindex))
{
Profiler.BeginSample(ProfilerDebugAmount == DebugInfoType.SeperateTags ? ("Processing Coroutine, " +
(_processLayers.ContainsKey(_indexToHandle[coindex]) ? "layer " + _processLayers[_indexToHandle[coindex]] : "no layer") +
(_processTags.ContainsKey(_indexToHandle[coindex]) ? ", tag " + _processTags[_indexToHandle[coindex]] : ", no tag"))
: "Processing Coroutine");
}
if (!EndOfFrameProcesses[coindex.i].MoveNext())
{
if (_indexToHandle.ContainsKey(coindex))
KillCoroutinesOnInstance(_indexToHandle[coindex]);
}
else if (EndOfFrameProcesses[coindex.i] != null && float.IsNaN(EndOfFrameProcesses[coindex.i].Current))
{
if (ReplacementFunction != null)
{
EndOfFrameProcesses[coindex.i] = ReplacementFunction(EndOfFrameProcesses[coindex.i], _indexToHandle[coindex]);
ReplacementFunction = null;
}
coindex.i--;
}
if (ProfilerDebugAmount != DebugInfoType.None)
Profiler.EndSample();
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
if (ex is MissingReferenceException)
Debug.LogError("This exception can probably be fixed by adding \"CancelWith(gameObject)\" when you run the coroutine.\n"
+ "Example: Timing.RunCoroutine(_foo().CancelWith(gameObject), Segment.EndOfFrame);");
}
}
}
currentCoroutine = default(CoroutineHandle);
}
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];
UpdateHeld[inner.i] = UpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextUpdateProcessSlot; outer.i++)
{
UpdateProcesses[outer.i] = null;
UpdatePaused[outer.i] = false;
UpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
FixedUpdateHeld[inner.i] = FixedUpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextFixedUpdateProcessSlot; outer.i++)
{
FixedUpdateProcesses[outer.i] = null;
FixedUpdatePaused[outer.i] = false;
FixedUpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
LateUpdateHeld[inner.i] = LateUpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextLateUpdateProcessSlot; outer.i++)
{
LateUpdateProcesses[outer.i] = null;
LateUpdatePaused[outer.i] = false;
LateUpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
SlowUpdateHeld[inner.i] = SlowUpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextSlowUpdateProcessSlot; outer.i++)
{
SlowUpdateProcesses[outer.i] = null;
SlowUpdatePaused[outer.i] = false;
SlowUpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
RealtimeUpdateHeld[inner.i] = RealtimeUpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextRealtimeUpdateProcessSlot; outer.i++)
{
RealtimeUpdateProcesses[outer.i] = null;
RealtimeUpdatePaused[outer.i] = false;
RealtimeUpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
EndOfFrameHeld[inner.i] = EndOfFrameHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextEndOfFrameProcessSlot; outer.i++)
{
EndOfFrameProcesses[outer.i] = null;
EndOfFramePaused[outer.i] = false;
EndOfFrameHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
ManualTimeframeHeld[inner.i] = ManualTimeframeHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextManualTimeframeProcessSlot; outer.i++)
{
ManualTimeframeProcesses[outer.i] = null;
ManualTimeframePaused[outer.i] = false;
ManualTimeframeHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
EditorUpdateHeld[inner.i] = EditorUpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextEditorUpdateProcessSlot; outer.i++)
{
EditorUpdateProcesses[outer.i] = null;
EditorUpdatePaused[outer.i] = false;
EditorUpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(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];
EditorUpdateHeld[inner.i] = EditorUpdateHeld[outer.i];
if (_indexToHandle.ContainsKey(inner))
{
RemoveGraffiti(_indexToHandle[inner]);
_handleToIndex.Remove(_indexToHandle[inner]);
_indexToHandle.Remove(inner);
}
_handleToIndex[_indexToHandle[outer]] = inner;
_indexToHandle.Add(inner, _indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
inner.i++;
}
}
for (outer.i = inner.i; outer.i < _nextEditorSlowUpdateProcessSlot; outer.i++)
{
EditorSlowUpdateProcesses[outer.i] = null;
EditorSlowUpdatePaused[outer.i] = false;
EditorSlowUpdateHeld[outer.i] = false;
if (_indexToHandle.ContainsKey(outer))
{
RemoveGraffiti(_indexToHandle[outer]);
_handleToIndex.Remove(_indexToHandle[outer]);
_indexToHandle.Remove(outer);
}
}
EditorSlowUpdateCoroutines = _nextEditorSlowUpdateProcessSlot = inner.i;
}
///
/// 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, GameObject gameObj)
{
return coroutine == null ? new CoroutineHandle() : Instance.RunCoroutineInternal(coroutine, Segment.Update,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), null, 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.
/// 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// 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, GameObject gameObj, string tag)
{
return coroutine == null ? new CoroutineHandle() : Instance.RunCoroutineInternal(coroutine, Segment.Update,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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.
/// 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, 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 segment)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, segment, null, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, Segment segment, GameObject gameObj)
{
return coroutine == null ? new CoroutineHandle() : Instance.RunCoroutineInternal(coroutine, segment,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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 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 segment, int layer)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, segment, 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.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public static CoroutineHandle RunCoroutine(IEnumerator coroutine, Segment segment, string tag)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, segment, null, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// 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 segment, GameObject gameObj, string tag)
{
return coroutine == null ? new CoroutineHandle() : Instance.RunCoroutineInternal(coroutine, segment,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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.
/// 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 segment, int layer, string tag)
{
return coroutine == null ? new CoroutineHandle()
: Instance.RunCoroutineInternal(coroutine, segment, 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, GameObject gameObj)
{
return coroutine == null ? new CoroutineHandle() : RunCoroutineInternal(coroutine, Segment.Update,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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.
/// 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 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// 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, GameObject gameObj, string tag)
{
return coroutine == null ? new CoroutineHandle() : RunCoroutineInternal(coroutine, Segment.Update,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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.
/// 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 segment)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, segment, 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, Segment segment, GameObject gameObj)
{
return coroutine == null ? new CoroutineHandle() : RunCoroutineInternal(coroutine, segment,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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.
/// The coroutine's handle, which can be used for Wait and Kill operations.
public CoroutineHandle RunCoroutineOnInstance(IEnumerator coroutine, Segment segment, int layer)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, segment, 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 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 segment, string tag)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, segment, 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// 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 segment, GameObject gameObj, string tag)
{
return coroutine == null ? new CoroutineHandle() : RunCoroutineInternal(coroutine, segment,
gameObj == null ? (int?)null : gameObj.GetInstanceID(), 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.
/// 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 segment, int layer, string tag)
{
return coroutine == null ? new CoroutineHandle()
: RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine in the Update segment, but not while the coroutine with the supplied handle is running.
///
/// The new coroutine's handle.
/// A tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, CoroutineHandle handle, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(handle);
}
else if (IsRunning(handle))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
return handle;
if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = Instance.RunCoroutineInternal(coroutine, Segment.Update, null, null,
new CoroutineHandle(Instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, handle, false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// The new coroutine's handle.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, GameObject gameObj, SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutine(coroutine) : RunCoroutineSingleton(coroutine, gameObj.GetInstanceID(), behaviorOnCollision);
}
///
/// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// The new coroutine's handle.
/// A layer to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, int layer, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(layer);
}
else if (Instance._layeredProcesses.ContainsKey(layer))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = Instance._layeredProcesses[layer].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = Instance.RunCoroutineInternal(coroutine, Segment.Update, layer, null,
new CoroutineHandle(Instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _instance._layeredProcesses[layer], false);
return newCoroutineHandle;
}
}
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 tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, string tag, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(tag);
}
else if (Instance._taggedProcesses.ContainsKey(tag))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = Instance._taggedProcesses[tag].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = Instance.RunCoroutineInternal(coroutine, Segment.Update, null, tag,
new CoroutineHandle(Instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _instance._taggedProcesses[tag], false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied graffitti unless there is already one or more coroutines running with both that
/// tag and layer.
///
/// The new coroutine's handle.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// A tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, GameObject gameObj, string tag, SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutineSingleton(coroutine, tag, behaviorOnCollision)
: RunCoroutineSingleton(coroutine, gameObj.GetInstanceID(), tag, behaviorOnCollision);
}
///
/// Run a new coroutine in the Update segment with the supplied graffitti unless there is already one or more coroutines running with both that
/// tag and layer.
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, int layer, string tag, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.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);
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var matchesEnum = Instance._taggedProcesses[tag].GetEnumerator();
while(matchesEnum.MoveNext())
if (_instance._processLayers.ContainsKey(matchesEnum.Current) && _instance._processLayers[matchesEnum.Current] == layer)
return matchesEnum.Current;
}
if (behaviorOnCollision == SingletonBehavior.Wait)
{
List matches = new List();
var matchesEnum = Instance._taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (Instance._processLayers.ContainsKey(matchesEnum.Current) && Instance._processLayers[matchesEnum.Current] == layer)
matches.Add(matchesEnum.Current);
if(matches.Count > 0)
{
CoroutineHandle newCoroutineHandle = _instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag,
new CoroutineHandle(_instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, matches, false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine, but not while the coroutine with the supplied handle is running.
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, CoroutineHandle handle, Segment segment,
SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(handle);
}
else if (IsRunning(handle))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
return handle;
if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = Instance.RunCoroutineInternal(coroutine, segment, null, null,
new CoroutineHandle(Instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, handle, false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, segment, null, null, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment segment, GameObject gameObj,
SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutine(coroutine, segment) : RunCoroutineSingleton(coroutine, segment, gameObj.GetInstanceID(), behaviorOnCollision);
}
///
/// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment segment, int layer, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(layer);
}
else if (Instance._layeredProcesses.ContainsKey(layer))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = Instance._layeredProcesses[layer].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = Instance.RunCoroutineInternal(coroutine, segment, layer, null,
new CoroutineHandle(Instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _instance._layeredProcesses[layer], false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, segment, 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment segment, string tag, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null)
return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(tag);
}
else if (Instance._taggedProcesses.ContainsKey(tag))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = Instance._taggedProcesses[tag].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = Instance.RunCoroutineInternal(coroutine, segment, null, tag,
new CoroutineHandle(Instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _instance._taggedProcesses[tag], false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, segment, null, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine with the supplied graffitti unless there is already one or more coroutines running with both that tag and layer.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// A tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment segment, GameObject gameObj, string tag,
SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutineSingleton(coroutine, segment, tag, behaviorOnCollision)
: RunCoroutineSingleton(coroutine, segment, gameObj.GetInstanceID(), tag, behaviorOnCollision);
}
///
/// Run a new coroutine with the supplied graffitti unless there is already one or more coroutines running with both that tag and layer.
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public static CoroutineHandle RunCoroutineSingleton(IEnumerator coroutine, Segment segment, int layer, string tag,
SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutines(layer, tag);
return Instance.RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(Instance._instanceID), true);
}
if (!Instance._taggedProcesses.ContainsKey(tag) || !Instance._layeredProcesses.ContainsKey(layer))
return Instance.RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(Instance._instanceID), true);
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var matchesEnum = Instance._taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_instance._processLayers.ContainsKey(matchesEnum.Current) && _instance._processLayers[matchesEnum.Current] == layer)
return matchesEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
List matches = new List();
var matchesEnum = Instance._taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_instance._processLayers.ContainsKey(matchesEnum.Current) && _instance._processLayers[matchesEnum.Current] == layer)
matches.Add(matchesEnum.Current);
if (matches.Count > 0)
{
CoroutineHandle newCoroutineHandle = _instance.RunCoroutineInternal(coroutine, segment, layer, tag,
new CoroutineHandle(_instance._instanceID), false);
WaitForOtherHandles(newCoroutineHandle, matches, false);
return newCoroutineHandle;
}
}
return Instance.RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(Instance._instanceID), true);
}
///
/// Run a new coroutine in the Update segment, but not while the coroutine with the supplied handle is running.
///
/// The new coroutine's handle.
/// A tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, CoroutineHandle handle, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(handle);
}
else if (_handleToIndex.ContainsKey(handle) && !CoindexIsNull(_handleToIndex[handle]))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
return handle;
if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, handle, false);
return newCoroutineHandle;
}
}
return RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// The new coroutine's handle.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, GameObject gameObj, SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutineOnInstance(coroutine)
: RunCoroutineSingletonOnInstance(coroutine, gameObj.GetInstanceID(), behaviorOnCollision);
}
///
/// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// The new coroutine's handle.
/// A layer to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, int layer, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(layer);
}
else if (_layeredProcesses.ContainsKey(layer))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = _layeredProcesses[layer].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _layeredProcesses[layer], false);
return newCoroutineHandle;
}
}
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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, string tag, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(tag);
}
else if (_taggedProcesses.ContainsKey(tag))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = _taggedProcesses[tag].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _taggedProcesses[tag], false);
return newCoroutineHandle;
}
}
return RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine in the Update segment with the supplied graffitti unless there is already one or more coroutines running with both that
/// tag and layer.
///
/// The new coroutine's handle.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// A tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, GameObject gameObj, string tag,
SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutineSingletonOnInstance(coroutine, tag, behaviorOnCollision)
: RunCoroutineSingletonOnInstance(coroutine, gameObj.GetInstanceID(), tag, behaviorOnCollision);
}
///
/// Run a new coroutine in the Update segment with the supplied graffitti unless there is already one or more coroutines running with both that
/// tag and layer.
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, int layer, string tag, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(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);
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer)
return matchesEnum.Current;
}
if (behaviorOnCollision == SingletonBehavior.Wait)
{
List matches = new List();
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer)
matches.Add(matchesEnum.Current);
if (matches.Count > 0)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, matches, false);
return newCoroutineHandle;
}
}
return RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), true);
}
///
/// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// The new coroutine's handle.
/// The segment that the coroutine should run in.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment segment, GameObject gameObj,
SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutineOnInstance(coroutine, segment)
: RunCoroutineSingletonOnInstance(coroutine, segment, gameObj.GetInstanceID(), behaviorOnCollision);
}
///
/// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer.
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment segment, int layer, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(layer);
}
else if (_layeredProcesses.ContainsKey(layer))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = _layeredProcesses[layer].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, segment, layer, null, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _layeredProcesses[layer], false);
return newCoroutineHandle;
}
}
return RunCoroutineInternal(coroutine, segment, 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment segment, string tag, SingletonBehavior behaviorOnCollision)
{
if (coroutine == null)
return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(tag);
}
else if (_taggedProcesses.ContainsKey(tag))
{
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var indexEnum = _taggedProcesses[tag].GetEnumerator();
while (indexEnum.MoveNext())
if (IsRunning(indexEnum.Current))
return indexEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, segment, null, tag, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, _taggedProcesses[tag], false);
return newCoroutineHandle;
}
}
return RunCoroutineInternal(coroutine, segment, 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.
/// The new coroutine will be put on a layer corresponding to this gameObject.
/// A tag to attach to the coroutine, and to check for existing instances.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment segment, GameObject gameObj, string tag,
SingletonBehavior behaviorOnCollision)
{
return gameObj == null ? RunCoroutineSingletonOnInstance(coroutine, segment, tag, behaviorOnCollision)
: RunCoroutineSingletonOnInstance(coroutine, segment, gameObj.GetInstanceID(), tag, behaviorOnCollision);
}
///
/// 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.
/// Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are
/// currently running.
/// The newly created or existing handle.
public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator coroutine, Segment segment, int layer, string tag,
SingletonBehavior behaviorOnCollision)
{
if (coroutine == null) return new CoroutineHandle();
if (behaviorOnCollision == SingletonBehavior.Overwrite)
{
KillCoroutinesOnInstance(layer, tag);
return RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(_instanceID), true);
}
if (!_taggedProcesses.ContainsKey(tag) || !_layeredProcesses.ContainsKey(layer))
return RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(_instanceID), true);
if (behaviorOnCollision == SingletonBehavior.Abort)
{
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer)
return matchesEnum.Current;
}
else if (behaviorOnCollision == SingletonBehavior.Wait)
{
List matches = new List();
var matchesEnum = _taggedProcesses[tag].GetEnumerator();
while (matchesEnum.MoveNext())
if (_processLayers.ContainsKey(matchesEnum.Current) && _processLayers[matchesEnum.Current] == layer)
matches.Add(matchesEnum.Current);
if (matches.Count > 0)
{
CoroutineHandle newCoroutineHandle = RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(_instanceID), false);
WaitForOtherHandles(newCoroutineHandle, matches, false);
return newCoroutineHandle;
}
}
return RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(_instanceID), true);
}
private CoroutineHandle RunCoroutineInternal(IEnumerator coroutine, Segment segment, int? layer, string tag, CoroutineHandle handle, bool prewarm)
{
ProcessIndex slot = new ProcessIndex { seg = segment };
if (_handleToIndex.ContainsKey(handle))
{
_indexToHandle.Remove(_handleToIndex[handle]);
_handleToIndex.Remove(handle);
}
float currentLocalTime = localTime;
float currentDeltaTime = deltaTime;
CoroutineHandle cashedHandle = currentCoroutine;
currentCoroutine = handle;
try
{
switch (segment)
{
case Segment.Update:
if (_nextUpdateProcessSlot >= UpdateProcesses.Length)
{
IEnumerator[] oldProcArray = UpdateProcesses;
bool[] oldPausedArray = UpdatePaused;
bool[] oldHeldArray = UpdateHeld;
UpdateProcesses = new IEnumerator[UpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
UpdatePaused = new bool[UpdateProcesses.Length];
UpdateHeld = new bool[UpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
UpdateProcesses[i] = oldProcArray[i];
UpdatePaused[i] = oldPausedArray[i];
UpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastUpdateProcessSlot = _nextUpdateProcessSlot;
slot.i = _nextUpdateProcessSlot++;
UpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!UpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (UpdateProcesses[slot.i] != null && float.IsNaN(UpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
UpdateProcesses[slot.i] = ReplacementFunction(UpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !UpdatePaused[slot.i] && !UpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
case Segment.FixedUpdate:
if (_nextFixedUpdateProcessSlot >= FixedUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = FixedUpdateProcesses;
bool[] oldPausedArray = FixedUpdatePaused;
bool[] oldHeldArray = FixedUpdateHeld;
FixedUpdateProcesses = new IEnumerator[FixedUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
FixedUpdatePaused = new bool[FixedUpdateProcesses.Length];
FixedUpdateHeld = new bool[FixedUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
FixedUpdateProcesses[i] = oldProcArray[i];
FixedUpdatePaused[i] = oldPausedArray[i];
FixedUpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastFixedUpdateProcessSlot = _nextFixedUpdateProcessSlot;
slot.i = _nextFixedUpdateProcessSlot++;
FixedUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!FixedUpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (FixedUpdateProcesses[slot.i] != null && float.IsNaN(FixedUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
FixedUpdateProcesses[slot.i] = ReplacementFunction(FixedUpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !FixedUpdatePaused[slot.i] && !FixedUpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
case Segment.LateUpdate:
if (_nextLateUpdateProcessSlot >= LateUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = LateUpdateProcesses;
bool[] oldPausedArray = LateUpdatePaused;
bool[] oldHeldArray = LateUpdateHeld;
LateUpdateProcesses = new IEnumerator[LateUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
LateUpdatePaused = new bool[LateUpdateProcesses.Length];
LateUpdateHeld = new bool[LateUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
LateUpdateProcesses[i] = oldProcArray[i];
LateUpdatePaused[i] = oldPausedArray[i];
LateUpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastLateUpdateProcessSlot = _nextLateUpdateProcessSlot;
slot.i = _nextLateUpdateProcessSlot++;
LateUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!LateUpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (LateUpdateProcesses[slot.i] != null && float.IsNaN(LateUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
LateUpdateProcesses[slot.i] = ReplacementFunction(LateUpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !LateUpdatePaused[slot.i] && !LateUpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
case Segment.SlowUpdate:
if (_nextSlowUpdateProcessSlot >= SlowUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = SlowUpdateProcesses;
bool[] oldPausedArray = SlowUpdatePaused;
bool[] oldHeldArray = SlowUpdateHeld;
SlowUpdateProcesses = new IEnumerator[SlowUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
SlowUpdatePaused = new bool[SlowUpdateProcesses.Length];
SlowUpdateHeld = new bool[SlowUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
SlowUpdateProcesses[i] = oldProcArray[i];
SlowUpdatePaused[i] = oldPausedArray[i];
SlowUpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastSlowUpdateProcessSlot = _nextSlowUpdateProcessSlot;
slot.i = _nextSlowUpdateProcessSlot++;
SlowUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!SlowUpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (SlowUpdateProcesses[slot.i] != null && float.IsNaN(SlowUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
SlowUpdateProcesses[slot.i] = ReplacementFunction(SlowUpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !SlowUpdatePaused[slot.i] && !SlowUpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
case Segment.RealtimeUpdate:
if (_nextRealtimeUpdateProcessSlot >= RealtimeUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = RealtimeUpdateProcesses;
bool[] oldPausedArray = RealtimeUpdatePaused;
bool[] oldHeldArray = RealtimeUpdateHeld;
RealtimeUpdateProcesses = new IEnumerator[RealtimeUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
RealtimeUpdatePaused = new bool[RealtimeUpdateProcesses.Length];
RealtimeUpdateHeld = new bool[RealtimeUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
RealtimeUpdateProcesses[i] = oldProcArray[i];
RealtimeUpdatePaused[i] = oldPausedArray[i];
RealtimeUpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastRealtimeUpdateProcessSlot = _nextRealtimeUpdateProcessSlot;
slot.i = _nextRealtimeUpdateProcessSlot++;
RealtimeUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!RealtimeUpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (RealtimeUpdateProcesses[slot.i] != null && float.IsNaN(RealtimeUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
RealtimeUpdateProcesses[slot.i] = ReplacementFunction(RealtimeUpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !RealtimeUpdatePaused[slot.i] && !RealtimeUpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
#if UNITY_EDITOR
case Segment.EditorUpdate:
if (!OnEditorStart())
return new CoroutineHandle();
if (handle.Key == 0)
handle = new CoroutineHandle(_instanceID);
if (_nextEditorUpdateProcessSlot >= EditorUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = EditorUpdateProcesses;
bool[] oldPausedArray = EditorUpdatePaused;
bool[] oldHeldArray = EditorUpdateHeld;
EditorUpdateProcesses = new IEnumerator[EditorUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
EditorUpdatePaused = new bool[EditorUpdateProcesses.Length];
EditorUpdateHeld = new bool[EditorUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
EditorUpdateProcesses[i] = oldProcArray[i];
EditorUpdatePaused[i] = oldPausedArray[i];
EditorUpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastEditorUpdateProcessSlot = _nextEditorUpdateProcessSlot;
slot.i = _nextEditorUpdateProcessSlot++;
EditorUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!EditorUpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (EditorUpdateProcesses[slot.i] != null && float.IsNaN(EditorUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
EditorUpdateProcesses[slot.i] = ReplacementFunction(EditorUpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !EditorUpdatePaused[slot.i] && !EditorUpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
case Segment.EditorSlowUpdate:
if (!OnEditorStart())
return new CoroutineHandle();
if (handle.Key == 0)
handle = new CoroutineHandle(_instanceID);
if (_nextEditorSlowUpdateProcessSlot >= EditorSlowUpdateProcesses.Length)
{
IEnumerator[] oldProcArray = EditorSlowUpdateProcesses;
bool[] oldPausedArray = EditorSlowUpdatePaused;
bool[] oldHeldArray = EditorSlowUpdateHeld;
EditorSlowUpdateProcesses = new IEnumerator[EditorSlowUpdateProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
EditorSlowUpdatePaused = new bool[EditorSlowUpdateProcesses.Length];
EditorSlowUpdateHeld = new bool[EditorSlowUpdateProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
EditorSlowUpdateProcesses[i] = oldProcArray[i];
EditorSlowUpdatePaused[i] = oldPausedArray[i];
EditorSlowUpdateHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastEditorSlowUpdateProcessSlot = _nextEditorSlowUpdateProcessSlot;
slot.i = _nextEditorSlowUpdateProcessSlot++;
EditorSlowUpdateProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
while (prewarm)
{
if (!EditorSlowUpdateProcesses[slot.i].MoveNext())
{
if (_indexToHandle.ContainsKey(slot))
KillCoroutinesOnInstance(_indexToHandle[slot]);
prewarm = false;
}
else if (EditorSlowUpdateProcesses[slot.i] != null && float.IsNaN(EditorSlowUpdateProcesses[slot.i].Current))
{
if (ReplacementFunction != null)
{
EditorSlowUpdateProcesses[slot.i] = ReplacementFunction(EditorSlowUpdateProcesses[slot.i], _indexToHandle[slot]);
ReplacementFunction = null;
}
prewarm = !EditorSlowUpdatePaused[slot.i] && !EditorSlowUpdateHeld[slot.i];
}
else
{
prewarm = false;
}
}
break;
#endif
case Segment.EndOfFrame:
if (_nextEndOfFrameProcessSlot >= EndOfFrameProcesses.Length)
{
IEnumerator[] oldProcArray = EndOfFrameProcesses;
bool[] oldPausedArray = EndOfFramePaused;
bool[] oldHeldArray = EndOfFrameHeld;
EndOfFrameProcesses = new IEnumerator[EndOfFrameProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
EndOfFramePaused = new bool[EndOfFrameProcesses.Length];
EndOfFrameHeld = new bool[EndOfFrameProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
EndOfFrameProcesses[i] = oldProcArray[i];
EndOfFramePaused[i] = oldPausedArray[i];
EndOfFrameHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastEndOfFrameProcessSlot = _nextEndOfFrameProcessSlot;
slot.i = _nextEndOfFrameProcessSlot++;
EndOfFrameProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
_eofWatcherHandle = RunCoroutineSingletonOnInstance(_EOFPumpWatcher(), _eofWatcherHandle, SingletonBehavior.Abort);
break;
case Segment.ManualTimeframe:
if (_nextManualTimeframeProcessSlot >= ManualTimeframeProcesses.Length)
{
IEnumerator[] oldProcArray = ManualTimeframeProcesses;
bool[] oldPausedArray = ManualTimeframePaused;
bool[] oldHeldArray = ManualTimeframeHeld;
ManualTimeframeProcesses = new IEnumerator[ManualTimeframeProcesses.Length + (ProcessArrayChunkSize * _expansions++)];
ManualTimeframePaused = new bool[ManualTimeframeProcesses.Length];
ManualTimeframeHeld = new bool[ManualTimeframeProcesses.Length];
for (int i = 0; i < oldProcArray.Length; i++)
{
ManualTimeframeProcesses[i] = oldProcArray[i];
ManualTimeframePaused[i] = oldPausedArray[i];
ManualTimeframeHeld[i] = oldHeldArray[i];
}
}
if (UpdateTimeValues(slot.seg))
_lastManualTimeframeProcessSlot = _nextManualTimeframeProcessSlot;
slot.i = _nextManualTimeframeProcessSlot++;
ManualTimeframeProcesses[slot.i] = coroutine;
if (null != tag)
AddTagOnInstance(tag, handle);
if (layer.HasValue)
AddLayerOnInstance((int)layer, handle);
_indexToHandle.Add(slot, handle);
_handleToIndex.Add(handle, slot);
break;
default:
handle = new CoroutineHandle();
break;
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
}
localTime = currentLocalTime;
deltaTime = currentDeltaTime;
currentCoroutine = cashedHandle;
return handle;
}
///
/// 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];
UpdateHeld = new bool[InitialBufferSizeLarge];
UpdateCoroutines = 0;
_nextUpdateProcessSlot = 0;
LateUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
LateUpdatePaused = new bool[InitialBufferSizeSmall];
LateUpdateHeld = new bool[InitialBufferSizeSmall];
LateUpdateCoroutines = 0;
_nextLateUpdateProcessSlot = 0;
FixedUpdateProcesses = new IEnumerator[InitialBufferSizeMedium];
FixedUpdatePaused = new bool[InitialBufferSizeMedium];
FixedUpdateHeld = new bool[InitialBufferSizeMedium];
FixedUpdateCoroutines = 0;
_nextFixedUpdateProcessSlot = 0;
SlowUpdateProcesses = new IEnumerator[InitialBufferSizeMedium];
SlowUpdatePaused = new bool[InitialBufferSizeMedium];
SlowUpdateHeld = new bool[InitialBufferSizeMedium];
SlowUpdateCoroutines = 0;
_nextSlowUpdateProcessSlot = 0;
RealtimeUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
RealtimeUpdatePaused = new bool[InitialBufferSizeSmall];
RealtimeUpdateHeld = new bool[InitialBufferSizeSmall];
RealtimeUpdateCoroutines = 0;
_nextRealtimeUpdateProcessSlot = 0;
EditorUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
EditorUpdatePaused = new bool[InitialBufferSizeSmall];
EditorUpdateHeld = new bool[InitialBufferSizeSmall];
EditorUpdateCoroutines = 0;
_nextEditorUpdateProcessSlot = 0;
EditorSlowUpdateProcesses = new IEnumerator[InitialBufferSizeSmall];
EditorSlowUpdatePaused = new bool[InitialBufferSizeSmall];
EditorSlowUpdateHeld = new bool[InitialBufferSizeSmall];
EditorSlowUpdateCoroutines = 0;
_nextEditorSlowUpdateProcessSlot = 0;
EndOfFrameProcesses = new IEnumerator[InitialBufferSizeSmall];
EndOfFramePaused = new bool[InitialBufferSizeSmall];
EndOfFrameHeld = new bool[InitialBufferSizeSmall];
EndOfFrameCoroutines = 0;
_nextEndOfFrameProcessSlot = 0;
ManualTimeframeProcesses = new IEnumerator[InitialBufferSizeSmall];
ManualTimeframePaused = new bool[InitialBufferSizeSmall];
ManualTimeframeHeld = 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);
Links.Clear();
#if UNITY_EDITOR
EditorApplication.update -= OnEditorUpdate;
#endif
return retVal;
}
///
/// 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[handle.Key] != null ? GetInstance(handle.Key).KillCoroutinesOnInstance(handle) : 0;
}
///
/// Kills all the coroutines in a list of coroutine handles.
///
/// A list of handles to be killed.
/// The number of coroutines that were found and killed.
public static int KillCoroutines(IEnumerable handles)
{
int count = 0;
foreach (CoroutineHandle handle in handles)
count += KillCoroutines(handle);
return count;
}
///
/// 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 (Normally 0 or 1).
public int KillCoroutinesOnInstance(CoroutineHandle handle)
{
int count = 0;
if (_handleToIndex.ContainsKey(handle))
{
if (_waitingTriggers.ContainsKey(handle))
CloseWaitingProcess(handle);
if (Nullify(handle))
count++;
RemoveGraffiti(handle);
}
if (Links.ContainsKey(handle))
{
var linksEnum = Links[handle].GetEnumerator();
Links.Remove(handle);
while (linksEnum.MoveNext())
count += KillCoroutines(linksEnum.Current);
}
return count;
}
///
/// Kills all coroutines on the given layer.
///
/// All coroutines on the layer corresponding with this GameObject will be killed.
/// The number of coroutines that were found and killed.
public static int KillCoroutines(GameObject gameObj)
{
return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(gameObj.GetInstanceID());
}
///
/// Kills all coroutines on the given layer.
///
/// All coroutines on the layer corresponding with this GameObject will be killed.
/// The number of coroutines that were found and killed.
public int KillCoroutinesOnInstance(GameObject gameObj)
{
return KillCoroutinesOnInstance(gameObj.GetInstanceID());
}
///
/// 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 (Nullify(matchEnum.Current))
{
if (_waitingTriggers.ContainsKey(matchEnum.Current))
CloseWaitingProcess(matchEnum.Current);
numberFound++;
}
RemoveGraffiti(matchEnum.Current);
if (Links.ContainsKey(matchEnum.Current))
{
var linksEnum = Links[matchEnum.Current].GetEnumerator();
Links.Remove(matchEnum.Current);
while (linksEnum.MoveNext())
numberFound += KillCoroutines(linksEnum.Current);
}
}
return numberFound;
}
///
/// 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 (Nullify(_handleToIndex[matchEnum.Current]))
{
if(_waitingTriggers.ContainsKey(matchEnum.Current))
CloseWaitingProcess(matchEnum.Current);
numberFound++;
}
RemoveGraffiti(matchEnum.Current);
if (Links.ContainsKey(matchEnum.Current))
{
var linksEnum = Links[matchEnum.Current].GetEnumerator();
Links.Remove(matchEnum.Current);
while (linksEnum.MoveNext())
numberFound += KillCoroutines(linksEnum.Current);
}
}
return numberFound;
}
///
/// Kills all coroutines with the given tag on the given layer.
///
/// All coroutines on the layer corresponding with this GameObject 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(GameObject gameObj, string tag)
{
return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(gameObj.GetInstanceID(), tag);
}
///
/// Kills all coroutines with the given tag on the given layer.
///
/// All coroutines on the layer corresponding with this GameObject 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(GameObject gameObj, string tag)
{
return KillCoroutinesOnInstance(gameObj.GetInstanceID(), 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 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(_handleToIndex[indexesEnum.Current]) || !_layeredProcesses[layer].Contains(indexesEnum.Current) ||
!Nullify(indexesEnum.Current))
continue;
if (_waitingTriggers.ContainsKey(indexesEnum.Current))
CloseWaitingProcess(indexesEnum.Current);
count++;
RemoveGraffiti(indexesEnum.Current);
if (Links.ContainsKey(indexesEnum.Current))
{
var linksEnum = Links[indexesEnum.Current].GetEnumerator();
Links.Remove(indexesEnum.Current);
while (linksEnum.MoveNext())
KillCoroutines(linksEnum.Current);
}
if (!_taggedProcesses.ContainsKey(tag) || !_layeredProcesses.ContainsKey(layer))
break;
indexesEnum = _taggedProcesses[tag].GetEnumerator();
}
return count;
}
///
/// 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)
{
if (ID >= 0x10)
return null;
return ActiveInstances[ID];
}
///
/// 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 localTime + waitTime;
}
private bool UpdateTimeValues(Segment segment)
{
switch (segment)
{
case Segment.Update:
if (_currentUpdateFrame != Time.frameCount)
{
deltaTime = Time.deltaTime;
_lastUpdateTime += deltaTime;
localTime = _lastUpdateTime;
_currentUpdateFrame = Time.frameCount;
return true;
}
else
{
deltaTime = Time.deltaTime;
localTime = _lastUpdateTime;
return false;
}
case Segment.LateUpdate:
if (_currentLateUpdateFrame != Time.frameCount)
{
deltaTime = Time.deltaTime;
_lastLateUpdateTime += deltaTime;
localTime = _lastLateUpdateTime;
_currentLateUpdateFrame = Time.frameCount;
return true;
}
else
{
deltaTime = Time.deltaTime;
localTime = _lastLateUpdateTime;
return false;
}
case Segment.FixedUpdate:
deltaTime = Time.fixedDeltaTime;
localTime = Time.fixedTime;
if (_lastFixedUpdateTime + 0.0001f < Time.fixedTime)
{
_lastFixedUpdateTime = Time.fixedTime;
return true;
}
return false;
case Segment.SlowUpdate:
if (_currentSlowUpdateFrame != Time.frameCount)
{
deltaTime = _lastSlowUpdateDeltaTime = Time.realtimeSinceStartup - _lastSlowUpdateTime;
localTime = _lastSlowUpdateTime = Time.realtimeSinceStartup;
_currentSlowUpdateFrame = Time.frameCount;
return true;
}
else
{
localTime = _lastSlowUpdateTime;
deltaTime = _lastSlowUpdateDeltaTime;
return false;
}
case Segment.RealtimeUpdate:
if (_currentRealtimeUpdateFrame != Time.frameCount)
{
deltaTime = Time.unscaledDeltaTime;
_lastRealtimeUpdateTime += deltaTime;
localTime = _lastRealtimeUpdateTime;
_currentRealtimeUpdateFrame = Time.frameCount;
return true;
}
else
{
deltaTime = Time.unscaledDeltaTime;
localTime = _lastRealtimeUpdateTime;
return false;
}
#if UNITY_EDITOR
case Segment.EditorUpdate:
if (_lastEditorUpdateTime + 0.0001 < EditorApplication.timeSinceStartup)
{
_lastEditorUpdateDeltaTime = (float)EditorApplication.timeSinceStartup - _lastEditorUpdateTime;
if (_lastEditorUpdateDeltaTime > Time.maximumDeltaTime)
_lastEditorUpdateDeltaTime = Time.maximumDeltaTime;
deltaTime = _lastEditorUpdateDeltaTime;
localTime = _lastEditorUpdateTime = (float)EditorApplication.timeSinceStartup;
return true;
}
else
{
deltaTime = _lastEditorUpdateDeltaTime;
localTime = _lastEditorUpdateTime;
return false;
}
case Segment.EditorSlowUpdate:
if (_lastEditorSlowUpdateTime + 0.0001 < EditorApplication.timeSinceStartup)
{
_lastEditorSlowUpdateDeltaTime = (float)EditorApplication.timeSinceStartup - _lastEditorSlowUpdateTime;
deltaTime = _lastEditorSlowUpdateDeltaTime;
localTime = _lastEditorSlowUpdateTime = (float)EditorApplication.timeSinceStartup;
return true;
}
else
{
deltaTime = _lastEditorSlowUpdateDeltaTime;
localTime = _lastEditorSlowUpdateTime;
return false;
}
#endif
case Segment.EndOfFrame:
if (_currentEndOfFrameFrame != Time.frameCount)
{
deltaTime = Time.deltaTime;
_lastEndOfFrameTime += deltaTime;
localTime = _lastEndOfFrameTime;
_currentEndOfFrameFrame = Time.frameCount;
return true;
}
else
{
deltaTime = Time.deltaTime;
localTime = _lastEndOfFrameTime;
return false;
}
case Segment.ManualTimeframe:
float timeCalculated = SetManualTimeframeTime == null ? Time.time : SetManualTimeframeTime(_lastManualTimeframeTime);
if (_lastManualTimeframeTime + 0.0001 < timeCalculated && _lastManualTimeframeTime - 0.0001 > timeCalculated)
{
localTime = timeCalculated;
deltaTime = localTime - _lastManualTimeframeTime;
if (deltaTime > Time.maximumDeltaTime)
deltaTime = Time.maximumDeltaTime;
_lastManualTimeframeDeltaTime = deltaTime;
_lastManualTimeframeTime = timeCalculated;
return true;
}
else
{
deltaTime = _lastManualTimeframeDeltaTime;
localTime = _lastManualTimeframeTime;
return false;
}
}
return true;
}
private float GetSegmentTime(Segment segment)
{
switch (segment)
{
case Segment.Update:
if (_currentUpdateFrame == Time.frameCount)
return _lastUpdateTime;
else
return _lastUpdateTime + Time.deltaTime;
case Segment.LateUpdate:
if (_currentUpdateFrame == Time.frameCount)
return _lastLateUpdateTime;
else
return _lastLateUpdateTime + Time.deltaTime;
case Segment.FixedUpdate:
return Time.fixedTime;
case Segment.SlowUpdate:
return Time.realtimeSinceStartup;
case Segment.RealtimeUpdate:
if (_currentRealtimeUpdateFrame == Time.frameCount)
return _lastRealtimeUpdateTime;
else
return _lastRealtimeUpdateTime + Time.unscaledDeltaTime;
#if UNITY_EDITOR
case Segment.EditorUpdate:
case Segment.EditorSlowUpdate:
return (float)EditorApplication.timeSinceStartup;
#endif
case Segment.EndOfFrame:
if (_currentUpdateFrame == Time.frameCount)
return _lastEndOfFrameTime;
else
return _lastEndOfFrameTime + Time.deltaTime;
case Segment.ManualTimeframe:
return _lastManualTimeframeTime;
default:
return 0f;
}
}
///
/// This will pause all coroutines running on the main 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)
{
count++;
UpdatePaused[i] = true;
if (UpdateProcesses[i].Current > GetSegmentTime(Segment.Update))
UpdateProcesses[i] = _InjectDelay(UpdateProcesses[i],
UpdateProcesses[i].Current - GetSegmentTime(Segment.Update));
}
}
for (i = 0; i < _nextLateUpdateProcessSlot; i++)
{
if (!LateUpdatePaused[i] && LateUpdateProcesses[i] != null)
{
count++;
LateUpdatePaused[i] = true;
if (LateUpdateProcesses[i].Current > GetSegmentTime(Segment.LateUpdate))
LateUpdateProcesses[i] = _InjectDelay(LateUpdateProcesses[i],
LateUpdateProcesses[i].Current - GetSegmentTime(Segment.LateUpdate));
}
}
for (i = 0; i < _nextFixedUpdateProcessSlot; i++)
{
if (!FixedUpdatePaused[i] && FixedUpdateProcesses[i] != null)
{
count++;
FixedUpdatePaused[i] = true;
if (FixedUpdateProcesses[i].Current > GetSegmentTime(Segment.FixedUpdate))
FixedUpdateProcesses[i] = _InjectDelay(FixedUpdateProcesses[i],
FixedUpdateProcesses[i].Current - GetSegmentTime(Segment.FixedUpdate));
}
}
for (i = 0; i < _nextSlowUpdateProcessSlot; i++)
{
if (!SlowUpdatePaused[i] && SlowUpdateProcesses[i] != null)
{
count++;
SlowUpdatePaused[i] = true;
if (SlowUpdateProcesses[i].Current > GetSegmentTime(Segment.SlowUpdate))
SlowUpdateProcesses[i] = _InjectDelay(SlowUpdateProcesses[i],
SlowUpdateProcesses[i].Current - GetSegmentTime(Segment.SlowUpdate));
}
}
for (i = 0; i < _nextRealtimeUpdateProcessSlot; i++)
{
if (!RealtimeUpdatePaused[i] && RealtimeUpdateProcesses[i] != null)
{
count++;
RealtimeUpdatePaused[i] = true;
if (RealtimeUpdateProcesses[i].Current > GetSegmentTime(Segment.RealtimeUpdate))
RealtimeUpdateProcesses[i] = _InjectDelay(RealtimeUpdateProcesses[i],
RealtimeUpdateProcesses[i].Current - GetSegmentTime(Segment.RealtimeUpdate));
}
}
for (i = 0; i < _nextEditorUpdateProcessSlot; i++)
{
if (!EditorUpdatePaused[i] && EditorUpdateProcesses[i] != null)
{
count++;
EditorUpdatePaused[i] = true;
if (EditorUpdateProcesses[i].Current > GetSegmentTime(Segment.EditorUpdate))
EditorUpdateProcesses[i] = _InjectDelay(EditorUpdateProcesses[i],
EditorUpdateProcesses[i].Current - GetSegmentTime(Segment.EditorUpdate));
}
}
for (i = 0; i < _nextEditorSlowUpdateProcessSlot; i++)
{
if (!EditorSlowUpdatePaused[i] && EditorSlowUpdateProcesses[i] != null)
{
count++;
EditorSlowUpdatePaused[i] = true;
if (EditorSlowUpdateProcesses[i].Current > GetSegmentTime(Segment.EditorSlowUpdate))
EditorSlowUpdateProcesses[i] = _InjectDelay(EditorSlowUpdateProcesses[i],
EditorSlowUpdateProcesses[i].Current - GetSegmentTime(Segment.EditorSlowUpdate));
}
}
for (i = 0; i < _nextEndOfFrameProcessSlot; i++)
{
if (!EndOfFramePaused[i] && EndOfFrameProcesses[i] != null)
{
count++;
EndOfFramePaused[i] = true;
if (EndOfFrameProcesses[i].Current > GetSegmentTime(Segment.EndOfFrame))
EndOfFrameProcesses[i] = _InjectDelay(EndOfFrameProcesses[i],
EndOfFrameProcesses[i].Current - GetSegmentTime(Segment.EndOfFrame));
}
}
for (i = 0; i < _nextManualTimeframeProcessSlot; i++)
{
if (!ManualTimeframePaused[i] && ManualTimeframeProcesses[i] != null)
{
count++;
ManualTimeframePaused[i] = true;
if (ManualTimeframeProcesses[i].Current > GetSegmentTime(Segment.ManualTimeframe))
ManualTimeframeProcesses[i] = _InjectDelay(ManualTimeframeProcesses[i],
ManualTimeframeProcesses[i].Current - GetSegmentTime(Segment.ManualTimeframe));
}
}
var indexesEnum = Links.GetEnumerator();
while(indexesEnum.MoveNext())
{
if (!_handleToIndex.ContainsKey(indexesEnum.Current.Key)) continue;
var linksEnum = indexesEnum.Current.Value.GetEnumerator();
while(linksEnum.MoveNext())
count += PauseCoroutines(linksEnum.Current);
}
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[handle.Key] != null ? 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 (Normally 0 or 1).
public int PauseCoroutinesOnInstance(CoroutineHandle handle)
{
int count = 0;
if (_handleToIndex.ContainsKey(handle) && !CoindexIsNull(_handleToIndex[handle]) && !SetPause(_handleToIndex[handle], true))
count++;
if (Links.ContainsKey(handle))
{
var links = Links[handle];
Links.Remove(handle);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += PauseCoroutines(linksEnum.Current);
Links.Add(handle, links);
}
return count;
}
///
/// This will pause any matching coroutines until ResumeCoroutines is called.
///
/// A list of handles to coroutines you want to pause.
/// The number of coroutines that were paused.
public static int PauseCoroutines(IEnumerable handles)
{
int total = 0;
var handlesEnum = handles.GetEnumerator();
while (!handlesEnum.MoveNext())
total += PauseCoroutines(handlesEnum.Current);
return total;
}
///
/// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called.
///
/// All coroutines on the layer corresponding with this GameObject will be paused.
/// The number of coroutines that were paused.
public static int PauseCoroutines(GameObject gameObj)
{
return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(gameObj);
}
///
/// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// All coroutines on the layer corresponding with this GameObject will be paused.
/// The number of coroutines that were paused.
public int PauseCoroutinesOnInstance(GameObject gameObj)
{
return gameObj == null ? 0 : PauseCoroutinesOnInstance(gameObj.GetInstanceID());
}
///
/// 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(_handleToIndex[matchesEnum.Current]) && !SetPause(_handleToIndex[matchesEnum.Current], true))
count++;
if (Links.ContainsKey(matchesEnum.Current))
{
var links = Links[matchesEnum.Current];
Links.Remove(matchesEnum.Current);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += PauseCoroutines(linksEnum.Current);
Links.Add(matchesEnum.Current, links);
}
}
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(_handleToIndex[matchesEnum.Current]) && !SetPause(_handleToIndex[matchesEnum.Current], true))
count++;
if (Links.ContainsKey(matchesEnum.Current))
{
var links = Links[matchesEnum.Current];
Links.Remove(matchesEnum.Current);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += PauseCoroutines(linksEnum.Current);
Links.Add(matchesEnum.Current, links);
}
}
return count;
}
///
/// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called.
///
/// All coroutines on the layer corresponding with this GameObject will be paused.
/// Any coroutines with a matching tag will be paused.
/// The number of coroutines that were paused.
public static int PauseCoroutines(GameObject gameObj, string tag)
{
return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(gameObj.GetInstanceID(), tag);
}
///
/// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called.
///
/// All coroutines on the layer corresponding with this GameObject will be paused.
/// Any coroutines with a matching tag will be paused.
/// The number of coroutines that were paused.
public int PauseCoroutinesOnInstance(GameObject gameObj, string tag)
{
return gameObj == null ? 0 : PauseCoroutinesOnInstance(gameObj.GetInstanceID(), tag);
}
///
/// 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(_handleToIndex[matchesEnum.Current]))
{
if (!SetPause(_handleToIndex[matchesEnum.Current], true))
count++;
if (Links.ContainsKey(matchesEnum.Current))
{
var links = Links[matchesEnum.Current];
Links.Remove(matchesEnum.Current);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += PauseCoroutines(linksEnum.Current);
Links.Add(matchesEnum.Current, links);
}
}
}
return count;
}
///
/// 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;
ProcessIndex coindex;
for (coindex.i = 0, coindex.seg = Segment.Update; coindex.i < _nextUpdateProcessSlot; coindex.i++)
{
if (UpdatePaused[coindex.i] && UpdateProcesses[coindex.i] != null)
{
UpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.LateUpdate; coindex.i < _nextLateUpdateProcessSlot; coindex.i++)
{
if (LateUpdatePaused[coindex.i] && LateUpdateProcesses[coindex.i] != null)
{
LateUpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.FixedUpdate; coindex.i < _nextFixedUpdateProcessSlot; coindex.i++)
{
if (FixedUpdatePaused[coindex.i] && FixedUpdateProcesses[coindex.i] != null)
{
FixedUpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.SlowUpdate; coindex.i < _nextSlowUpdateProcessSlot; coindex.i++)
{
if (SlowUpdatePaused[coindex.i] && SlowUpdateProcesses[coindex.i] != null)
{
SlowUpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.RealtimeUpdate; coindex.i < _nextRealtimeUpdateProcessSlot; coindex.i++)
{
if (RealtimeUpdatePaused[coindex.i] && RealtimeUpdateProcesses[coindex.i] != null)
{
RealtimeUpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.EditorUpdate; coindex.i < _nextEditorUpdateProcessSlot; coindex.i++)
{
if (EditorUpdatePaused[coindex.i] && EditorUpdateProcesses[coindex.i] != null)
{
EditorUpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.EditorSlowUpdate; coindex.i < _nextEditorSlowUpdateProcessSlot; coindex.i++)
{
if (EditorSlowUpdatePaused[coindex.i] && EditorSlowUpdateProcesses[coindex.i] != null)
{
EditorSlowUpdatePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.EndOfFrame; coindex.i < _nextEndOfFrameProcessSlot; coindex.i++)
{
if (EndOfFramePaused[coindex.i] && EndOfFrameProcesses[coindex.i] != null)
{
EndOfFramePaused[coindex.i] = false;
count++;
}
}
for (coindex.i = 0, coindex.seg = Segment.ManualTimeframe; coindex.i < _nextManualTimeframeProcessSlot; coindex.i++)
{
if (ManualTimeframePaused[coindex.i] && ManualTimeframeProcesses[coindex.i] != null)
{
ManualTimeframePaused[coindex.i] = false;
count++;
}
}
var indexesEnum = Links.GetEnumerator();
while (indexesEnum.MoveNext())
{
if (!_handleToIndex.ContainsKey(indexesEnum.Current.Key)) continue;
var linksEnum = indexesEnum.Current.Value.GetEnumerator();
while (linksEnum.MoveNext())
count += ResumeCoroutines(linksEnum.Current);
}
return count;
}
///
/// This will resume any matching coroutines.
///
/// The handle of the coroutine to resume.
/// The number of coroutines that were resumed. (Normally 0 or 1).
public static int ResumeCoroutines(CoroutineHandle handle)
{
return ActiveInstances[handle.Key] != null ? GetInstance(handle.Key).ResumeCoroutinesOnInstance(handle) : 0;
}
///
/// This will resume any matching coroutines.
///
/// A list of handles to coroutines you want to resume.
/// The number of coroutines that were resumed.
public static int ResumeCoroutines(IEnumerable handles)
{
int count = 0;
var handlesEnum = handles.GetEnumerator();
while (!handlesEnum.MoveNext())
ResumeCoroutines(handlesEnum.Current);
return count;
}
///
/// 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. (Normally 0 or 1)
public int ResumeCoroutinesOnInstance(CoroutineHandle handle)
{
int count = 0;
if (_handleToIndex.ContainsKey(handle) && !CoindexIsNull(_handleToIndex[handle]) && SetPause(_handleToIndex[handle], false))
count++;
if (Links.ContainsKey(handle))
{
var links = Links[handle];
Links.Remove(handle);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += ResumeCoroutines(linksEnum.Current);
Links.Add(handle, links);
}
return count;
}
///
/// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has
/// no effect.
///
/// All coroutines on the layer corresponding with this GameObject will be resumed.
/// The number of coroutines that were resumed.
public static int ResumeCoroutines(GameObject gameObj)
{
return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(gameObj.GetInstanceID());
}
///
/// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect.
///
/// All coroutines on the layer corresponding with this GameObject will be resumed.
/// The number of coroutines that were resumed.
public int ResumeCoroutinesOnInstance(GameObject gameObj)
{
return gameObj == null ? 0 : ResumeCoroutinesOnInstance(gameObj.GetInstanceID());
}
///
/// 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(_handleToIndex[indexesEnum.Current]) && SetPause(_handleToIndex[indexesEnum.Current], false))
{
count++;
}
if (Links.ContainsKey(indexesEnum.Current))
{
var links = Links[indexesEnum.Current];
Links.Remove(indexesEnum.Current);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += ResumeCoroutines(linksEnum.Current);
Links.Add(indexesEnum.Current, links);
}
}
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(_handleToIndex[indexesEnum.Current]) && SetPause(_handleToIndex[indexesEnum.Current], false))
{
count++;
}
if (Links.ContainsKey(indexesEnum.Current))
{
var links = Links[indexesEnum.Current];
Links.Remove(indexesEnum.Current);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += ResumeCoroutines(linksEnum.Current);
Links.Add(indexesEnum.Current, links);
}
}
return count;
}
///
/// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has
/// no effect.
///
/// All coroutines on the layer corresponding with this GameObject will be resumed.
/// Any coroutines previously paused with a matching tag will be resumend.
/// The number of coroutines that were resumed.
public static int ResumeCoroutines(GameObject gameObj, string tag)
{
return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(gameObj.GetInstanceID(), tag);
}
///
/// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect.
///
/// All coroutines on the layer corresponding with this GameObject will be resumed.
/// Any coroutines previously paused with a matching tag will be resumend.
/// The number of coroutines that were resumed.
public int ResumeCoroutinesOnInstance(GameObject gameObj, string tag)
{
return gameObj == null ? 0 : ResumeCoroutinesOnInstance(gameObj.GetInstanceID(), tag);
}
///
/// 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(_handleToIndex[indexesEnum.Current]) && _layeredProcesses[layer].Contains(indexesEnum.Current))
{
if (SetPause(_handleToIndex[indexesEnum.Current], false))
count++;
if (Links.ContainsKey(indexesEnum.Current))
{
var links = Links[indexesEnum.Current];
Links.Remove(indexesEnum.Current);
var linksEnum = links.GetEnumerator();
while (linksEnum.MoveNext())
count += ResumeCoroutines(linksEnum.Current);
Links.Add(indexesEnum.Current, links);
}
}
}
return count;
}
///
/// 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(handle)
? inst._processTags[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(handle)
? inst._processLayers[handle] : (int?)null;
}
///
/// Returns >NET's name for the coroutine that the handle points to.
///
/// The handle to the coroutine.
/// The underlying debug name of the coroutine, or info about the state of the coroutine.
public static string GetDebugName(CoroutineHandle handle)
{
if (handle.Key == 0)
return "Uninitialized handle";
Timing inst = GetInstance(handle.Key);
if (inst == null)
return "Invalid handle";
if (!inst._handleToIndex.ContainsKey(handle))
return "Expired coroutine";
return inst.CoindexPeek(inst._handleToIndex[handle]).ToString();
}
///
/// 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(handle)))
return false;
inst.RemoveTagOnInstance(handle);
inst.AddTagOnInstance(newTag, 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(handle)))
return false;
inst.RemoveLayerOnInstance(handle);
inst.AddLayerOnInstance(newLayer, 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;
// TODO, invistage whether leaving holes here causes problems.
inst.RunCoroutineInternal(inst.CoindexExtract(inst._handleToIndex[handle]), newSegment, inst._processLayers.ContainsKey(handle)
? inst._processLayers[handle] : (int?)null, inst._processTags.ContainsKey(handle)
? inst._processTags[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.RemoveLayerOnInstance(handle);
return true;
}
///
/// Tests to see if the handle you have points to a valid coroutine that is currently running.
///
/// 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 coroutine that has not ended but is paused.
///
/// The handle to test.
/// Whether it's a paused coroutine.
[System.Obsolete("Replaced with isAliveAndPaused.", false)]
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]);
}
///
/// Tests to see if the handle you have points to a coroutine that has not ended but is paused.
///
/// The handle to test.
/// Whether it's a paused coroutine.
public static bool IsAliveAndPaused(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 AddTagOnInstance(string tag, CoroutineHandle handle)
{
_processTags.Add(handle, tag);
if(_taggedProcesses.ContainsKey(tag))
_taggedProcesses[tag].Add(handle);
else
_taggedProcesses.Add(tag, new HashSet { handle });
}
private void AddLayerOnInstance(int layer, CoroutineHandle handle)
{
_processLayers.Add(handle, layer);
if (_layeredProcesses.ContainsKey(layer))
_layeredProcesses[layer].Add(handle);
else
_layeredProcesses.Add(layer, new HashSet { handle });
}
private void RemoveTagOnInstance(CoroutineHandle handle)
{
if (_processTags.ContainsKey(handle))
{
if (_taggedProcesses[_processTags[handle]].Count > 1)
_taggedProcesses[_processTags[handle]].Remove(handle);
else
_taggedProcesses.Remove(_processTags[handle]);
_processTags.Remove(handle);
}
}
private void RemoveLayerOnInstance(CoroutineHandle handle)
{
if (_processLayers.ContainsKey(handle))
{
if (_layeredProcesses[_processLayers[handle]].Count > 1)
_layeredProcesses[_processLayers[handle]].Remove(handle);
else
_layeredProcesses.Remove(_processLayers[handle]);
_processLayers.Remove(handle);
}
}
private void RemoveGraffiti(CoroutineHandle handle)
{
if (_processLayers.ContainsKey(handle))
{
if (_layeredProcesses[_processLayers[handle]].Count > 1)
_layeredProcesses[_processLayers[handle]].Remove(handle);
else
_layeredProcesses.Remove(_processLayers[handle]);
_processLayers.Remove(handle);
}
if (_processTags.ContainsKey(handle))
{
if (_taggedProcesses[_processTags[handle]].Count > 1)
_taggedProcesses[_processTags[handle]].Remove(handle);
else
_taggedProcesses.Remove(_processTags[handle]);
_processTags.Remove(handle);
}
}
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;
}
}
/// Whether it was already null.
private bool Nullify(CoroutineHandle handle)
{
return Nullify(_handleToIndex[handle]);
}
/// Whether it was already null.
private bool Nullify(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 SetPause(ProcessIndex coindex, bool newPausedState)
{
if (CoindexPeek(coindex) == null)
return false;
bool isPaused;
switch (coindex.seg)
{
case Segment.Update:
isPaused = UpdatePaused[coindex.i];
UpdatePaused[coindex.i] = newPausedState;
if (newPausedState && UpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
UpdateProcesses[coindex.i] = _InjectDelay(UpdateProcesses[coindex.i],
UpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.FixedUpdate:
isPaused = FixedUpdatePaused[coindex.i];
FixedUpdatePaused[coindex.i] = newPausedState;
if (newPausedState && FixedUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
FixedUpdateProcesses[coindex.i] = _InjectDelay(FixedUpdateProcesses[coindex.i],
FixedUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.LateUpdate:
isPaused = LateUpdatePaused[coindex.i];
LateUpdatePaused[coindex.i] = newPausedState;
if (newPausedState && LateUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
LateUpdateProcesses[coindex.i] = _InjectDelay(LateUpdateProcesses[coindex.i],
LateUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.SlowUpdate:
isPaused = SlowUpdatePaused[coindex.i];
SlowUpdatePaused[coindex.i] = newPausedState;
if (newPausedState && SlowUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
SlowUpdateProcesses[coindex.i] = _InjectDelay(SlowUpdateProcesses[coindex.i],
SlowUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.RealtimeUpdate:
isPaused = RealtimeUpdatePaused[coindex.i];
RealtimeUpdatePaused[coindex.i] = newPausedState;
if (newPausedState && RealtimeUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
RealtimeUpdateProcesses[coindex.i] = _InjectDelay(RealtimeUpdateProcesses[coindex.i],
RealtimeUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.EditorUpdate:
isPaused = EditorUpdatePaused[coindex.i];
EditorUpdatePaused[coindex.i] = newPausedState;
if (newPausedState && EditorUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
EditorUpdateProcesses[coindex.i] = _InjectDelay(EditorUpdateProcesses[coindex.i],
EditorUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.EditorSlowUpdate:
isPaused = EditorSlowUpdatePaused[coindex.i];
EditorSlowUpdatePaused[coindex.i] = newPausedState;
if (newPausedState && EditorSlowUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
EditorSlowUpdateProcesses[coindex.i] = _InjectDelay(EditorSlowUpdateProcesses[coindex.i],
EditorSlowUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.EndOfFrame:
isPaused = EndOfFramePaused[coindex.i];
EndOfFramePaused[coindex.i] = newPausedState;
if (newPausedState && EndOfFrameProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
EndOfFrameProcesses[coindex.i] = _InjectDelay(EndOfFrameProcesses[coindex.i],
EndOfFrameProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
case Segment.ManualTimeframe:
isPaused = ManualTimeframePaused[coindex.i];
ManualTimeframePaused[coindex.i] = newPausedState;
if (newPausedState && ManualTimeframeProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
ManualTimeframeProcesses[coindex.i] = _InjectDelay(ManualTimeframeProcesses[coindex.i],
ManualTimeframeProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isPaused;
default:
return false;
}
}
private bool SetHeld(ProcessIndex coindex, bool newHeldState)
{
if (CoindexPeek(coindex) == null)
return false;
bool isHeld;
switch (coindex.seg)
{
case Segment.Update:
isHeld = UpdateHeld[coindex.i];
UpdateHeld[coindex.i] = newHeldState;
if (newHeldState && UpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
UpdateProcesses[coindex.i] = _InjectDelay(UpdateProcesses[coindex.i],
UpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.FixedUpdate:
isHeld = FixedUpdateHeld[coindex.i];
FixedUpdateHeld[coindex.i] = newHeldState;
if (newHeldState && FixedUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
FixedUpdateProcesses[coindex.i] = _InjectDelay(FixedUpdateProcesses[coindex.i],
FixedUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.LateUpdate:
isHeld = LateUpdateHeld[coindex.i];
LateUpdateHeld[coindex.i] = newHeldState;
if (newHeldState && LateUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
LateUpdateProcesses[coindex.i] = _InjectDelay(LateUpdateProcesses[coindex.i],
LateUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.SlowUpdate:
isHeld = SlowUpdateHeld[coindex.i];
SlowUpdateHeld[coindex.i] = newHeldState;
if (newHeldState && SlowUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
SlowUpdateProcesses[coindex.i] = _InjectDelay(SlowUpdateProcesses[coindex.i],
SlowUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.RealtimeUpdate:
isHeld = RealtimeUpdateHeld[coindex.i];
RealtimeUpdateHeld[coindex.i] = newHeldState;
if (newHeldState && RealtimeUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
RealtimeUpdateProcesses[coindex.i] = _InjectDelay(RealtimeUpdateProcesses[coindex.i],
RealtimeUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.EditorUpdate:
isHeld = EditorUpdateHeld[coindex.i];
EditorUpdateHeld[coindex.i] = newHeldState;
if (newHeldState && EditorUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
EditorUpdateProcesses[coindex.i] = _InjectDelay(EditorUpdateProcesses[coindex.i],
EditorUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.EditorSlowUpdate:
isHeld = EditorSlowUpdateHeld[coindex.i];
EditorSlowUpdateHeld[coindex.i] = newHeldState;
if (newHeldState && EditorSlowUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
EditorSlowUpdateProcesses[coindex.i] = _InjectDelay(EditorSlowUpdateProcesses[coindex.i],
EditorSlowUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.EndOfFrame:
isHeld = EndOfFrameHeld[coindex.i];
EndOfFrameHeld[coindex.i] = newHeldState;
if (newHeldState && EndOfFrameProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
EndOfFrameProcesses[coindex.i] = _InjectDelay(EndOfFrameProcesses[coindex.i],
EndOfFrameProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
case Segment.ManualTimeframe:
isHeld = ManualTimeframeHeld[coindex.i];
ManualTimeframeHeld[coindex.i] = newHeldState;
if (newHeldState && ManualTimeframeProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
ManualTimeframeProcesses[coindex.i] = _InjectDelay(ManualTimeframeProcesses[coindex.i],
ManualTimeframeProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return isHeld;
default:
return false;
}
}
private IEnumerator CreateHold(ProcessIndex coindex, IEnumerator coptr)
{
if (CoindexPeek(coindex) == null)
return null;
switch (coindex.seg)
{
case Segment.Update:
UpdateHeld[coindex.i] = true;
if (UpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(UpdateProcesses[coindex.i], UpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.FixedUpdate:
FixedUpdateHeld[coindex.i] = true;
if (FixedUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(FixedUpdateProcesses[coindex.i],
FixedUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.LateUpdate:
LateUpdateHeld[coindex.i] = true;
if (LateUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(LateUpdateProcesses[coindex.i],
LateUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.SlowUpdate:
SlowUpdateHeld[coindex.i] = true;
if (SlowUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(SlowUpdateProcesses[coindex.i],
SlowUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.RealtimeUpdate:
RealtimeUpdateHeld[coindex.i] = true;
if (RealtimeUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(RealtimeUpdateProcesses[coindex.i],
RealtimeUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.EditorUpdate:
EditorUpdateHeld[coindex.i] = true;
if (EditorUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(EditorUpdateProcesses[coindex.i],
EditorUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.EditorSlowUpdate:
EditorSlowUpdateHeld[coindex.i] = true;
if (EditorSlowUpdateProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(EditorSlowUpdateProcesses[coindex.i],
EditorSlowUpdateProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.EndOfFrame:
EndOfFrameHeld[coindex.i] = true;
if (EndOfFrameProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(EndOfFrameProcesses[coindex.i],
EndOfFrameProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
case Segment.ManualTimeframe:
ManualTimeframeHeld[coindex.i] = true;
if (ManualTimeframeProcesses[coindex.i].Current > GetSegmentTime(coindex.seg))
coptr = _InjectDelay(ManualTimeframeProcesses[coindex.i],
ManualTimeframeProcesses[coindex.i].Current - GetSegmentTime(coindex.seg));
return coptr;
default:
return coptr;
}
}
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 bool CoindexIsHeld(ProcessIndex coindex)
{
switch (coindex.seg)
{
case Segment.Update:
return UpdateHeld[coindex.i];
case Segment.FixedUpdate:
return FixedUpdateHeld[coindex.i];
case Segment.LateUpdate:
return LateUpdateHeld[coindex.i];
case Segment.SlowUpdate:
return SlowUpdateHeld[coindex.i];
case Segment.RealtimeUpdate:
return RealtimeUpdateHeld[coindex.i];
case Segment.EditorUpdate:
return EditorUpdateHeld[coindex.i];
case Segment.EditorSlowUpdate:
return EditorSlowUpdateHeld[coindex.i];
case Segment.EndOfFrame:
return EndOfFrameHeld[coindex.i];
case Segment.ManualTimeframe:
return ManualTimeframeHeld[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(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
public static float WaitUntilDone(IEnumerator newCoroutine)
{
return WaitUntilDone(RunCoroutine(newCoroutine), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
public static float WaitUntilDone(IEnumerator newCoroutine, string tag)
{
return WaitUntilDone(RunCoroutine(newCoroutine, tag), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
public static float WaitUntilDone(IEnumerator newCoroutine, int layer)
{
return WaitUntilDone(RunCoroutine(newCoroutine, layer), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// 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.
public static float WaitUntilDone(IEnumerator newCoroutine, int layer, string tag)
{
return WaitUntilDone(RunCoroutine(newCoroutine, layer, tag), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// The segment that the new coroutine should run in.
public static float WaitUntilDone(IEnumerator newCoroutine, Segment segment)
{
return WaitUntilDone(RunCoroutine(newCoroutine, segment), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// The segment that the new coroutine should run in.
/// An optional tag to attach to the coroutine which can later be used to identify this coroutine.
public static float WaitUntilDone(IEnumerator newCoroutine, Segment segment, string tag)
{
return WaitUntilDone(RunCoroutine(newCoroutine, segment, tag), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// The segment that the new coroutine should run in.
/// An optional layer to attach to the coroutine which can later be used to identify this coroutine.
public static float WaitUntilDone(IEnumerator newCoroutine, Segment segment, int layer)
{
return WaitUntilDone(RunCoroutine(newCoroutine, segment, layer), true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the
/// current one until it finishes.
///
/// The coroutine to pause for.
/// The segment that the new 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.
public static float WaitUntilDone(IEnumerator newCoroutine, Segment segment, int layer, string tag)
{
return WaitUntilDone(RunCoroutine(newCoroutine, segment, layer, tag), true);
}
///
/// 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 WaitUntilDone(otherCoroutine, true);
}
///
/// Use the command "yield return Timing.WaitUntilDone(otherCoroutine, false);" to pause the current
/// coroutine until otherCoroutine is done, supressing warnings.
///
/// The coroutine to pause for.
/// Post a warning if no hold action was actually performed.
public static float WaitUntilDone(CoroutineHandle otherCoroutine, bool warnOnIssue)
{
Timing inst = GetInstance(otherCoroutine.Key);
if (inst != null && inst._handleToIndex.ContainsKey(otherCoroutine))
{
if (inst.CoindexIsNull(inst._handleToIndex[otherCoroutine]))
return 0f;
if (!inst._waitingTriggers.ContainsKey(otherCoroutine))
{
inst.CoindexReplace(inst._handleToIndex[otherCoroutine],
inst._StartWhenDone(otherCoroutine, inst.CoindexPeek(inst._handleToIndex[otherCoroutine])));
inst._waitingTriggers.Add(otherCoroutine, new HashSet());
}
if (inst.currentCoroutine == otherCoroutine)
{
Assert.IsFalse(warnOnIssue, "A coroutine cannot wait for itself.");
return WaitForOneFrame;
}
if (!inst.currentCoroutine.IsValid)
{
Assert.IsFalse(warnOnIssue, "The two coroutines are not running on the same MEC instance.");
return WaitForOneFrame;
}
inst._waitingTriggers[otherCoroutine].Add(inst.currentCoroutine);
if (!inst._allWaiting.Contains(inst.currentCoroutine))
inst._allWaiting.Add(inst.currentCoroutine);
inst.SetHeld(inst._handleToIndex[inst.currentCoroutine], true);
inst.SwapToLast(otherCoroutine, inst.currentCoroutine);
return float.NaN;
}
Assert.IsFalse(warnOnIssue, "WaitUntilDone cannot hold, the coroutine handle that was passed in is invalid: " + otherCoroutine);
return 0f;
}
///
/// This will pause one coroutine until another coroutine finishes running. Note: This is NOT used with a yield return statement.
///
/// The coroutine that should be paused.
/// The coroutine that will be waited for.
/// Whether a warning should be logged if there is a problem.
public static void WaitForOtherHandles(CoroutineHandle handle, CoroutineHandle otherHandle, bool warnOnIssue = true)
{
if (!IsRunning(handle) || !IsRunning(otherHandle))
return;
if(handle == otherHandle)
{
Assert.IsFalse(warnOnIssue, "A coroutine cannot wait for itself.");
return;
}
if(handle.Key != otherHandle.Key)
{
Assert.IsFalse(warnOnIssue, "A coroutine cannot wait for another coroutine on a different MEC instance.");
return;
}
Timing inst = GetInstance(handle.Key);
if (inst != null && inst._handleToIndex.ContainsKey(handle) && inst._handleToIndex.ContainsKey(otherHandle) &&
!inst.CoindexIsNull(inst._handleToIndex[otherHandle]))
{
if (!inst._waitingTriggers.ContainsKey(otherHandle))
{
inst.CoindexReplace(inst._handleToIndex[otherHandle],
inst._StartWhenDone(otherHandle, inst.CoindexPeek(inst._handleToIndex[otherHandle])));
inst._waitingTriggers.Add(otherHandle, new HashSet());
}
inst._waitingTriggers[otherHandle].Add(handle);
if (!inst._allWaiting.Contains(handle))
inst._allWaiting.Add(handle);
inst.SetHeld(inst._handleToIndex[handle], true);
inst.SwapToLast(otherHandle, handle);
}
}
///
/// This will pause one coroutine until the other coroutines finish running. Note: This is NOT used with a yield return statement.
///
/// The coroutine that should be paused.
/// A list of coroutines to be waited for.
/// Whether a warning should be logged if there is a problem.
public static void WaitForOtherHandles(CoroutineHandle handle, IEnumerable otherHandles, bool warnOnIssue = true)
{
if (!IsRunning(handle))
return;
Timing inst = GetInstance(handle.Key);
var othersEnum = otherHandles.GetEnumerator();
while(othersEnum.MoveNext())
{
if(!IsRunning(othersEnum.Current))
continue;
if (handle == othersEnum.Current)
{
Assert.IsFalse(warnOnIssue, "A coroutine cannot wait for itself.");
continue;
}
if (handle.Key != othersEnum.Current.Key)
{
Assert.IsFalse(warnOnIssue, "A coroutine cannot wait for another coroutine on a different MEC instance.");
continue;
}
if (!inst._waitingTriggers.ContainsKey(othersEnum.Current))
{
inst.CoindexReplace(inst._handleToIndex[othersEnum.Current],
inst._StartWhenDone(othersEnum.Current, inst.CoindexPeek(inst._handleToIndex[othersEnum.Current])));
inst._waitingTriggers.Add(othersEnum.Current, new HashSet());
}
inst._waitingTriggers[othersEnum.Current].Add(handle);
if (!inst._allWaiting.Contains(handle))
inst._allWaiting.Add(handle);
inst.SetHeld(inst._handleToIndex[handle], true);
inst.SwapToLast(othersEnum.Current, handle);
}
}
private void SwapToLast(CoroutineHandle firstHandle, CoroutineHandle lastHandle)
{
if (firstHandle.Key != lastHandle.Key)
return;
ProcessIndex firstIndex = _handleToIndex[firstHandle];
ProcessIndex lastIndex = _handleToIndex[lastHandle];
if (firstIndex.seg != lastIndex.seg || firstIndex.i <= lastIndex.i)
return;
IEnumerator tempCoptr = CoindexPeek(firstIndex);
CoindexReplace(firstIndex, CoindexPeek(lastIndex));
CoindexReplace(lastIndex, tempCoptr);
_indexToHandle[firstIndex] = lastHandle;
_indexToHandle[lastIndex] = firstHandle;
_handleToIndex[firstHandle] = lastIndex;
_handleToIndex[lastHandle] = firstIndex;
bool tmpB = SetPause(firstIndex, CoindexIsPaused(lastIndex));
SetPause(lastIndex, tmpB);
tmpB = SetHeld(firstIndex, CoindexIsHeld(lastIndex));
SetHeld(lastIndex, tmpB);
if (_waitingTriggers.ContainsKey(lastHandle))
{
var trigsEnum = _waitingTriggers[lastHandle].GetEnumerator();
while (trigsEnum.MoveNext())
SwapToLast(lastHandle, trigsEnum.Current);
}
if (_allWaiting.Contains(firstHandle))
{
var keyEnum = _waitingTriggers.GetEnumerator();
while (keyEnum.MoveNext())
{
var valueEnum = keyEnum.Current.Value.GetEnumerator();
while (valueEnum.MoveNext())
if (valueEnum.Current == firstHandle)
SwapToLast(keyEnum.Current.Key, firstHandle);
}
}
}
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) && !HandleIsInWaitingList(tasksEnum.Current))
{
SetHeld(_handleToIndex[tasksEnum.Current], false);
_allWaiting.Remove(tasksEnum.Current);
}
}
}
private bool HandleIsInWaitingList(CoroutineHandle handle)
{
var triggersEnum = _waitingTriggers.GetEnumerator();
while (triggersEnum.MoveNext())
if (triggersEnum.Current.Value.Contains(handle))
return true;
return false;
}
private static IEnumerator ReturnTmpRefForRepFunc(IEnumerator coptr, CoroutineHandle handle)
{
return _tmpRef as IEnumerator;
}
#if !UNITY_2018_3_OR_NEWER
///
/// 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;
_tmpRef = wwwObject;
ReplacementFunction = WaitUntilDoneWwwHelper;
return float.NaN;
}
private static IEnumerator WaitUntilDoneWwwHelper(IEnumerator coptr, CoroutineHandle handle)
{
return _StartWhenDone(_tmpRef as WWW, coptr);
}
private static IEnumerator _StartWhenDone(WWW wwwObject, IEnumerator pausedProc)
{
while (!wwwObject.isDone)
yield return WaitForOneFrame;
_tmpRef = pausedProc;
ReplacementFunction = ReturnTmpRefForRepFunc;
yield return float.NaN;
}
#endif
///
/// 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 float.NaN;
CoroutineHandle handle = CurrentCoroutine;
Timing inst = GetInstance(CurrentCoroutine.Key);
if (inst == null) return float.NaN;
_tmpRef = _StartWhenDone(operation, inst.CoindexPeek(inst._handleToIndex[handle]));
ReplacementFunction = ReturnTmpRefForRepFunc;
return float.NaN;
}
private static IEnumerator _StartWhenDone(AsyncOperation operation, IEnumerator pausedProc)
{
while (!operation.isDone)
yield return WaitForOneFrame;
_tmpRef = pausedProc;
ReplacementFunction = ReturnTmpRefForRepFunc;
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(CustomYieldInstruction operation)
{
if (operation == null || !operation.keepWaiting) return float.NaN;
CoroutineHandle handle = CurrentCoroutine;
Timing inst = GetInstance(CurrentCoroutine.Key);
if (inst == null) return float.NaN;
_tmpRef = _StartWhenDone(operation, inst.CoindexPeek(inst._handleToIndex[handle]));
ReplacementFunction = ReturnTmpRefForRepFunc;
return float.NaN;
}
private static IEnumerator _StartWhenDone(CustomYieldInstruction operation, IEnumerator pausedProc)
{
while (operation.keepWaiting)
yield return WaitForOneFrame;
_tmpRef = pausedProc;
ReplacementFunction = ReturnTmpRefForRepFunc;
yield return float.NaN;
}
///
/// 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 float.NaN;
_tmpRef = evaluatorFunc;
ReplacementFunction = WaitUntilTrueHelper;
return float.NaN;
}
private static IEnumerator WaitUntilTrueHelper(IEnumerator coptr, CoroutineHandle handle)
{
return _StartWhenDone(_tmpRef as System.Func, false, coptr);
}
///
/// 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 float.NaN;
_tmpRef = evaluatorFunc;
ReplacementFunction = WaitUntilFalseHelper;
return float.NaN;
}
private static IEnumerator WaitUntilFalseHelper(IEnumerator coptr, CoroutineHandle handle)
{
return _StartWhenDone(_tmpRef as System.Func, true, coptr);
}
private static IEnumerator _StartWhenDone(System.Func evaluatorFunc, bool continueOn, IEnumerator pausedProc)
{
while (evaluatorFunc() == continueOn)
yield return WaitForOneFrame;
_tmpRef = pausedProc;
ReplacementFunction = ReturnTmpRefForRepFunc;
yield return float.NaN;
}
private IEnumerator _InjectDelay(IEnumerator proc, float waitTime)
{
yield return WaitForSecondsOnInstance(waitTime);
_tmpRef = proc;
ReplacementFunction = ReturnTmpRefForRepFunc;
yield return float.NaN;
}
///
/// Keeps this coroutine from executing until UnlockCoroutine is called with a matching key.
///
/// The handle to the coroutine to be locked.
/// The key to use. A new key can be generated by calling "new CoroutineHandle(0)".
/// Whether the lock was successful.
public bool LockCoroutine(CoroutineHandle coroutine, CoroutineHandle key)
{
if (coroutine.Key != _instanceID || key == new CoroutineHandle() || key.Key != 0)
return false;
if (!_waitingTriggers.ContainsKey(key))
_waitingTriggers.Add(key, new HashSet { coroutine });
else
_waitingTriggers[key].Add(coroutine);
_allWaiting.Add(coroutine);
SetHeld(_handleToIndex[coroutine], true);
return true;
}
///
/// Unlocks a coroutine that has been locked, so long as the key matches.
///
/// The handle to the coroutine to be unlocked.
/// The key that the coroutine was previously locked with.
/// Whether the coroutine was successfully unlocked.
public bool UnlockCoroutine(CoroutineHandle coroutine, CoroutineHandle key)
{
if (coroutine.Key != _instanceID || key == new CoroutineHandle() ||
!_handleToIndex.ContainsKey(coroutine) || !_waitingTriggers.ContainsKey(key))
return false;
if (_waitingTriggers[key].Count == 1)
_waitingTriggers.Remove(key);
else
_waitingTriggers[key].Remove(coroutine);
if (!HandleIsInWaitingList(coroutine))
{
SetHeld(_handleToIndex[coroutine], false);
_allWaiting.Remove(coroutine);
}
return true;
}
///
/// This will create a one way link between two handles. If the master coroutine ends for any reason or is paused or resumed
/// that will also happen to the slave coroutine. If a two way link is desired then just call this funciton twice with
/// parameters reversed.
///
/// The coroutine that generates the link events
/// The coroutine that recieves the link events
/// The number of coroutines that were linked.
public static int LinkCoroutines(CoroutineHandle master, CoroutineHandle slave)
{
if (!IsRunning(slave) || !master.IsValid)
{
return 0;
}
else if (!IsRunning(master))
{
KillCoroutines(slave);
return 1;
}
if (Links.ContainsKey(master))
{
if (!Links[master].Contains(slave))
{
Links[master].Add(slave);
return 1;
}
else
{
return 0;
}
}
else
{
Links.Add(master, new HashSet { slave });
return 1;
}
}
///
/// This will remove the link between two coroutine handles if one exists.
///
/// The coroutine that generates the link events
/// The coroutine that recieves the link events
/// if true this will also remove any links that exist from the slave to the master
/// The number of coroutines that were unlinked.
public static int UnlinkCoroutines(CoroutineHandle master, CoroutineHandle slave, bool twoWay = false)
{
int count = 0;
if (Links.ContainsKey(master) && Links[master].Contains(slave))
{
if (Links[master].Count <= 1)
Links.Remove(master);
else
Links[master].Remove(slave);
count++;
}
if (twoWay && Links.ContainsKey(slave) && Links[slave].Contains(master))
{
if (Links[slave].Count <= 1)
Links.Remove(slave);
else
Links[slave].Remove(master);
count++;
}
return count;
}
///
/// You can use something like "yield return Timing.GetMyHandle(x => myHandle = x)" inside a running coroutine to get
/// that coroutine's handle.
///
/// The function that will recieve the handle.
public static float GetMyHandle(System.Action reciever)
{
_tmpRef = reciever;
ReplacementFunction = GetHandleHelper;
return float.NaN;
}
private static IEnumerator GetHandleHelper(IEnumerator input, CoroutineHandle handle)
{
System.Action reciever = _tmpRef as System.Action;
if (reciever != null)
reciever(handle);
return input;
}
///
/// 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)
{
_tmpSegment = newSegment;
ReplacementFunction = SwitchCoroutineRepS;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepS(IEnumerator coptr, CoroutineHandle handle)
{
Timing instance = GetInstance(handle.Key);
instance.RunCoroutineInternal(coptr, _tmpSegment, instance._processLayers.ContainsKey(handle) ? instance._processLayers[handle] : (int?)null,
instance._processTags.ContainsKey(handle) ? instance._processTags[handle] : null, handle, false);
return null;
}
///
/// 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)
{
_tmpSegment = newSegment;
_tmpRef = newTag;
ReplacementFunction = SwitchCoroutineRepST;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepST(IEnumerator coptr, CoroutineHandle handle)
{
Timing instance = GetInstance(handle.Key);
instance.RunCoroutineInternal(coptr, _tmpSegment,
instance._processLayers.ContainsKey(handle) ? instance._processLayers[handle] : (int?)null, _tmpRef as string, handle, false);
return null;
}
///
/// 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)
{
_tmpSegment = newSegment;
_tmpInt = newLayer;
ReplacementFunction = SwitchCoroutineRepSL;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepSL(IEnumerator coptr, CoroutineHandle handle)
{
Timing instance = GetInstance(handle.Key);
instance.RunCoroutineInternal(coptr, _tmpSegment, _tmpInt,
instance._processTags.ContainsKey(handle) ? instance._processTags[handle] : null, handle, false);
return null;
}
///
/// 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)
{
_tmpSegment = newSegment;
_tmpInt = newLayer;
_tmpRef = newTag;
ReplacementFunction = SwitchCoroutineRepSLT;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepSLT(IEnumerator coptr, CoroutineHandle handle)
{
GetInstance(handle.Key).RunCoroutineInternal(coptr, _tmpSegment, _tmpInt, _tmpRef as string, handle, false);
return null;
}
///
/// 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)
{
_tmpRef = newTag;
ReplacementFunction = SwitchCoroutineRepT;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepT(IEnumerator coptr, CoroutineHandle handle)
{
Timing instance = GetInstance(handle.Key);
instance.RemoveTagOnInstance(handle);
if ((_tmpRef as string) != null)
instance.AddTagOnInstance((string)_tmpRef, handle);
return coptr;
}
///
/// 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)
{
_tmpInt = newLayer;
ReplacementFunction = SwitchCoroutineRepL;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepL(IEnumerator coptr, CoroutineHandle handle)
{
RemoveLayer(handle);
GetInstance(handle.Key).AddLayerOnInstance(_tmpInt, handle);
return coptr;
}
///
/// 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)
{
_tmpInt = newLayer;
_tmpRef = newTag;
ReplacementFunction = SwitchCoroutineRepLT;
return float.NaN;
}
private static IEnumerator SwitchCoroutineRepLT(IEnumerator coptr, CoroutineHandle handle)
{
Timing instance = GetInstance(handle.Key);
instance.RemoveLayerOnInstance(handle);
instance.AddLayerOnInstance(_tmpInt, handle);
instance.RemoveTagOnInstance(handle);
if ((_tmpRef as string) != null)
instance.AddTagOnInstance((string)_tmpRef, handle);
return coptr;
}
///
/// 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, null));
}
///
/// 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, null));
}
///
/// Calls the specified action after a specified number of seconds.
///
/// The number of seconds to wait before calling the action.
/// The action to call.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed
/// before calling the action.
/// The handle to the coroutine that is started by this function.
public static CoroutineHandle CallDelayed(float delay, System.Action action, GameObject gameObject)
{
return action == null ? new CoroutineHandle() : RunCoroutine(Instance._DelayedCall(delay, action, gameObject), gameObject);
}
///
/// Calls the specified action after a specified number of seconds.
///
/// The number of seconds to wait before calling the action.
/// The action to call.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed
/// before calling the action.
/// The handle to the coroutine that is started by this function.
public CoroutineHandle CallDelayedOnInstance(float delay, System.Action action, GameObject gameObject)
{
return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_DelayedCall(delay, action, gameObject), gameObject);
}
private IEnumerator _DelayedCall(float delay, System.Action action, GameObject cancelWith)
{
yield return WaitForSecondsOnInstance(delay);
if (ReferenceEquals(cancelWith, null) || cancelWith != null)
action();
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(period, action, null));
if (!float.IsPositiveInfinity(timeframe))
RunCoroutine(Instance._WatchCall(timeframe, handle, null, onDone));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(period, action, null));
if (!float.IsPositiveInfinity(timeframe))
RunCoroutineOnInstance(_WatchCall(timeframe, handle, null, onDone));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(period, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(period, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(period, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
RunCoroutine(Instance._WatchCall(timeframe, handle, null, onDone), timing);
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(period, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, null, onDone), timing));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(period, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(period, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(0f, action, null));
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(timeframe, handle, null, onDone)));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(0f, action, null));
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, null, onDone)));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(0f, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// Calls the supplied action at the given rate for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(0f, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(0f, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(timeframe, handle, null, onDone), timing));
return handle;
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(0f, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, null, onDone), timing));
return handle;
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(0f, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
///
/// Calls the supplied action every frame for a given number of seconds.
///
/// The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(0f, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
private IEnumerator _WatchCall(float timeframe, CoroutineHandle handle, GameObject gObject, System.Action onDone)
{
yield return WaitForSecondsOnInstance(timeframe);
KillCoroutinesOnInstance(handle);
if (onDone != null && (ReferenceEquals(gObject, null) || gObject != null))
onDone();
}
private IEnumerator _CallContinuously(float period, System.Action action, GameObject gObject)
{
while (ReferenceEquals(gObject, null) || gObject != null)
{
yield return WaitForSecondsOnInstance(period);
if (ReferenceEquals(gObject, null) || (gObject != null && gObject.activeInHierarchy))
action();
}
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(reference, period, action, null));
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, null, onDone)));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(reference, period, action, null));
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, null, onDone)));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(reference, period, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(reference, period, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(reference, period, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, null, onDone), timing));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(reference, period, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, null, onDone), timing));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(reference, period, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The amount of time between calls.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(reference, period, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutine(Instance._CallContinuously(reference, 0f, action, null));
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, null, onDone)));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_CallContinuously(reference, 0f, action, null));
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, null, onDone)));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(reference, 0f, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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,
GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(reference, 0f, action, gameObject), gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, gameObject, onDone), gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(reference, 0f, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, null, onDone), timing));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// 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)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(reference, 0f, action, null), timing);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, null, onDone), timing));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutine(Instance._CallContinuously(reference, 0f, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutine(Instance._WatchCall(reference, timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
///
/// 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. Use float.PositiveInfinity to run indefinitely.
/// The action to call every frame.
/// The timing segment to run in.
/// A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed or disabled
/// before calling the action.
/// 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, GameObject gameObject, System.Action onDone = null)
{
CoroutineHandle handle = action == null ? new CoroutineHandle()
: RunCoroutineOnInstance(_CallContinuously(reference, 0f, action, gameObject), timing, gameObject);
if (!float.IsPositiveInfinity(timeframe))
LinkCoroutines(handle, RunCoroutineOnInstance(_WatchCall(reference, timeframe, handle, gameObject, onDone), timing, gameObject));
return handle;
}
private IEnumerator _WatchCall(T reference, float timeframe, CoroutineHandle handle, GameObject gObject, System.Action onDone)
{
yield return WaitForSecondsOnInstance(timeframe);
KillCoroutinesOnInstance(handle);
if (onDone != null && (ReferenceEquals(gObject, null) || gObject != null))
onDone(reference);
}
private IEnumerator _CallContinuously(T reference, float period, System.Action action, GameObject gObject)
{
while ((ReferenceEquals(gObject, null) || gObject != null))
{
yield return WaitForSecondsOnInstance(period);
if (ReferenceEquals(gObject, null) || (gObject != null && gObject.activeInHierarchy))
action(reference);
}
}
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;
}
}
[System.Obsolete("Unity coroutine function, use RunCoroutine instead.", true)]
public new Coroutine StartCoroutine(System.Collections.IEnumerator routine) { return null; }
[System.Obsolete("Unity coroutine function, use RunCoroutine instead.", true)]
public new Coroutine StartCoroutine(string methodName, object value) { return null; }
[System.Obsolete("Unity coroutine function, use RunCoroutine instead.", true)]
public new Coroutine StartCoroutine(string methodName) { return null; }
[System.Obsolete("Unity coroutine function, use RunCoroutine instead.", true)]
public new Coroutine StartCoroutine_Auto(System.Collections.IEnumerator routine) { return null; }
[System.Obsolete("Unity coroutine function, use KillCoroutines instead.", true)]
public new void StopCoroutine(string methodName) {}
[System.Obsolete("Unity coroutine function, use KillCoroutines instead.", true)]
public new void StopCoroutine(System.Collections.IEnumerator routine) {}
[System.Obsolete("Unity coroutine function, use KillCoroutines instead.", true)]
public new void StopCoroutine(Coroutine routine) {}
[System.Obsolete("Unity coroutine function, use KillCoroutines instead.", true)]
public new void StopAllCoroutines() {}
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void Destroy(Object obj) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void Destroy(Object obj, float f) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void DestroyObject(Object obj) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void DestroyObject(Object obj, float f) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void DestroyImmediate(Object obj) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void DestroyImmediate(Object obj, bool b) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void Instantiate(Object obj) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void Instantiate(Object original, Vector3 position, Quaternion rotation) { }
[System.Obsolete("Use your own GameObject for this.", true)]
public new static void Instantiate