Compare commits

..

277 Commits
2.2.5 ... 2.5.9

Author SHA1 Message Date
github-actions[bot]
27a0c06ede feat: Update package.json to 2.5.9 2024-10-01 06:16:52 +00:00
neuecc
e4082ecd75 Merge remote-tracking branch 'origin/master' 2024-10-01 14:59:02 +09:00
neuecc
3b0fd784ff meta 2024-10-01 14:58:57 +09:00
neuecc
dc9ebfd765 Add AsyncInstantiateOperation.WithCancellation, ToUniTask for Unity 2022.3.20/Unity 2022.3 or newer 2024-10-01 14:50:13 +09:00
Yoshifumi Kawai
005c83fbd7 Merge pull request #623 from Cysharp/feature/ci
ci: remove Unity 2021 LTS from Build matrix
2024-10-01 10:44:30 +09:00
github-actions[bot]
5984b67ecb feat: Update package.json to 2.5.8 2024-09-30 11:45:57 +00:00
neuecc
05fdf48058 Merge remote-tracking branch 'origin/master' 2024-09-30 20:43:06 +09:00
Yoshifumi Kawai
647ed6ff82 Merge pull request #621 from dvsilch/master
add generic type UnityAction support & fix typo
2024-09-30 20:42:57 +09:00
neuecc
0826b7e976 Add UniTask.WhenEach 2024-09-30 20:42:17 +09:00
dvsilch
a51632cd4b fix: add overloads for CancellationToken 2024-09-30 10:13:29 +08:00
dvsilch
bf945a7ef4 fix: rename parameters and type parameters 2024-09-30 10:11:36 +08:00
dvsilch
353f15e94f fix: add .Forget() call and rename paramters to keep coding style consistent 2024-09-27 23:45:05 +08:00
dvsilch
cf19f18662 fix: typo 2024-09-27 22:57:36 +08:00
dvsilch
fdb9d1cf95 feature: add overload in UniTask.UnityAction to support generic type UnityAction 2024-09-27 22:57:05 +08:00
Yoshifumi Kawai
2e0917428b Merge pull request #620 from albermotion/master
Added a note for users using Unity 2023.1 or newer to prevent compilation error
2024-09-27 09:48:04 +09:00
Alberto
0b16005f4b Added a note for users using Unity 2023.1 or newer 2024-09-26 22:33:37 +02:00
github-actions[bot]
74bbe87b58 feat: Update package.json to 2.5.7 2024-09-26 06:24:48 +00:00
Yoshifumi Kawai
6f4131539b Merge pull request #619 from kochounoyume/add-state-argument
Add overload in UniTask.WaitUntil, UniTask.WaitWhile and UniTask.Defer
2024-09-26 12:52:56 +09:00
Kochoyume
06283f0ffb Add to the code that I forgot to write 2024-09-24 23:58:28 +09:00
Kochoyume
dfe5ee43c2 Add overload in UniTask.WaitUntil, UniTask.WaitWhile and UniTask.Defer to avoid closure allocation 2024-09-24 23:37:44 +09:00
Ikiru Yoshizaki
eaa553dc83 ci: remove Unity 2021 LTS from Build matrix 2024-09-24 18:30:54 +09:00
github-actions[bot]
83d8a2b424 feat: Update package.json to 2.5.6 2024-09-24 09:20:07 +00:00
Yoshifumi Kawai
4d204e4aa6 Update build-debug.yml 2024-09-24 17:49:34 +09:00
Yoshifumi Kawai
87e164e275 Merge pull request #600 from Iblis/textmeshpro_unity6_adoptions
TextMeshPro Unity6 adoptions
2024-09-24 17:16:20 +09:00
Yoshifumi Kawai
b63eb8d090 Merge pull request #610 from LucianoPC/forget-ignored-task
Forget ignored task
2024-09-24 17:14:40 +09:00
neuecc
75119acb50 Fix WaitWhile(bool cancelImmediately = true) does not work correctly
, and when cancelImmediately = true and canceled task remove Trakcking immediately
2024-09-24 17:12:50 +09:00
Ikiru Yoshizaki
f7b3c2fbe1 ci: update release unity version to 2022.3.39f1 [skip ci] 2024-09-18 17:06:00 +09:00
Ikiru Yoshizaki
b317ecfa01 ci: set max-parallel to restrict up to 2 run [skip ci] 2024-09-18 16:27:42 +09:00
Ikiru Yoshizaki
7b05569ef7 ci: single job 2024-09-18 16:27:42 +09:00
Luciano Prestes Cavalcanti
e0465c6c2c Forget ignored task 2024-08-19 08:18:57 -03:00
Yoshifumi Kawai
9057452c86 Merge pull request #607 from Redpenguine/master
fix: incorrect download progress reporting
2024-08-14 19:54:15 +09:00
Mykyta Myronenko
a2f6f84bde fix: incorrect download progress reporting 2024-08-10 19:29:54 +03:00
Ikiru Yoshizaki
f057abff0f chore: remove Unity UserSettigs from git handling 2024-07-31 16:11:03 +09:00
Ikiru Yoshizaki
c61a7d9961 Merge pull request #605 from Cysharp/dependabot/github_actions/peaceiris/actions-gh-pages-4
chore(deps): bump peaceiris/actions-gh-pages from 3 to 4
2024-07-30 17:09:56 +09:00
Ikiru Yoshizaki
9587f2eeec Merge pull request #606 from Cysharp/dependabot/github_actions/technote-space/toc-generator-4.3.1
chore(deps): bump technote-space/toc-generator from 2.4.0 to 4.3.1
2024-07-30 17:09:49 +09:00
Ikiru Yoshizaki
550784f31c ci: check not dependabot 2024-07-30 17:07:43 +09:00
Ikiru Yoshizaki
11b3282b3d ci: Don't allow dependabot to run Unity CI 2024-07-30 17:01:09 +09:00
dependabot[bot]
b2532b0798 chore(deps): bump technote-space/toc-generator from 2.4.0 to 4.3.1
Bumps [technote-space/toc-generator](https://github.com/technote-space/toc-generator) from 2.4.0 to 4.3.1.
- [Release notes](https://github.com/technote-space/toc-generator/releases)
- [Changelog](https://github.com/technote-space/toc-generator/blob/main/.releasegarc)
- [Commits](https://github.com/technote-space/toc-generator/compare/v2.4.0...v4.3.1)

---
updated-dependencies:
- dependency-name: technote-space/toc-generator
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-30 06:42:27 +00:00
dependabot[bot]
4fc41ecb17 chore(deps): bump peaceiris/actions-gh-pages from 3 to 4
Bumps [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages) from 3 to 4.
- [Release notes](https://github.com/peaceiris/actions-gh-pages/releases)
- [Changelog](https://github.com/peaceiris/actions-gh-pages/blob/main/CHANGELOG.md)
- [Commits](https://github.com/peaceiris/actions-gh-pages/compare/v3...v4)

---
updated-dependencies:
- dependency-name: peaceiris/actions-gh-pages
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-30 06:42:24 +00:00
Ikiru Yoshizaki
e52663cef6 Merge pull request #570 from Cysharp/ci/dependabot
ci: add depndabot.yaml to update github-actions
2024-07-30 15:41:57 +09:00
Ikiru Yoshizaki
1827be2de7 Merge pull request #603 from Cysharp/feature/test
ci: Change Unity UnitTest from Mono to IL2CPP and enabled on CI
2024-07-30 15:41:47 +09:00
Ikiru Yoshizaki
8560561ef3 chore: remove Layouts for Unity2022 2024-07-30 15:17:05 +09:00
Ikiru Yoshizaki
2019f1fa7f ci: update CI Unity 2024-07-30 15:16:54 +09:00
Ikiru Yoshizaki
9e2265d148 ci: split job for build and test 2024-07-30 14:46:59 +09:00
Ikiru Yoshizaki
9d02279822 ci: extend Unity Build timeout to 20m 2024-07-30 14:25:31 +09:00
Ikiru Yoshizaki
17ce06d93c chore: remove com.unity.ai.navigation as 2021.3.39f1 failed and not inuse 2024-07-30 14:07:59 +09:00
Ikiru Yoshizaki
7b810413fe fix: missing include Packages folder for Unity 2024-07-30 14:00:06 +09:00
Ikiru Yoshizaki
d78c0d6c02 ci: remove garbage folder 2024-07-30 12:36:34 +09:00
Ikiru Yoshizaki
d248acc7d1 chore: bump RuntimeUnitTestToolkit to 2.6.0 to adapt Unity 2022 Build API change 2024-07-30 12:34:46 +09:00
Ikiru Yoshizaki
4c0b1f753a chore: bump UniTask unity version to 2022.3.39f1 2024-07-24 20:11:26 +09:00
Ikiru Yoshizaki
7bb6feda55 chore: switch to src/UniTask/*.cproj 2024-07-24 20:10:17 +09:00
Ikiru Yoshizaki
f8a501290a chore: upload 2024-07-24 20:08:11 +09:00
Ikiru Yoshizaki
cb497c9eb5 ci: bump Unity version to LTS, Unity Unit Test with LTS. 2024-07-24 19:35:31 +09:00
Ikiru Yoshizaki
342a37a074 ci: add strategy.fail-fast: false 2024-07-24 17:44:49 +09:00
Ikiru Yoshizaki
c3146ec74f ci: change Unit Test to IL2CPP 2024-07-24 17:24:01 +09:00
Ikiru Yoshizaki
df16813fae ci: bump actions/checkout@v3 -> v4 2024-07-24 17:22:28 +09:00
Philipp Walser
8d98bbc7ba added version contraint, tmp is part of ugui since v2.0.0 2024-07-12 19:05:38 +02:00
Philipp Walser
bb095697f7 added versionDefine to set TMP support if ugui is found, too 2024-07-12 19:01:59 +02:00
github-actions[bot]
cdf88c6a6a feat: Update package.json to 2.5.5 2024-07-01 06:47:55 +00:00
Yoshifumi Kawai
4eee2c9270 Merge pull request #599 from xfvvvv/patch-1
Fix onTextSelection and onEndTextSelection stack overflow issue
2024-07-01 15:45:30 +09:00
Chelal
222b1401f5 Fix onTextSelection and onEndTextSelection stack overflow issue 2024-06-29 21:51:27 +08:00
Ikiru Yoshizaki
fbe0bf8515 Merge pull request #579 from Cysharp/feature/artifact
ci: change upload-artifact & download-artifact to Cysharp/Actions
2024-04-30 14:36:53 +09:00
Ikiru Yoshizaki
626685292c ci: set upload-artifact retention-period: 1 2024-04-30 14:06:49 +09:00
Ikiru Yoshizaki
67794f5cdd ci: change upload-artifact & download-artifact to Cysharp/Actions 2024-04-30 12:43:17 +09:00
Mayuki Sawatari
2e225fb841 Merge pull request #571 from Cysharp/feature/secret
feat: change load secret from op
2024-04-17 18:29:49 +09:00
Ikiru Yoshizaki
935523f25c feat: change load secret from op 2024-04-17 16:09:55 +09:00
Ikiru Yoshizaki
3b3f7ebd3e ci: add depndabot.yaml to update github-actions 2024-04-16 12:14:52 +09:00
Yoshifumi Kawai
88ecfa2992 Merge pull request #565 from divdeploy/master
chore: fix comment
2024-04-08 17:03:08 +09:00
divdeploy
aa70fe5c5a chore: fix comment
Signed-off-by: divdeploy <chenguangxue@outlook.com>
2024-04-05 23:28:56 +08:00
Yoshifumi Kawai
0c8057c668 Merge pull request #538 from kochounoyume/argument-allowed-factory
Factory method allowed argument
2024-04-05 13:30:39 +09:00
Kochoyume
28867646b0 Fix T state as the first argument 2024-03-31 00:05:18 +09:00
Kochoyume
ca60864021 Fix comment 2024-03-30 23:57:43 +09:00
Kochoyume
1e4561da22 Fix comment 2024-03-30 23:57:43 +09:00
Kochoyume
1496cc990a Fix misspelling 2024-03-30 23:57:43 +09:00
Kochoyume
7bb3bf8d0e Update UniTask.Create, Unitask.Action and UniTask.UnityAction 2024-03-30 23:57:43 +09:00
github-actions[bot]
d057074f17 feat: Update package.json to 2.5.4 2024-03-28 06:22:15 +00:00
hadashiA
b724a2aa84 Merge pull request #557 from Cysharp/hadashiA/fix-cancel-immediate
Fix unintended returning to pool with cancelImmediately
2024-03-28 15:21:40 +09:00
hadashiA
938ddd5356 Tweaks 2024-03-28 15:15:55 +09:00
hadashiA
911c37d4d8 Tweaks 2024-03-28 15:14:10 +09:00
hadashiA
caccccb0b5 Fix timing to returning to pool 2024-03-28 15:00:41 +09:00
hadashiA
a48f11d31b Fix unintended returning to pool with cancelImmediately (WaitUntil,etc) 2024-03-28 14:46:37 +09:00
hadashiA
fcd93feb56 Fix unintended returning to pool with cancelImmediately (AsyncOperation) 2024-03-28 14:45:55 +09:00
hadashiA
b472b23773 Fix unintended returning to pool with cancelImmediately (UniTask.Delay) 2024-03-28 14:29:30 +09:00
Yoshifumi Kawai
01c8fada1f Merge pull request #542 from Cysharp/feature/new_release
ci: Cysharp/Actions/.github/workflows/create-release.yaml
2024-03-25 18:30:50 +09:00
Ikiru Yoshizaki
10cd137126 ci: Cysharp/Actions/.github/workflows/create-release.yaml 2024-02-07 21:04:48 +09:00
Yoshifumi Kawai
809d23edae Merge pull request #541 from TORISOUP/fix_ToArray
Optimization of ToArray in Merge method
2024-02-04 23:19:47 +09:00
TORISOUP
d38731bc44 fix call ToArray 2024-02-04 20:51:21 +09:00
github-actions[bot]
64792b672d feat: Update package.json to 2.5.3 2024-01-25 12:52:16 +00:00
neuecc
3892cc2299 Merge branch 'master' of https://github.com/Cysharp/UniTask 2024-01-25 21:51:45 +09:00
neuecc
5bfccaa3b6 autoReleaseWhenCancelled -> autoReleaseWhenCanceled 2024-01-25 21:51:40 +09:00
github-actions[bot]
b49b7332bb feat: Update package.json to 2.5.2 2024-01-25 11:43:24 +00:00
neuecc
08184af737 simplify UNITASK define 2024-01-25 20:42:42 +09:00
Yoshifumi Kawai
0ef6c59385 Merge pull request #535 from kochounoyume/valuetask-error-netframework
UniTask does not work in .NET Framework environment after adding UniTask.AsValueTask
2024-01-25 20:26:21 +09:00
Yoshifumi Kawai
4b0bd3b509 Merge pull request #536 from Cysharp/hadashiA/release-handle
Fix "Release handle when cancellation is requested"
2024-01-25 20:26:13 +09:00
Kochoyume
9a4720d180 Fix:Addressed generic parameter attributes error in the .Net Framework 2024-01-25 20:05:45 +09:00
hadashiA
b99646558c Add a flag autoReleaseWhenCancelled to addressable extensionhs 2024-01-25 19:03:00 +09:00
hadashiA
ee12dd9ae7 Fix omissions in Addressable.Release and IsValid checks 2024-01-25 17:47:06 +09:00
Kochoyume
006e0f2c81 Revert "Fix conditional compilation to work with .NET Framework"
This reverts commit 7d31299b5c.
2024-01-25 16:16:01 +09:00
Kochoyume
7d31299b5c Fix conditional compilation to work with .NET Framework 2024-01-25 01:02:57 +09:00
Yoshifumi Kawai
fe8bf834e6 Update README.md 2024-01-24 10:47:31 +09:00
github-actions[bot]
5843258e8c feat: Update package.json to 2.5.1 2024-01-24 01:44:21 +00:00
Yoshifumi Kawai
6cd002645e Merge pull request #533 from doyasu24/feature/add-unitask-asvaluetask-for-unity
add UniTask.AsValueTask for Unity
2024-01-24 10:41:39 +09:00
doyasu24
4fe0861714 fix: use UNITY_2018_3_OR_NEWER instead of UNITY_2018_1_OR_NEWER 2024-01-19 23:42:17 +09:00
doyasu24
fbbba061dd ValueTask is available in Unity 2021_2_OR_NEWER or .NET Core 2024-01-19 23:40:28 +09:00
doyasu24
81f2e37ea5 add UniTask.AsValueTask for Unity 2024-01-19 00:29:21 +09:00
Yoshifumi Kawai
66de0d3a58 Merge pull request #519 from Cysharp/guitarrapc-patch-1
Use Cysharp/Actions/setup-dotnet default version
2024-01-12 15:34:54 +09:00
Yoshifumi Kawai
beb10abbf7 Merge pull request #524 from Saismirk/master
Fixed typo in TimeoutWithoutException summary.
2024-01-12 15:22:35 +09:00
Saismirk
d60f64761b Fixed typo in TimeoutWithoutException summary. 2023-12-10 12:53:52 -05:00
Luciano Prestes Cavalcanti
36ac0863ad Release handle when cancellation is requested 2023-11-22 08:09:03 -03:00
Ikiru Yoshizaki
104f8e09ca Update build-release.yml 2023-11-15 12:09:34 +09:00
Ikiru Yoshizaki
cfbff008c4 Use Cysharp/Actions/setup-dotnet default version
## tl;dr;

It support both .NET 6,7 and 8. No need specify version.
2023-11-15 11:55:27 +09:00
Yoshifumi Kawai
5cc97c7f00 ReadMe 2023-11-02 18:23:43 +09:00
github-actions[bot]
5666292496 feat: Update package.json to 2.5.0 2023-11-02 05:03:47 +00:00
hadashiA
1288cbc128 Merge pull request #518 from Cysharp/hadashiA/awaitable-to-unitask
Add Awaitable.AsUniTask()
2023-11-02 14:02:36 +09:00
hadashiA
5f3aa18f38 Add Awaitable<T>.ToUniTask 2023-11-02 13:54:55 +09:00
hadashiA
0970ae8c31 Merge pull request #517 from Cysharp/hadashiA/cancel-immediately-flag
Add a flag to cancel immediately instead of player loop
2023-11-02 13:52:12 +09:00
hadashiA
ad23f7fb29 Fix #if directive that should be in .tt 2023-11-02 12:54:59 +09:00
hadashiA
a4be8f316e Add Awaitable.AsUniTask() 2023-11-02 12:35:05 +09:00
hadashiA
370425578f Fix AssetBundleRequestAll 2023-11-02 12:24:41 +09:00
hadashiA
1b76f77608 Add test 2023-11-02 12:24:41 +09:00
hadashiA
0579984355 Use AsyncOperation.completed callback usually 2023-11-02 12:24:41 +09:00
hadashiA
39cf81d2ab Add test for unity AsyncOperation 2023-11-02 12:24:41 +09:00
hadashiA
0a203c8db9 Cache Action in advance 2023-11-02 12:24:41 +09:00
hadashiA
55be4dba82 Add callback handler to AsyncOperationConfiguredSource instead to create other sources 2023-11-02 12:24:41 +09:00
hadashiA
f0adf36633 Use AsyncOperation.completed handler with new optional argument 2023-11-02 12:24:41 +09:00
hadashiA
24afc4f3eb Add cancelImmediately flag for assetbundle extensions 2023-11-02 12:24:41 +09:00
hadashiA
2cf06af433 Change AsyncEnumerable factory to use OperationCanceledException 2023-11-02 12:24:36 +09:00
hadashiA
94be2e748b Add cancelImmediately flag for addressable extensions 2023-10-27 15:06:12 +09:00
hadashiA
7f582e5e29 Update README 2023-10-27 14:52:58 +09:00
hadashiA
3f042c8886 Add cancel immediate flag 2023-10-27 12:42:12 +09:00
Yoshifumi Kawai
6f5d818544 Merge pull request #515 from ananttheant/fix/readme-typo
Fix typo in README.md
2023-10-26 13:11:42 +09:00
Anant Sharma
2ccb37cb02 Fix typo in README.md 2023-10-25 15:24:27 +01:00
github-actions[bot]
cfe509a556 feat: Update package.json to 2.4.1 2023-09-21 03:22:58 +00:00
hadashiA
a46a4cac01 Merge pull request #509 from Cysharp/ku/fix-dotween-registration
Fix a bug in Dotween after returning to the pool of `CancellationToken.Register`
2023-09-21 12:20:43 +09:00
hadashiA
3ed28e534a Tweaks 2023-09-21 10:00:27 +09:00
hadashiA
be8dbe8804 Fixed a bug in Dotween after returning to the pool of CancellationToken.Register 2023-09-20 17:35:04 +09:00
github-actions[bot]
64f7eec4e9 feat: Update package.json to 2.4.0 2023-09-14 07:43:41 +00:00
hadashiA
3a93f4a49f Update README.md 2023-09-14 16:40:42 +09:00
hadashiA
71958adc3d Merge pull request #498 from Cysharp/hadashiA/async-linq-merge
Add UniTaskAsyncEnumerable.Merge
2023-09-14 16:28:05 +09:00
hadashiA
acc71550c9 Merge pull request #496 from Cysharp/hadashiA/awaitable
Add EndOfFrame implementation using `UnityEngine.Awaitable`
2023-09-14 16:26:40 +09:00
hadashiA
3ba64412f8 Reduce the lock 2023-09-14 16:26:13 +09:00
hadashiA
90c5e5a6ad Merge pull request #500 from Cysharp/hadashiA/inner-ex2
Use always innerException for Task.AsUniTask
2023-09-14 16:22:09 +09:00
hadashiA
8a022ee02d Merge pull request #499 from Cysharp/hadashiA/fix-completion-source-retval
Fix conditions for UniTaskCompletionSourceCore.TrySet* to be true
2023-09-14 16:12:32 +09:00
hadashiA
6a89ea8139 Merge pull request #503 from Cysharp/hadashiA/fix-auto-reset-source
Add check to that AutoResetUniTaskSource already returned to the pool
2023-09-14 16:10:42 +09:00
hadashiA
90c81613ac Add check to that innerException is empty 2023-09-14 16:08:32 +09:00
hadashiA
7c62904a74 Merge pull request #489 from Merglasch/EarlyInit
Earlier intialization for Unitask, depending on unity version
2023-09-14 15:43:34 +09:00
hadashiA
4f6344a12f Add check to AutoResetUniTaskSource already returned to the pool 2023-09-14 10:36:31 +09:00
hadashiA
937d3adf66 Fix race condition 2023-09-12 14:34:53 +09:00
hadashiA
3bac16229f Reduce lock 2023-09-11 00:22:21 +09:00
hadashiA
ea57847c97 Add dispose 2023-09-09 17:04:02 +09:00
hadashiA
730d68132d Tweaks 2023-09-09 14:27:06 +09:00
hadashiA
6db872236e Fix test 2023-09-09 10:16:01 +09:00
hadashiA
ba7e676c6f Fix test 2023-09-09 10:01:58 +09:00
hadashiA
6e99accf99 Fix race condition (todo: too wide lock range?) 2023-09-09 08:49:52 +09:00
hadashiA
b195df9773 Update README 2023-09-08 20:06:02 +09:00
hadashiA
f303d9d7e8 Add UniTaskAsyncEnumerable.Merge 2023-09-08 20:05:51 +09:00
hadashiA
62a2a2e8f9 Use always innerException for Task.AsUniTask 2023-09-08 18:43:41 +09:00
hadashiA
ffbadbcc4c Update README about WaitForEndOfFrame 2023-09-08 18:00:39 +09:00
hadashiA
50ad2ee9d6 Fix conditions for UniTaskCompletionSourceCore.TrySet* to be true 2023-09-08 17:31:19 +09:00
hadashiA
c170af5642 Merge pull request #487 from Cysharp/hadashiA/fix-test
Fix TriggerEvent problem with iterate breaking on Remove when it has multiple handlers
2023-09-08 17:22:16 +09:00
hadashiA
242bceecd3 Merge pull request #492 from Cysharp/hadashiA/readme
Update README about DOTween
2023-09-08 17:19:30 +09:00
hadashiA
06346b8a2a Merge pull request #493 from Cysharp/hadashiA/monitor
Reduce the times of AwakeMonitor checking
2023-09-08 17:18:50 +09:00
hadashiA
b071eeadfb Merge pull request #486 from Cysharp/hadashiA/inner-ex
Use innerException for `Task.AsUniTask`
2023-09-08 17:17:28 +09:00
hadashiA
e7f23d8328 Merge pull request #497 from Cysharp/hadashiA/net6
Use dotnet >= 6.0
2023-09-08 17:16:36 +09:00
hadashiA
47a3f09abf Merge pull request #485 from Cysharp/hadashiA/fix-dotween
Fix a problem in dotween where an extra update would run after canceling
2023-09-08 17:16:20 +09:00
hadashiA
a7a6af0a68 Fix AwakeMonitor to not duplicates 2023-09-08 09:36:42 +09:00
hadashiA
f203b6c051 Merge pull request #494 from Cysharp/hadashiA/web-req-null-check
Add check if UnityWebRequest was destroyed
2023-09-07 18:13:46 +09:00
hadashiA
07211f1fc3 Bump dotnet version to 6.0/7.0 2023-09-07 18:12:47 +09:00
hadashiA
bc27f6c0d8 Fix test 2023-09-07 17:43:40 +09:00
hadashiA
c65f9c3497 Add EndOfFrame implementation using UnityEngine.Awaitable 2023-09-07 17:36:06 +09:00
hadashiA
afe5f57adc Use CancellationToken.Register to cancel DOTWeen 2023-09-07 17:05:11 +09:00
hadashiA
9135c7ce56 Add check if UnityWebRequest was destroyed 2023-09-07 10:35:48 +09:00
hadashiA
7fae415689 Reduce the times of AwakeMonitor checking 2023-09-07 10:03:55 +09:00
hadashiA
e5cc8667ac docs: update TOC 2023-09-07 00:58:51 +00:00
hadashiA
0ea18d0e16 Update README about DOTween 2023-09-07 09:58:00 +09:00
hadashiA
2d674999f0 Use InnerException when only be one 2023-09-07 09:11:47 +09:00
David Klein
3121903fa3 Earlier intialization for Unitask, depending on unity version 2023-09-04 11:00:50 +02:00
hadashiA
af2e49aa29 Fix TriggerEvent.SetCancel 2023-09-03 20:40:04 +09:00
hadashiA
22940635fe Fix TriggerEvent problem with iterate breaking on Remove when it has multiple handlers 2023-09-02 22:26:09 +09:00
hadashiA
c1042b32b7 Merge pull request #488 from Cysharp/revert-445-fix-wait-async
Revert "Fixed https://github.com/Cysharp/UniTask/issues/444"
2023-09-01 20:08:55 +09:00
hadashiA
29a144694d Revert "Fixed https://github.com/Cysharp/UniTask/issues/444" 2023-09-01 19:52:22 +09:00
hadashiA
548d56e654 Merge pull request #445 from faveris/fix-wait-async
Fixed https://github.com/Cysharp/UniTask/issues/444
2023-09-01 17:06:31 +09:00
hadashiA
6fb4f2d6d2 Support exception unwrapping for AsUniTask of Task.WhenAll 2023-09-01 16:58:11 +09:00
hadashiA
8eac07ad24 Use innerException for Task.AsUniTask 2023-09-01 10:49:43 +09:00
hadashiA
716402a180 Fix a problem in dotween where an extra update would run after canceling 2023-08-31 19:22:17 +09:00
hadashiA
4c3d6938ed Merge pull request #484 from Cysharp/hadashiA/fix-async-enumerable
Fix problem with finally in UniTaskAsyncEnumerable.Create not being executed
2023-08-31 19:17:31 +09:00
hadashiA
b4486802f2 Fix problem with part of await foreach not executing on break 2023-08-31 12:42:53 +09:00
Yoshifumi Kawai
d210e3d76a Merge pull request #457 from sgaumin/wait-for-seconds
Add WaitForSeconds method declarations #371
2023-06-23 19:04:48 +09:00
Ikiru Yoshizaki
f2773f585e Revert "Revert "Merge pull request #459 from Cysharp/feature/prevent""
This reverts commit 305695ad5d.
2023-05-08 12:22:51 +09:00
Ikiru Yoshizaki
305695ad5d Revert "Merge pull request #459 from Cysharp/feature/prevent"
This reverts commit 356a4ee62e.
2023-04-26 14:14:51 +09:00
Ikiru Yoshizaki
418ab36a72 Merge pull request #460 from Cysharp/feature/unity
chore: change unity build to cysharp actions
2023-04-26 12:35:55 +09:00
Ikiru Yoshizaki
563b4fbbd5 chore: remove license 2023-04-25 19:48:54 +09:00
Ikiru Yoshizaki
878d33115f chore: change unity build to cysharp actions 2023-04-25 19:39:40 +09:00
Ikiru Yoshizaki
356a4ee62e Merge pull request #459 from Cysharp/feature/prevent
chote: prevent github workflow change
2023-04-25 18:50:19 +09:00
Ikiru Yoshizaki
eb32ae25e0 chote: prevent github workflow change 2023-04-25 16:56:50 +09:00
Sébastien Gaumin
3ca4062536 Add WaitForSeconds method declarations #371 2023-04-07 00:33:31 +09:00
Artem Kolesnykov
019f8aaf30 Deleted preserveRemoveSelf because Remove() should always remove a trigger for pooling to work correctly 2023-02-12 17:33:19 +02:00
Artem Kolesnykov
663fa737f3 Added a test case for https://github.com/Cysharp/UniTask/issues/444 2023-02-12 17:33:19 +02:00
Yoshifumi Kawai
73d86259ce f 2022-12-26 06:02:57 +09:00
Yoshifumi Kawai
c7eedf85c7 Merge pull request #421 from ivribalko/master
fixed typo in README.md (AysncLocal)
2022-11-21 12:48:07 +09:00
Ivan Rybalko
8dc3ffd552 fixed typo (AysncLocal) 2022-11-10 20:28:07 +00:00
github-actions[bot]
b992a061fb feat: Update package.json to 2.3.3 2022-11-01 11:41:05 +00:00
neuecc
4fc09a6f61 more 2022-11-01 20:40:24 +09:00
neuecc
e57176a43c Merge remote-tracking branch 'origin/master' 2022-11-01 20:39:37 +09:00
Yoshifumi Kawai
710d0d9012 Merge pull request #418 from adarapata/fix-asyncenumerable-cancel
Fix UnityEventHandlerAsyncEnumerator cancellation
2022-11-01 20:39:22 +09:00
neuecc
039de3ef65 Text -> UnityEngine.UI.Text #401 2022-11-01 20:33:24 +09:00
imo
de38f63a55 Token was incorrectly specified. 2022-11-01 20:12:55 +09:00
Yoshifumi Kawai
38f8193199 Update README.md 2022-10-25 13:51:57 +09:00
neuecc
15cffb7357 docs: update TOC 2022-10-25 04:50:13 +00:00
Yoshifumi Kawai
d55748e05b Merge pull request #374 from wqaetly/readme_cn
doc:provide simple chinese readme
2022-10-25 13:50:01 +09:00
NKG丶MadLife
5602861dd4 Update README_CN.md 2022-10-25 12:10:28 +08:00
github-actions[bot]
d2245bc38b feat: Update package.json to 2.3.2 2022-10-24 12:59:01 +00:00
neuecc
f092f6a112 Fix AwaitForAllAssets stackoverflow #394 2022-10-24 21:57:42 +09:00
neuecc
ed617a04a6 if UNITY_2022_2_OR_NEWER, use destroyCancellationToken 2022-10-24 21:56:03 +09:00
neuecc
340736795c UnityEvent.AsAsyncEnumerable handle cancel correctly #365 2022-10-24 21:51:23 +09:00
neuecc
dc804ffb13 breaking changes, UniTask.WaitForFixedUpdate wait at LastFixedUpdate #377 2022-10-24 21:18:36 +09:00
neuecc
a879989d1c Unity 2023.1.0a15, remove AsyncOperation.GetAwaiter to avoid conflict 2022-10-24 21:11:49 +09:00
Yoshifumi Kawai
ee54559532 Merge pull request #413 from battleroy/battleroy/observable-extension-cancellation-token-forwarding
Fix cancellation token forwarding
2022-10-12 10:53:30 +09:00
Evgeny Chasovitin
4a72ec2a1a Fix cancellation token forwarding at FirstValueToUniTaskObserver and ToUniTaskObserver; 2022-10-11 23:01:19 +04:00
Yoshifumi Kawai
e999268305 Merge pull request #395 from kroonhorstdino/diagnostics_helper_null_check
Diagnostics helper null check
2022-09-30 18:49:10 +09:00
Yoshifumi Kawai
8300c1b1e6 Merge pull request #399 from shiena/fix/prevent-nre
fix: prevent NullReferenceException in TimeoutController
2022-09-30 18:04:57 +09:00
KOGA Mitsuhiro
daa0c7b9a0 fix: prevent NullReferenceException in TimeoutController 2022-09-14 02:56:06 +09:00
KOGA Mitsuhiro
9b9a4ec76a fix: prevent NullReferenceException in TimeoutController 2022-09-08 15:12:05 +09:00
Christoph Hüter
3f8e43b83f Remove empty line with spaces 2022-08-31 03:00:22 +02:00
Christoph Hüter
cf6f0799e9 Remove spaces in empty line 2022-08-25 13:51:44 +02:00
Christoph Hüter
91ba4f003a Add null checks to diagnostics helper functions 2022-08-25 13:48:52 +02:00
Yoshifumi Kawai
f48cb4b03e Merge pull request #392 from Ryuu-64/master
Typo in TaskPool.cs annotation internaly -> internally
2022-08-23 10:38:44 +09:00
DESKTOP-FQ830JM\Ryuu
70a243d978 typo in TaskPool.cs internaly -> internally 2022-08-22 12:20:52 +08:00
Yoshifumi Kawai
9b95f3b9f6 Merge pull request #385 from fpagyu/support-addressablesCN
re-define UNITASK_ADDRESSABLE_SUPPORT for supporting Addressables.CN
2022-08-02 10:46:39 +09:00
yuzj
a25adb601b re-define UNITASK_ADDRESSABLE_SUPPORT for supporting Addressables.CN 2022-08-01 18:21:04 +08:00
Ikiru Yoshizaki
e6240879c4 chore: checkout@v3 2022-07-26 15:34:50 +09:00
Ikiru Yoshizaki
a94e8cceac Merge pull request #381 from Cysharp/feature/actions
feat: use Cysharp/Actions reusable workflows/actions
2022-07-26 13:59:46 +09:00
Ikiru Yoshizaki
0595a4182a feat: use Cysharp/Actions for release 2022-07-26 13:10:40 +09:00
Ikiru Yoshizaki
df96c119c1 chore: set timeout 2022-07-26 13:10:32 +09:00
Ikiru Yoshizaki
534f4a2588 chore: use Cysharp/Actions reusable workflow stale 2022-07-26 13:10:22 +09:00
Ikiru Yoshizaki
873485ad1a chore: IsPackable marking 2022-07-26 13:10:10 +09:00
NKG丶MadLife
f6037d6c9b doc:provide simple chinese readme 2022-07-16 10:02:16 +08:00
Yoshifumi Kawai
78db78c7bd Merge pull request #369 from nolimet/bugfix/issue#368
Fix for issue #368 UnityWebRequestException extra line in exception message
2022-06-23 17:46:29 +09:00
Jesse Stam
226e272787 Added simple check to see if there is text.
Add this so we don't add a new line we don't need.
2022-06-23 09:31:05 +02:00
neuecc
9e2163616b Merge remote-tracking branch 'origin/master' 2022-03-03 08:14:22 +09:00
neuecc
52df6fbf3f t 2022-03-03 08:14:18 +09:00
github-actions[bot]
33d32baea4 feat: Update package.json to 2.3.1 2022-03-02 23:02:44 +00:00
neuecc
b0250cfe75 Merge remote-tracking branch 'origin/master' 2022-03-03 08:02:10 +09:00
neuecc
7a35f121cd build and analyzer 2022-03-03 08:02:06 +09:00
github-actions[bot]
79f1566fdb feat: Update package.json to 2.3.0 2022-03-02 22:56:07 +00:00
neuecc
364b67805d test ignore 2022-03-03 07:53:14 +09:00
neuecc
62ca0c6e92 Fix IObservable.ToUniTask does not propagate unobserved exception 2022-03-03 07:40:28 +09:00
neuecc
f63212aa17 ReadMe more 2022-03-03 07:34:49 +09:00
neuecc
768fd16e60 UniTask,Run obsolete 2022-03-03 07:32:15 +09:00
neuecc
3c99010ba0 Add UniTask.WaitForEndOfFrame(MonoBehaviour), Obsolete no args. 2022-03-03 07:22:58 +09:00
neuecc
5c668717d8 Run DelayFrame on UnityEditor 2022-03-03 06:23:34 +09:00
Yoshifumi Kawai
b089f74c65 Merge pull request #323 from SolidAlloy/throw-exception-fix
Fix exceptions never being reported when UniTask is executed without await and Forget()
2022-03-03 06:04:55 +09:00
Yoshifumi Kawai
fcf4f21cc1 Merge pull request #300 from satanabe1/fix-bad_image_format_exception
Fix BadImageFormatException when StackTrace captured on UniTaskTracker
2022-03-03 05:34:07 +09:00
Yoshifumi Kawai
ee2fd3e91d Merge pull request #280 from yellowisher/master
[DoTween]: fix "AwaitFor~" extensions ignore original callback
2022-03-03 05:31:33 +09:00
Yoshifumi Kawai
27604496ca Merge pull request #327 from cjaligaga/patch-1
Update README.md
2022-02-08 10:42:27 +09:00
cjaligaga
0d01034a57 Update README.md
grammar correction to avoid confusion
2021-11-09 13:00:26 +08:00
neuecc
50a67d8f41 r 2021-10-26 19:48:28 +09:00
Yoshifumi Kawai
2a23a85cdd Update README.md 2021-10-26 00:31:02 +09:00
Yoshifumi Kawai
e127d9976e Update README.md 2021-10-25 22:51:58 +09:00
Artem Perepelitsa
c31b78e45e Add a unit test to verify that an unawaited task reports exceptions 2021-10-16 12:18:52 +03:00
Artem Perepelitsa
b6b0b4000d Add unobserved task exception publishing if an exception inside ExceptionResultSource is never thrown 2021-10-16 11:55:30 +03:00
neuecc
69be818a46 AnalyzeSymbol -> AnalyzeOperation 2021-08-27 16:51:39 +09:00
neuecc
a1dee8b54f add experimental analyzer 2021-08-27 16:44:05 +09:00
Yoshifumi Kawai
4f6166102d Merge pull request #285 from Cysharp/chore/xml
chore: add intellisense xml to nuget
2021-07-27 06:26:56 +09:00
Yoshifumi Kawai
6b1d2c231a Merge pull request #284 from Cysharp/chore/setup_dotnet
chore: remove setup-dotnet
2021-07-27 06:26:47 +09:00
watanabe_satoshi
0715dd31bf fix BadImageFormatException 2021-07-05 18:41:31 +09:00
Ikiru Yoshizaki
26dbfa3655 chore: add intellisense xml to nuget 2021-05-24 14:38:36 +09:00
Ikiru Yoshizaki
6ac55e37a1 chore: remove setup-dotnet 2021-05-24 11:01:36 +09:00
Yoshifumi Kawai
60bfbae787 Update package.json 2021-05-11 10:07:23 +09:00
yellowisher
fc9ddeb15c Fix typo 2021-05-08 14:40:02 +09:00
yellowisher
dfe18d11ff [DoTween]: call original complete callback as well 2021-05-08 14:39:26 +09:00
Yoshifumi Kawai
958a8e11ab Merge pull request #266 from oktomus/patch-1
Fix wording and code instructions for -batchmode usage
2021-04-21 16:51:30 +09:00
Kevin Masson
257186313b Fix wording and code instructions for -batchmode usage
`Environment.Exit(0)` didn't work for me, the process was still running. `EditorApplication.Exit(0);` works and kills the `Unity Editor` process correctly.
2021-04-20 14:31:16 +02:00
Ikiru Yoshizaki
5bd508b31c shore: skip ci supported by default 2021-04-19 18:47:10 +09:00
Yoshifumi Kawai
9e18ba332e Update README.md 2021-04-18 11:26:35 +09:00
Yoshifumi Kawai
946b9003f0 Update README.md 2021-04-13 19:03:58 +09:00
Yoshifumi Kawai
ffa55becf3 Update README.md 2021-04-13 14:09:32 +09:00
101 changed files with 6169 additions and 4562 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: [neuecc]

7
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,7 @@
# ref: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly" # Check for updates to GitHub Actions every week

View File

@@ -4,83 +4,85 @@ on:
push:
branches:
- "master"
tags:
- "!*" # not a tag push
pull_request:
branches:
- "master"
jobs:
build-dotnet:
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
timeout-minutes: 10
steps:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.x
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
- uses: actions/checkout@v4
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- run: dotnet build -c Debug
- run: dotnet test -c Debug
build-unity:
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]')) && ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
if: ${{ ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')) && github.triggering_actor != 'dependabot[bot]' }}
strategy:
fail-fast: false
max-parallel: 2
matrix:
unity: ["2019.3.9f1", "2019.4.13f1", "2020.1.12f1"]
include:
- unity: 2019.3.9f1
license: UNITY_LICENSE_2019
- unity: 2019.4.13f1
license: UNITY_LICENSE_2019
- unity: 2020.1.12f1
license: UNITY_LICENSE_2020
unity: ["2022.3.39f1", "6000.0.12f1"] # Test with LTS
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v2
# Execute scripts: RuntimeUnitTestToolkit
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend mono /BuildTarget StandaloneLinux64
- name: Build UnitTest(Linux64, mono)
uses: game-ci/unity-builder@v2.0-alpha-6
env:
UNITY_LICENSE: ${{ secrets[matrix.license] }}
- name: Load secrets
id: op-load-secret
uses: 1password/load-secrets-action@v2
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: UnitTestBuilder.BuildUnitTest
customParameters: /headless /ScriptBackend mono
versioning: None
- name: Execute UnitTest
run: ./src/UniTask/bin/UnitTest/StandaloneLinux64_Mono2x/test
export-env: false
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
UNITY_EMAIL: "op://GitHubActionsPublic/UNITY_LICENSE/username"
UNITY_PASSWORD: "op://GitHubActionsPublic/UNITY_LICENSE/credential"
UNITY_SERIAL: "op://GitHubActionsPublic/UNITY_LICENSE/serial"
- uses: actions/checkout@v4
# Execute scripts: Export Package
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- name: Export unitypackage
uses: game-ci/unity-builder@v2.0-alpha-6
- name: Build Unity (.unitypacakge)
if: ${{ startsWith(matrix.unity, '2022') }} # only execute once
uses: Cysharp/Actions/.github/actions/unity-builder@main
env:
UNITY_LICENSE: ${{ secrets[matrix.license] }}
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: PackageExporter.Export
versioning: None
- name: check all .meta is commited
run: |
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
exit 1
else
echo "Great, all .meta files are commited."
fi
working-directory: src/UniTask
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
with:
directory: src/UniTask
# Execute UnitTest
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod UnitTestBuilder.BuildUnitTest /headless /ScriptBackend IL2CPP /BuildTarget StandaloneLinux64
- name: Build UnitTest (IL2CPP)
uses: Cysharp/Actions/.github/actions/unity-builder@main
env:
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: UnitTestBuilder.BuildUnitTest
customParameters: "/headless /ScriptBackend IL2CPP"
- name: Check UnitTest file is generated
run: ls -lR ./src/UniTask/bin/UnitTest
- name: Execute UnitTest
run: ./src/UniTask/bin/UnitTest/StandaloneLinux64_IL2CPP/test
# Store artifacts.
- uses: actions/upload-artifact@v2
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
if: ${{ startsWith(matrix.unity, '2021') }} # only execute 2021
with:
name: UniTask.unitypackage-${{ matrix.unity }}.zip
path: ./src/UniTask/*.unitypackage
retention-days: 1

View File

@@ -8,11 +8,11 @@ on:
jobs:
run-docfx:
if: "!(contains(github.event.head_commit.message, '[skip ci]') || contains(github.event.head_commit.message, '[ci skip]'))"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: Cysharp/DocfxTemplate
path: docs/_DocfxTemplate
@@ -25,7 +25,7 @@ jobs:
with:
args: build docs/docfx.json
- name: Publish to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/_site
publish_dir: docs/_site

View File

@@ -6,187 +6,105 @@ on:
tag:
description: "tag: git tag you want create. (sample 1.0.0)"
required: true
dry_run:
description: "dry_run: true will never create relase/nuget."
dry-run:
description: "dry-run: true will never create relase/nuget."
required: true
default: "false"
env:
GIT_TAG: ${{ github.event.inputs.tag }}
DRY_RUN: ${{ github.event.inputs.dry_run }}
DRY_RUN_BRANCH_PREFIX: "test_release"
DOTNET_SDK_VERISON_3: 3.1.x
default: false
type: boolean
jobs:
update-packagejson:
runs-on: ubuntu-latest
env:
TARGET_FILE: ./src/UniTask/Assets/Plugins/UniTask/package.json
outputs:
sha: ${{ steps.commit.outputs.sha }}
steps:
- uses: actions/checkout@v2
- name: Output package.json (Before)
run: cat ${{ env.TARGET_FILE}}
- name: Update package.json to version ${{ env.GIT_TAG }}
run: sed -i -e "s/\(\"version\":\) \"\(.*\)\",/\1 \"${{ env.GIT_TAG }}\",/" ${{ env.TARGET_FILE }}
- name: Check update
id: check_update
run: |
cat ${{ env.TARGET_FILE}}
git diff --exit-code || echo "::set-output name=changed::1"
- name: Commit files
id: commit
if: steps.check_update.outputs.changed == '1'
run: |
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git commit -m "feat: Update package.json to ${{ env.GIT_TAG }}" -a
echo "::set-output name=sha::$(git rev-parse HEAD)"
- name: Check sha
run: echo "SHA ${SHA}"
env:
SHA: ${{ steps.commit.outputs.sha }}
- name: Create Tag
if: steps.check_update.outputs.changed == '1'
run: git tag ${{ env.GIT_TAG }}
- name: Push changes
if: env.DRY_RUN == 'false' && steps.check_update.outputs.changed == '1'
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
tags: true
- name: Push changes (dry_run)
if: env.DRY_RUN == 'true' && steps.check_update.outputs.changed == '1'
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
tags: false
uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
with:
file-path: ./src/UniTask/Assets/Plugins/UniTask/package.json
tag: ${{ inputs.tag }}
dry-run: ${{ inputs.dry-run }}
build-dotnet:
needs: [update-packagejson]
runs-on: ubuntu-latest
timeout-minutes: 10
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
steps:
- run: echo ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
ref: ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/setup-dotnet@v1
with:
dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
# build and pack
- run: dotnet build -c Release -p:Version=${{ env.GIT_TAG }}
- run: dotnet build -c Release -p:Version=${{ inputs.tag }}
- run: dotnet test -c Release --no-build
- run: dotnet pack ./src/UniTask.NetCore/UniTask.NetCore.csproj -c Release --no-build -p:Version=${{ env.GIT_TAG }} -o ./publish
- run: dotnet pack ./src/UniTask.NetCore/UniTask.NetCore.csproj -c Release --no-build -p:Version=${{ inputs.tag }} -o ./publish
# Store artifacts.
- uses: actions/upload-artifact@v1
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
with:
name: nuget
path: ./publish/
retention-days: 1
build-unity:
needs: [update-packagejson]
strategy:
matrix:
unity: ["2019.3.9f1"]
include:
- unity: 2019.3.9f1
license: UNITY_LICENSE_2019
unity: ["2022.3.39f1"]
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Load secrets
id: op-load-secret
uses: 1password/load-secrets-action@v2
with:
export-env: false
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
UNITY_EMAIL: "op://GitHubActionsPublic/UNITY_LICENSE/username"
UNITY_PASSWORD: "op://GitHubActionsPublic/UNITY_LICENSE/credential"
UNITY_SERIAL: "op://GitHubActionsPublic/UNITY_LICENSE/serial"
- run: echo ${{ needs.update-packagejson.outputs.sha }}
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
ref: ${{ needs.update-packagejson.outputs.sha }}
# Execute scripts: Export Package
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- name: Export unitypackage
uses: game-ci/unity-builder@v2.0-alpha-6
- name: Build Unity (.unitypacakge)
uses: Cysharp/Actions/.github/actions/unity-builder@main
env:
UNITY_LICENSE: ${{ secrets[matrix.license] }}
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
with:
projectPath: src/UniTask
unityVersion: ${{ matrix.unity }}
targetPlatform: StandaloneLinux64
buildMethod: PackageExporter.Export
versioning: None
- name: check all .meta is commited
run: |
if git ls-files --others --exclude-standard -t | grep --regexp='[.]meta$'; then
echo "Detected .meta file generated. Do you forgot commit a .meta file?"
exit 1
else
echo "Great, all .meta files are commited."
fi
working-directory: src/UniTask
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
with:
directory: src/UniTask
# Store artifacts.
- uses: actions/upload-artifact@v2
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
with:
name: UniTask.${{ env.GIT_TAG }}.unitypackage
path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
name: UniTask.${{ inputs.tag }}.unitypackage
path: ./src/UniTask/UniTask.${{ inputs.tag }}.unitypackage
retention-days: 1
# release
create-release:
if: github.event.inputs.dry_run == 'false'
needs: [update-packagejson, build-dotnet, build-unity]
runs-on: ubuntu-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
NUGET_XMLDOC_MODE: skip
steps:
# setup dotnet for nuget push
- uses: actions/setup-dotnet@v1
with:
dotnet-version: "${{ env.DOTNET_SDK_VERSION_3 }}"
# Create Releases
- uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.GIT_TAG }}
release_name: Ver.${{ env.GIT_TAG }}
commitish: ${{ needs.update-packagejson.outputs.sha }}
draft: true
prerelease: false
# Download(All) Artifacts to current directory
- uses: actions/download-artifact@v2
# Upload to NuGet
- run: dotnet nuget push "./nuget/*.nupkg" --skip-duplicate -s https://www.nuget.org/api/v2/package -k ${{ secrets.NUGET_KEY }}
# Upload to Releases(unitypackage)
- uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./UniTask.${{ env.GIT_TAG }}.unitypackage/UniTask.${{ env.GIT_TAG }}.unitypackage
asset_name: UniTask.${{ env.GIT_TAG }}.unitypackage
asset_content_type: application/octet-stream
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
with:
commit-id: ${{ needs.update-packagejson.outputs.sha }}
dry-run: ${{ inputs.dry-run }}
tag: ${{ inputs.tag }}
nuget-push: true
release-upload: true
release-asset-path: ./UniTask.${{ inputs.tag }}.unitypackage/UniTask.${{ inputs.tag }}.unitypackage
secrets: inherit
cleanup:
if: github.event.inputs.dry_run == 'true'
needs: [build-dotnet, build-unity]
runs-on: ubuntu-latest
steps:
- name: Delete branch
uses: dawidd6/action-delete-branch@v3
with:
github_token: ${{ github.token }}
branches: ${{ env.DRY_RUN_BRANCH_PREFIX }}-${{ env.GIT_TAG }}
if: ${{ needs.update-packagejson.outputs.is-branch-created == 'true' }}
needs: [update-packagejson, build-dotnet, build-unity]
uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
with:
branch: ${{ needs.update-packagejson.outputs.branch-name }}

View File

@@ -0,0 +1,10 @@
name: Prevent github change
on:
pull_request:
paths:
- ".github/**/*.yaml"
- ".github/**/*.yml"
jobs:
detect:
uses: Cysharp/Actions/.github/workflows/prevent-github-change.yaml@main

View File

@@ -1,24 +1,10 @@
name: "Close stale issues"
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# enable issue
stale-issue-message: "This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days."
stale-issue-label: "stale"
# enable pr
stale-pr-message: "This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days."
stale-pr-label: "stale"
days-before-stale: 90
days-before-close: 7
exempt-issue-labels: "wip"
exempt-pr-labels: "wip"
remove-stale-when-updated: true
uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main

View File

@@ -10,6 +10,6 @@ jobs:
name: TOC Generator
runs-on: ubuntu-latest
steps:
- uses: technote-space/toc-generator@v2.4.0
- uses: technote-space/toc-generator@v4.3.1
with:
TOC_TITLE: "## Table of Contents"

145
.gitignore vendored
View File

@@ -80,7 +80,7 @@ _ReSharper*
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
@@ -130,134 +130,15 @@ UpgradeLog*.XML
Assets/WSATestCertificate.pfx
.vs/
Assembly-CSharp\.csproj
UniRx\.Async\.csproj
UniRx\.Async\.Editor\.csproj
UniRx\.Async\.Tests\.csproj
UniTask\.sln
RuntimeUnitTestToolkit\.csproj
Assembly-CSharp-Editor\.csproj
UniRx\.Async\.unitypackage
UniRx.Async.Tests.Editor.csproj
src/UniTask/UniTask.csproj
src/UniTask/UniTask.Editor.csproj
src/UniTask/UniTask.Tests.csproj
src/UniTask/UniTask.Tests.Editor.csproj
src/UniTask/UniTask.*.unitypackage
src/UniTask/UniTask.Linq.csproj
src/UniTask/DOTween.Modules.csproj
src/UniTask/Unity.Addressables.csproj
src/UniTask/Unity.Addressables.Editor.csproj
src/UniTask/Unity.Analytics.DataPrivacy.csproj
src/UniTask/Unity.Recorder.csproj
src/UniTask/Unity.Recorder.Editor.csproj
src/UniTask/Unity.ResourceManager.csproj
src/UniTask/Unity.Rider.Editor.csproj
src/UniTask/Unity.ScriptableBuildPipeline.csproj
src/UniTask/Unity.ScriptableBuildPipeline.Editor.csproj
src/UniTask/Unity.TextMeshPro.csproj
src/UniTask/Unity.TextMeshPro.Editor.csproj
src/UniTask/Unity.Timeline.csproj
src/UniTask/Unity.Timeline.Editor.csproj
src/UniTask/Unity.VisualStudio.Editor.csproj
src/UniTask/Unity.VSCode.Editor.csproj
src/UniTask/UnityEditor.CacheServer.csproj
src/UniTask/UnityEditor.TestRunner.csproj
src/UniTask/UnityEditor.UI.csproj
src/UniTask/UnityEngine.Advertisements.csproj
src/UniTask/UnityEngine.Monetization.csproj
src/UniTask/UnityEngine.TestRunner.csproj
src/UniTask/UnityEngine.UI.csproj
src/UniTask/TempAsm.csproj
src/UniTask/UniTask.Addressables.csproj
src/UniTask/UniTask.DOTween.csproj
src/UniTask/UniTask.TextMeshPro.csproj
src/UniTask/RuntimeUnitTestToolkit.Player.csproj
src/UniTask/TempAsm.Player.csproj
src/UniTask/UniTask.Addressables.Player.csproj
src/UniTask/UniTask.DOTween.Player.csproj
src/UniTask/UniTask.Linq.Player.csproj
src/UniTask/UniTask.Player.csproj
src/UniTask/UniTask.Tests.Player.csproj
src/UniTask/UniTask.TextMeshPro.Player.csproj
src/UniTask/Unity.Addressables.Player.csproj
src/UniTask/Unity.Analytics.DataPrivacy.Player.csproj
src/UniTask/Unity.ResourceManager.Player.csproj
src/UniTask/Unity.ScriptableBuildPipeline.Player.csproj
src/UniTask/Unity.TextMeshPro.Player.csproj
src/UniTask/Unity.Timeline.Player.csproj
src/UniTask/UnityEngine.Advertisements.Player.csproj
src/UniTask/UnityEngine.Monetization.Player.csproj
src/UniTask/UnityEngine.TestRunner.Player.csproj
src/UniTask/UnityEngine.UI.Player.csproj
src/UniTask/DOTween.Modules.Player.csproj
src/UniTask/Assembly-CSharp.Player.csproj
src/UniTask/Unity.EditorCoroutines.Editor.csproj
src/UniTask/.vsconfig
src/UniTask/Logs/ApiUpdaterCheck.txt
src/UniTask/Assembly-CSharp-firstpass.csproj
# Unity
# Unity
.vsconfig
src/UniTask/Library/*
src/UniTask/Temp/*
src/UniTask/Logs/*
src/UniTask/[Uu]ser[Ss]ettings/
src/UniTask/*.sln
src/UniTask/*.csproj
src/UniTask/*.unitypackage
!src/UniTask/Packages/

170
README.md
View File

@@ -1,6 +1,6 @@
UniTask
===
[![GitHub Actions](https://github.com/Cysharp/UniTask/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/UniTask/actions) [![Releases](https://img.shields.io/github/release/Cysharp/UniTask.svg)](https://github.com/Cysharp/UniTask/releases)
[![GitHub Actions](https://github.com/Cysharp/UniTask/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/UniTask/actions) [![Releases](https://img.shields.io/github/release/Cysharp/UniTask.svg)](https://github.com/Cysharp/UniTask/releases) [![Readme_CN](https://img.shields.io/badge/UniTask-%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3-red)](https://github.com/Cysharp/UniTask/blob/master/README_CN.md)
Provides an efficient allocation free async/await integration for Unity.
@@ -44,7 +44,6 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
- [API References](#api-references)
- [UPM Package](#upm-package)
- [Install via git URL](#install-via-git-url)
- [Install via OpenUPM](#install-via-openupm)
- [.NET Core](#net-core)
- [License](#license)
@@ -52,7 +51,7 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
Getting started
---
Install via [UPM package](#upm-package) or asset package(`UniTask.*.*.*.unitypackage`) available in [UniTask/releases](https://github.com/Cysharp/UniTask/releases) page.
Install via [UPM package](#upm-package) with git reference or asset package(`UniTask.*.*.*.unitypackage`) available in [UniTask/releases](https://github.com/Cysharp/UniTask/releases).
```csharp
// extension awaiter/methods can be used by this namespace
@@ -86,8 +85,13 @@ async UniTask<string> DemoAsync()
await UniTask.Yield();
await UniTask.NextFrame();
// replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate))
// replacement of WaitForEndOfFrame
#if UNITY_2023_1_OR_NEWER
await UniTask.WaitForEndOfFrame();
#else
// requires MonoBehaviour(CoroutineRunner))
await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour
#endif
// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
await UniTask.WaitForFixedUpdate();
@@ -156,7 +160,7 @@ UniTask provides three pattern of extension methods.
> Note: AssetBundleRequest has `asset` and `allAssets`, default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
The type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`. They are like `Task.WhenAll`/`Task.WhenAny` but the return type is more useful. They return value tuples so you can deconstruct each result and pass multiple types.
The type of `UniTask` can use utilities like `UniTask.WhenAll`, `UniTask.WhenAny`, `UniTask.WhenEach`. They are like `Task.WhenAll`/`Task.WhenAny` but the return type is more useful. They return value tuples so you can deconstruct each result and pass multiple types.
```csharp
public async UniTaskVoid LoadManyAsync()
@@ -241,9 +245,57 @@ CancellationToken can be created by `CancellationTokenSource` or MonoBehaviour's
await UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
```
When cancellation is detected, all methods throw `OperationCanceledException` and propagate upstream. `OperationCanceledException` is a special exception, if this exception is not handled, it is propagated finally to `UniTaskScheduler.UnobservedTaskException`.
For propagate Cancellation, all async method recommend to accept `CancellationToken cancellationToken` at last argument, and pass `CancellationToken` from root to end.
The default behaviour of received unhandled exception is to write log as exception. Log level can be changed using `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to use custom behaviour, set an action to `UniTaskScheduler.UnobservedTaskException.`
```csharp
await FooAsync(this.GetCancellationTokenOnDestroy());
// ---
async UniTask FooAsync(CancellationToken cancellationToken)
{
await BarAsync(cancellationToken);
}
async UniTask BarAsync(CancellationToken cancellationToken)
{
await UniTask.Delay(TimeSpan.FromSeconds(3), cancellationToken);
}
```
`CancellationToken` means lifecycle of async. You can hold your own lifecycle insteadof default CancellationTokenOnDestroy.
```csharp
public class MyBehaviour : MonoBehaviour
{
CancellationTokenSource disableCancellation = new CancellationTokenSource();
CancellationTokenSource destroyCancellation = new CancellationTokenSource();
private void OnEnable()
{
if (disableCancellation != null)
{
disableCancellation.Dispose();
}
disableCancellation = new CancellationTokenSource();
}
private void OnDisable()
{
disableCancellation.Cancel();
}
private void OnDestroy()
{
destroyCancellation.Cancel();
destroyCancellation.Dispose();
}
}
```
When cancellation is detected, all methods throw `OperationCanceledException` and propagate upstream. When exception(not limited to `OperationCanceledException`) is not handled in async method, it is propagated finally to `UniTaskScheduler.UnobservedTaskException`. The default behaviour of received unhandled exception is to write log as exception. Log level can be changed using `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to use custom behaviour, set an action to `UniTaskScheduler.UnobservedTaskException.`
And also `OperationCanceledException` is a special exception, this is silently ignored at `UnobservedTaskException`.
If you want to cancel behaviour in an async UniTask method, throw `OperationCanceledException` manually.
@@ -265,7 +317,7 @@ public async UniTask<int> BarAsync()
var x = await FooAsync();
return x * 2;
}
catch (Exception ex) when (!(ex is OperationCanceledException))
catch (Exception ex) when (!(ex is OperationCanceledException)) // when (ex is not OperationCanceledException) at C# 9.0
{
return -1;
}
@@ -284,6 +336,18 @@ if (isCanceled)
Note: Only suppress throws if you call directly into the most source method. Otherwise, the return value will be converted, but the entire pipeline will not suppress throws.
Some features that use Unity's player loop, such as `UniTask.Yield` and `UniTask.Delay` etc, determines CancellationToken state on the player loop.
This means it does not cancel immediately upon `CancellationToken` fired.
If you want to change this behaviour, the cancellation to be immediate, set the `cancelImmediately` flag as an argument.
```csharp
await UniTask.Yield(cancellationToken, cancelImmediately: true);
```
Note: Setting `cancelImmediately` to true and detecting an immediate cancellation is more costly than the default behavior.
This is because it uses `CancellationToken.Register`; it is heavier than checking CancellationToken on the player loop.
Timeout handling
---
Timeout is a variation of cancellation. You can set timeout by `CancellationTokenSouce.CancelAfterSlim(TimeSpan)` and pass CancellationToken to async methods.
@@ -311,7 +375,7 @@ If you want to use timeout with other source of cancellation, use `CancellationT
```csharp
var cancelToken = new CancellationTokenSource();
cancelButton.onClick.AddListener(()=>
cancelButton.onClick.AddListener(() =>
{
cancelToken.Cancel(); // cancel from button click.
});
@@ -448,17 +512,22 @@ public enum PlayerLoopTiming
It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop.
`PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar to `WaitForEndOfFrame` in coroutine.
`PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`.
> `await UniTask.WaitForEndOfFrame()` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, use a coroutine instead.
> `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`.
>
> Note: In Unity 2023.1 or newer, `await UniTask.WaitForEndOfFrame();` no longer requires MonoBehaviour. It uses `UnityEngine.Awaitable.EndOfFrameAsync`.
`yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and fastest.
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and runs on YieldRunner. It is the most lightweight and fastest.
`AsyncOperation` is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after being called, the loaded scene's `Start` is called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
In UniTask, await directly uses native timing, `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
In UniTask, await directly uses native timing, while `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
> Note: When using Unity 2023.1 or newer, ensure you have `using UnityEngine;` in the using statements of your file when working with new `UnityEngine.Awaitable` methods like `SceneManager.LoadSceneAsync`.
> This prevents compilation errors by avoiding the use of the `UnityEngine.AsyncOperation` version.
In the stacktrace, you can check where it is running in playerloop.
@@ -610,7 +679,8 @@ By default, UniTask supports TextMeshPro(`BindTo(TMP_Text)` and `TMP_InputField`
There are defined in separated asmdefs like `UniTask.TextMeshPro`, `UniTask.DOTween`, `UniTask.Addressables`.
TextMeshPro and Addressables support are automatically enabled when importing their packages from package manager. However for DOTween support, it is required to import `com.demigiant.dotween` from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or to define `UNITASK_DOTWEEN_SUPPORT` to enable it.
TextMeshPro and Addressables support are automatically enabled when importing their packages from package manager.
However for DOTween support, after importing from the [DOTWeen assets](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676r) and define the scripting define symbol `UNITASK_DOTWEEN_SUPPORT` to enable it.
```csharp
// sequential
@@ -633,7 +703,7 @@ Unity 2020.2 supports C# 8.0 so you can use `await foreach`. This is the new Upd
```csharp
// Unity 2020.2, C# 8.0
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate(token))
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate().WithCancellation(token))
{
Debug.Log("Update() " + Time.frameCount);
}
@@ -643,10 +713,23 @@ In a C# 7.3 environment, you can use the `ForEachAsync` method to work in almost
```csharp
// C# 7.3(Unity 2018.3~)
await UniTaskAsyncEnumerable.EveryUpdate(token).ForEachAsync(_ =>
await UniTaskAsyncEnumerable.EveryUpdate().ForEachAsync(_ =>
{
Debug.Log("Update() " + Time.frameCount);
});
}, token);
```
`UniTask.WhenEach` that is similar to .NET 9's `Task.WhenEach` can consume new way for await multiple tasks.
```csharp
await foreach (var result in UniTask.WhenEach(task1, task2, task3))
{
// The result is of type WhenEachResult<T>.
// It contains either `T Result` or `Exception Exception`.
// You can check `IsCompletedSuccessfully` or `IsFaulted` to determine whether to access `.Result` or `.Exception`.
// If you want to throw an exception when `IsFaulted` and retrieve the result when successful, use `GetResult()`.
Debug.Log(result.GetResult());
}
```
UniTaskAsyncEnumerable implements asynchronous LINQ, similar to LINQ in `IEnumerable<T>` or Rx in `IObservable<T>`. All standard LINQ query operators can be applied to asynchronous streams. For example, the following code shows how to apply a Where filter to a button-click asynchronous stream that runs once every two clicks.
@@ -669,7 +752,7 @@ Async LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAs
It's closer to UniRx (Reactive Extensions), but UniTaskAsyncEnumerable is a pull-based asynchronous stream, whereas Rx was a push-based asynchronous stream. Note that although similar, the characteristics are different and the details behave differently along with them.
`UniTaskAsyncEnumerable` is the entry point like `Enumerable`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
`UniTaskAsyncEnumerable` is the entry point like `Enumerable`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`,`Merge` `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
The method with Func as an argument has three additional overloads, `***Await`, `***AwaitWithCancellation`.
@@ -757,32 +840,13 @@ async UniTask TripleClick(CancellationToken token)
}
```
All MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can be enabled by `using Cysharp.Threading.Tasks.Triggers;`.
All MonoBehaviour message events can convert async-streams by `AsyncTriggers` that can be enabled by `using Cysharp.Threading.Tasks.Triggers;`. AsyncTrigger can be created using `GetAsync***Trigger` and triggers itself as UniTaskAsyncEnumerable.
```csharp
using Cysharp.Threading.Tasks.Triggers;
async UniTaskVoid MonitorCollision()
{
await gameObject.OnCollisionEnterAsync();
Debug.Log("Collision Enter");
/* do anything */
await gameObject.OnCollisionExitAsync();
Debug.Log("Collision Exit");
}
```
Similar to uGUI event, AsyncTrigger can be created using `GetAsync***Trigger` and triggers itself as UniTaskAsyncEnumerable.
```csharp
// use await multiple times, get AsyncTriggerHandler is more efficient.
using(var trigger = this.GetOnCollisionEnterAsyncHandler())
{
await OnCollisionEnterAsync();
await OnCollisionEnterAsync();
await OnCollisionEnterAsync();
}
var trigger = this.GetOnCollisionEnterAsyncHandler();
await trigger.OnCollisionEnterAsync();
await trigger.OnCollisionEnterAsync();
await trigger.OnCollisionEnterAsync();
// every moves.
await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
@@ -810,9 +874,9 @@ rp.WithoutCurrent().BindTo(this.textComponent);
await rp.WaitAsync(); // wait until next value set
// also exists ToReadOnlyReactiveProperty
// also exists ToReadOnlyAsyncReactiveProperty
var rp2 = new AsyncReactiveProperty<int>(99);
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyReactiveProperty();
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
```
A pull-type asynchronous stream does not get the next values until the asynchronous processing in the sequence is complete. This could spill data from push-type events such as buttons.
@@ -918,9 +982,9 @@ UniTask's own unit tests are written using Unity Test Runner and [Cysharp/Runtim
ThreadPool limitation
---
Most UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run` and `UniTask.SwitchToThreadPool` running on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
Most UniTask methods run on a single thread (PlayerLoop), with only `UniTask.Run`(`Task.Run` equivalent) and `UniTask.SwitchToThreadPool` running on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
`UniTask.Run` will be deprecated in the future (marked with an Obsolete) and only `RunOnThreadPool` will be used. If you use `UniTask.Run`, consider whether you can use `UniTask.Create` or `UniTask.Void`.
`UniTask.Run` is now deprecated. You can use `UniTask.RunOnThreadPool` instead. And also consider whether you can use `UniTask.Create` or `UniTask.Void`.
IEnumerator.ToUniTask limitation
---
@@ -937,7 +1001,7 @@ UniTask can run on Unity Editor like an Editor Coroutine. However, there are som
* UniTask.Delay's DelayType.DeltaTime, UnscaledDeltaTime do not work correctly because they can not get deltaTime in editor. Therefore run on EditMode, automatically change DelayType to `DelayType.Realtime` that wait for the right time.
* All PlayerLoopTiming run on the timing `EditorApplication.update`.
* `-batchmode` with `-quit` does not work because does not run `EditorApplication.update`(quit on single frame) so should not use `-quit` and quit manually with `Environment.Exit(0)`.
* `-batchmode` with `-quit` does not work because Unity does not run `EditorApplication.update` and quit after a single frame. Instead, don't use `-quit` and quit manually with `EditorApplication.Exit(0)`.
Compare with Standard Task API
---
@@ -975,9 +1039,10 @@ Use UniTask type.
| `IAsyncDisposable` | `IUniTaskAsyncDisposable` |
| `Task.Delay` | `UniTask.Delay` |
| `Task.Yield` | `UniTask.Yield` |
| `Task.Run` | `UniTask.Run` |
| `Task.Run` | `UniTask.RunOnThreadPool` |
| `Task.WhenAll` | `UniTask.WhenAll` |
| `Task.WhenAny` | `UniTask.WhenAny` |
| `Task.WhenEach` | `UniTask.WhenEach` |
| `Task.CompletedTask` | `UniTask.CompletedTask` |
| `Task.FromException` | `UniTask.FromException` |
| `Task.FromResult` | `UniTask.FromResult` |
@@ -1043,13 +1108,6 @@ or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/
If you want to set a target version, UniTask uses the `*.*.*` release tag so you can specify a version like `#2.1.0`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0`.
### Install via OpenUPM
The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).
```
openupm add com.cysharp.unitask
```
.NET Core
---
@@ -1059,7 +1117,7 @@ For .NET Core, use NuGet.
UniTask of .NET Core version is a subset of Unity UniTask with PlayerLoop dependent methods removed.
It runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AysncLocal` also does not work because it ignores ExecutionContext.
It runs at higher performance than the standard Task/ValueTask, but you should be careful to ignore the ExecutionContext/SynchronizationContext when using it. `AsyncLocal` also does not work because it ignores ExecutionContext.
If you use UniTask internally, but provide ValueTask as an external API, you can write it like the following(Inspired by [PooledAwait](https://github.com/mgravell/PooledAwait)).

1134
README_CN.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,15 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
# Visual Studio Version 17
VisualStudioVersion = 17.0.31606.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCoreTests", "src\UniTask.NetCoreTests\UniTask.NetCoreTests.csproj", "{B3E311A4-70D8-4131-9965-C073A99D201A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCore", "src\UniTask.NetCore\UniTask.NetCore.csproj", "{16EE20D0-7FB1-483A-8467-A5EEDBF1F5BF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UniTask.NetCoreSandbox", "src\UniTask.NetCoreSandbox\UniTask.NetCoreSandbox.csproj", "{3915E72E-33E0-4A14-A6D8-872702200E58}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniTask.Analyzer", "src\UniTask.Analyzer\UniTask.Analyzer.csproj", "{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,6 +29,10 @@ Global
{3915E72E-33E0-4A14-A6D8-872702200E58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3915E72E-33E0-4A14-A6D8-872702200E58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3915E72E-33E0-4A14-A6D8-872702200E58}.Release|Any CPU.Build.0 = Release|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0AC6F052-A255-4EE3-9E05-1C02D49AB1C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,8 @@
{
"profiles": {
"UniTask.Analyzer": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\UniTask.NetCoreSandbox\\UniTask.NetCoreSandbox.csproj"
}
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>library</OutputType>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<IsRoslynComponent>true</IsRoslynComponent>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackBuildOutputs</TargetsForTfmSpecificContentInPackage>
<IncludeBuildOutput>false</IncludeBuildOutput>
<IncludeSymbols>false</IncludeSymbols>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<DevelopmentDependency>true</DevelopmentDependency>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
</ItemGroup>
<Target Name="PackBuildOutputs" DependsOnTargets="SatelliteDllsProjectOutputGroup;DebugSymbolsProjectOutputGroup">
<ItemGroup>
<TfmSpecificPackageFile Include="$(TargetDir)\*.dll" PackagePath="analyzers\dotnet\cs" />
<TfmSpecificPackageFile Include="@(SatelliteDllsProjectOutputGroupOutput->'%(FinalOutputPath)')" PackagePath="analyzers\dotnet\cs\%(SatelliteDllsProjectOutputGroupOutput.Culture)\" />
</ItemGroup>
</Target>
</Project>

View File

@@ -0,0 +1,54 @@
#pragma warning disable RS2008
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using System.Collections.Immutable;
using System.Threading;
namespace UniTask.Analyzer
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class UniTaskAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
id: "UNITASK001",
title: "UniTaskAnalyzer001: Must pass CancellationToken",
messageFormat: "Must pass CancellationToken",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "Pass CancellationToken or CancellationToken.None.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterOperationAction(AnalyzeOperation, OperationKind.Invocation);
}
private static void AnalyzeOperation(OperationAnalysisContext context)
{
var token = context.Compilation.GetTypeByMetadataName(typeof(CancellationToken).FullName);
if (token == null) return;
if (context.Operation is IInvocationOperation invocation)
{
foreach (var arg in invocation.Arguments)
{
if (arg.ArgumentKind == ArgumentKind.DefaultValue)
{
if (SymbolEqualityComparer.Default.Equals(arg.Parameter.Type, token))
{
var diagnostic = Diagnostic.Create(Rule, arg.Syntax.GetLocation());
context.ReportDiagnostic(diagnostic);
}
}
}
}
}
}
}

View File

@@ -1,39 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;netstandard2.1;netstandard2.0</TargetFrameworks>
<AssemblyName>UniTask</AssemblyName>
<LangVersion>8.0</LangVersion>
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
<PropertyGroup>
<TargetFrameworks>net6.0;net7.0;netstandard2.1;netstandard2.0</TargetFrameworks>
<AssemblyName>UniTask</AssemblyName>
<LangVersion>8.0</LangVersion>
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
<DefineConstants>UNITASK_NETCORE</DefineConstants>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<!-- NuGet Packaging -->
<Id>UniTask</Id>
<PackageVersion>$(Version)</PackageVersion>
<Company>Cysharp</Company>
<Authors>Cysharp</Authors>
<Copyright>© Cysharp, Inc.</Copyright>
<PackageTags>task;async</PackageTags>
<Description>Provides an efficient async/await integration to Unity and .NET Core.</Description>
<PackageProjectUrl>https://github.com/Cysharp/UniTask</PackageProjectUrl>
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>opensource.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<!-- NuGet Packaging -->
<Id>UniTask</Id>
<PackageVersion>$(Version)</PackageVersion>
<Company>Cysharp</Company>
<Authors>Cysharp</Authors>
<Copyright>© Cysharp, Inc.</Copyright>
<PackageTags>task;async</PackageTags>
<Description>Provides an efficient async/await integration to Unity and .NET Core.</Description>
<PackageProjectUrl>https://github.com/Cysharp/UniTask</PackageProjectUrl>
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Icon.png</PackageIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>opensource.snk</AssemblyOriginatorKeyFile>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup>
<None Include="Icon.png" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup>
<None Include="Icon.png" Pack="true" PackagePath="/" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs" Exclude="&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Triggers\*.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Linq\UnityExtensions\*.cs;&#xD;&#xA; &#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;&#xD;&#xA; &#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\TimeoutController.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopTimer.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;&#xD;&#xA;" />
<Compile Remove="..\UniTask\Assets\Plugins\UniTask\Runtime\_InternalVisibleTo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs" Exclude="&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Triggers\*.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Linq\UnityExtensions\*.cs;&#xD;&#xA; &#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;&#xD;&#xA; &#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\TimeoutController.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopTimer.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;&#xD;&#xA;..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;&#xD;&#xA;" />
<Compile Remove="..\UniTask\Assets\Plugins\UniTask\Runtime\_InternalVisibleTo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
</ItemGroup>
</Project>

View File

@@ -1,258 +0,0 @@
using BenchmarkDotNet.Attributes;
using System.Linq;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using Cysharp.Threading.Tasks;
using PooledAwait;
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.CompilerServices;
using Cysharp.Threading.Tasks.CompilerServices;
using System.Collections.Concurrent;
[Config(typeof(BenchmarkConfig))]
public class AllocationCheck
{
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
// iterations, so that we're only really measuring the inner loop
private const int InnerOps = 1000;
[Benchmark(OperationsPerInvoke = InnerOps)]
public async Task ViaUniTask()
{
for (int i = 0; i < InnerOps; i++)
{
var a = Core();
var b = Core();
var c = Core();
await a;
await b;
await c;
}
static async UniTask Core()
{
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
}
}
[Benchmark(OperationsPerInvoke = InnerOps)]
public async Task<int> ViaUniTaskT()
{
var sum = 0;
for (int i = 0; i < InnerOps; i++)
{
var a = Core();
var b = Core();
var c = Core();
sum += await a;
sum += await b;
sum += await c;
}
return sum;
static async UniTask<int> Core()
{
var a = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
var b = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
var c = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
return 10;
}
}
//[Benchmark(OperationsPerInvoke = InnerOps)]
//[Benchmark]
public void ViaUniTaskVoid()
{
for (int i = 0; i < InnerOps; i++)
{
Core().Forget();
Core().Forget();
Core().Forget();
}
static async UniTaskVoid Core()
{
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
}
}
struct Foo : IAsyncStateMachine
{
public AsyncUniTaskVoidMethodBuilder builder;
public TestAwaiter awaiter;
public TestAwaiter awaiterawaiter;
public int state;
public void MoveNext()
{
switch (state)
{
case -1:
awaiterawaiter = awaiter.GetAwaiter();
if (awaiterawaiter.IsCompleted)
{
goto case 0;
}
else
{
state = 0;
builder.AwaitUnsafeOnCompleted(ref awaiterawaiter, ref this);
return;
}
case 0:
default:
goto END;
}
END:
builder.SetResult();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
}
}
public class TaskTestException : Exception
{
}
public struct TestAwaiter : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
public TestAwaiter(bool isCompleted, UniTaskStatus status)
{
this.isCompleted = isCompleted;
this.status = status;
}
public TestAwaiter GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public void GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
break;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
}
public struct TestAwaiter<T> : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
readonly T value;
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
{
this.isCompleted = isCompleted;
this.status = status;
this.value = value;
}
public TestAwaiter<T> GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public T GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
return value;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
}
}
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
{
public static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
public static void CreatePoolItems(int count)
{
for (int i = 0; i < count; i++)
{
pool.Enqueue(new ThreadPoolWorkItem());
}
}
Action continuation;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ThreadPoolWorkItem Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
{
item = new ThreadPoolWorkItem();
}
item.continuation = continuation;
return item;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Execute()
{
var call = continuation;
continuation = null;
pool.Enqueue(this);
call.Invoke();
}
}

View File

@@ -1,283 +0,0 @@
using BenchmarkDotNet.Attributes;
using System.Linq;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using Cysharp.Threading.Tasks;
using PooledAwait;
using System;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.CompilerServices;
using Cysharp.Threading.Tasks.CompilerServices;
//class Program
//{
// static void Main(string[] args)
// {
// var switcher = new BenchmarkSwitcher(new[]
// {
// typeof(StandardBenchmark)
// });
//#if DEBUG
// var b = new StandardBenchmark();
//#else
// switcher.Run(args);
//#endif
// }
//}
public class BenchmarkConfig : ManualConfig
{
public BenchmarkConfig()
{
AddDiagnoser(MemoryDiagnoser.Default);
AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1)/*.RunOncePerIteration()*/);
}
}
// borrowed from PooledAwait
[Config(typeof(BenchmarkConfig))]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
[CategoriesColumn]
public class ComparisonBenchmarks
{
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
// iterations, so that we're only really measuring the inner loop
private const int InnerOps = 1000;
public bool ConfigureAwait { get; set; } = false;
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("Task<T>")]
public async Task<int> ViaTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async Task<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("Task")]
public async Task ViaTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async Task Inner()
{
await Task.Yield();
await Task.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("ValueTask<T>")]
public async Task<int> ViaValueTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async ValueTask<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
[BenchmarkCategory("ValueTask")]
public async Task ViaValueTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async ValueTask Inner()
{
await Task.Yield();
await Task.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("ValueTask<T>")]
public async Task<int> ViaPooledValueTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async PooledValueTask<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("ValueTask")]
public async Task ViaPooledValueTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async PooledValueTask Inner()
{
await Task.Yield();
await Task.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("Task<T>")]
public async Task<int> ViaPooledTaskT()
{
int sum = 0;
for (int i = 0; i < InnerOps; i++)
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
return sum;
static async PooledTask<int> Inner(int x, int y)
{
int i = x;
await Task.Yield();
i *= y;
await Task.Yield();
return 5 * i;
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
[BenchmarkCategory("Task")]
public async Task ViaPooledTask()
{
for (int i = 0; i < InnerOps; i++)
await Inner().ConfigureAwait(ConfigureAwait);
static async PooledTask Inner()
{
await Task.Yield();
await Task.Yield();
}
}
// ---
//[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskVoid")]
//[BenchmarkCategory("UniTask")]
//public async Task ViaUniTaskVoid()
//{
// for (int i = 0; i < InnerOps; i++)
// {
// await Inner();
// }
// static async UniTaskVoid Inner()
// {
// await UniTask.Yield();
// await UniTask.Yield();
// }
//}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTask")]
[BenchmarkCategory("UniTask")]
public async Task ViaUniTask()
{
for (int i = 0; i < InnerOps; i++)
{
await Inner();
}
static async UniTask Inner()
{
await UniTask.Yield();
await UniTask.Yield();
}
}
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskT")]
[BenchmarkCategory("UniTask")]
public async Task<int> ViaUniTaskT()
{
var sum = 0;
for (int i = 0; i < InnerOps; i++)
{
sum += await Inner(1, 2);
}
return sum;
static async UniTask<int> Inner(int x, int y)
{
int i = x;
await UniTask.Yield();
i *= y;
await UniTask.Yield();
return 5 * i;
}
}
}
public struct MyAwaiter : ICriticalNotifyCompletion
{
public MyAwaiter GetAwaiter() => this;
public bool IsCompleted => false;
public void GetResult()
{
}
public void OnCompleted(Action continuation)
{
continuation();
}
public void UnsafeOnCompleted(Action continuation)
{
continuation();
}
}
public struct MyTestStateMachine : IAsyncStateMachine
{
public void MoveNext()
{
//throw new NotImplementedException();
}
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
//throw new NotImplementedException();
}
}

View File

@@ -17,499 +17,34 @@ using System.Reactive.Concurrency;
namespace NetCoreSandbox
{
public class MySyncContext : SynchronizationContext
public class Program
{
public MySyncContext()
{
}
public override void Post(SendOrPostCallback d, object state)
{
Console.WriteLine("Called SyncContext Post!");
base.Post(d, state);
}
}
public class Text
{
public string text { get; set; }
}
public class ZeroAllocAsyncAwaitInDotNetCore
{
public ValueTask<int> NanikaAsync(int x, int y)
{
return Core(this, x, y);
static async UniTask<int> Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)
{
// nanika suru...
await Task.Delay(TimeSpan.FromSeconds(x + y));
return 10;
}
}
}
public class TaskTestException : Exception
{
}
class Foo
{
public async UniTask MethodFooAsync()
{
await MethodBarAsync();
}
private async UniTask MethodBarAsync()
{
Throw();
}
private void Throw()
{
throw new Exception();
}
}
public struct TestAwaiter : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
public TestAwaiter(bool isCompleted, UniTaskStatus status)
{
this.isCompleted = isCompleted;
this.status = status;
}
public TestAwaiter GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public void GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
break;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
}
}
public struct TestAwaiter<T> : ICriticalNotifyCompletion
{
readonly UniTaskStatus status;
readonly bool isCompleted;
readonly T value;
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
{
this.isCompleted = isCompleted;
this.status = status;
this.value = value;
}
public TestAwaiter<T> GetAwaiter() => this;
public bool IsCompleted => isCompleted;
public T GetResult()
{
switch (status)
{
case UniTaskStatus.Faulted:
throw new TaskTestException();
case UniTaskStatus.Canceled:
throw new OperationCanceledException();
case UniTaskStatus.Pending:
case UniTaskStatus.Succeeded:
default:
return value;
}
}
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
}
public void UnsafeOnCompleted(Action continuation)
{
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
}
}
public static partial class UnityUIComponentExtensions
{
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
{
AAAACORECORE(source, text).Forget();
async UniTaskVoid AAAACORECORE(IUniTaskAsyncEnumerable<string> source2, Text text2)
{
var e = source2.GetAsyncEnumerator();
try
{
while (await e.MoveNextAsync())
{
text2.text = e.Current;
// action(e.Current);
}
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
}
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text)
//{
// return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
//}
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text, Func<T, string> selector)
//{
// return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
//}
//public static IDisposable SubscribeToInteractable(this IObservable<bool> source, Selectable selectable)
//{
// return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
//}
}
class Program
{
static string FlattenGenArgs(Type type)
{
if (type.IsGenericType)
{
var t = string.Join(", ", type.GetGenericArguments().Select(x => FlattenGenArgs(x)));
return Regex.Replace(type.Name, "`.+", "") + "<" + t + ">";
}
//x.ReturnType.GetGenericArguments()
else
{
return type.Name;
}
}
static async IAsyncEnumerable<int> FooAsync([EnumeratorCancellation]CancellationToken cancellationToken = default)
{
yield return 1;
await Task.Delay(10, cancellationToken);
}
public class MyDisposable : IDisposable
{
public void Dispose()
{
}
}
static void Test()
{
var disp = new MyDisposable();
using var _ = new MyDisposable();
Console.WriteLine("tako");
}
static async UniTask FooBarAsync()
{
await using (UniTask.ReturnToCurrentSynchronizationContext())
{
await UniTask.SwitchToThreadPool();
}
}
static async UniTask Aaa()
{
await FooBarAsync();
Console.WriteLine("FooBarAsync End");
}
static async UniTask WhereSelect()
{
await foreach (var item in UniTaskAsyncEnumerable.Range(1, 10)
.SelectAwait(async x =>
{
await UniTask.Yield();
return x;
})
.Where(x => x % 2 == 0))
{
Console.WriteLine(item);
}
}
static async Task Main(string[] args)
{
#if !DEBUG
var cts = new CancellationTokenSource();
// OK.
await FooAsync(10, cts.Token);
// NG(Compiler Error)
// await FooAsync(10);
//await new AllocationCheck().ViaUniTaskVoid();
//Console.ReadLine();
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
//await new ComparisonBenchmarks().ViaUniTaskT();
return;
#endif
var e = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Start {i}");
await writer.YieldAsync(i);
Console.WriteLine($"End {i}");
}
});
var ee = e.GetAsyncEnumerator();
while (await ee.MoveNextAsync())
{
Console.WriteLine("ForEach " + ee.Current);
}
}
static async UniTask YieldCore()
static async UniTask FooAsync(int x, CancellationToken cancellationToken = default)
{
await UniTask.Yield();
}
#pragma warning disable CS1998
static async UniTask<int> AsyncTest()
{
// empty
await new TestAwaiter(false, UniTaskStatus.Succeeded);
await new TestAwaiter(true, UniTaskStatus.Succeeded);
await new TestAwaiter(false, UniTaskStatus.Succeeded);
return 10;
}
#pragma warning restore CS1998
void Foo()
{
// AsyncEnumerable.Range(1,10).Do(
// AsyncEnumerable.t
var sb = new StringBuilder();
sb.AppendLine(@"using System;
using System.Threading;
namespace Cysharp.Threading.Tasks.Linq
{
");
var chako = typeof(AsyncEnumerable).GetMethods()
.OrderBy(x => x.Name)
.Select(x =>
{
var ret = FlattenGenArgs(x.ReturnType);
var generics = string.Join(", ", x.GetGenericArguments().Select(x => x.Name));
if (x.GetParameters().Length == 0) return "";
var self = x.GetParameters().First();
if (x.GetCustomAttributes(typeof(ExtensionAttribute), true).Length == 0)
{
return "";
}
var arg1Type = FlattenGenArgs(x.GetParameters().First().ParameterType);
var others = string.Join(", ", x.GetParameters().Skip(1).Select(y => FlattenGenArgs(y.ParameterType) + " " + y.Name));
if (!string.IsNullOrEmpty(others))
{
others = ", " + others;
}
var template = $"public static {ret} {x.Name}<{generics}>(this {arg1Type} {self.Name}{others})";
return template.Replace("ValueTask", "UniTask").Replace("IAsyncEnumerable", "IUniTaskAsyncEnumerable").Replace("<>", "");
})
.Where(x => x != "")
.Select(x => x + "\r\n{\r\n throw new NotImplementedException();\r\n}")
.ToArray();
var huga = string.Join("\r\n\r\n", chako);
foreach (var item in typeof(AsyncEnumerable).GetMethods().Select(x => x.Name).Distinct())
{
if (item.EndsWith("AwaitAsync") || item.EndsWith("AwaitWithCancellationAsync") || item.EndsWith("WithCancellation"))
{
continue;
}
var item2 = item.Replace("Async", "");
item2 = item2.Replace("Await", "");
var format = @"
internal sealed class {0}
{{
}}
";
sb.Append(string.Format(format, item2));
}
sb.Append("}");
Console.WriteLine(sb.ToString());
}
public static async IAsyncEnumerable<int> AsyncGen()
{
await UniTask.SwitchToThreadPool();
yield return 10;
await UniTask.SwitchToThreadPool();
yield return 100;
}
}
class MyEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new MyEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
class MyEnumerator : IEnumerator<int>
{
public int Current => throw new NotImplementedException();
object IEnumerator.Current => throw new NotImplementedException();
public void Dispose()
{
Console.WriteLine("Called Dispose");
}
public bool MoveNext()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
}
public class MyClass<T>
{
public CustomAsyncEnumerator<T> GetAsyncEnumerator()
{
//IAsyncEnumerable
return new CustomAsyncEnumerator<T>();
}
}
public struct CustomAsyncEnumerator<T>
{
int count;
public T Current
{
get
{
return default;
}
}
public UniTask<bool> MoveNextAsync()
{
if (count++ == 3)
{
return UniTask.FromResult(false);
//return false;
}
return UniTask.FromResult(true);
}
public UniTask DisposeAsync()
{
return default;
}
}
}

