summaryrefslogtreecommitdiff
path: root/Assets
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2020-03-06 00:30:31 +0800
committerchai <chaifix@163.com>2020-03-06 00:30:31 +0800
commit38d4a551880f913a873c3d2c91a98f0434dfa4b2 (patch)
treea7fd10896449b6596ac464dd3d4881dbc6fd8c82 /Assets
Diffstat (limited to 'Assets')
-rw-r--r--Assets/Art.meta8
-rw-r--r--Assets/Art/Resources.meta8
-rw-r--r--Assets/Art/Resources/res1.txt1
-rw-r--r--Assets/Art/Resources/res1.txt.meta7
-rw-r--r--Assets/Art/Resources/res5.txt1
-rw-r--r--Assets/Art/Resources/res5.txt.meta7
-rw-r--r--Assets/Art/StreamingAssets.meta8
-rw-r--r--Assets/Art/StreamingAssets/test.txt1
-rw-r--r--Assets/Art/StreamingAssets/test.txt.meta7
-rw-r--r--Assets/Art/StreamingAssets/test2.txt1
-rw-r--r--Assets/Art/StreamingAssets/test2.txt.meta7
-rw-r--r--Assets/Art/StreamingAssets/test3.txt1
-rw-r--r--Assets/Art/StreamingAssets/test3.txt.meta7
-rw-r--r--Assets/Files.meta8
-rw-r--r--Assets/Files/file1.abc1
-rw-r--r--Assets/Files/file1.abc.meta7
-rw-r--r--Assets/Files/file1.bcd1
-rw-r--r--Assets/Files/file1.bcd.meta7
-rw-r--r--Assets/Files/file1.txt1
-rw-r--r--Assets/Files/file1.txt.meta7
-rw-r--r--Assets/Files/file2.txt1
-rw-r--r--Assets/Files/file2.txt.meta7
-rw-r--r--Assets/Files/file3.txt1
-rw-r--r--Assets/Files/file3.txt.meta7
-rw-r--r--Assets/Files/file4.txt1
-rw-r--r--Assets/Files/file4.txt.meta7
-rw-r--r--Assets/Files/file5.txt1
-rw-r--r--Assets/Files/file5.txt.meta7
-rw-r--r--Assets/Files/file6.txt1
-rw-r--r--Assets/Files/file6.txt.meta7
-rw-r--r--Assets/Files/fileMapping.txt9
-rw-r--r--Assets/Files/fileMapping.txt.meta7
-rw-r--r--Assets/Plugins.meta8
-rw-r--r--Assets/Plugins/Trinary Software.meta9
-rw-r--r--Assets/Plugins/Trinary Software/Editor.meta9
-rw-r--r--Assets/Plugins/Trinary Software/Editor/MecIcon.pngbin0 -> 36388 bytes
-rw-r--r--Assets/Plugins/Trinary Software/Editor/MecIcon.png.meta57
-rw-r--r--Assets/Plugins/Trinary Software/Pro-only Features.pdfbin0 -> 542257 bytes
-rw-r--r--Assets/Plugins/Trinary Software/Pro-only Features.pdf.meta8
-rw-r--r--Assets/Plugins/Trinary Software/Quick Start Guide.pdfbin0 -> 689308 bytes
-rw-r--r--Assets/Plugins/Trinary Software/Quick Start Guide.pdf.meta8
-rw-r--r--Assets/Plugins/Trinary Software/Timing.cs7059
-rw-r--r--Assets/Plugins/Trinary Software/Timing.cs.meta12
-rw-r--r--Assets/Prefabs.meta8
-rw-r--r--Assets/Prefabs/prefab1.prefab81
-rw-r--r--Assets/Prefabs/prefab1.prefab.meta8
-rw-r--r--Assets/Resources.meta8
-rw-r--r--Assets/Resources/SubFolder.meta8
-rw-r--r--Assets/Resources/SubFolder/res1.txt1
-rw-r--r--Assets/Resources/SubFolder/res1.txt.meta7
-rw-r--r--Assets/Resources/Version.txt1
-rw-r--r--Assets/Resources/Version.txt.meta7
-rw-r--r--Assets/Resources/bundles.manifest5
-rw-r--r--Assets/Resources/bundles.manifest.meta7
-rw-r--r--Assets/Resources/res1.txt1
-rw-r--r--Assets/Resources/res1.txt.meta7
-rw-r--r--Assets/Resources/res2.txt1
-rw-r--r--Assets/Resources/res2.txt.meta7
-rw-r--r--Assets/Resources/res3.txt1
-rw-r--r--Assets/Resources/res3.txt.meta7
-rw-r--r--Assets/Resources/res4.txt1
-rw-r--r--Assets/Resources/res4.txt.meta7
-rw-r--r--Assets/Scenes.meta8
-rw-r--r--Assets/Scenes/SampleScene.unity642
-rw-r--r--Assets/Scenes/SampleScene.unity.meta7
-rw-r--r--Assets/Scripts.meta8
-rw-r--r--Assets/Scripts/Editor.meta8
-rw-r--r--Assets/Scripts/Editor/BuildCustomPipeline.cs16
-rw-r--r--Assets/Scripts/Editor/BuildCustomPipeline.cs.meta11
-rw-r--r--Assets/Scripts/Editor/BundleHelper.cs82
-rw-r--r--Assets/Scripts/Editor/BundleHelper.cs.meta11
-rw-r--r--Assets/Scripts/FileUtil.cs57
-rw-r--r--Assets/Scripts/FileUtil.cs.meta11
-rw-r--r--Assets/Scripts/PathHelper.cs41
-rw-r--r--Assets/Scripts/PathHelper.cs.meta11
-rw-r--r--Assets/Scripts/ResManager.cs273
-rw-r--r--Assets/Scripts/ResManager.cs.meta11
-rw-r--r--Assets/Scripts/Test.cs56
-rw-r--r--Assets/Scripts/Test.cs.meta11
-rw-r--r--Assets/StreamingAssets.meta8
-rw-r--r--Assets/StreamingAssets/PackData.meta8
-rw-r--r--Assets/StreamingAssets/PackData/PackDatabin0 -> 1607 bytes
-rw-r--r--Assets/StreamingAssets/PackData/PackData.meta7
-rw-r--r--Assets/StreamingAssets/PackData/bundle00.abbin0 -> 1194 bytes
-rw-r--r--Assets/StreamingAssets/PackData/bundle00.ab.meta7
-rw-r--r--Assets/StreamingAssets/PackData/bundle01.abbin0 -> 3576 bytes
-rw-r--r--Assets/StreamingAssets/PackData/bundle01.ab.meta7
-rw-r--r--Assets/StreamingAssets/PackData/bundle02.abbin0 -> 3564 bytes
-rw-r--r--Assets/StreamingAssets/PackData/bundle02.ab.meta7
-rw-r--r--Assets/StreamingAssets/PackData/bundle03.abbin0 -> 1170 bytes
-rw-r--r--Assets/StreamingAssets/PackData/bundle03.ab.meta7
-rw-r--r--Assets/StreamingAssets/test.txt1
-rw-r--r--Assets/StreamingAssets/test.txt.meta7
-rw-r--r--Assets/StreamingAssets/test2.txt1
-rw-r--r--Assets/StreamingAssets/test2.txt.meta7
-rw-r--r--Assets/Textrues.meta8
-rw-r--r--Assets/Textrues/img.pngbin0 -> 442 bytes
-rw-r--r--Assets/Textrues/img.png.meta88
98 files changed, 8922 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
new file mode 100644
index 0000000..97f8edd
--- /dev/null
+++ b/Assets/Plugins/Trinary Software/Editor/MecIcon.png
Binary files differ
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
new file mode 100644
index 0000000..67532be
--- /dev/null
+++ b/Assets/Plugins/Trinary Software/Pro-only Features.pdf
Binary files differ
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
new file mode 100644
index 0000000..4715cb5
--- /dev/null
+++ b/Assets/Plugins/Trinary Software/Quick Start Guide.pdf
Binary files differ
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
new file mode 100644
index 0000000..a2f7ce2
--- /dev/null
+++ b/Assets/StreamingAssets/PackData/PackData
Binary files differ
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
new file mode 100644
index 0000000..4a3774e
--- /dev/null
+++ b/Assets/StreamingAssets/PackData/bundle00.ab
Binary files differ
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
new file mode 100644
index 0000000..4566e62
--- /dev/null
+++ b/Assets/StreamingAssets/PackData/bundle01.ab
Binary files differ
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
new file mode 100644
index 0000000..f31b9a2
--- /dev/null
+++ b/Assets/StreamingAssets/PackData/bundle02.ab
Binary files differ
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
new file mode 100644
index 0000000..2c6f7d3
--- /dev/null
+++ b/Assets/StreamingAssets/PackData/bundle03.ab
Binary files differ
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
new file mode 100644
index 0000000..0d11f85
--- /dev/null
+++ b/Assets/Textrues/img.png
Binary files differ
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