mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-17 04:30:13 +00:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9e27c03d4 | ||
|
|
73a63b7f67 | ||
|
|
30bec5d5c4 | ||
|
|
ec9204d381 | ||
|
|
9a6584ff0d | ||
|
|
98538ef7c7 | ||
|
|
519590ca6e | ||
|
|
dce4366f3e | ||
|
|
88026ab14a | ||
|
|
95998ff3f2 | ||
|
|
64285ae060 | ||
|
|
40e020fb02 | ||
|
|
e63dba1350 | ||
|
|
f213ff497e | ||
|
|
7568061eda | ||
|
|
459a572c1d | ||
|
|
06067cd4c8 | ||
|
|
d9983cfe27 | ||
|
|
70eb7cd3ee | ||
|
|
cc3c70af90 | ||
|
|
8042b29ff8 | ||
|
|
b0d01ca75f | ||
|
|
7a63ab7088 | ||
|
|
bdf102f145 | ||
|
|
41cea030ab | ||
|
|
f9fd769be7 | ||
|
|
579304fe47 | ||
|
|
740ca7ef01 | ||
|
|
7c0f199fe0 | ||
|
|
9a3ec31533 | ||
|
|
37d8f4f48e | ||
|
|
27a0c06ede | ||
|
|
e4082ecd75 | ||
|
|
3b0fd784ff | ||
|
|
dc9ebfd765 | ||
|
|
005c83fbd7 | ||
|
|
5984b67ecb | ||
|
|
05fdf48058 | ||
|
|
647ed6ff82 | ||
|
|
0826b7e976 | ||
|
|
a51632cd4b | ||
|
|
bf945a7ef4 | ||
|
|
353f15e94f | ||
|
|
cf19f18662 | ||
|
|
fdb9d1cf95 | ||
|
|
2e0917428b | ||
|
|
0b16005f4b | ||
|
|
74bbe87b58 | ||
|
|
6f4131539b | ||
|
|
06283f0ffb | ||
|
|
dfe5ee43c2 | ||
|
|
eaa553dc83 | ||
|
|
83d8a2b424 | ||
|
|
4d204e4aa6 | ||
|
|
87e164e275 | ||
|
|
b63eb8d090 | ||
|
|
75119acb50 | ||
|
|
f7b3c2fbe1 | ||
|
|
b317ecfa01 | ||
|
|
7b05569ef7 | ||
|
|
e0465c6c2c | ||
|
|
9057452c86 | ||
|
|
a2f6f84bde | ||
|
|
f057abff0f | ||
|
|
c61a7d9961 | ||
|
|
9587f2eeec | ||
|
|
550784f31c | ||
|
|
11b3282b3d | ||
|
|
b2532b0798 | ||
|
|
4fc41ecb17 | ||
|
|
e52663cef6 | ||
|
|
1827be2de7 | ||
|
|
8560561ef3 | ||
|
|
2019f1fa7f | ||
|
|
9e2265d148 | ||
|
|
9d02279822 | ||
|
|
17ce06d93c | ||
|
|
7b810413fe | ||
|
|
d78c0d6c02 | ||
|
|
d248acc7d1 | ||
|
|
4c0b1f753a | ||
|
|
7bb6feda55 | ||
|
|
f8a501290a | ||
|
|
cb497c9eb5 | ||
|
|
342a37a074 | ||
|
|
c3146ec74f | ||
|
|
df16813fae | ||
|
|
8d98bbc7ba | ||
|
|
bb095697f7 | ||
|
|
cdf88c6a6a | ||
|
|
4eee2c9270 | ||
|
|
222b1401f5 | ||
|
|
fbe0bf8515 | ||
|
|
626685292c | ||
|
|
67794f5cdd | ||
|
|
2e225fb841 | ||
|
|
935523f25c | ||
|
|
3b3f7ebd3e | ||
|
|
88ecfa2992 | ||
|
|
aa70fe5c5a | ||
|
|
0c8057c668 | ||
|
|
28867646b0 | ||
|
|
ca60864021 | ||
|
|
1e4561da22 | ||
|
|
1496cc990a | ||
|
|
7bb3bf8d0e | ||
|
|
d057074f17 | ||
|
|
b724a2aa84 | ||
|
|
938ddd5356 | ||
|
|
911c37d4d8 | ||
|
|
caccccb0b5 | ||
|
|
a48f11d31b | ||
|
|
fcd93feb56 | ||
|
|
b472b23773 | ||
|
|
01c8fada1f | ||
|
|
10cd137126 | ||
|
|
809d23edae | ||
|
|
d38731bc44 | ||
|
|
64792b672d | ||
|
|
3892cc2299 | ||
|
|
5bfccaa3b6 |
13
.config/dotnet-tools.json
Normal file
13
.config/dotnet-tools.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"docfx": {
|
||||||
|
"version": "2.78.3",
|
||||||
|
"commands": [
|
||||||
|
"docfx"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
.editorconfig
Normal file
41
.editorconfig
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# Visual Studio Spell checker configs (https://learn.microsoft.com/en-us/visualstudio/ide/text-spell-checker?view=vs-2022#how-to-customize-the-spell-checker)
|
||||||
|
spelling_exclusion_path = ./exclusion.dic
|
||||||
|
|
||||||
|
[*.cs]
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8-bom
|
||||||
|
end_of_line = unset
|
||||||
|
|
||||||
|
# Solution files
|
||||||
|
[*.{sln,slnx}]
|
||||||
|
end_of_line = unset
|
||||||
|
|
||||||
|
# MSBuild project files
|
||||||
|
[*.{csproj,props,targets}]
|
||||||
|
end_of_line = unset
|
||||||
|
|
||||||
|
# Xml config files
|
||||||
|
[*.{ruleset,config,nuspec,resx,runsettings,DotSettings}]
|
||||||
|
end_of_line = unset
|
||||||
|
|
||||||
|
[*{_AssemblyInfo.cs,.notsupported.cs}]
|
||||||
|
generated_code = true
|
||||||
|
|
||||||
|
# C# code style settings
|
||||||
|
[*.{cs}]
|
||||||
|
dotnet_diagnostic.IDE0044.severity = none # IDE0044: Make field readonly
|
||||||
|
|
||||||
|
# https://stackoverflow.com/questions/79195382/how-to-disable-fading-unused-methods-in-visual-studio-2022-17-12-0
|
||||||
|
dotnet_diagnostic.IDE0051.severity = none # IDE0051: Remove unused private member
|
||||||
|
dotnet_diagnostic.IDE0130.severity = none # IDE0130: Namespace does not match folder structure
|
||||||
18
.github/dependabot.yaml
vendored
Normal file
18
.github/dependabot.yaml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# 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
|
||||||
|
groups:
|
||||||
|
dependencies:
|
||||||
|
patterns:
|
||||||
|
- "*"
|
||||||
|
cooldown:
|
||||||
|
default-days: 14 # Wait 14 days before creating another PR for the same dependency. This will prevent vulnerability on the package impact.
|
||||||
|
ignore:
|
||||||
|
# I just want update action when major/minor version is updated. patch updates are too noisy.
|
||||||
|
- dependency-name: "*"
|
||||||
|
update-types:
|
||||||
|
- version-update:semver-patch
|
||||||
93
.github/workflows/build-debug.yaml
vendored
Normal file
93
.github/workflows/build-debug.yaml
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
name: Build-Debug
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-dotnet:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||||
|
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||||
|
- run: dotnet build -c Release
|
||||||
|
- run: dotnet test -c Release
|
||||||
|
- run: dotnet pack -c Release --no-build -p:IncludeSymbols=true -o $GITHUB_WORKSPACE/artifacts
|
||||||
|
|
||||||
|
build-unity:
|
||||||
|
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: ["2022.3.39f1", "6000.0.12f1"] # Test with LTS
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 30 # Unity build takes more than 20min.
|
||||||
|
steps:
|
||||||
|
- name: Load secrets
|
||||||
|
id: op-load-secret
|
||||||
|
uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 # v2.0.0
|
||||||
|
with:
|
||||||
|
export-env: false
|
||||||
|
env:
|
||||||
|
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
|
||||||
|
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
|
||||||
|
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
|
||||||
|
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
|
||||||
|
|
||||||
|
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||||
|
|
||||||
|
# Execute scripts: Export Package
|
||||||
|
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||||
|
- name: Build Unity (.unitypacakge)
|
||||||
|
if: ${{ startsWith(matrix.unity, '2022') }} # only execute once
|
||||||
|
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: PackageExporter.Export
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
||||||
|
with:
|
||||||
|
directory: src/UniTask
|
||||||
|
|
||||||
|
# Store artifacts.
|
||||||
|
- 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
|
||||||
69
.github/workflows/build-debug.yml
vendored
69
.github/workflows/build-debug.yml
vendored
@@ -1,69 +0,0 @@
|
|||||||
name: Build-Debug
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "master"
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- "master"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-dotnet:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
|
||||||
- run: dotnet build -c Debug
|
|
||||||
- run: dotnet test -c Debug
|
|
||||||
|
|
||||||
build-unity:
|
|
||||||
if: "((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:'))"
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
unity: ["2019.3.9f1", "2019.4.13f1", "2020.1.12f1"]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 15
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
# 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: Cysharp/Actions/.github/actions/unity-builder@main
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
with:
|
|
||||||
projectPath: src/UniTask
|
|
||||||
unityVersion: ${{ matrix.unity }}
|
|
||||||
targetPlatform: StandaloneLinux64
|
|
||||||
buildMethod: UnitTestBuilder.BuildUnitTest
|
|
||||||
customParameters: /headless /ScriptBackend mono
|
|
||||||
- name: Execute UnitTest
|
|
||||||
run: ./src/UniTask/bin/UnitTest/StandaloneLinux64_Mono2x/test
|
|
||||||
|
|
||||||
# Execute scripts: Export Package
|
|
||||||
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
|
||||||
- name: Build Unity (.unitypacakge)
|
|
||||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
with:
|
|
||||||
projectPath: src/UniTask
|
|
||||||
unityVersion: ${{ matrix.unity }}
|
|
||||||
targetPlatform: StandaloneLinux64
|
|
||||||
buildMethod: PackageExporter.Export
|
|
||||||
|
|
||||||
- uses: Cysharp/Actions/.github/actions/check-metas@main # check meta files
|
|
||||||
with:
|
|
||||||
directory: src/UniTask
|
|
||||||
|
|
||||||
# Store artifacts.
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: UniTask.unitypackage-${{ matrix.unity }}.zip
|
|
||||||
path: ./src/UniTask/*.unitypackage
|
|
||||||
58
.github/workflows/build-docs.yaml
vendored
Normal file
58
.github/workflows/build-docs.yaml
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
name: build-docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- feature/docs
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-docfx:
|
||||||
|
if: ${{ ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')) && github.triggering_actor != 'dependabot[bot]' }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pages: write
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- name: Load secrets
|
||||||
|
id: op-load-secret
|
||||||
|
uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 # v2.0.0
|
||||||
|
with:
|
||||||
|
export-env: false
|
||||||
|
env:
|
||||||
|
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
|
||||||
|
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
|
||||||
|
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
|
||||||
|
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
|
||||||
|
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||||
|
# Execute scripts: Export Package
|
||||||
|
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||||
|
- name: Build Unity (.unitypackage)
|
||||||
|
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: "2022.3.39f1"
|
||||||
|
targetPlatform: StandaloneLinux64
|
||||||
|
buildMethod: PackageExporter.Export
|
||||||
|
|
||||||
|
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||||
|
with:
|
||||||
|
repository: Cysharp/DocfxTemplate
|
||||||
|
path: docs/_DocfxTemplate
|
||||||
|
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||||
|
- name: dotnet tool restore
|
||||||
|
run: dotnet tool restore
|
||||||
|
- name: Docfx metadata
|
||||||
|
run: dotnet docfx metadata docs/docfx.json
|
||||||
|
- name: Docfx build
|
||||||
|
run: dotnet docfx build docs/docfx.json
|
||||||
|
- name: Publish to GitHub Pages
|
||||||
|
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: docs/_site
|
||||||
31
.github/workflows/build-docs.yml
vendored
31
.github/workflows/build-docs.yml
vendored
@@ -1,31 +0,0 @@
|
|||||||
name: build-docs
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- feature/docs
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-docfx:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 10
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
repository: Cysharp/DocfxTemplate
|
|
||||||
path: docs/_DocfxTemplate
|
|
||||||
- uses: Kirbyrawr/docfx-action@master
|
|
||||||
name: Docfx metadata
|
|
||||||
with:
|
|
||||||
args: metadata docs/docfx.json
|
|
||||||
- uses: Kirbyrawr/docfx-action@master
|
|
||||||
name: Docfx build
|
|
||||||
with:
|
|
||||||
args: build docs/docfx.json
|
|
||||||
- name: Publish to GitHub Pages
|
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
publish_dir: docs/_site
|
|
||||||
@@ -12,48 +12,63 @@ on:
|
|||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
env:
|
|
||||||
GIT_TAG: ${{ github.event.inputs.tag }}
|
|
||||||
DRY_RUN: ${{ github.event.inputs.dry-run }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-packagejson:
|
update-packagejson:
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: write
|
||||||
uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
|
uses: Cysharp/Actions/.github/workflows/update-packagejson.yaml@main
|
||||||
with:
|
with:
|
||||||
file-path: ./src/UniTask/Assets/Plugins/UniTask/package.json
|
file-path: ./src/UniTask/Assets/Plugins/UniTask/package.json
|
||||||
tag: ${{ github.event.inputs.tag }}
|
tag: ${{ inputs.tag }}
|
||||||
dry-run: ${{ fromJson(github.event.inputs.dry-run) }}
|
dry-run: ${{ inputs.dry-run }}
|
||||||
|
|
||||||
build-dotnet:
|
build-dotnet:
|
||||||
needs: [update-packagejson]
|
needs: [update-packagejson]
|
||||||
runs-on: ubuntu-latest
|
permissions:
|
||||||
|
contents: read
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||||
- uses: actions/checkout@v3
|
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||||
with:
|
with:
|
||||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
||||||
# build and pack
|
# 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 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.
|
# Store artifacts.
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
|
||||||
with:
|
with:
|
||||||
name: nuget
|
name: nuget
|
||||||
path: ./publish/
|
path: ./publish/
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
build-unity:
|
build-unity:
|
||||||
needs: [update-packagejson]
|
needs: [update-packagejson]
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
unity: ["2019.3.9f1"]
|
unity: ["2022.3.39f1"]
|
||||||
runs-on: ubuntu-latest
|
permissions:
|
||||||
|
contents: read
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
|
- name: Load secrets
|
||||||
|
id: op-load-secret
|
||||||
|
uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 # v2.0.0
|
||||||
|
with:
|
||||||
|
export-env: false
|
||||||
|
env:
|
||||||
|
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
|
||||||
|
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
|
||||||
|
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
|
||||||
|
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
|
||||||
|
|
||||||
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
- run: echo ${{ needs.update-packagejson.outputs.sha }}
|
||||||
- uses: actions/checkout@v3
|
- uses: Cysharp/Actions/.github/actions/checkout@main
|
||||||
with:
|
with:
|
||||||
ref: ${{ needs.update-packagejson.outputs.sha }}
|
ref: ${{ needs.update-packagejson.outputs.sha }}
|
||||||
# Execute scripts: Export Package
|
# Execute scripts: Export Package
|
||||||
@@ -61,9 +76,9 @@ jobs:
|
|||||||
- name: Build Unity (.unitypacakge)
|
- name: Build Unity (.unitypacakge)
|
||||||
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
uses: Cysharp/Actions/.github/actions/unity-builder@main
|
||||||
env:
|
env:
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
|
||||||
with:
|
with:
|
||||||
projectPath: src/UniTask
|
projectPath: src/UniTask
|
||||||
unityVersion: ${{ matrix.unity }}
|
unityVersion: ${{ matrix.unity }}
|
||||||
@@ -75,46 +90,33 @@ jobs:
|
|||||||
directory: src/UniTask
|
directory: src/UniTask
|
||||||
|
|
||||||
# Store artifacts.
|
# Store artifacts.
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: Cysharp/Actions/.github/actions/upload-artifact@main
|
||||||
with:
|
with:
|
||||||
name: UniTask.${{ env.GIT_TAG }}.unitypackage
|
name: UniTask.${{ inputs.tag }}.unitypackage
|
||||||
path: ./src/UniTask/UniTask.${{ env.GIT_TAG }}.unitypackage
|
path: ./src/UniTask/UniTask.${{ inputs.tag }}.unitypackage
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
# release
|
||||||
create-release:
|
create-release:
|
||||||
if: github.event.inputs.dry-run == 'false'
|
|
||||||
needs: [update-packagejson, build-dotnet, build-unity]
|
needs: [update-packagejson, build-dotnet, build-unity]
|
||||||
runs-on: ubuntu-latest
|
permissions:
|
||||||
timeout-minutes: 10
|
contents: write
|
||||||
steps:
|
id-token: write # required for NuGet Trusted Publish
|
||||||
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
|
uses: Cysharp/Actions/.github/workflows/create-release.yaml@main
|
||||||
# Create Releases
|
|
||||||
- uses: actions/create-release@v1
|
|
||||||
id: create_release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ env.GIT_TAG }}
|
commit-id: ${{ needs.update-packagejson.outputs.sha }}
|
||||||
release_name: Ver.${{ env.GIT_TAG }}
|
dry-run: ${{ inputs.dry-run }}
|
||||||
commitish: ${{ needs.update-packagejson.outputs.sha }}
|
tag: ${{ inputs.tag }}
|
||||||
draft: true
|
nuget-push: true
|
||||||
prerelease: false
|
release-upload: true
|
||||||
# Download(All) Artifacts to current directory
|
release-asset-path: ./UniTask.${{ inputs.tag }}.unitypackage/UniTask.${{ inputs.tag }}.unitypackage
|
||||||
- uses: actions/download-artifact@v2
|
secrets: inherit
|
||||||
# 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
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if: needs.update-packagejson.outputs.is-branch-created == 'true'
|
if: ${{ needs.update-packagejson.outputs.is-branch-created == 'true' }}
|
||||||
needs: [update-packagejson, build-dotnet, build-unity]
|
needs: [update-packagejson, build-dotnet, build-unity]
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
|
uses: Cysharp/Actions/.github/workflows/clean-packagejson-branch.yaml@main
|
||||||
with:
|
with:
|
||||||
branch: ${{ needs.update-packagejson.outputs.branch-name }}
|
branch: ${{ needs.update-packagejson.outputs.branch-name }}
|
||||||
@@ -7,4 +7,6 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
detect:
|
detect:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
uses: Cysharp/Actions/.github/workflows/prevent-github-change.yaml@main
|
uses: Cysharp/Actions/.github/workflows/prevent-github-change.yaml@main
|
||||||
@@ -7,4 +7,8 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main
|
uses: Cysharp/Actions/.github/workflows/stale-issue.yaml@main
|
||||||
15
.github/workflows/toc.yaml
vendored
Normal file
15
.github/workflows/toc.yaml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: TOC Generator
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'README.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
toc:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
uses: Cysharp/Actions/.github/workflows/toc-generator.yaml@main
|
||||||
|
with:
|
||||||
|
TOC_TITLE: "## Table of Contents"
|
||||||
|
secrets: inherit
|
||||||
15
.github/workflows/toc.yml
vendored
15
.github/workflows/toc.yml
vendored
@@ -1,15 +0,0 @@
|
|||||||
name: TOC Generator
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'README.md'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
generateTOC:
|
|
||||||
name: TOC Generator
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: technote-space/toc-generator@v2.4.0
|
|
||||||
with:
|
|
||||||
TOC_TITLE: "## Table of Contents"
|
|
||||||
157
.gitignore
vendored
157
.gitignore
vendored
@@ -100,7 +100,19 @@ publish
|
|||||||
*.Publish.xml
|
*.Publish.xml
|
||||||
|
|
||||||
# NuGet Packages Directory
|
# NuGet Packages Directory
|
||||||
packages
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
# packages # upm pacakge will use Packages
|
||||||
|
# **/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
# !**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
# Windows Azure Build Output
|
# Windows Azure Build Output
|
||||||
csx
|
csx
|
||||||
@@ -130,134 +142,15 @@ UpgradeLog*.XML
|
|||||||
Assets/WSATestCertificate.pfx
|
Assets/WSATestCertificate.pfx
|
||||||
.vs/
|
.vs/
|
||||||
|
|
||||||
Assembly-CSharp\.csproj
|
# Unity
|
||||||
|
|
||||||
UniRx\.Async\.csproj
|
# Unity
|
||||||
|
.vsconfig
|
||||||
UniRx\.Async\.Editor\.csproj
|
src/UniTask/Library/*
|
||||||
|
src/UniTask/Temp/*
|
||||||
UniRx\.Async\.Tests\.csproj
|
src/UniTask/Logs/*
|
||||||
|
src/UniTask/[Uu]ser[Ss]ettings/
|
||||||
UniTask\.sln
|
src/UniTask/*.sln
|
||||||
|
src/UniTask/*.csproj
|
||||||
RuntimeUnitTestToolkit\.csproj
|
src/UniTask/*.unitypackage
|
||||||
|
!src/UniTask/Packages/
|
||||||
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
|
|
||||||
|
|||||||
27
Directory.Build.props
Normal file
27
Directory.Build.props
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)opensource.snk</AssemblyOriginatorKeyFile>
|
||||||
|
|
||||||
|
<!-- NuGet Package Information -->
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<PackageVersion>$(Version)</PackageVersion>
|
||||||
|
<Company>Cysharp</Company>
|
||||||
|
<Authors>Cysharp</Authors>
|
||||||
|
<Copyright>© Cysharp, Inc.</Copyright>
|
||||||
|
<PackageTags>task;async</PackageTags>
|
||||||
|
<PackageProjectUrl>https://github.com/Cysharp/UniTask</PackageProjectUrl>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<RepositoryUrl>$(PackageProjectUrl)</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
<PackageIcon>Icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="$(MSBuildThisFileDirectory)Icon.png" Pack="true" PackagePath="\" />
|
||||||
|
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
|
||||||
|
<EmbeddedResource Include="$(MSBuildThisFileDirectory)LICENSE" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
31
README.md
31
README.md
@@ -33,6 +33,7 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
|
|||||||
- [AsyncEnumerable and Async LINQ](#asyncenumerable-and-async-linq)
|
- [AsyncEnumerable and Async LINQ](#asyncenumerable-and-async-linq)
|
||||||
- [Awaitable Events](#awaitable-events)
|
- [Awaitable Events](#awaitable-events)
|
||||||
- [Channel](#channel)
|
- [Channel](#channel)
|
||||||
|
- [vs Awaitable](#vs-awaitable)
|
||||||
- [For Unit Testing](#for-unit-testing)
|
- [For Unit Testing](#for-unit-testing)
|
||||||
- [ThreadPool limitation](#threadpool-limitation)
|
- [ThreadPool limitation](#threadpool-limitation)
|
||||||
- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)
|
- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)
|
||||||
@@ -67,6 +68,7 @@ async UniTask<string> DemoAsync()
|
|||||||
await SceneManager.LoadSceneAsync("scene2");
|
await SceneManager.LoadSceneAsync("scene2");
|
||||||
|
|
||||||
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
|
// .WithCancellation enables Cancel, GetCancellationTokenOnDestroy synchornizes with lifetime of GameObject
|
||||||
|
// after Unity 2022.2, you can use `destroyCancellationToken` in MonoBehaviour
|
||||||
var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
|
var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
|
||||||
|
|
||||||
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
|
// .ToUniTask accepts progress callback(and all options), Progress.Create is a lightweight alternative of IProgress<T>
|
||||||
@@ -160,7 +162,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.
|
> 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
|
```csharp
|
||||||
public async UniTaskVoid LoadManyAsync()
|
public async UniTaskVoid LoadManyAsync()
|
||||||
@@ -293,6 +295,8 @@ public class MyBehaviour : MonoBehaviour
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
After Unity 2022.2, Unity adds CancellationToken in [MonoBehaviour.destroyCancellationToken](https://docs.unity3d.com/ScriptReference/MonoBehaviour-destroyCancellationToken.html) and [Application.exitCancellationToken](https://docs.unity3d.com/ScriptReference/Application-exitCancellationToken.html).
|
||||||
|
|
||||||
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.`
|
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`.
|
And also `OperationCanceledException` is a special exception, this is silently ignored at `UnobservedTaskException`.
|
||||||
@@ -526,6 +530,9 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.
|
|||||||
|
|
||||||
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`.
|
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.
|
In the stacktrace, you can check where it is running in playerloop.
|
||||||
|
|
||||||

|

|
||||||
@@ -716,6 +723,19 @@ await UniTaskAsyncEnumerable.EveryUpdate().ForEachAsync(_ =>
|
|||||||
}, token);
|
}, 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.
|
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.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
@@ -937,6 +957,14 @@ public class AsyncMessageBroker<T> : IDisposable
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
vs Awaitable
|
||||||
|
---
|
||||||
|
Unity 6 introduces the awaitable type, [Awaitable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Awaitable.html). To put it simply, Awaitable can be considered a subset of UniTask, and in fact, Awaitable's design was influenced by UniTask. It should be able to handle PlayerLoop-based awaits, pooled Tasks, and support for cancellation with `CancellationToken` in a similar way. With its inclusion in the standard library, you may wonder whether to continue using UniTask or migrate to Awaitable. Here's a brief guide.
|
||||||
|
|
||||||
|
First, the functionality provided by Awaitable is equivalent to what coroutines offer. Instead of `yield return`, you use await; `await NextFrameAsync()` replaces `yield return null`; and there are equivalents for `WaitForSeconds` and `EndOfFrame`. However, that's the extent of it. Being coroutine-based in terms of functionality, it lacks Task-based features. In practical application development using async/await, operations like `WhenAll` are essential. Additionally, UniTask enables many frame-based operations (such as `DelayFrame`) and more flexible PlayerLoopTiming control, which are not available in Awaitable. Of course, there's no Tracker Window either.
|
||||||
|
|
||||||
|
Therefore, I recommend using UniTask for application development. UniTask is a superset of Awaitable and includes many essential features. For library development, where you want to avoid external dependencies, using Awaitable as a return type for methods would be appropriate. Awaitable can be converted to UniTask using `AsUniTask`, so there's no issue in handling Awaitable-based functionality within the UniTask library. Of course, if you don't need to worry about dependencies, using UniTask would be the best choice even for library development.
|
||||||
|
|
||||||
For Unit Testing
|
For Unit Testing
|
||||||
---
|
---
|
||||||
Unity's `[UnityTest]` attribute can test coroutine(IEnumerator) but can not test async. `UniTask.ToCoroutine` bridges async/await to coroutine so you can test async methods.
|
Unity's `[UnityTest]` attribute can test coroutine(IEnumerator) but can not test async. `UniTask.ToCoroutine` bridges async/await to coroutine so you can test async methods.
|
||||||
@@ -1026,6 +1054,7 @@ Use UniTask type.
|
|||||||
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
||||||
| `Task.WhenAll` | `UniTask.WhenAll` |
|
| `Task.WhenAll` | `UniTask.WhenAll` |
|
||||||
| `Task.WhenAny` | `UniTask.WhenAny` |
|
| `Task.WhenAny` | `UniTask.WhenAny` |
|
||||||
|
| `Task.WhenEach` | `UniTask.WhenEach` |
|
||||||
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
||||||
| `Task.FromException` | `UniTask.FromException` |
|
| `Task.FromException` | `UniTask.FromException` |
|
||||||
| `Task.FromResult` | `UniTask.FromResult` |
|
| `Task.FromResult` | `UniTask.FromResult` |
|
||||||
|
|||||||
420
README_CN.md
420
README_CN.md
@@ -2,27 +2,27 @@ UniTask
|
|||||||
===
|
===
|
||||||
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases)
|
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases)
|
||||||
|
|
||||||
为Unity提供一个高性能,0GC的async/await异步方案。
|
为Unity提供一个高性能,零堆内存分配的 async/await 异步方案。
|
||||||
|
|
||||||
- 基于值类型的`UniTask<T>`和自定义的 AsyncMethodBuilder 来实现0GC
|
- 基于值类型的`UniTask<T>`和自定义的 AsyncMethodBuilder 来实现零堆内存分配
|
||||||
- 使所有 Unity 的 AsyncOperations 和 Coroutines 可等待
|
- 使所有 Unity 的 AsyncOperations 和 Coroutines 可等待
|
||||||
- 基于 PlayerLoop 的任务( `UniTask.Yield`, `UniTask.Delay`, `UniTask.DelayFrame`, etc..) 可以替换所有协程操作
|
- 基于 PlayerLoop 的任务(`UniTask.Yield`,`UniTask.Delay`,`UniTask.DelayFrame`等..)可以替换所有协程操作
|
||||||
- 对MonoBehaviour 消息事件和 uGUI 事件进行 可等待/异步枚举 拓展
|
- 对 MonoBehaviour 消息事件和 uGUI 事件进行可等待/异步枚举扩展
|
||||||
- 完全在 Unity 的 PlayerLoop 上运行,因此不使用Thread,并且同样能在 WebGL、wasm 等平台上运行。
|
- 完全在 Unity 的 PlayerLoop 上运行,因此不使用Thread,并且同样能在 WebGL、wasm 等平台上运行。
|
||||||
- 带有 Channel 和 AsyncReactiveProperty的异步 LINQ,
|
- 带有 Channel 和 AsyncReactiveProperty 的异步 LINQ
|
||||||
- 提供一个 TaskTracker EditorWindow 以追踪所有 UniTask 分配来预防内存泄漏
|
- 提供一个 TaskTracker EditorWindow 以追踪所有 UniTask 分配来预防内存泄漏
|
||||||
- 与原生 Task/ValueTask/IValueTaskSource 高度兼容的行为
|
- 与原生 Task/ValueTask/IValueTaskSource 高度兼容的行为
|
||||||
|
|
||||||
有关技术细节,请参阅博客文章:[UniTask v2 — Unity 的0GC async/await 以及 异步LINQ 的使用](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
|
有关技术细节,请参阅博客文章:[UniTask v2 — 适用于 Unity 的零堆内存分配的async/await,支持异步 LINQ](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
|
||||||
有关高级技巧,请参阅博客文章:[通过异步装饰器模式扩展 UnityWebRequest — UniTask 的高级技术](https://medium.com/@neuecc/extends-unitywebrequest-via-async-decorator-pattern-advanced-techniques-of-unitask-ceff9c5ee846)
|
有关高级技巧,请参阅博客文章:[通过异步装饰器模式扩展 UnityWebRequest — UniTask 的高级技术](https://medium.com/@neuecc/extends-unitywebrequest-via-async-decorator-pattern-advanced-techniques-of-unitask-ceff9c5ee846)
|
||||||
|
|
||||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
## Table of Contents
|
## 目录
|
||||||
|
|
||||||
- [入门](#%E5%85%A5%E9%97%A8)
|
- [入门](#%E5%85%A5%E9%97%A8)
|
||||||
- [UniTask 和 AsyncOperation 基础知识](#unitask-%E5%92%8C-asyncoperation-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86)
|
- [UniTask 和 AsyncOperation 的基础知识](#unitask-%E5%92%8C-asyncoperation-%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86)
|
||||||
- [Cancellation and Exception handling](#cancellation-and-exception-handling)
|
- [取消和异常处理](#%E5%8F%96%E6%B6%88%E5%92%8C%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86)
|
||||||
- [超时处理](#%E8%B6%85%E6%97%B6%E5%A4%84%E7%90%86)
|
- [超时处理](#%E8%B6%85%E6%97%B6%E5%A4%84%E7%90%86)
|
||||||
- [进度](#%E8%BF%9B%E5%BA%A6)
|
- [进度](#%E8%BF%9B%E5%BA%A6)
|
||||||
- [PlayerLoop](#playerloop)
|
- [PlayerLoop](#playerloop)
|
||||||
@@ -32,41 +32,42 @@ UniTask
|
|||||||
- [AsyncEnumerable 和 Async LINQ](#asyncenumerable-%E5%92%8C-async-linq)
|
- [AsyncEnumerable 和 Async LINQ](#asyncenumerable-%E5%92%8C-async-linq)
|
||||||
- [可等待事件](#%E5%8F%AF%E7%AD%89%E5%BE%85%E4%BA%8B%E4%BB%B6)
|
- [可等待事件](#%E5%8F%AF%E7%AD%89%E5%BE%85%E4%BA%8B%E4%BB%B6)
|
||||||
- [Channel](#channel)
|
- [Channel](#channel)
|
||||||
|
- [与 Awaitable 对比](#%E4%B8%8E-awaitable-%E5%AF%B9%E6%AF%94)
|
||||||
- [单元测试](#%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95)
|
- [单元测试](#%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95)
|
||||||
- [线程池限制](#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E9%99%90%E5%88%B6)
|
- [线程池的限制](#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E9%99%90%E5%88%B6)
|
||||||
- [IEnumerator.ToUniTask 限制](#ienumeratortounitask-%E9%99%90%E5%88%B6)
|
- [IEnumerator.ToUniTask 的限制](#ienumeratortounitask-%E7%9A%84%E9%99%90%E5%88%B6)
|
||||||
- [关于UnityEditor](#%E5%85%B3%E4%BA%8Eunityeditor)
|
- [关于 UnityEditor](#%E5%85%B3%E4%BA%8E-unityeditor)
|
||||||
- [与原生Task API对比](#%E4%B8%8E%E5%8E%9F%E7%94%9Ftask-api%E5%AF%B9%E6%AF%94)
|
- [与原生 Task API 对比](#%E4%B8%8E%E5%8E%9F%E7%94%9F-task-api-%E5%AF%B9%E6%AF%94)
|
||||||
- [池化配置](#%E6%B1%A0%E5%8C%96%E9%85%8D%E7%BD%AE)
|
- [池化配置](#%E6%B1%A0%E5%8C%96%E9%85%8D%E7%BD%AE)
|
||||||
- [Profiler下的分配](#profiler%E4%B8%8B%E7%9A%84%E5%88%86%E9%85%8D)
|
- [Profiler 下的堆内存分配](#profiler-%E4%B8%8B%E7%9A%84%E5%A0%86%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D)
|
||||||
- [UniTaskSynchronizationContext](#unitasksynchronizationcontext)
|
- [UniTaskSynchronizationContext](#unitasksynchronizationcontext)
|
||||||
- [API References](#api-references)
|
- [API 文档](#api-%E6%96%87%E6%A1%A3)
|
||||||
- [UPM Package](#upm-package)
|
- [UPM 包](#upm-%E5%8C%85)
|
||||||
- [通过 git URL 安装](#%E9%80%9A%E8%BF%87-git-url-%E5%AE%89%E8%A3%85)
|
- [通过 git URL 安装](#%E9%80%9A%E8%BF%87-git-url-%E5%AE%89%E8%A3%85)
|
||||||
- [通过 OpenUPM 安装](#%E9%80%9A%E8%BF%87-openupm-%E5%AE%89%E8%A3%85)
|
- [关于 .NET Core](#%E5%85%B3%E4%BA%8E-net-core)
|
||||||
- [.NET Core](#net-core)
|
- [许可证](#%E8%AE%B8%E5%8F%AF%E8%AF%81)
|
||||||
- [License](#license)
|
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
入门
|
入门
|
||||||
---
|
---
|
||||||
通过[UniTask/releases](https://github.com/Cysharp/UniTask/releases)页面中提供的[UPM 包](https://github.com/Cysharp/UniTask#upm-package)或资产包 ( `UniTask.*.*.*.unitypackage`)安装。
|
通过[UniTask/releases](https://github.com/Cysharp/UniTask/releases)页面中提供的[UPM 包](https://github.com/Cysharp/UniTask#upm-package)或资产包(`UniTask.*.*.*.unitypackage`)安装。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 使用 UniTask 所需的命名空间
|
// 使用 UniTask 所需的命名空间
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
|
|
||||||
// 你可以返回一个形如 UniTask<T>(或 UniTask) 的类型,这种类型事为Unity定制的,作为替代原生Task<T>的轻量级方案
|
// 您可以返回一个形如 UniTask<T>(或 UniTask) 的类型,这种类型事为Unity定制的,作为替代原生 Task<T> 的轻量级方案
|
||||||
// 为Unity集成的 0GC,快速调用,0消耗的 async/await 方案
|
// 为 Unity 集成的零堆内存分配,快速调用,0消耗的 async/await 方案
|
||||||
async UniTask<string> DemoAsync()
|
async UniTask<string> DemoAsync()
|
||||||
{
|
{
|
||||||
// 你可以等待一个Unity异步对象
|
// 您可以等待一个 Unity 异步对象
|
||||||
var asset = await Resources.LoadAsync<TextAsset>("foo");
|
var asset = await Resources.LoadAsync<TextAsset>("foo");
|
||||||
var txt = (await UnityWebRequest.Get("https://...").SendWebRequest()).downloadHandler.text;
|
var txt = (await UnityWebRequest.Get("https://...").SendWebRequest()).downloadHandler.text;
|
||||||
await SceneManager.LoadSceneAsync("scene2");
|
await SceneManager.LoadSceneAsync("scene2");
|
||||||
|
|
||||||
// .WithCancellation 会启用取消功能,GetCancellationTokenOnDestroy 表示获取一个依赖对象生命周期的 Cancel 句柄,当对象被销毁时,将会调用这个 Cancel 句柄,从而实现取消的功能
|
// .WithCancellation 会启用取消功能,GetCancellationTokenOnDestroy 表示获取一个依赖对象生命周期的 Cancel 句柄,当对象被销毁时,将会调用这个 Cancel 句柄,从而实现取消的功能
|
||||||
|
// 在 Unity 2022.2之后,您可以在 MonoBehaviour 中使用`destroyCancellationToken`
|
||||||
var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
|
var asset2 = await Resources.LoadAsync<TextAsset>("bar").WithCancellation(this.GetCancellationTokenOnDestroy());
|
||||||
|
|
||||||
// .ToUniTask 可接收一个 progress 回调以及一些配置参数,Progress.Create 是 IProgress<T> 的轻量级替代方案
|
// .ToUniTask 可接收一个 progress 回调以及一些配置参数,Progress.Create 是 IProgress<T> 的轻量级替代方案
|
||||||
@@ -78,29 +79,34 @@ async UniTask<string> DemoAsync()
|
|||||||
// yield return new WaitForSeconds/WaitForSecondsRealtime 的替代方案
|
// yield return new WaitForSeconds/WaitForSecondsRealtime 的替代方案
|
||||||
await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);
|
await UniTask.Delay(TimeSpan.FromSeconds(10), ignoreTimeScale: false);
|
||||||
|
|
||||||
// 可以等待任何 playerloop 的生命周期(PreUpdate, Update, LateUpdate, 等...)
|
// 可以等待任何 playerloop 的生命周期(PreUpdate,Update,LateUpdate等)
|
||||||
await UniTask.Yield(PlayerLoopTiming.PreLateUpdate);
|
await UniTask.Yield(PlayerLoopTiming.PreLateUpdate);
|
||||||
|
|
||||||
// yield return null 替代方案
|
// yield return null 的替代方案
|
||||||
await UniTask.Yield();
|
await UniTask.Yield();
|
||||||
await UniTask.NextFrame();
|
await UniTask.NextFrame();
|
||||||
|
|
||||||
// WaitForEndOfFrame 替代方案 (需要 MonoBehaviour(CoroutineRunner))
|
// WaitForEndOfFrame 的替代方案
|
||||||
|
#if UNITY_2023_1_OR_NEWER
|
||||||
|
await UniTask.WaitForEndOfFrame();
|
||||||
|
#else
|
||||||
|
// 需要 MonoBehaviour(CoroutineRunner)
|
||||||
await UniTask.WaitForEndOfFrame(this); // this是一个 MonoBehaviour
|
await UniTask.WaitForEndOfFrame(this); // this是一个 MonoBehaviour
|
||||||
|
#endif
|
||||||
|
|
||||||
// yield return new WaitForFixedUpdate 替代方案,(和 UniTask.Yield(PlayerLoopTiming.FixedUpdate) 效果一样)
|
// yield return new WaitForFixedUpdate 的替代方案,(等同于 UniTask.Yield(PlayerLoopTiming.FixedUpdate))
|
||||||
await UniTask.WaitForFixedUpdate();
|
await UniTask.WaitForFixedUpdate();
|
||||||
|
|
||||||
// yield return WaitUntil 替代方案
|
// yield return WaitUntil 的替代方案
|
||||||
await UniTask.WaitUntil(() => isActive == false);
|
await UniTask.WaitUntil(() => isActive == false);
|
||||||
|
|
||||||
// WaitUntil拓展,指定某个值改变时触发
|
// WaitUntil 扩展,指定某个值改变时触发
|
||||||
await UniTask.WaitUntilValueChanged(this, x => x.isActive);
|
await UniTask.WaitUntilValueChanged(this, x => x.isActive);
|
||||||
|
|
||||||
// 你可以直接 await 一个 IEnumerator 协程
|
// 您可以直接 await 一个 IEnumerator 协程
|
||||||
await FooCoroutineEnumerator();
|
await FooCoroutineEnumerator();
|
||||||
|
|
||||||
// 你可以直接 await 一个原生 task
|
// 您可以直接 await 一个原生 task
|
||||||
await Task.Run(() => 100);
|
await Task.Run(() => 100);
|
||||||
|
|
||||||
// 多线程示例,在此行代码后的内容都运行在一个线程池上
|
// 多线程示例,在此行代码后的内容都运行在一个线程池上
|
||||||
@@ -108,7 +114,7 @@ async UniTask<string> DemoAsync()
|
|||||||
|
|
||||||
/* 工作在线程池上的代码 */
|
/* 工作在线程池上的代码 */
|
||||||
|
|
||||||
// 转回主线程
|
// 转回主线程(等同于 UniRx 的`ObserveOnMainThread`)
|
||||||
await UniTask.SwitchToMainThread();
|
await UniTask.SwitchToMainThread();
|
||||||
|
|
||||||
// 获取异步的 webrequest
|
// 获取异步的 webrequest
|
||||||
@@ -125,37 +131,37 @@ async UniTask<string> DemoAsync()
|
|||||||
// 构造一个 async-wait,并通过元组语义轻松获取所有结果
|
// 构造一个 async-wait,并通过元组语义轻松获取所有结果
|
||||||
var (google, bing, yahoo) = await UniTask.WhenAll(task1, task2, task3);
|
var (google, bing, yahoo) = await UniTask.WhenAll(task1, task2, task3);
|
||||||
|
|
||||||
// WhenAll简写形式
|
// WhenAll 的简写形式,元组可以直接 await
|
||||||
var (google2, bing2, yahoo2) = await (task1, task2, task3);
|
var (google2, bing2, yahoo2) = await (task1, task2, task3);
|
||||||
|
|
||||||
// 返回一个异步值,或者你也可以使用`UniTask`(无结果), `UniTaskVoid`(协程,不可等待)
|
// 返回一个异步值,或者您也可以使用`UniTask`(无结果),`UniTaskVoid`(不可等待)
|
||||||
return (asset as TextAsset)?.text ?? throw new InvalidOperationException("Asset not found");
|
return (asset as TextAsset)?.text ?? throw new InvalidOperationException("Asset not found");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
UniTask 和 AsyncOperation 基础知识
|
UniTask 和 AsyncOperation 的基础知识
|
||||||
---
|
---
|
||||||
UniTask 功能依赖于 C# 7.0( [task-like custom async method builder feature](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md) ) 所以需要的 Unity 最低版本是`Unity 2018.3` ,官方支持的最低版本是`Unity 2018.4.13f1`.
|
UniTask 功能依赖于 C# 7.0([task-like custom async method builder feature](https://github.com/dotnet/roslyn/blob/master/docs/features/task-types.md)),所以需要`Unity 2018.3`之后的版本,官方支持的最低版本是`Unity 2018.4.13f1`。
|
||||||
|
|
||||||
为什么需要 UniTask(自定义task对象)?因为原生 Task 太重,与 Unity 线程(单线程)相性不好。UniTask 不使用线程和 SynchronizationContext/ExecutionContext,因为 Unity 的异步对象由 Unity 的引擎层自动调度。它实现了更快和更低的分配,并且与Unity完全兼容。
|
为什么需要 UniTask(自定义task对象)?因为原生 Task 太重,与 Unity 线程(单线程)相性不好。因为 Unity 的异步对象由 Unity 的引擎层自动调度,所以 UniTask 不使用线程和 SynchronizationContext/ExecutionContext。它实现了更快和更低的分配,并且与Unity完全兼容。
|
||||||
|
|
||||||
你可以在使用 `using Cysharp.Threading.Tasks;`时对 `AsyncOperation`, `ResourceRequest`,`AssetBundleRequest`, `AssetBundleCreateRequest`, `UnityWebRequestAsyncOperation`, `AsyncGPUReadbackRequest`, `IEnumerator`以及其他的异步操作进行 await
|
您可以在使用`using Cysharp.Threading.Tasks;`时对`AsyncOperation`,`ResourceRequest`,`AssetBundleRequest`,`AssetBundleCreateRequest`,`UnityWebRequestAsyncOperation`,`AsyncGPUReadbackRequest`,`IEnumerator`以及其他的异步操作进行 await
|
||||||
|
|
||||||
UniTask 提供了三种模式的扩展方法。
|
UniTask 提供了三种模式的扩展方法。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
* await asyncOperation;
|
await asyncOperation;
|
||||||
* .WithCancellation(CancellationToken);
|
.WithCancellation(CancellationToken);
|
||||||
* .ToUniTask(IProgress, PlayerLoopTiming, CancellationToken);
|
.ToUniTask(IProgress, PlayerLoopTiming, CancellationToken);
|
||||||
```
|
```
|
||||||
|
|
||||||
`WithCancellation`是`ToUniTask`的简化版本,两者都返回`UniTask`。有关 cancellation 的详细信息,请参阅:[取消和异常处理](https://github.com/Cysharp/UniTask#cancellation-and-exception-handling)部分。
|
`WithCancellation`是`ToUniTask`的简化版本,两者都返回`UniTask`。有关 cancellation 的详细信息,请参阅:[取消和异常处理](https://github.com/Cysharp/UniTask#cancellation-and-exception-handling)部分。
|
||||||
|
|
||||||
> 注意:await 会在 PlayerLoop 执行await对象的相应native生命周期方法时返回(如果条件满足的话),而 WithCancellation 和 ToUniTask 是从指定的 PlayerLoop 生命周期执行时返回。有关 PlayLoop生命周期 的详细信息,请参阅:[PlayerLoop](https://github.com/Cysharp/UniTask#playerloop)部分。
|
> 注意:await 会在 PlayerLoop 执行await对象的相应native生命周期方法时返回(如果条件满足的话),而 WithCancellation 和 ToUniTask 是从指定的 PlayerLoop 生命周期执行时返回。有关 PlayLoop生命周期 的详细信息,请参阅:[PlayerLoop](https://github.com/Cysharp/UniTask#playerloop)部分。
|
||||||
|
|
||||||
> 注意: AssetBundleRequest 有`asset`和`allAssets`,默认 await 返回`asset`。如果你想得到`allAssets`,你可以使用`AwaitForAllAssets()`方法。
|
> 注意: AssetBundleRequest 有`asset`和`allAssets`,默认 await 返回`asset`。如果您想得到`allAssets`,您可以使用`AwaitForAllAssets()`方法。
|
||||||
|
|
||||||
`UniTask`可以使用`UniTask.WhenAll`和`UniTask.WhenAny`等实用函数。它们就像`Task.WhenAll`/`Task.WhenAny`。但它们会返回内容,这很有用。它们会返回值元组,因此您可以传递多种类型并解构每个结果。
|
`UniTask`可以使用`UniTask.WhenAll`,`UniTask.WhenAny`,`UniTask.WhenEach`等实用函数。它们就像`Task.WhenAll`和`Task.WhenAny`,但它们返回的数据类型更好用。它们会返回值元组,因此您可以传递多种类型并解构每个结果。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public async UniTaskVoid LoadManyAsync()
|
public async UniTaskVoid LoadManyAsync()
|
||||||
@@ -174,7 +180,7 @@ async UniTask<Sprite> LoadAsSprite(string path)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果你想转换一个回调逻辑块,让它变成UniTask的话,可以使用 `UniTaskCompletionSource<T>` (`TaskCompletionSource<T>`的轻量级魔改版)
|
如果您想要将一个回调转换为 UniTask,您可以使用`UniTaskCompletionSource<T>`,它是`TaskCompletionSource<T>`的轻量级版本。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public UniTask<int> WrapByUniTaskCompletionSource()
|
public UniTask<int> WrapByUniTaskCompletionSource()
|
||||||
@@ -182,47 +188,43 @@ public UniTask<int> WrapByUniTaskCompletionSource()
|
|||||||
var utcs = new UniTaskCompletionSource<int>();
|
var utcs = new UniTaskCompletionSource<int>();
|
||||||
|
|
||||||
// 当操作完成时,调用 utcs.TrySetResult();
|
// 当操作完成时,调用 utcs.TrySetResult();
|
||||||
// 当操作失败时, 调用 utcs.TrySetException();
|
// 当操作失败时,调用 utcs.TrySetException();
|
||||||
// 当操作取消时, 调用 utcs.TrySetCanceled();
|
// 当操作取消时,调用 utcs.TrySetCanceled();
|
||||||
|
|
||||||
return utcs.Task; //本质上就是返回了一个 UniTask<int>
|
return utcs.Task; //本质上就是返回了一个 UniTask<int>
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以进行如下转换
|
您可以进行如下转换:<br>-`Task` -> `UniTask `:使用`AsUniTask`<br>-`UniTask` -> `UniTask<AsyncUnit>`:使用 `AsAsyncUnitUniTask`<br>-`UniTask<T>` -> `UniTask`:使用 `AsUniTask`。`UniTask<T>` -> `UniTask`的转换是无消耗的。
|
||||||
|
|
||||||
- `Task` -> `UniTask `: 使用`AsUniTask`
|
如果您想将异步转换为协程,您可以使用`.ToCoroutine()`,这对于您想只允许使用协程系统大有帮助。
|
||||||
- `UniTask` -> `UniTask<AsyncUnit>`: 使用 `AsAsyncUnitUniTask`
|
|
||||||
- `UniTask<T>` -> `UniTask`: 使用 `AsUniTask`,这两者的转换是无消耗的
|
|
||||||
|
|
||||||
如果你想将异步转换为协程,你可以使用`.ToCoroutine()`,如果你只想允许使用协程系统,这很有用。
|
UniTask 不能 await 两次。这是与.NET Standard 2.1 中引入的[ValueTask/IValueTaskSource](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=netcore-3.1)具有相同的约束。
|
||||||
|
|
||||||
UniTask 不能await两次。这是与.NET Standard 2.1 中引入的[ValueTask/IValueTaskSource](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1?view=netcore-3.1)相同的约束。
|
> 千万不要对 `ValueTask<TResult>` 实例执行以下操作:
|
||||||
|
|
||||||
> 永远不应在 ValueTask 实例上执行以下操作:
|
|
||||||
>
|
>
|
||||||
> - 多次await实例。
|
> - 多次await实例。
|
||||||
> - 多次调用 AsTask。
|
> - 多次调用 AsTask。
|
||||||
> - 在操作尚未完成时调用 .Result 或 .GetAwaiter().GetResult(),多次调用也是不允许的。
|
> - 在操作尚未完成时调用 .Result 或 .GetAwaiter().GetResult(),或对它们进行多次调用。
|
||||||
> - 混用上述行为更是不被允许的。
|
> - 对实例进行上述多种操作。
|
||||||
>
|
>
|
||||||
> 如果您执行上述任何操作,则结果是未定义。
|
> 如果您执行了上述任何操作,则结果是未定义的。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var task = UniTask.DelayFrame(10);
|
var task = UniTask.DelayFrame(10);
|
||||||
await task;
|
await task;
|
||||||
await task; // 寄了, 抛出异常
|
await task; // 错误,抛出异常
|
||||||
```
|
```
|
||||||
|
|
||||||
如果实在需要多次await一个异步操作,可以使用`UniTask.Lazy`来支持多次调用。`.Preserve()`同样允许多次调用(由UniTask内部缓存的结果)。这种方法在函数范围内有多个调用时很有用。
|
如果实在需要多次 await 一个异步操作,可以使用支持多次调用的`UniTask.Lazy`。`.Preserve()`同样允许多次调用(由 UniTask 内部缓存结果)。这种方法在函数范围内有多次调用时很有用。
|
||||||
|
|
||||||
同样的`UniTaskCompletionSource`可以在同一个地方被await多次,或者在很多不同的地方被await。
|
同样的,`UniTaskCompletionSource`可以在同一个地方被 await 多次,或者在很多不同的地方被 await。
|
||||||
|
|
||||||
Cancellation and Exception handling
|
取消和异常处理
|
||||||
---
|
---
|
||||||
一些 UniTask 工厂方法有一个`CancellationToken cancellationToken = default`参数。Unity 的一些异步操作也有`WithCancellation(CancellationToken)`和`ToUniTask(..., CancellationToken cancellation = default)`拓展方法。
|
一些 UniTask 工厂方法中有一个`CancellationToken cancellationToken = default`参数。Unity 的一些异步操作也有`WithCancellation(CancellationToken)`和`ToUniTask(..., CancellationToken cancellation = default)`扩展方法。
|
||||||
|
|
||||||
可以传递原生[`CancellationTokenSource`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource)给参数CancellationToken
|
可以通过原生的[`CancellationTokenSource`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource)将 CancellationToken 传递给参数
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
@@ -237,14 +239,14 @@ await UnityWebRequest.Get("http://google.co.jp").SendWebRequest().WithCancellati
|
|||||||
await UniTask.DelayFrame(1000, cancellationToken: cts.Token);
|
await UniTask.DelayFrame(1000, cancellationToken: cts.Token);
|
||||||
```
|
```
|
||||||
|
|
||||||
CancellationToken 可以由`CancellationTokenSource`或 MonoBehaviour 的`GetCancellationTokenOnDestroy`扩展方法创建。
|
CancellationToken 可通过`CancellationTokenSource`或 MonoBehaviour 的扩展方法`GetCancellationTokenOnDestroy`来创建。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 这个CancellationTokenSource和this GameObject生命周期相同,当this GameObject Destroy的时候,就会执行Cancel
|
// 这个 CancellationToken 的生命周期与 GameObject 的相同
|
||||||
await UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
|
await UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
|
||||||
```
|
```
|
||||||
|
|
||||||
对于链式取消,所有异步方法都建议最后一个参数接受`CancellationToken cancellationToken`,并将`CancellationToken`从头传递到尾。
|
对于链式取消,建议所有异步方法的最后一个参数都接受`CancellationToken cancellationToken`,并将`CancellationToken`从头传递到尾。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
await FooAsync(this.GetCancellationTokenOnDestroy());
|
await FooAsync(this.GetCancellationTokenOnDestroy());
|
||||||
@@ -262,7 +264,7 @@ async UniTask BarAsync(CancellationToken cancellationToken)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`CancellationToken`表示异步的生命周期。您可以使用自定义的生命周期,而不是默认的 CancellationTokenOnDestroy。
|
`CancellationToken`代表了异步操作的生命周期。您可以不使用默认的 CancellationTokenOnDestroy ,通过自定义的`CancellationToken`自行管理生命周期。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class MyBehaviour : MonoBehaviour
|
public class MyBehaviour : MonoBehaviour
|
||||||
@@ -292,9 +294,11 @@ public class MyBehaviour : MonoBehaviour
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
当检测到取消时,所有方法都会向上游抛出并传播`OperationCanceledException`。当异常(不限于`OperationCanceledException`)没有在异步方法中处理时,它将最终传播到`UniTaskScheduler.UnobservedTaskException`。接收到的未处理异常的默认行为是将日志写入异常。可以使用`UniTaskScheduler.UnobservedExceptionWriteLogType`更改日志级别。如果要使用自定义行为,请为`UniTaskScheduler.UnobservedTaskException.`设置一个委托
|
在Unity 2022.2之后,Unity在[MonoBehaviour.destroyCancellationToken](https://docs.unity3d.com/ScriptReference/MonoBehaviour-destroyCancellationToken.html)和[Application.exitCancellationToken](https://docs.unity3d.com/ScriptReference/Application-exitCancellationToken.html)中添加了 CancellationToken。
|
||||||
|
|
||||||
而`OperationCanceledException`是一个特殊的异常,会被`UnobservedTaskException`.无视
|
当检测到取消时,所有方法都会向上游抛出并传播`OperationCanceledException`。当异常(不限于`OperationCanceledException`)没有在异步方法中处理时,它将被传播到`UniTaskScheduler.UnobservedTaskException`。默认情况下,将接收到的未处理异常作为一般异常写入日志。可以使用`UniTaskScheduler.UnobservedExceptionWriteLogType`更改日志级别。若想对接收到未处理异常时的处理进行自定义,请为`UniTaskScheduler.UnobservedTaskException`设置一个委托
|
||||||
|
|
||||||
|
而`OperationCanceledException`是一种特殊的异常,会被`UnobservedTaskException`无视
|
||||||
|
|
||||||
如果要取消异步 UniTask 方法中的行为,请手动抛出`OperationCanceledException`。
|
如果要取消异步 UniTask 方法中的行为,请手动抛出`OperationCanceledException`。
|
||||||
|
|
||||||
@@ -306,7 +310,7 @@ public async UniTask<int> FooAsync()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果您处理异常但想忽略(传播到全局cancellation处理的地方),请使用异常过滤器。
|
如果您只想处理异常,忽略取消操作(让其传播到全局处理 cancellation 的地方),请使用异常过滤器。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public async UniTask<int> BarAsync()
|
public async UniTask<int> BarAsync()
|
||||||
@@ -316,14 +320,14 @@ public async UniTask<int> BarAsync()
|
|||||||
var x = await FooAsync();
|
var x = await FooAsync();
|
||||||
return x * 2;
|
return x * 2;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is OperationCanceledException)) // when (ex is not OperationCanceledException) at C# 9.0
|
catch (Exception ex) when (!(ex is OperationCanceledException)) // 在 C# 9.0 下改成 when (ex is not OperationCanceledException)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
throws/catch`OperationCanceledException`有点重,所以如果性能是一个问题,请使用`UniTask.SuppressCancellationThrow`以避免 OperationCanceledException 抛出。它将返回`(bool IsCanceled, T Result)`而不是抛出。
|
抛出和捕获`OperationCanceledException`有点重度,如果比较在意性能开销,请使用`UniTask.SuppressCancellationThrow`以避免抛出 OperationCanceledException 。它将返回`(bool IsCanceled, T Result)`而不是抛出异常。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var (isCanceled, _) = await UniTask.DelayFrame(10, cancellationToken: cts.Token).SuppressCancellationThrow();
|
var (isCanceled, _) = await UniTask.DelayFrame(10, cancellationToken: cts.Token).SuppressCancellationThrow();
|
||||||
@@ -333,7 +337,19 @@ if (isCanceled)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
注意:仅当您在原方法直接调用SuppressCancellationThrow时才会抑制异常抛出。否则,返回值将被转换,且整个管道不会抑制 throws。
|
注意:仅当您在源头处直接调用`UniTask.SuppressCancellationThrow`时才会抑制异常抛出。否则,返回值将被转换,且整个管道不会抑制异常抛出。
|
||||||
|
|
||||||
|
`UniTask.Yield`和`UniTask.Delay`等功能依赖于 Unity 的 PlayerLoop,它们在 PlayerLoop 中确定`CancellationToken`状态。
|
||||||
|
这意味着当`CancellationToken`被触发时,它们并不会立即取消。
|
||||||
|
|
||||||
|
如果要更改此行为,实现立即取消,可将`cancelImmediately`标志设置为 true。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
await UniTask.Yield(cancellationToken, cancelImmediately: true);
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:比起默认行为,设置 `cancelImmediately` 为 true 并检测立即取消会有更多的性能开销。
|
||||||
|
这是因为它使用了`CancellationToken.Register`;这比在 PlayerLoop 中检查 CancellationToken 更重度。
|
||||||
|
|
||||||
超时处理
|
超时处理
|
||||||
---
|
---
|
||||||
@@ -341,7 +357,7 @@ if (isCanceled)
|
|||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
cts.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
|
cts.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 设置5s超时。
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -356,19 +372,19 @@ catch (OperationCanceledException ex)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> > `CancellationTokenSouce.CancelAfter`是一个原生的api。但是在 Unity 中你不应该使用它,因为它依赖于线程计时器。`CancelAfterSlim`是 UniTask 的扩展方法,它使用 PlayerLoop 代替。
|
> `CancellationTokenSouce.CancelAfter`是一个原生的 api。但是在 Unity 中您不应该使用它,因为它依赖于线程计时器。`CancelAfterSlim`是 UniTask 的扩展方法,它使用 PlayerLoop 代替了线程计时器。
|
||||||
>
|
|
||||||
> 如果您想将超时与其他cancellation一起使用,请使用`CancellationTokenSource.CreateLinkedTokenSource`.
|
如果您想将超时与其他 cancellation 一起使用,请使用`CancellationTokenSource.CreateLinkedTokenSource`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var cancelToken = new CancellationTokenSource();
|
var cancelToken = new CancellationTokenSource();
|
||||||
cancelButton.onClick.AddListener(()=>
|
cancelButton.onClick.AddListener(()=>
|
||||||
{
|
{
|
||||||
cancelToken.Cancel(); // 点击按钮后取消
|
cancelToken.Cancel(); // 点击按钮后取消。
|
||||||
});
|
});
|
||||||
|
|
||||||
var timeoutToken = new CancellationTokenSource();
|
var timeoutToken = new CancellationTokenSource();
|
||||||
timeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 设置5s超时
|
timeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 设置5s超时。
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -390,19 +406,19 @@ catch (OperationCanceledException ex)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
为优化减少每个调用异步方法超时的 CancellationTokenSource 分配,您可以使用 UniTask 的`TimeoutController`.
|
为减少每次调用异步方法时用于超时的 CancellationTokenSource 的堆内存分配,您可以使用 UniTask 的`TimeoutController`进行优化。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
TimeoutController timeoutController = new TimeoutController(); // 复用timeoutController
|
TimeoutController timeoutController = new TimeoutController(); // 提前创建好,以便复用。
|
||||||
|
|
||||||
async UniTask FooAsync()
|
async UniTask FooAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 你可以通过 timeoutController.Timeout(TimeSpan) 传递到 cancellationToken.
|
// 您可以通过 timeoutController.Timeout(TimeSpan) 把超时设置传递到 cancellationToken。
|
||||||
await UnityWebRequest.Get("http://foo").SendWebRequest()
|
await UnityWebRequest.Get("http://foo").SendWebRequest()
|
||||||
.WithCancellation(timeoutController.Timeout(TimeSpan.FromSeconds(5)));
|
.WithCancellation(timeoutController.Timeout(TimeSpan.FromSeconds(5)));
|
||||||
timeoutController.Reset(); // 当await完成后调用Reset(停止超时计时器,并准备下一次复用)
|
timeoutController.Reset(); // 当 await 完成后调用 Reset(停止超时计时器,并准备下一次复用)。
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex)
|
catch (OperationCanceledException ex)
|
||||||
{
|
{
|
||||||
@@ -414,7 +430,7 @@ async UniTask FooAsync()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果您想将超时与其他取消源一起使用,请使用`new TimeoutController(CancellationToken)`.
|
如果您想将超时结合其他取消源一起使用,请使用`new TimeoutController(CancellationToken)`.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
TimeoutController timeoutController;
|
TimeoutController timeoutController;
|
||||||
@@ -427,11 +443,11 @@ void Start()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
注意:UniTask 有`.Timeout`,`.TimeoutWithoutException`方法,但是,如果可能,不要使用这些,请通过`CancellationToken`. 由于`.Timeout`作用在task外部,无法停止超时任务。`.Timeout`表示超时时忽略结果。如果您将一个`CancellationToken`传递给该方法,它将从任务内部执行,因此可以停止正在运行的任务。
|
注意:UniTask 有`.Timeout`,`.TimeoutWithoutException`方法,但如果可以的话,尽量不要使用这些方法,请传递`CancellationToken`。因为`.Timeout`是在任务外部执行,所以无法停止超时任务。`.Timeout`意味着超时后忽略结果。如果您将一个`CancellationToken`传递给该方法,它将从任务内部执行,因此可以停止正在运行的任务。
|
||||||
|
|
||||||
进度
|
进度
|
||||||
---
|
---
|
||||||
一些Unity的异步操作具有`ToUniTask(IProgress<float> progress = null, ...)`扩展方法。
|
一些 Unity 的异步操作具有`ToUniTask(IProgress<float> progress = null, ...)`的扩展方法。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var progress = Progress.Create<float>(x => Debug.Log(x));
|
var progress = Progress.Create<float>(x => Debug.Log(x));
|
||||||
@@ -441,9 +457,9 @@ var request = await UnityWebRequest.Get("http://google.co.jp")
|
|||||||
.ToUniTask(progress: progress);
|
.ToUniTask(progress: progress);
|
||||||
```
|
```
|
||||||
|
|
||||||
您不应该使用原生的`new System.Progress<T>`,因为它每次都会导致GC分配。改为使用`Cysharp.Threading.Tasks.Progress`。这个 progress factory 有两个方法,`Create`和`CreateOnlyValueChanged`. `CreateOnlyValueChanged`仅在进度值更新时调用。
|
您不应该使用原生的`new System.Progress<T>`,因为每次调用它都会产生堆内存分配。请改用`Cysharp.Threading.Tasks.Progress`。这个 progress 工厂类有两个方法,`Create`和`CreateOnlyValueChanged`。`CreateOnlyValueChanged`仅在进度值更新时调用。
|
||||||
|
|
||||||
为调用者实现 IProgress 接口会更好,因为这样可以没有 lambda 分配。
|
为调用者实现 IProgress 接口会更好,这样不会因使用 lambda 而产生堆内存分配。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class Foo : MonoBehaviour, IProgress<float>
|
public class Foo : MonoBehaviour, IProgress<float>
|
||||||
@@ -464,7 +480,7 @@ public class Foo : MonoBehaviour, IProgress<float>
|
|||||||
|
|
||||||
PlayerLoop
|
PlayerLoop
|
||||||
---
|
---
|
||||||
UniTask 在自定义[PlayerLoop](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html)上运行。UniTask 的基于 playerloop 的方法(例如`Delay`、`DelayFrame`、`asyncOperation.ToUniTask`等)接受这个`PlayerLoopTiming`。
|
UniTask 运行在自定义的[PlayerLoop](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html)中。UniTask 中基于 PlayerLoop 的方法(如`Delay`、`DelayFrame`、`asyncOperation.ToUniTask`等)接受这个`PlayerLoopTiming`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public enum PlayerLoopTiming
|
public enum PlayerLoopTiming
|
||||||
@@ -497,27 +513,32 @@ public enum PlayerLoopTiming
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
它表示何时运行,您可以检查[PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae)到 Unity 的默认 playerloop 并注入 UniTask 的自定义循环。
|
它表明了异步任务会在哪个时机运行,您可以查阅[PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae)以了解 Unity 的默认 PlayerLoop 以及注入的 UniTask 的自定义循环。
|
||||||
|
|
||||||
`PlayerLoopTiming.Update`与协程中的`yield return null`类似,但在 Update(Update 和 uGUI 事件(button.onClick, etc...) 前被调用(在`ScriptRunBehaviourUpdate`时被调用),yield return null 在`ScriptRunDelayedDynamicFrameRate`时被调用。`PlayerLoopTiming.FixedUpdate`类似于`WaitForFixedUpdate`。
|
`PlayerLoopTiming.Update`与协程中的`yield return null`类似,但它会在`ScriptRunBehaviourUpdate`时,Update(Update 和 uGUI 事件(button.onClick等)之前被调用,而 yield return null 是在`ScriptRunDelayedDynamicFrameRate`时被调用。`PlayerLoopTiming.FixedUpdate`类似于`WaitForFixedUpdate`。
|
||||||
|
|
||||||
> `PlayerLoopTiming.LastPostLateUpdate`不等同于协程的`yield return new WaitForEndOfFrame()`. 协程的 WaitForEndOfFrame 似乎在 PlayerLoop 完成后运行。一些需要协程结束帧(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, 等) 的方法在 async/await 时无法正常工作。在这些情况下,请将 MonoBehaviour(coroutine runner) 传递给`UniTask.WaitForEndOfFrame`. 例如,`await UniTask.WaitForEndOfFrame(this);`是`yield return new WaitForEndOfFrame()`轻量级0GC的替代方案。
|
> `PlayerLoopTiming.LastPostLateUpdate`不等同于协程的`yield return new WaitForEndOfFrame()`。协程的 WaitForEndOfFrame 似乎在 PlayerLoop 完成后运行。一些需要协程结束帧的方法(`Texture2D.ReadPixels`,`ScreenCapture.CaptureScreenshotAsTexture`,`CommandBuffer`等)在 async/await 时无法正常工作。在这些情况下,请将 MonoBehaviour(用于运行协程)传递给`UniTask.WaitForEndOfFrame`。例如,`await UniTask.WaitForEndOfFrame(this);`是`yield return new WaitForEndOfFrame()`轻量级无堆内存分配的替代方案。
|
||||||
|
|
||||||
`yield return null`和`UniTask.Yield`相似但不同。`yield return null`总是返回下一帧但`UniTask.Yield`返回下一个调用。也就是说,`UniTask.Yield(PlayerLoopTiming.Update)`在 `PreUpdate`上调用,它返回相同的帧。`UniTask.NextFrame()`保证返回下一帧,您可以认为它的行为与`yield return null`一致.
|
> 注意:在 Unity 2023.1或更高的版本中,`await UniTask.WaitForEndOfFrame();`不再需要 MonoBehaviour。因为它使用了`UnityEngine.Awaitable.EndOfFrameAsync`。
|
||||||
|
|
||||||
> UniTask.Yield(without CancellationToken) 是一种特殊类型,返回`YieldAwaitable`并在 YieldRunner 上运行。它是最轻量和最快的。
|
`yield return null`和`UniTask.Yield`相似但不同。`yield return null`总是返回下一帧但`UniTask.Yield`返回下一次调用。也就是说,`UniTask.Yield(PlayerLoopTiming.Update)`在 `PreUpdate`上调用,它返回同一帧。`UniTask.NextFrame()`保证返回下一帧,您可以认为它的行为与`yield return null`一致。
|
||||||
|
|
||||||
`AsyncOperation`在原生生命周期返回。例如,await `SceneManager.LoadSceneAsync`在`EarlyUpdate.UpdatePreloading`时返回,在此之后,加载的场景的`Start`方法调用自`EarlyUpdate.ScriptRunDelayedStartupFrame`。同样的,`await UnityWebRequest`在`EarlyUpdate.ExecuteMainThreadJobs`时返回.
|
> UniTask.Yield(不带 CancellationToken)是一种特殊类型,返回`YieldAwaitable`并在 YieldRunner 上运行。它是最轻量和最快的。
|
||||||
|
|
||||||
在 UniTask 中,await 直接使用原生生命周期,`WithCancellation`和`ToUniTask`可以指定使用的原生生命周期。这通常不会有问题,但是`LoadSceneAsync`在等待之后,它会导致开始和继续的不同顺序。所以建议不要使用`LoadSceneAsync.ToUniTask`。
|
`AsyncOperation`在原生生命周期返回。例如,await `SceneManager.LoadSceneAsync`在`EarlyUpdate.UpdatePreloading`时返回,在此之后,在`EarlyUpdate.ScriptRunDelayedStartupFrame`时调用已加载场景的`Start`方法。同样的,`await UnityWebRequest`在`EarlyUpdate.ExecuteMainThreadJobs`时返回。
|
||||||
|
|
||||||
在堆栈跟踪中,您可以检查它在 playerloop 中的运行位置。
|
在 UniTask 中,直接 await 使用的是原生生命周期,而`WithCancellation`和`ToUniTask`使用的特定的生命周期。这通常不会有问题,但对于`LoadSceneAsync`,它会导致`Start`方法与 await 之后的逻辑的执行顺序错乱。所以建议不要使用`LoadSceneAsync.ToUniTask`。
|
||||||
|
|
||||||
|
> 注意:在 Unity 2023.1或更高的版本中,当您使用新的`UnityEngine.Awaitable`方法(如`SceneManager.LoadSceneAsync`)时,请确保您的文件的 using 指令区域中包含`using UnityEngine;`。
|
||||||
|
> 这可以通过避免使用`UnityEngine.AsyncOperation`版本来防止编译错误。
|
||||||
|
|
||||||
|
在堆栈跟踪中,您可以检查它在 PlayerLoop 中的运行位置。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
默认情况下,UniTask 的 PlayerLoop 初始化在`[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`.
|
默认情况下,UniTask 的 PlayerLoop 在`[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]`初始化。
|
||||||
|
|
||||||
在 BeforeSceneLoad 中调用方法的顺序是不确定的,所以如果你想在其他 BeforeSceneLoad 方法中使用 UniTask,你应该尝试在此之前初始化它。
|
在 BeforeSceneLoad 中调用的方法,它们的执行顺序是不确定的,所以如果您想在其他 BeforeSceneLoad 方法中使用 UniTask,您应该尝试在此之前初始化好 PlayerLoop。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// AfterAssembliesLoaded 表示将会在 BeforeSceneLoad 之前调用
|
// AfterAssembliesLoaded 表示将会在 BeforeSceneLoad 之前调用
|
||||||
@@ -529,15 +550,15 @@ public static void InitUniTaskLoop()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
如果您导入 Unity 的`Entities`包,则会将自定义playerloop重置为默认值`BeforeSceneLoad`并注入 ECS 的循环。当 Unity 在 UniTask 的 initialize 方法之后调用 ECS 的 inject 方法时,UniTask 将不再工作。
|
如果您导入了 Unity 的`Entities`包,则会在`BeforeSceneLoad`将自定义 PlayerLoop 重置为默认值,并注入 ECS 的循环。当 Unity 在 UniTask 的初始化方法执行之后调用了 ECS 的注入方法,UniTask 将不再起作用。
|
||||||
|
|
||||||
为了解决这个问题,您可以在 ECS 初始化后重新初始化 UniTask PlayerLoop。
|
为了解决这个问题,您可以在 ECS 初始化后重新初始化 UniTask PlayerLoop。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 获取ECS Loop.
|
// 获取 ECS Loop。
|
||||||
var playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
|
var playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
|
||||||
|
|
||||||
// 设置UniTask PlayerLoop
|
// 设置 UniTask PlayerLoop。
|
||||||
PlayerLoopHelper.Initialize(ref playerLoop);
|
PlayerLoopHelper.Initialize(ref playerLoop);
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -551,16 +572,16 @@ void Start()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以通过删除未使用的 PlayerLoopTiming 注入来稍微优化循环成本。您可以在初始化时调用`PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)`。
|
您可以通过移除未使用的 PlayerLoopTiming 注入来稍微优化循环成本。您可以在初始化时调用`PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var loop = PlayerLoop.GetCurrentPlayerLoop();
|
var loop = PlayerLoop.GetCurrentPlayerLoop();
|
||||||
PlayerLoopHelper.Initialize(ref loop, InjectPlayerLoopTimings.Minimum); // 最小化 is Update | FixedUpdate | LastPostLateUpdate
|
PlayerLoopHelper.Initialize(ref loop, InjectPlayerLoopTimings.Minimum); // Minimum 就是 Update | FixedUpdate | LastPostLateUpdate
|
||||||
```
|
```
|
||||||
|
|
||||||
`InjectPlayerLoopTimings`有三个预设,`All`,`Standard`(除 LastPostLateUpdate 外),`Minimum`(`Update | FixedUpdate | LastPostLateUpdate`)。默认为全部,您可以组合自定义注入时间,例如`InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate`.
|
`InjectPlayerLoopTimings`有三个预设,`All`,`Standard`(All 除 LastPostLateUpdate 外),`Minimum`(`Update | FixedUpdate | LastPostLateUpdate`)。默认为 All,您可以通过组合来自定义要注入的时机,例如`InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate`。
|
||||||
|
|
||||||
使用未注入`PlayerLoopTiming`的[Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md)可能会出错。例如,您可以为`InjectPlayerLoopTimings.Minimum`设置`BannedSymbols.txt`
|
使用未注入`PlayerLoopTiming`的[Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md)可能会出错。例如,您可以像下列方式那样,为`InjectPlayerLoopTimings.Minimum`设置`BannedSymbols.txt`
|
||||||
|
|
||||||
```txt
|
```txt
|
||||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.Initialization; Isn't injected this PlayerLoop in this project.
|
F:Cysharp.Threading.Tasks.PlayerLoopTiming.Initialization; Isn't injected this PlayerLoop in this project.
|
||||||
@@ -578,13 +599,13 @@ F:Cysharp.Threading.Tasks.PlayerLoopTiming.TimeUpdate; Isn't injected this Playe
|
|||||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastTimeUpdate; Isn't injected this PlayerLoop in this project.
|
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastTimeUpdate; Isn't injected this PlayerLoop in this project.
|
||||||
```
|
```
|
||||||
|
|
||||||
您可以将`RS0030`严重性配置为错误。
|
您可以将`RS0030`的严重性配置为错误。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
async void 与 async UniTaskVoid 对比
|
async void 与 async UniTaskVoid 对比
|
||||||
---
|
---
|
||||||
`async void`是一个原生的 C# 任务系统,因此它不能在 UniTask 系统上运行。也最好不要使用它。`async UniTaskVoid`是`async UniTask`的轻量级版本,因为它没有等待完成并立即向`UniTaskScheduler.UnobservedTaskException`报告错误. 如果您不需要等待(即发即弃),那么使用`UniTaskVoid`会更好。不幸的是,要解除警告,您需要在尾部添加`Forget()`.
|
`async void`是一个原生的 C# 任务系统,因此它不在 UniTask 系统上运行。也最好不要使用它。`async UniTaskVoid`是`async UniTask`的轻量级版本,因为它没有等待完成并立即向`UniTaskScheduler.UnobservedTaskException`报告错误。如果您不需要等待(即发即弃),那么使用`UniTaskVoid`会更好。不幸的是,要解除警告,您需要在尾部添加`Forget()`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public async UniTaskVoid FireAndForgetMethod()
|
public async UniTaskVoid FireAndForgetMethod()
|
||||||
@@ -599,7 +620,7 @@ public void Caller()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
UniTask 也有`Forget`方法,类似`UniTaskVoid`且效果相同。但是如果你完全不需要使用`await`,`UniTaskVoid`会更高效。
|
UniTask 也有`Forget`方法,与`UniTaskVoid`类似且效果相同。如果您完全不需要使用`await`,那么使用`UniTaskVoid`会更高效。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public async UniTask DoAsync()
|
public async UniTask DoAsync()
|
||||||
@@ -614,7 +635,7 @@ public void Caller()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
要使用注册到事件的异步 lambda,请不要使用`async void`. 相反,您可以使用`UniTask.Action` 或 `UniTask.UnityAction`,两者都通过`async UniTaskVoid` lambda 创建委托。
|
要使用注册到事件的异步 lambda,请不要使用`async void`。您可以使用`UniTask.Action` 或 `UniTask.UnityAction`来代替,这两者都通过`async UniTaskVoid` lambda 来创建委托。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
Action actEvent;
|
Action actEvent;
|
||||||
@@ -636,7 +657,7 @@ class Sample : MonoBehaviour
|
|||||||
{
|
{
|
||||||
async UniTaskVoid Start()
|
async UniTaskVoid Start()
|
||||||
{
|
{
|
||||||
// async init code.
|
// 异步初始化代码。
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -647,22 +668,22 @@ UniTaskTracker
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
* Enable AutoReload(Toggle) - 自动重新加载。
|
- Enable AutoReload(Toggle) - 自动重新加载。
|
||||||
* Reload - 重新加载视图(重新扫描内存中UniTask实例,并刷新界面)。
|
- Reload - 重新加载视图(重新扫描内存中UniTask实例,并刷新界面)。
|
||||||
* GC.Collect - 调用 GC.Collect。
|
- GC.Collect - 调用 GC.Collect。
|
||||||
* Enable Tracking(Toggle) - 开始跟踪异步/等待 UniTask。性能影响:低。
|
- Enable Tracking(Toggle) - 开始跟踪异步/等待 UniTask。性能影响:低。
|
||||||
* Enable StackTrace(Toggle) - 在任务启动时捕获 StackTrace。性能影响:高。
|
- Enable StackTrace(Toggle) - 在任务启动时捕获 StackTrace。性能影响:高。
|
||||||
|
|
||||||
UniTaskTracker 仅用于调试用途,因为启用跟踪和捕获堆栈跟踪很有用,但会对性能产生重大影响。推荐的用法是启用跟踪和堆栈跟踪以查找任务泄漏并在完成时禁用它们。
|
UniTaskTracker 仅用于调试用途,因为启用跟踪和捕获堆栈跟踪很有用,但会对性能产生重大影响。推荐的用法是只在查找任务泄漏时启用跟踪和堆栈跟踪,并在使用完毕后禁用它们。
|
||||||
|
|
||||||
外部拓展
|
外部拓展
|
||||||
---
|
---
|
||||||
默认情况下,UniTask 支持 TextMeshPro(`BindTo(TMP_Text)`和`TMP_InputField`,并且TMP_InputField有同原生uGUI `InputField`类似的事件扩展)、DOTween(`Tween`作为等待)和Addressables(`AsyncOperationHandle``AsyncOperationHandle<T>`作为等待)。
|
默认情况下,UniTask 支持 TextMeshPro(`BindTo(TMP_Text)`和像原生 uGUI `InputField` 那样的事件扩展,如`TMP_InputField`)、DOTween(`Tween`作为可等待的)和 Addressables(`AsyncOperationHandle`和`AsyncOperationHandle<T>`作为可等待的)。
|
||||||
|
|
||||||
在单独的 asmdef 中定义,如`UniTask.TextMeshPro`, `UniTask.DOTween`, `UniTask.Addressables`.
|
它们被定义在了如`UniTask.TextMeshPro`,`UniTask.DOTween`,`UniTask.Addressables`等单独的 asmdef文件中。
|
||||||
|
|
||||||
从 Package manager 中导入软件包时,会自动启用对 TextMeshPro 和 Addressables 的支持。
|
从包管理器中导入软件包时,会自动启用对 TextMeshPro 和 Addressables 的支持。
|
||||||
但对于 DOTween 支持,则需要从 [DOTWeen assets](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676r) 中导入并定义脚本定义符号 `UNITASK_DOTWEEN_SUPPORT` 后才能启用。
|
但对于 DOTween 的支持,则需要从[DOTWeen assets](https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676r)中导入并定义脚本定义符号`UNITASK_DOTWEEN_SUPPORT`后才能启用。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 动画序列
|
// 动画序列
|
||||||
@@ -677,21 +698,21 @@ await UniTask.WhenAll(
|
|||||||
transform.DOScale(10, 3).WithCancellation(ct));
|
transform.DOScale(10, 3).WithCancellation(ct));
|
||||||
```
|
```
|
||||||
|
|
||||||
DOTween 支持的默认行为( `await`, `WithCancellation`, `ToUniTask`) await tween 被终止。它适用于 Complete(true/false) 和 Kill(true/false)。但是如果你想重用tweens ( `SetAutoKill(false)`),它就不能按预期工作。如果您想等待另一个时间点,Tween 中存在以下扩展方法,`AwaitForComplete`, `AwaitForPause`, `AwaitForPlay`, `AwaitForRewind`, `AwaitForStepComplete`。
|
DOTween 支持的默认行为(`await`,`WithCancellation`,`ToUniTask`) 会等待到 tween 被终止。它适用于 Complete(true/false) 和 Kill(true/false)。但是如果您想复用 tweens(`SetAutoKill(false)`),它就不能按预期工作。如果您想等待另一个时间点,Tween 中存在以下扩展方法,`AwaitForComplete`,`AwaitForPause`,`AwaitForPlay`,`AwaitForRewind`,`AwaitForStepComplete`。
|
||||||
|
|
||||||
AsyncEnumerable 和 Async LINQ
|
AsyncEnumerable 和 Async LINQ
|
||||||
---
|
---
|
||||||
Unity 2020.2 支持 C# 8.0,因此您可以使用`await foreach`. 这是异步时代的新更新符号。
|
Unity 2020.2 支持 C# 8.0,因此您可以使用`await foreach`。这是异步时代的新更新符号。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// Unity 2020.2, C# 8.0
|
// Unity 2020.2,C# 8.0
|
||||||
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate().WithCancellation(token))
|
await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate().WithCancellation(token))
|
||||||
{
|
{
|
||||||
Debug.Log("Update() " + Time.frameCount);
|
Debug.Log("Update() " + Time.frameCount);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在 C# 7.3 环境中,您可以使用该`ForEachAsync`方法以几乎相同的方式工作。
|
在 C# 7.3 环境中,您可以使用`ForEachAsync`方法以几乎相同的方式工作。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// C# 7.3(Unity 2018.3~)
|
// C# 7.3(Unity 2018.3~)
|
||||||
@@ -701,7 +722,20 @@ await UniTaskAsyncEnumerable.EveryUpdate().ForEachAsync(_ =>
|
|||||||
}, token);
|
}, token);
|
||||||
```
|
```
|
||||||
|
|
||||||
UniTaskAsyncEnumerable 实现异步 LINQ,类似于 LINQ 的`IEnumerable<T>`或 Rx 的 `IObservable<T>`。所有标准 LINQ 查询运算符都可以应用于异步流。例如,以下代码表示如何将 Where 过滤器应用于每两次单击运行一次的按钮单击异步流。
|
`UniTask.WhenEach`类似于 .NET 9 的`Task.WhenEach`,它可以使用新的方式来等待多个任务。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
await foreach (var result in UniTask.WhenEach(task1, task2, task3))
|
||||||
|
{
|
||||||
|
// 结果的类型为 WhenEachResult<T>。
|
||||||
|
// 它包含 `T Result` or `Exception Exception`。
|
||||||
|
// 您可以检查 `IsCompletedSuccessfully` 或 `IsFaulted` 以确定是访 `.Result` 还是 `.Exception`。
|
||||||
|
// 如果希望在 `IsFaulted` 时抛出异常并在成功时获取结果,可以使用 `GetResult()`。
|
||||||
|
Debug.Log(result.GetResult());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
UniTaskAsyncEnumerable 实现了异步 LINQ,类似于 LINQ 的`IEnumerable<T>`或 Rx 的 `IObservable<T>`。所有标准 LINQ 查询运算符都可以应用于异步流。例如,以下代码展示了如何将 Where 过滤器应用于每两次单击运行一次的按钮点击异步流。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
await okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).ForEachAsync(_ =>
|
await okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).ForEachAsync(_ =>
|
||||||
@@ -709,7 +743,7 @@ await okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).ForEachAsy
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Fire and Forget 风格(例如,事件处理),你也可以使用`Subscribe`.
|
即发即弃(Fire and Forget)风格(例如,事件处理),您也可以使用`Subscribe`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).Subscribe(_ =>
|
okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).Subscribe(_ =>
|
||||||
@@ -717,13 +751,13 @@ okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).Subscribe(_ =>
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Async LINQ 在 时启用`using Cysharp.Threading.Tasks.Linq;`,并且`UniTaskAsyncEnumerable`在`UniTask.Linq`asmdef 中定义。
|
在引入`using Cysharp.Threading.Tasks.Linq;`后,异步 LINQ 将被启用,并且`UniTaskAsyncEnumerable`在 asmdef 文件`UniTask.Linq`中定义。
|
||||||
|
|
||||||
它更接近 UniRx(Reactive Extensions),但 UniTaskAsyncEnumerable 是pull-base的异步流,而 Rx 是基于push-base异步流。请注意,尽管相似,但特征不同,并且细节的行为也随之不同。
|
它更接近 UniRx(Reactive Extensions),但 UniTaskAsyncEnumerable 是基于 pull 的异步流,而 Rx 是基于 push 的异步流。请注意,尽管它们相似,但特性不同,细节也有所不同。
|
||||||
|
|
||||||
`UniTaskAsyncEnumerable`是类似的入口点`Enumerable`。除了标准查询运算符之外,还有其他 Unity 生成器,例如`EveryUpdate`、`Timer`、`TimerFrame`、`Interval`、`IntervalFrame`和`EveryValueChanged`。并且还添加了额外的 UniTask 原始查询运算符,如`Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`。
|
`UniTaskAsyncEnumerable`是类似`Enumerable`的入口点。除了标准查询操作符之外,还为 Unity 提供了其他生成器,例如`EveryUpdate`、`Timer`、`TimerFrame`、`Interval`、`IntervalFrame`和`EveryValueChanged`。此外,还添加了 UniTask 原生的查询操作符,如`Append`,`Prepend`,`DistinctUntilChanged`,`ToHashSet`,`Buffer`,`CombineLatest`,`Do`,`Never`,`ForEachAsync`,`Pairwise`,`Publish`,`Queue`,`Return`,`SkipUntil`,`TakeUntil`,`SkipUntilCanceled`,`TakeUntilCanceled`,`TakeLast`,`Subscribe`。
|
||||||
|
|
||||||
以 Func 作为参数的方法具有三个额外的重载,`***Await`, `***AwaitWithCancellation`。
|
以 Func 作为参数的方法具有三个额外的重载,另外两个是`***Await`和`***AwaitWithCancellation`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
Select(Func<T, TR> selector)
|
Select(Func<T, TR> selector)
|
||||||
@@ -731,12 +765,12 @@ SelectAwait(Func<T, UniTask<TR>> selector)
|
|||||||
SelectAwaitWithCancellation(Func<T, CancellationToken, UniTask<TR>> selector)
|
SelectAwaitWithCancellation(Func<T, CancellationToken, UniTask<TR>> selector)
|
||||||
```
|
```
|
||||||
|
|
||||||
如果在 func 方法内部使用`async`,请使用***Awaitor `***AwaitWithCancellation`。
|
如果在 func 内部使用`async`方法,请使用`***Await`或`***AwaitWithCancellation`。
|
||||||
|
|
||||||
如何创建异步迭代器:C# 8.0 支持异步迭代器(`async yield return`),但它只允许`IAsyncEnumerable<T>`并且当然需要 C# 8.0。UniTask 支持`UniTaskAsyncEnumerable.Create`创建自定义异步迭代器的方法。
|
如何创建异步迭代器:C# 8.0 支持异步迭代器(`async yield return`),但它只允许`IAsyncEnumerable<T>`,当然也需要 C# 8.0。UniTask 支持使用`UniTaskAsyncEnumerable.Create`方法来创建自定义异步迭代器。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// IAsyncEnumerable, C# 8.0 异步迭代器. ( 不要这样用,因为IAsyncEnumerable不被UniTask控制).
|
// IAsyncEnumerable,C# 8.0 异步迭代器。(请不要这样使用,因为 IAsyncEnumerable 不被 UniTask 所控制)。
|
||||||
public async IAsyncEnumerable<int> MyEveryUpdate([EnumeratorCancellation]CancellationToken cancelationToken = default)
|
public async IAsyncEnumerable<int> MyEveryUpdate([EnumeratorCancellation]CancellationToken cancelationToken = default)
|
||||||
{
|
{
|
||||||
var frameCount = 0;
|
var frameCount = 0;
|
||||||
@@ -751,14 +785,14 @@ public async IAsyncEnumerable<int> MyEveryUpdate([EnumeratorCancellation]Cancell
|
|||||||
// UniTaskAsyncEnumerable.Create 并用 `await writer.YieldAsync` 代替 `yield return`.
|
// UniTaskAsyncEnumerable.Create 并用 `await writer.YieldAsync` 代替 `yield return`.
|
||||||
public IUniTaskAsyncEnumerable<int> MyEveryUpdate()
|
public IUniTaskAsyncEnumerable<int> MyEveryUpdate()
|
||||||
{
|
{
|
||||||
// writer(IAsyncWriter<T>) has `YieldAsync(value)` method.
|
// writer(IAsyncWriter<T>) 有 `YieldAsync(value)` 方法。
|
||||||
return UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
return UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||||
{
|
{
|
||||||
var frameCount = 0;
|
var frameCount = 0;
|
||||||
await UniTask.Yield();
|
await UniTask.Yield();
|
||||||
while (!token.IsCancellationRequested)
|
while (!token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
await writer.YieldAsync(frameCount++); // instead of `yield return`
|
await writer.YieldAsync(frameCount++); // 代替 `yield return`
|
||||||
await UniTask.Yield();
|
await UniTask.Yield();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -767,7 +801,7 @@ public IUniTaskAsyncEnumerable<int> MyEveryUpdate()
|
|||||||
|
|
||||||
可等待事件
|
可等待事件
|
||||||
---
|
---
|
||||||
所有 uGUI 组件都实现`***AsAsyncEnumerable`了异步事件流的转换。
|
所有 uGUI 组件都实现了`***AsAsyncEnumerable`,以实现对事件的异步流的转换。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
async UniTask TripleClick()
|
async UniTask TripleClick()
|
||||||
@@ -809,7 +843,7 @@ async UniTask TripleClick(CancellationToken token)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
所有 MonoBehaviour 消息事件都可以转换异步流`AsyncTriggers`,可以通过`using Cysharp.Threading.Tasks.Triggers;`进行启用,.AsyncTrigger 可以使用 UniTaskAsyncEnumerable 来创建,通过`GetAsync***Trigger`触发。
|
所有 MonoBehaviour 消息事件均可通过`AsyncTriggers`转换成异步流,`AsyncTriggers`可通过引入`using Cysharp.Threading.Tasks.Triggers;`来启用。`AsyncTriggers`可以使用`GetAsync***Trigger`来创建,并将它作为 UniTaskAsyncEnumerable 来触发。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var trigger = this.GetOnCollisionEnterAsyncHandler();
|
var trigger = this.GetOnCollisionEnterAsyncHandler();
|
||||||
@@ -817,18 +851,18 @@ await trigger.OnCollisionEnterAsync();
|
|||||||
await trigger.OnCollisionEnterAsync();
|
await trigger.OnCollisionEnterAsync();
|
||||||
await trigger.OnCollisionEnterAsync();
|
await trigger.OnCollisionEnterAsync();
|
||||||
|
|
||||||
// every moves.
|
// 每次移动触发。
|
||||||
await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
|
await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
|
||||||
{
|
{
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
`AsyncReactiveProperty`,`AsyncReadOnlyReactiveProperty`是 UniTask 的 ReactiveProperty 版本。将异步流值绑定到 Unity 组件(Text/Selectable/TMP/Text)`BindTo`的`IUniTaskAsyncEnumerable<T>`扩展方法。
|
`AsyncReactiveProperty`,`AsyncReadOnlyReactiveProperty`是 UniTask 的 ReactiveProperty 版本。`BindTo`的`IUniTaskAsyncEnumerable<T>`扩展方法,可以把异步流值绑定到 Unity 组件(Text/Selectable/TMP/Text)。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var rp = new AsyncReactiveProperty<int>(99);
|
var rp = new AsyncReactiveProperty<int>(99);
|
||||||
|
|
||||||
// AsyncReactiveProperty 本身是 IUniTaskAsyncEnumerable, 可以通过LINQ进行查询
|
// AsyncReactiveProperty 本身是 IUniTaskAsyncEnumerable,可以通过 LINQ 进行查询
|
||||||
rp.ForEachAsync(x =>
|
rp.ForEachAsync(x =>
|
||||||
{
|
{
|
||||||
Debug.Log(x);
|
Debug.Log(x);
|
||||||
@@ -851,16 +885,16 @@ var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyAsyncReactiveProper
|
|||||||
在序列中的异步处理完成之前,pull-based异步流不会获取下一个值。这可能会从按钮等推送类型的事件中溢出数据。
|
在序列中的异步处理完成之前,pull-based异步流不会获取下一个值。这可能会从按钮等推送类型的事件中溢出数据。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 在3s完成前,无法获取event
|
// 在3s延迟结束前,无法获取 event
|
||||||
await button.OnClickAsAsyncEnumerable().ForEachAwaitAsync(async x =>
|
await button.OnClickAsAsyncEnumerable().ForEachAwaitAsync(async x =>
|
||||||
{
|
{
|
||||||
await UniTask.Delay(TimeSpan.FromSeconds(3));
|
await UniTask.Delay(TimeSpan.FromSeconds(3));
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
它很有用(防止双击),但有时没用。
|
它(在防止双击方面)是有用的,但有时也并非都有用。
|
||||||
|
|
||||||
使用该`Queue()`方法还将在异步处理期间对事件进行排队。
|
使用`Queue()`方法在异步处理期间也会对事件进行排队。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// 异步处理中对 message 进行排队
|
// 异步处理中对 message 进行排队
|
||||||
@@ -870,7 +904,7 @@ await button.OnClickAsAsyncEnumerable().Queue().ForEachAwaitAsync(async x =>
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
或使用`Subscribe`, fire and forget 风格。
|
或使用即发即弃风格的`Subscribe`。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
button.OnClickAsAsyncEnumerable().Subscribe(async x =>
|
button.OnClickAsAsyncEnumerable().Subscribe(async x =>
|
||||||
@@ -883,11 +917,11 @@ Channel
|
|||||||
---
|
---
|
||||||
`Channel`与[System.Threading.Tasks.Channels](https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels?view=netcore-3.1)相同,类似于 GoLang Channel。
|
`Channel`与[System.Threading.Tasks.Channels](https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels?view=netcore-3.1)相同,类似于 GoLang Channel。
|
||||||
|
|
||||||
目前只支持多生产者、单消费者无界渠道。它可以由`Channel.CreateSingleConsumerUnbounded<T>()`.
|
目前只支持多生产者、单消费者无界 Channel。它可以通过`Channel.CreateSingleConsumerUnbounded<T>()`来创建。
|
||||||
|
|
||||||
对于 producer(`.Writer`),用`TryWrite`推送值和`TryComplete`完成通道。对于 consumer(`.Reader`),使用`TryRead`、`WaitToReadAsync`、`ReadAsync`和`Completion`,`ReadAllAsync`来读取队列的消息。
|
对于生产者(`.Writer`),使用`TryWrite`来推送值,使用`TryComplete`来完成 Channel。对于消费者(`.Reader`),使用`TryRead`、`WaitToReadAsync`、`ReadAsync`和`Completion`,`ReadAllAsync`来读取队列的消息。
|
||||||
|
|
||||||
`ReadAllAsync`返回`IUniTaskAsyncEnumerable<T>` 查询 LINQ 运算符。Reader 只允许单消费者,但使用`.Publish()`查询运算符来启用多播消息。例如,制作 pub/sub 实用程序。
|
`ReadAllAsync`返回`IUniTaskAsyncEnumerable<T>` 因此可以使用 LINQ 操作符。Reader 只允许单消费者,但可以使用`.Publish()`查询操作符来启用多播消息。例如,可以制作发布/订阅工具。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class AsyncMessageBroker<T> : IDisposable
|
public class AsyncMessageBroker<T> : IDisposable
|
||||||
@@ -922,6 +956,14 @@ public class AsyncMessageBroker<T> : IDisposable
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
与 Awaitable 对比
|
||||||
|
---
|
||||||
|
Unity 6 引入了可等待类型[Awaitable](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Awaitable.html)。简而言之,Awaitable 可以被认为是 UniTask 的一个子集,并且事实上,Awaitable的设计也受 UniTask 的影响。它应该能够处理基于 PlayerLoop 的 await,池化 Task,以及支持以类似的方式使用`CancellationToken`进行取消。随着它被包含在标准库中,您可能想知道是继续使用 UniTask 还是迁移到 Awaitable。以下是简要指南。
|
||||||
|
|
||||||
|
首先,Awaitable 提供的功能与协程提供的功能相同。使用 await 代替`yield return`;`await NextFrameAsync()`代替`yield return null`;`WaitForSeconds`和`EndOfFrame`等价。然而,这只是两者之间的差异。就功能而言,它是基于协程的,缺乏基于 Task 的特性。在使用 async/await 的实际应用程序开发中,像`WhenAll`这样的操作是必不可少的。此外,UniTask 支持许多基于帧的操作(如`DelayFrame`)和更灵活的 PlayerLoopTiming 控制,这些在 Awaitable 中是不可用的。当然,它也没有跟踪器窗口。
|
||||||
|
|
||||||
|
因此,我推荐在应用程序开发中使用 UniTask。UniTask 是 Awaitable 的超集,并包含了许多基本特性。对于库开发,如果您希望避免外部依赖,可以使用 Awaitable 作为方法的返回类型。因为 Awaitable 可以使用`AsUniTask`转换为 UniTask,所以支持在 UniTask 库中处理基于 Awaitable 的功能。即便是在库开发中,如果您不需要担心依赖关系,使用 UniTask 也会是您的最佳选择。
|
||||||
|
|
||||||
单元测试
|
单元测试
|
||||||
---
|
---
|
||||||
Unity 的`[UnityTest]`属性可以测试协程(IEnumerator)但不能测试异步。`UniTask.ToCoroutine`将 async/await 桥接到协程,以便您可以测试异步方法。
|
Unity 的`[UnityTest]`属性可以测试协程(IEnumerator)但不能测试异步。`UniTask.ToCoroutine`将 async/await 桥接到协程,以便您可以测试异步方法。
|
||||||
@@ -947,46 +989,46 @@ public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
UniTask 自己的单元测试是使用 Unity Test Runner 和[Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit)编写的,以与 CI 集成并检查 IL2CPP 是否正常工作。
|
UniTask 自身的单元测试是使用 Unity Test Runner 和[Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit)编写的,以集成到 CI 中并检查 IL2CPP 是否正常工作。
|
||||||
|
|
||||||
## 线程池限制
|
## 线程池的限制
|
||||||
|
|
||||||
大多数 UniTask 方法在单个线程 (PlayerLoop) 上运行,只有`UniTask.Run`(`Task.Run`等效)和`UniTask.SwitchToThreadPool`在线程池上运行。如果您使用线程池,它将无法与 WebGL 等平台兼容。
|
大多数 UniTask 方法在单个线程 (PlayerLoop) 上运行,只有`UniTask.Run`(等同于`Task.Run`)和`UniTask.SwitchToThreadPool`在线程池上运行。如果您使用线程池,它将无法与 WebGL 等平台兼容。
|
||||||
|
|
||||||
`UniTask.Run`现在已弃用。你可以改用`UniTask.RunOnThreadPool`。并且还要考虑是否可以使用`UniTask.Create`或`UniTask.Void`。
|
`UniTask.Run`现在已弃用。您可以改用`UniTask.RunOnThreadPool`。并且还要考虑是否可以使用`UniTask.Create`或`UniTask.Void`。
|
||||||
|
|
||||||
## IEnumerator.ToUniTask 限制
|
## IEnumerator.ToUniTask 的限制
|
||||||
|
|
||||||
您可以将协程(IEnumerator)转换为 UniTask(或直接等待),但它有一些限制。
|
您可以将协程(IEnumerator)转换为 UniTask(或直接 await),但它有一些限制。
|
||||||
|
|
||||||
- 不支持`WaitForEndOfFrame`,`WaitForFixedUpdate`,`Coroutine`
|
- 不支持`WaitForEndOfFrame`,`WaitForFixedUpdate`,`Coroutine`
|
||||||
- Loop生命周期与`StartCoroutine`不一样,它使用指定`PlayerLoopTiming`的并且默认情况下,`PlayerLoopTiming.Update`在 MonoBehaviour`Update`和`StartCoroutine`的循环之前运行。
|
- 生命周期与`StartCoroutine`不一样,它使用指定的`PlayerLoopTiming`,并且默认情况下,`PlayerLoopTiming.Update`在 MonoBehaviour 的`Update`和`StartCoroutine`的循环之前执行。
|
||||||
|
|
||||||
如果您想要从协程到异步的完全兼容转换,请使用`IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)`重载。它在参数 MonoBehaviour 的实例上执行 StartCoroutine 并等待它在 UniTask 中完成。
|
如果您想要实现从协程到异步的完全兼容转换,请使用`IEnumerator.ToUniTask(MonoBehaviour coroutineRunner)`重载。它会在传入的 MonoBehaviour 实例中执行 StartCoroutine 并在 UniTask 中等待它完成。
|
||||||
|
|
||||||
## 关于 UnityEditor
|
## 关于 UnityEditor
|
||||||
|
|
||||||
UniTask 可以像编辑器协程一样在 Unity 编辑器上运行。但是,有一些限制。
|
UniTask 可以像编辑器协程一样在 Unity 编辑器上运行。但它有一些限制。
|
||||||
|
|
||||||
- UniTask.Delay 的 DelayType.DeltaTime、UnscaledDeltaTime 无法正常工作,因为它们无法在编辑器中获取 deltaTime。因此在 EditMode 上运行,会自动将 DelayType 更改为`DelayType.Realtime`等待正确的时间。
|
- UniTask.Delay 的 DelayType.DeltaTime、UnscaledDeltaTime 无法正常工作,因为它们无法在编辑器中获取 deltaTime。因此在 EditMode 下运行时,会自动将 DelayType 更改为能等待正确的时间的`DelayType.Realtime`。
|
||||||
- 所有 PlayerLoopTiming 都在`EditorApplication.update`生命周期上运行。
|
- 所有 PlayerLoopTiming 都在`EditorApplication.update`生命周期上运行。
|
||||||
- 带`-quit`的`-batchmode`带不起作用,因为 Unity`EditorApplication.update`在单帧后不会运行并退出。相反,不要使用`-quit`并手动退出`EditorApplication.Exit(0)`.
|
- 带`-quit`的`-batchmode`不起作用,因为 Unity 不会执行 `EditorApplication.update` 并在一帧后退出。因此,不要使用`-quit`并使用`EditorApplication.Exit(0)`手动退出。
|
||||||
|
|
||||||
与原生 Task API 对比
|
与原生 Task API 对比
|
||||||
---
|
---
|
||||||
UniTask 有许多原生的 Task-like API。此表显示了一一对应的 API 是什么。
|
UniTask 有许多原生的类Task API。此表展示了两者相对应的 API。
|
||||||
|
|
||||||
使用原生类型。
|
使用原生类型。
|
||||||
|
|
||||||
| .NET Type | UniTask Type |
|
| .NET 类型 | UniTask 类型 |
|
||||||
| --- | --- |
|
|---------------------------| --- |
|
||||||
| `IProgress<T>` | --- |
|
| `IProgress<T>` | --- |
|
||||||
| `CancellationToken` | --- |
|
| `CancellationToken` | --- |
|
||||||
| `CancellationTokenSource` | --- |
|
| `CancellationTokenSource` | --- |
|
||||||
|
|
||||||
使用 UniTask 类型.
|
使用 UniTask 类型。
|
||||||
|
|
||||||
| .NET Type | UniTask Type |
|
| .NET 类型 | UniTask 类型 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `Task`/`ValueTask` | `UniTask` |
|
| `Task`/`ValueTask` | `UniTask` |
|
||||||
| `Task<T>`/`ValueTask<T>` | `UniTask<T>` |
|
| `Task<T>`/`ValueTask<T>` | `UniTask<T>` |
|
||||||
@@ -1011,6 +1053,7 @@ UniTask 有许多原生的 Task-like API。此表显示了一一对应的 API
|
|||||||
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
| `Task.Run` | `UniTask.RunOnThreadPool` |
|
||||||
| `Task.WhenAll` | `UniTask.WhenAll` |
|
| `Task.WhenAll` | `UniTask.WhenAll` |
|
||||||
| `Task.WhenAny` | `UniTask.WhenAny` |
|
| `Task.WhenAny` | `UniTask.WhenAny` |
|
||||||
|
| `Task.WhenEach` | `UniTask.WhenEach` |
|
||||||
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
||||||
| `Task.FromException` | `UniTask.FromException` |
|
| `Task.FromException` | `UniTask.FromException` |
|
||||||
| `Task.FromResult` | `UniTask.FromResult` |
|
| `Task.FromResult` | `UniTask.FromResult` |
|
||||||
@@ -1020,7 +1063,7 @@ UniTask 有许多原生的 Task-like API。此表显示了一一对应的 API
|
|||||||
|
|
||||||
池化配置
|
池化配置
|
||||||
---
|
---
|
||||||
UniTask 积极缓存异步promise对象以实现零分配(有关技术细节,请参阅博客文章[UniTask v2 — Unity 的零分配异步/等待,使用异步 LINQ](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd))。默认情况下,它缓存所有promise ,但您可以配置`TaskPool.SetMaxPoolSize`为您的值,该值表示每种类型的缓存大小。`TaskPool.GetCacheSizeInfo`返回池中当前缓存的对象。
|
UniTask 通过积极缓存异步 promise 对象实现零堆内存分配(有关技术细节,请参阅博客文章[UniTask v2 — 适用于 Unity 的零堆内存分配的async/await,支持异步 LINQ](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd))。默认情况下,它缓存所有 promise,但您可以通过调用`TaskPool.SetMaxPoolSize`方法来自定义每种类型的最大缓存大小。`TaskPool.GetCacheSizeInfo`返回池中当前缓存的对象。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
||||||
@@ -1029,19 +1072,19 @@ foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Profiler下的分配
|
Profiler 下的堆内存分配
|
||||||
---
|
---
|
||||||
在 UnityEditor 中,分析器显示编译器生成的 AsyncStateMachine 的分配,但它只发生在调试(开发)构建中。C# 编译器将 AsyncStateMachine 生成为 Debug 构建的类和 Release 构建的结构。
|
在 UnityEditor 中,能从 profiler 中看到编译器生成的 AsyncStateMachine 的堆内存分配,但它只出现在Debug(development)构建中。C# 编译器在Debug 构建时将 AsyncStateMachine 生成为类,而在Release 构建时将其生成为结构。
|
||||||
|
|
||||||
Unity 从 2020.1 开始支持代码优化选项(右,页脚)。
|
Unity 从2020.1版本开始支持代码优化选项(位于右下角)。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
您可以将 C# 编译器优化更改为 release 以删除开发版本中的 AsyncStateMachine 分配。此优化选项也可以通过设置`Compilation.CompilationPipeline-codeOptimization`和`Compilation.CodeOptimization`。
|
在开发构建中,您可以通过将 C# 编译器优化设置为 release 模式来移除 AsyncStateMachine 的堆内存分配。此优化选项也可以通过`Compilation.CompilationPipeline-codeOptimization`和`Compilation.CodeOptimization`来设置。
|
||||||
|
|
||||||
UniTaskSynchronizationContext
|
UniTaskSynchronizationContext
|
||||||
---
|
---
|
||||||
Unity 的默认 SynchronizationContext( `UnitySynchronizationContext`) 在性能方面表现不佳。UniTask 绕过`SynchronizationContext`(和`ExecutionContext`) 因此它不使用它,但如果存在`async Task`,则仍然使用它。`UniTaskSynchronizationContext`是`UnitySynchronizationContext`性能更好的替代品。
|
Unity 的默认 SynchronizationContext(`UnitySynchronizationContext`) 在性能方面表现不佳。UniTask 绕过`SynchronizationContext`(和`ExecutionContext`) 因此 UniTask 不使用它,但如果存在`async Task`,则仍然使用它。`UniTaskSynchronizationContext`是`UnitySynchronizationContext`性能更好的替代品。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class SyncContextInjecter
|
public class SyncContextInjecter
|
||||||
@@ -1056,45 +1099,38 @@ public class SyncContextInjecter
|
|||||||
|
|
||||||
这是一个可选的选择,并不总是推荐;`UniTaskSynchronizationContext`性能不如`async UniTask`,并且不是完整的 UniTask 替代品。它也不保证与`UnitySynchronizationContext`完全兼容
|
这是一个可选的选择,并不总是推荐;`UniTaskSynchronizationContext`性能不如`async UniTask`,并且不是完整的 UniTask 替代品。它也不保证与`UnitySynchronizationContext`完全兼容
|
||||||
|
|
||||||
API References
|
API 文档
|
||||||
---
|
---
|
||||||
UniTask 的 API 参考由[DocFX](https://dotnet.github.io/docfx/)和[Cysharp/DocfXTemplate托管在](https://github.com/Cysharp/DocfxTemplate)[cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html)上。
|
UniTask 的 API 文档托管在[cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html),使用[DocFX](https://dotnet.github.io/docfx/)和[Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate)生成。
|
||||||
|
|
||||||
例如,UniTask 的工厂方法可以在[UniTask#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.UniTask.html#methods-1)中看到。UniTaskAsyncEnumerable 的工厂/扩展方法可以在[UniTaskAsyncEnumerable#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.Linq.UniTaskAsyncEnumerable.html#methods-1)中看到。
|
例如,UniTask 的工厂方法可以在[UniTask#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.UniTask.html#methods-1)中查阅。UniTaskAsyncEnumerable 的工厂方法和扩展方法可以在[UniTaskAsyncEnumerable#methods](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.Linq.UniTaskAsyncEnumerable.html#methods-1)中查阅。
|
||||||
|
|
||||||
UPM Package
|
UPM 包
|
||||||
---
|
---
|
||||||
### 通过 git URL 安装
|
### 通过 git URL 安装
|
||||||
|
|
||||||
需要支持 git 包路径查询参数的 unity 版本(Unity >= 2019.3.4f1,Unity >= 2020.1a21)。您可以添加`https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask`到包管理器
|
需要支持 git 包路径查询参数的 Unity 版本(Unity >= 2019.3.4f1,Unity >= 2020.1a21)。您可以在包管理器中添加`https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask`
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
或添加`"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"`到`Packages/manifest.json`.
|
或在`Packages/manifest.json`中添加`"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"` 。
|
||||||
|
|
||||||
如果要设置目标版本,UniTask 使用`*.*.*`发布标签,因此您可以指定一个版本,如`#2.1.0`. 例如`https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0`.
|
UniTask 使用`*.*.*`发布标签来指定版本,因此如果您要设置指定版本,您可以在后面添加像`#2.1.0`这样的版本标签。例如`https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.1.0` 。
|
||||||
|
|
||||||
### 通过 OpenUPM 安装
|
|
||||||
|
|
||||||
该软件包在[openupm 注册表](https://openupm.com/)中可用。建议通过[openupm-cli](https://github.com/openupm/openupm-cli)安装。
|
关于 .NET Core
|
||||||
|
|
||||||
```
|
|
||||||
openupm add com.cysharp.unitask
|
|
||||||
```
|
|
||||||
|
|
||||||
.NET Core
|
|
||||||
---
|
---
|
||||||
对于 .NET Core,请使用 NuGet。
|
对于 .NET Core,请使用 NuGet。
|
||||||
|
|
||||||
> PM> Install-Package [UniTask](https://www.nuget.org/packages/UniTask)
|
> PM> Install-Package [UniTask](https://www.nuget.org/packages/UniTask)
|
||||||
|
|
||||||
.NET Core 版本的 UniTask 是 Unity UniTask 的子集,移除了 PlayerLoop 依赖的方法。
|
.NET Core 版本的 UniTask 是 Unity 版本的 UniTask 的子集,它移除了依赖 PlayerLoop 的方法。
|
||||||
|
|
||||||
它以比标准 Task/ValueTask 更高的性能运行,但在使用时应注意忽略 ExecutionContext/SynchronizationContext。`AsyncLocal`也不起作用,因为它忽略了 ExecutionContext。
|
相比于原生 Task 和 ValueTask,它能以更高的性能运行,但在使用时应注意忽略 ExecutionContext 和 SynchronizationContext。因为它忽略了 ExecutionContext,`AsyncLocal`也不起作用。
|
||||||
|
|
||||||
如果您在内部使用 UniTask,但将 ValueTask 作为外部 API 提供,您可以编写如下(受[PooledAwait](https://github.com/mgravell/PooledAwait)启发)代码。
|
如果您在内部使用 UniTask,但将 ValueTask 作为外部 API 提供,您可以编写如下代码(受[PooledAwait](https://github.com/mgravell/PooledAwait)启发)。
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class ZeroAllocAsyncAwaitInDotNetCore
|
public class ZeroAllocAsyncAwaitInDotNetCore
|
||||||
@@ -1125,10 +1161,10 @@ public ValueTask TestAsync()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
.NET Core 版本允许用户在与Unity共享代码时(例如[CysharpOnion](https://github.com/Cysharp/MagicOnion/)),像使用接口一样使用UniTask。.NET Core 版本的 UniTask 可以提供丝滑的代码共享体验。
|
.NET Core 版本的 UniTask 是为了让用户在与 Unity 共享代码时(例如使用[CysharpOnion](https://github.com/Cysharp/MagicOnion/)),能够将 UniTask 用作接口。.NET Core 版本的 UniTask 使得代码共享更加顺畅。
|
||||||
|
|
||||||
WhenAll 等实用方法作为 UniTask 的补充,由[Cysharp/ValueTaskSupplement](https://github.com/Cysharp/ValueTaskSupplement)提供。
|
[Cysharp/ValueTaskSupplement](https://github.com/Cysharp/ValueTaskSupplement)提供了一些实用方法,如 WhenAll,这些方法等效于 UniTask。
|
||||||
|
|
||||||
License
|
许可证
|
||||||
---
|
---
|
||||||
此仓库基于MIT协议
|
此库采用MIT许可证
|
||||||
|
|||||||
@@ -4,7 +4,11 @@
|
|||||||
"src": [
|
"src": [
|
||||||
{
|
{
|
||||||
"files": [
|
"files": [
|
||||||
"UniTask/Assets/Plugins/UniTask/Runtime/**/*.cs"
|
"UniTask/Library/ScriptAssemblies/UniTask*.dll"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"UniTask/Library/ScriptAssemblies/UniTask.Tests.dll",
|
||||||
|
"UniTask/Library/ScriptAssemblies/UniTask.Tests.Editor.dll"
|
||||||
],
|
],
|
||||||
"src": "../src"
|
"src": "../src"
|
||||||
}
|
}
|
||||||
@@ -54,7 +58,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dest": "_site",
|
"dest": "_site",
|
||||||
|
|
||||||
"globalMetadataFiles": [],
|
"globalMetadataFiles": [],
|
||||||
"fileMetadataFiles": [],
|
"fileMetadataFiles": [],
|
||||||
"template": [
|
"template": [
|
||||||
|
|||||||
@@ -10,27 +10,11 @@
|
|||||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
|
|
||||||
<!-- NuGet Packaging -->
|
<!-- 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>
|
<IsPackable>true</IsPackable>
|
||||||
|
<Id>UniTask</Id>
|
||||||
|
<Description>Provides an efficient async/await integration to Unity and .NET Core.</Description>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Icon.png" Pack="true" PackagePath="/" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs" Exclude="
..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Triggers\*.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Linq\UnityExtensions\*.cs;
 
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;
 
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\TimeoutController.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopTimer.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
" />
|
<Compile Include="..\UniTask\Assets\Plugins\UniTask\Runtime\**\*.cs" Exclude="
..\UniTask\Assets\Plugins\UniTask\Editor\*.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Triggers\*.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Linq\UnityExtensions\*.cs;
 
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityEqualityComparer.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\DiagnosticsExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\PlayerLoopRunner.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;
 
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\TimeoutController.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopTimer.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
" />
|
||||||
<Compile Remove="..\UniTask\Assets\Plugins\UniTask\Runtime\_InternalVisibleTo.cs" />
|
<Compile Remove="..\UniTask\Assets\Plugins\UniTask\Runtime\_InternalVisibleTo.cs" />
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<RootNamespace>NetCoreSandbox</RootNamespace>
|
<RootNamespace>NetCoreSandbox</RootNamespace>
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -16,8 +15,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
|
<ProjectReference Include="..\UniTask.NetCore\UniTask.NetCore.csproj" />
|
||||||
|
|
||||||
|
|
||||||
<ProjectReference Include="..\UniTask.Analyzer\UniTask.Analyzer.csproj">
|
<ProjectReference Include="..\UniTask.Analyzer\UniTask.Analyzer.csproj">
|
||||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
<OutputItemType>Analyzer</OutputItemType>
|
<OutputItemType>Analyzer</OutputItemType>
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
|
|
||||||
<RootNamespace>NetCoreTests</RootNamespace>
|
<RootNamespace>NetCoreTests</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
69
src/UniTask.NetCoreTests/WhenEachTest.cs
Normal file
69
src/UniTask.NetCoreTests/WhenEachTest.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,12 +21,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return ToUniTask(handle).GetAwaiter();
|
return ToUniTask(handle).GetAwaiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCancelled = false)
|
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
|
||||||
{
|
{
|
||||||
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately, autoReleaseWhenCancelled: autoReleaseWhenCancelled);
|
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), bool cancelImmediately = false, bool autoReleaseWhenCancelled = false)
|
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);
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return UniTask.CompletedTask;
|
return UniTask.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCancelled, out var token), token);
|
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCanceled, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
|
public struct AsyncOperationHandleAwaiter : ICriticalNotifyCompletion
|
||||||
@@ -109,7 +109,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
bool autoReleaseWhenCancelled;
|
bool autoReleaseWhenCanceled;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
@@ -119,7 +120,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
completedCallback = HandleCompleted;
|
completedCallback = HandleCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCancelled, 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)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -134,15 +135,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.handle = handle;
|
result.handle = handle;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
result.autoReleaseWhenCanceled = autoReleaseWhenCanceled;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
result.autoReleaseWhenCancelled = autoReleaseWhenCancelled;
|
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
{
|
{
|
||||||
var promise = (AsyncOperationHandleConfiguredSource)state;
|
var promise = (AsyncOperationHandleConfiguredSource)state;
|
||||||
if (promise.autoReleaseWhenCancelled && promise.handle.IsValid())
|
if (promise.autoReleaseWhenCanceled && promise.handle.IsValid())
|
||||||
{
|
{
|
||||||
Addressables.Release(promise.handle);
|
Addressables.Release(promise.handle);
|
||||||
}
|
}
|
||||||
@@ -169,14 +171,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
if (autoReleaseWhenCancelled && handle.IsValid())
|
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||||
{
|
{
|
||||||
Addressables.Release(handle);
|
Addressables.Release(handle);
|
||||||
}
|
}
|
||||||
@@ -191,12 +192,25 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.TrySetResult(AsyncUnit.Default);
|
core.TrySetResult(AsyncUnit.Default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult(short token)
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
{
|
{
|
||||||
@@ -217,14 +231,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
completed = true;
|
completed = true;
|
||||||
if (autoReleaseWhenCancelled && handle.IsValid())
|
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||||
{
|
{
|
||||||
Addressables.Release(handle);
|
Addressables.Release(handle);
|
||||||
}
|
}
|
||||||
@@ -234,7 +247,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (progress != null && handle.IsValid())
|
if (progress != null && handle.IsValid())
|
||||||
{
|
{
|
||||||
progress.Report(handle.PercentComplete);
|
progress.Report(handle.GetDownloadStatus().Percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -261,12 +274,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return ToUniTask(handle).GetAwaiter();
|
return ToUniTask(handle).GetAwaiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCancelled = false)
|
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken, bool cancelImmediately = false, bool autoReleaseWhenCanceled = false)
|
||||||
{
|
{
|
||||||
return ToUniTask(handle, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately, autoReleaseWhenCancelled: autoReleaseWhenCancelled);
|
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), bool cancelImmediately = false, bool autoReleaseWhenCancelled = false)
|
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);
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
||||||
|
|
||||||
@@ -284,7 +297,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return UniTask.FromResult(handle.Result);
|
return UniTask.FromResult(handle.Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, cancelImmediately, autoReleaseWhenCancelled, 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>>
|
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||||
@@ -303,7 +316,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
bool autoReleaseWhenCancelled;
|
bool autoReleaseWhenCanceled;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
UniTaskCompletionSourceCore<T> core;
|
||||||
@@ -313,7 +327,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
completedCallback = HandleCompleted;
|
completedCallback = HandleCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, bool autoReleaseWhenCancelled, 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)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -329,14 +343,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.autoReleaseWhenCancelled = autoReleaseWhenCancelled;
|
result.autoReleaseWhenCanceled = autoReleaseWhenCanceled;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
{
|
{
|
||||||
var promise = (AsyncOperationHandleConfiguredSource<T>)state;
|
var promise = (AsyncOperationHandleConfiguredSource<T>)state;
|
||||||
if (promise.autoReleaseWhenCancelled && promise.handle.IsValid())
|
if (promise.autoReleaseWhenCanceled && promise.handle.IsValid())
|
||||||
{
|
{
|
||||||
Addressables.Release(promise.handle);
|
Addressables.Release(promise.handle);
|
||||||
}
|
}
|
||||||
@@ -363,14 +378,12 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
if (autoReleaseWhenCancelled && handle.IsValid())
|
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||||
{
|
{
|
||||||
Addressables.Release(handle);
|
Addressables.Release(handle);
|
||||||
}
|
}
|
||||||
@@ -385,12 +398,25 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.TrySetResult(argHandle.Result);
|
core.TrySetResult(argHandle.Result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public T GetResult(short token)
|
public T GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
{
|
{
|
||||||
@@ -416,14 +442,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
completed = true;
|
completed = true;
|
||||||
if (autoReleaseWhenCancelled && handle.IsValid())
|
if (autoReleaseWhenCanceled && handle.IsValid())
|
||||||
{
|
{
|
||||||
Addressables.Release(handle);
|
Addressables.Release(handle);
|
||||||
}
|
}
|
||||||
@@ -433,7 +458,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (progress != null && handle.IsValid())
|
if (progress != null && handle.IsValid())
|
||||||
{
|
{
|
||||||
progress.Report(handle.PercentComplete);
|
progress.Report(handle.GetDownloadStatus().Percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
"name": "com.unity.textmeshpro",
|
"name": "com.unity.textmeshpro",
|
||||||
"expression": "",
|
"expression": "",
|
||||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "com.unity.ugui",
|
||||||
|
"expression": "2.0.0",
|
||||||
|
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"noEngineReferences": false
|
"noEngineReferences": false
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
|
|
||||||
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IEnumerable<IUniTaskAsyncEnumerable<T>> sources)
|
public static IUniTaskAsyncEnumerable<T> Merge<T>(this IEnumerable<IUniTaskAsyncEnumerable<T>> sources)
|
||||||
{
|
{
|
||||||
return new Merge<T>(sources.ToArray());
|
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)
|
public static IUniTaskAsyncEnumerable<T> Merge<T>(params IUniTaskAsyncEnumerable<T>[] sources)
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
YieldPromise()
|
YieldPromise()
|
||||||
@@ -227,6 +228,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -252,9 +254,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -290,6 +299,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.Reset();
|
core.Reset();
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,6 +319,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
NextFramePromise()
|
NextFramePromise()
|
||||||
{
|
{
|
||||||
@@ -328,6 +339,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -353,9 +365,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -414,6 +433,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
WaitForEndOfFramePromise()
|
WaitForEndOfFramePromise()
|
||||||
{
|
{
|
||||||
@@ -432,6 +452,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -457,9 +478,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -533,6 +561,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
int delayFrameCount;
|
int delayFrameCount;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
int currentFrameCount;
|
int currentFrameCount;
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
@@ -556,6 +585,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.delayFrameCount = delayFrameCount;
|
result.delayFrameCount = delayFrameCount;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -581,9 +611,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -653,6 +690,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
delayFrameCount = default;
|
delayFrameCount = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -673,6 +711,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
float elapsed;
|
float elapsed;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
@@ -696,6 +735,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
|
result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -721,9 +761,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -775,6 +822,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
elapsed = default;
|
elapsed = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -795,6 +843,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
int initialFrame;
|
int initialFrame;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
@@ -818,6 +867,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -843,9 +893,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -897,6 +954,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
elapsed = default;
|
elapsed = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -916,6 +974,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
ValueStopwatch stopwatch;
|
ValueStopwatch stopwatch;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
@@ -938,6 +997,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.stopwatch = ValueStopwatch.StartNew();
|
result.stopwatch = ValueStopwatch.StartNew();
|
||||||
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
|
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -963,9 +1023,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -1013,6 +1080,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
stopwatch = default;
|
stopwatch = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return factory();
|
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)
|
public static UniTask<T> Create<T>(Func<UniTask<T>> factory)
|
||||||
{
|
{
|
||||||
return factory();
|
return factory();
|
||||||
@@ -137,11 +147,19 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return () => asyncAction(cancellationToken).Forget();
|
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
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create async void(UniTaskVoid) UnityAction.
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
/// For exampe: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
|
/// For example: onClick.AddListener(UniTask.UnityAction(async () => { /* */ } ))
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static UnityEngine.Events.UnityAction UnityAction(Func<UniTaskVoid> asyncAction)
|
public static UnityEngine.Events.UnityAction UnityAction(Func<UniTaskVoid> asyncAction)
|
||||||
{
|
{
|
||||||
@@ -150,13 +168,94 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create async void(UniTaskVoid) UnityAction.
|
/// Create async void(UniTaskVoid) UnityAction.
|
||||||
/// For exampe: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
|
/// For example: onClick.AddListener(UniTask.UnityAction(FooAsync, this.GetCancellationTokenOnDestroy()))
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static UnityEngine.Events.UnityAction UnityAction(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
public static UnityEngine.Events.UnityAction UnityAction(Func<CancellationToken, UniTaskVoid> asyncAction, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return () => asyncAction(cancellationToken).Forget();
|
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
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -175,6 +274,22 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask<T>(new DeferPromise<T>(factory), 0);
|
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>
|
/// <summary>
|
||||||
/// Never complete.
|
/// Never complete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -438,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>
|
sealed class NeverPromise<T> : IUniTaskSource<T>
|
||||||
{
|
{
|
||||||
static readonly Action<object> cancellationCallback = CancellationCallback;
|
static readonly Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.Tracing;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
|
||||||
@@ -14,11 +15,21 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(WaitUntilPromise<T>.Create(state, predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
|
||||||
{
|
{
|
||||||
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
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);
|
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
|
||||||
@@ -49,6 +60,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
Func<bool> predicate;
|
Func<bool> predicate;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
@@ -70,6 +82,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
result.predicate = predicate;
|
result.predicate = predicate;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -95,9 +108,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -147,6 +167,136 @@ namespace Cysharp.Threading.Tasks
|
|||||||
predicate = default;
|
predicate = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class WaitUntilPromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise<T>>
|
||||||
|
{
|
||||||
|
static TaskPool<WaitUntilPromise<T>> pool;
|
||||||
|
WaitUntilPromise<T> nextNode;
|
||||||
|
public ref WaitUntilPromise<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
|
static WaitUntilPromise()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(WaitUntilPromise<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<T, bool> predicate;
|
||||||
|
T argument;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
|
WaitUntilPromise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource Create(T argument, Func<T, 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 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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,6 +315,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
Func<bool> predicate;
|
Func<bool> predicate;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
@@ -186,6 +337,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
result.predicate = predicate;
|
result.predicate = predicate;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -211,9 +363,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -263,6 +422,136 @@ namespace Cysharp.Threading.Tasks
|
|||||||
predicate = default;
|
predicate = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class WaitWhilePromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise<T>>
|
||||||
|
{
|
||||||
|
static TaskPool<WaitWhilePromise<T>> pool;
|
||||||
|
WaitWhilePromise<T> nextNode;
|
||||||
|
public ref WaitWhilePromise<T> NextNode => ref nextNode;
|
||||||
|
|
||||||
|
static WaitWhilePromise()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise<T>), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<T, bool> predicate;
|
||||||
|
T argument;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
|
WaitWhilePromise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource Create(T argument, Func<T, 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<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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,6 +569,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
@@ -287,7 +577,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, bool completeImmediately, out short token)
|
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, bool cancelImmediately, out short token)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -300,8 +590,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (completeImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
{
|
{
|
||||||
@@ -325,9 +616,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
public UniTaskStatus GetStatus(short token)
|
||||||
@@ -362,6 +660,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.Reset();
|
core.Reset();
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,6 +684,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IEqualityComparer<U> equalityComparer;
|
IEqualityComparer<U> equalityComparer;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<U> core;
|
UniTaskCompletionSourceCore<U> core;
|
||||||
|
|
||||||
@@ -410,6 +710,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.currentValue = monitorFunction(target);
|
result.currentValue = monitorFunction(target);
|
||||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -435,9 +736,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -497,6 +805,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
equalityComparer = default;
|
equalityComparer = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,6 +828,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IEqualityComparer<U> equalityComparer;
|
IEqualityComparer<U> equalityComparer;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<U> core;
|
UniTaskCompletionSourceCore<U> core;
|
||||||
|
|
||||||
@@ -543,6 +853,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.currentValue = monitorFunction(target);
|
result.currentValue = monitorFunction(target);
|
||||||
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -568,9 +879,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -630,6 +948,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
equalityComparer = default;
|
equalityComparer = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
183
src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenEach.cs
Normal file
183
src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.WhenEach.cs
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 8760bbbab905a534eb6fb7b61b736926
|
guid: 7cac24fdda5112047a1cd3dd66b542c4
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -201,6 +201,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
task.Forget();
|
||||||
return UniTask.FromCanceled(cancellationToken);
|
return UniTask.FromCanceled(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +225,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
task.Forget();
|
||||||
return UniTask.FromCanceled<T>(cancellationToken);
|
return UniTask.FromCanceled<T>(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||||
@@ -127,6 +128,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -155,9 +157,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -216,6 +225,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,10 +233,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -240,7 +249,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -45,7 +45,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
AsyncGPUReadbackRequest asyncOperation;
|
AsyncGPUReadbackRequest asyncOperation;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
|
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
|
||||||
|
|
||||||
AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||||
@@ -66,6 +66,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
|
|
||||||
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
if (cancelImmediately && cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
@@ -91,9 +92,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -146,6 +154,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
asyncOperation = default;
|
asyncOperation = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 12bdad0556e999f4aa82da29415d361f
|
guid: 8321f4244edfdcd4798b4fcc92a736c9
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -97,6 +97,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
@@ -123,6 +124,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -151,9 +153,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
core.GetResult(token);
|
core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -209,6 +218,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,10 +226,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -231,7 +239,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -320,6 +327,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
||||||
@@ -346,6 +354,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -374,9 +383,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -436,6 +452,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,10 +460,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -458,7 +473,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -548,6 +562,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
||||||
@@ -574,6 +589,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -602,9 +618,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -664,6 +687,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,10 +695,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -686,7 +708,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
#endif
|
||||||
@@ -777,6 +798,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AssetBundle> core;
|
UniTaskCompletionSourceCore<AssetBundle> core;
|
||||||
@@ -803,6 +825,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -831,9 +854,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -893,6 +923,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,10 +931,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -915,7 +944,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
#endif
|
||||||
@@ -1021,6 +1049,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<UnityWebRequest> core;
|
UniTaskCompletionSourceCore<UnityWebRequest> core;
|
||||||
@@ -1047,6 +1076,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -1076,9 +1106,16 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return core.GetResult(token);
|
return core.GetResult(token);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -1146,6 +1183,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1153,10 +1191,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -1172,7 +1208,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
IProgress<float> progress;
|
IProgress<float> progress;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration cancellationTokenRegistration;
|
CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
bool cancelImmediately;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
|
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
|
||||||
@@ -191,6 +192,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
result.asyncOperation = asyncOperation;
|
result.asyncOperation = asyncOperation;
|
||||||
result.progress = progress;
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.cancelImmediately = cancelImmediately;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
asyncOperation.completed += result.continuationAction;
|
asyncOperation.completed += result.continuationAction;
|
||||||
@@ -226,10 +228,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
<# } #>
|
<# } #>
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
|
||||||
{
|
{
|
||||||
TryReturn();
|
TryReturn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<# if (!IsVoid(t)) { #>
|
<# if (!IsVoid(t)) { #>
|
||||||
void IUniTaskSource.GetResult(short token)
|
void IUniTaskSource.GetResult(short token)
|
||||||
@@ -304,6 +309,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
cancellationTokenRegistration.Dispose();
|
cancellationTokenRegistration.Dispose();
|
||||||
|
cancelImmediately = default;
|
||||||
return pool.TryPush(this);
|
return pool.TryPush(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,10 +317,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
if (completed)
|
if (completed)
|
||||||
{
|
{
|
||||||
TryReturn();
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
completed = true;
|
completed = true;
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -337,7 +341,6 @@ namespace Cysharp.Threading.Tasks
|
|||||||
<# } #>
|
<# } #>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
<# if(IsUnityWebRequest(t) || IsAssetBundleModule(t)) { #>
|
<# if(IsUnityWebRequest(t) || IsAssetBundleModule(t)) { #>
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
void InvokeCore(string item1, int item2, int item3)
|
void InvokeCore(string item1, int item2, int item3)
|
||||||
{
|
{
|
||||||
innerEvent.Invoke(item1, item2, item3);
|
Invoke((item1, item2, item3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
|
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
|
||||||
"version": "2.5.2",
|
"version": "2.5.10",
|
||||||
"unity": "2018.4",
|
"unity": "2018.4",
|
||||||
"description": "Provides an efficient async/await integration to Unity.",
|
"description": "Provides an efficient async/await integration to Unity.",
|
||||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 894f21dfce4e82343a91661e1ec1a455
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 959c1472a5d812843bedf9341e87af3b
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "RuntimeUnitTestToolkit",
|
|
||||||
"references": [
|
|
||||||
],
|
|
||||||
"optionalUnityReferences": [
|
|
||||||
"TestAssemblies"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": []
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 14c4fea4b238088479114ba2ffe195f9
|
|
||||||
AssemblyDefinitionImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 660baed073888b8438569f57e42679b2
|
|
||||||
timeCreated: 1476793308
|
|
||||||
licenseType: Pro
|
|
||||||
MonoImporter:
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -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": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b7883c7ac5d6ea4409a229aeab14e796
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
// RETRY:
|
// RETRY:
|
||||||
// try
|
// try
|
||||||
// {
|
// {
|
||||||
// context.RequestHeaders["x-accesss-token"] = token;
|
// context.RequestHeaders["x-access-token"] = token;
|
||||||
// return await next(context, cancellationToken);
|
// return await next(context, cancellationToken);
|
||||||
// }
|
// }
|
||||||
// catch (UnityWebRequestException ex)
|
// catch (UnityWebRequestException ex)
|
||||||
|
|||||||
@@ -18,10 +18,14 @@ using UnityEngine.SceneManagement;
|
|||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// using DG.Tweening;
|
// using DG.Tweening;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public struct MyJob : IJob
|
public struct MyJob : IJob
|
||||||
{
|
{
|
||||||
public int loopCount;
|
public int loopCount;
|
||||||
@@ -116,7 +120,28 @@ public class AsyncMessageBroker<T> : IDisposable
|
|||||||
connection.Dispose();
|
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
|
public class SandboxMain : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -144,6 +169,19 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
Debug.Log("Again");
|
Debug.Log("Again");
|
||||||
|
|
||||||
|
|
||||||
|
// var foo = InstantiateAsync<SandboxMain>(this).ToUniTask();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// var tako = await foo;
|
||||||
|
|
||||||
|
|
||||||
|
//UnityAction action;
|
||||||
|
|
||||||
|
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,6 +592,7 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
async UniTaskVoid Start()
|
async UniTaskVoid Start()
|
||||||
{
|
{
|
||||||
|
await new WhenEachTest().Each();
|
||||||
|
|
||||||
|
|
||||||
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
|
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ OcclusionCullingSettings:
|
|||||||
--- !u!104 &2
|
--- !u!104 &2
|
||||||
RenderSettings:
|
RenderSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 9
|
serializedVersion: 10
|
||||||
m_Fog: 0
|
m_Fog: 0
|
||||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
m_FogMode: 3
|
m_FogMode: 3
|
||||||
@@ -38,13 +38,11 @@ RenderSettings:
|
|||||||
m_ReflectionIntensity: 1
|
m_ReflectionIntensity: 1
|
||||||
m_CustomReflection: {fileID: 0}
|
m_CustomReflection: {fileID: 0}
|
||||||
m_Sun: {fileID: 0}
|
m_Sun: {fileID: 0}
|
||||||
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
|
|
||||||
m_UseRadianceAmbientProbe: 0
|
m_UseRadianceAmbientProbe: 0
|
||||||
--- !u!157 &3
|
--- !u!157 &3
|
||||||
LightmapSettings:
|
LightmapSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 11
|
serializedVersion: 12
|
||||||
m_GIWorkflowMode: 1
|
|
||||||
m_GISettings:
|
m_GISettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_BounceScale: 1
|
m_BounceScale: 1
|
||||||
@@ -67,9 +65,6 @@ LightmapSettings:
|
|||||||
m_LightmapParameters: {fileID: 0}
|
m_LightmapParameters: {fileID: 0}
|
||||||
m_LightmapsBakeMode: 1
|
m_LightmapsBakeMode: 1
|
||||||
m_TextureCompression: 1
|
m_TextureCompression: 1
|
||||||
m_FinalGather: 0
|
|
||||||
m_FinalGatherFiltering: 1
|
|
||||||
m_FinalGatherRayCount: 256
|
|
||||||
m_ReflectionCompression: 2
|
m_ReflectionCompression: 2
|
||||||
m_MixedBakeMode: 2
|
m_MixedBakeMode: 2
|
||||||
m_BakeBackend: 0
|
m_BakeBackend: 0
|
||||||
@@ -98,13 +93,14 @@ LightmapSettings:
|
|||||||
m_TrainingDataDestination: TrainingData
|
m_TrainingDataDestination: TrainingData
|
||||||
m_LightProbeSampleCountMultiplier: 4
|
m_LightProbeSampleCountMultiplier: 4
|
||||||
m_LightingDataAsset: {fileID: 0}
|
m_LightingDataAsset: {fileID: 0}
|
||||||
m_UseShadowmask: 1
|
m_LightingSettings: {fileID: 4890085278179872738, guid: 814185d368762ed45a2298d112780689,
|
||||||
|
type: 2}
|
||||||
--- !u!196 &4
|
--- !u!196 &4
|
||||||
NavMeshSettings:
|
NavMeshSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
m_BuildSettings:
|
m_BuildSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 3
|
||||||
agentTypeID: 0
|
agentTypeID: 0
|
||||||
agentRadius: 0.5
|
agentRadius: 0.5
|
||||||
agentHeight: 2
|
agentHeight: 2
|
||||||
@@ -117,7 +113,9 @@ NavMeshSettings:
|
|||||||
cellSize: 0.16666667
|
cellSize: 0.16666667
|
||||||
manualTileSize: 0
|
manualTileSize: 0
|
||||||
tileSize: 256
|
tileSize: 256
|
||||||
accuratePlacement: 0
|
buildHeightMesh: 0
|
||||||
|
maxJobWorkers: 0
|
||||||
|
preserveTilesOutsideBounds: 0
|
||||||
debug:
|
debug:
|
||||||
m_Flags: 0
|
m_Flags: 0
|
||||||
m_NavMeshData: {fileID: 0}
|
m_NavMeshData: {fileID: 0}
|
||||||
@@ -150,10 +148,10 @@ RectTransform:
|
|||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1584557232}
|
- {fileID: 1584557232}
|
||||||
m_Father: {fileID: 1556045508}
|
m_Father: {fileID: 1556045508}
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
@@ -174,6 +172,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_Navigation:
|
m_Navigation:
|
||||||
m_Mode: 3
|
m_Mode: 3
|
||||||
|
m_WrapAround: 0
|
||||||
m_SelectOnUp: {fileID: 0}
|
m_SelectOnUp: {fileID: 0}
|
||||||
m_SelectOnDown: {fileID: 0}
|
m_SelectOnDown: {fileID: 0}
|
||||||
m_SelectOnLeft: {fileID: 0}
|
m_SelectOnLeft: {fileID: 0}
|
||||||
@@ -218,6 +217,8 @@ MonoBehaviour:
|
|||||||
m_Material: {fileID: 0}
|
m_Material: {fileID: 0}
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
m_RaycastTarget: 1
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
m_OnCullStateChanged:
|
m_OnCullStateChanged:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
@@ -270,9 +271,17 @@ Camera:
|
|||||||
m_projectionMatrixMode: 1
|
m_projectionMatrixMode: 1
|
||||||
m_GateFitMode: 2
|
m_GateFitMode: 2
|
||||||
m_FOVAxisMode: 0
|
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_SensorSize: {x: 36, y: 24}
|
||||||
m_LensShift: {x: 0, y: 0}
|
m_LensShift: {x: 0, y: 0}
|
||||||
m_FocalLength: 50
|
|
||||||
m_NormalizedViewPortRect:
|
m_NormalizedViewPortRect:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
@@ -306,12 +315,13 @@ Transform:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 518730348}
|
m_GameObject: {fileID: 518730348}
|
||||||
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 488, y: 418, z: 0}
|
m_LocalPosition: {x: 488, y: 418, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 1
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &519420028
|
--- !u!1 &519420028
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -352,9 +362,11 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
camera: {fileID: 518730349}
|
mycamera: {fileID: 0}
|
||||||
okButton: {fileID: 16537672}
|
okButton: {fileID: 16537672}
|
||||||
cancelButton: {fileID: 628393011}
|
cancelButton: {fileID: 628393011}
|
||||||
|
RP1:
|
||||||
|
latestValue: 0
|
||||||
text: {fileID: 2101290655}
|
text: {fileID: 2101290655}
|
||||||
button: {fileID: 0}
|
button: {fileID: 0}
|
||||||
--- !u!20 &519420031
|
--- !u!20 &519420031
|
||||||
@@ -371,9 +383,17 @@ Camera:
|
|||||||
m_projectionMatrixMode: 1
|
m_projectionMatrixMode: 1
|
||||||
m_GateFitMode: 2
|
m_GateFitMode: 2
|
||||||
m_FOVAxisMode: 0
|
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_SensorSize: {x: 36, y: 24}
|
||||||
m_LensShift: {x: 0, y: 0}
|
m_LensShift: {x: 0, y: 0}
|
||||||
m_FocalLength: 50
|
|
||||||
m_NormalizedViewPortRect:
|
m_NormalizedViewPortRect:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
@@ -407,12 +427,13 @@ Transform:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 519420028}
|
m_GameObject: {fileID: 519420028}
|
||||||
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: -10}
|
m_LocalPosition: {x: 0, y: 0, z: -10}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &628393009
|
--- !u!1 &628393009
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -443,10 +464,10 @@ RectTransform:
|
|||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 865871445}
|
- {fileID: 865871445}
|
||||||
m_Father: {fileID: 1556045508}
|
m_Father: {fileID: 1556045508}
|
||||||
m_RootOrder: 1
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
@@ -467,6 +488,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
m_Navigation:
|
m_Navigation:
|
||||||
m_Mode: 3
|
m_Mode: 3
|
||||||
|
m_WrapAround: 0
|
||||||
m_SelectOnUp: {fileID: 0}
|
m_SelectOnUp: {fileID: 0}
|
||||||
m_SelectOnDown: {fileID: 0}
|
m_SelectOnDown: {fileID: 0}
|
||||||
m_SelectOnLeft: {fileID: 0}
|
m_SelectOnLeft: {fileID: 0}
|
||||||
@@ -511,6 +533,8 @@ MonoBehaviour:
|
|||||||
m_Material: {fileID: 0}
|
m_Material: {fileID: 0}
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
m_RaycastTarget: 1
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
m_OnCullStateChanged:
|
m_OnCullStateChanged:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
@@ -560,9 +584,9 @@ RectTransform:
|
|||||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 628393010}
|
m_Father: {fileID: 628393010}
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
@@ -584,6 +608,8 @@ MonoBehaviour:
|
|||||||
m_Material: {fileID: 0}
|
m_Material: {fileID: 0}
|
||||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||||
m_RaycastTarget: 1
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
m_OnCullStateChanged:
|
m_OnCullStateChanged:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
@@ -639,6 +665,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
m_SendPointerHoverToParent: 1
|
||||||
m_HorizontalAxis: Horizontal
|
m_HorizontalAxis: Horizontal
|
||||||
m_VerticalAxis: Vertical
|
m_VerticalAxis: Vertical
|
||||||
m_SubmitButton: Submit
|
m_SubmitButton: Submit
|
||||||
@@ -668,12 +695,13 @@ Transform:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 872009839}
|
m_GameObject: {fileID: 872009839}
|
||||||
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 2
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &1556045504
|
--- !u!1 &1556045504
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -733,6 +761,7 @@ MonoBehaviour:
|
|||||||
m_FallbackScreenDPI: 96
|
m_FallbackScreenDPI: 96
|
||||||
m_DefaultSpriteDPI: 96
|
m_DefaultSpriteDPI: 96
|
||||||
m_DynamicPixelsPerUnit: 1
|
m_DynamicPixelsPerUnit: 1
|
||||||
|
m_PresetInfoIsWorld: 0
|
||||||
--- !u!223 &1556045507
|
--- !u!223 &1556045507
|
||||||
Canvas:
|
Canvas:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -750,7 +779,9 @@ Canvas:
|
|||||||
m_OverrideSorting: 0
|
m_OverrideSorting: 0
|
||||||
m_OverridePixelPerfect: 0
|
m_OverridePixelPerfect: 0
|
||||||
m_SortingBucketNormalizedSize: 0
|
m_SortingBucketNormalizedSize: 0
|
||||||
|
m_VertexColorAlwaysGammaSpace: 0
|
||||||
m_AdditionalShaderChannelsFlag: 0
|
m_AdditionalShaderChannelsFlag: 0
|
||||||
|
m_UpdateRectTransformForStandalone: 0
|
||||||
m_SortingLayerID: 0
|
m_SortingLayerID: 0
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
m_TargetDisplay: 0
|
m_TargetDisplay: 0
|
||||||
@@ -764,12 +795,12 @@ RectTransform:
|
|||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 16537671}
|
- {fileID: 16537671}
|
||||||
- {fileID: 628393010}
|
- {fileID: 628393010}
|
||||||
- {fileID: 2101290654}
|
- {fileID: 2101290654}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 3
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {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_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 16537671}
|
m_Father: {fileID: 16537671}
|
||||||
m_RootOrder: 0
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 1, y: 1}
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
@@ -828,6 +859,8 @@ MonoBehaviour:
|
|||||||
m_Material: {fileID: 0}
|
m_Material: {fileID: 0}
|
||||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||||
m_RaycastTarget: 1
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
m_OnCullStateChanged:
|
m_OnCullStateChanged:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
@@ -883,9 +916,9 @@ RectTransform:
|
|||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 1556045508}
|
m_Father: {fileID: 1556045508}
|
||||||
m_RootOrder: 2
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
@@ -907,6 +940,8 @@ MonoBehaviour:
|
|||||||
m_Material: {fileID: 0}
|
m_Material: {fileID: 0}
|
||||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||||
m_RaycastTarget: 1
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
m_OnCullStateChanged:
|
m_OnCullStateChanged:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
@@ -932,3 +967,11 @@ CanvasRenderer:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 2101290653}
|
m_GameObject: {fileID: 2101290653}
|
||||||
m_CullTransparentMesh: 0
|
m_CullTransparentMesh: 0
|
||||||
|
--- !u!1660057539 &9223372036854775807
|
||||||
|
SceneRoots:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Roots:
|
||||||
|
- {fileID: 519420032}
|
||||||
|
- {fileID: 518730350}
|
||||||
|
- {fileID: 872009842}
|
||||||
|
- {fileID: 1556045508}
|
||||||
|
|||||||
74
src/UniTask/Assets/Scenes/WaitWhileTest.cs
Normal file
74
src/UniTask/Assets/Scenes/WaitWhileTest.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3518da33b6245d341a0ef3670ee9268b
|
guid: a478e5f6126dc184ca902adfb35401b4
|
||||||
timeCreated: 1488689723
|
|
||||||
licenseType: Pro
|
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
defaultReferences: []
|
defaultReferences: []
|
||||||
executionOrder: 0
|
executionOrder: 0
|
||||||
@@ -145,6 +145,11 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
public int MyProperty { get; set; }
|
public int MyProperty { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MyBooleanClass
|
||||||
|
{
|
||||||
|
public bool MyProperty { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[UnityTest]
|
[UnityTest]
|
||||||
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
|
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
@@ -159,6 +164,20 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
diff.Should().Be(11);
|
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]
|
[UnityTest]
|
||||||
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
|
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
@@ -173,6 +192,20 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
diff.Should().Be(11);
|
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]
|
[UnityTest]
|
||||||
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
|
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Cysharp.Threading.Tasks;
|
#pragma warning disable CS0618
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
using Cysharp.Threading.Tasks.Linq;
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ TextureImporter:
|
|||||||
213: 1950921086533113773
|
213: 1950921086533113773
|
||||||
second: sample_texture_2
|
second: sample_texture_2
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 12
|
serializedVersion: 13
|
||||||
mipmaps:
|
mipmaps:
|
||||||
mipMapMode: 0
|
mipMapMode: 0
|
||||||
enableMipMap: 0
|
enableMipMap: 0
|
||||||
@@ -86,6 +86,7 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
- serializedVersion: 3
|
- serializedVersion: 3
|
||||||
@@ -98,6 +99,7 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
- serializedVersion: 3
|
- serializedVersion: 3
|
||||||
@@ -110,6 +112,7 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
- serializedVersion: 3
|
- serializedVersion: 3
|
||||||
@@ -122,6 +125,7 @@ TextureImporter:
|
|||||||
crunchedCompression: 0
|
crunchedCompression: 0
|
||||||
allowsAlphaSplitting: 0
|
allowsAlphaSplitting: 0
|
||||||
overridden: 0
|
overridden: 0
|
||||||
|
ignorePlatformSupport: 0
|
||||||
androidETC2FallbackOverride: 0
|
androidETC2FallbackOverride: 0
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
spriteSheet:
|
spriteSheet:
|
||||||
@@ -200,7 +204,10 @@ TextureImporter:
|
|||||||
edges: []
|
edges: []
|
||||||
weights: []
|
weights: []
|
||||||
secondaryTextures: []
|
secondaryTextures: []
|
||||||
nameFileIdTable: {}
|
nameFileIdTable:
|
||||||
|
sample_texture_0: -2664112245596591751
|
||||||
|
sample_texture_1: -4606777057269188692
|
||||||
|
sample_texture_2: 1950921086533113773
|
||||||
mipmapLimitGroupName:
|
mipmapLimitGroupName:
|
||||||
pSDRemoveMatte: 0
|
pSDRemoveMatte: 0
|
||||||
userData:
|
userData:
|
||||||
|
|||||||
@@ -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
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|||||||
45
src/UniTask/Packages/manifest.json
Normal file
45
src/UniTask/Packages/manifest.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
360
src/UniTask/Packages/packages-lock.json
Normal file
360
src/UniTask/Packages/packages-lock.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/UniTask/ProjectSettings/MemorySettings.asset
Normal file
35
src/UniTask/ProjectSettings/MemorySettings.asset
Normal 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: {}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
--- !u!129 &1
|
--- !u!129 &1
|
||||||
PlayerSettings:
|
PlayerSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 20
|
serializedVersion: 26
|
||||||
productGUID: 904cd7a3163037f42a9204c0e2f2b7bd
|
productGUID: 904cd7a3163037f42a9204c0e2f2b7bd
|
||||||
AndroidProfiler: 0
|
AndroidProfiler: 0
|
||||||
AndroidFilterTouchesWhenObscured: 0
|
AndroidFilterTouchesWhenObscured: 0
|
||||||
@@ -48,12 +48,16 @@ PlayerSettings:
|
|||||||
defaultScreenHeightWeb: 600
|
defaultScreenHeightWeb: 600
|
||||||
m_StereoRenderingPath: 0
|
m_StereoRenderingPath: 0
|
||||||
m_ActiveColorSpace: 0
|
m_ActiveColorSpace: 0
|
||||||
|
unsupportedMSAAFallback: 0
|
||||||
|
m_SpriteBatchVertexThreshold: 300
|
||||||
m_MTRendering: 1
|
m_MTRendering: 1
|
||||||
|
mipStripping: 0
|
||||||
|
numberOfMipsStripped: 0
|
||||||
|
numberOfMipsStrippedPerMipmapLimitGroup: {}
|
||||||
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
|
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
|
||||||
iosShowActivityIndicatorOnLoading: -1
|
iosShowActivityIndicatorOnLoading: -1
|
||||||
androidShowActivityIndicatorOnLoading: -1
|
androidShowActivityIndicatorOnLoading: -1
|
||||||
iosUseCustomAppBackgroundBehavior: 0
|
iosUseCustomAppBackgroundBehavior: 0
|
||||||
iosAllowHTTPDownload: 1
|
|
||||||
allowedAutorotateToPortrait: 1
|
allowedAutorotateToPortrait: 1
|
||||||
allowedAutorotateToPortraitUpsideDown: 1
|
allowedAutorotateToPortraitUpsideDown: 1
|
||||||
allowedAutorotateToLandscapeRight: 1
|
allowedAutorotateToLandscapeRight: 1
|
||||||
@@ -66,6 +70,13 @@ PlayerSettings:
|
|||||||
androidRenderOutsideSafeArea: 1
|
androidRenderOutsideSafeArea: 1
|
||||||
androidUseSwappy: 0
|
androidUseSwappy: 0
|
||||||
androidBlitType: 0
|
androidBlitType: 0
|
||||||
|
androidResizableWindow: 0
|
||||||
|
androidDefaultWindowWidth: 1920
|
||||||
|
androidDefaultWindowHeight: 1080
|
||||||
|
androidMinimumWindowWidth: 400
|
||||||
|
androidMinimumWindowHeight: 300
|
||||||
|
androidFullscreenMode: 1
|
||||||
|
androidAutoRotationBehavior: 1
|
||||||
defaultIsNativeResolution: 1
|
defaultIsNativeResolution: 1
|
||||||
macRetinaSupport: 1
|
macRetinaSupport: 1
|
||||||
runInBackground: 1
|
runInBackground: 1
|
||||||
@@ -77,6 +88,7 @@ PlayerSettings:
|
|||||||
hideHomeButton: 0
|
hideHomeButton: 0
|
||||||
submitAnalytics: 1
|
submitAnalytics: 1
|
||||||
usePlayerLog: 1
|
usePlayerLog: 1
|
||||||
|
dedicatedServerOptimizations: 0
|
||||||
bakeCollisionMeshes: 0
|
bakeCollisionMeshes: 0
|
||||||
forceSingleInstance: 0
|
forceSingleInstance: 0
|
||||||
useFlipModelSwapchain: 1
|
useFlipModelSwapchain: 1
|
||||||
@@ -111,16 +123,22 @@ PlayerSettings:
|
|||||||
switchNVNShaderPoolsGranularity: 33554432
|
switchNVNShaderPoolsGranularity: 33554432
|
||||||
switchNVNDefaultPoolsGranularity: 16777216
|
switchNVNDefaultPoolsGranularity: 16777216
|
||||||
switchNVNOtherPoolsGranularity: 16777216
|
switchNVNOtherPoolsGranularity: 16777216
|
||||||
|
switchGpuScratchPoolGranularity: 2097152
|
||||||
|
switchAllowGpuScratchShrinking: 0
|
||||||
|
switchNVNMaxPublicTextureIDCount: 0
|
||||||
|
switchNVNMaxPublicSamplerIDCount: 0
|
||||||
|
switchNVNGraphicsFirmwareMemory: 32
|
||||||
|
switchMaxWorkerMultiple: 8
|
||||||
stadiaPresentMode: 0
|
stadiaPresentMode: 0
|
||||||
stadiaTargetFramerate: 0
|
stadiaTargetFramerate: 0
|
||||||
vulkanNumSwapchainBuffers: 3
|
vulkanNumSwapchainBuffers: 3
|
||||||
vulkanEnableSetSRGBWrite: 0
|
vulkanEnableSetSRGBWrite: 0
|
||||||
m_SupportedAspectRatios:
|
vulkanEnablePreTransform: 0
|
||||||
4:3: 1
|
vulkanEnableLateAcquireNextImage: 0
|
||||||
5:4: 1
|
vulkanEnableCommandBufferRecycling: 1
|
||||||
16:10: 1
|
loadStoreDebugModeEnabled: 0
|
||||||
16:9: 1
|
visionOSBundleVersion: 1.0
|
||||||
Others: 1
|
tvOSBundleVersion: 1.0
|
||||||
bundleVersion: 0.1
|
bundleVersion: 0.1
|
||||||
preloadedAssets: []
|
preloadedAssets: []
|
||||||
metroInputSource: 0
|
metroInputSource: 0
|
||||||
@@ -129,46 +147,29 @@ PlayerSettings:
|
|||||||
xboxOneDisableKinectGpuReservation: 1
|
xboxOneDisableKinectGpuReservation: 1
|
||||||
xboxOneEnable7thCore: 1
|
xboxOneEnable7thCore: 1
|
||||||
vrSettings:
|
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
|
enable360StereoCapture: 0
|
||||||
isWsaHolographicRemotingEnabled: 0
|
isWsaHolographicRemotingEnabled: 0
|
||||||
enableFrameTimingStats: 0
|
enableFrameTimingStats: 0
|
||||||
|
enableOpenGLProfilerGPURecorders: 1
|
||||||
|
allowHDRDisplaySupport: 0
|
||||||
useHDRDisplay: 0
|
useHDRDisplay: 0
|
||||||
D3DHDRBitDepth: 0
|
hdrBitDepth: 0
|
||||||
m_ColorGamuts: 00000000
|
m_ColorGamuts: 00000000
|
||||||
targetPixelDensity: 30
|
targetPixelDensity: 30
|
||||||
resolutionScalingMode: 0
|
resolutionScalingMode: 0
|
||||||
|
resetResolutionOnWindowResize: 0
|
||||||
androidSupportedAspectRatio: 1
|
androidSupportedAspectRatio: 1
|
||||||
androidMaxAspectRatio: 2.1
|
androidMaxAspectRatio: 2.1
|
||||||
applicationIdentifier:
|
applicationIdentifier:
|
||||||
Standalone: com.Company.ProductName
|
Standalone: com.DefaultCompany.UniTask
|
||||||
buildNumber: {}
|
buildNumber:
|
||||||
|
Standalone: 0
|
||||||
|
VisionOS: 0
|
||||||
|
iPhone: 0
|
||||||
|
tvOS: 0
|
||||||
|
overrideDefaultApplicationIdentifier: 0
|
||||||
AndroidBundleVersionCode: 1
|
AndroidBundleVersionCode: 1
|
||||||
AndroidMinSdkVersion: 19
|
AndroidMinSdkVersion: 22
|
||||||
AndroidTargetSdkVersion: 0
|
AndroidTargetSdkVersion: 0
|
||||||
AndroidPreferredInstallLocation: 1
|
AndroidPreferredInstallLocation: 1
|
||||||
aotOptions:
|
aotOptions:
|
||||||
@@ -181,12 +182,15 @@ PlayerSettings:
|
|||||||
APKExpansionFiles: 0
|
APKExpansionFiles: 0
|
||||||
keepLoadedShadersAlive: 0
|
keepLoadedShadersAlive: 0
|
||||||
StripUnusedMeshComponents: 1
|
StripUnusedMeshComponents: 1
|
||||||
|
strictShaderVariantMatching: 0
|
||||||
VertexChannelCompressionMask: 4054
|
VertexChannelCompressionMask: 4054
|
||||||
iPhoneSdkVersion: 988
|
iPhoneSdkVersion: 988
|
||||||
iOSTargetOSVersionString: 10.0
|
iOSTargetOSVersionString: 12.0
|
||||||
tvOSSdkVersion: 0
|
tvOSSdkVersion: 0
|
||||||
tvOSRequireExtendedGameController: 0
|
tvOSRequireExtendedGameController: 0
|
||||||
tvOSTargetOSVersionString: 10.0
|
tvOSTargetOSVersionString: 12.0
|
||||||
|
VisionOSSdkVersion: 0
|
||||||
|
VisionOSTargetOSVersionString: 1.0
|
||||||
uIPrerenderedIcon: 0
|
uIPrerenderedIcon: 0
|
||||||
uIRequiresPersistentWiFi: 0
|
uIRequiresPersistentWiFi: 0
|
||||||
uIRequiresFullScreen: 1
|
uIRequiresFullScreen: 1
|
||||||
@@ -220,32 +224,48 @@ PlayerSettings:
|
|||||||
iOSLaunchScreeniPadFillPct: 100
|
iOSLaunchScreeniPadFillPct: 100
|
||||||
iOSLaunchScreeniPadSize: 100
|
iOSLaunchScreeniPadSize: 100
|
||||||
iOSLaunchScreeniPadCustomXibPath:
|
iOSLaunchScreeniPadCustomXibPath:
|
||||||
iOSUseLaunchScreenStoryboard: 0
|
|
||||||
iOSLaunchScreenCustomStoryboardPath:
|
iOSLaunchScreenCustomStoryboardPath:
|
||||||
|
iOSLaunchScreeniPadCustomStoryboardPath:
|
||||||
iOSDeviceRequirements: []
|
iOSDeviceRequirements: []
|
||||||
iOSURLSchemes: []
|
iOSURLSchemes: []
|
||||||
|
macOSURLSchemes: []
|
||||||
iOSBackgroundModes: 0
|
iOSBackgroundModes: 0
|
||||||
iOSMetalForceHardShadows: 0
|
iOSMetalForceHardShadows: 0
|
||||||
metalEditorSupport: 1
|
metalEditorSupport: 1
|
||||||
metalAPIValidation: 1
|
metalAPIValidation: 1
|
||||||
|
metalCompileShaderBinary: 0
|
||||||
iOSRenderExtraFrameOnPause: 0
|
iOSRenderExtraFrameOnPause: 0
|
||||||
|
iosCopyPluginsCodeInsteadOfSymlink: 0
|
||||||
appleDeveloperTeamID:
|
appleDeveloperTeamID:
|
||||||
iOSManualSigningProvisioningProfileID:
|
iOSManualSigningProvisioningProfileID:
|
||||||
tvOSManualSigningProvisioningProfileID:
|
tvOSManualSigningProvisioningProfileID:
|
||||||
|
VisionOSManualSigningProvisioningProfileID:
|
||||||
iOSManualSigningProvisioningProfileType: 0
|
iOSManualSigningProvisioningProfileType: 0
|
||||||
tvOSManualSigningProvisioningProfileType: 0
|
tvOSManualSigningProvisioningProfileType: 0
|
||||||
|
VisionOSManualSigningProvisioningProfileType: 0
|
||||||
appleEnableAutomaticSigning: 0
|
appleEnableAutomaticSigning: 0
|
||||||
iOSRequireARKit: 0
|
iOSRequireARKit: 0
|
||||||
iOSAutomaticallyDetectAndAddCapabilities: 1
|
iOSAutomaticallyDetectAndAddCapabilities: 1
|
||||||
appleEnableProMotion: 0
|
appleEnableProMotion: 0
|
||||||
|
shaderPrecisionModel: 0
|
||||||
clonedFromGUID: 5f34be1353de5cf4398729fda238591b
|
clonedFromGUID: 5f34be1353de5cf4398729fda238591b
|
||||||
templatePackageId: com.unity.template.2d@3.1.0
|
templatePackageId: com.unity.template.2d@3.1.0
|
||||||
templateDefaultScene: Assets/Scenes/SampleScene.unity
|
templateDefaultScene: Assets/Scenes/SampleScene.unity
|
||||||
|
useCustomMainManifest: 0
|
||||||
|
useCustomLauncherManifest: 0
|
||||||
|
useCustomMainGradleTemplate: 0
|
||||||
|
useCustomLauncherGradleManifest: 0
|
||||||
|
useCustomBaseGradleTemplate: 0
|
||||||
|
useCustomGradlePropertiesTemplate: 0
|
||||||
|
useCustomGradleSettingsTemplate: 0
|
||||||
|
useCustomProguardFile: 0
|
||||||
AndroidTargetArchitectures: 1
|
AndroidTargetArchitectures: 1
|
||||||
|
AndroidTargetDevices: 0
|
||||||
AndroidSplashScreenScale: 0
|
AndroidSplashScreenScale: 0
|
||||||
androidSplashScreen: {fileID: 0}
|
androidSplashScreen: {fileID: 0}
|
||||||
AndroidKeystoreName: '{inproject}: '
|
AndroidKeystoreName: '{inproject}: '
|
||||||
AndroidKeyaliasName:
|
AndroidKeyaliasName:
|
||||||
|
AndroidEnableArmv9SecurityFeatures: 0
|
||||||
AndroidBuildApkPerCpuArchitecture: 0
|
AndroidBuildApkPerCpuArchitecture: 0
|
||||||
AndroidTVCompatibility: 0
|
AndroidTVCompatibility: 0
|
||||||
AndroidIsGame: 1
|
AndroidIsGame: 1
|
||||||
@@ -258,11 +278,15 @@ PlayerSettings:
|
|||||||
height: 180
|
height: 180
|
||||||
banner: {fileID: 0}
|
banner: {fileID: 0}
|
||||||
androidGamepadSupportLevel: 0
|
androidGamepadSupportLevel: 0
|
||||||
|
chromeosInputEmulation: 1
|
||||||
|
AndroidMinifyRelease: 0
|
||||||
|
AndroidMinifyDebug: 0
|
||||||
AndroidValidateAppBundleSize: 1
|
AndroidValidateAppBundleSize: 1
|
||||||
AndroidAppBundleSizeToValidate: 100
|
AndroidAppBundleSizeToValidate: 100
|
||||||
m_BuildTargetIcons: []
|
m_BuildTargetIcons: []
|
||||||
m_BuildTargetPlatformIcons: []
|
m_BuildTargetPlatformIcons: []
|
||||||
m_BuildTargetBatching: []
|
m_BuildTargetBatching: []
|
||||||
|
m_BuildTargetShaderSettings: []
|
||||||
m_BuildTargetGraphicsJobs:
|
m_BuildTargetGraphicsJobs:
|
||||||
- m_BuildTarget: MacStandaloneSupport
|
- m_BuildTarget: MacStandaloneSupport
|
||||||
m_GraphicsJobs: 0
|
m_GraphicsJobs: 0
|
||||||
@@ -298,8 +322,13 @@ PlayerSettings:
|
|||||||
m_BuildTargetGraphicsAPIs:
|
m_BuildTargetGraphicsAPIs:
|
||||||
- m_BuildTarget: AndroidPlayer
|
- m_BuildTarget: AndroidPlayer
|
||||||
m_APIs: 150000000b000000
|
m_APIs: 150000000b000000
|
||||||
m_Automatic: 0
|
m_Automatic: 1
|
||||||
|
- m_BuildTarget: iOSSupport
|
||||||
|
m_APIs: 10000000
|
||||||
|
m_Automatic: 1
|
||||||
m_BuildTargetVRSettings: []
|
m_BuildTargetVRSettings: []
|
||||||
|
m_DefaultShaderChunkSizeInMB: 16
|
||||||
|
m_DefaultShaderChunkCount: 0
|
||||||
openGLRequireES31: 0
|
openGLRequireES31: 0
|
||||||
openGLRequireES31AEP: 0
|
openGLRequireES31AEP: 0
|
||||||
openGLRequireES32: 0
|
openGLRequireES32: 0
|
||||||
@@ -309,7 +338,11 @@ PlayerSettings:
|
|||||||
iPhone: 1
|
iPhone: 1
|
||||||
tvOS: 1
|
tvOS: 1
|
||||||
m_BuildTargetGroupLightmapEncodingQuality: []
|
m_BuildTargetGroupLightmapEncodingQuality: []
|
||||||
|
m_BuildTargetGroupHDRCubemapEncodingQuality: []
|
||||||
m_BuildTargetGroupLightmapSettings: []
|
m_BuildTargetGroupLightmapSettings: []
|
||||||
|
m_BuildTargetGroupLoadStoreDebugModeSettings: []
|
||||||
|
m_BuildTargetNormalMapEncoding: []
|
||||||
|
m_BuildTargetDefaultTextureCompressionFormat: []
|
||||||
playModeTestRunnerEnabled: 0
|
playModeTestRunnerEnabled: 0
|
||||||
runPlayModeTestAsEditModeTest: 0
|
runPlayModeTestAsEditModeTest: 0
|
||||||
actionOnDotNetUnhandledException: 1
|
actionOnDotNetUnhandledException: 1
|
||||||
@@ -319,14 +352,20 @@ PlayerSettings:
|
|||||||
cameraUsageDescription:
|
cameraUsageDescription:
|
||||||
locationUsageDescription:
|
locationUsageDescription:
|
||||||
microphoneUsageDescription:
|
microphoneUsageDescription:
|
||||||
|
bluetoothUsageDescription:
|
||||||
|
macOSTargetOSVersion: 10.13.0
|
||||||
|
switchNMETAOverride:
|
||||||
switchNetLibKey:
|
switchNetLibKey:
|
||||||
switchSocketMemoryPoolSize: 6144
|
switchSocketMemoryPoolSize: 6144
|
||||||
switchSocketAllocatorPoolSize: 128
|
switchSocketAllocatorPoolSize: 128
|
||||||
switchSocketConcurrencyLimit: 14
|
switchSocketConcurrencyLimit: 14
|
||||||
switchScreenResolutionBehavior: 2
|
switchScreenResolutionBehavior: 2
|
||||||
switchUseCPUProfiler: 0
|
switchUseCPUProfiler: 0
|
||||||
|
switchEnableFileSystemTrace: 0
|
||||||
|
switchLTOSetting: 0
|
||||||
switchApplicationID: 0x01004b9000490000
|
switchApplicationID: 0x01004b9000490000
|
||||||
switchNSODependencies:
|
switchNSODependencies:
|
||||||
|
switchCompilerFlags:
|
||||||
switchTitleNames_0:
|
switchTitleNames_0:
|
||||||
switchTitleNames_1:
|
switchTitleNames_1:
|
||||||
switchTitleNames_2:
|
switchTitleNames_2:
|
||||||
@@ -342,6 +381,7 @@ PlayerSettings:
|
|||||||
switchTitleNames_12:
|
switchTitleNames_12:
|
||||||
switchTitleNames_13:
|
switchTitleNames_13:
|
||||||
switchTitleNames_14:
|
switchTitleNames_14:
|
||||||
|
switchTitleNames_15:
|
||||||
switchPublisherNames_0:
|
switchPublisherNames_0:
|
||||||
switchPublisherNames_1:
|
switchPublisherNames_1:
|
||||||
switchPublisherNames_2:
|
switchPublisherNames_2:
|
||||||
@@ -357,6 +397,7 @@ PlayerSettings:
|
|||||||
switchPublisherNames_12:
|
switchPublisherNames_12:
|
||||||
switchPublisherNames_13:
|
switchPublisherNames_13:
|
||||||
switchPublisherNames_14:
|
switchPublisherNames_14:
|
||||||
|
switchPublisherNames_15:
|
||||||
switchIcons_0: {fileID: 0}
|
switchIcons_0: {fileID: 0}
|
||||||
switchIcons_1: {fileID: 0}
|
switchIcons_1: {fileID: 0}
|
||||||
switchIcons_2: {fileID: 0}
|
switchIcons_2: {fileID: 0}
|
||||||
@@ -372,6 +413,7 @@ PlayerSettings:
|
|||||||
switchIcons_12: {fileID: 0}
|
switchIcons_12: {fileID: 0}
|
||||||
switchIcons_13: {fileID: 0}
|
switchIcons_13: {fileID: 0}
|
||||||
switchIcons_14: {fileID: 0}
|
switchIcons_14: {fileID: 0}
|
||||||
|
switchIcons_15: {fileID: 0}
|
||||||
switchSmallIcons_0: {fileID: 0}
|
switchSmallIcons_0: {fileID: 0}
|
||||||
switchSmallIcons_1: {fileID: 0}
|
switchSmallIcons_1: {fileID: 0}
|
||||||
switchSmallIcons_2: {fileID: 0}
|
switchSmallIcons_2: {fileID: 0}
|
||||||
@@ -387,6 +429,7 @@ PlayerSettings:
|
|||||||
switchSmallIcons_12: {fileID: 0}
|
switchSmallIcons_12: {fileID: 0}
|
||||||
switchSmallIcons_13: {fileID: 0}
|
switchSmallIcons_13: {fileID: 0}
|
||||||
switchSmallIcons_14: {fileID: 0}
|
switchSmallIcons_14: {fileID: 0}
|
||||||
|
switchSmallIcons_15: {fileID: 0}
|
||||||
switchManualHTML:
|
switchManualHTML:
|
||||||
switchAccessibleURLs:
|
switchAccessibleURLs:
|
||||||
switchLegalInformation:
|
switchLegalInformation:
|
||||||
@@ -396,7 +439,6 @@ PlayerSettings:
|
|||||||
switchReleaseVersion: 0
|
switchReleaseVersion: 0
|
||||||
switchDisplayVersion: 1.0.0
|
switchDisplayVersion: 1.0.0
|
||||||
switchStartupUserAccount: 0
|
switchStartupUserAccount: 0
|
||||||
switchTouchScreenUsage: 0
|
|
||||||
switchSupportedLanguagesMask: 0
|
switchSupportedLanguagesMask: 0
|
||||||
switchLogoType: 0
|
switchLogoType: 0
|
||||||
switchApplicationErrorCodeCategory:
|
switchApplicationErrorCodeCategory:
|
||||||
@@ -438,6 +480,7 @@ PlayerSettings:
|
|||||||
switchNativeFsCacheSize: 32
|
switchNativeFsCacheSize: 32
|
||||||
switchIsHoldTypeHorizontal: 0
|
switchIsHoldTypeHorizontal: 0
|
||||||
switchSupportedNpadCount: 8
|
switchSupportedNpadCount: 8
|
||||||
|
switchEnableTouchScreen: 1
|
||||||
switchSocketConfigEnabled: 0
|
switchSocketConfigEnabled: 0
|
||||||
switchTcpInitialSendBufferSize: 32
|
switchTcpInitialSendBufferSize: 32
|
||||||
switchTcpInitialReceiveBufferSize: 64
|
switchTcpInitialReceiveBufferSize: 64
|
||||||
@@ -448,7 +491,12 @@ PlayerSettings:
|
|||||||
switchSocketBufferEfficiency: 4
|
switchSocketBufferEfficiency: 4
|
||||||
switchSocketInitializeEnabled: 1
|
switchSocketInitializeEnabled: 1
|
||||||
switchNetworkInterfaceManagerInitializeEnabled: 1
|
switchNetworkInterfaceManagerInitializeEnabled: 1
|
||||||
switchPlayerConnectionEnabled: 1
|
switchUseNewStyleFilepaths: 0
|
||||||
|
switchUseLegacyFmodPriorities: 0
|
||||||
|
switchUseMicroSleepForYield: 1
|
||||||
|
switchEnableRamDiskSupport: 0
|
||||||
|
switchMicroSleepForYieldTime: 25
|
||||||
|
switchRamDiskSpaceSize: 12
|
||||||
ps4NPAgeRating: 12
|
ps4NPAgeRating: 12
|
||||||
ps4NPTitleSecret:
|
ps4NPTitleSecret:
|
||||||
ps4NPTrophyPackPath:
|
ps4NPTrophyPackPath:
|
||||||
@@ -475,6 +523,7 @@ PlayerSettings:
|
|||||||
ps4ShareFilePath:
|
ps4ShareFilePath:
|
||||||
ps4ShareOverlayImagePath:
|
ps4ShareOverlayImagePath:
|
||||||
ps4PrivacyGuardImagePath:
|
ps4PrivacyGuardImagePath:
|
||||||
|
ps4ExtraSceSysFile:
|
||||||
ps4NPtitleDatPath:
|
ps4NPtitleDatPath:
|
||||||
ps4RemotePlayKeyAssignment: -1
|
ps4RemotePlayKeyAssignment: -1
|
||||||
ps4RemotePlayKeyMappingDir:
|
ps4RemotePlayKeyMappingDir:
|
||||||
@@ -517,6 +566,9 @@ PlayerSettings:
|
|||||||
ps4disableAutoHideSplash: 0
|
ps4disableAutoHideSplash: 0
|
||||||
ps4videoRecordingFeaturesUsed: 0
|
ps4videoRecordingFeaturesUsed: 0
|
||||||
ps4contentSearchFeaturesUsed: 0
|
ps4contentSearchFeaturesUsed: 0
|
||||||
|
ps4CompatibilityPS5: 0
|
||||||
|
ps4AllowPS5Detection: 0
|
||||||
|
ps4GPU800MHz: 1
|
||||||
ps4attribEyeToEyeDistanceSettingVR: 0
|
ps4attribEyeToEyeDistanceSettingVR: 0
|
||||||
ps4IncludedModules: []
|
ps4IncludedModules: []
|
||||||
ps4attribVROutputEnabled: 0
|
ps4attribVROutputEnabled: 0
|
||||||
@@ -528,6 +580,7 @@ PlayerSettings:
|
|||||||
webGLMemorySize: 16
|
webGLMemorySize: 16
|
||||||
webGLExceptionSupport: 1
|
webGLExceptionSupport: 1
|
||||||
webGLNameFilesAsHashes: 0
|
webGLNameFilesAsHashes: 0
|
||||||
|
webGLShowDiagnostics: 0
|
||||||
webGLDataCaching: 1
|
webGLDataCaching: 1
|
||||||
webGLDebugSymbols: 0
|
webGLDebugSymbols: 0
|
||||||
webGLEmscriptenArgs:
|
webGLEmscriptenArgs:
|
||||||
@@ -536,18 +589,47 @@ PlayerSettings:
|
|||||||
webGLAnalyzeBuildSize: 0
|
webGLAnalyzeBuildSize: 0
|
||||||
webGLUseEmbeddedResources: 0
|
webGLUseEmbeddedResources: 0
|
||||||
webGLCompressionFormat: 1
|
webGLCompressionFormat: 1
|
||||||
|
webGLWasmArithmeticExceptions: 0
|
||||||
webGLLinkerTarget: 1
|
webGLLinkerTarget: 1
|
||||||
webGLThreadsSupport: 0
|
webGLThreadsSupport: 0
|
||||||
webGLWasmStreaming: 0
|
webGLDecompressionFallback: 0
|
||||||
|
webGLInitialMemorySize: 32
|
||||||
|
webGLMaximumMemorySize: 2048
|
||||||
|
webGLMemoryGrowthMode: 2
|
||||||
|
webGLMemoryLinearGrowthStep: 16
|
||||||
|
webGLMemoryGeometricGrowthStep: 0.2
|
||||||
|
webGLMemoryGeometricGrowthCap: 96
|
||||||
|
webGLPowerPreference: 2
|
||||||
scriptingDefineSymbols: {}
|
scriptingDefineSymbols: {}
|
||||||
|
additionalCompilerArguments: {}
|
||||||
platformArchitecture: {}
|
platformArchitecture: {}
|
||||||
scriptingBackend:
|
scriptingBackend:
|
||||||
Android: 1
|
Android: 1
|
||||||
|
Server: 1
|
||||||
Standalone: 1
|
Standalone: 1
|
||||||
il2cppCompilerConfiguration: {}
|
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: {}
|
incrementalIl2cppBuild: {}
|
||||||
|
suppressCommonWarnings: 1
|
||||||
allowUnsafeCode: 0
|
allowUnsafeCode: 0
|
||||||
|
useDeterministicCompilation: 1
|
||||||
additionalIl2CppArgs:
|
additionalIl2CppArgs:
|
||||||
scriptingRuntimeVersion: 1
|
scriptingRuntimeVersion: 1
|
||||||
gcIncremental: 0
|
gcIncremental: 0
|
||||||
@@ -578,11 +660,13 @@ PlayerSettings:
|
|||||||
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
|
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
|
||||||
a: 1}
|
a: 1}
|
||||||
metroSplashScreenUseBackgroundColor: 0
|
metroSplashScreenUseBackgroundColor: 0
|
||||||
|
syncCapabilities: 0
|
||||||
platformCapabilities: {}
|
platformCapabilities: {}
|
||||||
metroTargetDeviceFamilies: {}
|
metroTargetDeviceFamilies: {}
|
||||||
metroFTAName:
|
metroFTAName:
|
||||||
metroFTAFileTypes: []
|
metroFTAFileTypes: []
|
||||||
metroProtocolName:
|
metroProtocolName:
|
||||||
|
vcxProjDefaultLanguage:
|
||||||
XboxOneProductId:
|
XboxOneProductId:
|
||||||
XboxOneUpdateKey:
|
XboxOneUpdateKey:
|
||||||
XboxOneSandboxId:
|
XboxOneSandboxId:
|
||||||
@@ -601,6 +685,7 @@ PlayerSettings:
|
|||||||
XboxOneCapability: []
|
XboxOneCapability: []
|
||||||
XboxOneGameRating: {}
|
XboxOneGameRating: {}
|
||||||
XboxOneIsContentPackage: 0
|
XboxOneIsContentPackage: 0
|
||||||
|
XboxOneEnhancedXboxCompatibilityMode: 0
|
||||||
XboxOneEnableGPUVariability: 1
|
XboxOneEnableGPUVariability: 1
|
||||||
XboxOneSockets: {}
|
XboxOneSockets: {}
|
||||||
XboxOneSplashScreen: {fileID: 0}
|
XboxOneSplashScreen: {fileID: 0}
|
||||||
@@ -609,10 +694,7 @@ PlayerSettings:
|
|||||||
XboxOneXTitleMemory: 8
|
XboxOneXTitleMemory: 8
|
||||||
XboxOneOverrideIdentityName:
|
XboxOneOverrideIdentityName:
|
||||||
XboxOneOverrideIdentityPublisher:
|
XboxOneOverrideIdentityPublisher:
|
||||||
vrEditorSettings:
|
vrEditorSettings: {}
|
||||||
daydream:
|
|
||||||
daydreamIconForeground: {fileID: 0}
|
|
||||||
daydreamIconBackground: {fileID: 0}
|
|
||||||
cloudServicesEnabled:
|
cloudServicesEnabled:
|
||||||
UNet: 1
|
UNet: 1
|
||||||
luminIcon:
|
luminIcon:
|
||||||
@@ -626,12 +708,22 @@ PlayerSettings:
|
|||||||
luminVersion:
|
luminVersion:
|
||||||
m_VersionCode: 1
|
m_VersionCode: 1
|
||||||
m_VersionName:
|
m_VersionName:
|
||||||
|
hmiPlayerDataPath:
|
||||||
|
hmiForceSRGBBlit: 1
|
||||||
|
embeddedLinuxEnableGamepadInput: 1
|
||||||
|
hmiLogStartupTiming: 0
|
||||||
|
hmiCpuConfiguration:
|
||||||
apiCompatibilityLevel: 6
|
apiCompatibilityLevel: 6
|
||||||
|
activeInputHandler: 0
|
||||||
|
windowsGamepadBackendHint: 0
|
||||||
cloudProjectId:
|
cloudProjectId:
|
||||||
framebufferDepthMemorylessMode: 0
|
framebufferDepthMemorylessMode: 0
|
||||||
|
qualitySettingsNames: []
|
||||||
projectName:
|
projectName:
|
||||||
organizationId:
|
organizationId:
|
||||||
cloudEnabled: 0
|
cloudEnabled: 0
|
||||||
enableNativePlatformBackendsForNewInputSystem: 0
|
|
||||||
disableOldInputManagerSupport: 0
|
|
||||||
legacyClampBlendShapeWeights: 1
|
legacyClampBlendShapeWeights: 1
|
||||||
|
hmiLoadingImage: {fileID: 0}
|
||||||
|
platformRequiresReadableAssets: 0
|
||||||
|
virtualTexturingSupportEnabled: 0
|
||||||
|
insecureHttpOption: 0
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
m_EditorVersion: 2020.2.1f1
|
m_EditorVersion: 2022.3.39f1
|
||||||
m_EditorVersionWithRevision: 2020.2.1f1 (270dd8c3da1c)
|
m_EditorVersionWithRevision: 2022.3.39f1 (4e1b0f82c39a)
|
||||||
|
|||||||
121
src/UniTask/ProjectSettings/SceneTemplateSettings.json
Normal file
121
src/UniTask/ProjectSettings/SceneTemplateSettings.json
Normal 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
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ UnityConnectSettings:
|
|||||||
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
|
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
|
||||||
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
|
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
|
||||||
m_ConfigUrl: https://config.uca.cloud.unity3d.com
|
m_ConfigUrl: https://config.uca.cloud.unity3d.com
|
||||||
|
m_DashboardUrl: https://dashboard.unity3d.com
|
||||||
m_TestInitMode: 0
|
m_TestInitMode: 0
|
||||||
CrashReportingSettings:
|
CrashReportingSettings:
|
||||||
m_EventUrl: https://perf-events.cloud.unity3d.com
|
m_EventUrl: https://perf-events.cloud.unity3d.com
|
||||||
@@ -22,6 +23,7 @@ UnityConnectSettings:
|
|||||||
m_Enabled: 0
|
m_Enabled: 0
|
||||||
m_TestMode: 0
|
m_TestMode: 0
|
||||||
m_InitializeOnStartup: 1
|
m_InitializeOnStartup: 1
|
||||||
|
m_PackageRequiringCoreStatsPresent: 0
|
||||||
UnityAdsSettings:
|
UnityAdsSettings:
|
||||||
m_Enabled: 0
|
m_Enabled: 0
|
||||||
m_InitializeOnStartup: 1
|
m_InitializeOnStartup: 1
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!162 &1
|
|
||||||
EditorUserSettings:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
serializedVersion: 4
|
|
||||||
m_ConfigSettings:
|
|
||||||
RecentlyUsedScenePath-0:
|
|
||||||
value: 22424703114646680e0b0227036c6c1118131a25340527392367083debf42d
|
|
||||||
flags: 0
|
|
||||||
vcSharedLogLevel:
|
|
||||||
value: 0d5e400f0650
|
|
||||||
flags: 0
|
|
||||||
m_VCAutomaticAdd: 1
|
|
||||||
m_VCDebugCom: 0
|
|
||||||
m_VCDebugCmd: 0
|
|
||||||
m_VCDebugOut: 0
|
|
||||||
m_SemanticMergeMode: 2
|
|
||||||
m_VCShowFailedCheckout: 1
|
|
||||||
m_VCOverwriteFailedCheckoutAssets: 1
|
|
||||||
m_VCProjectOverlayIcons: 1
|
|
||||||
m_VCHierarchyOverlayIcons: 1
|
|
||||||
m_VCOtherOverlayIcons: 1
|
|
||||||
m_VCAllowAsyncUpdate: 0
|
|
||||||
Reference in New Issue
Block a user