View File

@@ -1,473 +0,0 @@
using BenchmarkDotNet.Attributes;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
[Config(typeof(BenchmarkConfig))]
public class QueueCheck
{
Node node1 = new Node();
Node node2 = new Node();
RefNode refNode1 = new RefNode();
RefNode refNode2 = new RefNode();
Queue<Node> q1 = new Queue<Node>();
Stack<Node> s1 = new Stack<Node>();
ConcurrentQueue<Node> cq = new ConcurrentQueue<Node>();
ConcurrentStack<Node> cs = new ConcurrentStack<Node>();
static TaskPool<Node> pool;
static TaskPoolRefNode<RefNode> poolRefNode;
static TaskPoolEqualNull<Node> poolEqualNull;
static TaskPoolClass<Node> poolClass = new TaskPoolClass<Node>();
static TaskPoolWithoutSize<Node> poolWithoutSize;
static TaskPoolWithoutLock<Node> poolWithoutLock;
[Benchmark]
public void Queue()
{
q1.Enqueue(node1);
q1.Enqueue(node1);
q1.TryDequeue(out _);
q1.TryDequeue(out _);
}
[Benchmark]
public void QueueLock()
{
lock (q1) { q1.Enqueue(node1); }
lock (q1) { q1.Enqueue(node1); }
lock (q1) { q1.TryDequeue(out _); }
lock (q1) { q1.TryDequeue(out _); }
}
[Benchmark]
public void Stack()
{
s1.Push(node1);
s1.Push(node2);
s1.TryPop(out _);
s1.TryPop(out _);
}
[Benchmark]
public void StackLock()
{
lock (s1) { s1.Push(node1); }
lock (s1) { s1.Push(node2); }
lock (s1) { s1.TryPop(out _); }
lock (s1) { s1.TryPop(out _); }
}
[Benchmark]
public void ConcurrentQueue()
{
cq.Enqueue(node1);
cq.Enqueue(node1);
cq.TryDequeue(out _);
cq.TryDequeue(out _);
}
[Benchmark]
public void ConcurrentStack()
{
cs.Push(node1);
cs.Push(node2);
cs.TryPop(out _);
cs.TryPop(out _);
}
[Benchmark]
public void TaskPool()
{
pool.TryPush(node1);
pool.TryPush(node2);
pool.TryPop(out _);
pool.TryPop(out _);
}
[Benchmark]
public void TaskPoolRefNode()
{
poolRefNode.TryPush(refNode1);
poolRefNode.TryPush(refNode2);
poolRefNode.TryPop(out _);
poolRefNode.TryPop(out _);
}
[Benchmark]
public void TaskPoolEqualNull()
{
poolEqualNull.TryPush(node1);
poolEqualNull.TryPush(node2);
poolEqualNull.TryPop(out _);
poolEqualNull.TryPop(out _);
}
[Benchmark]
public void TaskPoolClass()
{
poolClass.TryPush(node1);
poolClass.TryPush(node2);
poolClass.TryPop(out _);
poolClass.TryPop(out _);
}
[Benchmark]
public void TaskPoolWithoutSize()
{
poolWithoutSize.TryPush(node1);
poolWithoutSize.TryPush(node2);
poolWithoutSize.TryPop(out _);
poolWithoutSize.TryPop(out _);
}
[Benchmark]
public void TaskPoolWithoutLock()
{
poolWithoutLock.TryPush(node1);
poolWithoutLock.TryPush(node2);
poolWithoutLock.TryPop(out _);
poolWithoutLock.TryPop(out _);
}
}
public sealed class Node : ITaskPoolNode<Node>
{
public Node NextNode { get; set; }
}
public interface ITaskPoolNode<T>
{
T NextNode { get; set; }
}
public sealed class RefNode :ITaskPoolRefNode<RefNode>
{
RefNode nextNode;
public ref RefNode NextNode => ref nextNode;
}
public interface ITaskPoolRefNode<T>
{
ref T NextNode { get; }
}
// mutable struct, don't mark readonly.
[StructLayout(LayoutKind.Auto)]
public struct TaskPoolWithoutLock<T>
where T : class, ITaskPoolNode<T>
{
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
//if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
// Volatile.Write(ref gate, 0);
return true;
}
//Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
//if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
// Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
//return false;
}
}
[StructLayout(LayoutKind.Auto)]
public struct TaskPool<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
[StructLayout(LayoutKind.Auto)]
public struct TaskPoolRefNode<T>
where T : class, ITaskPoolRefNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
ref var nextNode = ref v.NextNode;
root = nextNode;
nextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
[StructLayout(LayoutKind.Auto)]
public struct TaskPoolEqualNull<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (v != null)
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
public class TaskPoolClass<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}
[StructLayout(LayoutKind.Auto)]
public struct TaskPoolWithoutSize<T>
where T : class, ITaskPoolNode<T>
{
int gate;
T root;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
{
root = v.NextNode;
v.NextNode = null;
result = v;
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
//if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
Volatile.Write(ref gate, 0);
return true;
}
//else
{
// Volatile.Write(ref gate, 0);
}
}
return false;
}
}

