diff options
author | chai <chaifix@163.com> | 2020-03-06 00:30:31 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2020-03-06 00:30:31 +0800 |
commit | 38d4a551880f913a873c3d2c91a98f0434dfa4b2 (patch) | |
tree | a7fd10896449b6596ac464dd3d4881dbc6fd8c82 |
141 files changed, 10577 insertions, 0 deletions
diff --git a/Assets/Art.meta b/Assets/Art.meta new file mode 100644 index 0000000..6f37e4c --- /dev/null +++ b/Assets/Art.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d726ae4a6547acb4fa8e2a5f6986e62c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Resources.meta b/Assets/Art/Resources.meta new file mode 100644 index 0000000..8dfc52c --- /dev/null +++ b/Assets/Art/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 409e10f19544a304c9e06906b30251b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Resources/res1.txt b/Assets/Art/Resources/res1.txt new file mode 100644 index 0000000..3abb740 --- /dev/null +++ b/Assets/Art/Resources/res1.txt @@ -0,0 +1 @@ +Assets/Art/Resources/res1.txt
\ No newline at end of file diff --git a/Assets/Art/Resources/res1.txt.meta b/Assets/Art/Resources/res1.txt.meta new file mode 100644 index 0000000..2c82490 --- /dev/null +++ b/Assets/Art/Resources/res1.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8dc3362571aceb742ac775b23b41804e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Resources/res5.txt b/Assets/Art/Resources/res5.txt new file mode 100644 index 0000000..5382df7 --- /dev/null +++ b/Assets/Art/Resources/res5.txt @@ -0,0 +1 @@ +Assets/Art/Resources/res5.txt
\ No newline at end of file diff --git a/Assets/Art/Resources/res5.txt.meta b/Assets/Art/Resources/res5.txt.meta new file mode 100644 index 0000000..acf6d06 --- /dev/null +++ b/Assets/Art/Resources/res5.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bb6a3fab697575e4b85a1023d9d18ab4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/StreamingAssets.meta b/Assets/Art/StreamingAssets.meta new file mode 100644 index 0000000..7014ee7 --- /dev/null +++ b/Assets/Art/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 63ee4022cb291fa4c962226a66ef7459 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/StreamingAssets/test.txt b/Assets/Art/StreamingAssets/test.txt new file mode 100644 index 0000000..78d724b --- /dev/null +++ b/Assets/Art/StreamingAssets/test.txt @@ -0,0 +1 @@ +Assets/StreamingAssets/test.txt
\ No newline at end of file diff --git a/Assets/Art/StreamingAssets/test.txt.meta b/Assets/Art/StreamingAssets/test.txt.meta new file mode 100644 index 0000000..eb64649 --- /dev/null +++ b/Assets/Art/StreamingAssets/test.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2111d4bc15ea1b04bb47272b912972bc +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/StreamingAssets/test2.txt b/Assets/Art/StreamingAssets/test2.txt new file mode 100644 index 0000000..23973e6 --- /dev/null +++ b/Assets/Art/StreamingAssets/test2.txt @@ -0,0 +1 @@ +Assets/Art/StreamingAssets/test2.txt
\ No newline at end of file diff --git a/Assets/Art/StreamingAssets/test2.txt.meta b/Assets/Art/StreamingAssets/test2.txt.meta new file mode 100644 index 0000000..ac27ac2 --- /dev/null +++ b/Assets/Art/StreamingAssets/test2.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 57d6fc76884c6904a92eb4cac765bf77 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/StreamingAssets/test3.txt b/Assets/Art/StreamingAssets/test3.txt new file mode 100644 index 0000000..32fc4c1 --- /dev/null +++ b/Assets/Art/StreamingAssets/test3.txt @@ -0,0 +1 @@ +Assets/Art/StreamingAssets/test3.txt
\ No newline at end of file diff --git a/Assets/Art/StreamingAssets/test3.txt.meta b/Assets/Art/StreamingAssets/test3.txt.meta new file mode 100644 index 0000000..bb55698 --- /dev/null +++ b/Assets/Art/StreamingAssets/test3.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 252ecd825c31e7048801ae3b8b30858e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Files.meta b/Assets/Files.meta new file mode 100644 index 0000000..b32eb29 --- /dev/null +++ b/Assets/Files.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2fce43b6f00c6ea449d29c9d5d8d877a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Files/file1.abc b/Assets/Files/file1.abc new file mode 100644 index 0000000..24a6e14 --- /dev/null +++ b/Assets/Files/file1.abc @@ -0,0 +1 @@ +Assets/Files/file1.abc
\ No newline at end of file diff --git a/Assets/Files/file1.abc.meta b/Assets/Files/file1.abc.meta new file mode 100644 index 0000000..22251e7 --- /dev/null +++ b/Assets/Files/file1.abc.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aefa20d591709b045912e3dfadca2c5a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: bundle01 + assetBundleVariant: ab diff --git a/Assets/Files/file1.bcd b/Assets/Files/file1.bcd new file mode 100644 index 0000000..4cf9b25 --- /dev/null +++ b/Assets/Files/file1.bcd @@ -0,0 +1 @@ +Assets/Files/file1.bcd
\ No newline at end of file diff --git a/Assets/Files/file1.bcd.meta b/Assets/Files/file1.bcd.meta new file mode 100644 index 0000000..35dcaee --- /dev/null +++ b/Assets/Files/file1.bcd.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4b63828827af1ed478bbf12cbb9c0c6b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: bundle02 + assetBundleVariant: ab diff --git a/Assets/Files/file1.txt b/Assets/Files/file1.txt new file mode 100644 index 0000000..5539980 --- /dev/null +++ b/Assets/Files/file1.txt @@ -0,0 +1 @@ +Assets/Files/file1.txt new
\ No newline at end of file diff --git a/Assets/Files/file1.txt.meta b/Assets/Files/file1.txt.meta new file mode 100644 index 0000000..4ca8c63 --- /dev/null +++ b/Assets/Files/file1.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 10a98b73673fc964aae6dea8633731e7 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle01 + assetBundleVariant: ab diff --git a/Assets/Files/file2.txt b/Assets/Files/file2.txt new file mode 100644 index 0000000..d44867e --- /dev/null +++ b/Assets/Files/file2.txt @@ -0,0 +1 @@ +Assets/Files/file2.txt new
\ No newline at end of file diff --git a/Assets/Files/file2.txt.meta b/Assets/Files/file2.txt.meta new file mode 100644 index 0000000..9916f2e --- /dev/null +++ b/Assets/Files/file2.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dd32edb13dadaaf438ddcccdadc99aa5 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle01 + assetBundleVariant: ab diff --git a/Assets/Files/file3.txt b/Assets/Files/file3.txt new file mode 100644 index 0000000..4a07a1c --- /dev/null +++ b/Assets/Files/file3.txt @@ -0,0 +1 @@ +Assets/Files/file3.txt new
\ No newline at end of file diff --git a/Assets/Files/file3.txt.meta b/Assets/Files/file3.txt.meta new file mode 100644 index 0000000..e8088ad --- /dev/null +++ b/Assets/Files/file3.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 56923216a78e12a448afff43e4809464 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle02 + assetBundleVariant: ab diff --git a/Assets/Files/file4.txt b/Assets/Files/file4.txt new file mode 100644 index 0000000..82b12f2 --- /dev/null +++ b/Assets/Files/file4.txt @@ -0,0 +1 @@ +Assets/Files/file4.txt new
\ No newline at end of file diff --git a/Assets/Files/file4.txt.meta b/Assets/Files/file4.txt.meta new file mode 100644 index 0000000..9f1b455 --- /dev/null +++ b/Assets/Files/file4.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 61286dc5c6111aa4b8fb362ae93ad064 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle02 + assetBundleVariant: ab diff --git a/Assets/Files/file5.txt b/Assets/Files/file5.txt new file mode 100644 index 0000000..44157c8 --- /dev/null +++ b/Assets/Files/file5.txt @@ -0,0 +1 @@ +Assets/Files/file5.txt new
\ No newline at end of file diff --git a/Assets/Files/file5.txt.meta b/Assets/Files/file5.txt.meta new file mode 100644 index 0000000..22abce0 --- /dev/null +++ b/Assets/Files/file5.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 468a4804a92c0b644bae4d718eea40d4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle03 + assetBundleVariant: ab diff --git a/Assets/Files/file6.txt b/Assets/Files/file6.txt new file mode 100644 index 0000000..506e23a --- /dev/null +++ b/Assets/Files/file6.txt @@ -0,0 +1 @@ +Assets/Files/file6.txt new
\ No newline at end of file diff --git a/Assets/Files/file6.txt.meta b/Assets/Files/file6.txt.meta new file mode 100644 index 0000000..7d206f0 --- /dev/null +++ b/Assets/Files/file6.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 24de50108fc7c554fa0ae4679c1615dc +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle03 + assetBundleVariant: ab diff --git a/Assets/Files/fileMapping.txt b/Assets/Files/fileMapping.txt new file mode 100644 index 0000000..a5eaa4c --- /dev/null +++ b/Assets/Files/fileMapping.txt @@ -0,0 +1,9 @@ +file1.abc,bundle01.ab +file1.txt,bundle01.ab +file1,bundle01.ab +file2,bundle01.ab +file1.bcd,bundle02.ab +file3,bundle02.ab +file4,bundle02.ab +file5,bundle03.ab +file6,bundle03.ab
\ No newline at end of file diff --git a/Assets/Files/fileMapping.txt.meta b/Assets/Files/fileMapping.txt.meta new file mode 100644 index 0000000..8d9c740 --- /dev/null +++ b/Assets/Files/fileMapping.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ee697760258728b44b5c79d0b52890e3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: bundle00 + assetBundleVariant: ab diff --git a/Assets/Plugins.meta b/Assets/Plugins.meta new file mode 100644 index 0000000..bf3d035 --- /dev/null +++ b/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa4d31a54cf0dd94784d2c0f4e5655ea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Trinary Software.meta b/Assets/Plugins/Trinary Software.meta new file mode 100644 index 0000000..616b6fb --- /dev/null +++ b/Assets/Plugins/Trinary Software.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 78018ab10cd0fdf48ba17bb3bc57ed62 +folderAsset: yes +timeCreated: 1456470394 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Trinary Software/Editor.meta b/Assets/Plugins/Trinary Software/Editor.meta new file mode 100644 index 0000000..2e833c9 --- /dev/null +++ b/Assets/Plugins/Trinary Software/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0d53480b6fb0cb246b44b84ec5156cc6 +folderAsset: yes +timeCreated: 1475431041 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Trinary Software/Editor/MecIcon.png b/Assets/Plugins/Trinary Software/Editor/MecIcon.png Binary files differnew file mode 100644 index 0000000..97f8edd --- /dev/null +++ b/Assets/Plugins/Trinary Software/Editor/MecIcon.png diff --git a/Assets/Plugins/Trinary Software/Editor/MecIcon.png.meta b/Assets/Plugins/Trinary Software/Editor/MecIcon.png.meta new file mode 100644 index 0000000..733447a --- /dev/null +++ b/Assets/Plugins/Trinary Software/Editor/MecIcon.png.meta @@ -0,0 +1,57 @@ +fileFormatVersion: 2 +guid: a0f854455b10ba44d819f36586b0909b +timeCreated: 1510247977 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + cubemapConvolution: 0 + cubemapConvolutionSteps: 7 + cubemapConvolutionExponent: 1.5 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 64 + textureSettings: + filterMode: 2 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + rGBM: 0 + compressionQuality: 50 + allowsAlphaSplitting: 0 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Trinary Software/Pro-only Features.pdf b/Assets/Plugins/Trinary Software/Pro-only Features.pdf Binary files differnew file mode 100644 index 0000000..67532be --- /dev/null +++ b/Assets/Plugins/Trinary Software/Pro-only Features.pdf diff --git a/Assets/Plugins/Trinary Software/Pro-only Features.pdf.meta b/Assets/Plugins/Trinary Software/Pro-only Features.pdf.meta new file mode 100644 index 0000000..ca8469a --- /dev/null +++ b/Assets/Plugins/Trinary Software/Pro-only Features.pdf.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce14f3c9291519249b0f1165984a41ba +timeCreated: 1471840991 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Trinary Software/Quick Start Guide.pdf b/Assets/Plugins/Trinary Software/Quick Start Guide.pdf Binary files differnew file mode 100644 index 0000000..4715cb5 --- /dev/null +++ b/Assets/Plugins/Trinary Software/Quick Start Guide.pdf diff --git a/Assets/Plugins/Trinary Software/Quick Start Guide.pdf.meta b/Assets/Plugins/Trinary Software/Quick Start Guide.pdf.meta new file mode 100644 index 0000000..4a34c89 --- /dev/null +++ b/Assets/Plugins/Trinary Software/Quick Start Guide.pdf.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2df0cfe12cb0d64c9d151d10f8ec206 +timeCreated: 1456009584 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Trinary Software/Timing.cs b/Assets/Plugins/Trinary Software/Timing.cs new file mode 100644 index 0000000..75ba9f1 --- /dev/null +++ b/Assets/Plugins/Trinary Software/Timing.cs @@ -0,0 +1,7059 @@ +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 + { + /// <summary> + /// The time between calls to SlowUpdate. + /// </summary> + [Tooltip("How quickly the SlowUpdate segment ticks.")] + public float TimeBetweenSlowUpdateCalls = 1f / 7f; + /// <summary> + /// 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. + /// </summary> + [Tooltip("How much data should be sent to the profiler window when it's open.")] + public DebugInfoType ProfilerDebugAmount; + /// <summary> + /// Whether the manual timeframe should automatically trigger during the update segment. + /// </summary> + [Tooltip("When using manual timeframe, should it run automatically after the update loop or only when TriggerManualTimframeUpdate is called.")] + public bool AutoTriggerManualTimeframe = true; + /// <summary> + /// The number of coroutines that are being run in the Update segment. + /// </summary> + [Tooltip("A count of the number of Update coroutines that are currently running."), Space(12)] + public int UpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the FixedUpdate segment. + /// </summary> + [Tooltip("A count of the number of FixedUpdate coroutines that are currently running.")] + public int FixedUpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the LateUpdate segment. + /// </summary> + [Tooltip("A count of the number of LateUpdate coroutines that are currently running.")] + public int LateUpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the SlowUpdate segment. + /// </summary> + [Tooltip("A count of the number of SlowUpdate coroutines that are currently running.")] + public int SlowUpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the RealtimeUpdate segment. + /// </summary> + [Tooltip("A count of the number of RealtimeUpdate coroutines that are currently running.")] + public int RealtimeUpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the EditorUpdate segment. + /// </summary> + [Tooltip("A count of the number of EditorUpdate coroutines that are currently running.")] + public int EditorUpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the EditorSlowUpdate segment. + /// </summary> + [Tooltip("A count of the number of EditorSlowUpdate coroutines that are currently running.")] + public int EditorSlowUpdateCoroutines; + /// <summary> + /// The number of coroutines that are being run in the EndOfFrame segment. + /// </summary> + [Tooltip("A count of the number of EndOfFrame coroutines that are currently running.")] + public int EndOfFrameCoroutines; + /// <summary> + /// The number of coroutines that are being run in the ManualTimeframe segment. + /// </summary> + [Tooltip("A count of the number of ManualTimeframe coroutines that are currently running.")] + public int ManualTimeframeCoroutines; + + /// <summary> + /// The time in seconds that the current segment has been running. + /// </summary> + [System.NonSerialized] + public float localTime; + /// <summary> + /// The time in seconds that the current segment has been running. + /// </summary> + public static float LocalTime { get { return Instance.localTime; } } + /// <summary> + /// The amount of time in fractional seconds that elapsed between this frame and the last frame. + /// </summary> + [System.NonSerialized] + public float deltaTime; + /// <summary> + /// The amount of time in fractional seconds that elapsed between this frame and the last frame. + /// </summary> + public static float DeltaTime { get { return Instance.deltaTime; } } + /// <summary> + /// 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. + /// </summary> + public System.Func<float, float> SetManualTimeframeTime; + /// <summary> + /// Used for advanced coroutine control. + /// </summary> + public static System.Func<IEnumerator<float>, CoroutineHandle, IEnumerator<float>> ReplacementFunction; + /// <summary> + /// This event fires just before each segment is run. + /// </summary> + public static event System.Action OnPreExecute; + /// <summary> + /// You can use "yield return Timing.WaitForOneFrame;" inside a coroutine function to go to the next frame. + /// </summary> + public const float WaitForOneFrame = float.NegativeInfinity; + /// <summary> + /// The main thread that (almost) everything in unity runs in. + /// </summary> + public static System.Threading.Thread MainThread { get; private set; } + /// <summary> + /// The handle of the current coroutine that is running. + /// </summary> + public static CoroutineHandle CurrentCoroutine { get { return Instance.currentCoroutine; } } + /// <summary> + /// The handle of the current coroutine that is running. + /// </summary> + 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<CoroutineHandle, HashSet<CoroutineHandle>> Links = new Dictionary<CoroutineHandle, HashSet<CoroutineHandle>>(); + private static readonly WaitForEndOfFrame EofWaitObject = new WaitForEndOfFrame(); + private readonly Dictionary<CoroutineHandle, HashSet<CoroutineHandle>> _waitingTriggers = new Dictionary<CoroutineHandle, HashSet<CoroutineHandle>>(); + private readonly HashSet<CoroutineHandle> _allWaiting = new HashSet<CoroutineHandle>(); + private readonly Dictionary<CoroutineHandle, ProcessIndex> _handleToIndex = new Dictionary<CoroutineHandle, ProcessIndex>(); + private readonly Dictionary<ProcessIndex, CoroutineHandle> _indexToHandle = new Dictionary<ProcessIndex, CoroutineHandle>(); + private readonly Dictionary<CoroutineHandle, string> _processTags = new Dictionary<CoroutineHandle, string>(); + private readonly Dictionary<string, HashSet<CoroutineHandle>> _taggedProcesses = new Dictionary<string, HashSet<CoroutineHandle>>(); + private readonly Dictionary<CoroutineHandle, int> _processLayers = new Dictionary<CoroutineHandle, int>(); + private readonly Dictionary<int, HashSet<CoroutineHandle>> _layeredProcesses = new Dictionary<int, HashSet<CoroutineHandle>>(); + + private IEnumerator<float>[] UpdateProcesses = new IEnumerator<float>[InitialBufferSizeLarge]; + private IEnumerator<float>[] LateUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + private IEnumerator<float>[] FixedUpdateProcesses = new IEnumerator<float>[InitialBufferSizeMedium]; + private IEnumerator<float>[] SlowUpdateProcesses = new IEnumerator<float>[InitialBufferSizeMedium]; + private IEnumerator<float>[] RealtimeUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + private IEnumerator<float>[] EditorUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + private IEnumerator<float>[] EditorSlowUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + private IEnumerator<float>[] EndOfFrameProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + private IEnumerator<float>[] ManualTimeframeProcesses = new IEnumerator<float>[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<Timing>() ?? instanceHome.AddComponent<Timing>(); + + _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); + } + } + + /// <summary> + /// 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. + /// </summary> + 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<float> _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; + } + + /// <summary> + /// Run a new coroutine in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, int layer) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, string tag) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, int layer, string tag) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, Segment segment) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, segment, null, null, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, Segment segment, int layer) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, segment, layer, null, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, Segment segment, string tag) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, segment, null, tag, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public static CoroutineHandle RunCoroutine(IEnumerator<float> coroutine, Segment segment, int layer, string tag) + { + return coroutine == null ? new CoroutineHandle() + : Instance.RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(Instance._instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, Segment.Update, null, null, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, GameObject gameObj) + { + return coroutine == null ? new CoroutineHandle() : RunCoroutineInternal(coroutine, Segment.Update, + gameObj == null ? (int?)null : gameObj.GetInstanceID(), null, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, int layer) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, Segment.Update, layer, null, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, string tag) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, Segment.Update, null, tag, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine on this Timing instance in the Update segment. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, int layer, string tag) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, Segment.Update, layer, tag, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, Segment segment) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, segment, null, null, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, Segment segment, GameObject gameObj) + { + return coroutine == null ? new CoroutineHandle() : RunCoroutineInternal(coroutine, segment, + gameObj == null ? (int?)null : gameObj.GetInstanceID(), null, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, Segment segment, int layer) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, segment, layer, null, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, Segment segment, string tag) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, segment, null, tag, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine on this Timing instance. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine on this Timing instance. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <returns>The coroutine's handle, which can be used for Wait and Kill operations.</returns> + public CoroutineHandle RunCoroutineOnInstance(IEnumerator<float> coroutine, Segment segment, int layer, string tag) + { + return coroutine == null ? new CoroutineHandle() + : RunCoroutineInternal(coroutine, segment, layer, tag, new CoroutineHandle(_instanceID), true); + } + + /// <summary> + /// Run a new coroutine in the Update segment, but not while the coroutine with the supplied handle is running. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="handle">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> coroutine, GameObject gameObj, SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutine(coroutine) : RunCoroutineSingleton(coroutine, gameObj.GetInstanceID(), behaviorOnCollision); + } + + /// <summary> + /// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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); + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> coroutine, GameObject gameObj, string tag, SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutineSingleton(coroutine, tag, behaviorOnCollision) + : RunCoroutineSingleton(coroutine, gameObj.GetInstanceID(), tag, behaviorOnCollision); + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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<CoroutineHandle> matches = new List<CoroutineHandle>(); + 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); + } + + /// <summary> + /// Run a new coroutine, but not while the coroutine with the supplied handle is running. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="handle">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> coroutine, Segment segment, GameObject gameObj, + SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutine(coroutine, segment) : RunCoroutineSingleton(coroutine, segment, gameObj.GetInstanceID(), behaviorOnCollision); + } + + /// <summary> + /// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine with the supplied graffitti unless there is already one or more coroutines running with both that tag and layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> coroutine, Segment segment, GameObject gameObj, string tag, + SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutineSingleton(coroutine, segment, tag, behaviorOnCollision) + : RunCoroutineSingleton(coroutine, segment, gameObj.GetInstanceID(), tag, behaviorOnCollision); + } + + /// <summary> + /// Run a new coroutine with the supplied graffitti unless there is already one or more coroutines running with both that tag and layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public static CoroutineHandle RunCoroutineSingleton(IEnumerator<float> 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<CoroutineHandle> matches = new List<CoroutineHandle>(); + 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment, but not while the coroutine with the supplied handle is running. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="handle">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> coroutine, GameObject gameObj, SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutineOnInstance(coroutine) + : RunCoroutineSingletonOnInstance(coroutine, gameObj.GetInstanceID(), behaviorOnCollision); + } + + /// <summary> + /// Run a new coroutine in the Update segment with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine in the Update segment with the supplied tag unless there is already one or more coroutines running with that tag. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> coroutine, GameObject gameObj, string tag, + SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutineSingletonOnInstance(coroutine, tag, behaviorOnCollision) + : RunCoroutineSingletonOnInstance(coroutine, gameObj.GetInstanceID(), tag, behaviorOnCollision); + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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<CoroutineHandle> matches = new List<CoroutineHandle>(); + 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); + } + + /// <summary> + /// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> coroutine, Segment segment, GameObject gameObj, + SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutineOnInstance(coroutine, segment) + : RunCoroutineSingletonOnInstance(coroutine, segment, gameObj.GetInstanceID(), behaviorOnCollision); + } + + /// <summary> + /// Run a new coroutine with the supplied layer unless there is already one or more coroutines running with that layer. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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); + } + + /// <summary> + /// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="gameObj">The new coroutine will be put on a layer corresponding to this gameObject.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> coroutine, Segment segment, GameObject gameObj, string tag, + SingletonBehavior behaviorOnCollision) + { + return gameObj == null ? RunCoroutineSingletonOnInstance(coroutine, segment, tag, behaviorOnCollision) + : RunCoroutineSingletonOnInstance(coroutine, segment, gameObj.GetInstanceID(), tag, behaviorOnCollision); + } + + /// <summary> + /// Run a new coroutine with the supplied tag unless there is already one or more coroutines running with that tag. + /// </summary> + /// <param name="coroutine">The new coroutine's handle.</param> + /// <param name="segment">The segment that the coroutine should run in.</param> + /// <param name="layer">A layer to attach to the coroutine, and to check for existing instances.</param> + /// <param name="tag">A tag to attach to the coroutine, and to check for existing instances.</param> + /// <param name="behaviorOnCollision">Should this coroutine fail to start, overwrite, or wait for any coroutines to finish if any matches are + /// currently running.</param> + /// <returns>The newly created or existing handle.</returns> + public CoroutineHandle RunCoroutineSingletonOnInstance(IEnumerator<float> 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<CoroutineHandle> matches = new List<CoroutineHandle>(); + 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<float> 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<float>[] oldProcArray = UpdateProcesses; + bool[] oldPausedArray = UpdatePaused; + bool[] oldHeldArray = UpdateHeld; + + UpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = FixedUpdateProcesses; + bool[] oldPausedArray = FixedUpdatePaused; + bool[] oldHeldArray = FixedUpdateHeld; + + FixedUpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = LateUpdateProcesses; + bool[] oldPausedArray = LateUpdatePaused; + bool[] oldHeldArray = LateUpdateHeld; + + LateUpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = SlowUpdateProcesses; + bool[] oldPausedArray = SlowUpdatePaused; + bool[] oldHeldArray = SlowUpdateHeld; + + SlowUpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = RealtimeUpdateProcesses; + bool[] oldPausedArray = RealtimeUpdatePaused; + bool[] oldHeldArray = RealtimeUpdateHeld; + + RealtimeUpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = EditorUpdateProcesses; + bool[] oldPausedArray = EditorUpdatePaused; + bool[] oldHeldArray = EditorUpdateHeld; + + EditorUpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = EditorSlowUpdateProcesses; + bool[] oldPausedArray = EditorSlowUpdatePaused; + bool[] oldHeldArray = EditorSlowUpdateHeld; + + EditorSlowUpdateProcesses = new IEnumerator<float>[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<float>[] oldProcArray = EndOfFrameProcesses; + bool[] oldPausedArray = EndOfFramePaused; + bool[] oldHeldArray = EndOfFrameHeld; + + EndOfFrameProcesses = new IEnumerator<float>[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<float>[] oldProcArray = ManualTimeframeProcesses; + bool[] oldPausedArray = ManualTimeframePaused; + bool[] oldHeldArray = ManualTimeframeHeld; + + ManualTimeframeProcesses = new IEnumerator<float>[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; + } + + /// <summary> + /// This will kill all coroutines running on the main MEC instance and reset the context. + /// </summary> + /// <returns>The number of coroutines that were killed.</returns> + public static int KillCoroutines() + { + return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(); + } + + /// <summary> + /// This will kill all coroutines running on the current MEC instance and reset the context. + /// </summary> + /// <returns>The number of coroutines that were killed.</returns> + public int KillCoroutinesOnInstance() + { + int retVal = _nextUpdateProcessSlot + _nextLateUpdateProcessSlot + _nextFixedUpdateProcessSlot + _nextSlowUpdateProcessSlot + + _nextRealtimeUpdateProcessSlot + _nextEditorUpdateProcessSlot + _nextEditorSlowUpdateProcessSlot + + _nextEndOfFrameProcessSlot + _nextManualTimeframeProcessSlot; + + UpdateProcesses = new IEnumerator<float>[InitialBufferSizeLarge]; + UpdatePaused = new bool[InitialBufferSizeLarge]; + UpdateHeld = new bool[InitialBufferSizeLarge]; + UpdateCoroutines = 0; + _nextUpdateProcessSlot = 0; + + LateUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + LateUpdatePaused = new bool[InitialBufferSizeSmall]; + LateUpdateHeld = new bool[InitialBufferSizeSmall]; + LateUpdateCoroutines = 0; + _nextLateUpdateProcessSlot = 0; + + FixedUpdateProcesses = new IEnumerator<float>[InitialBufferSizeMedium]; + FixedUpdatePaused = new bool[InitialBufferSizeMedium]; + FixedUpdateHeld = new bool[InitialBufferSizeMedium]; + FixedUpdateCoroutines = 0; + _nextFixedUpdateProcessSlot = 0; + + SlowUpdateProcesses = new IEnumerator<float>[InitialBufferSizeMedium]; + SlowUpdatePaused = new bool[InitialBufferSizeMedium]; + SlowUpdateHeld = new bool[InitialBufferSizeMedium]; + SlowUpdateCoroutines = 0; + _nextSlowUpdateProcessSlot = 0; + + RealtimeUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + RealtimeUpdatePaused = new bool[InitialBufferSizeSmall]; + RealtimeUpdateHeld = new bool[InitialBufferSizeSmall]; + RealtimeUpdateCoroutines = 0; + _nextRealtimeUpdateProcessSlot = 0; + + EditorUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + EditorUpdatePaused = new bool[InitialBufferSizeSmall]; + EditorUpdateHeld = new bool[InitialBufferSizeSmall]; + EditorUpdateCoroutines = 0; + _nextEditorUpdateProcessSlot = 0; + + EditorSlowUpdateProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + EditorSlowUpdatePaused = new bool[InitialBufferSizeSmall]; + EditorSlowUpdateHeld = new bool[InitialBufferSizeSmall]; + EditorSlowUpdateCoroutines = 0; + _nextEditorSlowUpdateProcessSlot = 0; + + EndOfFrameProcesses = new IEnumerator<float>[InitialBufferSizeSmall]; + EndOfFramePaused = new bool[InitialBufferSizeSmall]; + EndOfFrameHeld = new bool[InitialBufferSizeSmall]; + EndOfFrameCoroutines = 0; + _nextEndOfFrameProcessSlot = 0; + + ManualTimeframeProcesses = new IEnumerator<float>[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; + } + + /// <summary> + /// Kills the instance of the coroutine handle if it exists. + /// </summary> + /// <param name="handle">The handle of the coroutine to kill.</param> + /// <returns>The number of coroutines that were found and killed (0 or 1).</returns> + public static int KillCoroutines(CoroutineHandle handle) + { + return ActiveInstances[handle.Key] != null ? GetInstance(handle.Key).KillCoroutinesOnInstance(handle) : 0; + } + + /// <summary> + /// Kills all the coroutines in a list of coroutine handles. + /// </summary> + /// <param name="handles">A list of handles to be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public static int KillCoroutines(IEnumerable<CoroutineHandle> handles) + { + int count = 0; + foreach (CoroutineHandle handle in handles) + count += KillCoroutines(handle); + + return count; + } + + /// <summary> + /// Kills the instance of the coroutine handle on this Timing instance if it exists. + /// </summary> + /// <param name="handle">The handle of the coroutine to kill.</param> + /// <returns>The number of coroutines that were found and killed (Normally 0 or 1).</returns> + 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; + } + + /// <summary> + /// Kills all coroutines on the given layer. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public static int KillCoroutines(GameObject gameObj) + { + return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(gameObj.GetInstanceID()); + } + + /// <summary> + /// Kills all coroutines on the given layer. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public int KillCoroutinesOnInstance(GameObject gameObj) + { + return KillCoroutinesOnInstance(gameObj.GetInstanceID()); + } + + /// <summary> + /// Kills all coroutines on the given layer. + /// </summary> + /// <param name="layer">All coroutines on this layer will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public static int KillCoroutines(int layer) + { + return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(layer); + } + + /// <summary> + /// Kills all coroutines on the given layer. + /// </summary> + /// <param name="layer">All coroutines on this layer will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + 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; + } + + /// <summary> + /// Kills all coroutines that have the given tag. + /// </summary> + /// <param name="tag">All coroutines with this tag will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public static int KillCoroutines(string tag) + { + return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(tag); + } + + /// <summary> + /// Kills all coroutines that have the given tag. + /// </summary> + /// <param name="tag">All coroutines with this tag will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + 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; + } + + /// <summary> + /// Kills all coroutines with the given tag on the given layer. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be killed.</param> + /// <param name="tag">All coroutines with this tag on the given layer will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public static int KillCoroutines(GameObject gameObj, string tag) + { + return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(gameObj.GetInstanceID(), tag); + } + + /// <summary> + /// Kills all coroutines with the given tag on the given layer. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be killed.</param> + /// <param name="tag">All coroutines with this tag on the given layer will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public int KillCoroutinesOnInstance(GameObject gameObj, string tag) + { + return KillCoroutinesOnInstance(gameObj.GetInstanceID(), tag); + } + + /// <summary> + /// Kills all coroutines with the given tag on the given layer. + /// </summary> + /// <param name="layer">All coroutines on this layer with the given tag will be killed.</param> + /// <param name="tag">All coroutines with this tag on the given layer will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + public static int KillCoroutines(int layer, string tag) + { + return _instance == null ? 0 : _instance.KillCoroutinesOnInstance(layer, tag); + } + + /// <summary> + /// Kills all coroutines with the given tag on the given layer. + /// </summary> + /// <param name="layer">All coroutines on this layer with the given tag will be killed.</param> + /// <param name="tag">All coroutines with this tag on the given layer will be killed.</param> + /// <returns>The number of coroutines that were found and killed.</returns> + 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; + } + + /// <summary> + /// Retrieves the MEC manager that corresponds to the supplied instance id. + /// </summary> + /// <param name="ID">The instance ID.</param> + /// <returns>The manager, or null if not found.</returns> + public static Timing GetInstance(byte ID) + { + if (ID >= 0x10) + return null; + return ActiveInstances[ID]; + } + + /// <summary> + /// Use "yield return Timing.WaitForSeconds(time);" to wait for the specified number of seconds. + /// </summary> + /// <param name="waitTime">Number of seconds to wait.</param> + public static float WaitForSeconds(float waitTime) + { + if (float.IsNaN(waitTime)) waitTime = 0f; + return LocalTime + waitTime; + } + + /// <summary> + /// Use "yield return timingInstance.WaitForSecondsOnInstance(time);" to wait for the specified number of seconds. + /// </summary> + /// <param name="waitTime">Number of seconds to wait.</param> + 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; + } + } + + /// <summary> + /// This will pause all coroutines running on the main MEC instance until ResumeCoroutines is called. + /// </summary> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines() + { + return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(); + } + + /// <summary> + /// This will pause all coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <returns>The number of coroutines that were paused.</returns> + 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; + } + + /// <summary> + /// This will pause any matching coroutines until ResumeCoroutines is called. + /// </summary> + /// <param name="handle">The handle of the coroutine to pause.</param> + /// <returns>The number of coroutines that were paused (0 or 1).</returns> + public static int PauseCoroutines(CoroutineHandle handle) + { + return ActiveInstances[handle.Key] != null ? GetInstance(handle.Key).PauseCoroutinesOnInstance(handle) : 0; + } + + /// <summary> + /// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <param name="handle">The handle of the coroutine to pause.</param> + /// <returns>The number of coroutines that were paused (Normally 0 or 1).</returns> + 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; + } + + /// <summary> + /// This will pause any matching coroutines until ResumeCoroutines is called. + /// </summary> + /// <param name="handle">A list of handles to coroutines you want to pause.</param> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines(IEnumerable<CoroutineHandle> handles) + { + int total = 0; + var handlesEnum = handles.GetEnumerator(); + while (!handlesEnum.MoveNext()) + total += PauseCoroutines(handlesEnum.Current); + return total; + } + + /// <summary> + /// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines(GameObject gameObj) + { + return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(gameObj); + } + + /// <summary> + /// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public int PauseCoroutinesOnInstance(GameObject gameObj) + { + return gameObj == null ? 0 : PauseCoroutinesOnInstance(gameObj.GetInstanceID()); + } + + /// <summary> + /// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called. + /// </summary> + /// <param name="layer">Any coroutines on the matching layer will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines(int layer) + { + return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(layer); + } + + /// <summary> + /// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <param name="layer">Any coroutines on the matching layer will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + 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; + } + + /// <summary> + /// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called. + /// </summary> + /// <param name="tag">Any coroutines with a matching tag will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines(string tag) + { + return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(tag); + } + + /// <summary> + /// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <param name="tag">Any coroutines with a matching tag will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + 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; + } + + /// <summary> + /// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be paused.</param> + /// <param name="tag">Any coroutines with a matching tag will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines(GameObject gameObj, string tag) + { + return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(gameObj.GetInstanceID(), tag); + } + + /// <summary> + /// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be paused.</param> + /// <param name="tag">Any coroutines with a matching tag will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public int PauseCoroutinesOnInstance(GameObject gameObj, string tag) + { + return gameObj == null ? 0 : PauseCoroutinesOnInstance(gameObj.GetInstanceID(), tag); + } + + /// <summary> + /// This will pause any matching coroutines running on the current MEC instance until ResumeCoroutines is called. + /// </summary> + /// <param name="layer">Any coroutines on the matching layer will be paused.</param> + /// <param name="tag">Any coroutines with a matching tag will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + public static int PauseCoroutines(int layer, string tag) + { + return _instance == null ? 0 : _instance.PauseCoroutinesOnInstance(layer, tag); + } + + /// <summary> + /// This will pause any matching coroutines running on this MEC instance until ResumeCoroutinesOnInstance is called. + /// </summary> + /// <param name="layer">Any coroutines on the matching layer will be paused.</param> + /// <param name="tag">Any coroutines with a matching tag will be paused.</param> + /// <returns>The number of coroutines that were paused.</returns> + 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; + } + + /// <summary> + /// This resumes all coroutines on the current MEC instance if they are currently paused, otherwise it has + /// no effect. + /// </summary> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines() + { + return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(); + } + + /// <summary> + /// This resumes all coroutines on this MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <returns>The number of coroutines that were resumed.</returns> + 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; + } + + /// <summary> + /// This will resume any matching coroutines. + /// </summary> + /// <param name="handle">The handle of the coroutine to resume.</param> + /// <returns>The number of coroutines that were resumed. (Normally 0 or 1).</returns> + public static int ResumeCoroutines(CoroutineHandle handle) + { + return ActiveInstances[handle.Key] != null ? GetInstance(handle.Key).ResumeCoroutinesOnInstance(handle) : 0; + } + + /// <summary> + /// This will resume any matching coroutines. + /// </summary> + /// <param name="handles">A list of handles to coroutines you want to resume.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines(IEnumerable<CoroutineHandle> handles) + { + int count = 0; + var handlesEnum = handles.GetEnumerator(); + while (!handlesEnum.MoveNext()) + ResumeCoroutines(handlesEnum.Current); + return count; + } + + /// <summary> + /// This will resume any matching coroutines running on this MEC instance. + /// </summary> + /// <param name="handle">The handle of the coroutine to resume.</param> + /// <returns>The number of coroutines that were resumed. (Normally 0 or 1)</returns> + 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; + } + + /// <summary> + /// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has + /// no effect. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be resumed.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines(GameObject gameObj) + { + return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(gameObj.GetInstanceID()); + } + + /// <summary> + /// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be resumed.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public int ResumeCoroutinesOnInstance(GameObject gameObj) + { + return gameObj == null ? 0 : ResumeCoroutinesOnInstance(gameObj.GetInstanceID()); + } + + /// <summary> + /// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has + /// no effect. + /// </summary> + /// <param name="layer">Any coroutines previously paused on the matching layer will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines(int layer) + { + return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(layer); + } + + /// <summary> + /// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <param name="layer">Any coroutines previously paused on the matching layer will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + 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; + } + + /// <summary> + /// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <param name="tag">Any coroutines previously paused with a matching tag will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines(string tag) + { + return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(tag); + } + + /// <summary> + /// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <param name="tag">Any coroutines previously paused with a matching tag will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + 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; + } + + /// <summary> + /// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has + /// no effect. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be resumed.</param> + /// <param name="tag">Any coroutines previously paused with a matching tag will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines(GameObject gameObj, string tag) + { + return _instance == null ? 0 : _instance.ResumeCoroutinesOnInstance(gameObj.GetInstanceID(), tag); + } + + /// <summary> + /// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <param name="gameObj">All coroutines on the layer corresponding with this GameObject will be resumed.</param> + /// <param name="tag">Any coroutines previously paused with a matching tag will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public int ResumeCoroutinesOnInstance(GameObject gameObj, string tag) + { + return gameObj == null ? 0 : ResumeCoroutinesOnInstance(gameObj.GetInstanceID(), tag); + } + + /// <summary> + /// This resumes any matching coroutines on the current MEC instance if they are currently paused, otherwise it has + /// no effect. + /// </summary> + /// <param name="layer">Any coroutines previously paused on the matching layer will be resumend.</param> + /// <param name="tag">Any coroutines previously paused with a matching tag will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + public static int ResumeCoroutines(int layer, string tag) + { + return _instance == null? 0 : _instance.ResumeCoroutinesOnInstance(layer, tag); + } + + /// <summary> + /// This resumes any matching coroutines on this MEC instance if they are currently paused, otherwise it has no effect. + /// </summary> + /// <param name="layer">Any coroutines previously paused on the matching layer will be resumend.</param> + /// <param name="tag">Any coroutines previously paused with a matching tag will be resumend.</param> + /// <returns>The number of coroutines that were resumed.</returns> + 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; + } + + /// <summary> + /// Returns the tag associated with the coroutine that the given handle points to, if it is running. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <returns>The coroutine's tag, or null if there is no matching tag.</returns> + 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; + } + + /// <summary> + /// Returns the layer associated with the coroutine that the given handle points to, if it is running. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <returns>The coroutine's layer as a nullable integer, or null if there is no matching layer.</returns> + 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; + } + + /// <summary> + /// Returns >NET's name for the coroutine that the handle points to. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <returns>The underlying debug name of the coroutine, or info about the state of the coroutine.</returns> + 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(); + } + + /// <summary> + /// Returns the segment that the coroutine with the given handle is running on. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <returns>The coroutine's segment, or Segment.Invalid if it's not found.</returns> + public static Segment GetSegment(CoroutineHandle handle) + { + Timing inst = GetInstance(handle.Key); + return inst != null && inst._handleToIndex.ContainsKey(handle) ? inst._handleToIndex[handle].seg : Segment.Invalid; + } + + /// <summary> + /// Sets the coroutine that the handle points to to have the given tag. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <param name="newTag">The new tag to assign, or null to clear the tag.</param> + /// <param name="overwriteExisting">If set to false then the tag will not be changed if the coroutine has an existing tag.</param> + /// <returns>Whether the tag was set successfully.</returns> + 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; + } + + /// <summary> + /// Sets the coroutine that the handle points to to have the given layer. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <param name="newLayer">The new tag to assign.</param> + /// <param name="overwriteExisting">If set to false then the tag will not be changed if the coroutine has an existing tag.</param> + /// <returns>Whether the layer was set successfully.</returns> + 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; + } + + /// <summary> + /// Sets the segment for the coroutine with the given handle. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <param name="newSegment">The new segment to run the coroutine in.</param> + /// <returns>Whether the segment was set successfully.</returns> + 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; + } + + /// <summary> + /// Sets the coroutine that the handle points to to have the given tag. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <returns>Whether the tag was removed successfully.</returns> + public static bool RemoveTag(CoroutineHandle handle) + { + return SetTag(handle, null); + } + + /// <summary> + /// Sets the coroutine that the handle points to to have the given layer. + /// </summary> + /// <param name="handle">The handle to the coroutine.</param> + /// <returns>Whether the layer was removed successfully.</returns> + 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; + } + + /// <summary> + /// Tests to see if the handle you have points to a valid coroutine that is currently running. + /// </summary> + /// <param name="handle">The handle to test.</param> + /// <returns>Whether it's a valid coroutine.</returns> + public static bool IsRunning(CoroutineHandle handle) + { + Timing inst = GetInstance(handle.Key); + return inst != null && inst._handleToIndex.ContainsKey(handle) && !inst.CoindexIsNull(inst._handleToIndex[handle]); + } + + /// <summary> + /// Tests to see if the handle you have points to a coroutine that has not ended but is paused. + /// </summary> + /// <param name="handle">The handle to test.</param> + /// <returns>Whether it's a paused coroutine.</returns> + [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]); + } + + /// <summary> + /// Tests to see if the handle you have points to a coroutine that has not ended but is paused. + /// </summary> + /// <param name="handle">The handle to test.</param> + /// <returns>Whether it's a paused coroutine.</returns> + 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<CoroutineHandle> { 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<CoroutineHandle> { 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<float> CoindexExtract(ProcessIndex coindex) + { + IEnumerator<float> 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<float> 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; + } + } + + /// <returns>Whether it was already null.</returns> + private bool Nullify(CoroutineHandle handle) + { + return Nullify(_handleToIndex[handle]); + } + + /// <returns>Whether it was already null.</returns> + 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<float> CreateHold(ProcessIndex coindex, IEnumerator<float> 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<float> 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; + } + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine) + { + return WaitUntilDone(RunCoroutine(newCoroutine), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, string tag) + { + return WaitUntilDone(RunCoroutine(newCoroutine, tag), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, int layer) + { + return WaitUntilDone(RunCoroutine(newCoroutine, layer), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, int layer, string tag) + { + return WaitUntilDone(RunCoroutine(newCoroutine, layer, tag), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="segment">The segment that the new coroutine should run in.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, Segment segment) + { + return WaitUntilDone(RunCoroutine(newCoroutine, segment), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="segment">The segment that the new coroutine should run in.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, Segment segment, string tag) + { + return WaitUntilDone(RunCoroutine(newCoroutine, segment, tag), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="segment">The segment that the new coroutine should run in.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, Segment segment, int layer) + { + return WaitUntilDone(RunCoroutine(newCoroutine, segment, layer), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(newCoroutine);" to start a new coroutine and pause the + /// current one until it finishes. + /// </summary> + /// <param name="newCoroutine">The coroutine to pause for.</param> + /// <param name="segment">The segment that the new coroutine should run in.</param> + /// <param name="layer">An optional layer to attach to the coroutine which can later be used to identify this coroutine.</param> + /// <param name="tag">An optional tag to attach to the coroutine which can later be used to identify this coroutine.</param> + public static float WaitUntilDone(IEnumerator<float> newCoroutine, Segment segment, int layer, string tag) + { + return WaitUntilDone(RunCoroutine(newCoroutine, segment, layer, tag), true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(otherCoroutine);" to pause the current + /// coroutine until otherCoroutine is done. + /// </summary> + /// <param name="otherCoroutine">The coroutine to pause for.</param> + public static float WaitUntilDone(CoroutineHandle otherCoroutine) + { + return WaitUntilDone(otherCoroutine, true); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(otherCoroutine, false);" to pause the current + /// coroutine until otherCoroutine is done, supressing warnings. + /// </summary> + /// <param name="otherCoroutine">The coroutine to pause for.</param> + /// <param name="warnOnIssue">Post a warning if no hold action was actually performed.</param> + 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<CoroutineHandle>()); + } + + 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; + } + + /// <summary> + /// This will pause one coroutine until another coroutine finishes running. Note: This is NOT used with a yield return statement. + /// </summary> + /// <param name="handle">The coroutine that should be paused.</param> + /// <param name="otherHandle">The coroutine that will be waited for.</param> + /// <param name="warnOnIssue">Whether a warning should be logged if there is a problem.</param> + 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<CoroutineHandle>()); + } + + inst._waitingTriggers[otherHandle].Add(handle); + if (!inst._allWaiting.Contains(handle)) + inst._allWaiting.Add(handle); + inst.SetHeld(inst._handleToIndex[handle], true); + inst.SwapToLast(otherHandle, handle); + } + } + + /// <summary> + /// This will pause one coroutine until the other coroutines finish running. Note: This is NOT used with a yield return statement. + /// </summary> + /// <param name="handle">The coroutine that should be paused.</param> + /// <param name="otherHandles">A list of coroutines to be waited for.</param> + /// <param name="warnOnIssue">Whether a warning should be logged if there is a problem.</param> + public static void WaitForOtherHandles(CoroutineHandle handle, IEnumerable<CoroutineHandle> 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<CoroutineHandle>()); + } + + 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<float> 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<float> _StartWhenDone(CoroutineHandle handle, IEnumerator<float> 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<float> ReturnTmpRefForRepFunc(IEnumerator<float> coptr, CoroutineHandle handle) + { + return _tmpRef as IEnumerator<float>; + } + +#if !UNITY_2018_3_OR_NEWER + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(wwwObject);" to pause the current + /// coroutine until the wwwObject is done. + /// </summary> + /// <param name="wwwObject">The www object to pause for.</param> + public static float WaitUntilDone(WWW wwwObject) + { + if (wwwObject == null || wwwObject.isDone) return 0f; + + _tmpRef = wwwObject; + ReplacementFunction = WaitUntilDoneWwwHelper; + return float.NaN; + } + + private static IEnumerator<float> WaitUntilDoneWwwHelper(IEnumerator<float> coptr, CoroutineHandle handle) + { + return _StartWhenDone(_tmpRef as WWW, coptr); + } + + private static IEnumerator<float> _StartWhenDone(WWW wwwObject, IEnumerator<float> pausedProc) + { + while (!wwwObject.isDone) + yield return WaitForOneFrame; + + _tmpRef = pausedProc; + ReplacementFunction = ReturnTmpRefForRepFunc; + yield return float.NaN; + } +#endif + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(operation);" to pause the current + /// coroutine until the operation is done. + /// </summary> + /// <param name="operation">The operation variable returned.</param> + 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<float> _StartWhenDone(AsyncOperation operation, IEnumerator<float> pausedProc) + { + while (!operation.isDone) + yield return WaitForOneFrame; + + _tmpRef = pausedProc; + ReplacementFunction = ReturnTmpRefForRepFunc; + yield return float.NaN; + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilDone(operation);" to pause the current + /// coroutine until the operation is done. + /// </summary> + /// <param name="operation">The operation variable returned.</param> + 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<float> _StartWhenDone(CustomYieldInstruction operation, IEnumerator<float> pausedProc) + { + while (operation.keepWaiting) + yield return WaitForOneFrame; + + _tmpRef = pausedProc; + ReplacementFunction = ReturnTmpRefForRepFunc; + yield return float.NaN; + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilTrue(evaluatorFunc);" to pause the current + /// coroutine until the evaluator function returns true. + /// </summary> + /// <param name="evaluatorFunc">The evaluator function.</param> + public static float WaitUntilTrue(System.Func<bool> evaluatorFunc) + { + if (evaluatorFunc == null || evaluatorFunc()) return float.NaN; + _tmpRef = evaluatorFunc; + ReplacementFunction = WaitUntilTrueHelper; + return float.NaN; + } + + private static IEnumerator<float> WaitUntilTrueHelper(IEnumerator<float> coptr, CoroutineHandle handle) + { + return _StartWhenDone(_tmpRef as System.Func<bool>, false, coptr); + } + + /// <summary> + /// Use the command "yield return Timing.WaitUntilFalse(evaluatorFunc);" to pause the current + /// coroutine until the evaluator function returns false. + /// </summary> + /// <param name="evaluatorFunc">The evaluator function.</param> + public static float WaitUntilFalse(System.Func<bool> evaluatorFunc) + { + if (evaluatorFunc == null || !evaluatorFunc()) return float.NaN; + _tmpRef = evaluatorFunc; + ReplacementFunction = WaitUntilFalseHelper; + return float.NaN; + } + + private static IEnumerator<float> WaitUntilFalseHelper(IEnumerator<float> coptr, CoroutineHandle handle) + { + return _StartWhenDone(_tmpRef as System.Func<bool>, true, coptr); + } + + private static IEnumerator<float> _StartWhenDone(System.Func<bool> evaluatorFunc, bool continueOn, IEnumerator<float> pausedProc) + { + while (evaluatorFunc() == continueOn) + yield return WaitForOneFrame; + + _tmpRef = pausedProc; + ReplacementFunction = ReturnTmpRefForRepFunc; + yield return float.NaN; + } + + private IEnumerator<float> _InjectDelay(IEnumerator<float> proc, float waitTime) + { + yield return WaitForSecondsOnInstance(waitTime); + + _tmpRef = proc; + ReplacementFunction = ReturnTmpRefForRepFunc; + yield return float.NaN; + } + + /// <summary> + /// Keeps this coroutine from executing until UnlockCoroutine is called with a matching key. + /// </summary> + /// <param name="coroutine">The handle to the coroutine to be locked.</param> + /// <param name="key">The key to use. A new key can be generated by calling "new CoroutineHandle(0)".</param> + /// <returns>Whether the lock was successful.</returns> + 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<CoroutineHandle> { coroutine }); + else + _waitingTriggers[key].Add(coroutine); + + _allWaiting.Add(coroutine); + + SetHeld(_handleToIndex[coroutine], true); + + return true; + } + + /// <summary> + /// Unlocks a coroutine that has been locked, so long as the key matches. + /// </summary> + /// <param name="coroutine">The handle to the coroutine to be unlocked.</param> + /// <param name="key">The key that the coroutine was previously locked with.</param> + /// <returns>Whether the coroutine was successfully unlocked.</returns> + 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; + } + + /// <summary> + /// 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. + /// </summary> + /// <param name="master">The coroutine that generates the link events</param> + /// <param name="slave">The coroutine that recieves the link events</param> + /// <returns>The number of coroutines that were linked.</returns> + 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<CoroutineHandle> { slave }); + return 1; + } + } + + /// <summary> + /// This will remove the link between two coroutine handles if one exists. + /// </summary> + /// <param name="master">The coroutine that generates the link events</param> + /// <param name="slave">The coroutine that recieves the link events</param> + /// <param name="twoWay">if true this will also remove any links that exist from the slave to the master</param> + /// <returns>The number of coroutines that were unlinked.</returns> + 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; + } + + /// <summary> + /// You can use something like "yield return Timing.GetMyHandle(x => myHandle = x)" inside a running coroutine to get + /// that coroutine's handle. + /// </summary> + /// <param name="reciever">The function that will recieve the handle.</param> + public static float GetMyHandle(System.Action<CoroutineHandle> reciever) + { + _tmpRef = reciever; + ReplacementFunction = GetHandleHelper; + return float.NaN; + } + + private static IEnumerator<float> GetHandleHelper(IEnumerator<float> input, CoroutineHandle handle) + { + System.Action<CoroutineHandle> reciever = _tmpRef as System.Action<CoroutineHandle>; + if (reciever != null) + reciever(handle); + return input; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(segment);" to switch this coroutine to + /// the given segment on the default instance. + /// </summary> + /// <param name="newSegment">The new segment to run in.</param> + public static float SwitchCoroutine(Segment newSegment) + { + _tmpSegment = newSegment; + ReplacementFunction = SwitchCoroutineRepS; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepS(IEnumerator<float> 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; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(segment, tag);" to switch this coroutine to + /// the given values. + /// </summary> + /// <param name="newSegment">The new segment to run in.</param> + /// <param name="newTag">The new tag to apply, or null to remove this coroutine's tag.</param> + public static float SwitchCoroutine(Segment newSegment, string newTag) + { + _tmpSegment = newSegment; + _tmpRef = newTag; + ReplacementFunction = SwitchCoroutineRepST; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepST(IEnumerator<float> 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; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(segment, layer);" to switch this coroutine to + /// the given values. + /// </summary> + /// <param name="newSegment">The new segment to run in.</param> + /// <param name="newLayer">The new layer to apply.</param> + public static float SwitchCoroutine(Segment newSegment, int newLayer) + { + _tmpSegment = newSegment; + _tmpInt = newLayer; + ReplacementFunction = SwitchCoroutineRepSL; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepSL(IEnumerator<float> 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; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(segment, layer, tag);" to switch this coroutine to + /// the given values. + /// </summary> + /// <param name="newSegment">The new segment to run in.</param> + /// <param name="newLayer">The new layer to apply.</param> + /// <param name="newTag">The new tag to apply, or null to remove this coroutine's tag.</param> + public static float SwitchCoroutine(Segment newSegment, int newLayer, string newTag) + { + _tmpSegment = newSegment; + _tmpInt = newLayer; + _tmpRef = newTag; + ReplacementFunction = SwitchCoroutineRepSLT; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepSLT(IEnumerator<float> coptr, CoroutineHandle handle) + { + GetInstance(handle.Key).RunCoroutineInternal(coptr, _tmpSegment, _tmpInt, _tmpRef as string, handle, false); + return null; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(tag);" to switch this coroutine to + /// the given tag. + /// </summary> + /// <param name="newTag">The new tag to apply, or null to remove this coroutine's tag.</param> + public static float SwitchCoroutine(string newTag) + { + _tmpRef = newTag; + ReplacementFunction = SwitchCoroutineRepT; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepT(IEnumerator<float> coptr, CoroutineHandle handle) + { + Timing instance = GetInstance(handle.Key); + instance.RemoveTagOnInstance(handle); + if ((_tmpRef as string) != null) + instance.AddTagOnInstance((string)_tmpRef, handle); + return coptr; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(layer);" to switch this coroutine to + /// the given layer. + /// </summary> + /// <param name="newLayer">The new layer to apply.</param> + public static float SwitchCoroutine(int newLayer) + { + _tmpInt = newLayer; + ReplacementFunction = SwitchCoroutineRepL; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepL(IEnumerator<float> coptr, CoroutineHandle handle) + { + RemoveLayer(handle); + GetInstance(handle.Key).AddLayerOnInstance(_tmpInt, handle); + return coptr; + } + + /// <summary> + /// Use the command "yield return Timing.SwitchCoroutine(layer, tag);" to switch this coroutine to + /// the given tag. + /// </summary> + /// <param name="newLayer">The new layer to apply.</param> + /// <param name="newTag">The new tag to apply, or null to remove this coroutine's tag.</param> + public static float SwitchCoroutine(int newLayer, string newTag) + { + _tmpInt = newLayer; + _tmpRef = newTag; + ReplacementFunction = SwitchCoroutineRepLT; + + return float.NaN; + } + + private static IEnumerator<float> SwitchCoroutineRepLT(IEnumerator<float> 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; + } + + /// <summary> + /// Calls the specified action after a specified number of seconds. + /// </summary> + /// <param name="delay">The number of seconds to wait before calling the action.</param> + /// <param name="action">The action to call.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallDelayed(float delay, System.Action action) + { + return action == null ? new CoroutineHandle() : RunCoroutine(Instance._DelayedCall(delay, action, null)); + } + + /// <summary> + /// Calls the specified action after a specified number of seconds. + /// </summary> + /// <param name="delay">The number of seconds to wait before calling the action.</param> + /// <param name="action">The action to call.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallDelayedOnInstance(float delay, System.Action action) + { + return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_DelayedCall(delay, action, null)); + } + + /// <summary> + /// Calls the specified action after a specified number of seconds. + /// </summary> + /// <param name="delay">The number of seconds to wait before calling the action.</param> + /// <param name="action">The action to call.</param> + /// <param name="gameObject">A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed + /// before calling the action.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallDelayed(float delay, System.Action action, GameObject gameObject) + { + return action == null ? new CoroutineHandle() : RunCoroutine(Instance._DelayedCall(delay, action, gameObject), gameObject); + } + + /// <summary> + /// Calls the specified action after a specified number of seconds. + /// </summary> + /// <param name="delay">The number of seconds to wait before calling the action.</param> + /// <param name="action">The action to call.</param> + /// <param name="gameObject">A GameObject that will be tagged onto the coroutine and checked to make sure it hasn't been destroyed + /// before calling the action.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallDelayedOnInstance(float delay, System.Action action, GameObject gameObject) + { + return action == null ? new CoroutineHandle() : RunCoroutineOnInstance(_DelayedCall(delay, action, gameObject), gameObject); + } + + private IEnumerator<float> _DelayedCall(float delay, System.Action action, GameObject cancelWith) + { + yield return WaitForSecondsOnInstance(delay); + + if (ReferenceEquals(cancelWith, null) || cancelWith != null) + action(); + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + 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<float> _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<float> _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(); + } + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallPeriodically<T>(T reference, float timeframe, float period, + System.Action<T> action, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallPeriodicallyOnInstance<T>(T reference, float timeframe, float period, + System.Action<T> action, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallPeriodically<T>(T reference, float timeframe, float period, + System.Action<T> action, GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallPeriodicallyOnInstance<T>(T reference, float timeframe, float period, + System.Action<T> action, GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallPeriodically<T>(T reference, float timeframe, float period, System.Action<T> action, + Segment timing, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallPeriodicallyOnInstance<T>(T reference, float timeframe, float period, System.Action<T> action, + Segment timing, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallPeriodically<T>(T reference, float timeframe, float period, System.Action<T> action, + Segment timing, GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action at the given rate for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each period.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="period">The amount of time between calls.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallPeriodicallyOnInstance<T>(T reference, float timeframe, float period, System.Action<T> action, + Segment timing, GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallContinuously<T>(T reference, float timeframe, System.Action<T> action, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallContinuouslyOnInstance<T>(T reference, float timeframe, System.Action<T> action, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallContinuously<T>(T reference, float timeframe, System.Action<T> action, + GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallContinuouslyOnInstance<T>(T reference, float timeframe, System.Action<T> action, + GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallContinuously<T>(T reference, float timeframe, System.Action<T> action, + Segment timing, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallContinuouslyOnInstance<T>(T reference, float timeframe, System.Action<T> action, + Segment timing, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public static CoroutineHandle CallContinuously<T>(T reference, float timeframe, System.Action<T> action, + Segment timing, GameObject gameObject, System.Action<T> 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; + } + + /// <summary> + /// Calls the supplied action every frame for a given number of seconds. + /// </summary> + /// <param name="reference">A value that will be passed in to the supplied action each frame.</param> + /// <param name="timeframe">The number of seconds that this function should run. Use float.PositiveInfinity to run indefinitely.</param> + /// <param name="action">The action to call every frame.</param> + /// <param name="timing">The timing segment to run in.</param> + /// <param name="gameObject">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.</param> + /// <param name="onDone">An optional action to call when this function finishes.</param> + /// <returns>The handle to the coroutine that is started by this function.</returns> + public CoroutineHandle CallContinuouslyOnInstance<T>(T reference, float timeframe, System.Action<T> action, + Segment timing, GameObject gameObject, System.Action<T> 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<float> _WatchCall<T>(T reference, float timeframe, CoroutineHandle handle, GameObject gObject, System.Action<T> onDone) + { + yield return WaitForSecondsOnInstance(timeframe); + + KillCoroutinesOnInstance(handle); + + if (onDone != null && (ReferenceEquals(gObject, null) || gObject != null)) + onDone(reference); + } + + private IEnumerator<float> _CallContinuously<T>(T reference, float period, System.Action<T> 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<ProcessIndex> + { + 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<T>(T original) where T : Object { } + + [System.Obsolete("Just.. no.", true)] + public new static T FindObjectOfType<T>() where T : Object { return null; } + + [System.Obsolete("Just.. no.", true)] + public new static Object FindObjectOfType(System.Type t) { return null; } + + [System.Obsolete("Just.. no.", true)] + public new static T[] FindObjectsOfType<T>() where T : Object { return null; } + + [System.Obsolete("Just.. no.", true)] + public new static Object[] FindObjectsOfType(System.Type t) { return null; } + + [System.Obsolete("Just.. no.", true)] + public new static void print(object message) { } + } + + /// <summary> + /// The timing segment that a coroutine is running in or should be run in. + /// </summary> + public enum Segment + { + /// <summary> + /// Sometimes returned as an error state + /// </summary> + Invalid = -1, + /// <summary> + /// This is the default timing segment + /// </summary> + Update, + /// <summary> + /// This is primarily used for physics calculations + /// </summary> + FixedUpdate, + /// <summary> + /// This is run immediately after update + /// </summary> + LateUpdate, + /// <summary> + /// This executes, by default, about as quickly as the eye can detect changes in a text field + /// </summary> + SlowUpdate, + /// <summary> + /// This is the same as update, but it ignores Unity's timescale + /// </summary> + RealtimeUpdate, + /// <summary> + /// This is a coroutine that runs in the unity editor while your app is not in play mode + /// </summary> + EditorUpdate, + /// <summary> + /// This executes in the unity editor about as quickly as the eye can detect changes in a text field + /// </summary> + EditorSlowUpdate, + /// <summary> + /// This segment executes as the very last action before the frame is done + /// </summary> + EndOfFrame, + /// <summary> + /// This segment can be configured to execute and/or define its notion of time in custom ways + /// </summary> + ManualTimeframe + } + + /// <summary> + /// How much debug info should be sent to the Unity profiler. NOTE: Setting this to anything above none shows up in the profiler as a + /// decrease in performance and a memory alloc. Those effects do not translate onto device. + /// </summary> + public enum DebugInfoType + { + /// <summary> + /// None coroutines will be separated in the Unity profiler + /// </summary> + None, + /// <summary> + /// The Unity profiler will identify each coroutine individually + /// </summary> + SeperateCoroutines, + /// <summary> + /// Coroutines will be separated and any tags or layers will be identified + /// </summary> + SeperateTags + } + + /// <summary> + /// How the new coroutine should act if there are any existing coroutines running. + /// </summary> + public enum SingletonBehavior + { + /// <summary> + /// Don't run this corutine if there are any matches + /// </summary> + Abort, + /// <summary> + /// Kill any matching coroutines when this one runs + /// </summary> + Overwrite, + /// <summary> + /// Pause this coroutine until any matches finish running + /// </summary> + Wait + } + + /// <summary> + /// A handle for a MEC coroutine. + /// </summary> + public struct CoroutineHandle : System.IEquatable<CoroutineHandle> + { + private const byte ReservedSpace = 0x0F; + private readonly static int[] NextIndex = { ReservedSpace + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + private readonly int _id; + + public byte Key { get { return (byte)(_id & ReservedSpace); } } + + public CoroutineHandle(byte ind) + { + if (ind > ReservedSpace) + ind -= ReservedSpace; + + _id = NextIndex[ind] + ind; + NextIndex[ind] += ReservedSpace + 1; + } + + public bool Equals(CoroutineHandle other) + { + return _id == other._id; + } + + public override bool Equals(object other) + { + if (other is CoroutineHandle) + return Equals((CoroutineHandle)other); + return false; + } + + public static bool operator ==(CoroutineHandle a, CoroutineHandle b) + { + return a._id == b._id; + } + + public static bool operator !=(CoroutineHandle a, CoroutineHandle b) + { + return a._id != b._id; + } + + public override int GetHashCode() + { + return _id; + } + + public override string ToString() + { + if (Timing.GetTag(this) == null) + { + if (Timing.GetLayer(this) == null) + return Timing.GetDebugName(this); + else + return Timing.GetDebugName(this) + " Layer: " + Timing.GetLayer(this); + } + else + { + if (Timing.GetLayer(this) == null) + return Timing.GetDebugName(this) + " Tag: " + Timing.GetTag(this); + else + return Timing.GetDebugName(this) + " Tag: " + Timing.GetTag(this) + " Layer: " + Timing.GetLayer(this); + } + } + + /// <summary> + /// Get or set the corrosponding coroutine's tag. Null removes the tag or represents no tag assigned. + /// </summary> + public string Tag + { + get { return Timing.GetTag(this); } + set { Timing.SetTag(this, value); } + } + + /// <summary> + /// Get or set the corrosponding coroutine's layer. Null removes the layer or represents no layer assigned. + /// </summary> + public int? Layer + { + get { return Timing.GetLayer(this); } + set + { + if (value == null) + Timing.RemoveLayer(this); + else + Timing.SetLayer(this, (int)value); + } + } + + /// <summary> + /// Get or set the coorsponding coroutine's segment. + /// </summary> + public Segment Segment + { + get { return Timing.GetSegment(this); } + set { Timing.SetSegment(this, value); } + } + + /// <summary> + /// Is true until the coroutine function ends or is killed. Setting this to false will kill the coroutine. + /// </summary> + public bool IsRunning + { + get { return Timing.IsRunning(this); } + set { if(!value) Timing.KillCoroutines(this); } + } + + /// <summary> + /// Is true while the coroutine is paused. + /// NOTE: This value was inverted. Replaced with IsAliveAndPaused which is not inverted. + /// </summary> + [System.Obsolete("This value was inverted. Replaced with IsAliveAndPaused which is not inverted.", false)] + public bool IsPaused + { + get { return Timing.IsPaused(this); } + set { if (value) Timing.PauseCoroutines(this); else Timing.ResumeCoroutines(this);} + } + + /// <summary> + /// Is true while the coroutine is paused. Setting this value will pause or resume the coroutine. + /// </summary> + public bool IsAliveAndPaused + { + get { return Timing.IsAliveAndPaused(this); } + set { if (value) Timing.PauseCoroutines(this); else Timing.ResumeCoroutines(this); } + } + + /// <summary> + /// Is true if this handle may have been a valid handle at some point. (i.e. is not an uninitialized handle, error handle, or a key to a coroutine lock) + /// </summary> + public bool IsValid + { + get { return Key != 0; } + } + } +} + +public static class MECExtensionMethods +{ + /// <summary> + /// Adds a delay to the beginning of this coroutine. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="timeToDelay">The number of seconds to delay this coroutine.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Delay(this IEnumerator<float> coroutine, float timeToDelay) + { + yield return MEC.Timing.WaitForSeconds(timeToDelay); + + while (coroutine.MoveNext()) + yield return coroutine.Current; + } + + /// <summary> + /// Adds a delay to the beginning of this coroutine until a function returns true. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="condition">The coroutine will be paused until this function returns true.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Delay(this IEnumerator<float> coroutine, System.Func<bool> condition) + { + while (!condition()) + yield return 0f; + + while (coroutine.MoveNext()) + yield return coroutine.Current; + } + + /// <summary> + /// Adds a delay to the beginning of this coroutine until a function returns true. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="data">A variable that will be passed into the condition function each time it is tested.</param> + /// <param name="condition">The coroutine will be paused until this function returns true.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Delay<T>(this IEnumerator<float> coroutine, T data, System.Func<T, bool> condition) + { + while (!condition(data)) + yield return 0f; + + while (coroutine.MoveNext()) + yield return coroutine.Current; + } + + /// <summary> + /// Adds a delay to the beginning of this coroutine in frames. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="framesToDelay">The number of frames to delay this coroutine.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> DelayFrames(this IEnumerator<float> coroutine, int framesToDelay) + { + while(framesToDelay-- > 0) + yield return 0f; + + while (coroutine.MoveNext()) + yield return coroutine.Current; + } + + /// <summary> + /// Cancels this coroutine when the supplied game object is destroyed or made inactive. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="gameObject">The GameObject to test.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> CancelWith(this IEnumerator<float> coroutine, GameObject gameObject) + { + while (MEC.Timing.MainThread != System.Threading.Thread.CurrentThread || + (gameObject && gameObject.activeInHierarchy && coroutine.MoveNext())) + yield return coroutine.Current; + } + + /// <summary> + /// Cancels this coroutine when either of the supplied game objects are destroyed or made inactive. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="gameObject1">The first GameObject to test.</param> + /// <param name="gameObject2">The second GameObject to test</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> CancelWith(this IEnumerator<float> coroutine, GameObject gameObject1, GameObject gameObject2) + { + while (MEC.Timing.MainThread != System.Threading.Thread.CurrentThread || (gameObject1 && gameObject1.activeInHierarchy && + gameObject2 && gameObject2.activeInHierarchy && coroutine.MoveNext())) + yield return coroutine.Current; + } + + /// <summary> + /// Cancels this coroutine when the supplied monobehavior is removed from its game object, or the game object is made inactive or destroyed. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="gameObject">The GameObject to test.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> CancelWith<T>(this IEnumerator<float> coroutine, T script) where T : MonoBehaviour + { + GameObject myGO = script.gameObject; + + while (MEC.Timing.MainThread != System.Threading.Thread.CurrentThread || + (myGO && myGO.activeInHierarchy && script != null && coroutine.MoveNext())) + yield return coroutine.Current; + } + + /// <summary> + /// Cancels this coroutine when the supplied function returns false. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="condition">The test function. True for continue, false to stop.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> CancelWith(this IEnumerator<float> coroutine, System.Func<bool> condition) + { + if (condition == null) yield break; + + while (MEC.Timing.MainThread != System.Threading.Thread.CurrentThread || (condition() && coroutine.MoveNext())) + yield return coroutine.Current; + } + + /// <summary> + /// Cancels this coroutine when the supplied game object is destroyed, but only pauses it while it's inactive. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="gameObject">The GameObject to test.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> PauseWith(this IEnumerator<float> coroutine, GameObject gameObject) + { + while(MEC.Timing.MainThread == System.Threading.Thread.CurrentThread && gameObject) + { + if (gameObject.activeInHierarchy) + { + if (coroutine.MoveNext()) + yield return coroutine.Current; + else + yield break; + } + else + { + yield return MEC.Timing.WaitForOneFrame; + } + } + } + + /// <summary> + /// Cancels this coroutine when either of the supplied game objects are destroyed, but only pauses them while they're inactive. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="gameObject1">The first GameObject to test.</param> + /// <param name="gameObject2">The second GameObject to test</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> PauseWith(this IEnumerator<float> coroutine, GameObject gameObject1, GameObject gameObject2) + { + while (MEC.Timing.MainThread == System.Threading.Thread.CurrentThread && gameObject1 && gameObject2) + { + if (gameObject1.activeInHierarchy && gameObject2.activeInHierarchy) + { + if (coroutine.MoveNext()) + yield return coroutine.Current; + else + yield break; + } + else + { + yield return MEC.Timing.WaitForOneFrame; + } + } + } + + /// <summary> + /// Cancels this coroutine when the supplied monobehavior is removed from its game object, or the game object is destroyed. Pauses the coroutine + /// if the game object or script is disabled. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="gameObject">The GameObject to test.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> PauseWith<T>(this IEnumerator<float> coroutine, T script) where T : MonoBehaviour + { + GameObject myGO = script.gameObject; + + while (MEC.Timing.MainThread == System.Threading.Thread.CurrentThread && myGO && myGO.GetComponent<T>() != null) + { + if (myGO.activeInHierarchy && script.enabled) + { + if (coroutine.MoveNext()) + yield return coroutine.Current; + else + yield break; + } + else + { + yield return MEC.Timing.WaitForOneFrame; + } + } + } + + /// <summary> + /// Pauses this coroutine whenever the supplied function returns false. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="condition">The test function. True for continue, false to stop.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> PauseWith(this IEnumerator<float> coroutine, System.Func<bool> condition) + { + if (condition == null) yield break; + + while (MEC.Timing.MainThread != System.Threading.Thread.CurrentThread || (condition() && coroutine.MoveNext())) + yield return coroutine.Current; + } + + /// <summary> + /// Runs the supplied coroutine immediately after this one. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="nextCoroutine">The coroutine to run next.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Append(this IEnumerator<float> coroutine, IEnumerator<float> nextCoroutine) + { + while (coroutine.MoveNext()) + yield return coroutine.Current; + + if (nextCoroutine == null) yield break; + + while (nextCoroutine.MoveNext()) + yield return nextCoroutine.Current; + } + + /// <summary> + /// Runs the supplied function immediately after this coroutine finishes. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="onDone">The action to run after this coroutine finishes.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Append(this IEnumerator<float> coroutine, System.Action onDone) + { + while (coroutine.MoveNext()) + yield return coroutine.Current; + + if (onDone != null) + onDone(); + } + + /// <summary> + /// Runs the supplied coroutine immediately before this one. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="lastCoroutine">The coroutine to run first.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Prepend(this IEnumerator<float> coroutine, IEnumerator<float> lastCoroutine) + { + if (lastCoroutine != null) + while (lastCoroutine.MoveNext()) + yield return lastCoroutine.Current; + + while (coroutine.MoveNext()) + yield return coroutine.Current; + } + + /// <summary> + /// Runs the supplied function immediately before this coroutine starts. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="onStart">The action to run before this coroutine starts.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Prepend(this IEnumerator<float> coroutine, System.Action onStart) + { + if (onStart != null) + onStart(); + + while (coroutine.MoveNext()) + yield return coroutine.Current; + } + + /// <summary> + /// Combines the this coroutine with another and runs them in a combined handle. + /// </summary> + /// <param name="coroutineA">The coroutine handle to act upon.</param> + /// <param name="coroutineB">The coroutine handle to combine.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Superimpose(this IEnumerator<float> coroutineA, IEnumerator<float> coroutineB) + { + return Superimpose(coroutineA, coroutineB, MEC.Timing.Instance); + } + + /// <summary> + /// Combines the this coroutine with another and runs them in a combined handle. + /// </summary> + /// <param name="coroutineA">The coroutine handle to act upon.</param> + /// <param name="coroutineB">The coroutine handle to combine.</param> + /// <param name="instance">The timing instance that this will be run in, if not the default instance.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Superimpose(this IEnumerator<float> coroutineA, IEnumerator<float> coroutineB, MEC.Timing instance) + { + while (coroutineA != null || coroutineB != null) + { + if (coroutineA != null && !(instance.localTime < coroutineA.Current) && !coroutineA.MoveNext()) + coroutineA = null; + + if (coroutineB != null && !(instance.localTime < coroutineB.Current) && !coroutineB.MoveNext()) + coroutineB = null; + + if ((coroutineA != null && float.IsNaN(coroutineA.Current)) || (coroutineB != null && float.IsNaN(coroutineB.Current))) + yield return float.NaN; + else if (coroutineA != null && coroutineB != null) + yield return coroutineA.Current < coroutineB.Current ? coroutineA.Current : coroutineB.Current; + else if (coroutineA == null && coroutineB != null) + yield return coroutineB.Current; + else if (coroutineA != null) + yield return coroutineA.Current; + } + } + + /// <summary> + /// Uses the passed in function to change the return values of this coroutine. + /// </summary> + /// <param name="coroutine">The coroutine handle to act upon.</param> + /// <param name="newReturn">A function that takes the current return value and returns the new return.</param> + /// <returns>The modified coroutine handle.</returns> + public static IEnumerator<float> Hijack(this IEnumerator<float> coroutine, System.Func<float, float> newReturn) + { + if (newReturn == null) yield break; + + while (coroutine.MoveNext()) + yield return newReturn(coroutine.Current); + } +} + diff --git a/Assets/Plugins/Trinary Software/Timing.cs.meta b/Assets/Plugins/Trinary Software/Timing.cs.meta new file mode 100644 index 0000000..21e6c1b --- /dev/null +++ b/Assets/Plugins/Trinary Software/Timing.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2d2433f4570c1404da40af9ea0b12741 +timeCreated: 1510248004 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: a0f854455b10ba44d819f36586b0909b, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs.meta b/Assets/Prefabs.meta new file mode 100644 index 0000000..11c33d6 --- /dev/null +++ b/Assets/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d20f7aa6880e3a340bdf0ac579d42ac3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/prefab1.prefab b/Assets/Prefabs/prefab1.prefab new file mode 100644 index 0000000..8b96227 --- /dev/null +++ b/Assets/Prefabs/prefab1.prefab @@ -0,0 +1,81 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 0} + m_RootGameObject: {fileID: 1507762233650148} + m_IsPrefabAsset: 1 +--- !u!1 &1507762233650148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 6 + m_Component: + - component: {fileID: 224318387343127358} + - component: {fileID: 222347782337831766} + - component: {fileID: 114157529808213254} + m_Layer: 0 + m_Name: prefab1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &114157529808213254 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1507762233650148} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -98529514, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Texture: {fileID: 2800000, guid: 15761c4d3ca73764abf9183f904ff833, type: 3} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &222347782337831766 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1507762233650148} + m_CullTransparentMesh: 0 +--- !u!224 &224318387343127358 +RectTransform: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1507762233650148} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -8.96875} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -2.6053119, y: 1.173451} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/Prefabs/prefab1.prefab.meta b/Assets/Prefabs/prefab1.prefab.meta new file mode 100644 index 0000000..db3ea3e --- /dev/null +++ b/Assets/Prefabs/prefab1.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d82dcc7826322f74bb9e4e24d6f19b78 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 100100000 + userData: + assetBundleName: bundle01 + assetBundleVariant: ab diff --git a/Assets/Resources.meta b/Assets/Resources.meta new file mode 100644 index 0000000..635ce5e --- /dev/null +++ b/Assets/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fee5e930016317b4caa203c58f1ed468 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/SubFolder.meta b/Assets/Resources/SubFolder.meta new file mode 100644 index 0000000..fdb7c8a --- /dev/null +++ b/Assets/Resources/SubFolder.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 20f7eeedb95995f4485a01734e7ab818 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/SubFolder/res1.txt b/Assets/Resources/SubFolder/res1.txt new file mode 100644 index 0000000..a4693d6 --- /dev/null +++ b/Assets/Resources/SubFolder/res1.txt @@ -0,0 +1 @@ +Assets/Resources/SubFolder/res1.txt
\ No newline at end of file diff --git a/Assets/Resources/SubFolder/res1.txt.meta b/Assets/Resources/SubFolder/res1.txt.meta new file mode 100644 index 0000000..2eef72c --- /dev/null +++ b/Assets/Resources/SubFolder/res1.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ca12f224c47f70140b4202bfe542d7c7 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Version.txt b/Assets/Resources/Version.txt new file mode 100644 index 0000000..afaf360 --- /dev/null +++ b/Assets/Resources/Version.txt @@ -0,0 +1 @@ +1.0.0
\ No newline at end of file diff --git a/Assets/Resources/Version.txt.meta b/Assets/Resources/Version.txt.meta new file mode 100644 index 0000000..ced9b79 --- /dev/null +++ b/Assets/Resources/Version.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d13fd2c1c68305543858d7e6ad43cff6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/bundles.manifest b/Assets/Resources/bundles.manifest new file mode 100644 index 0000000..ba0a577 --- /dev/null +++ b/Assets/Resources/bundles.manifest @@ -0,0 +1,5 @@ +bundle00.ab,1194,3ae5ebb999c62cfe97c78472aee1a0ba +bundle01.ab,3576,7c93eabe5f29c887b9316e47f16c4268 +bundle02.ab,3564,59b38b05bd3fba1fd047b8ec7763c52c +bundle03.ab,1170,7119df5c395b33ad24cd111b3a5d2ae4 +PackData,1607,f6db34914ade50ec58cb08eb6b5025d1 diff --git a/Assets/Resources/bundles.manifest.meta b/Assets/Resources/bundles.manifest.meta new file mode 100644 index 0000000..cc93cbf --- /dev/null +++ b/Assets/Resources/bundles.manifest.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 70c5e6767efe2554b9a329e5cf4526f8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/res1.txt b/Assets/Resources/res1.txt new file mode 100644 index 0000000..76ac562 --- /dev/null +++ b/Assets/Resources/res1.txt @@ -0,0 +1 @@ +Assets/Resources/res1.txt
\ No newline at end of file diff --git a/Assets/Resources/res1.txt.meta b/Assets/Resources/res1.txt.meta new file mode 100644 index 0000000..ee85fbd --- /dev/null +++ b/Assets/Resources/res1.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 899c018031c6ab944976ef78a0c850e3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/res2.txt b/Assets/Resources/res2.txt new file mode 100644 index 0000000..386bb11 --- /dev/null +++ b/Assets/Resources/res2.txt @@ -0,0 +1 @@ +Assets/Resources/res2.txt
\ No newline at end of file diff --git a/Assets/Resources/res2.txt.meta b/Assets/Resources/res2.txt.meta new file mode 100644 index 0000000..d20ea37 --- /dev/null +++ b/Assets/Resources/res2.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0a0fecb0a03c8f64bb8a6b344951f8b6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/res3.txt b/Assets/Resources/res3.txt new file mode 100644 index 0000000..3776d8b --- /dev/null +++ b/Assets/Resources/res3.txt @@ -0,0 +1 @@ +Assets/Resources/res3.txt
\ No newline at end of file diff --git a/Assets/Resources/res3.txt.meta b/Assets/Resources/res3.txt.meta new file mode 100644 index 0000000..a72d45f --- /dev/null +++ b/Assets/Resources/res3.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 23b9659f0256d604795cbdea6c4096ec +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/res4.txt b/Assets/Resources/res4.txt new file mode 100644 index 0000000..d7f33c2 --- /dev/null +++ b/Assets/Resources/res4.txt @@ -0,0 +1 @@ +Assets/Resources/res4.txt
\ No newline at end of file diff --git a/Assets/Resources/res4.txt.meta b/Assets/Resources/res4.txt.meta new file mode 100644 index 0000000..2d9eef5 --- /dev/null +++ b/Assets/Resources/res4.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3d0e44aa39d173c42a500ea94355cd10 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes.meta b/Assets/Scenes.meta new file mode 100644 index 0000000..17072cf --- /dev/null +++ b/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f704ae4b4f98ae41a0bce26658850c1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..57412fc --- /dev/null +++ b/Assets/Scenes/SampleScene.unity @@ -0,0 +1,642 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657826, g: 0.49641263, b: 0.57481676, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_TemporalCoherenceThreshold: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 10 + m_Resolution: 2 + m_BakeResolution: 10 + m_AtlasSize: 512 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 256 + m_PVRBounces: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ShowResolutionOverlay: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &170076733 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 170076735} + - component: {fileID: 170076734} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &170076734 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 170076733} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &170076735 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 170076733} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &200744366 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 200744369} + - component: {fileID: 200744368} + - component: {fileID: 200744367} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &200744367 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 200744366} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &200744368 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 200744366} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &200744369 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 200744366} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &317495879 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 317495880} + - component: {fileID: 317495882} + - component: {fileID: 317495881} + - component: {fileID: 317495883} + m_Layer: 5 + m_Name: Root + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &317495880 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 317495879} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1617676350} + m_Father: {fileID: 377595892} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.040609762, y: 0.03} + m_AnchorMax: {x: 0.95, y: 0.97} + m_AnchoredPosition: {x: 0, y: -0.000015258789} + m_SizeDelta: {x: 0, y: -0.000030517578} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &317495881 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 317495879} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1367256648, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1617676350} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 1 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 1 + m_Viewport: {fileID: 0} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 0} + m_HorizontalScrollbarVisibility: 0 + m_VerticalScrollbarVisibility: 0 + m_HorizontalScrollbarSpacing: 0 + m_VerticalScrollbarSpacing: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.ScrollRect+ScrollRectEvent, UnityEngine.UI, Version=1.0.0.0, + Culture=neutral, PublicKeyToken=null +--- !u!222 &317495882 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 317495879} + m_CullTransparentMesh: 0 +--- !u!114 &317495883 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 317495879} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -98529514, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!1 &377595888 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 377595892} + - component: {fileID: 377595891} + - component: {fileID: 377595890} + - component: {fileID: 377595889} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &377595889 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 377595888} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1301386320, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &377595890 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 377595888} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &377595891 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 377595888} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 1 + m_Camera: {fileID: 534669904} + m_PlaneDistance: 1 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &377595892 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 377595888} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 317495880} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &534669902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 534669905} + - component: {fileID: 534669904} + - component: {fileID: 534669903} + - component: {fileID: 534669907} + - component: {fileID: 534669906} + m_Layer: 0 + m_Name: Main Camera + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &534669903 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_Enabled: 1 +--- !u!20 &534669904 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 32 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &534669905 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &534669906 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 97aee000e53f1464bbd45e96b6ea0f9a, type: 3} + m_Name: + m_EditorClassIdentifier: + text: {fileID: 1617676352} +--- !u!114 &534669907 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 534669902} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2d2433f4570c1404da40af9ea0b12741, type: 3} + m_Name: + m_EditorClassIdentifier: + TimeBetweenSlowUpdateCalls: 0.14285715 + ProfilerDebugAmount: 0 + AutoTriggerManualTimeframe: 1 + UpdateCoroutines: 0 + FixedUpdateCoroutines: 0 + LateUpdateCoroutines: 0 + SlowUpdateCoroutines: 0 + RealtimeUpdateCoroutines: 0 + EditorUpdateCoroutines: 0 + EditorSlowUpdateCoroutines: 0 + EndOfFrameCoroutines: 0 + ManualTimeframeCoroutines: 0 + _instanceID: 0 +--- !u!1 &1617676349 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1617676350} + - component: {fileID: 1617676353} + - component: {fileID: 1617676352} + - component: {fileID: 1617676351} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1617676350 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1617676349} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 317495880} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1617676351 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1617676349} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741964061, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!114 &1617676352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1617676349} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 0 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u8D44\u6E90\u6D4B\u8BD5\n " +--- !u!222 &1617676353 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1617676349} + m_CullTransparentMesh: 0 diff --git a/Assets/Scenes/SampleScene.unity.meta b/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..9531828 --- /dev/null +++ b/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99c9720ab356a0642a771bea13969a05 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts.meta b/Assets/Scripts.meta new file mode 100644 index 0000000..b5b90af --- /dev/null +++ b/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a9fc2f152bf2bf4ca68a560149d6a34 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor.meta b/Assets/Scripts/Editor.meta new file mode 100644 index 0000000..b1cf477 --- /dev/null +++ b/Assets/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22e71af268e34ac4f86477c2ec704ddf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor/BuildCustomPipeline.cs b/Assets/Scripts/Editor/BuildCustomPipeline.cs new file mode 100644 index 0000000..3c91409 --- /dev/null +++ b/Assets/Scripts/Editor/BuildCustomPipeline.cs @@ -0,0 +1,16 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; + +public class BuildCustomPipeline : IPreprocessBuildWithReport +{ + public int callbackOrder { get { return 0; } } + public void OnPreprocessBuild(BuildReport report) + { + // BundleHelper.BuildBundles(); + } + +} diff --git a/Assets/Scripts/Editor/BuildCustomPipeline.cs.meta b/Assets/Scripts/Editor/BuildCustomPipeline.cs.meta new file mode 100644 index 0000000..5230b90 --- /dev/null +++ b/Assets/Scripts/Editor/BuildCustomPipeline.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 900a82c1f64da4b488ea055108308070 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor/BundleHelper.cs b/Assets/Scripts/Editor/BundleHelper.cs new file mode 100644 index 0000000..631d542 --- /dev/null +++ b/Assets/Scripts/Editor/BundleHelper.cs @@ -0,0 +1,82 @@ +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Linq; +using System.IO; +using UnityEngine; +using UnityEditor; + +public class BundleHelper +{ + + static string TempPath = Application.temporaryCachePath + "/PackData"; + static string TargetPath = Application.dataPath + "/StreamingAssets/PackData"; // or Application.streamingAssetsPath + static string MainBundleName = "PackData"; + static string MainBundle = TargetPath + "/PackData"; + static string ManifestFile = Application.dataPath + "/Resources/bundles.manifest"; + + [MenuItem("Build/Build bundles")] + public static void BuildBundles() + { + if(!Directory.Exists(TempPath)) + Directory.CreateDirectory(TempPath); + BuildAssetBundleOptions options = BuildAssetBundleOptions.None; + options |= BuildAssetBundleOptions.ChunkBasedCompression; + options |= BuildAssetBundleOptions.DeterministicAssetBundle; + options |= BuildAssetBundleOptions.ForceRebuildAssetBundle; + options |= BuildAssetBundleOptions.StrictMode; +#if UNITY_IOS + BuildPipeline.BuildAssetBundles(TempPath, options, BuildTarget.iOS); +#elif UNITY_ANDROID + BuildPipeline.BuildAssetBundles(TempPath, options, BuildTarget.Android); +#else + BuildPipeline.BuildAssetBundles(TempPath, options, BuildTarget.StandaloneWindows); +#endif + Debug.Log("Bundle生成结束"); + // Move to StreamingAssets + if (!Directory.Exists(TargetPath)) + Directory.CreateDirectory(TargetPath); + string[] files = Directory.GetFiles(TempPath, "*.*"); + string dirPath = null; + foreach(string file in files) + { + if (!file.EndsWith(".manifest") && !file.EndsWith(".meta")) + { + dirPath = file.Replace('\\', '/'); + dirPath = dirPath.Replace(TempPath, TargetPath); + if (File.Exists(dirPath)) + File.Delete(dirPath); + File.Move(file, dirPath); + } + } + // 将bundle的md5写入bundles.manifest文件 + AssetBundle mainBundle = AssetBundle.LoadFromFile(MainBundle); + if (mainBundle != null) + { + AssetBundleManifest manifest = mainBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); + if (manifest != null) + { + if (File.Exists(ManifestFile)) + File.Delete(ManifestFile); + using (StreamWriter file = new System.IO.StreamWriter(ManifestFile, true)) + { + string[] bundles = manifest.GetAllAssetBundles(); + List<string> _bundles = bundles.ToList<string>(); + _bundles.Add(MainBundleName); + foreach (string bundle in _bundles) + { + string path = TargetPath + "/" + bundle ; + if (!File.Exists(path)) + continue; + long size = new FileInfo(path).Length; + byte[] data = File.ReadAllBytes(path); + string hash = FileUtil.GetMD5Hash(data); + file.WriteLine(bundle + "," + size + "," + hash); + } + }; + } + mainBundle.Unload(true); + } + } + +} diff --git a/Assets/Scripts/Editor/BundleHelper.cs.meta b/Assets/Scripts/Editor/BundleHelper.cs.meta new file mode 100644 index 0000000..673f75d --- /dev/null +++ b/Assets/Scripts/Editor/BundleHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9eb05f681b7bd80448b2f488711dad41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/FileUtil.cs b/Assets/Scripts/FileUtil.cs new file mode 100644 index 0000000..b0e9b8c --- /dev/null +++ b/Assets/Scripts/FileUtil.cs @@ -0,0 +1,57 @@ +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.IO; +using System; +using UnityEngine; + +public class FileUtil { + + public static string GetMD5Hash(byte[] data) + { + string strHash = ""; + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + byte[] bytesHash = md5.ComputeHash(data); + strHash = BitConverter.ToString(bytesHash); + strHash = strHash.Replace("-", ""); + } + return strHash.ToLower(); + } + + public static string GetMD5Hash(string pathName) + { + if (!File.Exists(pathName)) + { + Debug.LogError("GetMD5Hash Error, file not exist: " + pathName); + return ""; + } + string strResult = ""; + string strHash = ""; + + byte[] bytesHash; + + FileStream fs = null; + using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) + { + try + { + fs = new FileStream(pathName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + bytesHash = md5.ComputeHash(fs); + fs.Close(); + strHash = BitConverter.ToString(bytesHash); + strHash = strHash.Replace("-", ""); + + strResult = strHash; + } + catch (System.Exception ex) + { + Debug.LogError("read md5 file error :" + pathName + " e: " + ex.ToString()); + } + } + + return strResult.ToLower(); + } + +} diff --git a/Assets/Scripts/FileUtil.cs.meta b/Assets/Scripts/FileUtil.cs.meta new file mode 100644 index 0000000..aeb1552 --- /dev/null +++ b/Assets/Scripts/FileUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0481cdb792bfaac469dd9cd32f24af3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/PathHelper.cs b/Assets/Scripts/PathHelper.cs new file mode 100644 index 0000000..7c23dd6 --- /dev/null +++ b/Assets/Scripts/PathHelper.cs @@ -0,0 +1,41 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class PathHelper{ + // 用于bundle读取的streaming路径 + // 不需要加file://协议 + public static string GetStreamingFullFilePath(string filePath) + { +#if UNITY_ANDROID + return Application.dataPath + "!assets/" + filePath; +#else + return Application.streamingAssetsPath + "/" + filePath; +#endif + } + + // 用于www读取的streaming路径 + // 需要加file协议 + public static string GetStreamingWWWFullFilePath(string filePath) + { +#if UNITY_ANDROID + return Application.streamingAssetsPath + "/" + filePath; +#else + return "file://" + Application.streamingAssetsPath + "/" + filePath; +#endif + } + + public static string GetPersistentFullFilePath(string filePath) + { + return Application.persistentDataPath + "/" + filePath; + } + +#if UNITY_IOS +// 将文件从自动上传iCloud中排除 +public static void ExcludeFileFromiCloud(string filePath) +{ + string full = GetPersistentFullFilePath(filePath); + UnityEngine.iOS.Device.SetNoBackupFlag(full); +} +#endif +} diff --git a/Assets/Scripts/PathHelper.cs.meta b/Assets/Scripts/PathHelper.cs.meta new file mode 100644 index 0000000..f13fefb --- /dev/null +++ b/Assets/Scripts/PathHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f866276720b96643a5cec178754bb40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ResManager.cs b/Assets/Scripts/ResManager.cs new file mode 100644 index 0000000..ba47f8e --- /dev/null +++ b/Assets/Scripts/ResManager.cs @@ -0,0 +1,273 @@ +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.IO; +using UnityEngine; +using UnityEngine.UI; +using MEC; + +public class ResManager { + + private struct BundleInfo{ + public long size; + public string hash; + } + + public static ResManager Instance + { + get + { + if (_instance == null) + _instance = new ResManager(); + return _instance; + } + } + static ResManager _instance; + + Test test; + string Content; + + static string BundleRoot = "PackData"; + static string ManifestBundleName = "PackData"; + static string ManifestFileResName = "bundles"; // under Resources/bundles.manifest + static string ManifesteRemotePath = "bundles.manifest"; +#if UNITY_STANDALONE_WIN + static string cdnAddress = "http://localhost/bundles/"; // PC +#elif UNITY_ANDROID + static string cdnAddress = "http://10.0.2.2/bundles/"; // AndroidEmu +#endif + + Dictionary<string, AssetBundle> CachedBundles = new Dictionary<string, AssetBundle>(); + Dictionary<string, string> FileMapping = new Dictionary<string, string>(); + AssetBundleManifest Manifest; + +#region 更新相关 + // 本地streamingAssetsPath下的bundles数据,从固化的bundles.manifest中读取 + Dictionary<string, BundleInfo> localBundles = new Dictionary<string, BundleInfo>(); + // CDN上的bundles数据 + Dictionary<string, BundleInfo> remoteBundles = new Dictionary<string, BundleInfo>(); +#endregion + + public void Init(Test test) + { + this.test = test; + LoadLocalBundlesInfo(); + Timing.Instance.RunCoroutineOnInstance(DownloadManifest()); + } + + void Print(string content , bool alert = false) + { + test.Print(content, alert); + } + + public string ResContent(string path) + { + TextAsset text = Resources.Load(path) as TextAsset; + if (text == null) + return null; + return text.text; + } + + public void ReadFileMapping() + { + AssetBundle bundle = LoadBundle("bundle00.ab"); // 不可以省略后缀 + if (bundle == null) + { + string path = PathHelper.GetStreamingFullFilePath(BundleRoot + "/bundle00.ab"); + Print("Bundle 为空, path = " + path, true); + return; + } + TextAsset text = bundle.LoadAsset<TextAsset>("fileMapping"); + if (text == null) + return; + string content = text.text; + content = content.Replace("\r", string.Empty); + string[] lines = content.Split('\n'); + Print("Load FileMapping:"); + foreach (string line in lines) + { + string[] part = line.Split(','); + FileMapping.Add(part[0], part[1]); + Print(part[0] + " " + part[1]); + } + } + + /// <summary> + /// 刚开始进入游戏的时候要写入.manifest,用来后续对比更新 + /// </summary> + public void LoadManifest() + { + AssetBundle bundle = LoadBundle(ManifestBundleName); + if (bundle == null) + { + Print("没有Manifest", true); + return; + } + Manifest = bundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); + if (Manifest == null) + { + Print("AssetBundleManifest", true); + return; + } + Print("All bundles:"); + string[] bundleNames = Manifest.GetAllAssetBundles(); + foreach (var bundleName in bundleNames) + { + Print(bundleName); + } + } + + public AssetBundle LoadBundle(string name) + { + AssetBundle bundle; + if (CachedBundles.TryGetValue(name, out bundle)) + { + return bundle; + } + string path = PathHelper.GetPersistentFullFilePath(BundleRoot + "/" + name); + Print(path); + if (!File.Exists(path)) + { + Print("不在persistent里"); + path = PathHelper.GetStreamingFullFilePath(BundleRoot + "/" + name); + } + bundle = AssetBundle.LoadFromFile(path); + if(bundle == null) + Print("是空的"); + CachedBundles.Add(name, bundle); + return bundle; + } + + public string GetBundleName(string assetName) + { + string bundleName; + FileMapping.TryGetValue(assetName, out bundleName); + return bundleName; + } + + public string BundleContent(string resName) + { + string bundleName = GetBundleName(resName); + if (bundleName == null) + return null; + AssetBundle bundle = LoadBundle(bundleName); + if (bundle == null) + return null; + TextAsset text = bundle.LoadAsset<TextAsset>(resName); + if (text == null) + return null; + return text.text; + } + + /// <summary> + /// 根据Resources/bundles.manifest读取本地bundle数据 + /// </summary> + private void LoadLocalBundlesInfo() + { + TextAsset manifest = Resources.Load<TextAsset>(ManifestFileResName); + if(manifest == null) + { + Debug.LogError("本地Resources目录下没有bundles.manifest"); + return; + } + string[] bundles = manifest.text.Replace("\r", string.Empty).Split('\n'); + string[] info; + foreach(string bundle in bundles) + { + info = bundle.Split(','); + if (info.Length != 3) + continue; + BundleInfo bi = new BundleInfo(); + bi.size = long.Parse(info[1]); + bi.hash = info[2]; + localBundles.Add(info[0], bi); + } + } + + IEnumerator<float> DownloadManifest() + { + WWW www = new WWW(cdnAddress + ManifesteRemotePath); + while(!www.isDone) + { + yield return Timing.WaitForSeconds(0.01f); + } + string content = www.text; + string[] bundles = content.Replace("\r", string.Empty).Split('\n'); + string[] info; + foreach (string bundle in bundles) + { + info = bundle.Split(','); + if (info.Length != 3) + continue; + BundleInfo bi = new BundleInfo(); + bi.size = long.Parse(info[1]); + bi.hash = info[2]; + remoteBundles.Add(info[0], bi); + } + // Download bundles + Timing.Instance.RunCoroutineOnInstance(DownloadBundles()); + } + + IEnumerator<float> DownloadBundles() + { + List<string> downloadBundles = new List<string>(); + foreach(var b in remoteBundles) + { + string bundleName = b.Key; + long size = b.Value.size; + string hash = b.Value.hash; + BundleInfo localInfo; + //1. 剔除首包中就有的 + if (localBundles.TryGetValue(bundleName, out localInfo) && localInfo.hash == hash) + continue; + //2. 剔除上次小版本更新下载下来的 + string persistentPath = PathHelper.GetPersistentFullFilePath(BundleRoot + "/" + bundleName); + if(File.Exists(persistentPath)) + { + long lastsize = new FileInfo(persistentPath).Length; + if(lastsize == size) + { + string lasthash = FileUtil.GetMD5Hash(persistentPath); + if (lasthash == "") + { + Debug.LogError("计算md5出错"); + } + else if (lasthash == hash) + continue; + } + } + downloadBundles.Add(bundleName); + } + //3. 下载 + foreach (string bundle in downloadBundles) + { + WWW www = new WWW(cdnAddress + bundle); + while(!www.isDone) + { + yield return Timing.WaitForSeconds(0.01f); + } + // save to persistentDataPath + Print("->下载" + bundle + "完毕"); + byte[] data = www.bytes; + string folder = PathHelper.GetPersistentFullFilePath(BundleRoot); + if (!Directory.Exists(folder)) + Directory.CreateDirectory(folder); + File.WriteAllBytes(folder + "/" + bundle, data); + } + + Print("Bundle 下载完毕,共下载" + downloadBundles.Count + "个"); + Print("------------------------------------------------------------------------"); + // test test + ResManager.Instance.ReadFileMapping(); + ResManager.Instance.LoadManifest(); + // Done + OnDownloaded(); + } + + void OnDownloaded() + { + if (test != null) + test.Testing(); + } + +} diff --git a/Assets/Scripts/ResManager.cs.meta b/Assets/Scripts/ResManager.cs.meta new file mode 100644 index 0000000..0e58ce6 --- /dev/null +++ b/Assets/Scripts/ResManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4014a0d4dcc96c744acda2162e08e6cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Test.cs b/Assets/Scripts/Test.cs new file mode 100644 index 0000000..da32140 --- /dev/null +++ b/Assets/Scripts/Test.cs @@ -0,0 +1,56 @@ +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.IO; +using UnityEngine; +using UnityEngine.UI; + +public class Test : MonoBehaviour { + + public Text text; + string Content; + + public void Print(string content, bool alert = false) + { + if (content == null) + content = "空"; + if(alert) + Content += "<Color=#ff0000ff>"; + Content += content + "\n"; + if(alert) + Content += "</Color>"; + text.text = Content; + } + + private void Awake() + { + ResManager.Instance.Init(this); + } + + public void Testing() + { + Print("----------------------------------------------------------------------------------------"); + Print("Application.dataPath=" + Application.dataPath); + Print("Application.streamingAssetsPath=" + Application.streamingAssetsPath); + Print("Application.persistentDataPath=" + Application.persistentDataPath); + Print("Application.temporaryCachePath=" + Application.temporaryCachePath); + Print("----------------------------------------------------------------------------------------"); + Print("读取Assets/Resources/res1.txt , 内容是"); + Print(ResManager.Instance.ResContent("res1")); + Print("读取Assets/Resources/SubFolder/res1.txt , 内容是"); + Print(ResManager.Instance.ResContent("SubFolder/res1")); + Print("读取Assets/Art/Resources/res5.txt , 内容是"); + Print(ResManager.Instance.ResContent("res5")); + Print("----------------------------------------------------------------------------------------"); + // AssetBundle.LoadAsset()可以省略后缀 + Print("读取Assets/Files/file1.txt , 内容是"); + Print(ResManager.Instance.BundleContent("file1.txt")); + Print(ResManager.Instance.BundleContent("file1")); + Print("读取Assets/Files/file1.abc, 内容是"); + Print(ResManager.Instance.BundleContent("file1.abc")); + Print("读取Assets/Files/file1.bcd, 内容是"); + Print(ResManager.Instance.BundleContent("file1.bcd")); + Print("说明进Bundle的资源不含后缀的资源名字不能冲突", true); + } + +} diff --git a/Assets/Scripts/Test.cs.meta b/Assets/Scripts/Test.cs.meta new file mode 100644 index 0000000..9c5d14a --- /dev/null +++ b/Assets/Scripts/Test.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97aee000e53f1464bbd45e96b6ea0f9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets.meta b/Assets/StreamingAssets.meta new file mode 100644 index 0000000..ca08dba --- /dev/null +++ b/Assets/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af70d535b0f9e2044ade02ad150c2cb1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/PackData.meta b/Assets/StreamingAssets/PackData.meta new file mode 100644 index 0000000..600c238 --- /dev/null +++ b/Assets/StreamingAssets/PackData.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 318b9f5bb69b67346b22b04033ebda2d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/PackData/PackData b/Assets/StreamingAssets/PackData/PackData Binary files differnew file mode 100644 index 0000000..a2f7ce2 --- /dev/null +++ b/Assets/StreamingAssets/PackData/PackData diff --git a/Assets/StreamingAssets/PackData/PackData.meta b/Assets/StreamingAssets/PackData/PackData.meta new file mode 100644 index 0000000..9b52512 --- /dev/null +++ b/Assets/StreamingAssets/PackData/PackData.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 89d4dd6caeec81740a15a83212af5317 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/PackData/bundle00.ab b/Assets/StreamingAssets/PackData/bundle00.ab Binary files differnew file mode 100644 index 0000000..4a3774e --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle00.ab diff --git a/Assets/StreamingAssets/PackData/bundle00.ab.meta b/Assets/StreamingAssets/PackData/bundle00.ab.meta new file mode 100644 index 0000000..5c916bc --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle00.ab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 824acb5c278325943b87dff921952fbc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/PackData/bundle01.ab b/Assets/StreamingAssets/PackData/bundle01.ab Binary files differnew file mode 100644 index 0000000..4566e62 --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle01.ab diff --git a/Assets/StreamingAssets/PackData/bundle01.ab.meta b/Assets/StreamingAssets/PackData/bundle01.ab.meta new file mode 100644 index 0000000..99647c5 --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle01.ab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 946a3f10504e77943828882ee27c88c2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/PackData/bundle02.ab b/Assets/StreamingAssets/PackData/bundle02.ab Binary files differnew file mode 100644 index 0000000..f31b9a2 --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle02.ab diff --git a/Assets/StreamingAssets/PackData/bundle02.ab.meta b/Assets/StreamingAssets/PackData/bundle02.ab.meta new file mode 100644 index 0000000..6aaddd6 --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle02.ab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 02456aa0755cbea4381d725bc9edd92f +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/PackData/bundle03.ab b/Assets/StreamingAssets/PackData/bundle03.ab Binary files differnew file mode 100644 index 0000000..2c6f7d3 --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle03.ab diff --git a/Assets/StreamingAssets/PackData/bundle03.ab.meta b/Assets/StreamingAssets/PackData/bundle03.ab.meta new file mode 100644 index 0000000..c5cc974 --- /dev/null +++ b/Assets/StreamingAssets/PackData/bundle03.ab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e463d34940a8ce14a9a547bf33f9d760 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/test.txt b/Assets/StreamingAssets/test.txt new file mode 100644 index 0000000..78d724b --- /dev/null +++ b/Assets/StreamingAssets/test.txt @@ -0,0 +1 @@ +Assets/StreamingAssets/test.txt
\ No newline at end of file diff --git a/Assets/StreamingAssets/test.txt.meta b/Assets/StreamingAssets/test.txt.meta new file mode 100644 index 0000000..ed795e4 --- /dev/null +++ b/Assets/StreamingAssets/test.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2313a2a6ad8ea4d4b9d92bf137bd592d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/test2.txt b/Assets/StreamingAssets/test2.txt new file mode 100644 index 0000000..4e826be --- /dev/null +++ b/Assets/StreamingAssets/test2.txt @@ -0,0 +1 @@ +Assets/StreamingAssets/test2.txt
\ No newline at end of file diff --git a/Assets/StreamingAssets/test2.txt.meta b/Assets/StreamingAssets/test2.txt.meta new file mode 100644 index 0000000..243de7c --- /dev/null +++ b/Assets/StreamingAssets/test2.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ee2f19c38d5c5ac47bff33d25b523006 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Textrues.meta b/Assets/Textrues.meta new file mode 100644 index 0000000..44cdc0e --- /dev/null +++ b/Assets/Textrues.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2dfa2e550f7027a4fbd3acf54fd34c15 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Textrues/img.png b/Assets/Textrues/img.png Binary files differnew file mode 100644 index 0000000..0d11f85 --- /dev/null +++ b/Assets/Textrues/img.png diff --git a/Assets/Textrues/img.png.meta b/Assets/Textrues/img.png.meta new file mode 100644 index 0000000..e4a7e77 --- /dev/null +++ b/Assets/Textrues/img.png.meta @@ -0,0 +1,88 @@ +fileFormatVersion: 2 +guid: 15761c4d3ca73764abf9183f904ff833 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 7 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: bundle02 + assetBundleVariant: ab diff --git a/Data/Android/new/PackData b/Data/Android/new/PackData Binary files differnew file mode 100644 index 0000000..36fc14e --- /dev/null +++ b/Data/Android/new/PackData diff --git a/Data/Android/new/bundle00.ab b/Data/Android/new/bundle00.ab Binary files differnew file mode 100644 index 0000000..4a3774e --- /dev/null +++ b/Data/Android/new/bundle00.ab diff --git a/Data/Android/new/bundle01.ab b/Data/Android/new/bundle01.ab Binary files differnew file mode 100644 index 0000000..d9435e1 --- /dev/null +++ b/Data/Android/new/bundle01.ab diff --git a/Data/Android/new/bundle02.ab b/Data/Android/new/bundle02.ab Binary files differnew file mode 100644 index 0000000..b179911 --- /dev/null +++ b/Data/Android/new/bundle02.ab diff --git a/Data/Android/new/bundle03.ab b/Data/Android/new/bundle03.ab Binary files differnew file mode 100644 index 0000000..94df076 --- /dev/null +++ b/Data/Android/new/bundle03.ab diff --git a/Data/Android/new/bundles.manifest b/Data/Android/new/bundles.manifest new file mode 100644 index 0000000..6b5e34e --- /dev/null +++ b/Data/Android/new/bundles.manifest @@ -0,0 +1,5 @@ +bundle00.ab,1194,3ae5ebb999c62cfe97c78472aee1a0ba +bundle01.ab,3584,9cb4a228f9e88318f3ba15401458a597 +bundle02.ab,3571,bb132bf7a886a0e023437e19ad796531 +bundle03.ab,1180,aff558f4dcebb4456b8fbbed027ec57f +PackData,1607,4ca778491c4dae4a076f983d71bbfb77 diff --git a/Data/Android/outdate/PackData b/Data/Android/outdate/PackData Binary files differnew file mode 100644 index 0000000..a2f7ce2 --- /dev/null +++ b/Data/Android/outdate/PackData diff --git a/Data/Android/outdate/bundle00.ab b/Data/Android/outdate/bundle00.ab Binary files differnew file mode 100644 index 0000000..4a3774e --- /dev/null +++ b/Data/Android/outdate/bundle00.ab diff --git a/Data/Android/outdate/bundle01.ab b/Data/Android/outdate/bundle01.ab Binary files differnew file mode 100644 index 0000000..4566e62 --- /dev/null +++ b/Data/Android/outdate/bundle01.ab diff --git a/Data/Android/outdate/bundle02.ab b/Data/Android/outdate/bundle02.ab Binary files differnew file mode 100644 index 0000000..f31b9a2 --- /dev/null +++ b/Data/Android/outdate/bundle02.ab diff --git a/Data/Android/outdate/bundle03.ab b/Data/Android/outdate/bundle03.ab Binary files differnew file mode 100644 index 0000000..2c6f7d3 --- /dev/null +++ b/Data/Android/outdate/bundle03.ab diff --git a/Data/Android/outdate/bundles.manifest b/Data/Android/outdate/bundles.manifest new file mode 100644 index 0000000..ba0a577 --- /dev/null +++ b/Data/Android/outdate/bundles.manifest @@ -0,0 +1,5 @@ +bundle00.ab,1194,3ae5ebb999c62cfe97c78472aee1a0ba +bundle01.ab,3576,7c93eabe5f29c887b9316e47f16c4268 +bundle02.ab,3564,59b38b05bd3fba1fd047b8ec7763c52c +bundle03.ab,1170,7119df5c395b33ad24cd111b3a5d2ae4 +PackData,1607,f6db34914ade50ec58cb08eb6b5025d1 diff --git a/Data/PC/new/PackData b/Data/PC/new/PackData Binary files differnew file mode 100644 index 0000000..59136ee --- /dev/null +++ b/Data/PC/new/PackData diff --git a/Data/PC/new/bundle00.ab b/Data/PC/new/bundle00.ab Binary files differnew file mode 100644 index 0000000..947f922 --- /dev/null +++ b/Data/PC/new/bundle00.ab diff --git a/Data/PC/new/bundle01.ab b/Data/PC/new/bundle01.ab Binary files differnew file mode 100644 index 0000000..5a14f7a --- /dev/null +++ b/Data/PC/new/bundle01.ab diff --git a/Data/PC/new/bundle02.ab b/Data/PC/new/bundle02.ab Binary files differnew file mode 100644 index 0000000..8d5aedb --- /dev/null +++ b/Data/PC/new/bundle02.ab diff --git a/Data/PC/new/bundle03.ab b/Data/PC/new/bundle03.ab Binary files differnew file mode 100644 index 0000000..32b575f --- /dev/null +++ b/Data/PC/new/bundle03.ab diff --git a/Data/PC/new/bundles.manifest b/Data/PC/new/bundles.manifest new file mode 100644 index 0000000..17aec75 --- /dev/null +++ b/Data/PC/new/bundles.manifest @@ -0,0 +1,5 @@ +bundle00.ab,1194,dd27374eaed373b233e0d14bf9817dc1 +bundle01.ab,3576,b0c82688e8a0801614df5ba39ce0eea9 +bundle02.ab,3571,f1fe91990e25db4538f0822ba335b16b +bundle03.ab,1179,ce97a098b6555d82489219b2fb7fe166 +PackData,1607,562b03dd01bcd3f8e547ce31fc5593e5 diff --git a/Data/PC/outdate/PackData b/Data/PC/outdate/PackData Binary files differnew file mode 100644 index 0000000..b4c4f32 --- /dev/null +++ b/Data/PC/outdate/PackData diff --git a/Data/PC/outdate/bundle00.ab b/Data/PC/outdate/bundle00.ab Binary files differnew file mode 100644 index 0000000..947f922 --- /dev/null +++ b/Data/PC/outdate/bundle00.ab diff --git a/Data/PC/outdate/bundle01.ab b/Data/PC/outdate/bundle01.ab Binary files differnew file mode 100644 index 0000000..f91137d --- /dev/null +++ b/Data/PC/outdate/bundle01.ab diff --git a/Data/PC/outdate/bundle02.ab b/Data/PC/outdate/bundle02.ab Binary files differnew file mode 100644 index 0000000..97dfafa --- /dev/null +++ b/Data/PC/outdate/bundle02.ab diff --git a/Data/PC/outdate/bundle03.ab b/Data/PC/outdate/bundle03.ab Binary files differnew file mode 100644 index 0000000..c83861a --- /dev/null +++ b/Data/PC/outdate/bundle03.ab diff --git a/Data/PC/outdate/bundles.manifest b/Data/PC/outdate/bundles.manifest new file mode 100644 index 0000000..5cce133 --- /dev/null +++ b/Data/PC/outdate/bundles.manifest @@ -0,0 +1,5 @@ +bundle00.ab,1194,dd27374eaed373b233e0d14bf9817dc1 +bundle01.ab,3574,1a47d14b5a3413b00e600230c7c48fd7 +bundle02.ab,3564,911b4e0e087671b93bb3665d0f22619c +bundle03.ab,1170,c98f7eccb217f3b12ae1f2697570423b +PackData,1607,9b8d03dcd3cff4f929727819e73d9f88 diff --git a/Output/android/android_apk_goes_here b/Output/android/android_apk_goes_here new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Output/android/android_apk_goes_here diff --git a/Output/win/win_player_goes_here b/Output/win/win_player_goes_here new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Output/win/win_player_goes_here diff --git a/ProjectSettings/AudioManager.asset b/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..4f31e74 --- /dev/null +++ b/ProjectSettings/AudioManager.asset @@ -0,0 +1,17 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 diff --git a/ProjectSettings/ClusterInputManager.asset b/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..78992f0 --- /dev/null +++ b/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 7 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0 + m_ClothInterCollisionStiffness: 0 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..ea88784 --- /dev/null +++ b/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,11 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 99c9720ab356a0642a771bea13969a05 + m_configObjects: {} diff --git a/ProjectSettings/EditorSettings.asset b/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..29dea52 --- /dev/null +++ b/ProjectSettings/EditorSettings.asset @@ -0,0 +1,21 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 7 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 2 + m_DefaultBehaviorMode: 0 + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd + m_ProjectGenerationRootNamespace: + m_UserGeneratedProjectSuffix: + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..e0de09e --- /dev/null +++ b/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,65 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 16002, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..17c8f53 --- /dev/null +++ b/ProjectSettings/InputManager.asset @@ -0,0 +1,295 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 diff --git a/ProjectSettings/NavMeshAreas.asset b/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/ProjectSettings/NetworkManager.asset b/ProjectSettings/NetworkManager.asset new file mode 100644 index 0000000..5dc6a83 --- /dev/null +++ b/ProjectSettings/NetworkManager.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!149 &1 +NetworkManager: + m_ObjectHideFlags: 0 + m_DebugLevel: 0 + m_Sendrate: 15 + m_AssetToPrefab: {} diff --git a/ProjectSettings/Physics2DSettings.asset b/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..132ee6b --- /dev/null +++ b/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,37 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 3 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_ChangeStopsCallbacks: 0 + m_CallbacksOnDisable: 1 + m_AutoSyncTransforms: 1 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/ProjectSettings/PresetManager.asset b/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..820e662 --- /dev/null +++ b/ProjectSettings/PresetManager.asset @@ -0,0 +1,27 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + m_DefaultList: + - type: + m_NativeTypeID: 108 + m_ManagedTypePPtr: {fileID: 0} + m_ManagedTypeFallback: + defaultPresets: + - m_Preset: {fileID: 2655988077585873504, guid: c1cf8506f04ef2c4a88b64b6c4202eea, + type: 2} + - type: + m_NativeTypeID: 1020 + m_ManagedTypePPtr: {fileID: 0} + m_ManagedTypeFallback: + defaultPresets: + - m_Preset: {fileID: 2655988077585873504, guid: 0cd792cc87e492d43b4e95b205fc5cc6, + type: 2} + - type: + m_NativeTypeID: 1006 + m_ManagedTypePPtr: {fileID: 0} + m_ManagedTypeFallback: + defaultPresets: + - m_Preset: {fileID: 2655988077585873504, guid: 7a99f8aa944efe94cb9bd74562b7d5f9, + type: 2} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..e939cdf --- /dev/null +++ b/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,751 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 15 + productGUID: 38748d133ed97bc4eb46a3463d9fb47c + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: MyCompany + productName: ResourcesTest + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + m_MTRendering: 1 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosAppInBackgroundBehavior: 0 + displayResolutionDialog: 1 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidBlitType: 0 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + graphicsJobs: 0 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + graphicsJobMode: 0 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + n3dsDisableStereoscopicView: 0 + n3dsEnableSharedListOpt: 1 + n3dsEnableVSync: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 0 + videoMemoryForVertexBuffers: 0 + psp2PowerMode: 0 + psp2AcquireBGM: 1 + vulkanEnableSetSRGBWrite: 0 + vulkanUseSWCommandBuffers: 0 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 0.1 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 0 + xboxOneEnable7thCore: 0 + isWsaHolographicRemotingEnabled: 0 + vrSettings: + cardboard: + depthFormat: 0 + enableTransitionView: 0 + daydream: + depthFormat: 0 + useSustainedPerformanceMode: 0 + enableVideoLayer: 0 + useProtectedVideoMemory: 0 + minimumSupportedHeadTracking: 0 + maximumSupportedHeadTracking: 1 + hololens: + depthFormat: 1 + depthBufferSharingEnabled: 0 + oculus: + sharedDepthBuffer: 0 + dashSupport: 0 + enable360StereoCapture: 0 + protectGraphicsMemory: 0 + useHDRDisplay: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: + Android: com.mycompany.resources_test + buildNumber: {} + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 16 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 1 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 8.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 9.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + iPhoneSplashScreen: {fileID: 0} + iPhoneHighResSplashScreen: {fileID: 0} + iPhoneTallHighResSplashScreen: {fileID: 0} + iPhone47inSplashScreen: {fileID: 0} + iPhone55inPortraitSplashScreen: {fileID: 0} + iPhone55inLandscapeSplashScreen: {fileID: 0} + iPhone58inPortraitSplashScreen: {fileID: 0} + iPhone58inLandscapeSplashScreen: {fileID: 0} + iPadPortraitSplashScreen: {fileID: 0} + iPadHighResPortraitSplashScreen: {fileID: 0} + iPadLandscapeSplashScreen: {fileID: 0} + iPadHighResLandscapeSplashScreen: {fileID: 0} + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSUseLaunchScreenStoryboard: 0 + iOSLaunchScreenCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + appleEnableProMotion: 0 + vulkanEditorSupport: 0 + clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea + templatePackageId: com.unity.3d@1.0.2 + templateDefaultScene: Assets/Scenes/SampleScene.unity + AndroidTargetArchitectures: 5 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 1 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + resolutionDialogBanner: {fileID: 0} + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: tvOS + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: Android + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: iPhone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: WebGL + m_StaticBatching: 0 + m_DynamicBatching: 0 + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 0b00000015000000 + m_Automatic: 1 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AppleTVSupport + m_APIs: 10000000 + m_Automatic: 0 + - m_BuildTarget: WebGLSupport + m_APIs: 0b000000 + m_Automatic: 1 + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - Oculus + - OpenVR + m_BuildTargetEnableVuforiaSettings: [] + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchTouchScreenUsage: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSupportedNpadStyles: 3 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 0 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + monoEnv: + psp2Splashimage: {fileID: 0} + psp2NPTrophyPackPath: + psp2NPSupportGBMorGJP: 0 + psp2NPAgeRating: 12 + psp2NPTitleDatPath: + psp2NPCommsID: + psp2NPCommunicationsID: + psp2NPCommsPassphrase: + psp2NPCommsSig: + psp2ParamSfxPath: + psp2ManualPath: + psp2LiveAreaGatePath: + psp2LiveAreaBackroundPath: + psp2LiveAreaPath: + psp2LiveAreaTrialPath: + psp2PatchChangeInfoPath: + psp2PatchOriginalPackage: + psp2PackagePassword: F69AzBlax3CF3EDNhm3soLBPh71Yexui + psp2KeystoneFile: + psp2MemoryExpansionMode: 0 + psp2DRMType: 0 + psp2StorageType: 0 + psp2MediaCapacity: 0 + psp2DLCConfigPath: + psp2ThumbnailPath: + psp2BackgroundPath: + psp2SoundPath: + psp2TrophyCommId: + psp2TrophyPackagePath: + psp2PackagedResourcesPath: + psp2SaveDataQuota: 10240 + psp2ParentalLevel: 1 + psp2ShortTitle: Not Set + psp2ContentID: IV0000-ABCD12345_00-0123456789ABCDEF + psp2Category: 0 + psp2MasterVersion: 01.00 + psp2AppVersion: 01.00 + psp2TVBootMode: 0 + psp2EnterButtonAssignment: 2 + psp2TVDisableEmu: 0 + psp2AllowTwitterDialog: 1 + psp2Upgradable: 0 + psp2HealthWarning: 0 + psp2UseLibLocation: 0 + psp2InfoBarOnStartup: 0 + psp2InfoBarColor: 0 + psp2ScriptOptimizationLevel: 0 + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + spritePackerPolicy: + webGLMemorySize: 256 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLLinkerTarget: 1 + scriptingDefineSymbols: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + incrementalIl2cppBuild: {} + allowUnsafeCode: 0 + additionalIl2CppArgs: + scriptingRuntimeVersion: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: Template_3D + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: Template_3D + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, + a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + metroCompilationOverrides: 1 + n3dsUseExtSaveData: 0 + n3dsCompressStaticMem: 1 + n3dsExtSaveDataNumber: 0x12345 + n3dsStackSize: 131072 + n3dsTargetPlatform: 2 + n3dsRegion: 7 + n3dsMediaSize: 0 + n3dsLogoStyle: 3 + n3dsTitle: GameName + n3dsProductCode: + n3dsApplicationId: 0xFF3FF + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnableGPUVariability: 0 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + xboxOneScriptCompiler: 0 + vrEditorSettings: + daydream: + daydreamIconForeground: {fileID: 0} + daydreamIconBackground: {fileID: 0} + cloudServicesEnabled: + UNet: 1 + facebookSdkVersion: 7.9.4 + apiCompatibilityLevel: 2 + cloudProjectId: + projectName: + organizationId: + cloudEnabled: 0 + enableNativePlatformBackendsForNewInputSystem: 0 + disableOldInputManagerSupport: 0 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..20d4d70 --- /dev/null +++ b/ProjectSettings/ProjectVersion.txt @@ -0,0 +1 @@ +m_EditorVersion: 2018.2.21f1 diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..b9320b3 --- /dev/null +++ b/ProjectSettings/QualitySettings.asset @@ -0,0 +1,190 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 4 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 4 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 4 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 4 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 2 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 4 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 4 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 4 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 4 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 4 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Nintendo 3DS: 5 + Nintendo Switch: 5 + PS4: 5 + PSP2: 2 + Standalone: 5 + Tizen: 2 + WebGL: 3 + WiiU: 5 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..17cb803 --- /dev/null +++ b/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - PostProcessing + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/ProjectSettings/TimeManager.asset b/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..06bcc6d --- /dev/null +++ b/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.1 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..1be4600 --- /dev/null +++ b/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + m_Enabled: 1 + m_TestMode: 0 + m_TestEventUrl: + m_TestConfigUrl: + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com/api/events/crashes + m_NativeEventUrl: https://perf-events.cloud.unity3d.com/symbolicate + m_Enabled: 0 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_TestEventUrl: + m_TestConfigUrl: + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 |