├── .gitignore ├── STask ├── ProjectSettings │ ├── boot.config │ ├── ProjectVersion.txt │ ├── ClusterInputManager.asset │ ├── PresetManager.asset │ ├── EditorBuildSettings.asset │ ├── XRSettings.asset │ ├── VersionControlSettings.asset │ ├── Packages │ │ └── com.unity.testtools.codecoverage │ │ │ └── Settings.json │ ├── TimeManager.asset │ ├── VFXManager.asset │ ├── AutoStreamingSettings.asset │ ├── AudioManager.asset │ ├── TagManager.asset │ ├── PackageManagerSettings.asset │ ├── EditorSettings.asset │ ├── UnityConnectSettings.asset │ ├── DynamicsManager.asset │ ├── MemorySettings.asset │ ├── NavMeshAreas.asset │ ├── Physics2DSettings.asset │ ├── GraphicsSettings.asset │ ├── SceneTemplateSettings.json │ ├── InputManager.asset │ └── QualitySettings.asset ├── UserSettings │ ├── Search.settings │ └── EditorUserSettings.asset ├── Assets │ ├── Plugins │ │ ├── STask │ │ │ ├── Runtime │ │ │ │ ├── STask.asmdef │ │ │ │ ├── AwaitableExtensions.cs.meta │ │ │ │ ├── Internal │ │ │ │ │ ├── TaskTracker.cs.meta │ │ │ │ │ ├── WeakDictionary.cs.meta │ │ │ │ │ ├── DiagnosticsExtensions.cs.meta │ │ │ │ │ ├── Error.cs.meta │ │ │ │ │ ├── ArrayPool.cs.meta │ │ │ │ │ ├── MinimumQueue.cs.meta │ │ │ │ │ ├── StatePool.cs.meta │ │ │ │ │ ├── ArrayPoolUtil.cs.meta │ │ │ │ │ ├── ContinuationQueue.cs.meta │ │ │ │ │ ├── PlayerLoopRunner.cs.meta │ │ │ │ │ ├── PooledDelegate.cs.meta │ │ │ │ │ ├── ValueStopwatch.cs.meta │ │ │ │ │ ├── UnityEqualityComparer.cs.meta │ │ │ │ │ ├── RuntimeHelpersAbstraction.cs.meta │ │ │ │ │ ├── PooledDelegate.cs │ │ │ │ │ ├── ValueStopwatch.cs │ │ │ │ │ ├── RuntimeHelpersAbstraction.cs │ │ │ │ │ ├── Error.cs │ │ │ │ │ ├── ArrayPoolUtil.cs │ │ │ │ │ ├── MinimumQueue.cs │ │ │ │ │ ├── ArrayPool.cs │ │ │ │ │ ├── StatePool.cs │ │ │ │ │ └── TaskTracker.cs │ │ │ │ ├── CancellationTokenExtensions.cs.meta │ │ │ │ ├── STask.asmdef.meta │ │ │ │ ├── Interface.meta │ │ │ │ ├── Internal.meta │ │ │ │ ├── CompilerServices.meta │ │ │ │ ├── STask.cs.meta │ │ │ │ ├── AsyncUnit.cs.meta │ │ │ │ ├── Progress.cs.meta │ │ │ │ ├── STask.Delay.cs.meta │ │ │ │ ├── STaskVoid.cs.meta │ │ │ │ ├── TaskPool.cs.meta │ │ │ │ ├── PlayerLoopHelper.cs.meta │ │ │ │ ├── PlayerLoopTimer.cs.meta │ │ │ │ ├── STask.Factory.cs.meta │ │ │ │ ├── STask.Update.cs.meta │ │ │ │ ├── STask.WaitUntil.cs.meta │ │ │ │ ├── STask.WhenAll.cs.meta │ │ │ │ ├── STask.WhenAny.cs.meta │ │ │ │ ├── STaskExtensions.cs.meta │ │ │ │ ├── STaskScheduler.cs.meta │ │ │ │ ├── TestStateMachine.cs.meta │ │ │ │ ├── STaskCompletionSource.cs.meta │ │ │ │ ├── TimeoutController.cs.meta │ │ │ │ ├── UnityAsyncExtensions.cs.meta │ │ │ │ ├── Interface │ │ │ │ │ ├── IPlayerLoopItem.cs.meta │ │ │ │ │ ├── ISTaskSource.cs.meta │ │ │ │ │ ├── PlayerLoopTiming.cs.meta │ │ │ │ │ ├── IPlayerLoopItem.cs │ │ │ │ │ ├── ISTaskSource.cs │ │ │ │ │ └── PlayerLoopTiming.cs │ │ │ │ ├── STask.WhenAll.Generated.cs.meta │ │ │ │ ├── STask.WhenAny.Generated.cs.meta │ │ │ │ ├── STaskExtensions.Shorthand.cs.meta │ │ │ │ ├── STaskVoid.cs │ │ │ │ ├── CancellationTokenSourceExtensions.cs.meta │ │ │ │ ├── CompilerServices │ │ │ │ │ ├── StateMachineRunner.cs.meta │ │ │ │ │ ├── AsyncSTaskMethodBuilder.cs.meta │ │ │ │ │ ├── AsyncMethodBuilderAttribute.cs.meta │ │ │ │ │ ├── AsyncSTaskVoidMethodBuilder.cs.meta │ │ │ │ │ ├── AsyncMethodBuilderAttribute.cs │ │ │ │ │ ├── AsyncSTaskVoidMethodBuilder.cs │ │ │ │ │ └── AsyncSTaskMethodBuilder.cs │ │ │ │ ├── AwaitableExtensions.cs │ │ │ │ ├── AsyncUnit.cs │ │ │ │ ├── CancellationTokenSourceExtensions.cs │ │ │ │ ├── CancellationTokenExtensions.cs │ │ │ │ ├── Progress.cs │ │ │ │ ├── STaskExtensions.cs │ │ │ │ ├── STaskScheduler.cs │ │ │ │ ├── TestStateMachine.cs │ │ │ │ ├── TaskPool.cs │ │ │ │ ├── STask.Update.cs │ │ │ │ ├── STask.WaitUntil.cs │ │ │ │ ├── TimeoutController.cs │ │ │ │ ├── STask.Factory.cs │ │ │ │ ├── STask.cs │ │ │ │ └── PlayerLoopTimer.cs │ │ │ ├── Editor │ │ │ │ ├── STaskTrackerTreeView.cs.meta │ │ │ │ ├── STaskTrackerWindow.cs.meta │ │ │ │ ├── STask.Editor.asmdef.meta │ │ │ │ ├── SplitterGUILayout.cs.meta │ │ │ │ ├── STask.Editor.asmdef │ │ │ │ ├── SplitterGUILayout.cs │ │ │ │ ├── STaskTrackerTreeView.cs │ │ │ │ └── STaskTrackerWindow.cs │ │ │ ├── package.json.meta │ │ │ ├── Editor.meta │ │ │ ├── Runtime.meta │ │ │ └── package.json │ │ └── STask.meta │ ├── Scenes.meta │ ├── Scenes │ │ └── SampleScene.unity.meta │ ├── Tests.meta │ ├── Plugins.meta │ └── Tests │ │ ├── Tests.asmdef.meta │ │ ├── Test.cs.meta │ │ ├── Tests.asmdef │ │ └── Test.cs ├── .gitignore └── Packages │ └── manifest.json ├── images ├── STaskMain.png ├── AsyncSequenceDiagram.png ├── STaskAsyncMethodBuilder.png ├── STaskCompletionSource0.png └── STaskCompletionSource1.png └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | -------------------------------------------------------------------------------- /STask/ProjectSettings/boot.config: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /STask/UserSettings/Search.settings: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "STask" 3 | } 4 | -------------------------------------------------------------------------------- /images/STaskMain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summid/STask/HEAD/images/STaskMain.png -------------------------------------------------------------------------------- /images/AsyncSequenceDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summid/STask/HEAD/images/AsyncSequenceDiagram.png -------------------------------------------------------------------------------- /images/STaskAsyncMethodBuilder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summid/STask/HEAD/images/STaskAsyncMethodBuilder.png -------------------------------------------------------------------------------- /images/STaskCompletionSource0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summid/STask/HEAD/images/STaskCompletionSource0.png -------------------------------------------------------------------------------- /images/STaskCompletionSource1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Summid/STask/HEAD/images/STaskCompletionSource1.png -------------------------------------------------------------------------------- /STask/ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2021.3.22f1c1 2 | m_EditorVersionWithRevision: 2021.3.22f1c1 (99bccbe894f5) 3 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/STaskTrackerTreeView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a293fd2981d4edb9ebf4af14e071600 3 | timeCreated: 1700476209 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/STaskTrackerWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2483fca30cab426b9ddc02671171b0b2 3 | timeCreated: 1700472838 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/AwaitableExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3cae7e4fc0fa49a09f0ce89c7a75dd44 3 | timeCreated: 1700814343 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/TaskTracker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c08a1fe51632444c8f1165821e93f948 3 | timeCreated: 1700532288 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/WeakDictionary.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b40e10fae5d5416894e45d967dd448f4 3 | timeCreated: 1700545899 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CancellationTokenExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec3afa84ef154d9395dc5185f60e67ac 3 | timeCreated: 1700728725 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/DiagnosticsExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70ddd306a31e4a3abcd539abe17dd0c9 3 | timeCreated: 1700555775 -------------------------------------------------------------------------------- /STask/ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /STask/ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_DefaultPresets: {} 8 | -------------------------------------------------------------------------------- /STask/Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6ea315d0fd7389c41b19996891e99ae3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Scenes/SampleScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9fc0d4010bbf28b4594072e72b8655ab 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /STask/Assets/Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c044f8df54b673947a2fb408542170df 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3417272f9058d44fb402600561cf19e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a5cf028aeb654a84c8a2a906543fd886 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /STask/Assets/Tests/Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 780447f9e24ea054eba4fd44f061ebf0 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ffc04c9a19a1309428fdbae7d44d50b3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d905e94237d46e44493011b77137bc91 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dc46e817bf0d21f439e67bd2a4e5ce1c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /STask/ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 545c05b61d3e3064c83ad45b22076e4d 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/STask.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 74193cea9f5af264a90b4c6c33292c58 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa5b4d29bf973184999b6abbcb174713 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0fedf7f563e5ac45bbb6c21bcd710dd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 276cbf26da9d1eb4c82ebf873cca4a70 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /STask/ProjectSettings/VersionControlSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!890905787 &1 4 | VersionControlSettings: 5 | m_ObjectHideFlags: 0 6 | m_Mode: Visible Meta Files 7 | m_CollabEditorSettings: 8 | inProgressEnabled: 1 9 | -------------------------------------------------------------------------------- /STask/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "m_Name": "Settings", 3 | "m_Path": "ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json", 4 | "m_Dictionary": { 5 | "m_DictionaryValues": [] 6 | } 7 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /STask/Assets/Tests/Test.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcf5bf50ccc3f1f4e9b2d58067a33968 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 05dd70a66ff18324785651c6fcc6fef6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/AsyncUnit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b71de4260f547b5409c648d8facf035f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Progress.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a11d9542f3184b44eb674b35401bf2dc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.Delay.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a1f76e62eefb92643ab9f808fdfa4d5c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskVoid.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 93ef5415dbe4be04e99a72a204dced9c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/TaskPool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02494730c20bf8a43a63f76760c4d515 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/SplitterGUILayout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2c9eadf516e406c4e95f7e1e3108fd38 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/Error.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f75e0d99e4ed79345878daba9efae66b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/PlayerLoopHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f89f331f5df151540a9cdda00e879529 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/PlayerLoopTimer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd0e873b8a3220144af70cba6ea03aa2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.Factory.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 91cd11bb3e3561a4c96834f08475daac 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.Update.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 624ededace991d044a077970b10b2a59 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.WaitUntil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 61e53d36e015b3241a4a20f873940f7b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.WhenAll.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac5959c3a6e3ba1408f30235de2ba81f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.WhenAny.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ea38bedfffc5ca42890371d0a236c3e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 083cb8d5eb03b5f49ba69c62ec4a5c19 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskScheduler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e5c60e444009c5647b1ac40b17f31164 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/TestStateMachine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad66e0deae66b5d4d988af06d882c990 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ArrayPool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3670cefb5e6fad4290d627358ad1244 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/MinimumQueue.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 413ea397dc52bf549b45c2de6f92771f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/StatePool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70dc76b98cb657d419e87e445d04d19f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskCompletionSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1ebdcc9f48b53804dabf9e06a5e3246a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/TimeoutController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8edbd10b3a08ebc49b5ca12f152db8ea 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/UnityAsyncExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3709b6e773817a342a390d87963d6997 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface/IPlayerLoopItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 78e9fd0067b49194bbc58a4e46748319 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface/ISTaskSource.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: faaf6a125a255a94db31e05b0ace86eb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface/PlayerLoopTiming.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8feb6efdea2e74647b267dd71294cb98 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ArrayPoolUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38ca0ef079c18ac40bf62929a9ebeba4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ContinuationQueue.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b0afe326fc586384dbcbc08d779a6d2e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/PlayerLoopRunner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62f62fdbdfab48743a5941848663d7f7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/PooledDelegate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a48f6299052dd0941b7061771c7e0cc6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ValueStopwatch.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c26ef78e8e6f1de4ca9787827f639816 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.WhenAll.Generated.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c95369197a0f666458d84cfdb6e7b294 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.WhenAny.Generated.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 43429334fc2e65440a445328efc615f7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskExtensions.Shorthand.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8626d6fe0b6a8c644872f948b8dcd0e0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/UnityEqualityComparer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd43caaf3c6625a4e9be282c7d734c4f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskVoid.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.CompilerServices; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace SFramework.Threading.Tasks 5 | { 6 | [AsyncMethodBuilder(typeof(AsyncSTaskVoidMethodBuilder))] 7 | public readonly struct STaskVoid 8 | { 9 | public void Forget() { } 10 | } 11 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CancellationTokenSourceExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a32da49bcc9ca44fb576a7cccc5dba3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/StateMachineRunner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 10d36287befa8de449683ee2dd2a2491 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/RuntimeHelpersAbstraction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c6c0d80fa4df5134aa9487731675734a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/AsyncSTaskMethodBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9583b0233621b8a4c89ba6f16522c375 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99af2771f21b02b47a927e81cb2028ea 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/AsyncSTaskVoidMethodBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd979d4d8595e85468d87a80befd89bc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /STask/ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_StripUpdateShader: {fileID: 0} 10 | m_RenderPipeSettingsPath: 11 | m_FixedTimeStep: 0.016666668 12 | m_MaxDeltaTime: 0.05 13 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.Runtime.CompilerServices 2 | { 3 | #if !NET_STANDARD_2_1 4 | internal sealed class AsyncMethodBuilderAttribute : Attribute 5 | { 6 | public Type BuilderType { get; } 7 | 8 | public AsyncMethodBuilderAttribute(Type type) 9 | { 10 | this.BuilderType = type; 11 | } 12 | } 13 | #endif 14 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.summid.stask", 3 | "displayName": "STask", 4 | "author": { 5 | "name": "Summid", 6 | "email": "summid@foxmail.com" 7 | }, 8 | "version": "1.0.4", 9 | "unity": "2021.3", 10 | "description": "Provides a simpler version of UniTask", 11 | "keywords": [ 12 | "async/await", 13 | "async", 14 | "Task" 15 | ], 16 | "license": "MIT", 17 | "category": "Task", 18 | "dependencies": {} 19 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface/IPlayerLoopItem.cs: -------------------------------------------------------------------------------- 1 | namespace SFramework.Threading.Tasks 2 | { 3 | /// 4 | /// PlayerLoopSystem的迭代对象 5 | /// 提供方法供PlayerLoopSystem迭代,返回 false 时迭代结束 6 | /// (类似IEnumerator) 7 | /// 8 | /// IEnumerator参考 9 | public interface IPlayerLoopItem 10 | { 11 | bool MoveNext(); 12 | } 13 | } -------------------------------------------------------------------------------- /STask/Assets/Tests/Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tests", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:545c05b61d3e3064c83ad45b22076e4d" 6 | ], 7 | "includePlatforms": [], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [ 12 | "" 13 | ], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/AutoStreamingSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1200 &1 4 | AutoStreamingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | mSearchMode: 15 8 | mCustomSearchFile: 9 | mTextureSearchString: 10 | mMeshSearchString: 11 | mTextures: [] 12 | mAudios: [] 13 | mMeshes: [] 14 | mScenes: [] 15 | mConfigCCD: 16 | useCCD: 0 17 | cosKey: 18 | projectGuid: 19 | bucketUuid: 20 | bucketName: 21 | badgeName: 22 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/AwaitableExtensions.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_2023_1_OR_NEWER 2 | 3 | namespace SFramework.Threading.Tasks 4 | { 5 | public static class AwaitableExtensions 6 | { 7 | public static async STask AsSTask(this UnityEngine.Awaitable awaitable) 8 | { 9 | await awaitable; 10 | } 11 | 12 | public static async STask AsSTask(this UnityEngine.Awaitable awaitable) 13 | { 14 | return await awaitable; 15 | } 16 | } 17 | } 18 | #endif -------------------------------------------------------------------------------- /STask/ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 1024 20 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/STask.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "STask.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:545c05b61d3e3064c83ad45b22076e4d" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /STask/UserSettings/EditorUserSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!162 &1 4 | EditorUserSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_ConfigSettings: 8 | RecentlyUsedSceneGuid-0: 9 | value: 5a5757560101590a5d0c0e24427b5d44434e4c7a7b7a23677f2b4565b7b5353a 10 | flags: 0 11 | vcSharedLogLevel: 12 | value: 0d5e400f0650 13 | flags: 0 14 | m_VCAutomaticAdd: 1 15 | m_VCDebugCom: 0 16 | m_VCDebugCmd: 0 17 | m_VCDebugOut: 0 18 | m_SemanticMergeMode: 2 19 | m_DesiredImportWorkerCount: 2 20 | m_StandbyImportWorkerCount: 2 21 | m_IdleImportWorkerShutdownDelay: 60000 22 | m_VCShowFailedCheckout: 1 23 | m_VCOverwriteFailedCheckoutAssets: 1 24 | m_VCProjectOverlayIcons: 1 25 | m_VCHierarchyOverlayIcons: 1 26 | m_VCOtherOverlayIcons: 1 27 | m_VCAllowAsyncUpdate: 1 28 | m_ArtifactGarbageCollection: 1 29 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/AsyncUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SFramework.Threading.Tasks 4 | { 5 | /// 6 | /// 的默认泛型类型,当无需返回值时,用来占坑,因此声明为 readonly 7 | /// 8 | public readonly struct AsyncUnit : IEquatable 9 | { 10 | public static readonly AsyncUnit Default = new AsyncUnit(); 11 | 12 | public override int GetHashCode() 13 | { 14 | return 0;//when Equals() returns true, the both of object must have the same GetHashCode() result; but the same hash code do NOT mean they're equal 15 | } 16 | 17 | public bool Equals(AsyncUnit other) 18 | { 19 | return true;//readonly struct, default true 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return "()"; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_EnablePreReleasePackages: 0 16 | m_EnablePackageDependencies: 0 17 | m_AdvancedSettingsExpanded: 1 18 | m_ScopedRegistriesSettingsExpanded: 1 19 | m_SeeAllPackageVersions: 0 20 | oneTimeWarningShown: 0 21 | m_Registries: 22 | - m_Id: main 23 | m_Name: 24 | m_Url: https://packages.unity.cn 25 | m_Scopes: [] 26 | m_IsDefault: 1 27 | m_Capabilities: 7 28 | m_UserSelectedRegistryName: 29 | m_UserAddingNewScopedRegistry: 0 30 | m_RegistryInfoDraft: 31 | m_Modified: 0 32 | m_ErrorMessage: 33 | m_UserModificationsInstanceId: -830 34 | m_OriginalInstanceId: -832 35 | m_LoadAssets: 0 36 | -------------------------------------------------------------------------------- /STask/ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 0 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 0 30 | m_SerializeInlineMappingsOnOneLine: 1 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Summid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /STask/ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_DashboardUrl: https://dashboard.unity3d.com 13 | m_CNEventUrl: https://cdp.cloud.unity.cn/v1/events 14 | m_CNConfigUrl: https://cdp.cloud.unity.cn/config 15 | m_TestInitMode: 0 16 | CrashReportingSettings: 17 | m_EventUrl: https://perf-events.cloud.unity.cn 18 | m_Enabled: 0 19 | m_LogBufferSize: 10 20 | m_CaptureEditorExceptions: 1 21 | UnityPurchasingSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | UnityAnalyticsSettings: 25 | m_Enabled: 1 26 | m_TestMode: 0 27 | m_InitializeOnStartup: 1 28 | UnityAdsSettings: 29 | m_Enabled: 0 30 | m_InitializeOnStartup: 1 31 | m_TestMode: 0 32 | m_IosGameId: 33 | m_AndroidGameId: 34 | m_GameIds: {} 35 | m_GameId: 36 | PerformanceReportingSettings: 37 | m_Enabled: 0 38 | -------------------------------------------------------------------------------- /STask/ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /STask/.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | /log/ 13 | 14 | # Asset meta data should only be ignored when the corresponding asset is also ignored 15 | !/[Aa]ssets/**/*.meta 16 | 17 | # Uncomment this line if you wish to ignore the asset store tools plugin 18 | # /[Aa]ssets/AssetStoreTools* 19 | 20 | # Autogenerated Jetbrains Rider plugin 21 | [Aa]ssets/Plugins/Editor/JetBrains* 22 | 23 | # Visual Studio cache directory 24 | .vs/ 25 | .vscode/ 26 | .vsconfig 27 | *.editorconfig 28 | .idea/ 29 | 30 | # Gradle cache directory 31 | .gradle/ 32 | 33 | # Autogenerated VS/MD/Consulo solution and project files 34 | ExportedObj/ 35 | .consulo/ 36 | *.csproj 37 | *.unityproj 38 | *.sln 39 | *.suo 40 | *.tmp 41 | *.user 42 | *.userprefs 43 | *.pidb 44 | *.booproj 45 | *.svd 46 | *.pdb 47 | *.mdb 48 | *.opendb 49 | *.VC.db 50 | 51 | # Unity3D generated meta files 52 | *.pidb.meta 53 | *.pdb.meta 54 | *.mdb.meta 55 | 56 | # Unity3D generated file on crash reports 57 | sysinfo.txt 58 | 59 | # Builds 60 | *.apk 61 | *.unitypackage 62 | 63 | # Crashlytics generated file 64 | crashlytics-build.properties 65 | 66 | -------------------------------------------------------------------------------- /STask/ProjectSettings/MemorySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!387306366 &1 4 | MemorySettings: 5 | m_ObjectHideFlags: 0 6 | m_EditorMemorySettings: 7 | m_MainAllocatorBlockSize: -1 8 | m_ThreadAllocatorBlockSize: -1 9 | m_MainGfxBlockSize: -1 10 | m_ThreadGfxBlockSize: -1 11 | m_CacheBlockSize: -1 12 | m_TypetreeBlockSize: -1 13 | m_ProfilerBlockSize: -1 14 | m_ProfilerEditorBlockSize: -1 15 | m_BucketAllocatorGranularity: -1 16 | m_BucketAllocatorBucketsCount: -1 17 | m_BucketAllocatorBlockSize: -1 18 | m_BucketAllocatorBlockCount: -1 19 | m_ProfilerBucketAllocatorGranularity: -1 20 | m_ProfilerBucketAllocatorBucketsCount: -1 21 | m_ProfilerBucketAllocatorBlockSize: -1 22 | m_ProfilerBucketAllocatorBlockCount: -1 23 | m_TempAllocatorSizeMain: -1 24 | m_JobTempAllocatorBlockSize: -1 25 | m_BackgroundJobTempAllocatorBlockSize: -1 26 | m_JobTempAllocatorReducedBlockSize: -1 27 | m_TempAllocatorSizeGIBakingWorker: -1 28 | m_TempAllocatorSizeNavMeshWorker: -1 29 | m_TempAllocatorSizeAudioWorker: -1 30 | m_TempAllocatorSizeCloudWorker: -1 31 | m_TempAllocatorSizeGfx: -1 32 | m_TempAllocatorSizeJobWorker: -1 33 | m_TempAllocatorSizeBackgroundWorker: -1 34 | m_TempAllocatorSizePreloadManager: -1 35 | m_PlatformMemorySettings: {} 36 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CancellationTokenSourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace SFramework.Threading.Tasks 5 | { 6 | public static partial class CancellationTokenSourceExtensions 7 | { 8 | private readonly static Action CancelCancellationTokenSourceStateDelegate = new Action(CancelCancellationTokenSourceState); 9 | 10 | private static void CancelCancellationTokenSourceState(object state) 11 | { 12 | var cts = (CancellationTokenSource)state; 13 | cts.Cancel(); 14 | } 15 | 16 | /// 17 | /// 取代 ,改为单线程 18 | /// 19 | public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) 20 | { 21 | return PlayerLoopTimer.StartNew(delayTimeSpan, false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts); 22 | } 23 | 24 | /// 25 | /// 取代 ,改为单线程 26 | /// 27 | public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) 28 | { 29 | return CancelAfterSlim(cts, TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CancellationTokenExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace SFramework.Threading.Tasks 5 | { 6 | public static class CancellationTokenExtensions 7 | { 8 | public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback) 9 | { 10 | var restoreFlow = false; 11 | if (!ExecutionContext.IsFlowSuppressed()) 12 | { 13 | ExecutionContext.SuppressFlow(); 14 | restoreFlow = true; 15 | } 16 | 17 | try 18 | { 19 | return cancellationToken.Register(callback, false); 20 | } 21 | finally 22 | { 23 | if (restoreFlow) 24 | { 25 | ExecutionContext.RestoreFlow(); 26 | } 27 | } 28 | } 29 | 30 | public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback, object state) 31 | { 32 | var restoreFlow = false; 33 | if (!ExecutionContext.IsFlowSuppressed()) 34 | { 35 | ExecutionContext.SuppressFlow(); 36 | restoreFlow = true; 37 | } 38 | 39 | try 40 | { 41 | return cancellationToken.Register(callback, state, false); 42 | } 43 | finally 44 | { 45 | if (restoreFlow) 46 | { 47 | ExecutionContext.RestoreFlow(); 48 | } 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /STask/Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.feature.development": "1.0.1", 4 | "com.unity.ide.visualstudio": "2.0.17", 5 | "com.unity.ugui": "1.0.0", 6 | "com.unity.visualscripting": "1.8.0", 7 | "com.unity.modules.ai": "1.0.0", 8 | "com.unity.modules.androidjni": "1.0.0", 9 | "com.unity.modules.animation": "1.0.0", 10 | "com.unity.modules.assetbundle": "1.0.0", 11 | "com.unity.modules.audio": "1.0.0", 12 | "com.unity.modules.cloth": "1.0.0", 13 | "com.unity.modules.director": "1.0.0", 14 | "com.unity.modules.imageconversion": "1.0.0", 15 | "com.unity.modules.imgui": "1.0.0", 16 | "com.unity.modules.jsonserialize": "1.0.0", 17 | "com.unity.modules.particlesystem": "1.0.0", 18 | "com.unity.modules.physics": "1.0.0", 19 | "com.unity.modules.physics2d": "1.0.0", 20 | "com.unity.modules.screencapture": "1.0.0", 21 | "com.unity.modules.terrain": "1.0.0", 22 | "com.unity.modules.terrainphysics": "1.0.0", 23 | "com.unity.modules.tilemap": "1.0.0", 24 | "com.unity.modules.ui": "1.0.0", 25 | "com.unity.modules.uielements": "1.0.0", 26 | "com.unity.modules.umbra": "1.0.0", 27 | "com.unity.modules.unityanalytics": "1.0.0", 28 | "com.unity.modules.unitywebrequest": "1.0.0", 29 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 30 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 31 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 32 | "com.unity.modules.unitywebrequestwww": "1.0.0", 33 | "com.unity.modules.vehicles": "1.0.0", 34 | "com.unity.modules.video": "1.0.0", 35 | "com.unity.modules.vr": "1.0.0", 36 | "com.unity.modules.wind": "1.0.0", 37 | "com.unity.modules.xr": "1.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /STask/ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/PooledDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace SFramework.Threading.Tasks.Internal 5 | { 6 | /// 7 | /// 池化委托,调用后自动放回对象池 8 | /// 9 | /// 10 | internal sealed class PooledDelegate : ITaskPoolNode> 11 | { 12 | private static TaskPool> pool; 13 | 14 | PooledDelegate nextNode; 15 | public ref PooledDelegate NextNode => ref this.nextNode; 16 | 17 | static PooledDelegate() 18 | { 19 | TaskPool.RegisterSizeGetter(typeof(PooledDelegate), () => pool.Size); 20 | } 21 | 22 | private readonly Action runDelegate;//用泛型Action包装下给用户 23 | private Action continuation;//真正的continuation,不用关心泛型 24 | 25 | private PooledDelegate() 26 | { 27 | this.runDelegate = this.Run; 28 | } 29 | 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | private void Run(T _) 32 | { 33 | Action call = this.continuation; 34 | this.continuation = null; 35 | if(call != null) 36 | { 37 | pool.TryPush(this); 38 | call.Invoke(); 39 | } 40 | } 41 | 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static Action Create(Action continuation) 44 | { 45 | if (!pool.TryPop(out PooledDelegate self)) 46 | { 47 | self = new PooledDelegate(); 48 | } 49 | 50 | self.continuation = continuation; 51 | return self.runDelegate; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ValueStopwatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace SFramework.Threading.Tasks.Internal 5 | { 6 | /// 7 | /// 值类型版本的 Stopwatch,在 ASP.NET Core 中已有实现 8 | /// 9 | /// 10 | public readonly struct ValueStopwatch 11 | { 12 | //Stopwatch.Frequency,一秒内有多少个 Stopwatch 的 tick 13 | //一个 Stopwatch 的 tick 包含了多少个 TimeSpan 的 tick 14 | private static double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency; 15 | 16 | private readonly long startTimestamp; 17 | 18 | public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp());//Stopwatch.GetTimestamp()当前Stopwatch已走过多少tick 19 | 20 | private ValueStopwatch(long startTimestamp) 21 | { 22 | this.startTimestamp = startTimestamp; 23 | } 24 | 25 | public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks); 26 | 27 | public bool IsInvalid => this.startTimestamp == 0; 28 | 29 | /// 30 | /// Elapsed Ticks in TimeSpan 31 | /// 32 | public long ElapsedTicks 33 | { 34 | get 35 | { 36 | if (this.startTimestamp == 0) 37 | { 38 | throw new InvalidOperationException("Detected invalid initialization(use 'default'), only to create from StartNew()"); 39 | } 40 | 41 | long delta = Stopwatch.GetTimestamp() - this.startTimestamp; 42 | return (long)(delta * TimestampToTicks);//转换为 TimeSpan 的 tick 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface/ISTaskSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace SFramework.Threading.Tasks 5 | { 6 | public enum STaskStatus 7 | { 8 | /// 任务执行中 9 | Pending = 0, 10 | /// 任务执行成功 11 | Succeeded = 1, 12 | /// 任务执行失败 13 | Faulted = 2, 14 | /// 任务被取消 15 | Canceled = 3, 16 | } 17 | 18 | /// 19 | /// 在STask中(配合 Awaiter)干活的对象,类似 IValueTaskSource 20 | /// 实现该接口可修改STask的行为(任务何时结束,任务结果是多少),以此来扩展STask 21 | /// 22 | public interface ISTaskSource 23 | { 24 | STaskStatus GetStatus(short token); 25 | void OnCompleted(Action continuation, object state, short token); 26 | void GetResult(short token); 27 | 28 | STaskStatus UnsafeGetStatus();//仅供 debug 使用 29 | } 30 | 31 | /// 32 | /// 有返回值版,覆盖GetResult(short token); 33 | /// 协变接口(out 修饰 T),支持 ISTaskSource[Base] = new ISTaskSource[Derive] 34 | /// 参考链接 35 | /// 36 | /// 37 | public interface ISTaskSource : ISTaskSource 38 | { 39 | new T GetResult(short token); 40 | } 41 | 42 | public static class STaskStatusExtensions 43 | { 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | public static bool IsCompleted(this STaskStatus status) 46 | { 47 | return status != STaskStatus.Pending; 48 | } 49 | 50 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 51 | public static bool IsCompletedSuccessfully(this STaskStatus status) 52 | { 53 | return status == STaskStatus.Succeeded; 54 | } 55 | 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | public static bool IsCanceled(this STaskStatus status) 58 | { 59 | return status == STaskStatus.Canceled; 60 | } 61 | 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public static bool IsFaulted(this STaskStatus status) 64 | { 65 | return status == STaskStatus.Faulted; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/RuntimeHelpersAbstraction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace SFramework.Threading.Tasks.Internal 7 | { 8 | internal static class RuntimeHelpersAbstraction 9 | { 10 | // If we can use RuntimeHelpers.IsReferenceOrContainsReferences(.NET Core 2.0), use it. 11 | public static bool IsWellKnownNoReferenceContainsType() 12 | { 13 | return WellKnowNoReferenceContainsType.IsWellKnownType; 14 | } 15 | 16 | private static bool WellKnownNoReferenceContainsTypeInitialize(Type t) 17 | { 18 | // The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single. 19 | if (t.IsPrimitive) 20 | return true; 21 | 22 | if (t.IsEnum) return true; 23 | if (t == typeof(DateTime)) return true; 24 | if (t == typeof(DateTimeOffset)) return true; 25 | if (t == typeof(Guid)) return true; 26 | if (t == typeof(decimal)) return true; 27 | 28 | //unwrap nullable 29 | if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) 30 | { 31 | return WellKnownNoReferenceContainsTypeInitialize(t.GetGenericArguments()[0]); 32 | } 33 | 34 | // or add other wellknown types(Vector, etc...) here 35 | if (t == typeof(Vector2)) return true; 36 | if (t == typeof(Vector3)) return true; 37 | if (t == typeof(Vector4)) return true; 38 | if (t == typeof(Color)) return true; 39 | if (t == typeof(Rect)) return true; 40 | if (t == typeof(Bounds)) return true; 41 | if (t == typeof(Quaternion)) return true; 42 | if (t == typeof(Vector2Int)) return true; 43 | if (t == typeof(Vector3Int)) return true; 44 | 45 | return false; 46 | } 47 | 48 | private static class WellKnowNoReferenceContainsType 49 | { 50 | public static readonly bool IsWellKnownType; 51 | 52 | static WellKnowNoReferenceContainsType() 53 | { 54 | IsWellKnownType = WellKnownNoReferenceContainsTypeInitialize(typeof(T)); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /STask/Assets/Tests/Test.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using SFramework.Threading.Tasks; 5 | using System; 6 | using UnityEngine; 7 | 8 | public class Test : MonoBehaviour 9 | { 10 | private async void Update() 11 | { 12 | if (Input.GetKeyDown(KeyCode.W)) 13 | { 14 | this.TestWhenAll(); 15 | } 16 | if (Input.GetKeyDown(KeyCode.A)) 17 | { 18 | this.TestWhenAny(); 19 | } 20 | if (Input.GetKeyDown(KeyCode.T)) 21 | { 22 | Debug.Log("before await"); 23 | await this.AsyncMethod(2000); 24 | 25 | // ↓↓不是 async 方法,所以不会走自定义状态机 26 | // await STask.Delay(2000); 27 | 28 | Debug.Log("after await"); 29 | } 30 | if (Input.GetKeyDown(KeyCode.F)) 31 | { 32 | _ = this.WaitForFrame(); 33 | } 34 | } 35 | 36 | public async void TestWhenAll() 37 | { 38 | Debug.LogWarning("Test Start"); 39 | var task1 = this.AsyncMethod(100); 40 | var task2 = this.AsyncMethod(233); 41 | var task3 = this.AsyncMethod(777); 42 | var awaitResult = await (task1, task2, task3); 43 | Debug.Log($"time {awaitResult.Item1}"); 44 | Debug.Log($"time {awaitResult.Item2}"); 45 | Debug.Log($"time {awaitResult.Item3}"); 46 | Debug.LogWarning("Test End"); 47 | } 48 | 49 | public async STaskVoid TestWhenAny() 50 | { 51 | Debug.LogWarning("Test Start"); 52 | var task1 = this.AsyncMethod(888); 53 | var task2 = this.AsyncMethod(233); 54 | var task3 = this.AsyncMethod(777); 55 | var awaitResult = await STask.WhenAny(task2, task1); 56 | Debug.Log($"left task win? {awaitResult.hasResultLeft}; result is {awaitResult.result}"); 57 | Debug.LogWarning("Test End"); 58 | } 59 | 60 | public async STask AsyncMethod(int milliseconds) 61 | { 62 | await STask.Delay(milliseconds); 63 | return Time.realtimeSinceStartup; 64 | } 65 | 66 | public async STaskVoid WaitForFrame() 67 | { 68 | int frameCount = 30; 69 | Debug.Log($"current frame count:{Time.frameCount}, wait frame count:{frameCount}"); 70 | await STask.DelayFrame(frameCount); 71 | Debug.Log($"current frame count:{Time.frameCount}"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /STask/ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 13 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: [] 47 | m_LightmapStripping: 0 48 | m_FogStripping: 0 49 | m_InstancingStripping: 0 50 | m_LightmapKeepPlain: 1 51 | m_LightmapKeepDirCombined: 1 52 | m_LightmapKeepDynamicPlain: 1 53 | m_LightmapKeepDynamicDirCombined: 1 54 | m_LightmapKeepShadowMask: 1 55 | m_LightmapKeepSubtractive: 1 56 | m_FogKeepLinear: 1 57 | m_FogKeepExp: 1 58 | m_FogKeepExp2: 1 59 | m_AlbedoSwatchInfos: [] 60 | m_LightsUseLinearIntensity: 0 61 | m_LightsUseColorTemperature: 0 62 | m_LogWhenShaderIsCompiled: 0 63 | m_AllowEnlightenSupportForUpgradedProject: 0 64 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/SplitterGUILayout.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace SFramework.Threading.Tasks.Editor 8 | { 9 | internal static class SplitterGUILayout 10 | { 11 | private static BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; 12 | 13 | private static Lazy splitterStateType = new Lazy(() => 14 | { 15 | Type type = typeof(EditorWindow).Assembly.GetTypes().First(x => x.FullName == "UnityEditor.SplitterState"); 16 | return type; 17 | }); 18 | 19 | private static Lazy splitterStateCtor = new Lazy(() => 20 | { 21 | Type type = splitterStateType.Value; 22 | return type.GetConstructor(flags, null, new Type[] { typeof(float[]), typeof(int[]), typeof(int[]) }, null); 23 | }); 24 | 25 | private static Lazy splitterGUILayoutType = new Lazy(() => 26 | { 27 | Type type = typeof(EditorWindow).Assembly.GetTypes().First(x => x.FullName == "UnityEditor.SplitterGUILayout"); 28 | return type; 29 | }); 30 | 31 | private static Lazy beginVerticalSplit = new Lazy(() => 32 | { 33 | Type type = splitterGUILayoutType.Value; 34 | return type.GetMethod("BeginVerticalSplit", flags, null, new Type[] { splitterStateType.Value, typeof(GUILayoutOption[]) }, null); 35 | }); 36 | 37 | private static Lazy endVerticalSplit = new Lazy(() => 38 | { 39 | Type type = splitterGUILayoutType.Value; 40 | return type.GetMethod("EndVerticalSplit", flags, null, Type.EmptyTypes, null); 41 | }); 42 | 43 | public static object CreateSplitterState(float[] relativeSizes, int[] minSizes, int[] maxSizes) 44 | { 45 | return splitterStateCtor.Value.Invoke(new object[] { relativeSizes, minSizes, maxSizes }); 46 | } 47 | 48 | public static void BeginVerticalSplit(object splitterState, params GUILayoutOption[] options) 49 | { 50 | beginVerticalSplit.Value.Invoke(null, new object[] { splitterState, options }); 51 | } 52 | 53 | public static void EndVerticalSplit() 54 | { 55 | endVerticalSplit.Value.Invoke(null, Type.EmptyTypes); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Progress.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using UnityEngine; 6 | 7 | namespace SFramework.Threading.Tasks 8 | { 9 | /// 10 | /// 轻量级 IProgress[T] 工厂 11 | /// 12 | public static class Progress 13 | { 14 | public static IProgress Create(Action handler) 15 | { 16 | if (handler == null) 17 | return NullProgress.Instance; 18 | return new AnonymousProgress(handler); 19 | } 20 | 21 | public static IProgress CreateOnlyValueChanged(Action handler, IEqualityComparer comparer = null) 22 | { 23 | if (handler == null) 24 | return NullProgress.Instance; 25 | return new OnlyValueChangedProgress(handler, comparer ?? UnityEqualityComparer.GetDefault()); 26 | } 27 | 28 | private sealed class NullProgress : IProgress 29 | { 30 | public static readonly IProgress Instance = new NullProgress(); 31 | 32 | NullProgress() { } 33 | 34 | public void Report(T value) { } 35 | } 36 | 37 | private sealed class AnonymousProgress : IProgress 38 | { 39 | private readonly Action action; 40 | 41 | public AnonymousProgress(Action action) 42 | { 43 | this.action = action; 44 | } 45 | 46 | public void Report(T value) 47 | { 48 | this.action(value); 49 | } 50 | } 51 | 52 | private sealed class OnlyValueChangedProgress : IProgress 53 | { 54 | private readonly Action action; 55 | private readonly IEqualityComparer comparer; 56 | private bool isFirstCall; 57 | private T latesValue; 58 | 59 | public OnlyValueChangedProgress(Action action, IEqualityComparer comparer) 60 | { 61 | this.action = action; 62 | this.comparer = comparer; 63 | this.isFirstCall = true; 64 | } 65 | 66 | public void Report(T value) 67 | { 68 | if (this.isFirstCall) 69 | { 70 | this.isFirstCall = false; 71 | } 72 | else if (this.comparer.Equals(value, this.latesValue)) 73 | { 74 | return; 75 | } 76 | 77 | this.latesValue = value; 78 | this.action(value); 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/Error.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace SFramework.Threading.Tasks.Internal 5 | { 6 | internal static class Error 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static void ThrowArgumentNullException(T value, string paramName) where T : class 10 | { 11 | if (value == null) 12 | ThrowArgumentNullExceptionCore(paramName); 13 | } 14 | 15 | [MethodImpl(MethodImplOptions.NoInlining)] 16 | private static void ThrowArgumentNullExceptionCore(string paramName) 17 | { 18 | throw new ArgumentNullException(paramName); 19 | } 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | public static Exception ArgumentOutOfRange(string paramName) 23 | { 24 | return new ArgumentOutOfRangeException(paramName); 25 | } 26 | 27 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 28 | public static Exception NoElements() 29 | { 30 | return new InvalidOperationException("Source sequence doesn't contain any elements."); 31 | } 32 | 33 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 34 | public static Exception MoreThanOneElement() 35 | { 36 | return new InvalidOperationException("Source sequence contains more than one element."); 37 | } 38 | 39 | [MethodImpl(MethodImplOptions.NoInlining)] 40 | public static void ThrowArgumentException(string message) 41 | { 42 | throw new ArgumentException(message); 43 | } 44 | 45 | [MethodImpl(MethodImplOptions.NoInlining)] 46 | public static void ThrowNotYetCompleted() 47 | { 48 | throw new InvalidOperationException("Not yet completed."); 49 | } 50 | 51 | [MethodImpl(MethodImplOptions.NoInlining)] 52 | public static T ThrowNotYetCompleted() 53 | { 54 | throw new InvalidOperationException("Not yet Completed."); 55 | } 56 | 57 | /// 58 | /// 若continuation已被注册,抛出异常 59 | /// 60 | /// 61 | /// 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public static void ThrowWhenContinuationIsAlreadyRegistered(T continuationField) where T : class 64 | { 65 | if (continuationField != null) 66 | ThrowInvalidOperationExceptionCore("continuation is already registered."); 67 | } 68 | 69 | [MethodImpl(MethodImplOptions.NoInlining)] 70 | private static void ThrowInvalidOperationExceptionCore(string message) 71 | { 72 | throw new InvalidOperationException(message); 73 | } 74 | 75 | [MethodImpl(MethodImplOptions.NoInlining)] 76 | public static void ThrowOperationCanceledException() 77 | { 78 | throw new OperationCanceledException(); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskExtensions.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using static SFramework.Threading.Tasks.STask; 4 | 5 | namespace SFramework.Threading.Tasks 6 | { 7 | public static partial class STaskExtensions 8 | { 9 | /// 10 | /// 直接调用 STask 方法不等待时使用,保证 STask 最后重置 token 11 | /// 12 | /// 13 | public static void Forget(this STask task) 14 | { 15 | //不使用 await 等待 STask 方法时,状态机不会调用 awaiter 中的 (Unsafe)OnCompleted 方法 16 | //因此我们手动注册回调,回调中调用 awaiter.GetResult 重置 token (当 awaiter 已完成时也重置) 17 | 18 | Awaiter awaiter = task.GetAwaiter(); 19 | if (awaiter.IsCompleted) 20 | { 21 | try 22 | { 23 | awaiter.GetResult(); 24 | } 25 | catch (Exception ex) 26 | { 27 | STaskScheduler.PublishUnobservedTaskException(ex); 28 | } 29 | } 30 | else 31 | { 32 | awaiter.SourceOnCompleted(state => 33 | { 34 | using (StateTuple t = (StateTuple)state)//用完后自动调用 StateTuple.Dispose() 35 | { 36 | try 37 | { 38 | t.Item1.GetResult(); 39 | } 40 | catch (Exception ex) 41 | { 42 | STaskScheduler.PublishUnobservedTaskException(ex); 43 | } 44 | } 45 | }, StateTuple.Create(awaiter)); 46 | } 47 | } 48 | 49 | /// 50 | /// 直接调用 STask 方法不等待时使用,保证 STask 最后重置 token 51 | /// 52 | /// 53 | public static void Forget(this STask task) 54 | { 55 | //不使用 await 等待 STask 方法时,状态机不会调用 awaiter 中的 (Unsafe)OnCompleted 方法 56 | //因此我们手动注册回调,回调中调用 awaiter.GetResult 重置 token (当 awaiter 已完成时也重置) 57 | 58 | STask.Awaiter awaiter = task.GetAwaiter(); 59 | if (awaiter.IsCompleted) 60 | { 61 | try 62 | { 63 | awaiter.GetResult(); 64 | } 65 | catch (Exception ex) 66 | { 67 | STaskScheduler.PublishUnobservedTaskException(ex); 68 | } 69 | } 70 | else 71 | { 72 | awaiter.SourceOnCompleted(state => 73 | { 74 | using (StateTuple.Awaiter> t = (StateTuple.Awaiter>)state)//用完后自动调用 StateTuple.Dispose() 75 | { 76 | try 77 | { 78 | t.Item1.GetResult(); 79 | } 80 | catch (Exception ex) 81 | { 82 | STaskScheduler.PublishUnobservedTaskException(ex); 83 | } 84 | } 85 | }, StateTuple.Create(awaiter)); 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/AsyncSTaskVoidMethodBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace SFramework.Threading.Tasks.CompilerServices 6 | { 7 | [StructLayout(LayoutKind.Auto)] 8 | public struct AsyncSTaskVoidMethodBuilder 9 | { 10 | private IStateMachineRunner runner; 11 | 12 | // 1. Static Create method 13 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 14 | public static AsyncSTaskVoidMethodBuilder Create() 15 | { 16 | return default; 17 | } 18 | 19 | // 2. TaskLike Task property(void) 20 | public STaskVoid Task 21 | { 22 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 23 | get 24 | { 25 | return default; 26 | } 27 | } 28 | 29 | // 3. SetException 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | public void SetException(Exception exception) 32 | { 33 | if (this.runner != null) 34 | { 35 | this.runner.Return(); 36 | this.runner = null; 37 | } 38 | 39 | STaskScheduler.PublishUnobservedTaskException(exception);//直接抛出异常 40 | } 41 | 42 | // 4. SetResult 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | public void SetResult() 45 | { 46 | if (this.runner != null) 47 | { 48 | this.runner.Return(); 49 | this.runner = null; 50 | } 51 | } 52 | 53 | // 5. AwaitOnCompleted 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) 56 | where TAwaiter : INotifyCompletion 57 | where TStateMachine : IAsyncStateMachine 58 | { 59 | if (this.runner == null) 60 | { 61 | AsyncSTaskVoid.SetStateMachine(ref stateMachine, ref this.runner); 62 | } 63 | 64 | awaiter.OnCompleted(this.runner.MoveNext); 65 | } 66 | 67 | // 6. AwaitUnsafeOnCompleted 68 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 69 | public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) 70 | where TAwaiter : ICriticalNotifyCompletion 71 | where TStateMachine : IAsyncStateMachine 72 | { 73 | if (this.runner == null) 74 | { 75 | AsyncSTaskVoid.SetStateMachine(ref stateMachine, ref this.runner); 76 | } 77 | 78 | awaiter.UnsafeOnCompleted(this.runner.MoveNext); 79 | } 80 | 81 | // 7. Start 82 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 83 | public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine 84 | { 85 | stateMachine.MoveNext(); 86 | } 87 | 88 | // 8. SetStateMachine 89 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 90 | public void SetStateMachine(IAsyncStateMachine stateMachine) 91 | { 92 | // don't use boxed stateMachine 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STaskScheduler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace SFramework.Threading.Tasks 5 | { 6 | /// 7 | /// STask 没有类似 TaskScheduler 的 scheduler,该类只处理未处理的异常 8 | /// 9 | public static class STaskScheduler 10 | { 11 | public static event Action UnobservedTaskException; 12 | 13 | /// 14 | /// 是否调用 UnobservedTaskException 来处理 OperationCanceledException;默认为 false 15 | /// 16 | public static bool PropagateOperationCanceledException = false; 17 | 18 | /// 19 | /// 捕获到未处理异常且没绑定 UnobservedTaskException 时,写到 UnityLog 的 LogType;默认为 Exception 20 | /// 21 | public static UnityEngine.LogType UnobservedExceptionWriteLogType = UnityEngine.LogType.Exception; 22 | 23 | /// 24 | /// 是否将异常发回Unity主线程;默认为 true 25 | /// 26 | public static bool DispatchUnityMainThread = true; 27 | 28 | private static void InvokeUnobservedTaskException(object state) 29 | { 30 | UnobservedTaskException((Exception)state); 31 | } 32 | 33 | /// 34 | /// 委托缓存 35 | /// 36 | private static readonly SendOrPostCallback handleExceptionInvoke = InvokeUnobservedTaskException; 37 | 38 | internal static void PublishUnobservedTaskException(Exception ex) 39 | { 40 | if (ex != null) 41 | { 42 | if (!PropagateOperationCanceledException && ex is OperationCanceledException) 43 | { 44 | return; 45 | } 46 | 47 | if (UnobservedTaskException != null) 48 | { 49 | if (!DispatchUnityMainThread || Thread.CurrentThread.ManagedThreadId == PlayerLoopHelper.MainThreadId) 50 | { 51 | UnobservedTaskException.Invoke(ex); 52 | } 53 | else 54 | { 55 | PlayerLoopHelper.UnitySynchronizationContext.Post(handleExceptionInvoke, ex); 56 | } 57 | } 58 | else 59 | { 60 | string msg = null; 61 | if (UnobservedExceptionWriteLogType != UnityEngine.LogType.Exception) 62 | { 63 | msg = "UnobservedTaskException: " + ex.ToString(); 64 | } 65 | switch (UnobservedExceptionWriteLogType) 66 | { 67 | case UnityEngine.LogType.Error: 68 | UnityEngine.Debug.LogError(msg); 69 | break; 70 | case UnityEngine.LogType.Assert: 71 | UnityEngine.Debug.LogAssertion(msg); 72 | break; 73 | case UnityEngine.LogType.Warning: 74 | UnityEngine.Debug.LogWarning(msg); 75 | break; 76 | case UnityEngine.LogType.Log: 77 | UnityEngine.Debug.Log(msg); 78 | break; 79 | case UnityEngine.LogType.Exception: 80 | UnityEngine.Debug.LogException(ex); 81 | break; 82 | default: 83 | break; 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/TestStateMachine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace SFramework.Threading.Tasks 7 | { 8 | public class TestStateMachine : MonoBehaviour 9 | { 10 | MyStateMachine stateMachine; 11 | 12 | private void Start() 13 | { 14 | this.stateMachine = new MyStateMachine() { state = -1, builder = new MyBuilder() }; 15 | } 16 | 17 | private void Update() 18 | { 19 | if (Input.GetKeyDown(KeyCode.U)) 20 | { 21 | this.stateMachine.MoveNext(); 22 | } 23 | 24 | if (Input.GetKeyDown(KeyCode.C)) 25 | { 26 | //Debug.Log($"continuation's target {((MyStateMachine)this.stateMachine.awaiter.continuation.Target).awaiter.num}"); 27 | this.stateMachine.awaiter.continuation?.Invoke(); 28 | } 29 | } 30 | } 31 | 32 | public struct MyStateMachine 33 | { 34 | public int state; 35 | public MyBuilder builder; 36 | public MyAwaiter awaiter; 37 | 38 | public void MoveNext() 39 | { 40 | if (this.state == -1) 41 | { 42 | this.state = 0; 43 | this.awaiter = new MyAwaiter() { num = 123, str = "123" }; 44 | this.builder.AwaitUnsafeOnCompleted(ref this.awaiter, ref this); 45 | //return; 46 | } 47 | else if (this.state == 0) 48 | { 49 | this.state = 1; 50 | this.awaiter.GetResult(); 51 | } 52 | 53 | Debug.Log($"num:{this.awaiter.num} | str:{this.awaiter.str}"); 54 | } 55 | } 56 | 57 | public class MyBuilder 58 | { 59 | public void AwaitUnsafeOnCompleted(ref MyAwaiter awaiter, ref MyStateMachine myStateMachine) 60 | { 61 | awaiter.UnsafeOnCompleted(myStateMachine.MoveNext); //这里会拷贝一份myStateMachine到计算堆栈的顶部(Ldobj命令,将地址指向的值类型对象复制到计算堆栈的顶部) 62 | //awaiter.UnsafeOnCompleted(myStateMachine.state); 63 | Debug.Log($"MB {awaiter.GetHashCode()}"); 64 | } 65 | } 66 | 67 | public struct MyAwaiter 68 | { 69 | public int num; 70 | public string str; 71 | public Action continuation; 72 | 73 | public void GetResult() 74 | { 75 | Debug.Log("GetResult"); 76 | //Debug.Log($"GetResult {((MyStateMachine)continuation.Target).awaiter.GetHashCode()}"); 77 | } 78 | 79 | public void UnsafeOnCompleted(Action continuation) 80 | { 81 | this.num = 233; 82 | this.str = "233"; 83 | this.continuation = continuation; 84 | Debug.Log($"MyAwaiter {((MyStateMachine)(continuation.Target)).awaiter.GetHashCode()}"); 85 | } 86 | 87 | public void UnsafeOnCompleted(int i) 88 | { 89 | 90 | } 91 | } 92 | } 93 | //为何执行到 MyAwaiter.GetResult() 后,其成员变量都为在 MyStateMachine 中初始化时候的值? 94 | //当 MyStateMachine 为 struct (release模式下),将要执行 MyBuilder.AwaitUnsafeOnCompleted 中的 await.UnsafeOnCompleted 时 95 | //通过ildasm工具可以看到il代码先将 myStateMachine 拷贝了一份,再执行的方法 96 | 97 | //为何要先拷贝再调用? 98 | //由于 awaiter.UnsafeOnCompleted 参数为 MyStateMachine 中的方法,因此需要先将 MyStateMachine 中的上下文都“捕获”起来(闭包) 99 | //若MyStateMachine为class则不存在问题,很迷惑 100 | 101 | //由于 MyAwaiter 为 struct 类型,在拷贝 MyStateMachine 时也就 new 了一个新的 MyAwaiter 102 | //当 MyAwaiter 为 class 类型时,虽然也会拷贝 MyStateMachine,但也不存在上述问题 -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ArrayPoolUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace SFramework.Threading.Tasks.Internal 7 | { 8 | internal static class ArrayPoolUtil 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | internal static void EnsureCapacity(ref T[] array, int index, ArrayPool pool) 12 | { 13 | if (array.Length <= index) 14 | { 15 | EnsureCapacityCore(ref array, index, pool); 16 | } 17 | } 18 | 19 | [MethodImpl(MethodImplOptions.NoInlining)] 20 | private static void EnsureCapacityCore(ref T[] array, int index, ArrayPool pool) 21 | { 22 | if (array.Length <= index) 23 | { 24 | int newSize = array.Length * 2; 25 | var newArray = pool.Rent(index < newSize ? newSize : index * 2); 26 | Array.Copy(array, 0, newArray, 0, array.Length); 27 | 28 | pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType()); 29 | 30 | array = newArray; 31 | } 32 | } 33 | 34 | public static RentArray Materialize(IEnumerable source) 35 | { 36 | if (source is T[] array) 37 | { 38 | return new RentArray(array, array.Length, null); 39 | } 40 | 41 | int defaultCount = 32; 42 | if (source is ICollection coll) 43 | { 44 | if (coll.Count == 0) 45 | { 46 | return new RentArray(Array.Empty(), 0, null); 47 | } 48 | 49 | defaultCount = coll.Count; 50 | var pool = ArrayPool.Shared; 51 | var buffer = pool.Rent(defaultCount); 52 | coll.CopyTo(buffer, 0); 53 | return new RentArray(buffer, coll.Count, pool); 54 | } 55 | else if (source is IReadOnlyCollection rcoll) 56 | { 57 | defaultCount = rcoll.Count; 58 | } 59 | 60 | if (defaultCount == 0) 61 | { 62 | return new RentArray(Array.Empty(), 0, null); 63 | } 64 | 65 | { 66 | var pool = ArrayPool.Shared; 67 | int index = 0; 68 | var buffer = pool.Rent(defaultCount); 69 | foreach (var item in source) 70 | { 71 | EnsureCapacity(ref buffer, index, pool); 72 | buffer[index++] = item; 73 | } 74 | 75 | return new RentArray(buffer, index, pool); 76 | } 77 | } 78 | 79 | public struct RentArray : IDisposable 80 | { 81 | public readonly T[] Array; 82 | public readonly int Length; 83 | private ArrayPool pool; 84 | 85 | public RentArray(T[] array, int length, ArrayPool pool) 86 | { 87 | this.Array = array; 88 | this.Length = length; 89 | this.pool = pool; 90 | } 91 | 92 | public void Dispose() 93 | { 94 | this.DisposeManually(!RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType()); 95 | } 96 | 97 | public void DisposeManually(bool clearArray) 98 | { 99 | if (this.pool != null) 100 | { 101 | if (clearArray) 102 | { 103 | System.Array.Clear(this.Array, 0, this.Length); 104 | } 105 | 106 | this.pool.Return(this.Array); 107 | this.pool = null; 108 | } 109 | } 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/TaskPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | using System.Threading; 7 | 8 | namespace SFramework.Threading.Tasks 9 | { 10 | /// 11 | /// TaskPool工具类,提供获取对象池大小接口,不实现对象池功能 12 | /// 13 | public static class TaskPool 14 | { 15 | internal static int MaxPoolSize; 16 | 17 | private static Dictionary> sizes = new Dictionary>(); 18 | 19 | static TaskPool() 20 | { 21 | //先从环境变量中寻找预定义的大小,若没找到则默认最大值 22 | try 23 | { 24 | string value = Environment.GetEnvironmentVariable("STASK_MAX_POOLSIZE"); 25 | if (value != null) 26 | { 27 | if (int.TryParse(value, out int size)) 28 | { 29 | MaxPoolSize = size; 30 | return; 31 | } 32 | } 33 | } 34 | catch { } 35 | 36 | MaxPoolSize = int.MaxValue; 37 | } 38 | 39 | public static void SetMaxPoolSize(int maxPoolSize) 40 | { 41 | MaxPoolSize = maxPoolSize; 42 | } 43 | 44 | public static IEnumerable<(Type, int)> GetCacheSizeInfo() 45 | { 46 | lock (sizes) 47 | { 48 | foreach(var item in sizes) 49 | { 50 | yield return (item.Key, item.Value()); 51 | } 52 | } 53 | } 54 | 55 | public static void RegisterSizeGetter(Type type,Func getSize) 56 | { 57 | lock (sizes) 58 | { 59 | sizes[type] = getSize; 60 | } 61 | } 62 | } 63 | 64 | public interface ITaskPoolNode 65 | { 66 | ref T NextNode { get; } 67 | } 68 | 69 | [StructLayout(LayoutKind.Auto)] 70 | public struct TaskPool where T : class, ITaskPoolNode 71 | { 72 | private int gate; 73 | private int size; 74 | private T root;//root为链表头,出队与入队都在root位置操作 75 | 76 | public int Size => this.size; 77 | 78 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 | public bool TryPop(out T result) 80 | { 81 | //if 'gate' equals comparand, it will be replaced by value, return original value in location1 82 | if (Interlocked.CompareExchange(ref this.gate, 1, 0) == 0) 83 | { 84 | T v = this.root; 85 | if (!(v is null)) 86 | { 87 | ref var nextNode = ref v.NextNode; 88 | this.root = nextNode; 89 | nextNode = null; 90 | this.size--; 91 | result = v; 92 | //The `Volatile.Write` method forces the value in location to be written to at the point of the call. 93 | //In addition, any earlier program-order loads and stores must occur before the call to Volatile.Write. 94 | Volatile.Write(ref this.gate, 0); 95 | return true; 96 | } 97 | 98 | Volatile.Write(ref this.gate, 0); 99 | } 100 | result = default; 101 | return false; 102 | } 103 | 104 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 105 | public bool TryPush(T item) 106 | { 107 | if (Interlocked.CompareExchange(ref this.gate, 1, 0) == 0) 108 | { 109 | if (this.size < TaskPool.MaxPoolSize) 110 | { 111 | item.NextNode = this.root; 112 | this.root = item; 113 | this.size++; 114 | Volatile.Write(ref this.gate, 0); 115 | return true; 116 | } 117 | else 118 | { 119 | Volatile.Write(ref this.gate, 0); 120 | } 121 | } 122 | return false; 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.Update.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using System.Threading; 4 | 5 | namespace SFramework.Threading.Tasks 6 | { 7 | public partial struct STask 8 | { 9 | /// 10 | /// 向PlayerLoop中添加迭代方法 11 | /// 12 | /// 13 | /// 14 | /// 15 | public static void UpdateTask(Action onUpdate, PlayerLoopTiming timing, CancellationToken cancellationToken) 16 | { 17 | if (onUpdate == null) 18 | { 19 | UnityEngine.Debug.LogWarning("UpdateTask onUpdate delegate is empty."); 20 | return; 21 | } 22 | new STask(UpdatePromise.Create(onUpdate, timing, cancellationToken, out short token), token); 23 | } 24 | 25 | sealed class UpdatePromise : ISTaskSource, IPlayerLoopItem, ITaskPoolNode 26 | { 27 | private static TaskPool pool; 28 | private UpdatePromise nextNode; 29 | public ref UpdatePromise NextNode => ref this.nextNode; 30 | 31 | static UpdatePromise() 32 | { 33 | TaskPool.RegisterSizeGetter(typeof(UpdatePromise), () => pool.Size); 34 | } 35 | 36 | private CancellationToken cancellationToken; 37 | private STaskCompletionSourceCore core; 38 | private Action onUpdate; 39 | 40 | private UpdatePromise() { } 41 | 42 | public static ISTaskSource Create(Action onUpdate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) 43 | { 44 | if (cancellationToken.IsCancellationRequested) 45 | { 46 | return AutoResetSTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); 47 | } 48 | 49 | if (!pool.TryPop(out UpdatePromise result)) 50 | { 51 | result = new UpdatePromise(); 52 | } 53 | 54 | result.onUpdate = onUpdate; 55 | result.cancellationToken = cancellationToken; 56 | 57 | TaskTracker.TrackActiveTask(result, 3); 58 | 59 | PlayerLoopHelper.AddAction(timing, result); 60 | 61 | token = result.core.Version; 62 | return result; 63 | } 64 | 65 | public void GetResult(short token) 66 | { 67 | try 68 | { 69 | this.core.GetResult(token); 70 | } 71 | finally 72 | { 73 | this.TryReturn(); 74 | } 75 | } 76 | 77 | public STaskStatus GetStatus(short token) 78 | { 79 | return this.core.GetStatus(token); 80 | } 81 | 82 | public STaskStatus UnsafeGetStatus() 83 | { 84 | return this.core.UnsafeGetStatus(); 85 | } 86 | 87 | public void OnCompleted(Action continuation, object state, short token) 88 | { 89 | this.core.OnCompleted(continuation, state, token); 90 | } 91 | 92 | public bool MoveNext() 93 | { 94 | if (this.cancellationToken.IsCancellationRequested || this.onUpdate == null) 95 | { 96 | this.core.TrySetCanceled(this.cancellationToken); 97 | return false; 98 | } 99 | 100 | if (PlayerLoopHelper.IsMainThread) 101 | { 102 | try 103 | { 104 | this.onUpdate?.Invoke(); 105 | return true; 106 | } 107 | catch (Exception ex) 108 | { 109 | this.core.TrySetException(ex); 110 | return false; 111 | } 112 | } 113 | 114 | this.core.TrySetResult(AsyncUnit.Default); 115 | return false; 116 | } 117 | 118 | private bool TryReturn() 119 | { 120 | TaskTracker.RemoveTracking(this); 121 | this.core.Reset(); 122 | this.cancellationToken = default; 123 | return pool.TryPush(this); 124 | } 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/MinimumQueue.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System; 3 | 4 | namespace SFramework.Threading.Tasks.Internal 5 | { 6 | /// 7 | /// 简易版 Queue 循环队列;只保留一种构造方法,去掉字段version、Contains方法、迭代器等用不到的内容 8 | /// 官方源码对比: 9 | /// 为优化方法调用性能,一些方法声明为内联调用 10 | /// 11 | /// 12 | internal class MinimumQueue 13 | { 14 | /// 每次扩容的最小值 15 | private const int MinimumGrow = 4; 16 | 17 | /// 扩容系数 18 | private const int GrowFactor = 200; 19 | 20 | private T[] array; 21 | /// 头指针,指向队列第一个元素 22 | private int head; 23 | /// 尾指针,指向队列最后一个元素的后一个位置 24 | private int tail; 25 | /// 当前队列的大小 26 | private int size; 27 | 28 | public MinimumQueue(int capacity) 29 | { 30 | if (capacity < 0) 31 | throw new ArgumentOutOfRangeException("capacity invalid"); 32 | this.array = new T[capacity]; 33 | this.head = this.tail = this.tail = 0; 34 | } 35 | 36 | public int Count 37 | { 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | get { return this.size; } 40 | } 41 | 42 | /// 43 | /// 取队首元素 44 | /// 队空时抛出异常 45 | /// 46 | /// 47 | /// 当 等于0时抛出 48 | /// 49 | /// 50 | public T Peek() 51 | { 52 | if (this.size == 0) 53 | this.ThrowForEmptyQueue(); 54 | return this.array[this.head]; 55 | } 56 | 57 | /// 58 | /// 入队 59 | /// 会自动扩列 60 | /// 61 | /// 62 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 63 | public void Enqueue(T item) 64 | { 65 | if (this.size == this.array.Length) 66 | { 67 | this.Grow(); 68 | } 69 | 70 | this.array[this.tail] = item; 71 | this.tail = (this.tail + 1) % this.array.Length; 72 | this.size++; 73 | } 74 | 75 | /// 76 | /// 出队 77 | /// 队空时抛出异常 78 | /// 79 | /// 80 | /// 当 等于0时抛出 81 | /// 82 | /// 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | public T Dequeue() 85 | { 86 | if (this.size == 0) 87 | this.ThrowForEmptyQueue(); 88 | 89 | T removed = this.array[this.head]; 90 | this.array[this.head] = default(T); 91 | this.head = (this.head + 1) % this.array.Length; 92 | this.size--; 93 | return removed; 94 | } 95 | 96 | /// 97 | /// 计算扩容大小,然后调用进行扩容 98 | /// 99 | private void Grow() 100 | { 101 | int newCapacity = (int)((long)this.array.Length * (long)GrowFactor / 100);//GrowFactor默认值为200,即每次扩容大小为目前的两倍 102 | if (newCapacity < this.array.Length + MinimumGrow) 103 | { 104 | //最小扩容大小 105 | newCapacity = this.array.Length + MinimumGrow; 106 | } 107 | this.SetCapacity(newCapacity); 108 | } 109 | 110 | /// 111 | /// 扩容数组 112 | /// 113 | /// 114 | private void SetCapacity(int capacity) 115 | { 116 | T[] newArray = new T[capacity]; 117 | if (this.size > 0) 118 | { 119 | if (this.head < this.tail) 120 | { 121 | //头指针在前,尾指针在后,即当前队列未发展成循环队列==>直接复制 122 | Array.Copy(this.array, this.head, newArray, 0, this.size); 123 | } 124 | else 125 | { 126 | //已经是循环队列的形状了 127 | Array.Copy(this.array, this.head, newArray, 0, this.array.Length - this.head);//先复制头指针后面的 128 | Array.Copy(this.array, 0, newArray, this.array.Length - this.head, this.tail);//再复制尾指针前面的 129 | } 130 | } 131 | 132 | this.array = newArray; 133 | this.head = 0; 134 | this.tail = this.size == capacity ? 0 : this.size; 135 | //size等于capacity时特殊处理,此时尾指针应该指向索引0位置(循环队列),从结果来看,扩容前后的数组没有区别 136 | //这个处理有点令人疑惑,因为要capacity与size相等几乎不可能(在MinimumGrow的限制下),但为了防止以后复制粘贴出错,还是加上 137 | //那么当capacity小于size时的情况呢?=> Array.Copy会抛出ArgumentException异常,因此这里就不处理了 138 | } 139 | 140 | 141 | private void ThrowForEmptyQueue() 142 | { 143 | throw new InvalidOperationException("Empty Queue"); 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.WaitUntil.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using System.Threading; 4 | 5 | namespace SFramework.Threading.Tasks 6 | { 7 | public partial struct STask 8 | { 9 | /// Wait until predicate return true 10 | public static STask WaitUntil(Func predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false) 11 | { 12 | return new STask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token); 13 | } 14 | 15 | private sealed class WaitUntilPromise : ISTaskSource, IPlayerLoopItem, ITaskPoolNode 16 | { 17 | private static TaskPool pool; 18 | private WaitUntilPromise nextNode; 19 | public ref WaitUntilPromise NextNode => ref this.nextNode; 20 | 21 | static WaitUntilPromise() 22 | { 23 | TaskPool.RegisterSizeGetter(typeof(WaitUntilPromise), () => pool.Size); 24 | } 25 | 26 | private Func predicate; 27 | private CancellationToken cancellationToken; 28 | private CancellationTokenRegistration cancellationTokenRegistration; 29 | private bool cancelImmediately; 30 | 31 | private STaskCompletionSourceCore core; 32 | 33 | private WaitUntilPromise() { } 34 | 35 | public static ISTaskSource Create(Func predicate, PlayerLoopTiming timing, CancellationToken cancellationToken,bool cancelImmediately, out short token) 36 | { 37 | if (cancellationToken.IsCancellationRequested) 38 | { 39 | return AutoResetSTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); 40 | } 41 | 42 | if (!pool.TryPop(out WaitUntilPromise result)) 43 | { 44 | result = new WaitUntilPromise(); 45 | } 46 | 47 | result.predicate = predicate; 48 | result.cancellationToken = cancellationToken; 49 | result.cancelImmediately = cancelImmediately; 50 | 51 | if (cancelImmediately && cancellationToken.CanBeCanceled) 52 | { 53 | result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state => 54 | { 55 | var promise = (WaitUntilPromise)state; 56 | promise.core.TrySetCanceled(promise.cancellationToken); 57 | }, result); 58 | } 59 | 60 | TaskTracker.TrackActiveTask(result, 3); 61 | 62 | PlayerLoopHelper.AddAction(timing, result); 63 | 64 | token = result.core.Version; 65 | return result; 66 | } 67 | 68 | public void GetResult(short token) 69 | { 70 | try 71 | { 72 | this.core.GetResult(token); 73 | } 74 | finally 75 | { 76 | if (!(this.cancelImmediately && this.cancellationToken.IsCancellationRequested)) 77 | { 78 | this.TryReturn(); 79 | } 80 | } 81 | } 82 | 83 | public STaskStatus GetStatus(short token) 84 | { 85 | return this.core.GetStatus(token); 86 | } 87 | 88 | public STaskStatus UnsafeGetStatus() 89 | { 90 | return this.core.UnsafeGetStatus(); 91 | } 92 | 93 | public void OnCompleted(Action continuation, object state, short token) 94 | { 95 | this.core.OnCompleted(continuation, state, token); 96 | } 97 | 98 | public bool MoveNext() 99 | { 100 | if (this.cancellationToken.IsCancellationRequested) 101 | { 102 | this.core.TrySetCanceled(this.cancellationToken); 103 | return false; 104 | } 105 | 106 | try 107 | { 108 | if (!this.predicate()) 109 | { 110 | return true; 111 | } 112 | } 113 | catch (Exception ex) 114 | { 115 | this.core.TrySetException(ex); 116 | return false; 117 | } 118 | 119 | this.core.TrySetResult(null); 120 | return false; 121 | } 122 | 123 | private bool TryReturn() 124 | { 125 | TaskTracker.RemoveTracking(this); 126 | this.core.Reset(); 127 | this.predicate = default; 128 | this.cancellationToken = default; 129 | this.cancellationTokenRegistration.Dispose(); 130 | this.cancelImmediately = default; 131 | return pool.TryPush(this); 132 | } 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/ArrayPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | 6 | namespace SFramework.Threading.Tasks.Internal 7 | { 8 | /// 9 | /// Same interface as System.Buffers.ArrayPool but only provides Shared. 10 | /// 11 | /// 12 | internal sealed class ArrayPool 13 | { 14 | // Same size as System.Buffers.DefaultArrayPool 15 | private const int DefaultMaxNumberOfArrayPerBucket = 50; 16 | 17 | private static readonly T[] EmptyArray = new T[0]; 18 | 19 | public static readonly ArrayPool Shared = new ArrayPool(); 20 | 21 | private readonly MinimumQueue[] buckets; 22 | private readonly SpinLock[] locks; 23 | 24 | private ArrayPool() 25 | { 26 | //see: GetQueueIndex 27 | this.buckets = new MinimumQueue[18]; 28 | this.locks = new SpinLock[18]; 29 | for (int i = 0; i < this.buckets.Length; ++i) 30 | { 31 | this.buckets[i] = new MinimumQueue(4); //提前准备四个数组 32 | this.locks[i] = new SpinLock(false); 33 | } 34 | } 35 | 36 | public T[] Rent(int minimumLength) 37 | { 38 | if (minimumLength < 0) 39 | { 40 | throw new ArgumentOutOfRangeException("minimumLength"); 41 | } 42 | else if (minimumLength == 0) 43 | { 44 | return EmptyArray; 45 | } 46 | 47 | int size = CalculateSize(minimumLength); 48 | int index = GetQueueIndex(size); 49 | if (index != -1) 50 | { 51 | var q = this.buckets[index]; 52 | bool lockTaken = false; 53 | try 54 | { 55 | this.locks[index].Enter(ref lockTaken); 56 | 57 | if (q.Count != 0) 58 | { 59 | return q.Dequeue(); 60 | } 61 | } 62 | finally 63 | { 64 | if (lockTaken) 65 | this.locks[index].Exit(false); 66 | } 67 | } 68 | 69 | return new T[size]; 70 | } 71 | 72 | public void Return(T[] array, bool clearArray = false) 73 | { 74 | if (array == null || array.Length == 0) 75 | return; 76 | 77 | int index = GetQueueIndex(array.Length); 78 | if (index != -1) 79 | { 80 | if (clearArray) 81 | { 82 | Array.Clear(array, 0, array.Length); 83 | } 84 | 85 | var q = this.buckets[index]; 86 | bool lockTaken = false; 87 | 88 | try 89 | { 90 | this.locks[index].Enter(ref lockTaken); 91 | 92 | if (q.Count > DefaultMaxNumberOfArrayPerBucket) 93 | return; 94 | 95 | q.Enqueue(array); 96 | } 97 | finally 98 | { 99 | if (lockTaken) 100 | this.locks[index].Exit(false); 101 | } 102 | } 103 | } 104 | 105 | /// 106 | /// get the 2^n ceil of the size 107 | /// 108 | /// 109 | /// 110 | private static int CalculateSize(int size) 111 | { 112 | // 获取大于或等于一个整数的最小2的幂 113 | 114 | size--; //避免 size 本身就是2的幂,计算后的结果却是 size*2 的情况 115 | size |= size >> 1; //使得与最高位(含)紧邻的 2 位低位为 1 116 | size |= size >> 2; //使得与最高位(含)紧邻的 4 位低位为 1 117 | size |= size >> 4; //使得与最高位(含)紧邻的 8 位低位为 1 118 | size |= size >> 8; 119 | size |= size >> 16; 120 | size += 1; //到此,最高位即其所有低位都变成 1 了(雾,我们再加 1 得到不小于 size 的最小 2次幂 121 | 122 | if (size < 8)//最小也补足到8,方便管理 123 | { 124 | size = 8; 125 | } 126 | 127 | return size; 128 | } 129 | 130 | /// 131 | /// get the index the array in the queue 132 | /// 133 | /// 134 | /// 135 | private static int GetQueueIndex(int size) 136 | { 137 | switch (size) 138 | { 139 | case 8: return 0; 140 | case 16: return 1; 141 | case 32: return 2; 142 | case 64: return 3; 143 | case 128: return 4; 144 | case 256: return 5; 145 | case 512: return 6; 146 | case 1024: return 7; 147 | case 2048: return 8; 148 | case 4096: return 9; 149 | case 8192: return 10; 150 | case 16384: return 11; 151 | case 32768: return 12; 152 | case 65536: return 13; 153 | case 131072: return 14; 154 | case 262144: return 15; 155 | case 524288: return 16; 156 | case 1048576: return 17; // max array length 157 | default: 158 | return -1; 159 | } 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/StatePool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace SFramework.Threading.Tasks.Internal 6 | { 7 | /// 8 | /// 获取 9 | /// 10 | internal static class StateTuple 11 | { 12 | public static StateTuple Create(T1 item1) 13 | { 14 | return StatePool.Create(item1); 15 | } 16 | 17 | public static StateTuple Create(T1 item1, T2 item2) 18 | { 19 | return StatePool.Create(item1, item2); 20 | } 21 | 22 | public static StateTuple Create(T1 item1, T2 item2, T3 item3) 23 | { 24 | return StatePool.Create(item1, item2, item3); 25 | } 26 | } 27 | 28 | /// 29 | /// 元组包装,底层用对象池缓存; 30 | /// 元组看起来有点鸡肋,只有缓存红利,它只是为了与后面保持一致, 31 | /// 重点在 32 | /// 33 | /// 34 | internal class StateTuple : IDisposable 35 | { 36 | public T1 Item1; 37 | 38 | /// 39 | /// 将 转换为 40 | /// 41 | /// 42 | public void Deconstruct(out T1 item1) 43 | { 44 | item1 = this.Item1; 45 | } 46 | 47 | public void Dispose()//用该对象的时候配合 using 使用 48 | { 49 | StatePool.Return(this); 50 | } 51 | } 52 | 53 | /// 54 | /// 的池子 55 | /// 56 | /// 57 | internal static class StatePool 58 | { 59 | private static readonly ConcurrentQueue> queue = new ConcurrentQueue>();//线程安全 Queue 60 | 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public static StateTuple Create(T1 item1) 63 | { 64 | if (queue.TryDequeue(out StateTuple value)) 65 | { 66 | value.Item1 = item1; 67 | return value; 68 | } 69 | 70 | return new StateTuple { Item1 = item1 }; 71 | } 72 | 73 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 74 | public static void Return(StateTuple tuple) 75 | { 76 | tuple.Item1 = default; 77 | queue.Enqueue(tuple); 78 | } 79 | } 80 | 81 | internal class StateTuple : IDisposable 82 | { 83 | public T1 Item1; 84 | public T2 Item2; 85 | 86 | public void Deconstruct(out T1 item1, out T2 item2) 87 | { 88 | item1 = this.Item1; 89 | item2 = this.Item2; 90 | } 91 | 92 | public void Dispose() 93 | { 94 | StatePool.Return(this); 95 | } 96 | } 97 | 98 | internal static class StatePool 99 | { 100 | static readonly ConcurrentQueue> queue = new ConcurrentQueue>(); 101 | 102 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 103 | public static StateTuple Create(T1 item1, T2 item2) 104 | { 105 | if (queue.TryDequeue(out var value)) 106 | { 107 | value.Item1 = item1; 108 | value.Item2 = item2; 109 | return value; 110 | } 111 | 112 | return new StateTuple { Item1 = item1, Item2 = item2 }; 113 | } 114 | 115 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 116 | public static void Return(StateTuple tuple) 117 | { 118 | tuple.Item1 = default; 119 | tuple.Item2 = default; 120 | queue.Enqueue(tuple); 121 | } 122 | } 123 | 124 | internal class StateTuple : IDisposable 125 | { 126 | public T1 Item1; 127 | public T2 Item2; 128 | public T3 Item3; 129 | 130 | public void Deconstruct(out T1 item1, out T2 item2, out T3 item3) 131 | { 132 | item1 = this.Item1; 133 | item2 = this.Item2; 134 | item3 = this.Item3; 135 | } 136 | 137 | public void Dispose() 138 | { 139 | StatePool.Return(this); 140 | } 141 | } 142 | 143 | internal static class StatePool 144 | { 145 | static readonly ConcurrentQueue> queue = new ConcurrentQueue>(); 146 | 147 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 148 | public static StateTuple Create(T1 item1, T2 item2, T3 item3) 149 | { 150 | if (queue.TryDequeue(out var value)) 151 | { 152 | value.Item1 = item1; 153 | value.Item2 = item2; 154 | value.Item3 = item3; 155 | return value; 156 | } 157 | 158 | return new StateTuple { Item1 = item1, Item2 = item2, Item3 = item3 }; 159 | } 160 | 161 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 162 | public static void Return(StateTuple tuple) 163 | { 164 | tuple.Item1 = default; 165 | tuple.Item2 = default; 166 | tuple.Item3 = default; 167 | queue.Enqueue(tuple); 168 | } 169 | } 170 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Interface/PlayerLoopTiming.cs: -------------------------------------------------------------------------------- 1 | namespace SFramework.Threading.Tasks 2 | { 3 | /// 4 | /// STask新增的自定义PlayerLoop 5 | /// 6 | public enum PlayerLoopTiming 7 | { 8 | Initialization = 0, 9 | LastInitialization = 1, 10 | 11 | EarlyUpdate = 2, 12 | LastEarlyUpdate = 3, 13 | 14 | FixedUpdate = 4, 15 | LastFixedUpdate = 5, 16 | 17 | PreUpdate = 6, 18 | LastPreUpdate = 7, 19 | 20 | Update = 8, 21 | LastUpdate = 9, 22 | 23 | PreLateUpdate = 10, 24 | LastPreLateUpdate = 11, 25 | 26 | PostLateUpdate = 12, 27 | LastPostLateUpdate = 13, 28 | 29 | //需要Unity2020.2及以上版本支持 https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html 30 | TimeUpdate = 14, 31 | LastTimeUpdate = 15, 32 | } 33 | } 34 | 35 | //Initialization 36 | //-- - 37 | //**STaskLoopRunnerYieldInitialization * * 38 | //**STaskLoopRunnerInitialization * * 39 | //PlayerUpdateTime 40 | //DirectorSampleTime 41 | //AsyncUploadTimeSlicedUpdate 42 | //SynchronizeInputs 43 | //SynchronizeState 44 | //XREarlyUpdate 45 | //**STaskLoopRunnerLastYieldInitialization** 46 | //**STaskLoopRunnerLastInitialization** 47 | 48 | //EarlyUpdate 49 | //--- 50 | //**STaskLoopRunnerYieldEarlyUpdate** 51 | //**STaskLoopRunnerEarlyUpdate** 52 | //PollPlayerConnection 53 | //ProfilerStartFrame 54 | //GpuTimestamp 55 | //AnalyticsCoreStatsUpdate 56 | //UnityWebRequestUpdate 57 | //ExecuteMainThreadJobs 58 | //ProcessMouseInWindow 59 | //ClearIntermediateRenderers 60 | //ClearLines 61 | //PresentBeforeUpdate 62 | //ResetFrameStatsAfterPresent 63 | //UpdateAsyncReadbackManager 64 | //UpdateStreamingManager 65 | //UpdateTextureStreamingManager 66 | //UpdatePreloading 67 | //RendererNotifyInvisible 68 | //PlayerCleanupCachedData 69 | //UpdateMainGameViewRect 70 | //UpdateCanvasRectTransform 71 | //XRUpdate 72 | //UpdateInputManager 73 | //ProcessRemoteInput 74 | //*ScriptRunDelayedStartupFrame* 75 | //UpdateKinect 76 | //DeliverIosPlatformEvents 77 | //TangoUpdate 78 | //DispatchEventQueueEvents 79 | //PhysicsResetInterpolatedTransformPosition 80 | //SpriteAtlasManagerUpdate 81 | //PerformanceAnalyticsUpdate 82 | //**STaskLoopRunnerLastYieldEarlyUpdate** 83 | //**STaskLoopRunnerLastEarlyUpdate** 84 | 85 | //FixedUpdate 86 | //--- 87 | //**STaskLoopRunnerYieldFixedUpdate** 88 | //**STaskLoopRunnerFixedUpdate** 89 | //ClearLines 90 | //NewInputFixedUpdate 91 | //DirectorFixedSampleTime 92 | //AudioFixedUpdate 93 | //*ScriptRunBehaviourFixedUpdate* 94 | //DirectorFixedUpdate 95 | //LegacyFixedAnimationUpdate 96 | //XRFixedUpdate 97 | //PhysicsFixedUpdate 98 | //Physics2DFixedUpdate 99 | //DirectorFixedUpdatePostPhysics 100 | //*ScriptRunDelayedFixedFrameRate* 101 | //**STaskLoopRunnerLastYieldFixedUpdate** 102 | //**STaskLoopRunnerLastFixedUpdate** 103 | 104 | //PreUpdate 105 | //--- 106 | //**STaskLoopRunnerYieldPreUpdate** 107 | //**STaskLoopRunnerPreUpdate** 108 | //PhysicsUpdate 109 | //Physics2DUpdate 110 | //CheckTexFieldInput 111 | //IMGUISendQueuedEvents 112 | //NewInputUpdate 113 | //SendMouseEvents 114 | //AIUpdate 115 | //WindUpdate 116 | //UpdateVideo 117 | //**STaskLoopRunnerLastYieldPreUpdate** 118 | //**STaskLoopRunnerLastPreUpdate** 119 | 120 | //Update 121 | //--- 122 | //**STaskLoopRunnerYieldUpdate** 123 | //**STaskLoopRunnerUpdate** 124 | //*ScriptRunBehaviourUpdate* 125 | //*ScriptRunDelayedDynamicFrameRate* 126 | //*ScriptRunDelayedTasks* 127 | //DirectorUpdate 128 | //**STaskLoopRunnerLastYieldUpdate** 129 | //**STaskLoopRunnerLastUpdate** 130 | 131 | //PreLateUpdate 132 | //--- 133 | //**STaskLoopRunnerYieldPreLateUpdate** 134 | //**STaskLoopRunnerPreLateUpdate** 135 | //AIUpdatePostScript 136 | //DirectorUpdateAnimationBegin 137 | //LegacyAnimationUpdate 138 | //DirectorUpdateAnimationEnd 139 | //DirectorDeferredEvaluate 140 | //EndGraphicsJobsAfterScriptUpdate 141 | //ParticleSystemBeginUpdateAll 142 | //ConstraintManagerUpdate 143 | //*ScriptRunBehaviourLateUpdate* 144 | //**STaskLoopRunnerLastYieldPreLateUpdate** 145 | //**STaskLoopRunnerLastPreLateUpdate** 146 | 147 | //PostLateUpdate 148 | //--- 149 | //**STaskLoopRunnerYieldPostLateUpdate** 150 | //**STaskLoopRunnerPostLateUpdate** 151 | //PlayerSendFrameStarted 152 | //DirectorLateUpdate 153 | //*ScriptRunDelayedDynamicFrameRate* 154 | //PhysicsSkinnedClothBeginUpdate 155 | //UpdateRectTransform 156 | //UpdateCanvasRectTransform 157 | //PlayerUpdateCanvases 158 | //UpdateAudio 159 | //VFXUpdate 160 | //ParticleSystemEndUpdateAll 161 | //EndGraphicsJobsAfterScriptLateUpdate 162 | //UpdateCustomRenderTextures 163 | //UpdateAllRenderers 164 | //EnlightenRuntimeUpdate 165 | //UpdateAllSkinnedMeshes 166 | //ProcessWebSendMessages 167 | //SortingGroupsUpdate 168 | //UpdateVideoTextures 169 | //UpdateVideo 170 | //DirectorRenderImage 171 | //PlayerEmitCanvasGeometry 172 | //PhysicsSkinnedClothFinishUpdate 173 | //FinishFrameRendering 174 | //BatchModeUpdate 175 | //PlayerSendFrameComplete 176 | //UpdateCaptureScreenshot 177 | //PresentAfterDraw 178 | //ClearImmediateRenderers 179 | //PlayerSendFramePostPresent 180 | //UpdateResolution 181 | //InputEndFrame 182 | //TriggerEndOfFrameCallbacks 183 | //GUIClearEvents 184 | //ShaderHandleErrors 185 | //ResetInputAxis 186 | //ThreadedLoadingDebug 187 | //ProfilerSynchronizeStats 188 | //MemoryFrameMaintenance 189 | //ExecuteGameCenterCallbacks 190 | //ProfilerEndFrame 191 | //**STaskLoopRunnerLastYieldPostLateUpdate** 192 | //**STaskLoopRunnerLastPostLateUpdate** -------------------------------------------------------------------------------- /STask/ProjectSettings/SceneTemplateSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "templatePinStates": [], 3 | "dependencyTypeInfos": [ 4 | { 5 | "userAdded": false, 6 | "type": "UnityEngine.AnimationClip", 7 | "ignore": false, 8 | "defaultInstantiationMode": 0, 9 | "supportsModification": true 10 | }, 11 | { 12 | "userAdded": false, 13 | "type": "UnityEditor.Animations.AnimatorController", 14 | "ignore": false, 15 | "defaultInstantiationMode": 0, 16 | "supportsModification": true 17 | }, 18 | { 19 | "userAdded": false, 20 | "type": "UnityEngine.AnimatorOverrideController", 21 | "ignore": false, 22 | "defaultInstantiationMode": 0, 23 | "supportsModification": true 24 | }, 25 | { 26 | "userAdded": false, 27 | "type": "UnityEditor.Audio.AudioMixerController", 28 | "ignore": false, 29 | "defaultInstantiationMode": 0, 30 | "supportsModification": true 31 | }, 32 | { 33 | "userAdded": false, 34 | "type": "UnityEngine.ComputeShader", 35 | "ignore": true, 36 | "defaultInstantiationMode": 1, 37 | "supportsModification": true 38 | }, 39 | { 40 | "userAdded": false, 41 | "type": "UnityEngine.Cubemap", 42 | "ignore": false, 43 | "defaultInstantiationMode": 0, 44 | "supportsModification": true 45 | }, 46 | { 47 | "userAdded": false, 48 | "type": "UnityEngine.GameObject", 49 | "ignore": false, 50 | "defaultInstantiationMode": 0, 51 | "supportsModification": true 52 | }, 53 | { 54 | "userAdded": false, 55 | "type": "UnityEditor.LightingDataAsset", 56 | "ignore": false, 57 | "defaultInstantiationMode": 0, 58 | "supportsModification": false 59 | }, 60 | { 61 | "userAdded": false, 62 | "type": "UnityEngine.LightingSettings", 63 | "ignore": false, 64 | "defaultInstantiationMode": 0, 65 | "supportsModification": true 66 | }, 67 | { 68 | "userAdded": false, 69 | "type": "UnityEngine.Material", 70 | "ignore": false, 71 | "defaultInstantiationMode": 0, 72 | "supportsModification": true 73 | }, 74 | { 75 | "userAdded": false, 76 | "type": "UnityEditor.MonoScript", 77 | "ignore": true, 78 | "defaultInstantiationMode": 1, 79 | "supportsModification": true 80 | }, 81 | { 82 | "userAdded": false, 83 | "type": "UnityEngine.PhysicMaterial", 84 | "ignore": false, 85 | "defaultInstantiationMode": 0, 86 | "supportsModification": true 87 | }, 88 | { 89 | "userAdded": false, 90 | "type": "UnityEngine.PhysicsMaterial2D", 91 | "ignore": false, 92 | "defaultInstantiationMode": 0, 93 | "supportsModification": true 94 | }, 95 | { 96 | "userAdded": false, 97 | "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", 98 | "ignore": false, 99 | "defaultInstantiationMode": 0, 100 | "supportsModification": true 101 | }, 102 | { 103 | "userAdded": false, 104 | "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", 105 | "ignore": false, 106 | "defaultInstantiationMode": 0, 107 | "supportsModification": true 108 | }, 109 | { 110 | "userAdded": false, 111 | "type": "UnityEngine.Rendering.VolumeProfile", 112 | "ignore": false, 113 | "defaultInstantiationMode": 0, 114 | "supportsModification": true 115 | }, 116 | { 117 | "userAdded": false, 118 | "type": "UnityEditor.SceneAsset", 119 | "ignore": false, 120 | "defaultInstantiationMode": 0, 121 | "supportsModification": false 122 | }, 123 | { 124 | "userAdded": false, 125 | "type": "UnityEngine.Shader", 126 | "ignore": true, 127 | "defaultInstantiationMode": 1, 128 | "supportsModification": true 129 | }, 130 | { 131 | "userAdded": false, 132 | "type": "UnityEngine.ShaderVariantCollection", 133 | "ignore": true, 134 | "defaultInstantiationMode": 1, 135 | "supportsModification": true 136 | }, 137 | { 138 | "userAdded": false, 139 | "type": "UnityEngine.Texture", 140 | "ignore": false, 141 | "defaultInstantiationMode": 0, 142 | "supportsModification": true 143 | }, 144 | { 145 | "userAdded": false, 146 | "type": "UnityEngine.Texture2D", 147 | "ignore": false, 148 | "defaultInstantiationMode": 0, 149 | "supportsModification": true 150 | }, 151 | { 152 | "userAdded": false, 153 | "type": "UnityEngine.Timeline.TimelineAsset", 154 | "ignore": false, 155 | "defaultInstantiationMode": 0, 156 | "supportsModification": true 157 | } 158 | ], 159 | "defaultDependencyTypeInfo": { 160 | "userAdded": false, 161 | "type": "", 162 | "ignore": false, 163 | "defaultInstantiationMode": 1, 164 | "supportsModification": true 165 | }, 166 | "newSceneOverride": 0 167 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/Internal/TaskTracker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Text; 6 | using System.Threading; 7 | 8 | namespace SFramework.Threading.Tasks.Internal 9 | { 10 | // public for add user custom. 11 | 12 | public static class TaskTracker 13 | { 14 | #if UNITY_EDITOR 15 | 16 | private static int trackingId = 0; 17 | 18 | public const string EnableAutoReloadKey = "STaskTrackerWindow_EnableAutoReloadKey"; 19 | public const string EnableTrackingKey = "STaskTrackerWindow_EnableTrackingKey"; 20 | public const string EnableStackTraceKey = "STaskTrackerWindow_EnableStackTraceKey"; 21 | 22 | public static class EditorEnableState 23 | { 24 | private static bool enableAutoReload; 25 | 26 | public static bool EnableAutoReload 27 | { 28 | get { return enableAutoReload; } 29 | set 30 | { 31 | enableAutoReload = value; 32 | UnityEditor.EditorPrefs.SetBool(EnableAutoReloadKey, value); 33 | } 34 | } 35 | 36 | private static bool enableTracking; 37 | public static bool EnableTracking 38 | { 39 | get { return enableTracking; } 40 | set 41 | { 42 | enableTracking = value; 43 | UnityEditor.EditorPrefs.SetBool(EnableTrackingKey, value); 44 | } 45 | } 46 | 47 | private static bool enableStackTrace; 48 | public static bool EnableStackTrace 49 | { 50 | get { return enableStackTrace; } 51 | set 52 | { 53 | enableStackTrace = value; 54 | UnityEditor.EditorPrefs.SetBool(EnableStackTraceKey, value); 55 | } 56 | } 57 | } 58 | 59 | #endif 60 | 61 | private static List> listPool 62 | = new List>(); 63 | private static readonly WeakDictionary tracking 64 | = new WeakDictionary(); 65 | 66 | [Conditional("UNITY_EDITOR")] 67 | public static void TrackActiveTask(ISTaskSource task, int skipFrame) 68 | { 69 | #if UNITY_EDITOR 70 | dirty = true; 71 | if (!EditorEnableState.EnableTracking) return; 72 | string stackTrace = EditorEnableState.EnableStackTrace ? new StackTrace(skipFrame, true).CleanupAsyncStackTrace() : ""; 73 | 74 | string typeName; 75 | if (EditorEnableState.EnableStackTrace) 76 | { 77 | var sb = new StringBuilder(); 78 | TypeBeautify(task.GetType(), sb); 79 | typeName = sb.ToString(); 80 | } 81 | else 82 | { 83 | typeName = task.GetType().Name; 84 | } 85 | tracking.TryAdd(task, (typeName, Interlocked.Increment(ref trackingId), DateTime.UtcNow, stackTrace)); 86 | #endif 87 | } 88 | 89 | [Conditional("UNITY_EDITOR")] 90 | public static void RemoveTracking(ISTaskSource task) 91 | { 92 | #if UNITY_EDITOR 93 | dirty = true; 94 | if (!EditorEnableState.EnableTracking) return; 95 | bool success = tracking.TryRemove(task); 96 | #endif 97 | } 98 | 99 | private static bool dirty; 100 | 101 | public static bool CheckAndResetDirty() 102 | { 103 | bool current = dirty; 104 | dirty = false; 105 | return current; 106 | } 107 | 108 | /// (trackingId, awaiterType, awaiterStatus, createdTime, stackTrace) 109 | public static void ForEachActiveTask(Action action) 110 | { 111 | lock (listPool) 112 | { 113 | int count = tracking.ToList(ref listPool, clear: false); 114 | try 115 | { 116 | for (int i = 0; i < count; i++) 117 | { 118 | action(listPool[i].Value.trackingId, listPool[i].Value.formattedType, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace); 119 | listPool[i] = default; 120 | } 121 | } 122 | catch 123 | { 124 | listPool.Clear(); 125 | throw; 126 | } 127 | } 128 | } 129 | 130 | private static void TypeBeautify(Type type, StringBuilder sb) 131 | { 132 | if (type.IsNested) 133 | { 134 | sb.Append(type.DeclaringType.Name.ToString()); 135 | sb.Append("."); 136 | } 137 | 138 | if (type.IsGenericType) 139 | { 140 | int genericsStart = type.Name.IndexOf("`"); 141 | if (genericsStart != -1) 142 | { 143 | sb.Append(type.Name.Substring(0, genericsStart)); 144 | } 145 | else 146 | { 147 | sb.Append(type.Name); 148 | } 149 | sb.Append("<"); 150 | bool first = true; 151 | foreach (Type item in type.GetGenericArguments()) 152 | { 153 | if (!first) 154 | { 155 | sb.Append(", "); 156 | } 157 | first = false; 158 | TypeBeautify(item, sb); 159 | } 160 | sb.Append(">"); 161 | } 162 | else 163 | { 164 | sb.Append(type.Name); 165 | } 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/TimeoutController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | using UnityEngine; 6 | using UnityEngine.Networking; 7 | 8 | namespace SFramework.Threading.Tasks 9 | { 10 | // CancellationTokenSource itself can not reuse but CancelAfter(Timeout.InfiniteTimeSpan) allows reuse if did not reach timeout. 11 | // Similar discussion: 12 | // https://github.com/dotnet/runtime/issues/4694 13 | // https://github.com/dotnet/runtime/issues/48492 14 | // This TimeoutController emulate similar implementation, using CancelAfterSlim; to achieve zero allocation timeout. 15 | 16 | // 优化每次调用异步方法时,创建CTS的性能开销: 17 | // TimeoutController timeoutController = new TimeoutController(); // setup to field for reuse. 18 | //async STask FooAsync() 19 | //{ 20 | // try 21 | // { 22 | // // you can pass timeoutController.Timeout(TimeSpan) to cancellationToken. 23 | // await UnityWebRequest.Get("http://foo").SendWebRequest() 24 | // .WithCancellation(timeoutController.Timeout(TimeSpan.FromSeconds(5))); 25 | // timeoutController.Reset(); // call Reset(Stop timeout timer and ready for reuse) when succeed. 26 | // } 27 | // catch (OperationCanceledException ex) 28 | // { 29 | // if (timeoutController.IsTimeout()) 30 | // { 31 | // UnityEngine.Debug.Log("timeout"); 32 | // } 33 | // } 34 | //} 35 | 36 | // TimeoutController可与其他CTS一起用,使用 new TimeoutController(CancellationToken) 37 | //TimeoutController timeoutController; 38 | //CancellationTokenSource clickCancelSource; 39 | //void Start() 40 | //{ 41 | // this.clickCancelSource = new CancellationTokenSource(); 42 | // this.timeoutController = new TimeoutController(clickCancelSource); 43 | //} 44 | 45 | public sealed class TimeoutController : IDisposable 46 | { 47 | private readonly static Action CancelCancellationTokenSourceStateDelegate = new Action(CancelCancellationTokenSourceState); 48 | 49 | private static void CancelCancellationTokenSourceState(object state) 50 | { 51 | var cts = (CancellationTokenSource)state; 52 | cts.Cancel(); 53 | } 54 | 55 | /// 默认CTS 56 | private CancellationTokenSource timeoutSource; 57 | /// 默认CTS与用户自定义CTS 58 | private CancellationTokenSource linkedSource; 59 | private PlayerLoopTimer timer; 60 | private bool isDisposed; 61 | 62 | private readonly DelayType delayType; 63 | private readonly PlayerLoopTiming delayTiming; 64 | /// 用户自定义CTS 65 | private readonly CancellationTokenSource originalLinkCancellationTokenSource; 66 | 67 | public TimeoutController(DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) 68 | { 69 | this.timeoutSource = new CancellationTokenSource(); 70 | this.originalLinkCancellationTokenSource = null; 71 | this.linkedSource = null; 72 | this.delayType = delayType; 73 | this.delayTiming = delayTiming; 74 | } 75 | 76 | public TimeoutController(CancellationTokenSource linkCancellationTokenSource, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update) 77 | { 78 | this.timeoutSource = new CancellationTokenSource(); 79 | this.originalLinkCancellationTokenSource = linkCancellationTokenSource; 80 | this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(this.timeoutSource.Token, linkCancellationTokenSource.Token); 81 | this.delayType = delayType; 82 | this.delayTiming = delayTiming; 83 | } 84 | 85 | public CancellationToken Timeout(int millisecondsTimeout) 86 | { 87 | return this.Timeout(TimeSpan.FromMilliseconds(millisecondsTimeout)); 88 | } 89 | 90 | public CancellationToken Timeout(TimeSpan timeout) 91 | { 92 | if (this.originalLinkCancellationTokenSource != null && this.originalLinkCancellationTokenSource.IsCancellationRequested) 93 | { 94 | //用户自定义CTS已经被用户取消,则不能再重新使用 95 | return this.originalLinkCancellationTokenSource.Token; 96 | } 97 | 98 | //倒计时结束,创建新CTS和timer 99 | if (this.timeoutSource.IsCancellationRequested) 100 | { 101 | this.timeoutSource.Dispose(); 102 | this.timeoutSource = new CancellationTokenSource(); 103 | if (this.linkedSource != null) 104 | { 105 | this.linkedSource.Cancel(); 106 | this.linkedSource.Dispose(); 107 | this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(this.timeoutSource.Token, this.originalLinkCancellationTokenSource.Token); 108 | } 109 | 110 | this.timer?.Dispose(); 111 | this.timer = null; 112 | } 113 | 114 | var useSource = (this.linkedSource != null) ? this.linkedSource : this.timeoutSource; 115 | var token = useSource.Token; 116 | if (this.timer == null) 117 | { 118 | // Timer complete => timeoutSource.Cancel() => linkedSource will be canceld as well 119 | // when (linked)token is canceled => stop timer 120 | this.timer = PlayerLoopTimer.StartNew(timeout, false, this.delayType, this.delayTiming, token, CancelCancellationTokenSourceStateDelegate, this.timeoutSource); 121 | } 122 | else 123 | { 124 | this.timer.Restart(timeout); 125 | } 126 | 127 | return token; 128 | } 129 | 130 | public bool IsTimeout() 131 | { 132 | return this.timeoutSource.IsCancellationRequested; 133 | } 134 | 135 | public void Reset() 136 | { 137 | this.timer?.Stop(); 138 | } 139 | 140 | public void Dispose() 141 | { 142 | if (this.isDisposed) 143 | return; 144 | 145 | try 146 | { 147 | // stop timer 148 | this.timer?.Dispose(); 149 | 150 | // cancel and dispose 151 | this.timeoutSource.Cancel(); 152 | this.timeoutSource.Dispose(); 153 | if (this.linkedSource != null) 154 | { 155 | this.linkedSource.Cancel(); 156 | this.linkedSource.Dispose(); 157 | } 158 | } 159 | finally 160 | { 161 | this.isDisposed = true; 162 | } 163 | } 164 | } 165 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/STaskTrackerTreeView.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using UnityEditor; 8 | using UnityEditor.IMGUI.Controls; 9 | using UnityEngine; 10 | 11 | namespace SFramework.Threading.Tasks.Editor 12 | { 13 | public class STaskTrackerViewItem : TreeViewItem 14 | { 15 | private static Regex removeHref = new Regex("(.+)", RegexOptions.Compiled); 16 | 17 | public string TaskType { get; set; } 18 | public string Elapsed { get; set; } 19 | public string Status { get; set; } 20 | 21 | private string position; 22 | public string Position 23 | { 24 | get { return this.position; } 25 | set 26 | { 27 | this.position = value; 28 | this.PositionFirstLine = GetFirstLine(this.position); 29 | } 30 | } 31 | 32 | public string PositionFirstLine { get; private set; } 33 | 34 | private static string GetFirstLine(string str) 35 | { 36 | var sb = new StringBuilder(); 37 | for (int i = 0; i < str.Length; i++) 38 | { 39 | if (str[i] == '\r' || str[i] == '\n') 40 | { 41 | break; 42 | } 43 | sb.Append(str[i]); 44 | } 45 | 46 | return removeHref.Replace(sb.ToString(), "$1"); 47 | } 48 | 49 | public STaskTrackerViewItem(int id) : base(id) 50 | { 51 | 52 | } 53 | } 54 | 55 | public class STaskTrackerTreeView : TreeView 56 | { 57 | private const string sortedColumnIndexStateKey = "STaskTrackerTreeView_sortedColumnIndex"; 58 | 59 | public IReadOnlyList CurrentBindingItems; 60 | 61 | public STaskTrackerTreeView() : this(new TreeViewState(), new MultiColumnHeader(new MultiColumnHeaderState(new[] 62 | { 63 | new MultiColumnHeaderState.Column() { headerContent = new GUIContent("TaskType"), width = 20 }, 64 | new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Elapsed"), width = 10 }, 65 | new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Status"), width = 20 }, 66 | new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Position") }, 67 | }))) { } 68 | 69 | private STaskTrackerTreeView(TreeViewState state, MultiColumnHeader header) 70 | : base(state, header) 71 | { 72 | this.rowHeight = 20; 73 | this.showAlternatingRowBackgrounds = true; 74 | this.showBorder = true; 75 | header.sortingChanged += this.HeaderSortingChanged; 76 | 77 | header.ResizeToFit(); 78 | this.Reload(); 79 | 80 | header.sortedColumnIndex = SessionState.GetInt(sortedColumnIndexStateKey, 1); 81 | } 82 | 83 | public void ReloadAndSort() 84 | { 85 | List currentSelected = this.state.selectedIDs; 86 | this.Reload(); 87 | this.HeaderSortingChanged(this.multiColumnHeader); 88 | this.state.selectedIDs = currentSelected; 89 | } 90 | 91 | private void HeaderSortingChanged(MultiColumnHeader multicolumnHeader) 92 | { 93 | SessionState.SetInt(sortedColumnIndexStateKey, multicolumnHeader.sortedColumnIndex); 94 | int index = multicolumnHeader.sortedColumnIndex; 95 | bool ascending = multicolumnHeader.IsSortedAscending(multicolumnHeader.sortedColumnIndex); 96 | 97 | var items = this.rootItem.children.Cast(); 98 | 99 | IOrderedEnumerable orderedEnumerable; 100 | switch (index) 101 | { 102 | case 0: 103 | orderedEnumerable = ascending ? items.OrderBy(item => item.TaskType) : items.OrderByDescending(item => item.TaskType); 104 | break; 105 | case 1: 106 | orderedEnumerable = ascending ? items.OrderBy(item => double.Parse(item.Elapsed)) : items.OrderByDescending(item => double.Parse(item.Elapsed)); 107 | break; 108 | case 2: 109 | orderedEnumerable = ascending ? items.OrderBy(item => item.Status) : items.OrderByDescending(item => item.Status); 110 | break; 111 | case 3: 112 | orderedEnumerable = ascending ? items.OrderBy(item => item.Position) : items.OrderByDescending(item => item.Position); 113 | break; 114 | default: 115 | throw new ArgumentOutOfRangeException(nameof(index), index, null); 116 | } 117 | 118 | this.CurrentBindingItems = this.rootItem.children = orderedEnumerable.Cast().ToList(); 119 | this.BuildRows(this.rootItem); 120 | } 121 | 122 | protected override TreeViewItem BuildRoot() 123 | { 124 | var root = new TreeViewItem() { depth = -1 }; 125 | 126 | var children = new List(); 127 | 128 | TaskTracker.ForEachActiveTask((trackingId, awaiterType, status, created, stackTrace) => 129 | { 130 | children.Add(new STaskTrackerViewItem(trackingId) { TaskType = awaiterType, Status = status.ToString(), Elapsed = (DateTime.UtcNow - created).TotalSeconds.ToString("00.00"), Position = stackTrace }); 131 | }); 132 | 133 | this.CurrentBindingItems = children; 134 | root.children = this.CurrentBindingItems as List; 135 | return root; 136 | } 137 | 138 | protected override bool CanMultiSelect(TreeViewItem item) 139 | { 140 | return false; 141 | } 142 | 143 | protected override void RowGUI(RowGUIArgs args) 144 | { 145 | var item = args.item as STaskTrackerViewItem; 146 | 147 | for (var visibleColumnIndex = 0; visibleColumnIndex < args.GetNumVisibleColumns(); visibleColumnIndex++) 148 | { 149 | var rect = args.GetCellRect(visibleColumnIndex); 150 | var columnIndex = args.GetColumn(visibleColumnIndex); 151 | 152 | var labelStyle = args.selected ? EditorStyles.whiteLabel : EditorStyles.label; 153 | labelStyle.alignment = TextAnchor.MiddleLeft; 154 | switch (columnIndex) 155 | { 156 | case 0: 157 | EditorGUI.LabelField(rect, item.TaskType, labelStyle); 158 | break; 159 | case 1: 160 | EditorGUI.LabelField(rect, item.Elapsed, labelStyle); 161 | break; 162 | case 2: 163 | EditorGUI.LabelField(rect, item.Status, labelStyle); 164 | break; 165 | case 3: 166 | EditorGUI.LabelField(rect, item.PositionFirstLine, labelStyle); 167 | break; 168 | default: 169 | throw new ArgumentOutOfRangeException(nameof(columnIndex), columnIndex, null); 170 | } 171 | } 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /STask/ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 16 41 | asyncUploadPersistentBuffer: 1 42 | resolutionScalingFixedDPIFactor: 1 43 | excludedTargetPlatforms: [] 44 | - serializedVersion: 2 45 | name: Low 46 | pixelLightCount: 0 47 | shadows: 0 48 | shadowResolution: 0 49 | shadowProjection: 1 50 | shadowCascades: 1 51 | shadowDistance: 20 52 | shadowNearPlaneOffset: 3 53 | shadowCascade2Split: 0.33333334 54 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 55 | shadowmaskMode: 0 56 | blendWeights: 2 57 | textureQuality: 0 58 | anisotropicTextures: 0 59 | antiAliasing: 0 60 | softParticles: 0 61 | softVegetation: 0 62 | realtimeReflectionProbes: 0 63 | billboardsFaceCameraPosition: 0 64 | vSyncCount: 0 65 | lodBias: 0.4 66 | maximumLODLevel: 0 67 | streamingMipmapsActive: 0 68 | streamingMipmapsAddAllCameras: 1 69 | streamingMipmapsMemoryBudget: 512 70 | streamingMipmapsRenderersPerFrame: 512 71 | streamingMipmapsMaxLevelReduction: 2 72 | streamingMipmapsMaxFileIORequests: 1024 73 | particleRaycastBudget: 16 74 | asyncUploadTimeSlice: 2 75 | asyncUploadBufferSize: 16 76 | asyncUploadPersistentBuffer: 1 77 | resolutionScalingFixedDPIFactor: 1 78 | excludedTargetPlatforms: [] 79 | - serializedVersion: 2 80 | name: Medium 81 | pixelLightCount: 1 82 | shadows: 1 83 | shadowResolution: 0 84 | shadowProjection: 1 85 | shadowCascades: 1 86 | shadowDistance: 20 87 | shadowNearPlaneOffset: 3 88 | shadowCascade2Split: 0.33333334 89 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 90 | shadowmaskMode: 0 91 | blendWeights: 2 92 | textureQuality: 0 93 | anisotropicTextures: 1 94 | antiAliasing: 0 95 | softParticles: 0 96 | softVegetation: 0 97 | realtimeReflectionProbes: 0 98 | billboardsFaceCameraPosition: 0 99 | vSyncCount: 1 100 | lodBias: 0.7 101 | maximumLODLevel: 0 102 | streamingMipmapsActive: 0 103 | streamingMipmapsAddAllCameras: 1 104 | streamingMipmapsMemoryBudget: 512 105 | streamingMipmapsRenderersPerFrame: 512 106 | streamingMipmapsMaxLevelReduction: 2 107 | streamingMipmapsMaxFileIORequests: 1024 108 | particleRaycastBudget: 64 109 | asyncUploadTimeSlice: 2 110 | asyncUploadBufferSize: 16 111 | asyncUploadPersistentBuffer: 1 112 | resolutionScalingFixedDPIFactor: 1 113 | excludedTargetPlatforms: [] 114 | - serializedVersion: 2 115 | name: High 116 | pixelLightCount: 2 117 | shadows: 2 118 | shadowResolution: 1 119 | shadowProjection: 1 120 | shadowCascades: 2 121 | shadowDistance: 40 122 | shadowNearPlaneOffset: 3 123 | shadowCascade2Split: 0.33333334 124 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 125 | shadowmaskMode: 1 126 | blendWeights: 2 127 | textureQuality: 0 128 | anisotropicTextures: 1 129 | antiAliasing: 0 130 | softParticles: 0 131 | softVegetation: 1 132 | realtimeReflectionProbes: 1 133 | billboardsFaceCameraPosition: 1 134 | vSyncCount: 1 135 | lodBias: 1 136 | maximumLODLevel: 0 137 | streamingMipmapsActive: 0 138 | streamingMipmapsAddAllCameras: 1 139 | streamingMipmapsMemoryBudget: 512 140 | streamingMipmapsRenderersPerFrame: 512 141 | streamingMipmapsMaxLevelReduction: 2 142 | streamingMipmapsMaxFileIORequests: 1024 143 | particleRaycastBudget: 256 144 | asyncUploadTimeSlice: 2 145 | asyncUploadBufferSize: 16 146 | asyncUploadPersistentBuffer: 1 147 | resolutionScalingFixedDPIFactor: 1 148 | excludedTargetPlatforms: [] 149 | - serializedVersion: 2 150 | name: Very High 151 | pixelLightCount: 3 152 | shadows: 2 153 | shadowResolution: 2 154 | shadowProjection: 1 155 | shadowCascades: 2 156 | shadowDistance: 70 157 | shadowNearPlaneOffset: 3 158 | shadowCascade2Split: 0.33333334 159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 160 | shadowmaskMode: 1 161 | blendWeights: 4 162 | textureQuality: 0 163 | anisotropicTextures: 2 164 | antiAliasing: 2 165 | softParticles: 1 166 | softVegetation: 1 167 | realtimeReflectionProbes: 1 168 | billboardsFaceCameraPosition: 1 169 | vSyncCount: 1 170 | lodBias: 1.5 171 | maximumLODLevel: 0 172 | streamingMipmapsActive: 0 173 | streamingMipmapsAddAllCameras: 1 174 | streamingMipmapsMemoryBudget: 512 175 | streamingMipmapsRenderersPerFrame: 512 176 | streamingMipmapsMaxLevelReduction: 2 177 | streamingMipmapsMaxFileIORequests: 1024 178 | particleRaycastBudget: 1024 179 | asyncUploadTimeSlice: 2 180 | asyncUploadBufferSize: 16 181 | asyncUploadPersistentBuffer: 1 182 | resolutionScalingFixedDPIFactor: 1 183 | excludedTargetPlatforms: [] 184 | - serializedVersion: 2 185 | name: Ultra 186 | pixelLightCount: 4 187 | shadows: 2 188 | shadowResolution: 2 189 | shadowProjection: 1 190 | shadowCascades: 4 191 | shadowDistance: 150 192 | shadowNearPlaneOffset: 3 193 | shadowCascade2Split: 0.33333334 194 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 195 | shadowmaskMode: 1 196 | blendWeights: 4 197 | textureQuality: 0 198 | anisotropicTextures: 2 199 | antiAliasing: 2 200 | softParticles: 1 201 | softVegetation: 1 202 | realtimeReflectionProbes: 1 203 | billboardsFaceCameraPosition: 1 204 | vSyncCount: 1 205 | lodBias: 2 206 | maximumLODLevel: 0 207 | streamingMipmapsActive: 0 208 | streamingMipmapsAddAllCameras: 1 209 | streamingMipmapsMemoryBudget: 512 210 | streamingMipmapsRenderersPerFrame: 512 211 | streamingMipmapsMaxLevelReduction: 2 212 | streamingMipmapsMaxFileIORequests: 1024 213 | particleRaycastBudget: 4096 214 | asyncUploadTimeSlice: 2 215 | asyncUploadBufferSize: 16 216 | asyncUploadPersistentBuffer: 1 217 | resolutionScalingFixedDPIFactor: 1 218 | excludedTargetPlatforms: [] 219 | m_PerPlatformDefaultQuality: 220 | Android: 2 221 | Lumin: 5 222 | GameCoreScarlett: 5 223 | GameCoreXboxOne: 5 224 | Nintendo 3DS: 5 225 | Nintendo Switch: 5 226 | PS4: 5 227 | PS5: 5 228 | Stadia: 5 229 | Standalone: 5 230 | WebGL: 3 231 | Windows Store Apps: 5 232 | XboxOne: 5 233 | iPhone: 2 234 | tvOS: 2 235 | -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.Factory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.ExceptionServices; 3 | using System.Threading; 4 | 5 | namespace SFramework.Threading.Tasks 6 | { 7 | public partial struct STask 8 | { 9 | public static readonly STask CompletedTask = new STask(); 10 | 11 | public static STask FromResult(T value) 12 | { 13 | return new STask(value); 14 | } 15 | 16 | #region FromException 17 | public static STask FromException(Exception exception) 18 | { 19 | if (exception is OperationCanceledException oce) 20 | { 21 | return FromCanceled(oce.CancellationToken); 22 | } 23 | return new STask(new ExceptionResultSource(exception), 0); 24 | } 25 | 26 | public static STask FromException(Exception exception) 27 | { 28 | if (exception is OperationCanceledException oce) 29 | { 30 | return FromCanceled(oce.CancellationToken); 31 | } 32 | return new STask(new ExceptionResultSource(exception), 0); 33 | } 34 | #endregion 35 | 36 | #region CanceledTask 37 | /// 默认的 Canceled STask 对象 (CancellationToken 为 None) 38 | private static readonly STask CanceledSTask = new Func(() =>//用委托包装下,当方法用 39 | { 40 | return new STask(new CanceledResultSource(CancellationToken.None), 0); 41 | })(); 42 | 43 | private static class CanceledSTaskCache 44 | { 45 | public static readonly STask Task; 46 | 47 | static CanceledSTaskCache() 48 | { 49 | Task = new STask(new CanceledResultSource(CancellationToken.None), 0); 50 | } 51 | } 52 | 53 | public static STask FromCanceled(CancellationToken cancellationToken = default) 54 | { 55 | if (cancellationToken == CancellationToken.None)//默认token 56 | { 57 | return CanceledSTask; 58 | } 59 | else 60 | { 61 | return new STask(new CanceledResultSource(cancellationToken), 0); 62 | } 63 | } 64 | 65 | public static STask FromCanceled(CancellationToken cancellationToken = default) 66 | { 67 | if (cancellationToken == CancellationToken.None) 68 | { 69 | return CanceledSTaskCache.Task; 70 | } 71 | else 72 | { 73 | return new STask(new CanceledResultSource(cancellationToken), 0); 74 | } 75 | } 76 | #endregion 77 | 78 | #region ISTaskSource 79 | private sealed class ExceptionResultSource : ISTaskSource 80 | { 81 | private readonly ExceptionDispatchInfo exception; 82 | private bool calledGet; 83 | 84 | public ExceptionResultSource(Exception exception) 85 | { 86 | this.exception = ExceptionDispatchInfo.Capture(exception); 87 | } 88 | 89 | public void GetResult(short token) 90 | { 91 | if (!this.calledGet) 92 | { 93 | this.calledGet = true; 94 | GC.SuppressFinalize(this);//不要调用析构函数,防止在Finalize线程调用析构函数之后,GC再重复调用 95 | } 96 | this.exception.Throw(); 97 | } 98 | 99 | public STaskStatus GetStatus(short token) 100 | { 101 | return STaskStatus.Faulted; 102 | } 103 | 104 | public STaskStatus UnsafeGetStatus() 105 | { 106 | return STaskStatus.Faulted; 107 | } 108 | 109 | public void OnCompleted(Action continuation, object state, short token) 110 | { 111 | continuation(state); 112 | } 113 | 114 | ~ExceptionResultSource() 115 | { 116 | if (!this.calledGet)//未处理异常,抛出来 117 | { 118 | STaskScheduler.PublishUnobservedTaskException(this.exception.SourceException); 119 | } 120 | } 121 | } 122 | 123 | private sealed class ExceptionResultSource : ISTaskSource 124 | { 125 | private readonly ExceptionDispatchInfo exception; 126 | private bool calledGet; 127 | 128 | public ExceptionResultSource(Exception exception) 129 | { 130 | this.exception = ExceptionDispatchInfo.Capture(exception); 131 | } 132 | 133 | public T GetResult(short token) 134 | { 135 | if (!this.calledGet) 136 | { 137 | this.calledGet = true; 138 | GC.SuppressFinalize(this);//不要调用析构函数,防止在Finalize线程调用析构函数之后,GC再重复调用 139 | } 140 | this.exception.Throw(); 141 | return default; 142 | } 143 | 144 | void ISTaskSource.GetResult(short token) 145 | { 146 | if (!this.calledGet) 147 | { 148 | this.calledGet = true; 149 | GC.SuppressFinalize(this); 150 | } 151 | this.exception.Throw(); 152 | } 153 | 154 | public STaskStatus GetStatus(short token) 155 | { 156 | return STaskStatus.Faulted; 157 | } 158 | 159 | public STaskStatus UnsafeGetStatus() 160 | { 161 | return STaskStatus.Faulted; 162 | } 163 | 164 | public void OnCompleted(Action continuation, object state, short token) 165 | { 166 | continuation(state); 167 | } 168 | 169 | ~ExceptionResultSource() 170 | { 171 | if (!this.calledGet)//未处理异常,抛出来 172 | { 173 | STaskScheduler.PublishUnobservedTaskException(this.exception.SourceException); 174 | } 175 | } 176 | } 177 | 178 | /// 179 | /// 用于创建被取消的 STask 180 | /// 181 | private sealed class CanceledResultSource : ISTaskSource 182 | { 183 | private readonly CancellationToken cancellationToken; 184 | 185 | public CanceledResultSource(CancellationToken cancellationToken) 186 | { 187 | this.cancellationToken = cancellationToken; 188 | } 189 | 190 | public void GetResult(short token) 191 | { 192 | throw new OperationCanceledException(this.cancellationToken); 193 | } 194 | 195 | public STaskStatus GetStatus(short token) 196 | { 197 | return STaskStatus.Canceled; 198 | } 199 | 200 | public STaskStatus UnsafeGetStatus() 201 | { 202 | return STaskStatus.Canceled; 203 | } 204 | 205 | public void OnCompleted(Action continuation, object state, short token) 206 | { 207 | continuation(state); 208 | } 209 | } 210 | 211 | private sealed class CanceledResultSource : ISTaskSource 212 | { 213 | private readonly CancellationToken cancellationToken; 214 | 215 | public CanceledResultSource(CancellationToken cancellationToken) 216 | { 217 | this.cancellationToken = cancellationToken; 218 | } 219 | 220 | public T GetResult(short token) 221 | { 222 | throw new OperationCanceledException(this.cancellationToken); 223 | } 224 | 225 | void ISTaskSource.GetResult(short token) 226 | { 227 | throw new OperationCanceledException(this.cancellationToken); 228 | } 229 | 230 | public STaskStatus GetStatus(short token) 231 | { 232 | return STaskStatus.Canceled; 233 | } 234 | 235 | public STaskStatus UnsafeGetStatus() 236 | { 237 | return STaskStatus.Canceled; 238 | } 239 | 240 | public void OnCompleted(Action continuation, object state, short token) 241 | { 242 | continuation(state); 243 | } 244 | } 245 | #endregion 246 | } 247 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Editor/STaskTrackerWindow.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using System.Linq; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace SFramework.Threading.Tasks.Editor 8 | { 9 | public class STaskTrackerWindow : EditorWindow 10 | { 11 | private static int interval; 12 | 13 | private static STaskTrackerWindow window; 14 | 15 | [MenuItem("Window/STask Tracker")] 16 | public static void OpenWindow() 17 | { 18 | if (window != null) 19 | { 20 | window.Close(); 21 | } 22 | 23 | // will called OnEnable(singleton instance will be set). 24 | GetWindow("STask Tracker").Show(); 25 | } 26 | 27 | private static readonly GUILayoutOption[] EmptyLayoutOption = new GUILayoutOption[0]; 28 | 29 | private STaskTrackerTreeView treeView; 30 | private object splitterState; 31 | 32 | private void OnEnable() 33 | { 34 | window = this;// set singleton. 35 | this.splitterState = SplitterGUILayout.CreateSplitterState(new float[] { 75f, 25f }, new int[] { 32, 32 }, null); 36 | this.treeView = new STaskTrackerTreeView(); 37 | TaskTracker.EditorEnableState.EnableAutoReload = EditorPrefs.GetBool(TaskTracker.EnableAutoReloadKey, false); 38 | TaskTracker.EditorEnableState.EnableTracking = EditorPrefs.GetBool(TaskTracker.EnableTrackingKey, false); 39 | TaskTracker.EditorEnableState.EnableStackTrace = EditorPrefs.GetBool(TaskTracker.EnableStackTraceKey, false); 40 | } 41 | 42 | private void OnGUI() 43 | { 44 | // Head 45 | this.RenderHeadPanel(); 46 | 47 | // Splittable 48 | SplitterGUILayout.BeginVerticalSplit(this.splitterState, EmptyLayoutOption); 49 | { 50 | // Column Table 51 | this.RenderTable(); 52 | 53 | // StackTrace details 54 | this.RenderDetailsPanel(); 55 | } 56 | SplitterGUILayout.EndVerticalSplit(); 57 | } 58 | 59 | #region HeadPanel 60 | 61 | public static bool EnableAutoReload => TaskTracker.EditorEnableState.EnableAutoReload; 62 | public static bool EnableTracking => TaskTracker.EditorEnableState.EnableTracking; 63 | public static bool EnableStackTrace => TaskTracker.EditorEnableState.EnableStackTrace; 64 | private static readonly GUIContent EnableAutoReloadHeadContent = EditorGUIUtility.TrTextContent("Enable AutoReload", "Reload automatically."); 65 | private static readonly GUIContent ReloadHeadContent = EditorGUIUtility.TrTextContent("Reload", "Reload View"); 66 | private static readonly GUIContent GCHeadContent = EditorGUIUtility.TrTextContent("GC.Collect", "Invoke GC.Collect"); 67 | private static readonly GUIContent EnableTrackingHeadContent = EditorGUIUtility.TrTextContent("Enable Tracking", "Start to track async/await STask. Performance impact:low"); 68 | private static readonly GUIContent EnableStackTraceHeadContent = EditorGUIUtility.TrTextContent("Enable StackTrace", "Capture StackTrace when task is started. Performance:high"); 69 | 70 | // [Enable Tracking] | [Enable StackTrace] 71 | private void RenderHeadPanel() 72 | { 73 | EditorGUILayout.BeginVertical(EmptyLayoutOption); 74 | { 75 | EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, EmptyLayoutOption); 76 | { 77 | if (GUILayout.Toggle(EnableAutoReload, EnableAutoReloadHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableAutoReload) 78 | { 79 | TaskTracker.EditorEnableState.EnableAutoReload = !EnableAutoReload; 80 | } 81 | 82 | if (GUILayout.Toggle(EnableTracking, EnableTrackingHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableTracking) 83 | { 84 | TaskTracker.EditorEnableState.EnableTracking = !EnableTracking; 85 | } 86 | 87 | if (GUILayout.Toggle(EnableStackTrace, EnableStackTraceHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption) != EnableStackTrace) 88 | { 89 | TaskTracker.EditorEnableState.EnableStackTrace = !EnableStackTrace; 90 | } 91 | 92 | GUILayout.FlexibleSpace(); 93 | 94 | if (GUILayout.Button(ReloadHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption)) 95 | { 96 | TaskTracker.CheckAndResetDirty(); 97 | this.treeView.ReloadAndSort(); 98 | this.Repaint(); 99 | } 100 | 101 | if (GUILayout.Button(GCHeadContent, EditorStyles.toolbarButton, EmptyLayoutOption)) 102 | { 103 | GC.Collect(); 104 | } 105 | } 106 | EditorGUILayout.EndHorizontal(); 107 | } 108 | EditorGUILayout.EndVertical(); 109 | } 110 | #endregion 111 | 112 | #region TableColumn 113 | 114 | private Vector2 tableScroll; 115 | private GUIStyle tableListStyle; 116 | 117 | private void RenderTable() 118 | { 119 | if (this.tableListStyle == null) 120 | { 121 | this.tableListStyle = new GUIStyle("CN Box"); 122 | this.tableListStyle.margin.top = 0; 123 | this.tableListStyle.padding.left = 3; 124 | } 125 | 126 | EditorGUILayout.BeginVertical(this.tableListStyle, EmptyLayoutOption); 127 | { 128 | this.tableScroll = EditorGUILayout.BeginScrollView(this.tableScroll, new GUILayoutOption[] 129 | { 130 | GUILayout.ExpandWidth(true), 131 | GUILayout.MaxWidth(2000f) 132 | }); 133 | var controlRect = EditorGUILayout.GetControlRect(new GUILayoutOption[] 134 | { 135 | GUILayout.ExpandHeight(true), 136 | GUILayout.ExpandWidth(true) 137 | }); 138 | 139 | this.treeView?.OnGUI(controlRect); 140 | EditorGUILayout.EndScrollView(); 141 | } 142 | EditorGUILayout.EndVertical(); 143 | } 144 | 145 | private void Update() 146 | { 147 | if (EnableAutoReload) 148 | { 149 | if (interval++ % 120 == 0) 150 | { 151 | if (TaskTracker.CheckAndResetDirty()) 152 | { 153 | this.treeView.ReloadAndSort(); 154 | this.Repaint(); 155 | } 156 | } 157 | } 158 | } 159 | 160 | #endregion 161 | 162 | #region Details 163 | 164 | private static GUIStyle detailsStyle; 165 | private Vector2 detailsScroll; 166 | 167 | private void RenderDetailsPanel() 168 | { 169 | if (detailsStyle == null) 170 | { 171 | detailsStyle = new GUIStyle("CN Message"); 172 | detailsStyle.wordWrap = false; 173 | detailsStyle.stretchHeight = true; 174 | detailsStyle.margin.right = 15; 175 | } 176 | 177 | string message = ""; 178 | var selected = this.treeView.state.selectedIDs; 179 | if (selected.Count > 0) 180 | { 181 | var first = selected[0]; 182 | var item = this.treeView.CurrentBindingItems.FirstOrDefault(x => x.id == first) as STaskTrackerViewItem; 183 | if (item != null) 184 | { 185 | message = item.Position; 186 | } 187 | } 188 | 189 | this.detailsScroll = EditorGUILayout.BeginScrollView(this.detailsScroll, EmptyLayoutOption); 190 | { 191 | var vector = detailsStyle.CalcSize(new GUIContent(message)); 192 | EditorGUILayout.SelectableLabel(message, detailsStyle, new GUILayoutOption[] 193 | { 194 | GUILayout.ExpandHeight(true), 195 | GUILayout.ExpandWidth(true), 196 | GUILayout.MinWidth(vector.x), 197 | GUILayout.MinHeight(vector.y) 198 | }); 199 | } 200 | EditorGUILayout.EndScrollView(); 201 | } 202 | 203 | #endregion 204 | } 205 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/CompilerServices/AsyncSTaskMethodBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using System.Security; 5 | 6 | namespace SFramework.Threading.Tasks.CompilerServices 7 | { 8 | [StructLayout(LayoutKind.Auto)] 9 | public struct AsyncSTaskMethodBuilder 10 | { 11 | IStateMachineRunnerPromise runnerPromise; 12 | Exception ex; 13 | 14 | /// 15 | /// 1.Static Create Method 16 | /// 17 | /// 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public static AsyncSTaskMethodBuilder Create() 20 | { 21 | return default; 22 | } 23 | 24 | /// 25 | /// 2.task-like 对象属性;Start 方法返回后将访问 builder.Task 26 | /// 27 | public STask Task 28 | { 29 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | get 31 | { 32 | if (this.runnerPromise != null) 33 | { 34 | return this.runnerPromise.Task; 35 | } 36 | else if (this.ex != null) 37 | { 38 | return STask.FromException(this.ex); 39 | } 40 | else 41 | { 42 | return STask.CompletedTask; 43 | } 44 | } 45 | } 46 | 47 | /// 48 | /// 3. SetException;发生异常后将调用该方法 49 | /// 50 | /// 51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 | public void SetException(Exception exception) 53 | { 54 | if (this.runnerPromise == null) 55 | { 56 | this.ex = exception; 57 | } 58 | else 59 | { 60 | this.runnerPromise.SetException(exception); 61 | } 62 | } 63 | 64 | /// 65 | /// 4. SetResult;状态机任务执行完毕后调用 66 | /// 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public void SetResult() 69 | { 70 | if (this.runnerPromise != null) 71 | { 72 | this.runnerPromise.SetResult(); 73 | } 74 | } 75 | 76 | /// 77 | /// 5. AwaitOnCompleted 78 | /// 79 | /// 80 | /// 81 | /// 82 | /// 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | public void AwaitOnCompleted(ref TAwaiter awaiter,ref TStateMachine stateMachine) 85 | where TAwaiter:INotifyCompletion 86 | where TStateMachine : IAsyncStateMachine 87 | { 88 | if (this.runnerPromise == null) 89 | { 90 | AsyncSTask.SetStateMachine(ref stateMachine, ref this.runnerPromise); 91 | } 92 | 93 | awaiter.OnCompleted(this.runnerPromise.MoveNext);//awaiter任务执行完毕,推动状态机运行 94 | } 95 | 96 | /// 97 | /// 6. AwaitUnsafeOnCompleted; 98 | /// 状态机遇到 await 关键字后,通过 GetAwaiter() 获取Awaiter,若其 IsCompleted 为 false,调用该方法注册 Awaiter 任务结束后的回调(builder.MoveNext) 99 | /// 至于调用 AwaitUnsafeOnCompleted 还是 AwaitOnCompleted,由 Awaiter 实现的接口决定 100 | /// 101 | /// 102 | /// 103 | /// 104 | /// 105 | [SecuritySafeCritical] 106 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 107 | public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter,ref TStateMachine stateMachine) 108 | where TAwaiter:ICriticalNotifyCompletion 109 | where TStateMachine : IAsyncStateMachine 110 | { 111 | if (this.runnerPromise == null) 112 | { 113 | AsyncSTask.SetStateMachine(ref stateMachine, ref this.runnerPromise); 114 | } 115 | 116 | awaiter.UnsafeOnCompleted(this.runnerPromise.MoveNext); 117 | } 118 | 119 | /// 120 | /// 7. Start 121 | /// 122 | /// 123 | /// 124 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 125 | public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine 126 | { 127 | stateMachine.MoveNext();//异步方法开始,启动状态机,一般会执行到第一个 await 关键字之前 128 | } 129 | 130 | /// 131 | /// 8. SetStateMachine 132 | /// 133 | /// 134 | public void SetStateMachine(IAsyncStateMachine stateMachine) 135 | { 136 | //由于性能问题,这里拒绝使用装箱之后的状态机,所以 nothing happened 137 | } 138 | } 139 | 140 | [StructLayout(LayoutKind.Auto)] 141 | public struct AsyncSTaskMethodBuilder 142 | { 143 | private IStateMachineRunnerPromise runnerPromise; 144 | private Exception ex; 145 | private T result; 146 | 147 | // 1. Static Create method 148 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 149 | public static AsyncSTaskMethodBuilder Create() 150 | { 151 | return default; 152 | } 153 | 154 | // 2. TaskLike Task property 155 | public STask Task 156 | { 157 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 158 | get 159 | { 160 | if (this.runnerPromise != null) 161 | { 162 | return this.runnerPromise.Task; 163 | } 164 | else if (this.ex != null) 165 | { 166 | return STask.FromException(this.ex); 167 | } 168 | else 169 | { 170 | return STask.FromResult(this.result); 171 | } 172 | } 173 | } 174 | 175 | // 3. SetException 176 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 177 | public void SetException(Exception exception) 178 | { 179 | if (this.runnerPromise == null) 180 | { 181 | this.ex = exception; 182 | } 183 | else 184 | { 185 | this.runnerPromise.SetException(exception); 186 | } 187 | } 188 | 189 | // 4. SetResult 190 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 191 | public void SetResult(T result) 192 | { 193 | if(this.runnerPromise == null) 194 | { 195 | this.result = result; 196 | } 197 | else 198 | { 199 | this.runnerPromise.SetResult(result); 200 | } 201 | } 202 | 203 | // 5. AwaitOnCompleted 204 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 205 | public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) 206 | where TAwaiter : INotifyCompletion 207 | where TStateMachine : IAsyncStateMachine 208 | { 209 | if (this.runnerPromise == null) 210 | { 211 | AsyncSTask.SetStateMachine(ref stateMachine, ref this.runnerPromise); 212 | } 213 | 214 | awaiter.OnCompleted(this.runnerPromise.MoveNext); 215 | } 216 | 217 | // 6. AwaitUnsafeOnCompleted 218 | [SecuritySafeCritical] 219 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 220 | public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) 221 | where TAwaiter : ICriticalNotifyCompletion 222 | where TStateMachine : IAsyncStateMachine 223 | { 224 | if (this.runnerPromise == null) 225 | { 226 | AsyncSTask.SetStateMachine(ref stateMachine, ref this.runnerPromise); 227 | } 228 | 229 | awaiter.UnsafeOnCompleted(this.runnerPromise.MoveNext); 230 | } 231 | 232 | // 7. Start 233 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 234 | public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine 235 | { 236 | stateMachine.MoveNext(); 237 | } 238 | 239 | // 8. SetStateMachine 240 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 241 | public void SetStateMachine(IAsyncStateMachine stateMachine) 242 | { 243 | //由于性能问题,这里拒绝使用装箱之后的状态机,所以 nothing happened 244 | } 245 | } 246 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/STask.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.CompilerServices; 2 | using System; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace SFramework.Threading.Tasks 7 | { 8 | internal static class AwaiterActions 9 | { 10 | internal static readonly Action InvokeContinuationDelegate = Continuation; 11 | 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | private static void Continuation(object state)//state is continuation 14 | { 15 | ((Action)state).Invoke(); 16 | } 17 | } 18 | 19 | /// 20 | /// 轻量级 task-like 对象 21 | /// 22 | /// 23 | [AsyncMethodBuilder(typeof(AsyncSTaskMethodBuilder))] 24 | [StructLayout(LayoutKind.Auto)] 25 | public readonly partial struct STask 26 | { 27 | private readonly ISTaskSource source; 28 | private readonly short token; 29 | 30 | /// 31 | /// 32 | /// 33 | /// 一般情况下是 34 | /// 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | public STask(ISTaskSource source, short token) 37 | { 38 | this.source = source; 39 | this.token = token; 40 | } 41 | 42 | public STaskStatus Status 43 | { 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | get 46 | { 47 | if (this.source == null) 48 | return STaskStatus.Succeeded; 49 | return this.source.GetStatus(this.token); 50 | } 51 | } 52 | 53 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 54 | public Awaiter GetAwaiter() 55 | { 56 | return new Awaiter(this); 57 | } 58 | 59 | public override string ToString() 60 | { 61 | if (this.source == null) 62 | return "()"; 63 | return "(" + this.source.UnsafeGetStatus() + ")"; 64 | } 65 | 66 | public readonly struct Awaiter : ICriticalNotifyCompletion 67 | { 68 | private readonly STask task; 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | public Awaiter(in STask task) 72 | { 73 | this.task = task; 74 | } 75 | 76 | public bool IsCompleted 77 | { 78 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 79 | get 80 | { 81 | return this.task.Status.IsCompleted(); 82 | } 83 | } 84 | 85 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 | public void GetResult() 87 | { 88 | if (this.task.source == null) 89 | return; 90 | this.task.source.GetResult(this.task.token); 91 | } 92 | 93 | 94 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 95 | public void OnCompleted(Action continuation) 96 | { 97 | if (this.task.source == null) 98 | { 99 | continuation(); 100 | } 101 | else 102 | { 103 | this.task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, this.task.token); 104 | } 105 | } 106 | 107 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 108 | public void UnsafeOnCompleted(Action continuation) 109 | { 110 | if (this.task.source == null) 111 | { 112 | continuation(); 113 | } 114 | else 115 | { 116 | this.task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, this.task.token); 117 | } 118 | } 119 | 120 | /// 121 | /// 手动注册 continuation 的话,用该方法来替代 OnCompleted 122 | /// 123 | /// 124 | /// 125 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 126 | public void SourceOnCompleted(Action continuation, object state) 127 | { 128 | if (this.task.source == null) 129 | { 130 | continuation(state); 131 | } 132 | else 133 | { 134 | this.task.source.OnCompleted(continuation, state, this.task.token); 135 | } 136 | } 137 | } 138 | } 139 | 140 | [AsyncMethodBuilder(typeof(AsyncSTaskMethodBuilder<>))] 141 | [StructLayout(LayoutKind.Auto)] 142 | public readonly struct STask 143 | { 144 | private readonly ISTaskSource source; 145 | private readonly T result; 146 | private readonly short token; 147 | 148 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 149 | public STask(T result) 150 | { 151 | this.source = default; 152 | this.token = default; 153 | this.result = result; 154 | } 155 | 156 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 157 | public STask(ISTaskSource source, short token) 158 | { 159 | this.source = source; 160 | this.token = token; 161 | this.result = default; 162 | } 163 | 164 | public STaskStatus Status 165 | { 166 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 167 | get 168 | { 169 | return (this.source == null) ? STaskStatus.Succeeded : this.source.GetStatus(this.token); 170 | } 171 | } 172 | 173 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 174 | public Awaiter GetAwaiter() 175 | { 176 | return new Awaiter(this); 177 | } 178 | 179 | public override string ToString() 180 | { 181 | return (this.source == null) ? this.result?.ToString() 182 | : "(" + this.source.UnsafeGetStatus() + ")"; 183 | } 184 | 185 | public readonly struct Awaiter : ICriticalNotifyCompletion 186 | { 187 | private readonly STask task; 188 | 189 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 190 | public Awaiter(in STask task) 191 | { 192 | this.task = task; 193 | } 194 | 195 | public bool IsCompleted 196 | { 197 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 198 | get 199 | { 200 | return this.task.Status.IsCompleted(); 201 | } 202 | } 203 | 204 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 205 | public T GetResult() 206 | { 207 | ISTaskSource source = this.task.source; 208 | if (source == null) 209 | { 210 | return this.task.result; 211 | } 212 | else 213 | { 214 | return source.GetResult(this.task.token); 215 | } 216 | } 217 | 218 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 219 | public void OnCompleted(Action continuation) 220 | { 221 | ISTaskSource source = this.task.source; 222 | if (source == null) 223 | { 224 | continuation(); 225 | } 226 | else 227 | { 228 | source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, this.task.token); 229 | } 230 | } 231 | 232 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 233 | public void UnsafeOnCompleted(Action continuation) 234 | { 235 | ISTaskSource source = this.task.source; 236 | if (source == null) 237 | { 238 | continuation(); 239 | } 240 | else 241 | { 242 | source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, this.task.token); 243 | } 244 | } 245 | 246 | /// 247 | /// 手动注册 continuation 的话,使用该方法替代 OnCompleted 248 | /// 249 | /// 250 | /// 251 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 252 | public void SourceOnCompleted(Action continuation, object state) 253 | { 254 | ISTaskSource source = this.task.source; 255 | if (source == null) 256 | { 257 | continuation(state); 258 | } 259 | else 260 | { 261 | source.OnCompleted(continuation, state, this.task.token); 262 | } 263 | } 264 | } 265 | } 266 | } -------------------------------------------------------------------------------- /STask/Assets/Plugins/STask/Runtime/PlayerLoopTimer.cs: -------------------------------------------------------------------------------- 1 | using SFramework.Threading.Tasks.Internal; 2 | using System; 3 | using System.Threading; 4 | using UnityEngine; 5 | 6 | namespace SFramework.Threading.Tasks 7 | { 8 | public abstract class PlayerLoopTimer : IDisposable, IPlayerLoopItem 9 | { 10 | private readonly CancellationToken cancellationToken; 11 | private readonly Action timerCallback; 12 | private readonly object state; 13 | private readonly PlayerLoopTiming playerLoopTiming; 14 | private readonly bool periodic; 15 | 16 | private bool isRunning; 17 | private bool tryStop; 18 | private bool isDisposed; 19 | 20 | protected PlayerLoopTimer(bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) 21 | { 22 | this.periodic = periodic; 23 | this.playerLoopTiming = playerLoopTiming; 24 | this.cancellationToken = cancellationToken; 25 | this.timerCallback = timerCallback; 26 | this.state = state; 27 | } 28 | 29 | public static PlayerLoopTimer Create(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) 30 | { 31 | #if UNITY_EDITOR 32 | //编辑器下强制使用RealTime 33 | if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying) 34 | { 35 | delayType = DelayType.RealTime; 36 | } 37 | #endif 38 | 39 | switch (delayType) 40 | { 41 | case DelayType.UnscaledDeltaTime: 42 | return new IgnoreTimeScalePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state); 43 | case DelayType.RealTime: 44 | return new RealtimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state); 45 | case DelayType.DeltaTime: 46 | default: 47 | return new DeltaTimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state); 48 | } 49 | } 50 | 51 | public static PlayerLoopTimer StartNew(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) 52 | { 53 | PlayerLoopTimer timer = Create(interval,periodic,delayType,playerLoopTiming, cancellationToken, timerCallback, state); 54 | timer.Restart(); 55 | return timer; 56 | } 57 | 58 | /// 59 | /// Restart(Reset and Start) timer 60 | /// 61 | /// 62 | public void Restart() 63 | { 64 | if (this.isDisposed) 65 | throw new ObjectDisposedException(null); 66 | 67 | this.ResetCore(null);//初始化 68 | if (!this.isRunning) 69 | { 70 | this.isRunning = true; 71 | PlayerLoopHelper.AddAction(this.playerLoopTiming, this); 72 | } 73 | this.tryStop = false; 74 | } 75 | 76 | /// 77 | /// Restart(Reset and Start) and change interval 78 | /// 79 | /// 80 | /// 81 | public void Restart(TimeSpan interval) 82 | { 83 | if(this.isDisposed) 84 | throw new ObjectDisposedException(null); 85 | 86 | this.ResetCore(interval);//初始化 87 | if (!this.isRunning) 88 | { 89 | this.isRunning = true; 90 | PlayerLoopHelper.AddAction(this.playerLoopTiming, this); 91 | } 92 | this.tryStop = false; 93 | } 94 | 95 | /// 96 | /// Stop timer 97 | /// 98 | public void Stop() 99 | { 100 | this.tryStop = true; 101 | } 102 | 103 | protected abstract void ResetCore(TimeSpan? newInterval); 104 | 105 | protected abstract bool MoveNextCore(); 106 | 107 | public void Dispose() 108 | { 109 | this.isDisposed = true; 110 | } 111 | 112 | bool IPlayerLoopItem.MoveNext() 113 | { 114 | if (this.isDisposed || this.tryStop || this.cancellationToken.IsCancellationRequested) 115 | { 116 | this.isRunning = false; 117 | return false; 118 | } 119 | 120 | if (!this.MoveNextCore())//迭代(计时)结束,调用回调 121 | { 122 | this.timerCallback(this.state); 123 | 124 | if (this.periodic) 125 | { 126 | //周期性计时器,重新计时 127 | this.ResetCore(null); 128 | return true; 129 | } 130 | else 131 | { 132 | //一次性计时器,生命周期结束 133 | this.isRunning = false; 134 | return false; 135 | } 136 | } 137 | 138 | return true; 139 | } 140 | } 141 | 142 | public sealed class DeltaTimePlayerLoopTimer : PlayerLoopTimer 143 | { 144 | private int initialFrame; 145 | private float elapsed; 146 | private float interval; 147 | 148 | public DeltaTimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) 149 | : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state) 150 | { 151 | this.ResetCore(interval); 152 | } 153 | 154 | protected override bool MoveNextCore() 155 | { 156 | if (this.elapsed == 0.0f) 157 | { 158 | if (this.initialFrame == Time.frameCount) 159 | { 160 | return true; 161 | } 162 | } 163 | 164 | this.elapsed += Time.deltaTime; 165 | if (this.elapsed >= this.interval) 166 | { 167 | return false; 168 | } 169 | 170 | return true; 171 | } 172 | 173 | protected override void ResetCore(TimeSpan? newInterval) 174 | { 175 | this.elapsed = 0.0f; 176 | this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; 177 | if (newInterval != null) 178 | { 179 | this.interval = (float)newInterval.Value.TotalSeconds; 180 | } 181 | } 182 | } 183 | 184 | public sealed class IgnoreTimeScalePlayerLoopTimer : PlayerLoopTimer 185 | { 186 | private int initialFrame; 187 | private float elapsed; 188 | private float interval; 189 | 190 | public IgnoreTimeScalePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) 191 | : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state) 192 | { 193 | this.ResetCore(interval); 194 | } 195 | 196 | protected override bool MoveNextCore() 197 | { 198 | if (this.elapsed == 0.0f) 199 | { 200 | if (this.initialFrame == Time.frameCount) 201 | { 202 | return true; 203 | } 204 | } 205 | 206 | this.elapsed += Time.unscaledDeltaTime; 207 | if (this.elapsed >= this.interval) 208 | { 209 | return false; 210 | } 211 | 212 | return true; 213 | } 214 | 215 | protected override void ResetCore(TimeSpan? newInterval) 216 | { 217 | this.elapsed = 0.0f; 218 | this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; 219 | if (newInterval != null) 220 | { 221 | this.interval = (float)newInterval.Value.TotalSeconds; 222 | } 223 | } 224 | } 225 | 226 | public sealed class RealtimePlayerLoopTimer : PlayerLoopTimer 227 | { 228 | private ValueStopwatch stopwatch; 229 | /// ticks in TimeSpan 230 | private long intervalTicks; 231 | 232 | public RealtimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) 233 | : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state) 234 | { 235 | this.ResetCore(interval); 236 | } 237 | 238 | protected override bool MoveNextCore() 239 | { 240 | if (this.stopwatch.ElapsedTicks >= this.intervalTicks) 241 | { 242 | return false; 243 | } 244 | 245 | return true; 246 | } 247 | 248 | protected override void ResetCore(TimeSpan? newInterval) 249 | { 250 | this.stopwatch = ValueStopwatch.StartNew(); 251 | if (newInterval != null) 252 | { 253 | this.intervalTicks = newInterval.Value.Ticks; 254 | } 255 | } 256 | } 257 | } --------------------------------------------------------------------------------