View File

@@ -2,8 +2,9 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>NetCoreSandbox</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
@@ -15,6 +16,12 @@
<ItemGroup>
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
<ProjectReference Include="..\UniTask.Analyzer\UniTask.Analyzer.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Analyzer</OutputItemType>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -159,6 +159,30 @@ namespace NetCoreTests.Linq
list.Should().Equal(100, 200, 300, 400);
}
[Fact]
public async Task AwaitForeachBreak()
{
var finallyCalled = false;
var enumerable = UniTaskAsyncEnumerable.Create<int>(async (writer, _) =>
{
try
{
await writer.YieldAsync(1);
}
finally
{
finallyCalled = true;
}
});
await foreach (var x in enumerable)
{
x.Should().Be(1);
break;
}
finallyCalled.Should().BeTrue();
}
async IAsyncEnumerable<int> Range(int from, int count)
{
for (int i = 0; i < count; i++)

View File

@@ -0,0 +1,139 @@
#pragma warning disable CS1998
using System;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using Xunit;
namespace NetCoreTests.Linq
{
public class MergeTest
{
[Fact]
public async Task TwoSource()
{
var semaphore = new SemaphoreSlim(1, 1);
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("A1");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("A2");
semaphore.Release();
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("B1");
await writer.YieldAsync("B2");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("B3");
semaphore.Release();
});
var result = await a.Merge(b).ToArrayAsync();
result.Should().Equal("A1", "B1", "B2", "A2", "B3");
}
[Fact]
public async Task ThreeSource()
{
var semaphore = new SemaphoreSlim(0, 1);
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("A1");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("A2");
semaphore.Release();
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await semaphore.WaitAsync();
await writer.YieldAsync("B1");
await writer.YieldAsync("B2");
semaphore.Release();
await semaphore.WaitAsync();
await writer.YieldAsync("B3");
semaphore.Release();
});
var c = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await UniTask.SwitchToThreadPool();
await writer.YieldAsync("C1");
semaphore.Release();
});
var result = await a.Merge(b, c).ToArrayAsync();
result.Should().Equal("C1", "A1", "B1", "B2", "A2", "B3");
}
[Fact]
public async Task Throw()
{
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await writer.YieldAsync("A1");
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
throw new UniTaskTestException();
});
var enumerator = a.Merge(b).GetAsyncEnumerator();
(await enumerator.MoveNextAsync()).Should().Be(true);
enumerator.Current.Should().Be("A1");
await Assert.ThrowsAsync<UniTaskTestException>(async () => await enumerator.MoveNextAsync());
}
[Fact]
public async Task Cancel()
{
var cts = new CancellationTokenSource();
var a = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await writer.YieldAsync("A1");
});
var b = UniTaskAsyncEnumerable.Create<string>(async (writer, _) =>
{
await writer.YieldAsync("B1");
});
var enumerator = a.Merge(b).GetAsyncEnumerator(cts.Token);
(await enumerator.MoveNextAsync()).Should().Be(true);
enumerator.Current.Should().Be("A1");
cts.Cancel();
await Assert.ThrowsAsync<OperationCanceledException>(async () => await enumerator.MoveNextAsync());
}
}
}

View File

@@ -0,0 +1,45 @@
#pragma warning disable CS1998
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class TaskExtensionsTest
{
[Fact]
public async Task PropagateException()
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await ThrowAsync().AsUniTask();
});
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await ThrowOrValueAsync().AsUniTask();
});
}
[Fact]
public async Task PropagateExceptionWhenAll()
{
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
{
await Task.WhenAll(ThrowAsync(), ThrowAsync()).AsUniTask();
});
}
async Task ThrowAsync()
{
throw new InvalidOperationException();
}
async Task<int> ThrowOrValueAsync()
{
throw new InvalidOperationException();
}
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>

View File

@@ -0,0 +1,80 @@
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using FluentAssertions;
using NetCoreTests.Linq;
using Xunit;
namespace NetCoreTests
{
public class AutoResetUniTaskCompletionSourceTest
{
[Fact]
public async Task SetResultAfterReturn()
{
var source1 = AutoResetUniTaskCompletionSource.Create();
source1.TrySetResult();
await source1.Task;
source1.TrySetResult().Should().BeFalse();
var source2 = AutoResetUniTaskCompletionSource.Create();
source2.TrySetResult();
await source2.Task;
source2.TrySetResult().Should().BeFalse();
}
[Fact]
public async Task SetCancelAfterReturn()
{
var source = AutoResetUniTaskCompletionSource.Create();
source.TrySetResult();
await source.Task;
source.TrySetCanceled().Should().BeFalse();
}
[Fact]
public async Task SetExceptionAfterReturn()
{
var source = AutoResetUniTaskCompletionSource.Create();
source.TrySetResult();
await source.Task;
source.TrySetException(new UniTaskTestException()).Should().BeFalse();
}
[Fact]
public async Task SetResultWithValueAfterReturn()
{
var source1 = AutoResetUniTaskCompletionSource<int>.Create();
source1.TrySetResult(100);
(await source1.Task).Should().Be(100);
source1.TrySetResult(100).Should().BeFalse();
var source2 = AutoResetUniTaskCompletionSource.Create();
source2.TrySetResult();
await source2.Task;
source2.TrySetResult().Should().BeFalse();
}
[Fact]
public async Task SetCancelWithValueAfterReturn()
{
var source = AutoResetUniTaskCompletionSource<int>.Create();
source.TrySetResult(100);
(await source.Task).Should().Be(100);
source.TrySetCanceled().Should().BeFalse();
}
[Fact]
public async Task SetExceptionWithValueAfterReturn()
{
var source = AutoResetUniTaskCompletionSource<int>.Create();
source.TrySetResult(100);
(await source.Task).Should().Be(100);
source.TrySetException(new UniTaskTestException()).Should().BeFalse();
}
}
}

View File

@@ -0,0 +1,69 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class WhenEachTest
{
[Fact]
public async Task Each()
{
var a = Delay(1, 3000);
var b = Delay(2, 1000);
var c = Delay(3, 2000);
var l = new List<int>();
await foreach (var item in UniTask.WhenEach(a, b, c))
{
l.Add(item.Result);
}
l.Should().Equal(2, 3, 1);
}
[Fact]
public async Task Error()
{
var a = Delay2(1, 3000);
var b = Delay2(2, 1000);
var c = Delay2(3, 2000);
var l = new List<WhenEachResult<int>>();
await foreach (var item in UniTask.WhenEach(a, b, c))
{
l.Add(item);
}
l[0].IsCompletedSuccessfully.Should().BeTrue();
l[0].IsFaulted.Should().BeFalse();
l[0].Result.Should().Be(2);
l[1].IsCompletedSuccessfully.Should().BeFalse();
l[1].IsFaulted.Should().BeTrue();
l[1].Exception.Message.Should().Be("ERROR");
l[2].IsCompletedSuccessfully.Should().BeTrue();
l[2].IsFaulted.Should().BeFalse();
l[2].Result.Should().Be(1);
}
async UniTask<int> Delay(int id, int sleep)
{
await Task.Delay(sleep);
return id;
}
async UniTask<int> Delay2(int id, int sleep)
{
await Task.Delay(sleep);
if (id == 3) throw new Exception("ERROR");
return id;
}
}
}

View File

@@ -22,7 +22,9 @@ public static class EditorRunnerChecker
//var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask();
//Debug.Log(r.downloadHandler.text.Substring(0, 100));
await UniTask.Yield();
//await UniTask.Yield();
await UniTask.DelayFrame(30);
Debug.Log("End");
}

View File

@@ -7,6 +7,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace Cysharp.Threading.Tasks
@@ -20,12 +21,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(handle).GetAwaiter();
}
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
return ToUniTask(handle, cancellationToken: cancellationToken);
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately, autoReleaseWhenCanceled: autoReleaseWhenCanceled);
}
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
@@ -44,7 +45,7 @@ namespace Cysharp.Threading.Tasks
return UniTask.CompletedTask;
}
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
}
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
@@ -103,20 +104,23 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
}
readonly Action<AsyncOperationHandle> continuationAction;
readonly Action<AsyncOperationHandle> completedCallback;
AsyncOperationHandle handle;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
IProgress<float> progress;
bool autoReleaseWhenCanceled;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncOperationHandleConfiguredSource()
{
continuationAction = Continuation;
completedCallback = HandleCompleted;
}
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCanceled, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -131,47 +135,81 @@ namespace Cysharp.Threading.Tasks
result.handle = handle;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.autoReleaseWhenCanceled = autoReleaseWhenCanceled;
result.completed = false;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncOperationHandleConfiguredSource)state;
if (promise.autoReleaseWhenCanceled && promise.handle.IsValid())
{
Addressables.Release(promise.handle);
}
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
handle.Completed += result.continuationAction;
handle.Completed += result.completedCallback;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperationHandle _)
void HandleCompleted(AsyncOperationHandle _)
{
handle.Completed -= continuationAction;
if (handle.IsValid())
{
handle.Completed -= completedCallback;
}
if (completed)
{
TryReturn();
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
if (autoReleaseWhenCanceled && handle.IsValid())
{
Addressables.Release(handle);
}
core.TrySetCanceled(cancellationToken);
}
else if (handle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(handle.OperationException);
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else if (handle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(handle.OperationException);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
core.TrySetResult(AsyncUnit.Default);
}
}
public void GetResult(short token)
{
core.GetResult(token);
try
{
core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
public UniTaskStatus GetStatus(short token)
@@ -193,20 +231,23 @@ namespace Cysharp.Threading.Tasks
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
if (autoReleaseWhenCanceled && handle.IsValid())
{
Addressables.Release(handle);
}
core.TrySetCanceled(cancellationToken);
return false;
}
if (progress != null && handle.IsValid())
{
progress.Report(handle.PercentComplete);
progress.Report(handle.GetDownloadStatus().Percent);
}
return true;
@@ -219,6 +260,7 @@ namespace Cysharp.Threading.Tasks
handle = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
@@ -232,12 +274,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(handle).GetAwaiter();
}
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
return ToUniTask(handle, cancellationToken: cancellationToken);
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately, autoReleaseWhenCanceled: autoReleaseWhenCanceled);
}
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
{
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
@@ -255,7 +297,7 @@ namespace Cysharp.Threading.Tasks
return UniTask.FromResult(handle.Result);
}
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
}
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
@@ -269,20 +311,23 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
}
readonly Action<AsyncOperationHandle<T>> continuationAction;
readonly Action<AsyncOperationHandle<T>> completedCallback;
AsyncOperationHandle<T> handle;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
IProgress<float> progress;
bool autoReleaseWhenCanceled;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<T> core;
AsyncOperationHandleConfiguredSource()
{
continuationAction = Continuation;
completedCallback = HandleCompleted;
}
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCanceled, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -298,46 +343,79 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken;
result.completed = false;
result.progress = progress;
result.autoReleaseWhenCanceled = autoReleaseWhenCanceled;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncOperationHandleConfiguredSource<T>)state;
if (promise.autoReleaseWhenCanceled && promise.handle.IsValid())
{
Addressables.Release(promise.handle);
}
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
handle.Completed += result.continuationAction;
handle.Completed += result.completedCallback;
token = result.core.Version;
return result;
}
void Continuation(AsyncOperationHandle<T> argHandle)
void HandleCompleted(AsyncOperationHandle<T> argHandle)
{
handle.Completed -= continuationAction;
if (handle.IsValid())
{
handle.Completed -= completedCallback;
}
if (completed)
{
TryReturn();
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
if (autoReleaseWhenCanceled && handle.IsValid())
{
Addressables.Release(handle);
}
core.TrySetCanceled(cancellationToken);
}
else if (argHandle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(argHandle.OperationException);
}
else
{
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else if (argHandle.Status == AsyncOperationStatus.Failed)
{
core.TrySetException(argHandle.OperationException);
}
else
{
core.TrySetResult(argHandle.Result);
}
core.TrySetResult(argHandle.Result);
}
}
public T GetResult(short token)
{
return core.GetResult(token);
try
{
return core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
void IUniTaskSource.GetResult(short token)
@@ -364,20 +442,23 @@ namespace Cysharp.Threading.Tasks
{
if (completed)
{
TryReturn();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completed = true;
if (autoReleaseWhenCanceled && handle.IsValid())
{
Addressables.Release(handle);
}
core.TrySetCanceled(cancellationToken);
return false;
}
if (progress != null && handle.IsValid())
{
progress.Report(handle.PercentComplete);
progress.Report(handle.GetDownloadStatus().Percent);
}
return true;
@@ -390,6 +471,7 @@ namespace Cysharp.Threading.Tasks
handle = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}

View File

@@ -2,7 +2,8 @@
"name": "UniTask.Addressables",
"references": [
"UniTask",
"Unity.ResourceManager"
"Unity.ResourceManager",
"Unity.Addressables"
],
"includePlatforms": [],
"excludePlatforms": [],
@@ -16,7 +17,12 @@
"name": "com.unity.addressables",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
},
{
"name": "com.unity.addressables.cn",
"expression": "",
"define": "UNITASK_ADDRESSABLE_SUPPORT"
}
],
"noEngineReferences": false
}
}

View File

@@ -16,14 +16,14 @@ namespace Cysharp.Threading.Tasks
Kill,
KillWithCompleteCallback,
Complete,
CompleteWithSeqeunceCallback,
CompleteWithSequenceCallback,
CancelAwait,
// AndCancelAwait
KillAndCancelAwait,
KillWithCompleteCallbackAndCancelAwait,
CompleteAndCancelAwait,
CompleteWithSeqeunceCallbackAndCancelAwait
CompleteWithSequenceCallbackAndCancelAwait
}
public static class DOTweenAsyncExtensions
@@ -143,24 +143,21 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
}
static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onCompleteCallbackDelegate;
readonly TweenCallback onUpdateDelegate;
Tween tween;
TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationRegistration;
CallbackType callbackType;
bool canceled;
TweenCallback originalUpdateAction;
TweenCallback originalCompleteAction;
UniTaskCompletionSourceCore<AsyncUnit> core;
TweenConfiguredSource()
{
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
onUpdateDelegate = OnUpdate;
}
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
@@ -180,41 +177,87 @@ namespace Cysharp.Threading.Tasks
result.cancelBehaviour = cancelBehaviour;
result.cancellationToken = cancellationToken;
result.callbackType = callbackType;
result.originalUpdateAction = tween.onUpdate;
result.canceled = false;
if (result.originalUpdateAction == result.onUpdateDelegate)
{
result.originalUpdateAction = null;
}
tween.onUpdate = result.onUpdateDelegate;
switch (callbackType)
{
case CallbackType.Kill:
result.originalCompleteAction = tween.onKill;
tween.onKill = result.onCompleteCallbackDelegate;
break;
case CallbackType.Complete:
result.originalCompleteAction = tween.onComplete;
tween.onComplete = result.onCompleteCallbackDelegate;
break;
case CallbackType.Pause:
result.originalCompleteAction = tween.onPause;
tween.onPause = result.onCompleteCallbackDelegate;
break;
case CallbackType.Play:
result.originalCompleteAction = tween.onPlay;
tween.onPlay = result.onCompleteCallbackDelegate;
break;
case CallbackType.Rewind:
result.originalCompleteAction = tween.onRewind;
tween.onRewind = result.onCompleteCallbackDelegate;
break;
case CallbackType.StepComplete:
result.originalCompleteAction = tween.onStepComplete;
tween.onStepComplete = result.onCompleteCallbackDelegate;
break;
default:
break;
}
if (result.originalCompleteAction == result.onCompleteCallbackDelegate)
{
result.originalCompleteAction = null;
}
if (cancellationToken.CanBeCanceled)
{
result.cancellationRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(x =>
{
var source = (TweenConfiguredSource)x;
switch (source.cancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
source.tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
source.canceled = true;
source.tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
source.tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
source.canceled = true;
source.tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
source.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
source.canceled = true;
source.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallback:
source.tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
source.canceled = true;
source.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
source.RestoreOriginalCallback();
source.core.TrySetCanceled(source.cancellationToken);
break;
}
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
token = result.core.Version;
@@ -228,7 +271,7 @@ namespace Cysharp.Threading.Tasks
if (this.cancelBehaviour == TweenCancelBehaviour.KillAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait
|| this.cancelBehaviour == TweenCancelBehaviour.CancelAwait)
{
canceled = true;
@@ -240,81 +283,11 @@ namespace Cysharp.Threading.Tasks
}
else
{
originalCompleteAction?.Invoke();
core.TrySetResult(AsyncUnit.Default);
}
}
void OnUpdate()
{
originalUpdateAction?.Invoke();
if (!cancellationToken.IsCancellationRequested)
{
return;
}
switch (this.cancelBehaviour)
{
case TweenCancelBehaviour.Kill:
default:
this.tween.Kill(false);
break;
case TweenCancelBehaviour.KillAndCancelAwait:
this.canceled = true;
this.tween.Kill(false);
break;
case TweenCancelBehaviour.KillWithCompleteCallback:
this.tween.Kill(true);
break;
case TweenCancelBehaviour.KillWithCompleteCallbackAndCancelAwait:
this.canceled = true;
this.tween.Kill(true);
break;
case TweenCancelBehaviour.Complete:
this.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteAndCancelAwait:
this.canceled = true;
this.tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
this.tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
this.canceled = true;
this.tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
// replace to empty(avoid callback after Canceled(instance is returned to pool.)
switch (callbackType)
{
case CallbackType.Kill:
tween.onKill = EmptyTweenCallback;
break;
case CallbackType.Complete:
tween.onComplete = EmptyTweenCallback;
break;
case CallbackType.Pause:
tween.onPause = EmptyTweenCallback;
break;
case CallbackType.Play:
tween.onPlay = EmptyTweenCallback;
break;
case CallbackType.Rewind:
tween.onRewind = EmptyTweenCallback;
break;
case CallbackType.StepComplete:
tween.onStepComplete = EmptyTweenCallback;
break;
default:
break;
}
this.core.TrySetCanceled(this.cancellationToken);
break;
}
}
static void DoCancelBeforeCreate(Tween tween, TweenCancelBehaviour tweenCancelBehaviour)
{
@@ -339,10 +312,10 @@ namespace Cysharp.Threading.Tasks
case TweenCancelBehaviour.CompleteAndCancelAwait:
tween.Complete(false);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallback:
case TweenCancelBehaviour.CompleteWithSequenceCallback:
tween.Complete(true);
break;
case TweenCancelBehaviour.CompleteWithSeqeunceCallbackAndCancelAwait:
case TweenCancelBehaviour.CompleteWithSequenceCallbackAndCancelAwait:
tween.Complete(true);
break;
case TweenCancelBehaviour.CancelAwait:
@@ -381,36 +354,41 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
tween.onUpdate = originalUpdateAction;
cancellationRegistration.Dispose();
RestoreOriginalCallback();
tween = default;
cancellationToken = default;
originalCompleteAction = default;
return pool.TryPush(this);
}
void RestoreOriginalCallback()
{
switch (callbackType)
{
case CallbackType.Kill:
tween.onKill = null;
tween.onKill = originalCompleteAction;
break;
case CallbackType.Complete:
tween.onComplete = null;
tween.onComplete = originalCompleteAction;
break;
case CallbackType.Pause:
tween.onPause = null;
tween.onPause = originalCompleteAction;
break;
case CallbackType.Play:
tween.onPlay = null;
tween.onPlay = originalCompleteAction;
break;
case CallbackType.Rewind:
tween.onRewind = null;
tween.onRewind = originalCompleteAction;
break;
case CallbackType.StepComplete:
tween.onStepComplete = null;
tween.onStepComplete = originalCompleteAction;
break;
default:
break;
}
tween = default;
cancellationToken = default;
originalUpdateAction = default;
return pool.TryPush(this);
}
}
}

View File

@@ -16,7 +16,12 @@
"name": "com.unity.textmeshpro",
"expression": "",
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
},
{
"name": "com.unity.ugui",
"expression": "2.0.0",
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
}
],
"noEngineReferences": false
}
}

View File

@@ -1,4 +1,9 @@
#pragma warning disable CS1591
#pragma warning disable CS0108
#if (UNITASK_NETCORE && !NETSTANDARD2_0) || UNITY_2022_3_OR_NEWER
#define SUPPORT_VALUETASK
#endif
using System;
using System.Runtime.CompilerServices;
@@ -19,9 +24,8 @@ namespace Cysharp.Threading.Tasks
// similar as IValueTaskSource
public interface IUniTaskSource
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
#if SUPPORT_VALUETASK
: System.Threading.Tasks.Sources.IValueTaskSource
#pragma warning disable CS0108
#endif
{
UniTaskStatus GetStatus(short token);
@@ -30,8 +34,7 @@ namespace Cysharp.Threading.Tasks
UniTaskStatus UnsafeGetStatus(); // only for debug use.
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
#pragma warning restore CS0108
#if SUPPORT_VALUETASK
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
{
@@ -53,13 +56,13 @@ namespace Cysharp.Threading.Tasks
}
public interface IUniTaskSource<out T> : IUniTaskSource
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
#if SUPPORT_VALUETASK
, System.Threading.Tasks.Sources.IValueTaskSource<T>
#endif
{
new T GetResult(short token);
#if !UNITY_2018_3_OR_NEWER && !NETSTANDARD2_0
#if SUPPORT_VALUETASK
new public UniTaskStatus GetStatus(short token)
{

View File

@@ -148,7 +148,7 @@ namespace Cysharp.Threading.Tasks.Internal
foreach (var candidateMethod in methods)
{
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>();
var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>(false);
if (attributes == null)
{
continue;

View File

@@ -39,7 +39,7 @@ namespace Cysharp.Threading.Tasks.Internal
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowArgumentException<T>(string message)
public static void ThrowArgumentException(string message)
{
throw new ArgumentException(message);
}

View File

@@ -52,6 +52,7 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
writer.Dispose();
return default;
}
@@ -127,7 +128,7 @@ namespace Cysharp.Threading.Tasks.Linq
}
}
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>, IDisposable
{
readonly _Create enumerator;
@@ -137,6 +138,15 @@ namespace Cysharp.Threading.Tasks.Linq
{
this.enumerator = enumerator;
}
public void Dispose()
{
var status = core.GetStatus(core.Version);
if (status == UniTaskStatus.Pending)
{
core.TrySetCanceled();
}
}
public void GetResult(short token)
{

View File

@@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
return new Merge<T>(new [] { first, second });
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IUniTaskAsyncEnumerable<T> first, IUniTaskAsyncEnumerable<T> second, IUniTaskAsyncEnumerable<T> third)
{
Error.ThrowArgumentNullException(first, nameof(first));
Error.ThrowArgumentNullException(second, nameof(second));
Error.ThrowArgumentNullException(third, nameof(third));
return new Merge<T>(new[] { first, second, third });
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IEnumerable<IUniTaskAsyncEnumerable<T>> sources)
{
return sources is IUniTaskAsyncEnumerable<T>[] array
? new Merge<T>(array)
: new Merge<T>(sources.ToArray());
}
public static IUniTaskAsyncEnumerable<T> Merge<T>(params IUniTaskAsyncEnumerable<T>[] sources)
{
return new Merge<T>(sources);
}
}
internal sealed class Merge<T> : IUniTaskAsyncEnumerable<T>
{
readonly IUniTaskAsyncEnumerable<T>[] sources;
public Merge(IUniTaskAsyncEnumerable<T>[] sources)
{
if (sources.Length <= 0)
{
Error.ThrowArgumentException("No source async enumerable to merge");
}
this.sources = sources;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
=> new _Merge(sources, cancellationToken);
enum MergeSourceState
{
Pending,
Running,
Completed,
}
sealed class _Merge : MoveNextSource, IUniTaskAsyncEnumerator<T>
{
static readonly Action<object> GetResultAtAction = GetResultAt;
readonly int length;
readonly IUniTaskAsyncEnumerator<T>[] enumerators;
readonly MergeSourceState[] states;
readonly Queue<(T, Exception, bool)> queuedResult = new Queue<(T, Exception, bool)>();
readonly CancellationToken cancellationToken;
int moveNextCompleted;
public T Current { get; private set; }
public _Merge(IUniTaskAsyncEnumerable<T>[] sources, CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
length = sources.Length;
states = ArrayPool<MergeSourceState>.Shared.Rent(length);
enumerators = ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Rent(length);
for (var i = 0; i < length; i++)
{
enumerators[i] = sources[i].GetAsyncEnumerator(cancellationToken);
states[i] = (int)MergeSourceState.Pending;;
}
}
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
completionSource.Reset();
Interlocked.Exchange(ref moveNextCompleted, 0);
if (HasQueuedResult() && Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
(T, Exception, bool) value;
lock (states)
{
value = queuedResult.Dequeue();
}
var resultValue = value.Item1;
var exception = value.Item2;
var hasNext = value.Item3;
if (exception != null)
{
completionSource.TrySetException(exception);
}
else
{
Current = resultValue;
completionSource.TrySetResult(hasNext);
}
return new UniTask<bool>(this, completionSource.Version);
}
for (var i = 0; i < length; i++)
{
lock (states)
{
if (states[i] == MergeSourceState.Pending)
{
states[i] = MergeSourceState.Running;
}
else
{
continue;
}
}
var awaiter = enumerators[i].MoveNextAsync().GetAwaiter();
if (awaiter.IsCompleted)
{
GetResultAt(i, awaiter);
}
else
{
awaiter.SourceOnCompleted(GetResultAtAction, StateTuple.Create(this, i, awaiter));
}
}
return new UniTask<bool>(this, completionSource.Version);
}
public async UniTask DisposeAsync()
{
for (var i = 0; i < length; i++)
{
await enumerators[i].DisposeAsync();
}
ArrayPool<MergeSourceState>.Shared.Return(states, true);
ArrayPool<IUniTaskAsyncEnumerator<T>>.Shared.Return(enumerators, true);
}
static void GetResultAt(object state)
{
using (var tuple = (StateTuple<_Merge, int, UniTask<bool>.Awaiter>)state)
{
tuple.Item1.GetResultAt(tuple.Item2, tuple.Item3);
}
}
void GetResultAt(int index, UniTask<bool>.Awaiter awaiter)
{
bool hasNext;
bool completedAll;
try
{
hasNext = awaiter.GetResult();
}
catch (Exception ex)
{
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
completionSource.TrySetException(ex);
}
else
{
lock (states)
{
queuedResult.Enqueue((default, ex, default));
}
}
return;
}
lock (states)
{
states[index] = hasNext ? MergeSourceState.Pending : MergeSourceState.Completed;
completedAll = !hasNext && IsCompletedAll();
}
if (hasNext || completedAll)
{
if (Interlocked.CompareExchange(ref moveNextCompleted, 1, 0) == 0)
{
Current = enumerators[index].Current;
completionSource.TrySetResult(!completedAll);
}
else
{
lock (states)
{
queuedResult.Enqueue((enumerators[index].Current, null, !completedAll));
}
}
}
}
bool HasQueuedResult()
{
lock (states)
{
return queuedResult.Count > 0;
}
}
bool IsCompletedAll()
{
lock (states)
{
for (var i = 0; i < length; i++)
{
if (states[i] != MergeSourceState.Completed)
{
return false;
}
}
}
return true;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ca56812f160c45d0bacb4339819edf1a
timeCreated: 1694133666

View File

@@ -4,38 +4,50 @@ namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{
return new EveryUpdate(updateTiming);
return new EveryUpdate(updateTiming, cancelImmediately);
}
}
internal class EveryUpdate : IUniTaskAsyncEnumerable<AsyncUnit>
{
readonly PlayerLoopTiming updateTiming;
readonly bool cancelImmediately;
public EveryUpdate(PlayerLoopTiming updateTiming)
public EveryUpdate(PlayerLoopTiming updateTiming, bool cancelImmediately)
{
this.updateTiming = updateTiming;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _EveryUpdate(updateTiming, cancellationToken);
return new _EveryUpdate(updateTiming, cancellationToken, cancelImmediately);
}
class _EveryUpdate : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{
readonly PlayerLoopTiming updateTiming;
CancellationToken cancellationToken;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
bool disposed;
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
{
this.updateTiming = updateTiming;
this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryUpdate)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
}
@@ -44,10 +56,14 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
if (disposed) return CompletedTasks.False;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
}
return new UniTask<bool>(this, completionSource.Version);
}
@@ -55,6 +71,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -63,7 +80,13 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || cancellationToken.IsCancellationRequested)
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
if (disposed)
{
completionSource.TrySetResult(false);
return false;

View File

@@ -7,7 +7,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null)
public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null, bool cancelImmediately = false)
where TTarget : class
{
var unityObject = target as UnityEngine.Object;
@@ -15,11 +15,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (isUnityObject)
{
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
}
else
{
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
}
}
}
@@ -30,18 +30,20 @@ namespace Cysharp.Threading.Tasks.Linq
readonly Func<TTarget, TProperty> propertySelector;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly PlayerLoopTiming monitorTiming;
readonly bool cancelImmediately;
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
{
this.target = target;
this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer;
this.monitorTiming = monitorTiming;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
}
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
@@ -50,13 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
readonly UnityEngine.Object targetAsUnityObject;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly Func<TTarget, TProperty> propertySelector;
CancellationToken cancellationToken;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
bool first;
TProperty currentValue;
bool disposed;
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
{
this.target = target;
this.targetAsUnityObject = target as UnityEngine.Object;
@@ -64,6 +67,16 @@ namespace Cysharp.Threading.Tasks.Linq
this.equalityComparer = equalityComparer;
this.cancellationToken = cancellationToken;
this.first = true;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryValueChanged)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(monitorTiming, this);
}
@@ -72,8 +85,15 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
if (disposed) return CompletedTasks.False;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return new UniTask<bool>(this, completionSource.Version);
}
if (first)
{
@@ -86,7 +106,6 @@ namespace Cysharp.Threading.Tasks.Linq
return CompletedTasks.True;
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -94,6 +113,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -102,13 +122,18 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || cancellationToken.IsCancellationRequested || targetAsUnityObject == null) // destroyed = cancel.
if (disposed || targetAsUnityObject == null)
{
completionSource.TrySetResult(false);
DisposeAsync().Forget();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
TProperty nextValue = default(TProperty);
try
{
@@ -139,18 +164,20 @@ namespace Cysharp.Threading.Tasks.Linq
readonly Func<TTarget, TProperty> propertySelector;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly PlayerLoopTiming monitorTiming;
readonly bool cancelImmediately;
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
{
this.target = new WeakReference<TTarget>(target, false);
this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer;
this.monitorTiming = monitorTiming;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
}
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
@@ -158,19 +185,30 @@ namespace Cysharp.Threading.Tasks.Linq
readonly WeakReference<TTarget> target;
readonly IEqualityComparer<TProperty> equalityComparer;
readonly Func<TTarget, TProperty> propertySelector;
CancellationToken cancellationToken;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
bool first;
TProperty currentValue;
bool disposed;
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
{
this.target = target;
this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer;
this.cancellationToken = cancellationToken;
this.first = true;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryValueChanged)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(monitorTiming, this);
}
@@ -179,8 +217,16 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
if (disposed) return CompletedTasks.False;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return new UniTask<bool>(this, completionSource.Version);
}
if (first)
{
first = false;
@@ -192,7 +238,6 @@ namespace Cysharp.Threading.Tasks.Linq
return CompletedTasks.True;
}
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -200,6 +245,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -208,13 +254,19 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
if (disposed || !target.TryGetTarget(out var t))
{
completionSource.TrySetResult(false);
DisposeAsync().Forget();
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
TProperty nextValue = default(TProperty);
try
{

View File

@@ -6,32 +6,32 @@ namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
{
return new Timer(dueTime, null, updateTiming, ignoreTimeScale);
return new Timer(dueTime, null, updateTiming, ignoreTimeScale, cancelImmediately);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
{
return new Timer(dueTime, period, updateTiming, ignoreTimeScale);
return new Timer(dueTime, period, updateTiming, ignoreTimeScale, cancelImmediately);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false)
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
{
return new Timer(period, period, updateTiming, ignoreTimeScale);
return new Timer(period, period, updateTiming, ignoreTimeScale, cancelImmediately);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{
if (dueTimeFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount);
}
return new TimerFrame(dueTimeFrameCount, null, updateTiming);
return new TimerFrame(dueTimeFrameCount, null, updateTiming, cancelImmediately);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{
if (dueTimeFrameCount < 0)
{
@@ -42,16 +42,16 @@ namespace Cysharp.Threading.Tasks.Linq
throw new ArgumentOutOfRangeException("Delay does not allow minus periodFrameCount. periodFrameCount:" + dueTimeFrameCount);
}
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming);
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancelImmediately);
}
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update)
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{
if (intervalFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus intervalFrameCount. intervalFrameCount:" + intervalFrameCount);
}
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming);
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming, cancelImmediately);
}
}
@@ -61,18 +61,20 @@ namespace Cysharp.Threading.Tasks.Linq
readonly TimeSpan dueTime;
readonly TimeSpan? period;
readonly bool ignoreTimeScale;
readonly bool cancelImmediately;
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale)
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, bool cancelImmediately)
{
this.updateTiming = updateTiming;
this.dueTime = dueTime;
this.period = period;
this.ignoreTimeScale = ignoreTimeScale;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken);
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken, cancelImmediately);
}
class _Timer : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
@@ -81,7 +83,8 @@ namespace Cysharp.Threading.Tasks.Linq
readonly float? period;
readonly PlayerLoopTiming updateTiming;
readonly bool ignoreTimeScale;
CancellationToken cancellationToken;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
int initialFrame;
float elapsed;
@@ -89,7 +92,7 @@ namespace Cysharp.Threading.Tasks.Linq
bool completed;
bool disposed;
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken)
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken, bool cancelImmediately)
{
this.dueTime = (float)dueTime.TotalSeconds;
this.period = (period == null) ? null : (float?)period.Value.TotalSeconds;
@@ -105,6 +108,16 @@ namespace Cysharp.Threading.Tasks.Linq
this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale;
this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_Timer)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
}
@@ -114,12 +127,16 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested || completed) return CompletedTasks.False;
if (disposed || completed) return CompletedTasks.False;
// reset value here.
this.elapsed = 0;
completionSource.Reset();
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
}
return new UniTask<bool>(this, completionSource.Version);
}
@@ -127,6 +144,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -135,11 +153,16 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || cancellationToken.IsCancellationRequested)
if (disposed)
{
completionSource.TrySetResult(false);
return false;
}
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
if (dueTimePhase)
{
@@ -187,24 +210,27 @@ namespace Cysharp.Threading.Tasks.Linq
readonly PlayerLoopTiming updateTiming;
readonly int dueTimeFrameCount;
readonly int? periodFrameCount;
readonly bool cancelImmediately;
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming)
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, bool cancelImmediately)
{
this.updateTiming = updateTiming;
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
this.cancelImmediately = cancelImmediately;
}
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken);
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken, cancelImmediately);
}
class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{
readonly int dueTimeFrameCount;
readonly int? periodFrameCount;
CancellationToken cancellationToken;
readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
int initialFrame;
int currentFrame;
@@ -212,7 +238,7 @@ namespace Cysharp.Threading.Tasks.Linq
bool completed;
bool disposed;
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
{
if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0;
if (periodFrameCount != null)
@@ -225,6 +251,15 @@ namespace Cysharp.Threading.Tasks.Linq
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_TimerFrame)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
@@ -234,13 +269,15 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask<bool> MoveNextAsync()
{
// return false instead of throw
if (disposed || cancellationToken.IsCancellationRequested || completed) return CompletedTasks.False;
if (disposed || completed) return CompletedTasks.False;
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
}
// reset value here.
this.currentFrame = 0;
completionSource.Reset();
return new UniTask<bool>(this, completionSource.Version);
}
@@ -249,6 +286,7 @@ namespace Cysharp.Threading.Tasks.Linq
{
if (!disposed)
{
cancellationTokenRegistration.Dispose();
disposed = true;
TaskTracker.RemoveTracking(this);
}
@@ -257,7 +295,12 @@ namespace Cysharp.Threading.Tasks.Linq
public bool MoveNext()
{
if (disposed || cancellationToken.IsCancellationRequested)
if (cancellationToken.IsCancellationRequested)
{
completionSource.TrySetCanceled(cancellationToken);
return false;
}
if (disposed)
{
completionSource.TrySetResult(false);
return false;

View File

@@ -285,7 +285,11 @@ namespace Cysharp.Threading.Tasks
return dest.ToArray();
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
#if UNITY_2020_1_OR_NEWER
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
#else
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
#endif
static void Init()
{
// capture default(unity) sync-context.
@@ -524,6 +528,14 @@ namespace Cysharp.Threading.Tasks
{
sb.AppendFormat("------{0}------", header.type.Name);
sb.AppendLine();
if (header.subSystemList is null)
{
sb.AppendFormat("{0} has no subsystems!", header.ToString());
sb.AppendLine();
continue;
}
foreach (var subSystem in header.subSystemList)
{
sb.AppendFormat("{0}", subSystem.type.Name);
@@ -545,6 +557,11 @@ namespace Cysharp.Threading.Tasks
foreach (var header in playerLoop.subSystemList)
{
if (header.subSystemList is null)
{
continue;
}
foreach (var subSystem in header.subSystemList)
{
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))

View File

@@ -7,7 +7,7 @@ using System.Threading;
namespace Cysharp.Threading.Tasks
{
// internaly used but public, allow to user create custom operator with pooling.
// internally used but public, allow to user create custom operator with pooling.
public static class TaskPool
{

View File

@@ -99,7 +99,7 @@ namespace Cysharp.Threading.Tasks
public void Reset()
{
timer.Stop();
timer?.Stop();
}
public void Dispose()
@@ -109,7 +109,7 @@ namespace Cysharp.Threading.Tasks
try
{
// stop timer.
timer.Dispose();
timer?.Dispose();
// cancel and dispose.
timeoutSource.Cancel();

View File

@@ -20,8 +20,6 @@ namespace Cysharp.Threading.Tasks
{
ITriggerHandler<T> head; // head.prev is last
ITriggerHandler<T> iteratingHead;
bool preserveRemoveSelf;
ITriggerHandler<T> iteratingNode;
void LogError(Exception ex)
@@ -55,18 +53,9 @@ namespace Cysharp.Threading.Tasks
Remove(h);
}
if (preserveRemoveSelf)
{
preserveRemoveSelf = false;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
else
{
h = h.Next;
}
// If `h` itself is removed by OnNext, h.Next is null.
// Therefore, instead of looking at h.Next, the `iteratingNode` reference itself is replaced.
h = h == iteratingNode ? h.Next : iteratingNode;
}
iteratingNode = null;
@@ -97,9 +86,8 @@ namespace Cysharp.Threading.Tasks
LogError(ex);
}
preserveRemoveSelf = false;
var next = h == iteratingNode ? h.Next : iteratingNode;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
@@ -132,9 +120,8 @@ namespace Cysharp.Threading.Tasks
LogError(ex);
}
preserveRemoveSelf = false;
var next = h == iteratingNode ? h.Next : iteratingNode;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
@@ -167,9 +154,8 @@ namespace Cysharp.Threading.Tasks
LogError(ex);
}
preserveRemoveSelf = false;
var next = h == iteratingNode ? h.Next : iteratingNode;
iteratingNode = null;
var next = h.Next;
Remove(h);
h = next;
}
@@ -241,71 +227,65 @@ namespace Cysharp.Threading.Tasks
{
if (handler == null) throw new ArgumentNullException(nameof(handler));
if (iteratingNode != null && iteratingNode == handler)
var prev = handler.Prev;
var next = handler.Next;
if (next != null)
{
// if remove self, reserve remove self after invoke completed.
preserveRemoveSelf = true;
next.Prev = prev;
}
else
if (handler == head)
{
var prev = handler.Prev;
var next = handler.Next;
if (next != null)
{
next.Prev = prev;
}
if (handler == head)
{
head = next;
}
else if (handler == iteratingHead)
{
iteratingHead = next;
}
else
{
// when handler is head, prev indicate last so don't use it.
if (prev != null)
{
prev.Next = next;
}
}
if (head != null)
{
if (head.Prev == handler)
{
if (prev != head)
{
head.Prev = prev;
}
else
{
head.Prev = null;
}
}
}
if (iteratingHead != null)
{
if (iteratingHead.Prev == handler)
{
if (prev != iteratingHead.Prev)
{
iteratingHead.Prev = prev;
}
else
{
iteratingHead.Prev = null;
}
}
}
handler.Prev = null;
handler.Next = null;
head = next;
}
// when handler is head, prev indicate last so don't use it.
else if (prev != null)
{
prev.Next = next;
}
if (handler == iteratingNode)
{
iteratingNode = next;
}
if (handler == iteratingHead)
{
iteratingHead = next;
}
if (head != null)
{
if (head.Prev == handler)
{
if (prev != head)
{
head.Prev = prev;
}
else
{
head.Prev = null;
}
}
}
if (iteratingHead != null)
{
if (iteratingHead.Prev == handler)
{
if (prev != iteratingHead.Prev)
{
iteratingHead.Prev = prev;
}
else
{
iteratingHead.Prev = null;
}
}
}
handler.Prev = null;
handler.Next = null;
}
}
}

View File

@@ -32,13 +32,11 @@ namespace Cysharp.Threading.Tasks.Triggers
if (cancellationTokenSource == null)
{
cancellationTokenSource = new CancellationTokenSource();
if (!awakeCalled)
{
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
}
}
if (!awakeCalled)
{
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
}
return cancellationTokenSource.Token;
}
}
@@ -83,7 +81,7 @@ namespace Cysharp.Threading.Tasks.Triggers
public bool MoveNext()
{
if (trigger.called) return false;
if (trigger.called || trigger.awakeCalled) return false;
if (trigger == null)
{
trigger.OnDestroy();

View File

@@ -8,6 +8,16 @@ namespace Cysharp.Threading.Tasks
{
public static class UniTaskCancellationExtensions
{
#if UNITY_2022_2_OR_NEWER
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this MonoBehaviour monoBehaviour)
{
return monoBehaviour.destroyCancellationToken;
}
#endif
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this GameObject gameObject)
{
@@ -17,6 +27,13 @@ namespace Cysharp.Threading.Tasks
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this Component component)
{
#if UNITY_2022_2_OR_NEWER
if (component is MonoBehaviour mb)
{
return mb.destroyCancellationToken;
}
#endif
return component.GetAsyncDestroyTrigger().CancellationToken;
}
}

View File

@@ -1,5 +1,11 @@
#pragma warning disable 0649
#if UNITASK_NETCORE || UNITY_2022_3_OR_NEWER
#define SUPPORT_VALUETASK
#endif
#if SUPPORT_VALUETASK
using System;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
@@ -10,7 +16,7 @@ namespace Cysharp.Threading.Tasks
{
public static ValueTask AsValueTask(this in UniTask task)
{
#if NETSTANDARD2_0
#if (UNITASK_NETCORE && NETSTANDARD2_0)
return new ValueTask(new UniTaskValueTaskSource(task), 0);
#else
return task;
@@ -19,7 +25,7 @@ namespace Cysharp.Threading.Tasks
public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task)
{
#if NETSTANDARD2_0
#if (UNITASK_NETCORE && NETSTANDARD2_0)
return new ValueTask<T>(new UniTaskValueTaskSource<T>(task), 0);
#else
return task;
@@ -36,7 +42,7 @@ namespace Cysharp.Threading.Tasks
await task;
}
#if NETSTANDARD2_0
#if (UNITASK_NETCORE && NETSTANDARD2_0)
class UniTaskValueTaskSource : IValueTaskSource
{
@@ -95,3 +101,4 @@ namespace Cysharp.Threading.Tasks
#endif
}
}
#endif

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8760bbbab905a534eb6fb7b61b736926
guid: d38f0478933be42d895c37b862540a1c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -2,6 +2,7 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Threading;
using UnityEngine;
@@ -32,14 +33,14 @@ namespace Cysharp.Threading.Tasks
return new YieldAwaitable(timing);
}
public static UniTask Yield(CancellationToken cancellationToken)
public static UniTask Yield(CancellationToken cancellationToken, bool cancelImmediately = false)
{
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token);
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken)
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
{
return new UniTask(YieldPromise.Create(timing, cancellationToken, out var token), token);
return new UniTask(YieldPromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
}
/// <summary>
@@ -47,7 +48,7 @@ namespace Cysharp.Threading.Tasks
/// </summary>
public static UniTask NextFrame()
{
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, out var token), token);
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, false, out var token), token);
}
/// <summary>
@@ -55,87 +56,113 @@ namespace Cysharp.Threading.Tasks
/// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing)
{
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, out var token), token);
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, false, out var token), token);
}
/// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary>
public static UniTask NextFrame(CancellationToken cancellationToken)
public static UniTask NextFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
{
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token);
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
}
/// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken)
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
{
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token);
return new UniTask(NextFramePromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate).
/// </summary>
#if UNITY_2023_1_OR_NEWER
public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToken = default)
{
await Awaitable.EndOfFrameAsync(cancellationToken);
}
#else
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static YieldAwaitable WaitForEndOfFrame()
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken).
/// </summary>
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken)
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken);
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
}
#endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
{
var source = WaitForEndOfFramePromise.Create(coroutineRunner, CancellationToken.None, false, out var token);
return new UniTask(source, token);
}
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately = false)
{
var source = WaitForEndOfFramePromise.Create(coroutineRunner, cancellationToken, cancelImmediately, out var token);
return new UniTask(source, token);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate).
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate).
/// </summary>
public static YieldAwaitable WaitForFixedUpdate()
{
return UniTask.Yield(PlayerLoopTiming.FixedUpdate);
// use LastFixedUpdate instead of FixedUpdate
// https://github.com/Cysharp/UniTask/issues/377
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate);
}
/// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken).
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken).
/// </summary>
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken)
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken, bool cancelImmediately = false)
{
return UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken);
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken, cancelImmediately);
}
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask WaitForSeconds(float duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return Delay(Mathf.RoundToInt(1000 * duration), ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask WaitForSeconds(int duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return Delay(1000 * duration, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
if (delayFrameCount < 0)
{
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. delayFrameCount:" + delayFrameCount);
}
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, out var token), token);
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken);
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
}
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
if (delayTimeSpan < TimeSpan.Zero)
{
@@ -154,16 +181,16 @@ namespace Cysharp.Threading.Tasks
{
case DelayType.UnscaledDeltaTime:
{
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
}
case DelayType.Realtime:
{
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
}
case DelayType.DeltaTime:
default:
{
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
}
}
}
@@ -180,13 +207,15 @@ namespace Cysharp.Threading.Tasks
}
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
YieldPromise()
{
}
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -198,8 +227,17 @@ namespace Cysharp.Threading.Tasks
result = new YieldPromise();
}
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (YieldPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -217,7 +255,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -253,6 +298,8 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
@@ -269,14 +316,16 @@ namespace Cysharp.Threading.Tasks
}
int frameCount;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<AsyncUnit> core;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
NextFramePromise()
{
}
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -290,6 +339,16 @@ namespace Cysharp.Threading.Tasks
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (NextFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -307,7 +366,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -348,10 +414,138 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
}
sealed class WaitForEndOfFramePromise : IUniTaskSource, ITaskPoolNode<WaitForEndOfFramePromise>, System.Collections.IEnumerator
{
static TaskPool<WaitForEndOfFramePromise> pool;
WaitForEndOfFramePromise nextNode;
public ref WaitForEndOfFramePromise NextNode => ref nextNode;
static WaitForEndOfFramePromise()
{
TaskPool.RegisterSizeGetter(typeof(WaitForEndOfFramePromise), () => pool.Size);
}
UniTaskCompletionSourceCore<object> core;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
WaitForEndOfFramePromise()
{
}
public static IUniTaskSource Create(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitForEndOfFramePromise();
}
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitForEndOfFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
coroutineRunner.StartCoroutine(result);
token = result.core.Version;
return result;
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
Reset(); // Reset Enumerator
cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this);
}
// Coroutine Runner implementation
static readonly WaitForEndOfFrame waitForEndOfFrameYieldInstruction = new WaitForEndOfFrame();
bool isFirst = true;
object IEnumerator.Current => waitForEndOfFrameYieldInstruction;
bool IEnumerator.MoveNext()
{
if (isFirst)
{
isFirst = false;
return true; // start WaitForEndOfFrame
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
core.TrySetResult(null);
return false;
}
public void Reset()
{
isFirst = true;
}
}
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
{
static TaskPool<DelayFramePromise> pool;
@@ -366,6 +560,8 @@ namespace Cysharp.Threading.Tasks
int initialFrame;
int delayFrameCount;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
int currentFrameCount;
UniTaskCompletionSourceCore<AsyncUnit> core;
@@ -374,7 +570,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -389,6 +585,16 @@ namespace Cysharp.Threading.Tasks
result.delayFrameCount = delayFrameCount;
result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -406,7 +612,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -444,7 +657,19 @@ namespace Cysharp.Threading.Tasks
// skip in initial frame.
if (initialFrame == Time.frameCount)
{
#if UNITY_EDITOR
// force use Realtime.
if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying)
{
//goto ++currentFrameCount
}
else
{
return true;
}
#else
return true;
#endif
}
}
@@ -464,6 +689,8 @@ namespace Cysharp.Threading.Tasks
currentFrameCount = default;
delayFrameCount = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
@@ -483,6 +710,8 @@ namespace Cysharp.Threading.Tasks
float delayTimeSpan;
float elapsed;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
@@ -490,7 +719,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -506,6 +735,16 @@ namespace Cysharp.Threading.Tasks
result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -523,7 +762,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -575,6 +821,8 @@ namespace Cysharp.Threading.Tasks
delayTimeSpan = default;
elapsed = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
@@ -594,6 +842,8 @@ namespace Cysharp.Threading.Tasks
float elapsed;
int initialFrame;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
@@ -601,7 +851,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -617,6 +867,16 @@ namespace Cysharp.Threading.Tasks
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayIgnoreTimeScalePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -634,7 +894,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -686,6 +953,8 @@ namespace Cysharp.Threading.Tasks
delayFrameTimeSpan = default;
elapsed = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
@@ -704,6 +973,8 @@ namespace Cysharp.Threading.Tasks
long delayTimeSpanTicks;
ValueStopwatch stopwatch;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<AsyncUnit> core;
@@ -711,7 +982,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -726,6 +997,16 @@ namespace Cysharp.Threading.Tasks
result.stopwatch = ValueStopwatch.StartNew();
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayRealtimePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -743,7 +1024,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -791,6 +1079,8 @@ namespace Cysharp.Threading.Tasks
core.Reset();
stopwatch = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}

View File

@@ -81,6 +81,16 @@ namespace Cysharp.Threading.Tasks
return factory();
}
public static UniTask Create(Func<CancellationToken, UniTask> factory, CancellationToken cancellationToken)
{
return factory(cancellationToken);
}
public static UniTask Create<T>(T state, Func<T, UniTask> factory)
{
return factory(state);
}
public static UniTask<T> Create<T>(Func<UniTask<T>> factory)
{
return factory();
@@ -137,11 +147,19 @@ namespace Cysharp.Threading.Tasks
return () => asyncAction(cancellationToken).Forget();
}
/// <summary>
/// helper of create add UniTaskVoid to delegate.
/// </summary>
public static Action Action<T>(T state, Func<T, UniTaskVoid> asyncAction)
{
return () => asyncAction(state).Forget();
}
#if UNITY_2018_3_OR_NEWER
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For exampe: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
/// For example: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction UnityAction(Func<UniTaskVoid> asyncAction)
{
@@ -150,13 +168,94 @@ namespace Cysharp.Threading.Tasks
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For exampe: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
/// For example: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
/// </summary>
public static UnityEngine.Events.UnityAction UnityAction(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
{
return () => asyncAction(cancellationToken).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(FooAsync, Argument))
/// </summary>
public static UnityEngine.Events.UnityAction UnityAction<T>(T state, Func<T, UniTaskVoid> asyncAction)
{
return () => asyncAction(state).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T arg) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T> UnityAction<T>(Func<T, UniTaskVoid> asyncAction)
{
return (arg) => asyncAction(arg).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T0, T1> UnityAction<T0, T1>(Func<T0, T1, UniTaskVoid> asyncAction)
{
return (arg0, arg1) => asyncAction(arg0, arg1).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T0, T1, T2> UnityAction<T0, T1, T2>(Func<T0, T1, T2, UniTaskVoid> asyncAction)
{
return (arg0, arg1, arg2) => asyncAction(arg0, arg1, arg2).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, T3 arg3) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T0, T1, T2, T3> UnityAction<T0, T1, T2, T3>(Func<T0, T1, T2, T3, UniTaskVoid> asyncAction)
{
return (arg0, arg1, arg2, arg3) => asyncAction(arg0, arg1, arg2, arg3).Forget();
}
// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T arg, CancellationToken cancellationToken) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T> UnityAction<T>(Func<T, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
{
return (arg) => asyncAction(arg, cancellationToken).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, CancellationToken cancellationToken) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T0, T1> UnityAction<T0, T1>(Func<T0, T1, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
{
return (arg0, arg1) => asyncAction(arg0, arg1, cancellationToken).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, CancellationToken cancellationToken) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T0, T1, T2> UnityAction<T0, T1, T2>(Func<T0, T1, T2, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
{
return (arg0, arg1, arg2) => asyncAction(arg0, arg1, arg2, cancellationToken).Forget();
}
/// <summary>
/// Create async void(UniTaskVoid) UnityAction.
/// For example: onClick.AddListener(UniTask.UnityAction(async (T0 arg0, T1 arg1, T2 arg2, T3 arg3, CancellationToken cancellationToken) => { /* */ } ))
/// </summary>
public static UnityEngine.Events.UnityAction<T0, T1, T2, T3> UnityAction<T0, T1, T2, T3>(Func<T0, T1, T2, T3, CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
{
return (arg0, arg1, arg2, arg3) => asyncAction(arg0, arg1, arg2, arg3, cancellationToken).Forget();
}
#endif
/// <summary>
@@ -175,6 +274,22 @@ namespace Cysharp.Threading.Tasks
return new UniTask<T>(new DeferPromise<T>(factory), 0);
}
/// <summary>
/// Defer the task creation just before call await.
/// </summary>
public static UniTask Defer<TState>(TState state, Func<TState, UniTask> factory)
{
return new UniTask(new DeferPromiseWithState<TState>(state, factory), 0);
}
/// <summary>
/// Defer the task creation just before call await.
/// </summary>
public static UniTask<TResult> Defer<TState, TResult>(TState state, Func<TState, UniTask<TResult>> factory)
{
return new UniTask<TResult>(new DeferPromiseWithState<TState, TResult>(state, factory), 0);
}
/// <summary>
/// Never complete.
/// </summary>
@@ -194,6 +309,7 @@ namespace Cysharp.Threading.Tasks
sealed class ExceptionResultSource : IUniTaskSource
{
readonly ExceptionDispatchInfo exception;
bool calledGet;
public ExceptionResultSource(Exception exception)
{
@@ -202,6 +318,11 @@ namespace Cysharp.Threading.Tasks
public void GetResult(short token)
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
exception.Throw();
}
@@ -219,11 +340,20 @@ namespace Cysharp.Threading.Tasks
{
continuation(state);
}
~ExceptionResultSource()
{
if (!calledGet)
{
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
}
}
}
sealed class ExceptionResultSource<T> : IUniTaskSource<T>
{
readonly ExceptionDispatchInfo exception;
bool calledGet;
public ExceptionResultSource(Exception exception)
{
@@ -232,12 +362,22 @@ namespace Cysharp.Threading.Tasks
public T GetResult(short token)
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
exception.Throw();
return default;
}
void IUniTaskSource.GetResult(short token)
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
exception.Throw();
}
@@ -255,6 +395,14 @@ namespace Cysharp.Threading.Tasks
{
continuation(state);
}
~ExceptionResultSource()
{
if (!calledGet)
{
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
}
}
}
sealed class CanceledResultSource : IUniTaskSource
@@ -405,6 +553,93 @@ namespace Cysharp.Threading.Tasks
}
}
sealed class DeferPromiseWithState<TState> : IUniTaskSource
{
Func<TState, UniTask> factory;
TState argument;
UniTask task;
UniTask.Awaiter awaiter;
public DeferPromiseWithState(TState argument, Func<TState, UniTask> factory)
{
this.argument = argument;
this.factory = factory;
}
public void GetResult(short token)
{
awaiter.GetResult();
}
public UniTaskStatus GetStatus(short token)
{
var f = Interlocked.Exchange(ref factory, null);
if (f != null)
{
task = f(argument);
awaiter = task.GetAwaiter();
}
return task.Status;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
awaiter.SourceOnCompleted(continuation, state);
}
public UniTaskStatus UnsafeGetStatus()
{
return task.Status;
}
}
sealed class DeferPromiseWithState<TState, TResult> : IUniTaskSource<TResult>
{
Func<TState, UniTask<TResult>> factory;
TState argument;
UniTask<TResult> task;
UniTask<TResult>.Awaiter awaiter;
public DeferPromiseWithState(TState argument, Func<TState, UniTask<TResult>> factory)
{
this.argument = argument;
this.factory = factory;
}
public TResult GetResult(short token)
{
return awaiter.GetResult();
}
void IUniTaskSource.GetResult(short token)
{
awaiter.GetResult();
}
public UniTaskStatus GetStatus(short token)
{
var f = Interlocked.Exchange(ref factory, null);
if (f != null)
{
task = f(argument);
awaiter = task.GetAwaiter();
}
return task.Status;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
awaiter.SourceOnCompleted(continuation, state);
}
public UniTaskStatus UnsafeGetStatus()
{
return task.Status;
}
}
sealed class NeverPromise<T> : IUniTaskSource<T>
{
static readonly Action<object> cancellationCallback = CancellationCallback;

View File

@@ -9,237 +9,56 @@ namespace Cysharp.Threading.Tasks
{
#region OBSOLETE_RUN
// Run is a confusing name, use only RunOnThreadPool in the future.
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
action();
}
finally
{
await UniTask.Yield();
}
}
else
{
action();
}
cancellationToken.ThrowIfCancellationRequested();
return RunOnThreadPool(action, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
action(state);
}
finally
{
await UniTask.Yield();
}
}
else
{
action(state);
}
cancellationToken.ThrowIfCancellationRequested();
return RunOnThreadPool(action, state, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
await action();
}
finally
{
await UniTask.Yield();
}
}
else
{
await action();
}
cancellationToken.ThrowIfCancellationRequested();
return RunOnThreadPool(action, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
await action(state);
}
finally
{
await UniTask.Yield();
}
}
else
{
await action(state);
}
cancellationToken.ThrowIfCancellationRequested();
return RunOnThreadPool(action, state, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return func();
}
finally
{
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
return func();
}
return RunOnThreadPool(func, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return await func();
}
finally
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
var result = await func();
cancellationToken.ThrowIfCancellationRequested();
return result;
}
return RunOnThreadPool(func, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return func(state);
}
finally
{
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
return func(state);
}
return RunOnThreadPool(func, state, configureAwait, cancellationToken);
}
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
public static async UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
[Obsolete("UniTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use UniTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use UniTask.Void(async void) or UniTask.Create(async UniTask) too.")]
public static UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToThreadPool();
cancellationToken.ThrowIfCancellationRequested();
if (configureAwait)
{
try
{
return await func(state);
}
finally
{
cancellationToken.ThrowIfCancellationRequested();
await UniTask.Yield();
cancellationToken.ThrowIfCancellationRequested();
}
}
else
{
var result = await func(state);
cancellationToken.ThrowIfCancellationRequested();
return result;
}
return RunOnThreadPool(func, state, configureAwait, cancellationToken);
}
#endregion
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask RunOnThreadPool(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
{

View File

@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Threading;
using Cysharp.Threading.Tasks.Internal;
@@ -9,30 +10,40 @@ namespace Cysharp.Threading.Tasks
{
public partial struct UniTask
{
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, out var token), token);
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask WaitUntil<T>(T state, Func<T, bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, out var token), token);
return new UniTask(WaitUntilPromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update)
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, out var token), token);
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask WaitWhile<T>(T state, Func<T, bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
return new UniTask(WaitWhilePromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update, bool completeImmediately = false)
{
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
}
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
where T : class
{
var unityObject = target as UnityEngine.Object;
var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
return new UniTask<U>(isUnityObject
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token)
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token);
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out var token)
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out token), token);
}
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
@@ -48,6 +59,8 @@ namespace Cysharp.Threading.Tasks
Func<bool> predicate;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
@@ -55,7 +68,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -69,6 +82,16 @@ namespace Cysharp.Threading.Tasks
result.predicate = predicate;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -86,7 +109,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -136,31 +166,36 @@ namespace Cysharp.Threading.Tasks
core.Reset();
predicate = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
sealed class WaitUntilPromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise<T>>
{
static TaskPool<WaitWhilePromise> pool;
WaitWhilePromise nextNode;
public ref WaitWhilePromise NextNode => ref nextNode;
static TaskPool<WaitUntilPromise<T>> pool;
WaitUntilPromise<T> nextNode;
public ref WaitUntilPromise<T> NextNode => ref nextNode;
static WaitWhilePromise()
static WaitUntilPromise()
{
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size);
TaskPool.RegisterSizeGetter(typeof(WaitUntilPromise<T>), () => pool.Size);
}
Func<bool> predicate;
Func<T, bool> predicate;
T argument;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
WaitWhilePromise()
WaitUntilPromise()
{
}
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(T argument, Func<T, bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -169,11 +204,22 @@ namespace Cysharp.Threading.Tasks
if (!pool.TryPop(out var result))
{
result = new WaitWhilePromise();
result = new WaitUntilPromise<T>();
}
result.predicate = predicate;
result.argument = argument;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilPromise<T>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -191,7 +237,141 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
try
{
if (!predicate(argument))
{
return true;
}
}
catch (Exception ex)
{
core.TrySetException(ex);
return false;
}
core.TrySetResult(null);
return false;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
predicate = default;
argument = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
{
static TaskPool<WaitWhilePromise> pool;
WaitWhilePromise nextNode;
public ref WaitWhilePromise NextNode => ref nextNode;
static WaitWhilePromise()
{
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size);
}
Func<bool> predicate;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
WaitWhilePromise()
{
}
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitWhilePromise();
}
result.predicate = predicate;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitWhilePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -241,30 +421,36 @@ namespace Cysharp.Threading.Tasks
core.Reset();
predicate = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
sealed class WaitWhilePromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise<T>>
{
static TaskPool<WaitUntilCanceledPromise> pool;
WaitUntilCanceledPromise nextNode;
public ref WaitUntilCanceledPromise NextNode => ref nextNode;
static TaskPool<WaitWhilePromise<T>> pool;
WaitWhilePromise<T> nextNode;
public ref WaitWhilePromise<T> NextNode => ref nextNode;
static WaitUntilCanceledPromise()
static WaitWhilePromise()
{
TaskPool.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size);
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise<T>), () => pool.Size);
}
Func<T, bool> predicate;
T argument;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
WaitUntilCanceledPromise()
WaitWhilePromise()
{
}
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, out short token)
public static IUniTaskSource Create(T argument, Func<T, bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -273,10 +459,22 @@ namespace Cysharp.Threading.Tasks
if (!pool.TryPop(out var result))
{
result = new WaitUntilCanceledPromise();
result = new WaitWhilePromise<T>();
}
result.predicate = predicate;
result.argument = argument;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitWhilePromise<T>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -294,7 +492,139 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
try
{
if (predicate(argument))
{
return true;
}
}
catch (Exception ex)
{
core.TrySetException(ex);
return false;
}
core.TrySetResult(null);
return false;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
predicate = default;
argument = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
{
static TaskPool<WaitUntilCanceledPromise> pool;
WaitUntilCanceledPromise nextNode;
public ref WaitUntilCanceledPromise NextNode => ref nextNode;
static WaitUntilCanceledPromise()
{
TaskPool.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size);
}
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<object> core;
WaitUntilCanceledPromise()
{
}
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new WaitUntilCanceledPromise();
}
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilCanceledPromise)state;
promise.core.TrySetResult(null);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -329,6 +659,8 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this);
core.Reset();
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
@@ -351,6 +683,8 @@ namespace Cysharp.Threading.Tasks
Func<T, U> monitorFunction;
IEqualityComparer<U> equalityComparer;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<U> core;
@@ -358,7 +692,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -376,6 +710,16 @@ namespace Cysharp.Threading.Tasks
result.currentValue = monitorFunction(target);
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilValueChangedUnityObjectPromise<T, U>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -393,7 +737,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -453,6 +804,8 @@ namespace Cysharp.Threading.Tasks
monitorFunction = default;
equalityComparer = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
@@ -474,6 +827,8 @@ namespace Cysharp.Threading.Tasks
Func<T, U> monitorFunction;
IEqualityComparer<U> equalityComparer;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<U> core;
@@ -481,7 +836,7 @@ namespace Cysharp.Threading.Tasks
{
}
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -498,6 +853,16 @@ namespace Cysharp.Threading.Tasks
result.currentValue = monitorFunction(target);
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilValueChangedStandardObjectPromise<T, U>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -515,7 +880,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -575,6 +947,8 @@ namespace Cysharp.Threading.Tasks
monitorFunction = default;
equalityComparer = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}

View File

@@ -0,0 +1,183 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Collections.Generic;
using System.Runtime.ExceptionServices;
using System.Threading;
namespace Cysharp.Threading.Tasks
{
public partial struct UniTask
{
public static IUniTaskAsyncEnumerable<WhenEachResult<T>> WhenEach<T>(IEnumerable<UniTask<T>> tasks)
{
return new WhenEachEnumerable<T>(tasks);
}
public static IUniTaskAsyncEnumerable<WhenEachResult<T>> WhenEach<T>(params UniTask<T>[] tasks)
{
return new WhenEachEnumerable<T>(tasks);
}
}
public readonly struct WhenEachResult<T>
{
public T Result { get; }
public Exception Exception { get; }
//[MemberNotNullWhen(false, nameof(Exception))]
public bool IsCompletedSuccessfully => Exception == null;
//[MemberNotNullWhen(true, nameof(Exception))]
public bool IsFaulted => Exception != null;
public WhenEachResult(T result)
{
this.Result = result;
this.Exception = null;
}
public WhenEachResult(Exception exception)
{
if (exception == null) throw new ArgumentNullException(nameof(exception));
this.Result = default!;
this.Exception = exception;
}
public void TryThrow()
{
if (IsFaulted)
{
ExceptionDispatchInfo.Capture(Exception).Throw();
}
}
public T GetResult()
{
if (IsFaulted)
{
ExceptionDispatchInfo.Capture(Exception).Throw();
}
return Result;
}
public override string ToString()
{
if (IsCompletedSuccessfully)
{
return Result?.ToString() ?? "";
}
else
{
return $"Exception{{{Exception.Message}}}";
}
}
}
internal enum WhenEachState : byte
{
NotRunning,
Running,
Completed
}
internal sealed class WhenEachEnumerable<T> : IUniTaskAsyncEnumerable<WhenEachResult<T>>
{
IEnumerable<UniTask<T>> source;
public WhenEachEnumerable(IEnumerable<UniTask<T>> source)
{
this.source = source;
}
public IUniTaskAsyncEnumerator<WhenEachResult<T>> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(source, cancellationToken);
}
sealed class Enumerator : IUniTaskAsyncEnumerator<WhenEachResult<T>>
{
readonly IEnumerable<UniTask<T>> source;
CancellationToken cancellationToken;
Channel<WhenEachResult<T>> channel;
IUniTaskAsyncEnumerator<WhenEachResult<T>> channelEnumerator;
int completeCount;
WhenEachState state;
public Enumerator(IEnumerable<UniTask<T>> source, CancellationToken cancellationToken)
{
this.source = source;
this.cancellationToken = cancellationToken;
}
public WhenEachResult<T> Current => channelEnumerator.Current;
public UniTask<bool> MoveNextAsync()
{
cancellationToken.ThrowIfCancellationRequested();
if (state == WhenEachState.NotRunning)
{
state = WhenEachState.Running;
channel = Channel.CreateSingleConsumerUnbounded<WhenEachResult<T>>();
channelEnumerator = channel.Reader.ReadAllAsync().GetAsyncEnumerator(cancellationToken);
if (source is UniTask<T>[] array)
{
ConsumeAll(this, array, array.Length);
}
else
{
using (var rentArray = ArrayPoolUtil.Materialize(source))
{
ConsumeAll(this, rentArray.Array, rentArray.Length);
}
}
}
return channelEnumerator.MoveNextAsync();
}
static void ConsumeAll(Enumerator self, UniTask<T>[] array, int length)
{
for (int i = 0; i < length; i++)
{
RunWhenEachTask(self, array[i], length).Forget();
}
static async UniTaskVoid RunWhenEachTask(Enumerator self, UniTask<T> task, int length)
{
try
{
var result = await task;
self.channel.Writer.TryWrite(new WhenEachResult<T>(result));
}
catch (Exception ex)
{
self.channel.Writer.TryWrite(new WhenEachResult<T>(ex));
}
if (Interlocked.Increment(ref self.completeCount) == length)
{
self.state = WhenEachState.Completed;
self.channel.Writer.TryComplete();
}
}
}
public async UniTask DisposeAsync()
{
if (channelEnumerator != null)
{
await channelEnumerator.DisposeAsync();
}
if (state != WhenEachState.Completed)
{
state = WhenEachState.Completed;
channel.Writer.TryComplete(new OperationCanceledException());
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 12bdad0556e999f4aa82da29415d361f
guid: 7cac24fdda5112047a1cd3dd66b542c4
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,6 +1,10 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#pragma warning disable CS0436
#if UNITASK_NETCORE || UNITY_2022_3_OR_NEWER
#define SUPPORT_VALUETASK
#endif
using Cysharp.Threading.Tasks.CompilerServices;
using System;
using System.Diagnostics;
@@ -69,7 +73,7 @@ namespace Cysharp.Threading.Tasks
return new UniTask<bool>(new IsCanceledSource(source), token);
}
#if !UNITY_2018_3_OR_NEWER
#if SUPPORT_VALUETASK
public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self)
{
@@ -78,7 +82,7 @@ namespace Cysharp.Threading.Tasks
return default;
}
#if NETSTANDARD2_0
#if (UNITASK_NETCORE && NETSTANDARD2_0)
return self.AsValueTask();
#else
return new System.Threading.Tasks.ValueTask(self.source, self.token);
@@ -118,7 +122,7 @@ namespace Cysharp.Threading.Tasks
this.source.GetResult(this.token);
return CompletedTasks.AsyncUnit;
}
else if(this.source is IUniTaskSource<AsyncUnit> asyncUnitSource)
else if (this.source is IUniTaskSource<AsyncUnit> asyncUnitSource)
{
return new UniTask<AsyncUnit>(asyncUnitSource, this.token);
}
@@ -440,7 +444,7 @@ namespace Cysharp.Threading.Tasks
return self.AsUniTask();
}
#if !UNITY_2018_3_OR_NEWER
#if SUPPORT_VALUETASK
public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
{
@@ -449,7 +453,7 @@ namespace Cysharp.Threading.Tasks
return new System.Threading.Tasks.ValueTask<T>(self.result);
}
#if NETSTANDARD2_0
#if (UNITASK_NETCORE && NETSTANDARD2_0)
return self.AsValueTask();
#else
return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);

View File

@@ -137,8 +137,8 @@ namespace Cysharp.Threading.Tasks
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
return true;
}
return true;
}
return false;
@@ -165,8 +165,8 @@ namespace Cysharp.Threading.Tasks
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
return true;
}
return true;
}
return false;
@@ -184,8 +184,8 @@ namespace Cysharp.Threading.Tasks
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
return true;
}
return true;
}
return false;
@@ -328,6 +328,7 @@ namespace Cysharp.Threading.Tasks
}
UniTaskCompletionSourceCore<AsyncUnit> core;
short version;
AutoResetUniTaskCompletionSource()
{
@@ -340,6 +341,7 @@ namespace Cysharp.Threading.Tasks
{
result = new AutoResetUniTaskCompletionSource();
}
result.version = result.core.Version;
TaskTracker.TrackActiveTask(result, 2);
return result;
}
@@ -383,19 +385,19 @@ namespace Cysharp.Threading.Tasks
[DebuggerHidden]
public bool TrySetResult()
{
return core.TrySetResult(AsyncUnit.Default);
return version == core.Version && core.TrySetResult(AsyncUnit.Default);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
return core.TrySetCanceled(cancellationToken);
return version == core.Version && core.TrySetCanceled(cancellationToken);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
return core.TrySetException(exception);
return version == core.Version && core.TrySetException(exception);
}
[DebuggerHidden]
@@ -409,7 +411,6 @@ namespace Cysharp.Threading.Tasks
{
TryReturn();
}
}
[DebuggerHidden]
@@ -451,6 +452,7 @@ namespace Cysharp.Threading.Tasks
}
UniTaskCompletionSourceCore<T> core;
short version;
AutoResetUniTaskCompletionSource()
{
@@ -463,6 +465,7 @@ namespace Cysharp.Threading.Tasks
{
result = new AutoResetUniTaskCompletionSource<T>();
}
result.version = result.core.Version;
TaskTracker.TrackActiveTask(result, 2);
return result;
}
@@ -506,19 +509,19 @@ namespace Cysharp.Threading.Tasks
[DebuggerHidden]
public bool TrySetResult(T result)
{
return core.TrySetResult(result);
return version == core.Version && core.TrySetResult(result);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
return core.TrySetCanceled(cancellationToken);
return version == core.Version && core.TrySetCanceled(cancellationToken);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
return core.TrySetException(exception);
return version == core.Version && core.TrySetException(exception);
}
[DebuggerHidden]
@@ -937,5 +940,5 @@ namespace Cysharp.Threading.Tasks
}
return false;
}
}
}
}

View File

@@ -28,7 +28,7 @@ namespace Cysharp.Threading.Tasks
p.TrySetCanceled();
break;
case TaskStatus.Faulted:
p.TrySetException(x.Exception);
p.TrySetException(x.Exception.InnerException ?? x.Exception);
break;
case TaskStatus.RanToCompletion:
p.TrySetResult(x.Result);
@@ -58,7 +58,7 @@ namespace Cysharp.Threading.Tasks
p.TrySetCanceled();
break;
case TaskStatus.Faulted:
p.TrySetException(x.Exception);
p.TrySetException(x.Exception.InnerException ?? x.Exception);
break;
case TaskStatus.RanToCompletion:
p.TrySetResult();
@@ -201,6 +201,7 @@ namespace Cysharp.Threading.Tasks
if (cancellationToken.IsCancellationRequested)
{
task.Forget();
return UniTask.FromCanceled(cancellationToken);
}
@@ -224,6 +225,7 @@ namespace Cysharp.Threading.Tasks
if (cancellationToken.IsCancellationRequested)
{
task.Forget();
return UniTask.FromCanceled<T>(cancellationToken);
}
@@ -454,7 +456,7 @@ namespace Cysharp.Threading.Tasks
}
/// <summary>
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCanceled).
/// </summary>
public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
{

View File

@@ -74,16 +74,19 @@ namespace Cysharp.Threading.Tasks
static async UniTaskVoid Fire<T>(AsyncSubject<T> subject, UniTask<T> task)
{
T value;
try
{
var value = await task;
subject.OnNext(value);
subject.OnCompleted();
value = await task;
}
catch (Exception ex)
{
subject.OnError(ex);
return;
}
subject.OnNext(value);
subject.OnCompleted();
}
static async UniTaskVoid Fire(AsyncSubject<AsyncUnit> subject, UniTask task)
@@ -91,13 +94,15 @@ namespace Cysharp.Threading.Tasks
try
{
await task;
subject.OnNext(AsyncUnit.Default);
subject.OnCompleted();
}
catch (Exception ex)
{
subject.OnError(ex);
return;
}
subject.OnNext(AsyncUnit.Default);
subject.OnCompleted();
}
class ToUniTaskObserver<T> : IObserver<T>
@@ -128,7 +133,7 @@ namespace Cysharp.Threading.Tasks
{
var self = (ToUniTaskObserver<T>)state;
self.disposable.Dispose();
self.promise.TrySetCanceled();
self.promise.TrySetCanceled(self.cancellationToken);
}
public void OnNext(T value)
@@ -198,7 +203,7 @@ namespace Cysharp.Threading.Tasks
{
var self = (FirstValueToUniTaskObserver<T>)state;
self.disposable.Dispose();
self.promise.TrySetCanceled();
self.promise.TrySetCanceled(self.cancellationToken);
}
public void OnNext(T value)

View File

@@ -21,15 +21,20 @@ namespace Cysharp.Threading.Tasks
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
{
return AwaitForAllAssets(asyncOperation, cancellationToken: cancellationToken);
return AwaitForAllAssets(asyncOperation, null, PlayerLoopTiming.Update, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return AwaitForAllAssets(asyncOperation, progress: null, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets);
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion
@@ -95,15 +100,20 @@ namespace Cysharp.Threading.Tasks
AssetBundleRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
Action<AsyncOperation> continuationAction;
AssetBundleRequestAllAssetsConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -118,6 +128,19 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AssetBundleRequestAllAssetsConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -135,7 +158,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -161,6 +191,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -188,8 +224,28 @@ namespace Cysharp.Threading.Tasks
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.allAssets);
}
}
}
}
}

View File

@@ -20,12 +20,17 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<AsyncGPUReadbackRequest> WithCancellation(this AsyncGPUReadbackRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, out var token), token);
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, cancelImmediately, out var token), token);
}
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
{
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
@@ -39,15 +44,15 @@ namespace Cysharp.Threading.Tasks
AsyncGPUReadbackRequest asyncOperation;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
AsyncGPUReadbackRequestAwaiterConfiguredSource()
{
}
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -61,6 +66,16 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncGPUReadbackRequestAwaiterConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -78,7 +93,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -131,6 +153,8 @@ namespace Cysharp.Threading.Tasks
core.Reset();
asyncOperation = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}

View File

@@ -0,0 +1,386 @@
// AsyncInstantiateOperation was added since Unity 2022.3.20 / 2023.3.0b7
#if UNITY_2022_3 && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17 || UNITY_2022_3_18 || UNITY_2022_3_19)
#define UNITY_2022_SUPPORT
#endif
#if UNITY_2022_SUPPORT || UNITY_2023_3_OR_NEWER
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
using UnityEngine;
namespace Cysharp.Threading.Tasks
{
public static class AsyncInstantiateOperationExtensions
{
// AsyncInstantiateOperation<T> has GetAwaiter so no need to impl
// public static UniTask<T[]>.Awaiter GetAwaiter<T>(this AsyncInstantiateOperation<T> operation) where T : Object
public static UniTask<UnityEngine.Object[]> WithCancellation<T>(this AsyncInstantiateOperation asyncOperation, CancellationToken cancellationToken)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object[]> WithCancellation<T>(this AsyncInstantiateOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object[]> ToUniTask(this AsyncInstantiateOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.Result);
return new UniTask<UnityEngine.Object[]>(AsyncInstantiateOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public static UniTask<T[]> WithCancellation<T>(this AsyncInstantiateOperation<T> asyncOperation, CancellationToken cancellationToken)
where T : UnityEngine.Object
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<T[]> WithCancellation<T>(this AsyncInstantiateOperation<T> asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
where T : UnityEngine.Object
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<T[]> ToUniTask<T>(this AsyncInstantiateOperation<T> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
where T : UnityEngine.Object
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T[]>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.Result);
return new UniTask<T[]>(AsyncInstantiateOperationConfiguredSource<T>.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
sealed class AsyncInstantiateOperationConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AsyncInstantiateOperationConfiguredSource>
{
static TaskPool<AsyncInstantiateOperationConfiguredSource> pool;
AsyncInstantiateOperationConfiguredSource nextNode;
public ref AsyncInstantiateOperationConfiguredSource NextNode => ref nextNode;
static AsyncInstantiateOperationConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncInstantiateOperationConfiguredSource), () => pool.Size);
}
AsyncInstantiateOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
Action<AsyncOperation> continuationAction;
AsyncInstantiateOperationConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object[]> Create(AsyncInstantiateOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncInstantiateOperationConfiguredSource();
}
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AsyncInstantiateOperationConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public UnityEngine.Object[] GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
core.TrySetResult(asyncOperation.Result);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.Result);
}
}
}
sealed class AsyncInstantiateOperationConfiguredSource<T> : IUniTaskSource<T[]>, IPlayerLoopItem, ITaskPoolNode<AsyncInstantiateOperationConfiguredSource<T>>
where T : UnityEngine.Object
{
static TaskPool<AsyncInstantiateOperationConfiguredSource<T>> pool;
AsyncInstantiateOperationConfiguredSource<T> nextNode;
public ref AsyncInstantiateOperationConfiguredSource<T> NextNode => ref nextNode;
static AsyncInstantiateOperationConfiguredSource()
{
TaskPool.RegisterSizeGetter(typeof(AsyncInstantiateOperationConfiguredSource<T>), () => pool.Size);
}
AsyncInstantiateOperation<T> asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<T[]> core;
Action<AsyncOperation> continuationAction;
AsyncInstantiateOperationConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<T[]> Create(AsyncInstantiateOperation<T> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<T[]>.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new AsyncInstantiateOperationConfiguredSource<T>();
}
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AsyncInstantiateOperationConfiguredSource<T>)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public T[] GetResult(short token)
{
try
{
return core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
core.TrySetResult(asyncOperation.Result);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.Result);
}
}
}
}
}
#endif

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 3518da33b6245d341a0ef3670ee9268b
timeCreated: 1488689723
licenseType: Pro
guid: 8321f4244edfdcd4798b4fcc92a736c9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@@ -15,23 +15,31 @@ namespace Cysharp.Threading.Tasks
{
#region AsyncOperation
#if !UNITY_2023_1_OR_NEWER
// from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
return new AsyncOperationAwaiter(asyncOperation);
}
#endif
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
if (asyncOperation.isDone) return UniTask.CompletedTask;
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
@@ -88,15 +96,20 @@ namespace Cysharp.Threading.Tasks
AsyncOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<AsyncUnit> core;
Action<AsyncOperation> continuationAction;
AsyncOperationConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -111,6 +124,19 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AsyncOperationConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -128,7 +154,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -150,6 +183,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -174,11 +213,31 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(AsyncUnit.Default);
}
}
}
#endregion
@@ -196,12 +255,17 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct ResourceRequestAwaiter : ICriticalNotifyCompletion
@@ -262,15 +326,20 @@ namespace Cysharp.Threading.Tasks
ResourceRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
Action<AsyncOperation> continuationAction;
ResourceRequestConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -285,6 +354,19 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (ResourceRequestConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -302,7 +384,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -328,6 +417,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -352,11 +447,31 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.asset);
}
}
}
#endregion
@@ -375,12 +490,17 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion
@@ -441,15 +561,20 @@ namespace Cysharp.Threading.Tasks
AssetBundleRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
Action<AsyncOperation> continuationAction;
AssetBundleRequestConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<UnityEngine.Object> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -464,6 +589,19 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AssetBundleRequestConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -481,7 +619,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -507,6 +652,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -531,11 +682,31 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.asset);
}
}
}
#endregion
@@ -555,12 +726,17 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion
@@ -621,15 +797,20 @@ namespace Cysharp.Threading.Tasks
AssetBundleCreateRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<AssetBundle> core;
Action<AsyncOperation> continuationAction;
AssetBundleCreateRequestConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -644,6 +825,19 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (AssetBundleCreateRequestConfiguredSource)state;
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -661,7 +855,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -687,6 +888,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
@@ -711,11 +918,31 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else
{
core.TrySetResult(asyncOperation.assetBundle);
}
}
}
#endregion
@@ -735,7 +962,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
@@ -747,7 +979,7 @@ namespace Cysharp.Threading.Tasks
}
return UniTask.FromResult(asyncOperation.webRequest);
}
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
@@ -816,15 +1048,20 @@ namespace Cysharp.Threading.Tasks
UnityWebRequestAsyncOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<UnityWebRequest> core;
Action<AsyncOperation> continuationAction;
UnityWebRequestAsyncOperationConfiguredSource()
{
continuationAction = Continuation;
}
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -839,6 +1076,20 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (UnityWebRequestAsyncOperationConfiguredSource)state;
source.asyncOperation.webRequest.Abort();
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -856,7 +1107,14 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
@@ -882,6 +1140,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
asyncOperation.webRequest.Abort();
@@ -914,11 +1178,35 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
else if (asyncOperation.webRequest.IsError())
{
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
}
else
{
core.TrySetResult(asyncOperation.webRequest);
}
}
}
#endregion

View File

@@ -16,6 +16,7 @@
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
Func<string, string> ToIUniTaskSourceReturnType = x => (x == "void") ? "IUniTaskSource" : $"IUniTaskSource<{x}>";
Func<(string typeName, string returnType, string returnField), bool> IsAsyncOperationBase = x => x.typeName == "AsyncOperation";
Func<(string typeName, string returnType, string returnField), bool> IsUnityWebRequest = x => x.returnType == "UnityWebRequest";
Func<(string typeName, string returnType, string returnField), bool> IsAssetBundleModule = x => x.typeName == "AssetBundleRequest" || x.typeName == "AssetBundleCreateRequest";
Func<(string typeName, string returnType, string returnField), bool> IsVoid = x => x.returnType == "void";
@@ -43,18 +44,30 @@ namespace Cysharp.Threading.Tasks
<# } #>
#region <#= t.typeName #>
<# if (IsAsyncOperationBase(t)) { #>
#if !UNITY_2023_1_OR_NEWER
// from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine.
<# } #>
public static <#= t.typeName #>Awaiter GetAwaiter(this <#= t.typeName #> asyncOperation)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
return new <#= t.typeName #>Awaiter(asyncOperation);
}
<# if (IsAsyncOperationBase(t)) { #>
#endif
<# } #>
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
}
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<#= IsVoid(t) ? "" : "<" + t.returnType + ">" #>(cancellationToken);
@@ -70,7 +83,7 @@ namespace Cysharp.Threading.Tasks
<# } else { #>
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
<# } #>
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
}
public struct <#= t.typeName #>Awaiter : ICriticalNotifyCompletion
@@ -151,15 +164,20 @@ namespace Cysharp.Threading.Tasks
<#= t.typeName #> asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
bool completed;
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
Action<AsyncOperation> continuationAction;
<#= t.typeName #>ConfiguredSource()
{
continuationAction = Continuation;
}
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
@@ -174,6 +192,22 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation;
result.progress = progress;
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
result.completed = false;
asyncOperation.completed += result.continuationAction;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (<#= t.typeName #>ConfiguredSource)state;
<# if(IsUnityWebRequest(t)) { #>
source.asyncOperation.webRequest.Abort();
<# } #>
source.core.TrySetCanceled(source.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
@@ -195,7 +229,10 @@ namespace Cysharp.Threading.Tasks
}
finally
{
TryReturn();
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
}
}
@@ -223,6 +260,12 @@ namespace Cysharp.Threading.Tasks
public bool MoveNext()
{
// Already completed
if (completed || asyncOperation == null)
{
return false;
}
if (cancellationToken.IsCancellationRequested)
{
<# if(IsUnityWebRequest(t)) { #>
@@ -261,11 +304,42 @@ namespace Cysharp.Threading.Tasks
{
TaskTracker.RemoveTracking(this);
core.Reset();
asyncOperation.completed -= continuationAction;
asyncOperation = default;
progress = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
void Continuation(AsyncOperation _)
{
if (completed)
{
return;
}
completed = true;
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
}
<# if(IsUnityWebRequest(t)) { #>
else if (asyncOperation.webRequest.IsError())
{
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
}
else
{
core.TrySetResult(asyncOperation.webRequest);
}
<# } else { #>
else
{
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
}
<# } #>
}
}
#endregion

View File

@@ -339,7 +339,7 @@ namespace Cysharp.Threading.Tasks
void InvokeCore(string item1, int item2, int item3)
{
innerEvent.Invoke(item1, item2, item3);
Invoke((item1, item2, item3));
}
public void Dispose()
@@ -673,7 +673,7 @@ namespace Cysharp.Threading.Tasks
}
if (cancellationToken2.CanBeCanceled)
{
registration2 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel2, this);
registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
}
}
@@ -688,13 +688,27 @@ namespace Cysharp.Threading.Tasks
static void OnCanceled1(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
self.DisposeAsync().Forget();
try
{
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
finally
{
self.DisposeAsync().Forget();
}
}
static void OnCanceled2(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
self.DisposeAsync().Forget();
try
{
self.completionSource.TrySetCanceled(self.cancellationToken2);
}
finally
{
self.DisposeAsync().Forget();
}
}
public UniTask DisposeAsync()
@@ -706,6 +720,8 @@ namespace Cysharp.Threading.Tasks
registration1.Dispose();
registration2.Dispose();
unityEvent.RemoveListener(unityAction);
completionSource.TrySetCanceled();
}
return default;
@@ -777,7 +793,7 @@ namespace Cysharp.Threading.Tasks
}
if (cancellationToken2.CanBeCanceled)
{
registration2 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel2, this);
registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
}
}
@@ -793,13 +809,27 @@ namespace Cysharp.Threading.Tasks
static void OnCanceled1(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
self.DisposeAsync().Forget();
try
{
self.completionSource.TrySetCanceled(self.cancellationToken1);
}
finally
{
self.DisposeAsync().Forget();
}
}
static void OnCanceled2(object state)
{
var self = (UnityEventHandlerAsyncEnumerator)state;
self.DisposeAsync().Forget();
try
{
self.completionSource.TrySetCanceled(self.cancellationToken2);
}
finally
{
self.DisposeAsync().Forget();
}
}
public UniTask DisposeAsync()
@@ -815,6 +845,8 @@ namespace Cysharp.Threading.Tasks
disp.Dispose();
}
unityEvent.RemoveListener(unityAction);
completionSource.TrySetCanceled();
}
return default;
@@ -823,4 +855,4 @@ namespace Cysharp.Threading.Tasks
}
}
#endif
#endif

View File

@@ -0,0 +1,17 @@
#if UNITY_2023_1_OR_NEWER
namespace Cysharp.Threading.Tasks
{
public static class UnityAwaitableExtensions
{
public static async UniTask AsUniTask(this UnityEngine.Awaitable awaitable)
{
await awaitable;
}
public static async UniTask<T> AsUniTask<T>(this UnityEngine.Awaitable<T> awaitable)
{
return await awaitable;
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c29533c9e4284dee914b71a6579ea274
timeCreated: 1698895807

View File

@@ -12,17 +12,17 @@ namespace Cysharp.Threading.Tasks
#if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
// <string> -> Text
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, bool rebindOnError = true)
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError)
{
var repeat = false;
BIND_AGAIN:
@@ -68,22 +68,22 @@ namespace Cysharp.Threading.Tasks
// <T> -> Text
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, bool rebindOnError = true)
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError = true)
{
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
}
public static void BindTo<T>(this AsyncReactiveProperty<T> source, Text text, bool rebindOnError = true)
public static void BindTo<T>(this AsyncReactiveProperty<T> source, UnityEngine.UI.Text text, bool rebindOnError = true)
{
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
}
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, UnityEngine.UI.Text text, CancellationToken cancellationToken, bool rebindOnError)
{
var repeat = false;
BIND_AGAIN:

View File

@@ -1,4 +1,4 @@
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
using System;
using System.Collections.Generic;
@@ -49,7 +49,7 @@ namespace Cysharp.Threading.Tasks
{
if (msg == null)
{
if (Text != null)
if(!string.IsNullOrWhiteSpace(Text))
{
msg = Error + Environment.NewLine + Text;
}

View File

@@ -1,11 +1,12 @@
{
"name": "com.cysharp.unitask",
"displayName": "UniTask",
"version": "2.2.5",
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
"version": "2.5.9",
"unity": "2018.4",
"description": "Provides an efficient async/await integration to Unity.",
"keywords": [ "async/await", "async", "Task", "UniTask" ],
"license": "MIT",
"category": "Task",
"dependencies": {}
}
}

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 894f21dfce4e82343a91661e1ec1a455
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,133 +0,0 @@
#if UNITY_EDITOR
using System;
using UnityEngine;
namespace RuntimeUnitTestToolkit.Editor
{
// functional declarative construction like flutter.
internal interface IBuilder
{
GameObject GameObject { get; }
T GetComponent<T>();
}
internal class Builder<T> : IBuilder
where T : Component
{
public T Component1 { get; private set; }
public GameObject GameObject { get; private set; }
public Transform Transform { get { return GameObject.transform; } }
public RectTransform RectTransform { get { return GameObject.GetComponent<RectTransform>(); } }
public Action<GameObject> SetTarget
{
set
{
value(this.GameObject);
}
}
public IBuilder Child
{
set
{
value.GameObject.transform.SetParent(GameObject.transform);
}
}
public IBuilder[] Children
{
set
{
foreach (var item in value)
{
item.GameObject.transform.SetParent(GameObject.transform);
}
}
}
public Builder(string name)
{
this.GameObject = new GameObject(name);
this.Component1 = GameObject.AddComponent<T>();
}
public Builder(string name, out T referenceSelf) // out primary reference.
{
this.GameObject = new GameObject(name);
this.Component1 = GameObject.AddComponent<T>();
referenceSelf = this.Component1;
}
public TComponent GetComponent<TComponent>()
{
return this.GameObject.GetComponent<TComponent>();
}
}
internal class Builder<T1, T2> : Builder<T1>
where T1 : Component
where T2 : Component
{
public T2 Component2 { get; private set; }
public Builder(string name)
: base(name)
{
this.Component2 = GameObject.AddComponent<T2>();
}
public Builder(string name, out T1 referenceSelf)
: base(name, out referenceSelf)
{
this.Component2 = GameObject.AddComponent<T2>();
}
}
internal class Builder<T1, T2, T3> : Builder<T1, T2>
where T1 : Component
where T2 : Component
where T3 : Component
{
public T3 Component3 { get; private set; }
public Builder(string name)
: base(name)
{
this.Component3 = GameObject.AddComponent<T3>();
}
public Builder(string name, out T1 referenceSelf)
: base(name, out referenceSelf)
{
this.Component3 = GameObject.AddComponent<T3>();
}
}
internal class Builder<T1, T2, T3, T4> : Builder<T1, T2, T3>
where T1 : Component
where T2 : Component
where T3 : Component
where T4 : Component
{
public T4 Component4 { get; private set; }
public Builder(string name)
: base(name)
{
this.Component4 = GameObject.AddComponent<T4>();
}
public Builder(string name, out T1 referenceSelf)
: base(name, out referenceSelf)
{
this.Component4 = GameObject.AddComponent<T4>();
}
}
}
#endif

View File

@@ -1,345 +0,0 @@
#if UNITY_EDITOR
using UnityEditor;
// Settings MenuItems.
public static partial class UnitTestBuilder
{
[MenuItem("Test/Settings/ScriptBackend/Mono", validate = true, priority = 1)]
static bool ValidateScriptBackendMono()
{
Menu.SetChecked("Test/Settings/ScriptBackend/Mono", LoadOrGetDefaultSettings().ScriptBackend == ScriptingImplementation.Mono2x);
return true;
}
[MenuItem("Test/Settings/ScriptBackend/Mono", validate = false, priority = 1)]
static void ScriptBackendMono()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentScriptBackend = false;
settings.ScriptBackend = ScriptingImplementation.Mono2x;
SaveSettings(settings);
}
[MenuItem("Test/Settings/ScriptBackend/IL2CPP", validate = true, priority = 2)]
static bool ValidateScriptBackendIL2CPP()
{
Menu.SetChecked("Test/Settings/ScriptBackend/IL2CPP", LoadOrGetDefaultSettings().ScriptBackend == ScriptingImplementation.IL2CPP);
return true;
}
[MenuItem("Test/Settings/ScriptBackend/IL2CPP", validate = false, priority = 2)]
static void ScriptBackendIL2CPP()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentScriptBackend = false;
settings.ScriptBackend = ScriptingImplementation.IL2CPP;
SaveSettings(settings);
}
[MenuItem("Test/Settings/AutoRunPlayer", validate = true, priority = 3)]
static bool ValidateAutoRun()
{
Menu.SetChecked("Test/Settings/AutoRunPlayer", LoadOrGetDefaultSettings().AutoRunPlayer);
return true;
}
[MenuItem("Test/Settings/AutoRunPlayer", validate = false, priority = 3)]
static void AutoRun()
{
var settings = LoadOrGetDefaultSettings();
settings.AutoRunPlayer = !settings.AutoRunPlayer;
SaveSettings(settings);
}
[MenuItem("Test/Settings/Headless", validate = true, priority = 4)]
static bool ValidateHeadless()
{
Menu.SetChecked("Test/Settings/Headless", LoadOrGetDefaultSettings().Headless);
return true;
}
[MenuItem("Test/Settings/Headless", validate = false, priority = 4)]
static void Headless()
{
var settings = LoadOrGetDefaultSettings();
settings.Headless = !settings.Headless;
SaveSettings(settings);
}
[MenuItem("Test/Settings/DisableAutoClose", validate = true, priority = 5)]
static bool ValidateDisableAutoClose()
{
Menu.SetChecked("Test/Settings/DisableAutoClose", LoadOrGetDefaultSettings().DisableAutoClose);
return true;
}
[MenuItem("Test/Settings/DisableAutoClose", validate = false, priority = 5)]
static void DisableAutoClose()
{
var settings = LoadOrGetDefaultSettings();
settings.DisableAutoClose = !settings.DisableAutoClose;
SaveSettings(settings);
}
// generated
/*
*
void Main()
{
var sb = new StringBuilder();
var p = 1;
foreach (var target in Enum.GetNames(typeof(BuildTarget)))
{
var path = $"Test/Settings/BuildTarget/{target}";
var priority = p++;
var template = $@"
[MenuItem(""{path}"", validate = true, priority = {priority})]
static bool ValidateBuildTarget{target}()
{{
Menu.SetChecked(""{path}"", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.{target});
return true;
}}
[MenuItem(""{path}"", validate = false, priority = {priority})]
static void BuildTarget{target}()
{{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.{target};
SaveSettings(settings);
}}";
sb.AppendLine(template);
}
sb.ToString().Dump();
}
public enum BuildTarget
{
StandaloneWindows,
StandaloneWindows64,
StandaloneLinux,
StandaloneLinux64,
StandaloneOSX,
WebGL,
iOS,
Android,
WSAPlayer,
PS4,
XboxOne,
Switch,
}
*/
[MenuItem("Test/Settings/BuildTarget/StandaloneWindows", validate = true, priority = 1)]
static bool ValidateBuildTargetStandaloneWindows()
{
Menu.SetChecked("Test/Settings/BuildTarget/StandaloneWindows", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneWindows);
return true;
}
[MenuItem("Test/Settings/BuildTarget/StandaloneWindows", validate = false, priority = 1)]
static void BuildTargetStandaloneWindows()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneWindows;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/StandaloneWindows64", validate = true, priority = 2)]
static bool ValidateBuildTargetStandaloneWindows64()
{
Menu.SetChecked("Test/Settings/BuildTarget/StandaloneWindows64", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneWindows64);
return true;
}
[MenuItem("Test/Settings/BuildTarget/StandaloneWindows64", validate = false, priority = 2)]
static void BuildTargetStandaloneWindows64()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneWindows64;
SaveSettings(settings);
}
#if !UNITY_2019_2_OR_NEWER
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = true, priority = 3)]
static bool ValidateBuildTargetStandaloneLinux()
{
Menu.SetChecked("Test/Settings/BuildTarget/StandaloneLinux", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneLinux);
return true;
}
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = false, priority = 3)]
static void BuildTargetStandaloneLinux()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneLinux;
SaveSettings(settings);
}
#endif
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux64", validate = true, priority = 4)]
static bool ValidateBuildTargetStandaloneLinux64()
{
Menu.SetChecked("Test/Settings/BuildTarget/StandaloneLinux64", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneLinux64);
return true;
}
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux64", validate = false, priority = 4)]
static void BuildTargetStandaloneLinux64()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneLinux64;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/StandaloneOSX", validate = true, priority = 5)]
static bool ValidateBuildTargetStandaloneOSX()
{
Menu.SetChecked("Test/Settings/BuildTarget/StandaloneOSX", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneOSX);
return true;
}
[MenuItem("Test/Settings/BuildTarget/StandaloneOSX", validate = false, priority = 5)]
static void BuildTargetStandaloneOSX()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneOSX;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/WebGL", validate = true, priority = 6)]
static bool ValidateBuildTargetWebGL()
{
Menu.SetChecked("Test/Settings/BuildTarget/WebGL", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.WebGL);
return true;
}
[MenuItem("Test/Settings/BuildTarget/WebGL", validate = false, priority = 6)]
static void BuildTargetWebGL()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.WebGL;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/iOS", validate = true, priority = 7)]
static bool ValidateBuildTargetiOS()
{
Menu.SetChecked("Test/Settings/BuildTarget/iOS", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.iOS);
return true;
}
[MenuItem("Test/Settings/BuildTarget/iOS", validate = false, priority = 7)]
static void BuildTargetiOS()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.iOS;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/Android", validate = true, priority = 8)]
static bool ValidateBuildTargetAndroid()
{
Menu.SetChecked("Test/Settings/BuildTarget/Android", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.Android);
return true;
}
[MenuItem("Test/Settings/BuildTarget/Android", validate = false, priority = 8)]
static void BuildTargetAndroid()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.Android;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/WSAPlayer", validate = true, priority = 9)]
static bool ValidateBuildTargetWSAPlayer()
{
Menu.SetChecked("Test/Settings/BuildTarget/WSAPlayer", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.WSAPlayer);
return true;
}
[MenuItem("Test/Settings/BuildTarget/WSAPlayer", validate = false, priority = 9)]
static void BuildTargetWSAPlayer()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.WSAPlayer;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/PS4", validate = true, priority = 10)]
static bool ValidateBuildTargetPS4()
{
Menu.SetChecked("Test/Settings/BuildTarget/PS4", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.PS4);
return true;
}
[MenuItem("Test/Settings/BuildTarget/PS4", validate = false, priority = 10)]
static void BuildTargetPS4()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.PS4;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/XboxOne", validate = true, priority = 11)]
static bool ValidateBuildTargetXboxOne()
{
Menu.SetChecked("Test/Settings/BuildTarget/XboxOne", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.XboxOne);
return true;
}
[MenuItem("Test/Settings/BuildTarget/XboxOne", validate = false, priority = 11)]
static void BuildTargetXboxOne()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.XboxOne;
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/Switch", validate = true, priority = 12)]
static bool ValidateBuildTargetSwitch()
{
Menu.SetChecked("Test/Settings/BuildTarget/Switch", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.Switch);
return true;
}
[MenuItem("Test/Settings/BuildTarget/Switch", validate = false, priority = 12)]
static void BuildTargetSwitch()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.Switch;
SaveSettings(settings);
}
}
#endif

View File

@@ -1,546 +0,0 @@
#if UNITY_EDITOR
using RuntimeUnitTestToolkit;
using RuntimeUnitTestToolkit.Editor;
using System;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
internal class RuntimeUnitTestSettings
{
public ScriptingImplementation ScriptBackend;
public bool UseCurrentScriptBackend;
public BuildTarget BuildTarget;
public bool UseCurrentBuildTarget;
public bool Headless;
public bool AutoRunPlayer;
public bool DisableAutoClose;
public RuntimeUnitTestSettings()
{
UseCurrentBuildTarget = true;
UseCurrentScriptBackend = true;
Headless = false;
AutoRunPlayer = true;
DisableAutoClose = false;
}
public override string ToString()
{
return $"{ScriptBackend} {BuildTarget} Headless:{Headless} AutoRunPlayer:{AutoRunPlayer} DisableAutoClose:{DisableAutoClose}";
}
}
// no namespace(because invoke from commandline)
public static partial class UnitTestBuilder
{
const string SettingsKeyBase = "RuntimeUnitTest.Settings.";
[MenuItem("Test/BuildUnitTest")]
public static void BuildUnitTest()
{
var settings = new RuntimeUnitTestSettings(); // default
string buildPath = null;
if (Application.isBatchMode) // from commandline
{
settings.AutoRunPlayer = false;
settings.DisableAutoClose = false;
var cmdArgs = Environment.GetCommandLineArgs();
for (int i = 0; i < cmdArgs.Length; i++)
{
if (string.Equals(cmdArgs[i].Trim('-', '/'), "ScriptBackend", StringComparison.OrdinalIgnoreCase))
{
settings.UseCurrentScriptBackend = false;
var str = cmdArgs[++i];
if (str.StartsWith("mono", StringComparison.OrdinalIgnoreCase))
{
settings.ScriptBackend = ScriptingImplementation.Mono2x;
}
else if (str.StartsWith("IL2CPP", StringComparison.OrdinalIgnoreCase))
{
settings.ScriptBackend = ScriptingImplementation.IL2CPP;
}
else
{
settings.ScriptBackend = (ScriptingImplementation)Enum.Parse(typeof(ScriptingImplementation), str, true);
}
}
else if (string.Equals(cmdArgs[i].Trim('-', '/'), "BuildTarget", StringComparison.OrdinalIgnoreCase))
{
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = (BuildTarget)Enum.Parse(typeof(BuildTarget), cmdArgs[++i], true);
}
else if (string.Equals(cmdArgs[i].Trim('-', '/'), "Headless", StringComparison.OrdinalIgnoreCase))
{
settings.Headless = true;
}
else if (string.Equals(cmdArgs[i].Trim('-', '/'), "buildPath", StringComparison.OrdinalIgnoreCase))
{
buildPath = cmdArgs[++i];
}
}
}
else
{
var key = SettingsKeyBase + Application.productName;
var settingsValue = EditorPrefs.GetString(key, null);
try
{
if (!string.IsNullOrWhiteSpace(settingsValue))
{
settings = JsonUtility.FromJson<RuntimeUnitTestSettings>(settingsValue);
}
}
catch
{
UnityEngine.Debug.LogError("Fail to load RuntimeUnitTest settings");
EditorPrefs.SetString(key, null);
}
}
if (settings.UseCurrentBuildTarget)
{
settings.BuildTarget = EditorUserBuildSettings.activeBuildTarget;
}
if (settings.UseCurrentScriptBackend)
{
settings.ScriptBackend = PlayerSettings.GetScriptingBackend(ToBuildTargetGroup(settings.BuildTarget));
}
if (buildPath == null)
{
buildPath = $"bin/UnitTest/{settings.BuildTarget}_{settings.ScriptBackend}/test" + GetExtensionForBuildTarget(settings.BuildTarget);
}
var originalScene = SceneManager.GetActiveScene().path;
BuildUnitTest(buildPath, settings.ScriptBackend, settings.BuildTarget, settings.Headless, settings.AutoRunPlayer, settings.DisableAutoClose);
// reopen original scene
if (!string.IsNullOrWhiteSpace(originalScene))
{
EditorSceneManager.OpenScene(originalScene, OpenSceneMode.Single);
}
else
{
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
}
}
[MenuItem("Test/LoadUnitTestScene")]
public static void LoadUnitTestScene()
{
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
BuildUnitTestRunnerScene();
EditorSceneManager.MarkSceneDirty(scene);
}
static RuntimeUnitTestSettings LoadOrGetDefaultSettings()
{
var key = SettingsKeyBase + Application.productName;
var settingsValue = EditorPrefs.GetString(key, null);
RuntimeUnitTestSettings settings = null;
try
{
if (!string.IsNullOrWhiteSpace(settingsValue))
{
settings = JsonUtility.FromJson<RuntimeUnitTestSettings>(settingsValue);
}
}
catch
{
UnityEngine.Debug.LogError("Fail to load RuntimeUnitTest settings");
EditorPrefs.SetString(key, null);
settings = null;
}
if (settings == null)
{
// default
settings = new RuntimeUnitTestSettings
{
UseCurrentBuildTarget = true,
UseCurrentScriptBackend = true,
Headless = false,
AutoRunPlayer = true,
};
}
return settings;
}
static void SaveSettings(RuntimeUnitTestSettings settings)
{
var key = SettingsKeyBase + Application.productName;
EditorPrefs.SetString(key, JsonUtility.ToJson(settings));
}
public static void BuildUnitTest(string buildPath, ScriptingImplementation scriptBackend, BuildTarget buildTarget, bool headless, bool autoRunPlayer, bool disableAutoClose)
{
var sceneName = "Assets/TempRuntimeUnitTestScene_" + DateTimeOffset.UtcNow.ToUnixTimeSeconds();
if (disableAutoClose)
{
sceneName += "_DisableAutoClose";
}
sceneName += ".unity";
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
BuildUnitTestRunnerScene();
EditorSceneManager.MarkSceneDirty(scene);
AssetDatabase.SaveAssets();
EditorSceneManager.SaveScene(scene, sceneName, false);
try
{
Build(sceneName, buildPath, new RuntimeUnitTestSettings { ScriptBackend = scriptBackend, BuildTarget = buildTarget, Headless = headless, AutoRunPlayer = autoRunPlayer, DisableAutoClose = disableAutoClose });
}
finally
{
AssetDatabase.DeleteAsset(sceneName);
}
}
public static UnitTestRunner BuildUnitTestRunnerScene()
{
const string kStandardSpritePath = "UI/Skin/UISprite.psd";
const string kBackgroundSpritePath = "UI/Skin/Background.psd";
var uisprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
var background = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpritePath);
ScrollRect buttonList;
VerticalLayoutGroup listLayout;
Scrollbar refListScrollbar;
ScrollRect logList;
Scrollbar refLogScrollbar;
Button clearButton;
Text logText;
// Flutter like coded build utility
var rootObject = new Builder<Camera>("SceneRoot")
{
Children = new IBuilder[] {
new Builder<EventSystem, StandaloneInputModule>("EventSystem"),
new Builder<Canvas, CanvasScaler, GraphicRaycaster>("Canvas") {
Component1 = { renderMode = RenderMode.ScreenSpaceOverlay },
Children = new IBuilder[] {
new Builder<HorizontalLayoutGroup, CanvasRenderer>("HorizontalSplitter") {
RectTransform = { anchorMin = new Vector2(0, 0), anchorMax = new Vector2(1, 1) },
Component1 = { childControlWidth = true, childControlHeight = true, spacing = 10 },
Children = new IBuilder[] {
new Builder<ScrollRect, CanvasRenderer>("ButtonList", out buttonList) {
RectTransform = { pivot = new Vector2(0.5f, 0.5f) },
Component1 = { horizontal =false, vertical = true, movementType = ScrollRect.MovementType.Clamped },
Children = new IBuilder[] {
new Builder<VerticalLayoutGroup, ContentSizeFitter>("ListLayoutToAttach", out listLayout) {
RectTransform = { anchorMin = new Vector2(0, 0), anchorMax = new Vector2(1, 1), pivot = new Vector2(0, 1) },
Component1 = { childControlWidth = true, childControlHeight = true, childForceExpandWidth = true, childForceExpandHeight = false, spacing = 10, padding = new RectOffset(10,20,10,10) },
Component2 = { horizontalFit = ContentSizeFitter.FitMode.Unconstrained, verticalFit = ContentSizeFitter.FitMode.PreferredSize },
SetTarget = self => { buttonList.content = self.GetComponent<RectTransform>(); },
Child = new Builder<Button, Image, LayoutElement>("ClearButton", out clearButton) {
Component2 = { sprite = uisprite, type = Image.Type.Sliced },
Component3 = { minHeight = 50 },
SetTarget = self => { self.GetComponent<Button>().targetGraphic = self.GetComponent<Graphic>(); },
Child = new Builder<Text>("ButtonText") {
RectTransform = { anchorMin = new Vector2(0, 0), anchorMax = new Vector2(1, 1), pivot = new Vector2(0.5f, 0.5f) },
Component1 = { text = "Clear", color = FromRGB(50, 50, 50), alignment = TextAnchor.MiddleCenter, fontSize = 24, lineSpacing = 1 }
}
}
},
new Builder<Scrollbar,Image>("ListScrollbar", out refListScrollbar) {
RectTransform = { anchorMin = new Vector2(1, 0), anchorMax = new Vector2(1, 1) },
Component1 = { navigation = new Navigation{ mode = Navigation.Mode.None }, direction = Scrollbar.Direction.BottomToTop, size = 1.0f },
Component2 = { sprite = background, type = Image.Type.Sliced },
SetTarget = self => { buttonList.verticalScrollbar = self.GetComponent<Scrollbar>(); },
Child = new Builder<RectTransform>("Sliding Area") {
RectTransform = { anchorMin = new Vector2(0, 0), anchorMax = new Vector2(1, 1) },
Child = new Builder<Image>("Handle") {
Component1 = { sprite = uisprite, type = Image.Type.Sliced },
SetTarget = self =>
{
refListScrollbar.targetGraphic = self.GetComponent<Graphic>();
refListScrollbar.handleRect = self.GetComponent<RectTransform>();
}
}
}
}
}
},
new Builder<ScrollRect, CanvasRenderer>("ScrollableText", out logList) {
RectTransform = { pivot = new Vector2(0.5f, 0.5f) },
Component1 = { horizontal =false, vertical = true, movementType = ScrollRect.MovementType.Elastic, elasticity = 0.1f },
Children = new IBuilder[] {
new Builder<Text, ContentSizeFitter>("Log", out logText) {
RectTransform = { anchorMin = new Vector2(0, 0), anchorMax = new Vector2(1, 1), pivot = new Vector2(0, 1) },
Component1 = { fontSize = 24, lineSpacing = 1, supportRichText = true, alignment = TextAnchor.UpperLeft, horizontalOverflow = HorizontalWrapMode.Wrap, verticalOverflow = VerticalWrapMode.Truncate },
Component2 = { horizontalFit = ContentSizeFitter.FitMode.Unconstrained, verticalFit = ContentSizeFitter.FitMode.PreferredSize },
SetTarget = self => { logList.content = self.GetComponent<RectTransform>(); }
},
new Builder<Scrollbar,Image>("LogScrollbar", out refLogScrollbar) {
RectTransform = { anchorMin = new Vector2(1, 0), anchorMax = new Vector2(1, 1) },
Component1 = { navigation = new Navigation{ mode = Navigation.Mode.None }, direction = Scrollbar.Direction.BottomToTop, size = 1.0f },
Component2 = { sprite = background, type = Image.Type.Sliced },
SetTarget = self => { logList.verticalScrollbar = self.GetComponent<Scrollbar>(); },
Child = new Builder<RectTransform>("Sliding Area2") {
RectTransform = { anchorMin = new Vector2(0, 0), anchorMax = new Vector2(1, 1) },
Child = new Builder<Image>("Handle2") {
Component1 = { sprite = uisprite, type = Image.Type.Sliced },
SetTarget = self =>
{
refLogScrollbar.targetGraphic = self.GetComponent<Graphic>();
refLogScrollbar.handleRect = self.GetComponent<RectTransform>();
}
}
}
}
}
},
}
}
}
}
}
};
// size modify after build complete:)
{
var rect = GameObject.Find("HorizontalSplitter").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
}
{
var rect = GameObject.Find("ListLayoutToAttach").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
}
{
var rect = GameObject.Find("ListScrollbar").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
rect.sizeDelta = new Vector2(30, 0);
}
{
var rect = GameObject.Find("ClearButton").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
}
{
var rect = GameObject.Find("Sliding Area").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
rect.sizeDelta = new Vector2(-20, -20);
}
{
var rect = GameObject.Find("Handle").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
rect.sizeDelta = new Vector2(20, 20);
}
{
var rect = GameObject.Find("ButtonText").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
}
{
var rect = GameObject.Find("Log").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(15, 0);
rect.offsetMax = new Vector2(-20, 0);
}
{
var rect = GameObject.Find("LogScrollbar").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(-30, 0);
rect.offsetMax = new Vector2(0, 0);
rect.sizeDelta = new Vector2(30, 0);
}
{
var rect = GameObject.Find("Sliding Area2").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
rect.sizeDelta = new Vector2(-20, -20);
}
{
var rect = GameObject.Find("Handle2").GetComponent<RectTransform>();
rect.offsetMin = new Vector2(0, 0);
rect.offsetMax = new Vector2(0, 0);
rect.sizeDelta = new Vector2(20, 20);
}
// add test script
var runner = rootObject.GameObject.AddComponent<UnitTestRunner>();
runner.clearButton = clearButton;
runner.list = listLayout.gameObject.GetComponent<RectTransform>();
runner.listScrollBar = refListScrollbar;
runner.logText = logText;
runner.logScrollBar = refLogScrollbar;
return runner;
}
static void Build(string sceneName, string buildPath, RuntimeUnitTestSettings settings)
{
var options = BuildOptions.BuildScriptsOnly | BuildOptions.IncludeTestAssemblies;
if (settings.AutoRunPlayer)
{
options |= BuildOptions.AutoRunPlayer;
}
if (settings.Headless)
{
options |= BuildOptions.EnableHeadlessMode;
}
var targetGroup = ToBuildTargetGroup(settings.BuildTarget);
var currentBackend = PlayerSettings.GetScriptingBackend(targetGroup);
if (currentBackend != settings.ScriptBackend)
{
UnityEngine.Debug.Log("Modify ScriptBackend to " + settings.ScriptBackend);
PlayerSettings.SetScriptingBackend(targetGroup, settings.ScriptBackend);
}
var buildOptions = new BuildPlayerOptions
{
target = settings.BuildTarget,
targetGroup = targetGroup,
options = options,
scenes = new[] { sceneName },
locationPathName = buildPath
};
UnityEngine.Debug.Log("UnitTest Build Start, " + settings.ToString());
var buildReport = BuildPipeline.BuildPlayer(buildOptions);
if (currentBackend != settings.ScriptBackend)
{
UnityEngine.Debug.Log("Restore ScriptBackend to " + currentBackend);
PlayerSettings.SetScriptingBackend(targetGroup, currentBackend);
}
if (buildReport.summary.result != BuildResult.Succeeded)
{
// Note: show error summary?
// Debug.LogError(buildReport.SummarizeErrors());
UnityEngine.Debug.LogError("UnitTest Build Failed.");
}
else
{
UnityEngine.Debug.Log("UnitTest Build Completed, binary located: " + buildOptions.locationPathName);
}
}
static Color FromRGB(int r, int g, int b)
{
return new Color(r / 255f, g / 255f, b / 255f);
}
static bool IsWindows(BuildTarget buildTarget)
{
switch (buildTarget)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.WSAPlayer:
return true;
default:
return false;
}
}
static string GetExtensionForBuildTarget(BuildTarget buildTarget)
{
switch (buildTarget)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.WSAPlayer:
return ".exe";
case BuildTarget.StandaloneOSX:
return ".app";
case BuildTarget.Android:
return ".apk";
default:
return "";
}
}
static BuildTargetGroup ToBuildTargetGroup(BuildTarget buildTarget)
{
#pragma warning disable CS0618
switch (buildTarget)
{
#if UNITY_2017_3_OR_NEWER
case BuildTarget.StandaloneOSX:
#else
case BuildTarget.StandaloneOSXIntel:
case BuildTarget.StandaloneOSXIntel64:
case BuildTarget.StandaloneOSXUniversal:
#endif // UNITY_2017_3_OR_NEWER
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.StandaloneLinux64:
#if !UNITY_2019_2_OR_NEWER
case BuildTarget.StandaloneLinux:
case BuildTarget.StandaloneLinuxUniversal:
#endif // !UNITY_2019_2_OR_NEWER
return BuildTargetGroup.Standalone;
case (BuildTarget)6:
case (BuildTarget)7:
case BuildTarget.WebGL:
return BuildTargetGroup.WebGL;
case BuildTarget.iOS:
return BuildTargetGroup.iOS;
case BuildTarget.PS3:
return BuildTargetGroup.PS3;
case BuildTarget.PS4:
return BuildTargetGroup.PS4;
case BuildTarget.XBOX360:
return BuildTargetGroup.XBOX360;
case BuildTarget.Android:
return BuildTargetGroup.Android;
case BuildTarget.WSAPlayer:
return BuildTargetGroup.WSA;
case BuildTarget.WP8Player:
return BuildTargetGroup.WP8;
case BuildTarget.Tizen:
return BuildTargetGroup.Tizen;
case BuildTarget.PSP2:
return BuildTargetGroup.PSP2;
case BuildTarget.PSM:
return BuildTargetGroup.PSM;
case BuildTarget.XboxOne:
return BuildTargetGroup.XboxOne;
case BuildTarget.SamsungTV:
return BuildTargetGroup.SamsungTV;
case BuildTarget.N3DS:
return BuildTargetGroup.N3DS;
case BuildTarget.WiiU:
return BuildTargetGroup.WiiU;
case BuildTarget.tvOS:
return BuildTargetGroup.tvOS;
case BuildTarget.Switch:
return BuildTargetGroup.Switch;
case BuildTarget.Lumin:
return BuildTargetGroup.Lumin;
case BuildTarget.BlackBerry:
return BuildTargetGroup.BlackBerry;
case BuildTarget.NoTarget:
default:
return BuildTargetGroup.Unknown;
}
#pragma warning restore CS0618
}
}
#endif

View File

@@ -1,16 +0,0 @@
{
"name": "RuntimeUnitTestToolkit",
"references": [
],
"optionalUnityReferences": [
"TestAssemblies"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 14c4fea4b238088479114ba2ffe195f9
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,684 +0,0 @@
using NUnit.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.TestTools;
using UnityEngine.UI;
namespace RuntimeUnitTestToolkit
{
public class UnitTestRunner : MonoBehaviour
{
// object is IEnumerator or Func<IEnumerator>
Dictionary<string, List<TestKeyValuePair>> tests = new Dictionary<string, List<TestKeyValuePair>>();
List<Pair> additionalActionsOnFirst = new List<Pair>();
public Button clearButton;
public RectTransform list;
public Scrollbar listScrollBar;
public Text logText;
public Scrollbar logScrollBar;
readonly Color passColor = new Color(0f, 1f, 0f, 1f); // green
readonly Color failColor = new Color(1f, 0f, 0f, 1f); // red
readonly Color normalColor = new Color(1f, 1f, 1f, 1f); // white
bool allTestGreen = true;
bool logClear = false;
void Start()
{
try
{
UnityEngine.Application.logMessageReceived += (a, b, c) =>
{
if (a.Contains("Mesh can not have more than 65000 vertices"))
{
logClear = true;
}
else
{
AppendToGraphicText("[" + c + "]" + a + "\n");
WriteToConsole("[" + c + "]" + a);
}
};
// register all test types
foreach (var item in GetTestTargetTypes())
{
RegisterAllMethods(item);
}
var executeAll = new List<Func<Coroutine>>();
foreach (var ___item in tests)
{
var actionList = ___item; // be careful, capture in lambda
executeAll.Add(() => StartCoroutine(RunTestInCoroutine(actionList)));
Add(actionList.Key, () => StartCoroutine(RunTestInCoroutine(actionList)));
}
var executeAllButton = Add("Run All Tests", () => StartCoroutine(ExecuteAllInCoroutine(executeAll)));
clearButton.gameObject.GetComponent<Image>().color = new Color(170 / 255f, 170 / 255f, 170 / 255f, 1);
executeAllButton.gameObject.GetComponent<Image>().color = new Color(250 / 255f, 150 / 255f, 150 / 255f, 1);
executeAllButton.transform.SetSiblingIndex(1);
additionalActionsOnFirst.Reverse();
foreach (var item in additionalActionsOnFirst)
{
var newButton = GameObject.Instantiate(clearButton);
newButton.name = item.Name;
newButton.onClick.RemoveAllListeners();
newButton.GetComponentInChildren<Text>().text = item.Name;
newButton.onClick.AddListener(item.Action);
newButton.transform.SetParent(list);
newButton.transform.SetSiblingIndex(1);
}
clearButton.onClick.AddListener(() =>
{
logText.text = "";
foreach (var btn in list.GetComponentsInChildren<Button>())
{
btn.interactable = true;
btn.GetComponent<Image>().color = normalColor;
}
executeAllButton.gameObject.GetComponent<Image>().color = new Color(250 / 255f, 150 / 255f, 150 / 255f, 1);
});
listScrollBar.value = 1;
logScrollBar.value = 1;
if (Application.isBatchMode)
{
// run immediately in player
StartCoroutine(ExecuteAllInCoroutine(executeAll));
}
}
catch (Exception ex)
{
if (Application.isBatchMode)
{
// when failed(can not start runner), quit immediately.
WriteToConsole(ex.ToString());
Application.Quit(1);
}
else
{
throw;
}
}
}
Button Add(string title, UnityAction test)
{
var newButton = GameObject.Instantiate(clearButton);
newButton.name = title;
newButton.onClick.RemoveAllListeners();
newButton.GetComponentInChildren<Text>().text = title;
newButton.onClick.AddListener(test);
newButton.transform.SetParent(list);
return newButton;
}
static IEnumerable<Type> GetTestTargetTypes()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var n = assembly.FullName;
if (n.StartsWith("UnityEngine")) continue;
if (n.StartsWith("mscorlib")) continue;
if (n.StartsWith("System")) continue;
foreach (var item in assembly.GetTypes())
{
foreach (var method in item.GetMethods())
{
TestAttribute t1 = null;
try
{
t1 = method.GetCustomAttribute<TestAttribute>(true);
}
catch (Exception ex)
{
Debug.Log("TestAttribute Load Fail, Assembly:" + assembly.FullName);
Debug.LogException(ex);
goto NEXT_ASSEMBLY;
}
if (t1 != null)
{
yield return item;
break;
}
UnityTestAttribute t2 = null;
try
{
t2 = method.GetCustomAttribute<UnityTestAttribute>(true);
}
catch (Exception ex)
{
Debug.Log("UnityTestAttribute Load Fail, Assembly:" + assembly.FullName);
Debug.LogException(ex);
goto NEXT_ASSEMBLY;
}
if (t2 != null)
{
yield return item;
break;
}
}
}
NEXT_ASSEMBLY:
continue;
}
}
public void AddTest(string group, string title, Action test, List<Action> setups, List<Action> teardowns)
{
List<TestKeyValuePair> list;
if (!tests.TryGetValue(group, out list))
{
list = new List<TestKeyValuePair>();
tests[group] = list;
}
list.Add(new TestKeyValuePair(title, test, setups, teardowns));
}
public void AddAsyncTest(string group, string title, Func<IEnumerator> asyncTestCoroutine, List<Action> setups, List<Action> teardowns)
{
List<TestKeyValuePair> list;
if (!tests.TryGetValue(group, out list))
{
list = new List<TestKeyValuePair>();
tests[group] = list;
}
list.Add(new TestKeyValuePair(title, asyncTestCoroutine, setups, teardowns));
}
public void AddCutomAction(string name, UnityAction action)
{
additionalActionsOnFirst.Add(new Pair { Name = name, Action = action });
}
public void RegisterAllMethods<T>()
where T : new()
{
RegisterAllMethods(typeof(T));
}
public void RegisterAllMethods(Type testType)
{
try
{
var test = Activator.CreateInstance(testType);
var methods = testType.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
List<Action> setups = new List<Action>();
List<Action> teardowns = new List<Action>();
foreach (var item in methods)
{
try
{
var setup = item.GetCustomAttribute<NUnit.Framework.SetUpAttribute>(true);
if (setup != null)
{
setups.Add((Action)Delegate.CreateDelegate(typeof(Action), test, item));
}
var teardown = item.GetCustomAttribute<NUnit.Framework.TearDownAttribute>(true);
if (teardown != null)
{
teardowns.Add((Action)Delegate.CreateDelegate(typeof(Action), test, item));
}
}
catch (Exception e)
{
UnityEngine.Debug.LogError(testType.Name + "." + item.Name + " failed to register setup/teardown method, exception: " + e.ToString());
}
}
foreach (var item in methods)
{
try
{
var iteratorTest = item.GetCustomAttribute<UnityEngine.TestTools.UnityTestAttribute>(true);
if (iteratorTest != null)
{
if (item.GetParameters().Length == 0 && item.ReturnType == typeof(IEnumerator))
{
var factory = (Func<IEnumerator>)Delegate.CreateDelegate(typeof(Func<IEnumerator>), test, item);
AddAsyncTest(factory.Target.GetType().Name, factory.Method.Name, factory, setups, teardowns);
}
else
{
var testData = GetTestData(item);
if (testData.Count != 0)
{
foreach (var item2 in testData)
{
Func<IEnumerator> factory;
if (item.IsGenericMethod)
{
var method2 = InferGenericType(item, item2);
factory = () => (IEnumerator)method2.Invoke(test, item2);
}
else
{
factory = () => (IEnumerator)item.Invoke(test, item2);
}
var name = item.Name + "(" + string.Join(", ", item2.Select(x => x?.ToString() ?? "null")) + ")";
name = name.Replace(Char.MinValue, ' ').Replace(Char.MaxValue, ' ').Replace("<", "[").Replace(">", "]");
AddAsyncTest(test.GetType().Name, name, factory, setups, teardowns);
}
}
else
{
UnityEngine.Debug.Log(testType.Name + "." + item.Name + " currently does not supported in RuntumeUnitTestToolkit(multiple parameter without TestCase or return type is invalid).");
}
}
}
var standardTest = item.GetCustomAttribute<NUnit.Framework.TestAttribute>(true);
if (standardTest != null)
{
if (item.GetParameters().Length == 0 && item.ReturnType == typeof(void))
{
var invoke = (Action)Delegate.CreateDelegate(typeof(Action), test, item);
AddTest(invoke.Target.GetType().Name, invoke.Method.Name, invoke, setups, teardowns);
}
else
{
var testData = GetTestData(item);
if (testData.Count != 0)
{
foreach (var item2 in testData)
{
Action invoke = null;
if (item.IsGenericMethod)
{
var method2 = InferGenericType(item, item2);
invoke = () => method2.Invoke(test, item2);
}
else
{
invoke = () => item.Invoke(test, item2);
}
var name = item.Name + "(" + string.Join(", ", item2.Select(x => x?.ToString() ?? "null")) + ")";
name = name.Replace(Char.MinValue, ' ').Replace(Char.MaxValue, ' ').Replace("<", "[").Replace(">", "]");
AddTest(test.GetType().Name, name, invoke, setups, teardowns);
}
}
else
{
UnityEngine.Debug.Log(testType.Name + "." + item.Name + " currently does not supported in RuntumeUnitTestToolkit(multiple parameter without TestCase or return type is invalid).");
}
}
}
}
catch (Exception e)
{
UnityEngine.Debug.LogError(testType.Name + "." + item.Name + " failed to register method, exception: " + e.ToString());
}
}
}
catch (Exception ex)
{
Debug.LogException(ex);
}
}
List<object[]> GetTestData(MethodInfo methodInfo)
{
List<object[]> testCases = new List<object[]>();
var inlineData = methodInfo.GetCustomAttributes<NUnit.Framework.TestCaseAttribute>(true);
foreach (var item in inlineData)
{
testCases.Add(item.Arguments);
}
var sourceData = methodInfo.GetCustomAttributes<NUnit.Framework.TestCaseSourceAttribute>(true);
foreach (var item in sourceData)
{
var enumerator = GetTestCaseSource(methodInfo, item.SourceType, item.SourceName, item.MethodParams);
foreach (var item2 in enumerator)
{
var item3 = item2 as IEnumerable; // object[][]
if (item3 != null)
{
var l = new List<object>();
foreach (var item4 in item3)
{
l.Add(item4);
}
testCases.Add(l.ToArray());
}
}
}
return testCases;
}
IEnumerable GetTestCaseSource(MethodInfo method, Type sourceType, string sourceName, object[] methodParams)
{
Type type = sourceType ?? method.DeclaringType;
MemberInfo[] member = type.GetMember(sourceName, BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (member.Length == 1)
{
MemberInfo memberInfo = member[0];
FieldInfo fieldInfo = memberInfo as FieldInfo;
if ((object)fieldInfo != null)
{
return (!fieldInfo.IsStatic) ? ReturnErrorAsParameter("The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.") : ((methodParams == null) ? ((IEnumerable)fieldInfo.GetValue(null)) : ReturnErrorAsParameter("You have specified a data source field but also given a set of parameters. Fields cannot take parameters, please revise the 3rd parameter passed to the TestCaseSourceAttribute and either remove it or specify a method."));
}
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
if ((object)propertyInfo != null)
{
return (!propertyInfo.GetGetMethod(nonPublic: true).IsStatic) ? ReturnErrorAsParameter("The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.") : ((methodParams == null) ? ((IEnumerable)propertyInfo.GetValue(null, null)) : ReturnErrorAsParameter("You have specified a data source property but also given a set of parameters. Properties cannot take parameters, please revise the 3rd parameter passed to the TestCaseSource attribute and either remove it or specify a method."));
}
MethodInfo methodInfo = memberInfo as MethodInfo;
if ((object)methodInfo != null)
{
return (!methodInfo.IsStatic) ? ReturnErrorAsParameter("The sourceName specified on a TestCaseSourceAttribute must refer to a static field, property or method.") : ((methodParams == null || methodInfo.GetParameters().Length == methodParams.Length) ? ((IEnumerable)methodInfo.Invoke(null, methodParams)) : ReturnErrorAsParameter("You have given the wrong number of arguments to the method in the TestCaseSourceAttribute, please check the number of parameters passed in the object is correct in the 3rd parameter for the TestCaseSourceAttribute and this matches the number of parameters in the target method and try again."));
}
}
return null;
}
MethodInfo InferGenericType(MethodInfo methodInfo, object[] parameters)
{
var set = new HashSet<Type>();
List<Type> genericParameters = new List<Type>();
foreach (var item in methodInfo.GetParameters()
.Select((x, i) => new { x.ParameterType, i })
.Where(x => x.ParameterType.IsGenericParameter)
.OrderBy(x => x.ParameterType.GenericParameterPosition))
{
if (set.Add(item.ParameterType)) // DistinctBy
{
genericParameters.Add(parameters[item.i].GetType());
}
}
return methodInfo.MakeGenericMethod(genericParameters.ToArray());
}
IEnumerable ReturnErrorAsParameter(string name)
{
throw new Exception(name);
}
System.Collections.IEnumerator ScrollLogToEndNextFrame()
{
yield return null;
yield return null;
logScrollBar.value = 0;
}
IEnumerator RunTestInCoroutine(KeyValuePair<string, List<TestKeyValuePair>> actionList)
{
Button self = null;
foreach (var btn in list.GetComponentsInChildren<Button>())
{
btn.interactable = false;
if (btn.name == actionList.Key) self = btn;
}
if (self != null)
{
self.GetComponent<Image>().color = normalColor;
}
var allGreen = true;
AppendToGraphicText("<color=yellow>" + actionList.Key + "</color>\n");
WriteToConsole("Begin Test Class: " + actionList.Key);
yield return null;
var totalExecutionTime = new List<double>();
foreach (var item2 in actionList.Value)
{
// setup
try
{
foreach (var setup in item2.Setups)
{
setup();
}
// before start, cleanup
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
AppendToGraphicText("<color=teal>" + item2.Key + "</color>\n");
yield return null;
var v = item2.Value;
var methodStopwatch = System.Diagnostics.Stopwatch.StartNew();
Exception exception = null;
if (v is Action)
{
try
{
((Action)v).Invoke();
}
catch (Exception ex)
{
exception = ex;
}
}
else
{
var coroutineFactory = (Func<IEnumerator>)v;
IEnumerator coroutine = null;
try
{
coroutine = coroutineFactory();
}
catch (Exception ex)
{
exception = ex;
}
if (exception == null)
{
yield return StartCoroutine(UnwrapEnumerator(coroutine, ex =>
{
exception = ex;
}));
}
}
methodStopwatch.Stop();
totalExecutionTime.Add(methodStopwatch.Elapsed.TotalMilliseconds);
if (exception == null)
{
AppendToGraphicText("OK, " + methodStopwatch.Elapsed.TotalMilliseconds.ToString("0.00") + "ms\n");
WriteToConsoleResult(item2.Key + ", " + methodStopwatch.Elapsed.TotalMilliseconds.ToString("0.00") + "ms", true);
}
else
{
AppendToGraphicText("<color=red>" + exception.ToString() + "</color>\n");
WriteToConsoleResult(item2.Key + ", " + exception.ToString(), false);
allGreen = false;
allTestGreen = false;
}
}
finally
{
foreach (var teardown in item2.Teardowns)
{
teardown();
}
}
}
AppendToGraphicText("[" + actionList.Key + "]" + totalExecutionTime.Sum().ToString("0.00") + "ms\n\n");
foreach (var btn in list.GetComponentsInChildren<Button>()) btn.interactable = true;
if (self != null)
{
self.GetComponent<Image>().color = allGreen ? passColor : failColor;
}
yield return StartCoroutine(ScrollLogToEndNextFrame());
}
IEnumerator ExecuteAllInCoroutine(List<Func<Coroutine>> tests)
{
allTestGreen = true;
foreach (var item in tests)
{
yield return item();
}
if (Application.isBatchMode)
{
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
bool disableAutoClose = (scene.name.Contains("DisableAutoClose"));
if (allTestGreen)
{
WriteToConsole("Test Complete Successfully");
if (!disableAutoClose)
{
Application.Quit();
}
}
else
{
WriteToConsole("Test Failed, please see [NG] log.");
if (!disableAutoClose)
{
Application.Quit(1);
}
}
}
}
IEnumerator UnwrapEnumerator(IEnumerator enumerator, Action<Exception> exceptionCallback)
{
var hasNext = true;
while (hasNext)
{
try
{
hasNext = enumerator.MoveNext();
}
catch (Exception ex)
{
exceptionCallback(ex);
hasNext = false;
}
if (hasNext)
{
// unwrap self for bug of Unity
// https://issuetracker.unity3d.com/issues/does-not-stop-coroutine-when-it-throws-exception-in-movenext-at-first-frame
var moreCoroutine = enumerator.Current as IEnumerator;
if (moreCoroutine != null)
{
yield return StartCoroutine(UnwrapEnumerator(moreCoroutine, ex =>
{
exceptionCallback(ex);
hasNext = false;
}));
}
else
{
yield return enumerator.Current;
}
}
}
}
static void WriteToConsole(string msg)
{
if (Application.isBatchMode)
{
Console.WriteLine(msg);
}
}
void AppendToGraphicText(string msg)
{
if (!Application.isBatchMode)
{
if (logClear)
{
logText.text = "";
logClear = false;
}
try
{
logText.text += msg;
}
catch
{
logClear = true;
}
}
}
static void WriteToConsoleResult(string msg, bool green)
{
if (Application.isBatchMode)
{
if (!green)
{
var currentForeground = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("[NG]");
Console.ForegroundColor = currentForeground;
}
else
{
var currentForeground = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("[OK]");
Console.ForegroundColor = currentForeground;
}
System.Console.WriteLine(msg);
}
}
struct Pair
{
public string Name;
public UnityAction Action;
}
}
public class TestKeyValuePair
{
public string Key;
/// <summary>IEnumerator or Func[IEnumerator]</summary>
public object Value;
public List<Action> Setups;
public List<Action> Teardowns;
public TestKeyValuePair(string key, object value, List<Action> setups, List<Action> teardowns)
{
this.Key = key;
this.Value = value;
this.Setups = setups;
this.Teardowns = teardowns;
}
}
}

View File

@@ -1,11 +0,0 @@
{
"name": "com.cysharp.runtimeunittesttoolkit",
"displayName": "RuntimeUnitTestToolkit",
"version": "2.3.0",
"unity": "2018.3",
"description": "CLI/GUI Frontend of Unity Test Runner to test on any platform.",
"keywords": ["test"],
"category": "Tests",
"dependencies": {
}
}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: b7883c7ac5d6ea4409a229aeab14e796
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -216,7 +216,7 @@
// RETRY:
// try
// {
// context.RequestHeaders["x-accesss-token"] = token;
// context.RequestHeaders["x-access-token"] = token;
// return await next(context, cancellationToken);
// }
// catch (UnityWebRequestException ex)

View File

@@ -20,8 +20,11 @@ using System.IO;
using System.Linq.Expressions;
// using DG.Tweening;
public struct MyJob : IJob
{
public int loopCount;
@@ -116,7 +119,28 @@ public class AsyncMessageBroker<T> : IDisposable
connection.Dispose();
}
}
public class WhenEachTest
{
public async UniTask Each()
{
var a = Delay(1, 3000);
var b = Delay(2, 1000);
var c = Delay(3, 2000);
var l = new List<int>();
await foreach (var item in UniTask.WhenEach(a, b, c))
{
Debug.Log(item.Result);
}
}
async UniTask<int> Delay(int id, int sleep)
{
await UniTask.Delay(sleep);
return id;
}
}
public class SandboxMain : MonoBehaviour
{
@@ -144,6 +168,18 @@ public class SandboxMain : MonoBehaviour
Debug.Log("Again");
// var foo = InstantiateAsync<SandboxMain>(this).ToUniTask();
// var tako = await foo;
return 10;
}
@@ -543,7 +579,7 @@ public class SandboxMain : MonoBehaviour
Debug.LogError(e);
return;
}
}
Debug.Log("TestAsync Finished.");
@@ -554,6 +590,8 @@ public class SandboxMain : MonoBehaviour
async UniTaskVoid Start()
{
await new WhenEachTest().Each();
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
@@ -562,61 +600,34 @@ public class SandboxMain : MonoBehaviour
PlayerLoopHelper.Initialize(ref currentLoop, InjectPlayerLoopTimings.Minimum); // minimum is Update | FixedUpdate | LastPostLateUpdate
var cancelToken = new CancellationTokenSource();
cancelButton.onClick.AddListener(()=>
{
cancelToken.Cancel(); // cancel from button click.
});
var timeoutToken = new CancellationTokenSource();
timeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
try
{
// combine token
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, timeoutToken.Token);
await UnityWebRequest.Get("http://foo").SendWebRequest().WithCancellation(linkedTokenSource.Token);
}
catch (OperationCanceledException ex)
{
if (timeoutToken.IsCancellationRequested)
{
UnityEngine.Debug.Log("Timeout.");
}
else if (cancelToken.IsCancellationRequested)
{
UnityEngine.Debug.Log("Cancel clicked.");
}
_ = ex;
}
// TestAsync(cts.Token).Forget();
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
{
// try timeout
try
{
//await UniTask.Delay(TimeSpan.FromSeconds(2), cancellationToken: timeoutController.Timeout(TimeSpan.FromSeconds(3)));
UnityEngine.Debug.Log("Delay Complete, Reset(and reuse).");
//timeoutController.Reset();
}
catch (OperationCanceledException ex)
{
//UnityEngine.Debug.Log("Timeout! FromTimeout?:" + timeoutController.IsTimeout());
_ = ex;
}
await UniTask.WaitForEndOfFrame(this);
var texture = new Texture2D(Screen.width, Screen.height);
texture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
texture.Apply();
await UniTask.Yield();
var jpg = texture.EncodeToJPG();
File.WriteAllBytes("testscreencapture.jpg", jpg);
Debug.Log("ok?");
//var texture = ScreenCapture.CaptureScreenshotAsTexture();
//if (texture == null)
//{
// Debug.Log("fail");
//}
//else
//{
// var jpg = texture.EncodeToJPG();
// File.WriteAllBytes("testscreencapture.jpg", jpg);
// Debug.Log("ok?");
//}
}));
cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>

View File

@@ -13,7 +13,7 @@ OcclusionCullingSettings:
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
@@ -38,13 +38,11 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 1
serializedVersion: 12
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
@@ -67,9 +65,6 @@ LightmapSettings:
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 0
@@ -98,13 +93,14 @@ LightmapSettings:
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
m_LightingSettings: {fileID: 4890085278179872738, guid: 814185d368762ed45a2298d112780689,
type: 2}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
@@ -117,7 +113,9 @@ NavMeshSettings:
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
@@ -150,10 +148,10 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1584557232}
m_Father: {fileID: 1556045508}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
@@ -174,6 +172,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
@@ -218,6 +217,8 @@ MonoBehaviour:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
@@ -270,9 +271,17 @@ Camera:
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
@@ -306,12 +315,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 518730348}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 488, y: 418, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &519420028
GameObject:
@@ -352,9 +362,11 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
m_Name:
m_EditorClassIdentifier:
camera: {fileID: 518730349}
mycamera: {fileID: 0}
okButton: {fileID: 16537672}
cancelButton: {fileID: 628393011}
RP1:
latestValue: 0
text: {fileID: 2101290655}
button: {fileID: 0}
--- !u!20 &519420031
@@ -371,9 +383,17 @@ Camera:
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
@@ -407,12 +427,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 519420028}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &628393009
GameObject:
@@ -443,10 +464,10 @@ RectTransform:
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 865871445}
m_Father: {fileID: 1556045508}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
@@ -467,6 +488,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
@@ -511,6 +533,8 @@ MonoBehaviour:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
@@ -560,9 +584,9 @@ RectTransform:
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 628393010}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
@@ -584,6 +608,8 @@ MonoBehaviour:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
@@ -639,6 +665,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SendPointerHoverToParent: 1
m_HorizontalAxis: Horizontal
m_VerticalAxis: Vertical
m_SubmitButton: Submit
@@ -668,12 +695,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 872009839}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1556045504
GameObject:
@@ -733,6 +761,7 @@ MonoBehaviour:
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 0
--- !u!223 &1556045507
Canvas:
m_ObjectHideFlags: 0
@@ -750,7 +779,9 @@ Canvas:
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
@@ -764,12 +795,12 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 16537671}
- {fileID: 628393010}
- {fileID: 2101290654}
m_Father: {fileID: 0}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -804,9 +835,9 @@ RectTransform:
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 16537671}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
@@ -828,6 +859,8 @@ MonoBehaviour:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
@@ -883,9 +916,9 @@ RectTransform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1556045508}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
@@ -907,6 +940,8 @@ MonoBehaviour:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
@@ -932,3 +967,11 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2101290653}
m_CullTransparentMesh: 0
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 519420032}
- {fileID: 518730350}
- {fileID: 872009842}
- {fileID: 1556045508}

View File

@@ -0,0 +1,74 @@
using Cysharp.Threading.Tasks;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
// https://github.com/Cysharp/UniTask/issues/617
public class WaitWhileTest : MonoBehaviour
{
private const float c_CallInterval = 0.3f;
private float m_JustBeforeCallTime;
private TaskObj m_TestObj;
// Start is called before the first frame update
void Start()
{
m_JustBeforeCallTime = Time.unscaledTime;
m_TestObj = new TaskObj();
// m_TestObj.Test(CancellationToken.None).Forget();
}
// Update is called once per frame
void Update()
{
if (Time.unscaledTime - m_JustBeforeCallTime > c_CallInterval)
{
m_JustBeforeCallTime = Time.unscaledTime;
m_TestObj.Test(CancellationToken.None).Forget();
}
}
}
public class TaskObj
{
private CancellationTokenSource m_CancelTokenSource;
private const float c_FinishElapsedTime = 0.1f;
private float m_StartTime;
public async UniTask Test(CancellationToken token)
{
try
{
CancelAndDisposeTokenSource();
m_CancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);
m_StartTime = Time.unscaledTime;
await UniTask.WaitWhile(IsContinued, cancellationToken: m_CancelTokenSource.Token, cancelImmediately: true);
Debug.Log("Task Finished");
}
catch (OperationCanceledException)
{
Debug.LogWarning("Task Canceled");
}
finally
{
CancelAndDisposeTokenSource();
}
}
private void CancelAndDisposeTokenSource()
{
m_CancelTokenSource?.Cancel();
m_CancelTokenSource?.Dispose();
m_CancelTokenSource = null;
}
private bool IsContinued()
{
return Time.unscaledTime - m_StartTime > c_FinishElapsedTime;
}
}

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 660baed073888b8438569f57e42679b2
timeCreated: 1476793308
licenseType: Pro
guid: a478e5f6126dc184ca902adfb35401b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@@ -0,0 +1,90 @@
using System.Collections;
using System.Threading;
using Cysharp.Threading.Tasks;
using FluentAssertions;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.TestTools;
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Cysharp.Threading.TasksTests
{
public class AsyncOperationTest
{
[UnityTest]
public IEnumerator ResourcesLoad_Completed() => UniTask.ToCoroutine(async () =>
{
var asyncOperation = Resources.LoadAsync<Texture2D>("sample_texture");
await asyncOperation.ToUniTask();
asyncOperation.isDone.Should().BeTrue();
asyncOperation.asset.GetType().Should().Be(typeof(Texture2D));
});
[UnityTest]
public IEnumerator ResourcesLoad_CancelOnPlayerLoop() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
var task = Resources.LoadAsync<Texture>("sample_texture").ToUniTask(cancellationToken: cts.Token, cancelImmediately: false);
cts.Cancel();
task.Status.Should().Be(UniTaskStatus.Pending);
await UniTask.NextFrame();
task.Status.Should().Be(UniTaskStatus.Canceled);
});
[Test]
public void ResourcesLoad_CancelImmediately()
{
{
var cts = new CancellationTokenSource();
var task = Resources.LoadAsync<Texture>("sample_texture").ToUniTask(cancellationToken: cts.Token, cancelImmediately: true);
cts.Cancel();
task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
[UnityTest]
public IEnumerator UnityWebRequest_Completed() => UniTask.ToCoroutine(async () =>
{
var filePath = System.IO.Path.Combine(Application.dataPath, "Tests", "Resources", "sample_texture.png");
var asyncOperation = UnityWebRequest.Get($"file://{filePath}").SendWebRequest();
await asyncOperation.ToUniTask();
asyncOperation.isDone.Should().BeTrue();
asyncOperation.webRequest.result.Should().Be(UnityWebRequest.Result.Success);
});
[UnityTest]
public IEnumerator UnityWebRequest_CancelOnPlayerLoop() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
var filePath = System.IO.Path.Combine(Application.dataPath, "Tests", "Resources", "sample_texture.png");
var task = UnityWebRequest.Get($"file://{filePath}").SendWebRequest().ToUniTask(cancellationToken: cts.Token);
cts.Cancel();
task.Status.Should().Be(UniTaskStatus.Pending);
await UniTask.NextFrame();
task.Status.Should().Be(UniTaskStatus.Canceled);
});
[Test]
public void UnityWebRequest_CancelImmediately()
{
var cts = new CancellationTokenSource();
cts.Cancel();
var filePath = System.IO.Path.Combine(Application.dataPath, "Tests", "Resources", "sample_texture.png");
var task = UnityWebRequest.Get($"file://{filePath}").SendWebRequest().ToUniTask(cancellationToken: cts.Token, cancelImmediately: true);
task.Status.Should().Be(UniTaskStatus.Canceled);
}
#endif
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 295d574a16494d6aa4d02fcb32179e39
timeCreated: 1698887128

View File

@@ -145,6 +145,11 @@ namespace Cysharp.Threading.TasksTests
public int MyProperty { get; set; }
}
class MyBooleanClass
{
public bool MyProperty { get; set; }
}
[UnityTest]
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
{
@@ -159,6 +164,20 @@ namespace Cysharp.Threading.TasksTests
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator WaitUntilWithState() => UniTask.ToCoroutine(async () =>
{
var v = new MyBooleanClass { MyProperty = false };
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => v.MyProperty = true).Forget();
var startFrame = Time.frameCount;
await UniTask.WaitUntil(v, static v => v.MyProperty, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame;
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
{
@@ -173,6 +192,20 @@ namespace Cysharp.Threading.TasksTests
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator WaitWhileWithState() => UniTask.ToCoroutine(async () =>
{
var v = new MyBooleanClass { MyProperty = true };
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(() => v.MyProperty = false).Forget();
var startFrame = Time.frameCount;
await UniTask.WaitWhile(v, static v => v.MyProperty, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame;
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
{
@@ -310,33 +343,33 @@ namespace Cysharp.Threading.TasksTests
yield return null;
}
[UnityTest]
public IEnumerator ExceptionUnobserved1() => UniTask.ToCoroutine(async () =>
{
bool calledEx = false;
Action<Exception> action = exx =>
{
calledEx = true;
exx.Message.Should().Be("MyException");
};
//[UnityTest]
//public IEnumerator ExceptionUnobserved1() => UniTask.ToCoroutine(async () =>
//{
// bool calledEx = false;
// Action<Exception> action = exx =>
// {
// calledEx = true;
// exx.Message.Should().Be("MyException");
// };
UniTaskScheduler.UnobservedTaskException += action;
// UniTaskScheduler.UnobservedTaskException += action;
var ex = InException1();
ex = default(UniTask);
// var ex = InException1();
// ex = default(UniTask);
await UniTask.DelayFrame(3);
// await UniTask.DelayFrame(3);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// GC.Collect();
// GC.WaitForPendingFinalizers();
// GC.Collect();
await UniTask.DelayFrame(1);
// await UniTask.DelayFrame(1);
calledEx.Should().BeTrue();
// calledEx.Should().BeTrue();
UniTaskScheduler.UnobservedTaskException -= action;
});
// UniTaskScheduler.UnobservedTaskException -= action;
//});
[UnityTest]
public IEnumerator ExceptionUnobserved2() => UniTask.ToCoroutine(async () =>
@@ -366,6 +399,29 @@ namespace Cysharp.Threading.TasksTests
UniTaskScheduler.UnobservedTaskException -= action;
});
// can not run on RuntimeUnitTestToolkit so ignore...
// [UnityTest]
// public IEnumerator ThrowExceptionUnawaited() => UniTask.ToCoroutine(async () =>
// {
// LogAssert.Expect(LogType.Exception, "Exception: MyException");
//#pragma warning disable 1998
// async UniTask Throw() => throw new Exception("MyException");
//#pragma warning restore 1998
//#pragma warning disable 4014
// Throw();
//#pragma warning restore 4014
// await UniTask.DelayFrame(3);
// GC.Collect();
// GC.WaitForPendingFinalizers();
// GC.Collect();
// await UniTask.DelayFrame(1);
// });
async UniTask InException1()
{
await UniTask.Yield();

View File

@@ -1,4 +1,6 @@
using Cysharp.Threading.Tasks;
#pragma warning disable CS0618
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using FluentAssertions;
using NUnit.Framework;

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 959c1472a5d812843bedf9341e87af3b
guid: 8d82913edf6ac48aca30f66ae9ba42d6
folderAsset: yes
DefaultImporter:
externalObjects: {}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,215 @@
fileFormatVersion: 2
guid: 535006a83baed4ebda99d24a909a2efe
TextureImporter:
internalIDToNameTable:
- first:
213: -2664112245596591751
second: sample_texture_0
- first:
213: -4606777057269188692
second: sample_texture_1
- first:
213: 1950921086533113773
second: sample_texture_2
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: sample_texture_0
rect:
serializedVersion: 2
x: 0
y: 76
width: 243
height: 251
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: 9796277170c270bd0800000000000000
internalID: -2664112245596591751
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: sample_texture_1
rect:
serializedVersion: 2
x: 227
y: 0
width: 190
height: 231
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: ca7fc069ca07110c0800000000000000
internalID: -4606777057269188692
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: sample_texture_2
rect:
serializedVersion: 2
x: 398
y: 87
width: 202
height: 188
alignment: 0
pivot: {x: 0, y: 0}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: -1
bones: []
spriteID: da710ab4460131b10800000000000000
internalID: 1950921086533113773
vertices: []
indices:
edges: []
weights: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable:
sample_texture_0: -2664112245596591751
sample_texture_1: -4606777057269188692
sample_texture_2: 1950921086533113773
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,6 @@
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#pragma warning disable CS0618
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine;

View File

@@ -0,0 +1,45 @@
{
"dependencies": {
"com.cysharp.runtimeunittesttoolkit": "https://github.com/Cysharp/RuntimeUnitTestToolkit.git?path=RuntimeUnitTestToolkit/Assets/RuntimeUnitTestToolkit#2.6.0",
"com.unity.collab-proxy": "2.4.3",
"com.unity.ide.rider": "3.0.31",
"com.unity.ide.visualstudio": "2.0.22",
"com.unity.ide.vscode": "1.2.5",
"com.unity.test-framework": "1.1.33",
"com.unity.textmeshpro": "3.0.6",
"com.unity.timeline": "1.7.6",
"com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.9",
"com.unity.ugui": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
}
}

View File

@@ -0,0 +1,360 @@
{
"dependencies": {
"com.cysharp.runtimeunittesttoolkit": {
"version": "https://github.com/Cysharp/RuntimeUnitTestToolkit.git?path=RuntimeUnitTestToolkit/Assets/RuntimeUnitTestToolkit#2.6.0",
"depth": 0,
"source": "git",
"dependencies": {},
"hash": "4e3dbfaa9c40b5cfdcb71a1d4e8bca0d45ca1055"
},
"com.unity.collab-proxy": {
"version": "2.4.3",
"depth": 0,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.ext.nunit": {
"version": "1.0.6",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.ide.rider": {
"version": "3.0.31",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ext.nunit": "1.0.6"
},
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": {
"version": "2.0.22",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.test-framework": "1.1.9"
},
"url": "https://packages.unity.com"
},
"com.unity.ide.vscode": {
"version": "1.2.5",
"depth": 0,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.sysroot": {
"version": "2.0.10",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.sysroot.linux-x86_64": {
"version": "2.0.9",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.sysroot": "2.0.10"
},
"url": "https://packages.unity.com"
},
"com.unity.test-framework": {
"version": "1.1.33",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ext.nunit": "1.0.6",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.textmeshpro": {
"version": "3.0.6",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ugui": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.timeline": {
"version": "1.7.6",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.modules.director": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.toolchain.win-x86_64-linux-x86_64": {
"version": "2.0.9",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.sysroot": "2.0.10",
"com.unity.sysroot.linux-x86_64": "2.0.9"
},
"url": "https://packages.unity.com"
},
"com.unity.ugui": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0"
}
},
"com.unity.modules.ai": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.androidjni": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.animation": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.assetbundle": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.audio": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.cloth": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0"
}
},
"com.unity.modules.director": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.animation": "1.0.0"
}
},
"com.unity.modules.imageconversion": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.imgui": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.jsonserialize": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.particlesystem": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.physics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.physics2d": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.screencapture": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.subsystems": {
"version": "1.0.0",
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0"
}
},
"com.unity.modules.terrain": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.terrainphysics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.terrain": "1.0.0"
}
},
"com.unity.modules.tilemap": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics2d": "1.0.0"
}
},
"com.unity.modules.ui": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.uielements": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
}
},
"com.unity.modules.umbra": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.unityanalytics": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
}
},
"com.unity.modules.unitywebrequest": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.unitywebrequestassetbundle": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
}
},
"com.unity.modules.unitywebrequestaudio": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.audio": "1.0.0"
}
},
"com.unity.modules.unitywebrequesttexture": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.unitywebrequestwww": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0"
}
},
"com.unity.modules.vehicles": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0"
}
},
"com.unity.modules.video": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
}
},
"com.unity.modules.vr": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.xr": "1.0.0"
}
},
"com.unity.modules.wind": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.xr": {
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.subsystems": "1.0.0"
}
}
}
}

View File

@@ -0,0 +1,35 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!387306366 &1
MemorySettings:
m_ObjectHideFlags: 0
m_EditorMemorySettings:
m_MainAllocatorBlockSize: -1
m_ThreadAllocatorBlockSize: -1
m_MainGfxBlockSize: -1
m_ThreadGfxBlockSize: -1
m_CacheBlockSize: -1
m_TypetreeBlockSize: -1
m_ProfilerBlockSize: -1
m_ProfilerEditorBlockSize: -1
m_BucketAllocatorGranularity: -1
m_BucketAllocatorBucketsCount: -1
m_BucketAllocatorBlockSize: -1
m_BucketAllocatorBlockCount: -1
m_ProfilerBucketAllocatorGranularity: -1
m_ProfilerBucketAllocatorBucketsCount: -1
m_ProfilerBucketAllocatorBlockSize: -1
m_ProfilerBucketAllocatorBlockCount: -1
m_TempAllocatorSizeMain: -1
m_JobTempAllocatorBlockSize: -1
m_BackgroundJobTempAllocatorBlockSize: -1
m_JobTempAllocatorReducedBlockSize: -1
m_TempAllocatorSizeGIBakingWorker: -1
m_TempAllocatorSizeNavMeshWorker: -1
m_TempAllocatorSizeAudioWorker: -1
m_TempAllocatorSizeCloudWorker: -1
m_TempAllocatorSizeGfx: -1
m_TempAllocatorSizeJobWorker: -1
m_TempAllocatorSizeBackgroundWorker: -1
m_TempAllocatorSizePreloadManager: -1
m_PlatformMemorySettings: {}

View File

@@ -3,7 +3,7 @@
--- !u!129 &1
PlayerSettings:
m_ObjectHideFlags: 0
serializedVersion: 20
serializedVersion: 26
productGUID: 904cd7a3163037f42a9204c0e2f2b7bd
AndroidProfiler: 0
AndroidFilterTouchesWhenObscured: 0
@@ -48,12 +48,16 @@ PlayerSettings:
defaultScreenHeightWeb: 600
m_StereoRenderingPath: 0
m_ActiveColorSpace: 0
unsupportedMSAAFallback: 0
m_SpriteBatchVertexThreshold: 300
m_MTRendering: 1
mipStripping: 0
numberOfMipsStripped: 0
numberOfMipsStrippedPerMipmapLimitGroup: {}
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
iosShowActivityIndicatorOnLoading: -1
androidShowActivityIndicatorOnLoading: -1
iosUseCustomAppBackgroundBehavior: 0
iosAllowHTTPDownload: 1
allowedAutorotateToPortrait: 1
allowedAutorotateToPortraitUpsideDown: 1
allowedAutorotateToLandscapeRight: 1
@@ -66,6 +70,13 @@ PlayerSettings:
androidRenderOutsideSafeArea: 1
androidUseSwappy: 0
androidBlitType: 0
androidResizableWindow: 0
androidDefaultWindowWidth: 1920
androidDefaultWindowHeight: 1080
androidMinimumWindowWidth: 400
androidMinimumWindowHeight: 300
androidFullscreenMode: 1
androidAutoRotationBehavior: 1
defaultIsNativeResolution: 1
macRetinaSupport: 1
runInBackground: 1
@@ -77,6 +88,7 @@ PlayerSettings:
hideHomeButton: 0
submitAnalytics: 1
usePlayerLog: 1
dedicatedServerOptimizations: 0
bakeCollisionMeshes: 0
forceSingleInstance: 0
useFlipModelSwapchain: 1
@@ -111,16 +123,22 @@ PlayerSettings:
switchNVNShaderPoolsGranularity: 33554432
switchNVNDefaultPoolsGranularity: 16777216
switchNVNOtherPoolsGranularity: 16777216
switchGpuScratchPoolGranularity: 2097152
switchAllowGpuScratchShrinking: 0
switchNVNMaxPublicTextureIDCount: 0
switchNVNMaxPublicSamplerIDCount: 0
switchNVNGraphicsFirmwareMemory: 32
switchMaxWorkerMultiple: 8
stadiaPresentMode: 0
stadiaTargetFramerate: 0
vulkanNumSwapchainBuffers: 3
vulkanEnableSetSRGBWrite: 0
m_SupportedAspectRatios:
4:3: 1
5:4: 1
16:10: 1
16:9: 1
Others: 1
vulkanEnablePreTransform: 0
vulkanEnableLateAcquireNextImage: 0
vulkanEnableCommandBufferRecycling: 1
loadStoreDebugModeEnabled: 0
visionOSBundleVersion: 1.0
tvOSBundleVersion: 1.0
bundleVersion: 0.1
preloadedAssets: []
metroInputSource: 0
@@ -129,46 +147,29 @@ PlayerSettings:
xboxOneDisableKinectGpuReservation: 1
xboxOneEnable7thCore: 1
vrSettings:
cardboard:
depthFormat: 0
enableTransitionView: 0
daydream:
depthFormat: 0
useSustainedPerformanceMode: 0
enableVideoLayer: 0
useProtectedVideoMemory: 0
minimumSupportedHeadTracking: 0
maximumSupportedHeadTracking: 1
hololens:
depthFormat: 1
depthBufferSharingEnabled: 1
lumin:
depthFormat: 0
frameTiming: 2
enableGLCache: 0
glCacheMaxBlobSize: 524288
glCacheMaxFileSize: 8388608
oculus:
sharedDepthBuffer: 1
dashSupport: 1
lowOverheadMode: 0
protectedContext: 0
v2Signing: 1
enable360StereoCapture: 0
isWsaHolographicRemotingEnabled: 0
enableFrameTimingStats: 0
enableOpenGLProfilerGPURecorders: 1
allowHDRDisplaySupport: 0
useHDRDisplay: 0
D3DHDRBitDepth: 0
hdrBitDepth: 0
m_ColorGamuts: 00000000
targetPixelDensity: 30
resolutionScalingMode: 0
resetResolutionOnWindowResize: 0
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier:
Standalone: com.Company.ProductName
buildNumber: {}
Standalone: com.DefaultCompany.UniTask
buildNumber:
Standalone: 0
VisionOS: 0
iPhone: 0
tvOS: 0
overrideDefaultApplicationIdentifier: 0
AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 19
AndroidMinSdkVersion: 22
AndroidTargetSdkVersion: 0
AndroidPreferredInstallLocation: 1
aotOptions:
@@ -181,12 +182,15 @@ PlayerSettings:
APKExpansionFiles: 0
keepLoadedShadersAlive: 0
StripUnusedMeshComponents: 1
strictShaderVariantMatching: 0
VertexChannelCompressionMask: 4054
iPhoneSdkVersion: 988
iOSTargetOSVersionString: 10.0
iOSTargetOSVersionString: 12.0
tvOSSdkVersion: 0
tvOSRequireExtendedGameController: 0
tvOSTargetOSVersionString: 10.0
tvOSTargetOSVersionString: 12.0
VisionOSSdkVersion: 0
VisionOSTargetOSVersionString: 1.0
uIPrerenderedIcon: 0
uIRequiresPersistentWiFi: 0
uIRequiresFullScreen: 1
@@ -220,32 +224,48 @@ PlayerSettings:
iOSLaunchScreeniPadFillPct: 100
iOSLaunchScreeniPadSize: 100
iOSLaunchScreeniPadCustomXibPath:
iOSUseLaunchScreenStoryboard: 0
iOSLaunchScreenCustomStoryboardPath:
iOSLaunchScreeniPadCustomStoryboardPath:
iOSDeviceRequirements: []
iOSURLSchemes: []
macOSURLSchemes: []
iOSBackgroundModes: 0
iOSMetalForceHardShadows: 0
metalEditorSupport: 1
metalAPIValidation: 1
metalCompileShaderBinary: 0
iOSRenderExtraFrameOnPause: 0
iosCopyPluginsCodeInsteadOfSymlink: 0
appleDeveloperTeamID:
iOSManualSigningProvisioningProfileID:
tvOSManualSigningProvisioningProfileID:
VisionOSManualSigningProvisioningProfileID:
iOSManualSigningProvisioningProfileType: 0
tvOSManualSigningProvisioningProfileType: 0
VisionOSManualSigningProvisioningProfileType: 0
appleEnableAutomaticSigning: 0
iOSRequireARKit: 0
iOSAutomaticallyDetectAndAddCapabilities: 1
appleEnableProMotion: 0
shaderPrecisionModel: 0
clonedFromGUID: 5f34be1353de5cf4398729fda238591b
templatePackageId: com.unity.template.2d@3.1.0
templateDefaultScene: Assets/Scenes/SampleScene.unity
useCustomMainManifest: 0
useCustomLauncherManifest: 0
useCustomMainGradleTemplate: 0
useCustomLauncherGradleManifest: 0
useCustomBaseGradleTemplate: 0
useCustomGradlePropertiesTemplate: 0
useCustomGradleSettingsTemplate: 0
useCustomProguardFile: 0
AndroidTargetArchitectures: 1
AndroidTargetDevices: 0
AndroidSplashScreenScale: 0
androidSplashScreen: {fileID: 0}
AndroidKeystoreName: '{inproject}: '
AndroidKeyaliasName:
AndroidEnableArmv9SecurityFeatures: 0
AndroidBuildApkPerCpuArchitecture: 0
AndroidTVCompatibility: 0
AndroidIsGame: 1
@@ -258,11 +278,15 @@ PlayerSettings:
height: 180
banner: {fileID: 0}
androidGamepadSupportLevel: 0
chromeosInputEmulation: 1
AndroidMinifyRelease: 0
AndroidMinifyDebug: 0
AndroidValidateAppBundleSize: 1
AndroidAppBundleSizeToValidate: 100
m_BuildTargetIcons: []
m_BuildTargetPlatformIcons: []
m_BuildTargetBatching: []
m_BuildTargetShaderSettings: []
m_BuildTargetGraphicsJobs:
- m_BuildTarget: MacStandaloneSupport
m_GraphicsJobs: 0
@@ -298,8 +322,13 @@ PlayerSettings:
m_BuildTargetGraphicsAPIs:
- m_BuildTarget: AndroidPlayer
m_APIs: 150000000b000000
m_Automatic: 0
m_Automatic: 1
- m_BuildTarget: iOSSupport
m_APIs: 10000000
m_Automatic: 1
m_BuildTargetVRSettings: []
m_DefaultShaderChunkSizeInMB: 16
m_DefaultShaderChunkCount: 0
openGLRequireES31: 0
openGLRequireES31AEP: 0
openGLRequireES32: 0
@@ -309,7 +338,11 @@ PlayerSettings:
iPhone: 1
tvOS: 1
m_BuildTargetGroupLightmapEncodingQuality: []
m_BuildTargetGroupHDRCubemapEncodingQuality: []
m_BuildTargetGroupLightmapSettings: []
m_BuildTargetGroupLoadStoreDebugModeSettings: []
m_BuildTargetNormalMapEncoding: []
m_BuildTargetDefaultTextureCompressionFormat: []
playModeTestRunnerEnabled: 0
runPlayModeTestAsEditModeTest: 0
actionOnDotNetUnhandledException: 1
@@ -319,14 +352,20 @@ PlayerSettings:
cameraUsageDescription:
locationUsageDescription:
microphoneUsageDescription:
bluetoothUsageDescription:
macOSTargetOSVersion: 10.13.0
switchNMETAOverride:
switchNetLibKey:
switchSocketMemoryPoolSize: 6144
switchSocketAllocatorPoolSize: 128
switchSocketConcurrencyLimit: 14
switchScreenResolutionBehavior: 2
switchUseCPUProfiler: 0
switchEnableFileSystemTrace: 0
switchLTOSetting: 0
switchApplicationID: 0x01004b9000490000
switchNSODependencies:
switchCompilerFlags:
switchTitleNames_0:
switchTitleNames_1:
switchTitleNames_2:
@@ -342,6 +381,7 @@ PlayerSettings:
switchTitleNames_12:
switchTitleNames_13:
switchTitleNames_14:
switchTitleNames_15:
switchPublisherNames_0:
switchPublisherNames_1:
switchPublisherNames_2:
@@ -357,6 +397,7 @@ PlayerSettings:
switchPublisherNames_12:
switchPublisherNames_13:
switchPublisherNames_14:
switchPublisherNames_15:
switchIcons_0: {fileID: 0}
switchIcons_1: {fileID: 0}
switchIcons_2: {fileID: 0}
@@ -372,6 +413,7 @@ PlayerSettings:
switchIcons_12: {fileID: 0}
switchIcons_13: {fileID: 0}
switchIcons_14: {fileID: 0}
switchIcons_15: {fileID: 0}
switchSmallIcons_0: {fileID: 0}
switchSmallIcons_1: {fileID: 0}
switchSmallIcons_2: {fileID: 0}
@@ -387,6 +429,7 @@ PlayerSettings:
switchSmallIcons_12: {fileID: 0}
switchSmallIcons_13: {fileID: 0}
switchSmallIcons_14: {fileID: 0}
switchSmallIcons_15: {fileID: 0}
switchManualHTML:
switchAccessibleURLs:
switchLegalInformation:
@@ -396,7 +439,6 @@ PlayerSettings:
switchReleaseVersion: 0
switchDisplayVersion: 1.0.0
switchStartupUserAccount: 0
switchTouchScreenUsage: 0
switchSupportedLanguagesMask: 0
switchLogoType: 0
switchApplicationErrorCodeCategory:
@@ -438,6 +480,7 @@ PlayerSettings:
switchNativeFsCacheSize: 32
switchIsHoldTypeHorizontal: 0
switchSupportedNpadCount: 8
switchEnableTouchScreen: 1
switchSocketConfigEnabled: 0
switchTcpInitialSendBufferSize: 32
switchTcpInitialReceiveBufferSize: 64
@@ -448,7 +491,12 @@ PlayerSettings:
switchSocketBufferEfficiency: 4
switchSocketInitializeEnabled: 1
switchNetworkInterfaceManagerInitializeEnabled: 1
switchPlayerConnectionEnabled: 1
switchUseNewStyleFilepaths: 0
switchUseLegacyFmodPriorities: 0
switchUseMicroSleepForYield: 1
switchEnableRamDiskSupport: 0
switchMicroSleepForYieldTime: 25
switchRamDiskSpaceSize: 12
ps4NPAgeRating: 12
ps4NPTitleSecret:
ps4NPTrophyPackPath:
@@ -475,6 +523,7 @@ PlayerSettings:
ps4ShareFilePath:
ps4ShareOverlayImagePath:
ps4PrivacyGuardImagePath:
ps4ExtraSceSysFile:
ps4NPtitleDatPath:
ps4RemotePlayKeyAssignment: -1
ps4RemotePlayKeyMappingDir:
@@ -517,6 +566,9 @@ PlayerSettings:
ps4disableAutoHideSplash: 0
ps4videoRecordingFeaturesUsed: 0
ps4contentSearchFeaturesUsed: 0
ps4CompatibilityPS5: 0
ps4AllowPS5Detection: 0
ps4GPU800MHz: 1
ps4attribEyeToEyeDistanceSettingVR: 0
ps4IncludedModules: []
ps4attribVROutputEnabled: 0
@@ -528,6 +580,7 @@ PlayerSettings:
webGLMemorySize: 16
webGLExceptionSupport: 1
webGLNameFilesAsHashes: 0
webGLShowDiagnostics: 0
webGLDataCaching: 1
webGLDebugSymbols: 0
webGLEmscriptenArgs:
@@ -536,18 +589,47 @@ PlayerSettings:
webGLAnalyzeBuildSize: 0
webGLUseEmbeddedResources: 0
webGLCompressionFormat: 1
webGLWasmArithmeticExceptions: 0
webGLLinkerTarget: 1
webGLThreadsSupport: 0
webGLWasmStreaming: 0
webGLDecompressionFallback: 0
webGLInitialMemorySize: 32
webGLMaximumMemorySize: 2048
webGLMemoryGrowthMode: 2
webGLMemoryLinearGrowthStep: 16
webGLMemoryGeometricGrowthStep: 0.2
webGLMemoryGeometricGrowthCap: 96
webGLPowerPreference: 2
scriptingDefineSymbols: {}
additionalCompilerArguments: {}
platformArchitecture: {}
scriptingBackend:
Android: 1
Server: 1
Standalone: 1
il2cppCompilerConfiguration: {}
managedStrippingLevel: {}
il2cppCodeGeneration: {}
managedStrippingLevel:
Android: 1
EmbeddedLinux: 1
GameCoreScarlett: 1
GameCoreXboxOne: 1
Nintendo Switch: 1
PS4: 1
PS5: 1
QNX: 1
Stadia: 1
Standalone: 1
VisionOS: 1
WebGL: 1
Windows Store Apps: 1
XboxOne: 1
iPhone: 1
tvOS: 1
incrementalIl2cppBuild: {}
suppressCommonWarnings: 1
allowUnsafeCode: 0
useDeterministicCompilation: 1
additionalIl2CppArgs:
scriptingRuntimeVersion: 1
gcIncremental: 0
@@ -578,11 +660,13 @@ PlayerSettings:
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
a: 1}
metroSplashScreenUseBackgroundColor: 0
syncCapabilities: 0
platformCapabilities: {}
metroTargetDeviceFamilies: {}
metroFTAName:
metroFTAFileTypes: []
metroProtocolName:
vcxProjDefaultLanguage:
XboxOneProductId:
XboxOneUpdateKey:
XboxOneSandboxId:
@@ -601,6 +685,7 @@ PlayerSettings:
XboxOneCapability: []
XboxOneGameRating: {}
XboxOneIsContentPackage: 0
XboxOneEnhancedXboxCompatibilityMode: 0
XboxOneEnableGPUVariability: 1
XboxOneSockets: {}
XboxOneSplashScreen: {fileID: 0}
@@ -609,10 +694,7 @@ PlayerSettings:
XboxOneXTitleMemory: 8
XboxOneOverrideIdentityName:
XboxOneOverrideIdentityPublisher:
vrEditorSettings:
daydream:
daydreamIconForeground: {fileID: 0}
daydreamIconBackground: {fileID: 0}
vrEditorSettings: {}
cloudServicesEnabled:
UNet: 1
luminIcon:
@@ -626,12 +708,22 @@ PlayerSettings:
luminVersion:
m_VersionCode: 1
m_VersionName:
hmiPlayerDataPath:
hmiForceSRGBBlit: 1
embeddedLinuxEnableGamepadInput: 1
hmiLogStartupTiming: 0
hmiCpuConfiguration:
apiCompatibilityLevel: 6
activeInputHandler: 0
windowsGamepadBackendHint: 0
cloudProjectId:
framebufferDepthMemorylessMode: 0
qualitySettingsNames: []
projectName:
organizationId:
cloudEnabled: 0
enableNativePlatformBackendsForNewInputSystem: 0
disableOldInputManagerSupport: 0
legacyClampBlendShapeWeights: 1
hmiLoadingImage: {fileID: 0}
platformRequiresReadableAssets: 0
virtualTexturingSupportEnabled: 0
insecureHttpOption: 0

View File

@@ -1,2 +1,2 @@
m_EditorVersion: 2020.2.1f1
m_EditorVersionWithRevision: 2020.2.1f1 (270dd8c3da1c)
m_EditorVersion: 2022.3.39f1
m_EditorVersionWithRevision: 2022.3.39f1 (4e1b0f82c39a)

View File

@@ -0,0 +1,121 @@
{
"templatePinStates": [],
"dependencyTypeInfos": [
{
"userAdded": false,
"type": "UnityEngine.AnimationClip",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.Animations.AnimatorController",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.AnimatorOverrideController",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.Audio.AudioMixerController",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.ComputeShader",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.Cubemap",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.GameObject",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.LightingDataAsset",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.LightingSettings",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Material",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.MonoScript",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.PhysicMaterial",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.PhysicsMaterial2D",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Rendering.PostProcessing.PostProcessResources",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Rendering.VolumeProfile",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEditor.SceneAsset",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.Shader",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.ShaderVariantCollection",
"defaultInstantiationMode": 1
},
{
"userAdded": false,
"type": "UnityEngine.Texture",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Texture2D",
"defaultInstantiationMode": 0
},
{
"userAdded": false,
"type": "UnityEngine.Timeline.TimelineAsset",
"defaultInstantiationMode": 0
}
],
"defaultDependencyTypeInfo": {
"userAdded": false,
"type": "<default_scene_template_dependencies>",
"defaultInstantiationMode": 1
},
"newSceneOverride": 0
}

View File

@@ -9,6 +9,7 @@ UnityConnectSettings:
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
m_ConfigUrl: https://config.uca.cloud.unity3d.com
m_DashboardUrl: https://dashboard.unity3d.com
m_TestInitMode: 0
CrashReportingSettings:
m_EventUrl: https://perf-events.cloud.unity3d.com
@@ -22,6 +23,7 @@ UnityConnectSettings:
m_Enabled: 0
m_TestMode: 0
m_InitializeOnStartup: 1
m_PackageRequiringCoreStatsPresent: 0
UnityAdsSettings:
m_Enabled: 0
m_InitializeOnStartup: 1

Some files were not shown because too many files have changed in this diff Show More