mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 11:30:09 +00:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bf9f4f062 | ||
|
|
d69490cb49 | ||
|
|
4e460c11ca | ||
|
|
9313969314 | ||
|
|
a40f89a922 | ||
|
|
e0d8410b62 | ||
|
|
bef1bd8ad1 | ||
|
|
81b4fcfac1 | ||
|
|
f1e4a3c65d | ||
|
|
65622b01f6 | ||
|
|
87dd5f13fd | ||
|
|
79cd2c17ba | ||
|
|
85fb08552e | ||
|
|
7bd4b6faf7 | ||
|
|
0b1ae7e295 | ||
|
|
35a893ad9e | ||
|
|
4955ed18f1 | ||
|
|
fe462328ab | ||
|
|
5136d92efa | ||
|
|
227f7872cb | ||
|
|
725b2fdc35 | ||
|
|
75abc8059f | ||
|
|
f1193743c8 | ||
|
|
109730eacd | ||
|
|
1f736afe86 | ||
|
|
4d554a6718 | ||
|
|
69c0c362e9 | ||
|
|
3bb446556a | ||
|
|
ea950d8cec | ||
|
|
a65f4da7a2 | ||
|
|
0bdc933c20 | ||
|
|
0c0f79c6db | ||
|
|
32f9b9d4ac | ||
|
|
53907a3719 | ||
|
|
4937aeee3f | ||
|
|
5e5b8aff89 | ||
|
|
a2cbbd82d0 | ||
|
|
7eac5d8ba8 | ||
|
|
e2b1ed55ae | ||
|
|
727c7102d3 | ||
|
|
1494ea6717 | ||
|
|
f1ce64dbd3 | ||
|
|
3bad5cd2bf | ||
|
|
7432c0073a | ||
|
|
f1813a7c94 | ||
|
|
9e45c0a4d1 | ||
|
|
2c652cdde7 | ||
|
|
7718d345c8 | ||
|
|
9f39708325 | ||
|
|
bb6dbfa920 | ||
|
|
ba265005bb | ||
|
|
4d7cc7ed61 | ||
|
|
b64f31eb0b | ||
|
|
38d159b69e | ||
|
|
d5455f3716 | ||
|
|
a72ceeba11 | ||
|
|
c6b7d332b2 | ||
|
|
f37278f2a6 | ||
|
|
3f3e03b83d | ||
|
|
c99d3eb3c3 | ||
|
|
08d5183e7e | ||
|
|
51769b2224 | ||
|
|
6ec0ed8d61 | ||
|
|
2e35324403 | ||
|
|
e9474649c4 | ||
|
|
a8e0ce50c8 | ||
|
|
db7ddba735 | ||
|
|
1999d94b33 | ||
|
|
44af123b6c | ||
|
|
547b700ba7 | ||
|
|
6b87d5d2b0 | ||
|
|
023894d45e | ||
|
|
009715c0da | ||
|
|
c2824027d4 | ||
|
|
65b6553a1a | ||
|
|
9d3b7adc8e | ||
|
|
3724fc204c | ||
|
|
b97451a915 | ||
|
|
9ddcac4c6c | ||
|
|
b61e3c347f | ||
|
|
0bb44066c0 | ||
|
|
305c4aaa07 | ||
|
|
42d627f3ba | ||
|
|
6dd2b464a3 | ||
|
|
32f24cf8f8 | ||
|
|
4a89e3ea86 | ||
|
|
887db5b281 | ||
|
|
fee5518a82 | ||
|
|
551128e64c | ||
|
|
c65ae8d18e | ||
|
|
c1f75d9ebd | ||
|
|
73a5ff6648 | ||
|
|
1c264f380e | ||
|
|
f02bfa0a1e | ||
|
|
9d684006fc | ||
|
|
c49f1ed028 | ||
|
|
d935b226c0 | ||
|
|
d9e20de8a5 | ||
|
|
23997f0f93 | ||
|
|
529272d11b | ||
|
|
1194c38568 | ||
|
|
f0d2ee2beb | ||
|
|
68cdda086a | ||
|
|
54ceca6ceb | ||
|
|
50bdf7460c | ||
|
|
c06e45d0bb | ||
|
|
3ed6e28a00 | ||
|
|
ab76098895 | ||
|
|
0a447e43b0 | ||
|
|
8df44f2768 | ||
|
|
a7ec64d644 | ||
|
|
868e104d85 | ||
|
|
7ced7f5764 | ||
|
|
12b39c6ba1 | ||
|
|
93df9d7693 | ||
|
|
3980f314fa | ||
|
|
c2538da1cd | ||
|
|
5ed943bca2 |
7
.github/workflows/build-debug.yml
vendored
7
.github/workflows/build-debug.yml
vendored
@@ -42,13 +42,6 @@ jobs:
|
||||
steps:
|
||||
- run: apt update && apt install git -y
|
||||
- uses: actions/checkout@v2
|
||||
# create unity activation file and store to artifacts.
|
||||
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -logFile -createManualActivationFile || exit 0
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Unity_v${{ matrix.unity }}.alf
|
||||
path: ./Unity_v${{ matrix.unity }}.alf
|
||||
# activate Unity from manual license file(ulf)
|
||||
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||
|
||||
50
.gitignore
vendored
50
.gitignore
vendored
@@ -205,3 +205,53 @@ 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
|
||||
|
||||
154
README.md
154
README.md
@@ -14,7 +14,8 @@ Provides an efficient allocation free async/await integration to Unity.
|
||||
* Highly compatible behaviour with Task/ValueTask/IValueTaskSource
|
||||
|
||||
Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ
|
||||
](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
|
||||
](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
|
||||
Advanced tips, see blog post: [Extends UnityWebRequest via async decorator pattern — Advanced Techniques of 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 -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
@@ -32,8 +33,13 @@ Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await f
|
||||
- [Awaitable Events](#awaitable-events)
|
||||
- [Channel](#channel)
|
||||
- [For Unit Testing](#for-unit-testing)
|
||||
- [ThreadPool limitation](#threadpool-limitation)
|
||||
- [IEnumerator.ToUniTask limitation](#ienumeratortounitask-limitation)
|
||||
- [For UnityEditor](#for-unityeditor)
|
||||
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
||||
- [Pooling Configuration](#pooling-configuration)
|
||||
- [Allocation on Profiler](#allocation-on-profiler)
|
||||
- [UniTaskSynchronizationContext](#unitasksynchronizationcontext)
|
||||
- [API References](#api-references)
|
||||
- [UPM Package](#upm-package)
|
||||
- [Install via git URL](#install-via-git-url)
|
||||
@@ -136,7 +142,7 @@ UniTask feature rely on C# 7.0([task-like custom async method builder feature](h
|
||||
|
||||
Why UniTask(custom task-like object) is required? Because Task is too heavy, not matched to Unity threading(single-thread). UniTask does not use thread and SynchronizationContext/ExecutionContext because almost Unity's asynchronous object is automaticaly dispatched by Unity's engine layer. It acquires more fast and more less allocation, completely integrated with Unity.
|
||||
|
||||
You can await `AsyncOperation`, `ResourceRequest`, `AssetBundleRequest`, `AssetBundleCreateRequest`, `UnityWebRequestAsyncOperation`, `IEnumerator` and others when `using Cysharp.Threading.Tasks;`.
|
||||
You can await `AsyncOperation`, `ResourceRequest`, `AssetBundleRequest`, `AssetBundleCreateRequest`, `UnityWebRequestAsyncOperation`, `AsyncGPUReadbackRequest`, `IEnumerator` and others when `using Cysharp.Threading.Tasks;`.
|
||||
|
||||
UniTask provides three pattern of extension methods.
|
||||
|
||||
@@ -150,25 +156,24 @@ UniTask provides three pattern of extension methods.
|
||||
|
||||
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. Details of timing, see: [PlayerLoop](#playerloop) section.
|
||||
|
||||
> Note: AssetBundleRequest has `asset` and `allAssets`, in default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
|
||||
|
||||
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
|
||||
|
||||
```csharp
|
||||
public class SceneAssets
|
||||
public async UniTaskVoid LoadManyAsync()
|
||||
{
|
||||
public SceneAssets()
|
||||
{
|
||||
// parallel load.
|
||||
var (a, b, c) = await UniTask.WhenAll(
|
||||
LoadAsSprite("foo"),
|
||||
LoadAsSprite("bar"),
|
||||
LoadAsSprite("baz"));
|
||||
}
|
||||
// parallel load.
|
||||
var (a, b, c) = await UniTask.WhenAll(
|
||||
LoadAsSprite("foo"),
|
||||
LoadAsSprite("bar"),
|
||||
LoadAsSprite("baz"));
|
||||
}
|
||||
|
||||
async UniTask<Sprite> LoadAsSprite(string path)
|
||||
{
|
||||
var resource = await Resources.LoadAsync<Sprite>(path);
|
||||
return (resource as Sprite);
|
||||
}
|
||||
async UniTask<Sprite> LoadAsSprite(string path)
|
||||
{
|
||||
var resource = await Resources.LoadAsync<Sprite>(path);
|
||||
return (resource as Sprite);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -208,7 +213,7 @@ await task;
|
||||
await task; // NG, throws Exception
|
||||
```
|
||||
|
||||
Store to the class field, you can use `UniTask.Lazy` that gurantee call multipletimes. `.Prevent()` allows for multiple calls (internally cached results). This is useful when multiple calls in a function scope.
|
||||
Store to the class field, you can use `UniTask.Lazy` that gurantee call multipletimes. `.Preserve()` allows for multiple calls (internally cached results). This is useful when multiple calls in a function scope.
|
||||
|
||||
Cancellation and Exception handling
|
||||
---
|
||||
@@ -384,9 +389,19 @@ var playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
|
||||
PlayerLoopHelper.Initialize(ref playerLoop);
|
||||
```
|
||||
|
||||
You can diagnostic UniTask's player loop is ready by `PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()`. And also `PlayerLoopHelper.DumpCurrentPlayerLoop` shows current all playerloop to console.
|
||||
|
||||
```csharp
|
||||
void Start()
|
||||
{
|
||||
UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
||||
PlayerLoopHelper.DumpCurrentPlayerLoop();
|
||||
}
|
||||
```
|
||||
|
||||
async void vs async UniTaskVoid
|
||||
---
|
||||
`async void` is a standard C# taks system so does not run on UniTask systems. It is better not to use. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and report error immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require to await it(fire and forget), use `UniTaskVoid` is better. Unfortunately to dismiss warning, require to using with `Forget()`.
|
||||
`async void` is a standard C# task system so does not run on UniTask systems. It is better not to use. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and report error immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require to await it(fire and forget), use `UniTaskVoid` is better. Unfortunately to dismiss warning, require to using with `Forget()`.
|
||||
|
||||
```csharp
|
||||
public async UniTaskVoid FireAndForgetMethod()
|
||||
@@ -431,6 +446,18 @@ actEvent += UniTask.Action(async () => { await UniTask.Yield(); });
|
||||
unityEvent += UniTask.UnityAction(async () => { await UniTask.Yield(); });
|
||||
```
|
||||
|
||||
`UniTaskVoid` can also use in MonoBehaviour's `Start` method.
|
||||
|
||||
```csharp
|
||||
class Sample : MonoBehaviour
|
||||
{
|
||||
async UniTaskVoid Start()
|
||||
{
|
||||
// async init code.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
UniTaskTracker
|
||||
---
|
||||
useful for check(leak) UniTasks. You can open tracker window in `Window -> UniTask Tracker`.
|
||||
@@ -447,9 +474,11 @@ For debug use, enable tracking and capture stacktrace is useful but it it declin
|
||||
|
||||
External Assets
|
||||
---
|
||||
In default, UniTask supports DOTween and Addressables(`AsyncOperationHandle` and `AsyncOpereationHandle<T>` as awaitable).
|
||||
In default, UniTask supports TextMeshPro(`BindTo(TMP_Text)` and `TMP_InputField` event extensions like standard uGUI `InputField`), DOTween(`Tween` as awaitable) and Addressables(`AsyncOperationHandle` and `AsyncOpereationHandle<T>` as awaitable).
|
||||
|
||||
For DOTween support, require to `com.demigiant.dotween` import from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or define `UNITASK_DOTWEEN_SUPPORT` to enable it.
|
||||
There are defined in separated asmdef like `UniTask.TextMeshPro`, `UniTask.DOTween`, `UniTask.Addressables`.
|
||||
|
||||
TextMeshPro and Addressables support are automatically enabled when import there package from package manager. However DOTween support, require to `com.demigiant.dotween` import from [OpenUPM](https://openupm.com/packages/com.demigiant.dotween/) or define `UNITASK_DOTWEEN_SUPPORT` to enable it.
|
||||
|
||||
```csharp
|
||||
// sequential
|
||||
@@ -464,6 +493,8 @@ await UniTask.WhenAll(
|
||||
transform.DOScale(10, 3).WithCancellation(ct));
|
||||
```
|
||||
|
||||
DOTween support's default behaviour(`await`, `WithCancellation`, `ToUniTask`) awaits tween is killed. It works both Complete(true/false) and Kill(true/false). But if you want to tween reuse(`SetAutoKill(false)`), it does not work you expected. Or, if you want to await for another timing, the following extension methods exist in Tween, `AwaitForComplete`, `AwaitForPause`, `AwaitForPlay`, `AwaitForRewind`, `AwaitForStepComplete`.
|
||||
|
||||
AsyncEnumerable and Async LINQ
|
||||
---
|
||||
Unity 2020.2.0a12 supports C# 8.0 so you can use `await foreach`. This is the new Update notation in async era.
|
||||
@@ -506,7 +537,7 @@ Async LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAs
|
||||
|
||||
It's closer to UniRx (Reactive Extensions), but UniTaskAsyncEnumerable is a pull-based asynchronous stream, whereas Rx was a push-based asynchronous stream. Note that although similar, the characteristics are different and the details behave differently along with them.
|
||||
|
||||
`UniTaskAsyncEnumerable` is the entry point like `Enumerbale`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
|
||||
`UniTaskAsyncEnumerable` is the entry point like `Enumerbale`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntil`, `TakeUntil`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
|
||||
|
||||
The method with Func as an argument has three additional overloads, `***Await`, `***AwaitWithCancellation`.
|
||||
|
||||
@@ -518,6 +549,38 @@ SelectAwaitWithCancellation(Func<T, CancellationToken, UniTask<TR>> selector)
|
||||
|
||||
If you want to use the `async` method inside the func, use the `***Await` or `***AwaitWithCancellation`.
|
||||
|
||||
How to create async iterator, C# 8.0 supports async iterator(`async yield return`) but it only allows `IAsyncEnumerable<T>` and of course requires C# 8.0. UniTask supports `UniTaskAsyncEnumerable.Create` method to create custom async iterator.
|
||||
|
||||
```csharp
|
||||
// IAsyncEnumerable, C# 8.0 version of async iterator. ( do not use this style, IAsyncEnumerable is not controled in UniTask).
|
||||
public async IAsyncEnumerable<int> MyEveryUpdate([EnumeratorCancellation]CancellationToken cancelationToken = default)
|
||||
{
|
||||
var frameCount = 0;
|
||||
await UniTask.Yield();
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
yield return frameCount++;
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
// UniTaskAsyncEnumerable.Create and use `await writer.YieldAsync` instead of `yield return`.
|
||||
public IUniTaskAsyncEnumerable<int> MyEveryUpdate()
|
||||
{
|
||||
// writer(IAsyncWriter<T>) has `YieldAsync(value)` method.
|
||||
return UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
var frameCount = 0;
|
||||
await UniTask.Yield();
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await writer.YieldAsync(frameCount++); // instead of `yield return`
|
||||
await UniTask.Yield();
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Awaitable Events
|
||||
---
|
||||
All uGUI component implements `***AsAsyncEnumerable` to convert asynchronous streams of events.
|
||||
@@ -721,6 +784,26 @@ public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
|
||||
|
||||
UniTask itself's unit test is written by Unity Test Runner and [Cysharp/RuntimeUnitTestToolkit](https://github.com/Cysharp/RuntimeUnitTestToolkit) to check on CI and IL2CPP working.
|
||||
|
||||
ThreadPool limitation
|
||||
---
|
||||
Most UniTask methods run in a single thread (PlayerLoop), but only `UniTask.Run` and `UniTask.SwitchToThreadPool` run on a thread pool. If you use a thread pool, it won't work with WebGL and so on.
|
||||
|
||||
`UniTask.Run` will be deprecated in the future (marked with an Obsolete) and only `RunOnThreadPool` will be used. Also, if you use `UniTask.Run`, consider whether you can use `UniTask.Create` or `UniTask.Void`.
|
||||
|
||||
IEnumerator.ToUniTask limitation
|
||||
---
|
||||
You can convert coroutine(IEnumerator) to UniTask(or await directly) but has some limitations.
|
||||
|
||||
* `WaitForEndOfFrame`/`WaitForFixedUpdate` is not supported, used `yield return null` instead.
|
||||
* Consuming loop timing is not same as StartCoroutine, it is used specified PlayerLoopTiming, and default's `PlayerLoopTiming.Update` is run before MonoBehaviour's Update and StartCoroutine's loop.
|
||||
|
||||
For UnityEditor
|
||||
---
|
||||
UniTask can run on Unity Edtitor like Editor Coroutine. However, there are some limitations.
|
||||
|
||||
* Delay, DelayFrame is not work correctly because can not get deltaTime in editor. Return the result of the await immediately; you can use `DelayType.Realtime` to wait for the right time.
|
||||
* All PlayerLoopTiming run on timing, `EditorApplication.update`.
|
||||
|
||||
Compare with Standard Task API
|
||||
---
|
||||
UniTask has many standard Task-like APIs. This table shows what is the alternative apis.
|
||||
@@ -778,7 +861,32 @@ foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
||||
}
|
||||
```
|
||||
|
||||
> In UnityEditor profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generate AsyncStateMachine as class on Debug build and as struct on Release build.
|
||||
Allocation on Profiler
|
||||
---
|
||||
In UnityEditor profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generate AsyncStateMachine as class on Debug build and as struct on Release build.
|
||||
|
||||
After Unity 2020.1 supports Code Optimization option on UnityEditor(right, footer).
|
||||
|
||||

|
||||
|
||||
You can change C# compiler optimization to release, it removes AsyncStateMachine allocation. Andalso optimization option can set via `Compilation.CompilationPipeline-codeOptimization`, and `Compilation.CodeOptimization`.
|
||||
|
||||
UniTaskSynchronizationContext
|
||||
---
|
||||
Unity's default SynchronizationContext(`UnitySynchronizationContext`) is poor implementation for performance. UniTask itself is bypass `SynchronizationContext`(and `ExecutionContext`) so does not use it but if exists in `async Task`, still used it. `UniTaskSynchronizationContext` is replacement of `UnitySynchronizationContext`, it is better for performance.
|
||||
|
||||
```csharp
|
||||
public class SyncContextInjecter
|
||||
{
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void Inject()
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new UniTaskSynchronizationContext());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is an optional choice and is not always recommended; `UniTaskSynchronizationContext` is less performance than `async UniTask` and is not a complete UniTask replacement. It also does not guarantee full behavioral compatibility with the `UnitySynchronizationContext`.
|
||||
|
||||
API References
|
||||
---
|
||||
@@ -798,7 +906,7 @@ After Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of gi
|
||||
|
||||
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"` to `Packages/manifest.json`.
|
||||
|
||||
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.19`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.19`.
|
||||
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.34`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.34`.
|
||||
|
||||
### Install via OpenUPM
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||
{
|
||||
static TaskPool<ThreadPoolWorkItem> pool;
|
||||
public ThreadPoolWorkItem NextNode { get; set; }
|
||||
ThreadPoolWorkItem nextNode;
|
||||
public ref ThreadPoolWorkItem NextNode => ref nextNode;
|
||||
|
||||
static ThreadPoolWorkItem()
|
||||
{
|
||||
|
||||
@@ -36,7 +36,9 @@
|
||||
..\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\PlayerLoopHelper.cs;
|
||||
@@ -44,9 +46,7 @@
|
||||
..\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.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
|
||||
" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
#pragma warning disable CS1998
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
using System.Linq;
|
||||
using System;
|
||||
@@ -56,6 +58,24 @@ namespace NetCoreSandbox
|
||||
|
||||
}
|
||||
|
||||
class Foo
|
||||
{
|
||||
public async UniTask MethodFooAsync()
|
||||
{
|
||||
await MethodBarAsync();
|
||||
}
|
||||
|
||||
private async UniTask MethodBarAsync()
|
||||
|
||||
{
|
||||
Throw();
|
||||
}
|
||||
|
||||
private void Throw()
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
@@ -275,53 +295,25 @@ namespace NetCoreSandbox
|
||||
//await new ComparisonBenchmarks().ViaUniTaskT();
|
||||
return;
|
||||
#endif
|
||||
// await new AllocationCheck().ViaUniTaskVoid();
|
||||
|
||||
// AsyncTest().Forge
|
||||
|
||||
Console.WriteLine("A?");
|
||||
var a = await new ZeroAllocAsyncAwaitInDotNetCore().NanikaAsync(1, 2);
|
||||
Console.WriteLine("RET:" + a);
|
||||
await WhereSelect();
|
||||
|
||||
SynchronizationContext.SetSynchronizationContext(new MySyncContext());
|
||||
|
||||
await Aaa();
|
||||
|
||||
|
||||
|
||||
|
||||
//AsyncTest().Forget();
|
||||
|
||||
// AsyncTest().Forget();
|
||||
|
||||
ThreadPool.SetMinThreads(100, 100);
|
||||
|
||||
//List<UniTask<int>> list = new List<UniTask<int>>();
|
||||
for (int i = 0; i < short.MaxValue; i++)
|
||||
var e = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
//// list.Add(AsyncTest());
|
||||
await YieldCore();
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Console.WriteLine($"Start {i}");
|
||||
await writer.YieldAsync(i);
|
||||
Console.WriteLine($"End {i}");
|
||||
}
|
||||
});
|
||||
|
||||
var ee = e.GetAsyncEnumerator();
|
||||
while (await ee.MoveNextAsync())
|
||||
{
|
||||
Console.WriteLine("ForEach " + ee.Current);
|
||||
}
|
||||
//await UniTask.WhenAll(list);
|
||||
|
||||
//Console.WriteLine("TOGO");
|
||||
|
||||
//var a = await AsyncTest();
|
||||
//var b = AsyncTest();
|
||||
//var c = AsyncTest();
|
||||
await YieldCore();
|
||||
|
||||
//await b;
|
||||
//await c;
|
||||
|
||||
|
||||
//foreach (var item in Cysharp.Threading.Tasks.Internal.TaskPool.GetCacheSizeInfo())
|
||||
//{
|
||||
// Console.WriteLine(item);
|
||||
//}
|
||||
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
static async UniTask YieldCore()
|
||||
|
||||
@@ -10,11 +10,14 @@ public class QueueCheck
|
||||
{
|
||||
Node node1 = new Node();
|
||||
Node node2 = new Node();
|
||||
RefNode refNode1 = new RefNode();
|
||||
RefNode refNode2 = new RefNode();
|
||||
Queue<Node> q1 = new Queue<Node>();
|
||||
Stack<Node> s1 = new Stack<Node>();
|
||||
ConcurrentQueue<Node> cq = new ConcurrentQueue<Node>();
|
||||
ConcurrentStack<Node> cs = new ConcurrentStack<Node>();
|
||||
static TaskPool<Node> pool;
|
||||
static TaskPoolRefNode<RefNode> poolRefNode;
|
||||
static TaskPoolEqualNull<Node> poolEqualNull;
|
||||
static TaskPoolClass<Node> poolClass = new TaskPoolClass<Node>();
|
||||
static TaskPoolWithoutSize<Node> poolWithoutSize;
|
||||
@@ -82,6 +85,14 @@ public class QueueCheck
|
||||
pool.TryPop(out _);
|
||||
pool.TryPop(out _);
|
||||
}
|
||||
[Benchmark]
|
||||
public void TaskPoolRefNode()
|
||||
{
|
||||
poolRefNode.TryPush(refNode1);
|
||||
poolRefNode.TryPush(refNode2);
|
||||
poolRefNode.TryPop(out _);
|
||||
poolRefNode.TryPop(out _);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void TaskPoolEqualNull()
|
||||
@@ -130,6 +141,18 @@ public interface ITaskPoolNode<T>
|
||||
T NextNode { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RefNode :ITaskPoolRefNode<RefNode>
|
||||
{
|
||||
RefNode nextNode;
|
||||
public ref RefNode NextNode => ref nextNode;
|
||||
}
|
||||
|
||||
public interface ITaskPoolRefNode<T>
|
||||
{
|
||||
ref T NextNode { get; }
|
||||
}
|
||||
|
||||
|
||||
// mutable struct, don't mark readonly.
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolWithoutLock<T>
|
||||
@@ -237,6 +260,60 @@ public struct TaskPool<T>
|
||||
return false;
|
||||
}
|
||||
}
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolRefNode<T>
|
||||
where T : class, ITaskPoolRefNode<T>
|
||||
{
|
||||
int gate;
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
ref var nextNode = ref v.NextNode;
|
||||
root = nextNode;
|
||||
nextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
//if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
{
|
||||
// Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPoolEqualNull<T>
|
||||
|
||||
170
src/UniTask.NetCoreTests/Linq/CreateTest.cs
Normal file
170
src/UniTask.NetCoreTests/Linq/CreateTest.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
#pragma warning disable CS1998
|
||||
#pragma warning disable CS0162
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests.Linq
|
||||
{
|
||||
public class CreateTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task SyncCreation()
|
||||
{
|
||||
var from = 10;
|
||||
var count = 100;
|
||||
|
||||
var xs = await UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
await writer.YieldAsync(from + i);
|
||||
}
|
||||
}).ToArrayAsync();
|
||||
|
||||
var ys = await Range(from, count).AsUniTaskAsyncEnumerable().ToArrayAsync();
|
||||
|
||||
xs.Should().BeEquivalentTo(ys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncManually()
|
||||
{
|
||||
var list = new List<int>();
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
list.Add(100);
|
||||
await writer.YieldAsync(10);
|
||||
|
||||
list.Add(200);
|
||||
await writer.YieldAsync(20);
|
||||
|
||||
list.Add(300);
|
||||
await writer.YieldAsync(30);
|
||||
|
||||
list.Add(400);
|
||||
});
|
||||
|
||||
list.Should().BeEmpty();
|
||||
var e = xs.GetAsyncEnumerator();
|
||||
|
||||
list.Should().BeEmpty();
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100);
|
||||
e.Current.Should().Be(10);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200);
|
||||
e.Current.Should().Be(20);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200, 300);
|
||||
e.Current.Should().Be(30);
|
||||
|
||||
(await e.MoveNextAsync()).Should().BeFalse();
|
||||
list.Should().BeEquivalentTo(100, 200, 300, 400);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncExceptionFirst()
|
||||
{
|
||||
var from = 10;
|
||||
var count = 100;
|
||||
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
throw new UniTaskTestException();
|
||||
await writer.YieldAsync(from + i);
|
||||
}
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs.ToArrayAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncException()
|
||||
{
|
||||
var from = 10;
|
||||
var count = 100;
|
||||
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
await writer.YieldAsync(from + i);
|
||||
|
||||
if (i == 15)
|
||||
{
|
||||
throw new UniTaskTestException();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<UniTaskTestException>(async () => await xs.ToArrayAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ASyncManually()
|
||||
{
|
||||
var list = new List<int>();
|
||||
var xs = UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
await UniTask.Yield();
|
||||
|
||||
list.Add(100);
|
||||
await writer.YieldAsync(10);
|
||||
|
||||
await UniTask.Yield();
|
||||
|
||||
list.Add(200);
|
||||
await writer.YieldAsync(20);
|
||||
|
||||
await UniTask.Yield();
|
||||
list.Add(300);
|
||||
await UniTask.Yield();
|
||||
await writer.YieldAsync(30);
|
||||
|
||||
await UniTask.Yield();
|
||||
|
||||
list.Add(400);
|
||||
});
|
||||
|
||||
list.Should().BeEmpty();
|
||||
var e = xs.GetAsyncEnumerator();
|
||||
|
||||
list.Should().BeEmpty();
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100);
|
||||
e.Current.Should().Be(10);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200);
|
||||
e.Current.Should().Be(20);
|
||||
|
||||
await e.MoveNextAsync();
|
||||
list.Should().BeEquivalentTo(100, 200, 300);
|
||||
e.Current.Should().Be(30);
|
||||
|
||||
(await e.MoveNextAsync()).Should().BeFalse();
|
||||
list.Should().BeEquivalentTo(100, 200, 300, 400);
|
||||
}
|
||||
|
||||
async IAsyncEnumerable<int> Range(int from, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return from + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ namespace NetCoreTests.Linq
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeUntil()
|
||||
public async Task TakeUntilCanceled()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace NetCoreTests.Linq
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SkipUntil()
|
||||
public async Task SkipUntilCanceled()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace NetCoreTests.Linq
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 30, 40 });
|
||||
foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
@@ -102,5 +102,64 @@ namespace NetCoreTests.Linq
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TakeUntil()
|
||||
{
|
||||
var cts = new AsyncReactiveProperty<int>(0);
|
||||
|
||||
var rp = new AsyncReactiveProperty<int>(1);
|
||||
|
||||
var xs = rp.TakeUntil(cts.WaitAsync()).ToArrayAsync();
|
||||
|
||||
var c = CancelAsync();
|
||||
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 1, 10, 20 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
rp.Value = 10;
|
||||
await Task.Yield();
|
||||
rp.Value = 20;
|
||||
await Task.Yield();
|
||||
cts.Value = 9999;
|
||||
rp.Value = 30;
|
||||
await Task.Yield();
|
||||
rp.Value = 40;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SkipUntil()
|
||||
{
|
||||
var cts = new AsyncReactiveProperty<int>(0);
|
||||
|
||||
var rp = new AsyncReactiveProperty<int>(1);
|
||||
|
||||
var xs = rp.SkipUntil(cts.WaitAsync()).ToArrayAsync();
|
||||
|
||||
var c = CancelAsync();
|
||||
|
||||
await c;
|
||||
var foo = await xs;
|
||||
|
||||
foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
|
||||
|
||||
async Task CancelAsync()
|
||||
{
|
||||
rp.Value = 10;
|
||||
await Task.Yield();
|
||||
rp.Value = 20;
|
||||
await Task.Yield();
|
||||
cts.Value = 9999;
|
||||
rp.Value = 30;
|
||||
await Task.Yield();
|
||||
rp.Value = 40;
|
||||
|
||||
rp.Dispose(); // complete.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
src/UniTask.NetCoreTests/WithCancellationTest.cs
Normal file
40
src/UniTask.NetCoreTests/WithCancellationTest.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class WithCancellationTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Standard()
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
var v = await UniTask.Run(() => 10).WithCancellation(cts.Token);
|
||||
|
||||
v.Should().Be(10);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Cancel()
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
var t = UniTask.Create(async () =>
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
return 10;
|
||||
}).WithCancellation(cts.Token);
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await t)).CancellationToken.Should().Be(cts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
|
||||
@@ -87,7 +87,8 @@ namespace Cysharp.Threading.Tasks
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
static TaskPool<WaitAsyncSource> pool;
|
||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
||||
WaitAsyncSource nextNode;
|
||||
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
||||
|
||||
static WaitAsyncSource()
|
||||
{
|
||||
@@ -404,7 +405,8 @@ namespace Cysharp.Threading.Tasks
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
static TaskPool<WaitAsyncSource> pool;
|
||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
||||
WaitAsyncSource nextNode;
|
||||
ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;
|
||||
|
||||
static WaitAsyncSource()
|
||||
{
|
||||
|
||||
@@ -11,6 +11,55 @@ namespace Cysharp.Threading.Tasks
|
||||
static readonly Action<object> cancellationTokenCallback = Callback;
|
||||
static readonly Action<object> disposeCallback = DisposeCallback;
|
||||
|
||||
public static CancellationToken ToCancellationToken(this UniTask task)
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
ToCancellationTokenCore(task, cts).Forget();
|
||||
return cts.Token;
|
||||
}
|
||||
|
||||
public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
|
||||
{
|
||||
if (linkToken.IsCancellationRequested)
|
||||
{
|
||||
return linkToken;
|
||||
}
|
||||
|
||||
if (!linkToken.CanBeCanceled)
|
||||
{
|
||||
return ToCancellationToken(task);
|
||||
}
|
||||
|
||||
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken);
|
||||
ToCancellationTokenCore(task, cts).Forget();
|
||||
|
||||
return cts.Token;
|
||||
}
|
||||
|
||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
|
||||
{
|
||||
return ToCancellationToken(task.AsUniTask());
|
||||
}
|
||||
|
||||
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
|
||||
{
|
||||
return ToCancellationToken(task.AsUniTask(), linkToken);
|
||||
}
|
||||
|
||||
static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
cts.Cancel();
|
||||
cts.Dispose();
|
||||
}
|
||||
|
||||
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
|
||||
@@ -9,15 +9,15 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class CancellationTokenSourceExtensions
|
||||
{
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
{
|
||||
var delay = UniTask.Delay(millisecondsDelay, ignoreTimeScale, delayTiming, cts.Token);
|
||||
var delay = UniTask.Delay(millisecondsDelay, delayType, delayTiming, cts.Token);
|
||||
CancelAfterCore(cts, delay).Forget();
|
||||
}
|
||||
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
{
|
||||
var delay = UniTask.Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cts.Token);
|
||||
var delay = UniTask.Delay(delayTimeSpan, delayType, delayTiming, cts.Token);
|
||||
CancelAfterCore(cts, delay).Forget();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
@@ -8,6 +8,10 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
// #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
|
||||
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
|
||||
// but currently it is labeled `Won't Fix`.
|
||||
|
||||
internal interface IStateMachineRunner
|
||||
{
|
||||
Action MoveNext { get; }
|
||||
@@ -83,7 +87,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
||||
}
|
||||
|
||||
public AsyncUniTaskVoid<TStateMachine> NextNode { get; set; }
|
||||
AsyncUniTaskVoid<TStateMachine> nextNode;
|
||||
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
|
||||
|
||||
public void Return()
|
||||
{
|
||||
@@ -153,7 +158,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public AsyncUniTask<TStateMachine> NextNode { get; set; }
|
||||
AsyncUniTask<TStateMachine> nextNode;
|
||||
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
|
||||
|
||||
static AsyncUniTask()
|
||||
{
|
||||
@@ -275,7 +281,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
||||
AsyncUniTask<TStateMachine, T> nextNode;
|
||||
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
|
||||
|
||||
static AsyncUniTask()
|
||||
{
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
||||
{
|
||||
static TaskPool<EnumeratorPromise> pool;
|
||||
public EnumeratorPromise NextNode { get; set; }
|
||||
EnumeratorPromise nextNode;
|
||||
public ref EnumeratorPromise NextNode => ref nextNode;
|
||||
|
||||
static EnumeratorPromise()
|
||||
{
|
||||
@@ -44,6 +45,9 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
IEnumerator innerEnumerator;
|
||||
CancellationToken cancellationToken;
|
||||
int initialFrame;
|
||||
bool loopRunning;
|
||||
bool calledGetResult;
|
||||
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
|
||||
@@ -66,10 +70,15 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.loopRunning = true;
|
||||
result.calledGetResult = false;
|
||||
result.initialFrame = -1;
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
|
||||
result.MoveNext(); // run immediately.
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -77,11 +86,15 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
calledGetResult = true;
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
if (!loopRunning)
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +115,38 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (calledGetResult)
|
||||
{
|
||||
loopRunning = false;
|
||||
TryReturn();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (innerEnumerator == null) // invalid status, returned but loop running?
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
loopRunning = false;
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (initialFrame == -1)
|
||||
{
|
||||
// Time can not touch in threadpool.
|
||||
if (PlayerLoopHelper.IsMainThread)
|
||||
{
|
||||
initialFrame = Time.frameCount;
|
||||
}
|
||||
}
|
||||
else if (initialFrame == Time.frameCount)
|
||||
{
|
||||
return true; // already executed in first frame, skip.
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (innerEnumerator.MoveNext())
|
||||
@@ -117,10 +156,12 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
loopRunning = false;
|
||||
core.TrySetException(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
loopRunning = false;
|
||||
core.TrySetResult(null);
|
||||
return false;
|
||||
}
|
||||
@@ -145,11 +186,10 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
else if (current is CustomYieldInstruction)
|
||||
else if (current is CustomYieldInstruction cyi)
|
||||
{
|
||||
// WWW, WaitForSecondsRealtime
|
||||
var e2 = UnwrapWaitCustomYieldInstruction((CustomYieldInstruction)current);
|
||||
while (e2.MoveNext())
|
||||
while (cyi.keepWaiting)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
@@ -194,26 +234,17 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
// WWW and others as CustomYieldInstruction.
|
||||
static IEnumerator UnwrapWaitCustomYieldInstruction(CustomYieldInstruction yieldInstruction)
|
||||
{
|
||||
while (yieldInstruction.keepWaiting)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly FieldInfo waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic);
|
||||
|
||||
static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
|
||||
{
|
||||
var second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
|
||||
var startTime = DateTimeOffset.UtcNow;
|
||||
var elapsed = 0.0f;
|
||||
while (true)
|
||||
{
|
||||
yield return null;
|
||||
|
||||
var elapsed = (DateTimeOffset.UtcNow - startTime).TotalSeconds;
|
||||
elapsed += Time.deltaTime;
|
||||
if (elapsed >= second)
|
||||
{
|
||||
break;
|
||||
|
||||
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables.meta
vendored
Normal file
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5b9231662e24c942b544bd85d4b39cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,24 +11,39 @@ using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class AddressableAsyncExtensions
|
||||
public static class AddressablesAsyncExtensions
|
||||
{
|
||||
#region AsyncOperationHandle
|
||||
#region AsyncOperationHandle
|
||||
|
||||
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||
{
|
||||
return new AsyncOperationHandleAwaiter(handle);
|
||||
return ToUniTask(handle).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
||||
{
|
||||
if (handle.IsDone) return UniTask.CompletedTask;
|
||||
return new UniTask(AsyncOperationHandleWithCancellationSource.Create(handle, cancellationToken, out var token), token);
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (handle.IsDone) return UniTask.CompletedTask;
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
// autoReleaseHandle:true handle is invalid(immediately internal handle == null) so return completed.
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
return UniTask.FromException(handle.OperationException);
|
||||
}
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
return new UniTask(AsyncOperationHandleConfiguredSource.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
@@ -77,29 +92,31 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource>
|
||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleWithCancellationSource> pool;
|
||||
public AsyncOperationHandleWithCancellationSource NextNode { get; set; }
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||
AsyncOperationHandleConfiguredSource nextNode;
|
||||
public ref AsyncOperationHandleConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncOperationHandleWithCancellationSource()
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource), () => pool.Size);
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperationHandle> continuationAction;
|
||||
AsyncOperationHandle handle;
|
||||
CancellationToken cancellationToken;
|
||||
IProgress<float> progress;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncOperationHandleWithCancellationSource()
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -108,16 +125,17 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleWithCancellationSource();
|
||||
result = new AsyncOperationHandleConfiguredSource();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
handle.Completed += result.continuationAction;
|
||||
|
||||
@@ -136,7 +154,11 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
@@ -182,125 +204,18 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperationHandle handle;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleConfiguredSource();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
if (progress != null && handle.IsValid())
|
||||
{
|
||||
progress.Report(handle.PercentComplete);
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
core.Reset();
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
@@ -308,96 +223,66 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region AsyncOperationHandle_T
|
||||
#region AsyncOperationHandle_T
|
||||
|
||||
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||
{
|
||||
return new AsyncOperationHandleAwaiter<T>(handle);
|
||||
return ToUniTask(handle).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
||||
{
|
||||
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||
return new UniTask<T>(AsyncOperationHandleWithCancellationSource<T>.Create(handle, cancellationToken, out var token), token);
|
||||
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
||||
|
||||
if (!handle.IsValid())
|
||||
{
|
||||
throw new Exception("Attempting to use an invalid operation handle");
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
return UniTask.FromException<T>(handle.OperationException);
|
||||
}
|
||||
return UniTask.FromResult(handle.Result);
|
||||
}
|
||||
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||
{
|
||||
AsyncOperationHandle<T> handle;
|
||||
Action<AsyncOperationHandle> continuationAction;
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||
AsyncOperationHandleConfiguredSource<T> nextNode;
|
||||
public ref AsyncOperationHandleConfiguredSource<T> NextNode => ref nextNode;
|
||||
|
||||
public AsyncOperationHandleAwaiter(AsyncOperationHandle<T> handle)
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
this.handle = handle;
|
||||
this.continuationAction = null;
|
||||
}
|
||||
|
||||
public bool IsCompleted => handle.IsDone;
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
if (continuationAction != null)
|
||||
{
|
||||
handle.CompletedTypeless -= continuationAction;
|
||||
continuationAction = null;
|
||||
}
|
||||
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
var e = handle.OperationException;
|
||||
handle = default;
|
||||
ExceptionDispatchInfo.Capture(e).Throw();
|
||||
}
|
||||
|
||||
var result = handle.Result;
|
||||
handle = default;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
UnsafeOnCompleted(continuation);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
||||
handle.CompletedTypeless += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleWithCancellationSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource<T>>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleWithCancellationSource<T>> pool;
|
||||
public AsyncOperationHandleWithCancellationSource<T> NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource<T>), () => pool.Size);
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperationHandle<T>> continuationAction;
|
||||
AsyncOperationHandle<T> handle;
|
||||
CancellationToken cancellationToken;
|
||||
IProgress<float> progress;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncOperationHandleWithCancellationSource()
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -406,16 +291,17 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleWithCancellationSource<T>();
|
||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
result.progress = progress;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
handle.Completed += result.continuationAction;
|
||||
|
||||
@@ -423,7 +309,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return result;
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperationHandle<T> _)
|
||||
void Continuation(AsyncOperationHandle<T> argHandle)
|
||||
{
|
||||
handle.Completed -= continuationAction;
|
||||
|
||||
@@ -434,13 +320,17 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else if (argHandle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(argHandle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(handle.Result);
|
||||
core.TrySetResult(argHandle.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -485,122 +375,11 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||
{
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperationHandle<T> handle;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
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
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
if (progress != null && handle.IsValid())
|
||||
{
|
||||
progress.Report(handle.PercentComplete);
|
||||
}
|
||||
|
||||
if (handle.IsDone)
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Failed)
|
||||
{
|
||||
core.TrySetException(handle.OperationException);
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(handle.Result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -615,7 +394,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables/UniTask.Addressables.asmdef
vendored
Normal file
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/Addressables/UniTask.Addressables.asmdef
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "UniTask.Addressables",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"Unity.ResourceManager"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "",
|
||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 593a5b492d29ac6448b1ebf7f035ef33
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween.meta
vendored
Normal file
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25cb2f742bfeb1d48a4e65d3140b955d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,7 +11,6 @@ using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
// The idea of TweenCancelBehaviour is borrowed from https://www.shibuya24.info/entry/dotween_async_await
|
||||
public enum TweenCancelBehaviour
|
||||
{
|
||||
Kill,
|
||||
@@ -29,6 +28,16 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public static class DOTweenAsyncExtensions
|
||||
{
|
||||
enum CallbackType
|
||||
{
|
||||
Kill,
|
||||
Complete,
|
||||
Pause,
|
||||
Play,
|
||||
Rewind,
|
||||
StepComplete
|
||||
}
|
||||
|
||||
public static TweenAwaiter GetAwaiter(this Tween tween)
|
||||
{
|
||||
return new TweenAwaiter(tween);
|
||||
@@ -39,7 +48,7 @@ namespace Cysharp.Threading.Tasks
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, out var token), token);
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, TweenCancelBehaviour.Kill, cancellationToken, CallbackType.Kill, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
@@ -47,7 +56,47 @@ namespace Cysharp.Threading.Tasks
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, out var token), token);
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Kill, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Complete, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForPause(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Pause, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForPlay(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Play, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForRewind(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.Rewind, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask AwaitForStepComplete(this Tween tween, TweenCancelBehaviour tweenCancelBehaviour = TweenCancelBehaviour.Kill, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
if (!tween.IsActive()) return UniTask.CompletedTask;
|
||||
return new UniTask(TweenConfiguredSource.Create(tween, tweenCancelBehaviour, cancellationToken, CallbackType.StepComplete, out var token), token);
|
||||
}
|
||||
|
||||
public struct TweenAwaiter : ICriticalNotifyCompletion
|
||||
@@ -86,7 +135,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
||||
{
|
||||
static TaskPool<TweenConfiguredSource> pool;
|
||||
public TweenConfiguredSource NextNode { get; set; }
|
||||
TweenConfiguredSource nextNode;
|
||||
public ref TweenConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static TweenConfiguredSource()
|
||||
{
|
||||
@@ -95,12 +145,13 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||
|
||||
readonly TweenCallback onKillDelegate;
|
||||
readonly TweenCallback onCompleteCallbackDelegate;
|
||||
readonly TweenCallback onUpdateDelegate;
|
||||
|
||||
Tween tween;
|
||||
TweenCancelBehaviour cancelBehaviour;
|
||||
CancellationToken cancellationToken;
|
||||
CallbackType callbackType;
|
||||
bool canceled;
|
||||
|
||||
TweenCallback originalUpdateAction;
|
||||
@@ -108,11 +159,11 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
TweenConfiguredSource()
|
||||
{
|
||||
onKillDelegate = OnKill;
|
||||
onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
|
||||
onUpdateDelegate = OnUpdate;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, CallbackType callbackType, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -128,6 +179,7 @@ namespace Cysharp.Threading.Tasks
|
||||
result.tween = tween;
|
||||
result.cancelBehaviour = cancelBehaviour;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.callbackType = callbackType;
|
||||
|
||||
result.originalUpdateAction = tween.onUpdate;
|
||||
result.canceled = false;
|
||||
@@ -138,7 +190,30 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
tween.onUpdate = result.onUpdateDelegate;
|
||||
tween.onKill = result.onKillDelegate;
|
||||
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = result.onCompleteCallbackDelegate;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
@@ -146,7 +221,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return result;
|
||||
}
|
||||
|
||||
void OnKill()
|
||||
void OnCompleteCallbackDelegate()
|
||||
{
|
||||
if (canceled)
|
||||
{
|
||||
@@ -199,7 +274,31 @@ namespace Cysharp.Threading.Tasks
|
||||
this.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CancelAwait:
|
||||
this.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Canceled(instance is returned to pool.)
|
||||
// replace to empty(avoid callback after Canceled(instance is returned to pool.)
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = EmptyTweenCallback;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = EmptyTweenCallback;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.core.TrySetCanceled(this.cancellationToken);
|
||||
break;
|
||||
}
|
||||
@@ -272,7 +371,31 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
tween.onUpdate = originalUpdateAction;
|
||||
tween.onKill = null;
|
||||
|
||||
switch (callbackType)
|
||||
{
|
||||
case CallbackType.Kill:
|
||||
tween.onKill = null;
|
||||
break;
|
||||
case CallbackType.Complete:
|
||||
tween.onComplete = null;
|
||||
break;
|
||||
case CallbackType.Pause:
|
||||
tween.onPause = null;
|
||||
break;
|
||||
case CallbackType.Play:
|
||||
tween.onPlay = null;
|
||||
break;
|
||||
case CallbackType.Rewind:
|
||||
tween.onRewind = null;
|
||||
break;
|
||||
case CallbackType.StepComplete:
|
||||
tween.onStepComplete = null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tween = default;
|
||||
cancellationToken = default;
|
||||
originalUpdateAction = default;
|
||||
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef
vendored
Normal file
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "UniTask.DOTween",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"DOTween.Modules"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.demigiant.dotween",
|
||||
"expression": "",
|
||||
"define": "UNITASK_DOTWEEN_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef.meta
vendored
Normal file
7
src/UniTask/Assets/Plugins/UniTask/Runtime/External/DOTween/UniTask.DOTween.asmdef.meta
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 029c1c1b674aaae47a6841a0b89ad80e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro.meta
vendored
Normal file
8
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro.meta
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f89da606bde9a4e4e94ae1189a029887
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,224 @@
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TMPro;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class TextMeshProAsyncExtensions
|
||||
{
|
||||
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnValueChangedAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnEndEditAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncEndTextSelectionEventHandler<(string, int, int)> GetAsyncEndTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnEndTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnEndTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onEndTextSelection), cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncTextSelectionEventHandler<(string, int, int)> GetAsyncTextSelectionEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<(string, int, int)> OnTextSelectionAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<(string, int, int)> OnTextSelectionAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<(string, int, int)>(new TextSelectionEventConverter(inputField.onTextSelection), cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncDeselectEventHandler<string> GetAsyncDeselectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnDeselectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onDeselect, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnDeselectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onDeselect, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncSelectEventHandler<string> GetAsyncSelectEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSelectAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSelect, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSelectAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSelect, cancellationToken);
|
||||
}
|
||||
|
||||
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsyncSubmitEventHandler<string> GetAsyncSubmitEventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<string> OnSubmitAsync(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<string>(inputField.onSubmit, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<string> OnSubmitAsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<string>(inputField.onSubmit, cancellationToken);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 79f4f2475e0b2c44e97ed1dee760627b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
<#@ template debug="false" hostspecific="false" language="C#" #>
|
||||
<#@ assembly name="System.Core" #>
|
||||
<#@ import namespace="System.Linq" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ output extension=".cs" #>
|
||||
<#
|
||||
var handlers = new (string name, string type)[] {
|
||||
("ValueChanged", "string"),
|
||||
("EndEdit", "string"),
|
||||
("EndTextSelection", "(string, int, int)"),
|
||||
("TextSelection", "(string, int, int)"),
|
||||
("Deselect", "string"),
|
||||
("Select", "string"),
|
||||
("Submit", "string"),
|
||||
};
|
||||
|
||||
Func<string, bool> shouldConvert = x => x.EndsWith("TextSelection");
|
||||
Func<string, string> eventName = x => shouldConvert(x) ? $"new TextSelectionEventConverter(inputField.on{x})" : $"inputField.on{x}";
|
||||
#>
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TMPro;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class TextMeshProAsyncExtensions
|
||||
{
|
||||
<# foreach(var (name, type) in handlers) { #>
|
||||
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), false);
|
||||
}
|
||||
|
||||
public static IAsync<#= (name) #>EventHandler<<#= type #>> GetAsync<#= (name) #>EventHandler(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, false);
|
||||
}
|
||||
|
||||
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static UniTask<<#= type #>> On<#= (name) #>Async(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new AsyncUnityEventHandler<<#= type #>>(<#= eventName(name) #>, cancellationToken, true).OnInvokeAsync();
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, inputField.GetCancellationTokenOnDestroy());
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<<#= type #>> On<#= (name) #>AsAsyncEnumerable(this TMP_InputField inputField, CancellationToken cancellationToken)
|
||||
{
|
||||
return new UnityEventHandlerAsyncEnumerable<<#= type #>>(<#= eventName(name) #>, cancellationToken);
|
||||
}
|
||||
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9bb9fc551a975d44a7180e022a2debe
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
130
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/TextMeshProAsyncExtensions.cs
vendored
Normal file
130
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/TextMeshProAsyncExtensions.cs
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using TMPro;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class TextMeshProAsyncExtensions
|
||||
{
|
||||
// <string> -> Text
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool moveNext;
|
||||
try
|
||||
{
|
||||
moveNext = await e.MoveNextAsync();
|
||||
repeat = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
if (rebindOnError && !repeat)
|
||||
{
|
||||
repeat = true;
|
||||
goto BIND_AGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moveNext) return;
|
||||
|
||||
text.text = e.Current;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <T> -> Text
|
||||
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo<T>(this AsyncReactiveProperty<T> source, TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool moveNext;
|
||||
try
|
||||
{
|
||||
moveNext = await e.MoveNextAsync();
|
||||
repeat = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
if (rebindOnError && !repeat)
|
||||
{
|
||||
repeat = true;
|
||||
goto BIND_AGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moveNext) return;
|
||||
|
||||
text.text = e.Current.ToString();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6ba480edafb67d4e91bb10feb64fae5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/UniTask.TextMeshPro.asmdef
vendored
Normal file
22
src/UniTask/Assets/Plugins/UniTask/Runtime/External/TextMeshPro/UniTask.TextMeshPro.asmdef
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "UniTask.TextMeshPro",
|
||||
"references": [
|
||||
"UniTask",
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.textmeshpro",
|
||||
"expression": "",
|
||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc47925d1a5fa2946bdd37746b2b5d48
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,7 +9,7 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
const int MaxArrayLength = 0X7FEFFFFF;
|
||||
const int InitialSize = 16;
|
||||
|
||||
|
||||
readonly PlayerLoopTiming timing;
|
||||
|
||||
SpinLock gate = new SpinLock();
|
||||
@@ -170,10 +170,17 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
|
||||
for (int i = 0; i < actionListCount; i++)
|
||||
{
|
||||
|
||||
var action = actionList[i];
|
||||
actionList[i] = null;
|
||||
|
||||
action();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -143,6 +143,7 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
var j = tail - 1;
|
||||
|
||||
var loopItems = this.loopItems;
|
||||
// eliminate array-bound check for i
|
||||
for (int i = 0; i < loopItems.Length; i++)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
static TaskPool<PooledDelegate<T>> pool;
|
||||
|
||||
public PooledDelegate<T> NextNode { get; set; }
|
||||
PooledDelegate<T> nextNode;
|
||||
public ref PooledDelegate<T> NextNode => ref nextNode;
|
||||
|
||||
static PooledDelegate()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
internal static class UnityWebRequestResultExtensions
|
||||
{
|
||||
public static bool IsError(this UnityWebRequest unityWebRequest)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
var result = unityWebRequest.result;
|
||||
return (result == UnityWebRequest.Result.ConnectionError)
|
||||
|| (result == UnityWebRequest.Result.DataProcessingError)
|
||||
|| (result == UnityWebRequest.Result.ProtocolError);
|
||||
#else
|
||||
return unityWebRequest.isHttpError || unityWebRequest.isNetworkError;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 111ba0e639de1d7428af6c823ead4918
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
internal readonly struct ValueStopwatch
|
||||
{
|
||||
static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;
|
||||
|
||||
readonly long startTimestamp;
|
||||
|
||||
public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp());
|
||||
|
||||
ValueStopwatch(long startTimestamp)
|
||||
{
|
||||
this.startTimestamp = startTimestamp;
|
||||
}
|
||||
|
||||
public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks);
|
||||
|
||||
public long ElapsedTicks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (startTimestamp == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Detected invalid initialization(use 'default'), only to create from StartNew().");
|
||||
}
|
||||
|
||||
var delta = Stopwatch.GetTimestamp() - startTimestamp;
|
||||
return (long)(delta * TimestampToTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f16fb466974ad034c8732c79c7fd67ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
174
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Create.cs
Normal file
174
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Create.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<T> Create<T>(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
|
||||
{
|
||||
Error.ThrowArgumentNullException(create, nameof(create));
|
||||
return new Create<T>(create);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAsyncWriter<T>
|
||||
{
|
||||
UniTask YieldAsync(T value);
|
||||
}
|
||||
|
||||
internal sealed class Create<T> : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
|
||||
|
||||
public Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create)
|
||||
{
|
||||
this.create = create;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _Create(create, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class _Create : MoveNextSource, IUniTaskAsyncEnumerator<T>
|
||||
{
|
||||
readonly Func<IAsyncWriter<T>, CancellationToken, UniTask> create;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
int state = -1;
|
||||
AsyncWriter writer;
|
||||
|
||||
public _Create(Func<IAsyncWriter<T>, CancellationToken, UniTask> create, CancellationToken cancellationToken)
|
||||
{
|
||||
this.create = create;
|
||||
this.cancellationToken = cancellationToken;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public T Current { get; private set; }
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return default;
|
||||
}
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (state == -2) return default;
|
||||
|
||||
completionSource.Reset();
|
||||
MoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void MoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case -1: // init
|
||||
{
|
||||
writer = new AsyncWriter(this);
|
||||
RunWriterTask(create(writer, cancellationToken)).Forget();
|
||||
if (Volatile.Read(ref state) == -2)
|
||||
{
|
||||
return; // complete synchronously
|
||||
}
|
||||
state = 0; // wait YieldAsync, it set TrySetResult(true)
|
||||
return;
|
||||
}
|
||||
case 0:
|
||||
writer.SignalWriter();
|
||||
return;
|
||||
default:
|
||||
goto DONE;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
state = -2;
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
DONE:
|
||||
state = -2;
|
||||
completionSource.TrySetResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
async UniTaskVoid RunWriterTask(UniTask task)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
goto DONE;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Volatile.Write(ref state, -2);
|
||||
completionSource.TrySetException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
DONE:
|
||||
Volatile.Write(ref state, -2);
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
|
||||
public void SetResult(T value)
|
||||
{
|
||||
Current = value;
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
|
||||
{
|
||||
readonly _Create enumerator;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
public AsyncWriter(_Create enumerator)
|
||||
{
|
||||
this.enumerator = enumerator;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
core.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 UniTask YieldAsync(T value)
|
||||
{
|
||||
core.Reset();
|
||||
enumerator.SetResult(value);
|
||||
return new UniTask(this, core.Version);
|
||||
}
|
||||
|
||||
public void SignalWriter()
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0202f723469f93945afa063bfb440d15
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -88,6 +88,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -156,6 +157,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -195,6 +197,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -263,6 +266,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -302,6 +306,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -382,6 +387,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -422,6 +428,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -502,6 +509,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -541,6 +549,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -621,6 +630,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -661,6 +671,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.selector = selector;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TResult Current { get; private set; }
|
||||
@@ -741,6 +752,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
187
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/SkipUntil.cs
Normal file
187
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/SkipUntil.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new SkipUntil<TSource>(source, other, null);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> SkipUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(other));
|
||||
|
||||
return new SkipUntil<TSource>(source, default, other);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SkipUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly UniTask other;
|
||||
readonly Func<CancellationToken, UniTask> other2;
|
||||
|
||||
public SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
|
||||
{
|
||||
this.source = source;
|
||||
this.other = other;
|
||||
this.other2 = other2;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (other2 != null)
|
||||
{
|
||||
return new _SkipUntil(source, this.other2(cancellationToken), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new _SkipUntil(source, this.other, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class _SkipUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken1;
|
||||
|
||||
bool completed;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
bool continueNext;
|
||||
Exception exception;
|
||||
|
||||
public _SkipUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken1 = cancellationToken1;
|
||||
if (cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
RunOther(other).Forget();
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (exception != null)
|
||||
{
|
||||
return UniTask.FromException<bool>(exception);
|
||||
}
|
||||
|
||||
if (cancellationToken1.IsCancellationRequested)
|
||||
{
|
||||
return UniTask.FromCanceled<bool>(cancellationToken1);
|
||||
}
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken1);
|
||||
}
|
||||
completionSource.Reset();
|
||||
|
||||
if (completed)
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
LOOP:
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
continueNext = true;
|
||||
MoveNextCore(this);
|
||||
if (continueNext)
|
||||
{
|
||||
continueNext = false;
|
||||
goto LOOP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (_SkipUntil)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
if (self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunOther(UniTask other)
|
||||
{
|
||||
try
|
||||
{
|
||||
await other;
|
||||
completed = true;
|
||||
SourceMoveNext();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (_SkipUntil)state;
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de932d79c8d9f3841a066d05ff29edc9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -32,13 +32,17 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
sealed class _SkipUntilCanceled : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||
static readonly Action<object> CancelDelegate2 = OnCanceled2;
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken1;
|
||||
CancellationToken cancellationToken2;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
CancellationTokenRegistration cancellationTokenRegistration2;
|
||||
|
||||
bool isCanceled;
|
||||
int isCanceled;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
bool continueNext;
|
||||
@@ -48,6 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.source = source;
|
||||
this.cancellationToken1 = cancellationToken1;
|
||||
this.cancellationToken2 = cancellationToken2;
|
||||
if (cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
|
||||
}
|
||||
if (cancellationToken1 != cancellationToken2 && cancellationToken2.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(CancelDelegate2, this);
|
||||
}
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
@@ -55,15 +67,18 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (cancellationToken1.IsCancellationRequested) isCanceled = true;
|
||||
if (cancellationToken2.IsCancellationRequested) isCanceled = true;
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
if (cancellationToken1.IsCancellationRequested) isCanceled = 1;
|
||||
if (cancellationToken2.IsCancellationRequested) isCanceled = 1;
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken2); // use only AsyncEnumerator provided token.
|
||||
}
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
|
||||
if (isCanceled != 0)
|
||||
{
|
||||
SourceMoveNext();
|
||||
}
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
@@ -102,25 +117,11 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
AGAIN:
|
||||
|
||||
if (self.isCanceled)
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
if (self.continueNext)
|
||||
{
|
||||
self.continueNext = false;
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self.cancellationToken1.IsCancellationRequested) self.isCanceled = true;
|
||||
if (self.cancellationToken2.IsCancellationRequested) self.isCanceled = true;
|
||||
|
||||
if (self.isCanceled) goto AGAIN;
|
||||
|
||||
if (!self.continueNext)
|
||||
{
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -130,9 +131,37 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (_SkipUntilCanceled)state;
|
||||
if (self.isCanceled == 0)
|
||||
{
|
||||
if (Interlocked.Increment(ref self.isCanceled) == 1)
|
||||
{
|
||||
self.cancellationTokenRegistration2.Dispose();
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled2(object state)
|
||||
{
|
||||
var self = (_SkipUntilCanceled)state;
|
||||
if (self.isCanceled == 0)
|
||||
{
|
||||
if (Interlocked.Increment(ref self.isCanceled) == 1)
|
||||
{
|
||||
self.cancellationTokenRegistration2.Dispose();
|
||||
self.SourceMoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
cancellationTokenRegistration2.Dispose();
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
|
||||
@@ -63,6 +63,42 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// OnNext, OnError
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
||||
@@ -105,6 +141,46 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// OnNext, OnCompleted
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
||||
@@ -147,6 +223,46 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static IDisposable SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void SubscribeAwait<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
Subscribes.SubscribeAwaitCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// IObserver
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
|
||||
@@ -195,7 +311,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current);
|
||||
try
|
||||
{
|
||||
onNext(e.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
@@ -227,7 +350,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current).Forget();
|
||||
try
|
||||
{
|
||||
onNext(e.Current).Forget();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
@@ -259,7 +389,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current, cancellationToken).Forget();
|
||||
try
|
||||
{
|
||||
onNext(e.Current, cancellationToken).Forget();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
@@ -291,7 +428,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
observer.OnNext(e.Current);
|
||||
try
|
||||
{
|
||||
observer.OnNext(e.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
observer.OnCompleted();
|
||||
}
|
||||
@@ -309,5 +453,84 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTaskVoid SubscribeAwaitCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
await onNext(e.Current);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (onError == NopError)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
onError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTaskVoid SubscribeAwaitCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
await onNext(e.Current, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (onError == NopError)
|
||||
{
|
||||
UniTaskScheduler.PublishUnobservedTaskException(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
onError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
190
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/TakeUntil.cs
Normal file
190
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/TakeUntil.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, UniTask other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
|
||||
return new TakeUntil<TSource>(source, other, null);
|
||||
}
|
||||
|
||||
public static IUniTaskAsyncEnumerable<TSource> TakeUntil<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<CancellationToken, UniTask> other)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(source, nameof(other));
|
||||
|
||||
return new TakeUntil<TSource>(source, default, other);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TakeUntil<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||
{
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
readonly UniTask other;
|
||||
readonly Func<CancellationToken, UniTask> other2;
|
||||
|
||||
public TakeUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, Func<CancellationToken, UniTask> other2)
|
||||
{
|
||||
this.source = source;
|
||||
this.other = other;
|
||||
this.other2 = other2;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (other2 != null)
|
||||
{
|
||||
return new _TakeUntil(source, this.other2(cancellationToken), cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new _TakeUntil(source, this.other, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class _TakeUntil : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||
{
|
||||
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||
|
||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||
CancellationToken cancellationToken1;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
|
||||
bool completed;
|
||||
Exception exception;
|
||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||
UniTask<bool>.Awaiter awaiter;
|
||||
|
||||
public _TakeUntil(IUniTaskAsyncEnumerable<TSource> source, UniTask other, CancellationToken cancellationToken1)
|
||||
{
|
||||
this.source = source;
|
||||
this.cancellationToken1 = cancellationToken1;
|
||||
|
||||
if (cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancelDelegate1, this);
|
||||
}
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
|
||||
RunOther(other).Forget();
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
return CompletedTasks.False;
|
||||
}
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
return UniTask.FromException<bool>(exception);
|
||||
}
|
||||
|
||||
if (cancellationToken1.IsCancellationRequested)
|
||||
{
|
||||
return UniTask.FromCanceled<bool>(cancellationToken1);
|
||||
}
|
||||
|
||||
if (enumerator == null)
|
||||
{
|
||||
enumerator = source.GetAsyncEnumerator(cancellationToken1);
|
||||
}
|
||||
|
||||
completionSource.Reset();
|
||||
SourceMoveNext();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
void SourceMoveNext()
|
||||
{
|
||||
try
|
||||
{
|
||||
awaiter = enumerator.MoveNextAsync().GetAwaiter();
|
||||
if (awaiter.IsCompleted)
|
||||
{
|
||||
MoveNextCore(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
awaiter.SourceOnCompleted(MoveNextCoreDelegate, this);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void MoveNextCore(object state)
|
||||
{
|
||||
var self = (_TakeUntil)state;
|
||||
|
||||
if (self.TryGetResult(self.awaiter, out var result))
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (self.exception != null)
|
||||
{
|
||||
self.completionSource.TrySetException(self.exception);
|
||||
}
|
||||
else if (self.cancellationToken1.IsCancellationRequested)
|
||||
{
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.Current = self.enumerator.Current;
|
||||
self.completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.completionSource.TrySetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunOther(UniTask other)
|
||||
{
|
||||
try
|
||||
{
|
||||
await other;
|
||||
completed = true;
|
||||
completionSource.TrySetResult(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
completionSource.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnCanceled1(object state)
|
||||
{
|
||||
var self = (_TakeUntil)state;
|
||||
self.completionSource.TrySetCanceled(self.cancellationToken1);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
if (enumerator != null)
|
||||
{
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12bda324162f15349afefc2c152ac07f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -19,8 +19,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||
{
|
||||
// UnityEngine.Debug.Log("Called ToArray");
|
||||
|
||||
var pool = ArrayPool<TSource>.Shared;
|
||||
var array = pool.Rent(16);
|
||||
|
||||
|
||||
@@ -208,7 +208,6 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
UnityEngine.Debug.Log("TRY_RESULT:" + target.TryGetTarget(out var _));
|
||||
if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
|
||||
{
|
||||
completionSource.TrySetResult(false);
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -165,6 +166,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -204,6 +206,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -281,6 +284,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -320,6 +324,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -410,6 +415,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -450,6 +456,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -540,6 +547,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -579,6 +587,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -669,6 +678,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -709,6 +719,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.predicate = predicate;
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.moveNextAction = MoveNext;
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
}
|
||||
|
||||
public TSource Current { get; private set; }
|
||||
@@ -799,6 +810,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return enumerator.DisposeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,32 @@ namespace Cysharp.Threading.Tasks
|
||||
return dest;
|
||||
}
|
||||
|
||||
static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
|
||||
{
|
||||
var loop = new PlayerLoopSystem
|
||||
{
|
||||
type = typeof(UniTaskSynchronizationContext),
|
||||
updateDelegate = UniTaskSynchronizationContext.Run
|
||||
};
|
||||
|
||||
// Remove items from previous initializations.
|
||||
var source = loopSystem.subSystemList
|
||||
.Where(ls => ls.type != typeof(UniTaskSynchronizationContext))
|
||||
.ToArray();
|
||||
|
||||
var dest = new System.Collections.Generic.List<PlayerLoopSystem>(source);
|
||||
|
||||
var index = dest.FindIndex(x => x.type.Name == "ScriptRunDelayedTasks");
|
||||
if (index == -1)
|
||||
{
|
||||
index = dest.FindIndex(x => x.type.Name == "UniTaskLoopRunnerUpdate");
|
||||
}
|
||||
|
||||
dest.Insert(index + 1, loop);
|
||||
|
||||
return dest.ToArray();
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
static void Init()
|
||||
{
|
||||
@@ -246,6 +272,8 @@ namespace Cysharp.Threading.Tasks
|
||||
if (item != null) item.Run();
|
||||
}
|
||||
}
|
||||
|
||||
UniTaskSynchronizationContext.Run();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -260,7 +288,7 @@ namespace Cysharp.Threading.Tasks
|
||||
// Initialization
|
||||
copyList[0].subSystemList = InsertRunner(copyList[0], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), yielders[1] = new ContinuationQueue(PlayerLoopTiming.LastInitialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[0] = new PlayerLoopRunner(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.LastInitialization));
|
||||
// EarlyUpdate
|
||||
copyList[1].subSystemList = InsertRunner(copyList[1], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(PlayerLoopTiming.EarlyUpdate),
|
||||
@@ -293,6 +321,9 @@ namespace Cysharp.Threading.Tasks
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate));
|
||||
|
||||
// Insert UniTaskSynchronizationContext to Update loop
|
||||
copyList[4].subSystemList = InsertUniTaskSynchronizationContext(copyList[4]);
|
||||
|
||||
playerLoop.subSystemList = copyList;
|
||||
PlayerLoop.SetPlayerLoop(playerLoop);
|
||||
}
|
||||
@@ -306,6 +337,56 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
yielders[(int)timing].Enqueue(continuation);
|
||||
}
|
||||
|
||||
// Diagnostics helper
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
|
||||
public static void DumpCurrentPlayerLoop()
|
||||
{
|
||||
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.AppendLine($"PlayerLoop List");
|
||||
foreach (var header in playerLoop.subSystemList)
|
||||
{
|
||||
sb.AppendFormat("------{0}------", header.type.Name);
|
||||
sb.AppendLine();
|
||||
foreach (var subSystem in header.subSystemList)
|
||||
{
|
||||
sb.AppendFormat("{0}", subSystem.type.Name);
|
||||
sb.AppendLine();
|
||||
|
||||
if (subSystem.subSystemList != null)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnityEngine.Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public static bool IsInjectedUniTaskPlayerLoop()
|
||||
{
|
||||
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||
|
||||
foreach (var header in playerLoop.subSystemList)
|
||||
{
|
||||
foreach (var subSystem in header.subSystemList)
|
||||
{
|
||||
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public interface ITaskPoolNode<T>
|
||||
{
|
||||
T NextNode { get; set; }
|
||||
ref T NextNode { get; }
|
||||
}
|
||||
|
||||
// mutable struct, don't mark readonly.
|
||||
@@ -77,8 +77,9 @@ namespace Cysharp.Threading.Tasks
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
ref var nextNode = ref v.NextNode;
|
||||
root = nextNode;
|
||||
nextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public enum DelayType
|
||||
{
|
||||
/// <summary>use Time.deltaTime.</summary>
|
||||
DeltaTime,
|
||||
/// <summary>Ignore timescale, use Time.unscaledDeltaTime.</summary>
|
||||
UnscaledDeltaTime,
|
||||
/// <summary>use Stopwatch.GetTimestamp().</summary>
|
||||
Realtime
|
||||
}
|
||||
|
||||
public partial struct UniTask
|
||||
{
|
||||
public static YieldAwaitable Yield(PlayerLoopTiming timing = PlayerLoopTiming.Update)
|
||||
@@ -74,32 +84,51 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
|
||||
if (delayTimeSpan < TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Delay does not allow minus millisecondsDelay. millisecondsDelay:" + millisecondsDelay);
|
||||
}
|
||||
|
||||
return (ignoreTimeScale)
|
||||
? new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token)
|
||||
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token);
|
||||
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
|
||||
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
|
||||
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (delayTimeSpan < TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan);
|
||||
}
|
||||
|
||||
return (ignoreTimeScale)
|
||||
? new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token)
|
||||
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token);
|
||||
switch (delayType)
|
||||
{
|
||||
case DelayType.UnscaledDeltaTime:
|
||||
{
|
||||
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
|
||||
}
|
||||
case DelayType.Realtime:
|
||||
{
|
||||
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
|
||||
}
|
||||
case DelayType.DeltaTime:
|
||||
default:
|
||||
{
|
||||
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
|
||||
{
|
||||
static TaskPool<YieldPromise> pool;
|
||||
public YieldPromise NextNode { get; set; }
|
||||
YieldPromise nextNode;
|
||||
public ref YieldPromise NextNode => ref nextNode;
|
||||
|
||||
static YieldPromise()
|
||||
{
|
||||
@@ -187,7 +216,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
|
||||
{
|
||||
static TaskPool<NextFramePromise> pool;
|
||||
public NextFramePromise NextNode { get; set; }
|
||||
NextFramePromise nextNode;
|
||||
public ref NextFramePromise NextNode => ref nextNode;
|
||||
|
||||
static NextFramePromise()
|
||||
{
|
||||
@@ -281,7 +311,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
|
||||
{
|
||||
static TaskPool<DelayFramePromise> pool;
|
||||
public DelayFramePromise NextNode { get; set; }
|
||||
DelayFramePromise nextNode;
|
||||
public ref DelayFramePromise NextNode => ref nextNode;
|
||||
|
||||
static DelayFramePromise()
|
||||
{
|
||||
@@ -396,7 +427,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
|
||||
{
|
||||
static TaskPool<DelayPromise> pool;
|
||||
public DelayPromise NextNode { get; set; }
|
||||
DelayPromise nextNode;
|
||||
public ref DelayPromise NextNode => ref nextNode;
|
||||
|
||||
static DelayPromise()
|
||||
{
|
||||
@@ -404,7 +436,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
int initialFrame;
|
||||
float delayFrameTimeSpan;
|
||||
float delayTimeSpan;
|
||||
float elapsed;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
@@ -414,7 +446,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -427,7 +459,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
result.elapsed = 0.0f;
|
||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||
result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
|
||||
|
||||
@@ -483,7 +515,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
if (elapsed >= delayFrameTimeSpan)
|
||||
if (elapsed >= delayTimeSpan)
|
||||
{
|
||||
core.TrySetResult(null);
|
||||
return false;
|
||||
@@ -496,7 +528,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
delayFrameTimeSpan = default;
|
||||
delayTimeSpan = default;
|
||||
elapsed = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
@@ -506,7 +538,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayIgnoreTimeScalePromise>
|
||||
{
|
||||
static TaskPool<DelayIgnoreTimeScalePromise> pool;
|
||||
public DelayIgnoreTimeScalePromise NextNode { get; set; }
|
||||
DelayIgnoreTimeScalePromise nextNode;
|
||||
public ref DelayIgnoreTimeScalePromise NextNode => ref nextNode;
|
||||
|
||||
static DelayIgnoreTimeScalePromise()
|
||||
{
|
||||
@@ -612,6 +645,105 @@ namespace Cysharp.Threading.Tasks
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DelayRealtimePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayRealtimePromise>
|
||||
{
|
||||
static TaskPool<DelayRealtimePromise> pool;
|
||||
DelayRealtimePromise nextNode;
|
||||
public ref DelayRealtimePromise NextNode => ref nextNode;
|
||||
|
||||
static DelayRealtimePromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(DelayRealtimePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
long delayTimeSpanTicks;
|
||||
ValueStopwatch stopwatch;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
DelayRealtimePromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new DelayRealtimePromise();
|
||||
}
|
||||
|
||||
result.stopwatch = ValueStopwatch.StartNew();
|
||||
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (stopwatch.ElapsedTicks >= delayTimeSpanTicks)
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
stopwatch = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct YieldAwaitable
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
@@ -174,18 +175,34 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask<T>(new DeferPromise<T>(factory), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Never complete.
|
||||
/// </summary>
|
||||
public static UniTask Never(CancellationToken cancellationToken)
|
||||
{
|
||||
return new UniTask<AsyncUnit>(new NeverPromise<AsyncUnit>(cancellationToken), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Never complete.
|
||||
/// </summary>
|
||||
public static UniTask<T> Never<T>(CancellationToken cancellationToken)
|
||||
{
|
||||
return new UniTask<T>(new NeverPromise<T>(cancellationToken), 0);
|
||||
}
|
||||
|
||||
sealed class ExceptionResultSource : IUniTaskSource
|
||||
{
|
||||
readonly Exception exception;
|
||||
readonly ExceptionDispatchInfo exception;
|
||||
|
||||
public ExceptionResultSource(Exception exception)
|
||||
{
|
||||
this.exception = exception;
|
||||
this.exception = ExceptionDispatchInfo.Capture(exception);
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
throw exception;
|
||||
exception.Throw();
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
@@ -206,21 +223,22 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
sealed class ExceptionResultSource<T> : IUniTaskSource<T>
|
||||
{
|
||||
readonly Exception exception;
|
||||
readonly ExceptionDispatchInfo exception;
|
||||
|
||||
public ExceptionResultSource(Exception exception)
|
||||
{
|
||||
this.exception = exception;
|
||||
this.exception = ExceptionDispatchInfo.Capture(exception);
|
||||
}
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
throw exception;
|
||||
exception.Throw();
|
||||
return default;
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
throw exception;
|
||||
exception.Throw();
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
@@ -382,6 +400,54 @@ namespace Cysharp.Threading.Tasks
|
||||
return task.Status;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class NeverPromise<T> : IUniTaskSource<T>
|
||||
{
|
||||
static readonly Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
public NeverPromise(CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
if (this.cancellationToken.CanBeCanceled)
|
||||
{
|
||||
this.cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (NeverPromise<T>)state;
|
||||
self.core.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
return core.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);
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class CompletedTasks
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public partial struct UniTask
|
||||
{
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask Run(Action action, bool configureAwait = true)
|
||||
#region OBSOLETE_RUN
|
||||
|
||||
// Run is a confusing name, use only RunOnThreadPool in the future.
|
||||
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -26,13 +35,19 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
action();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask Run(Action<object> action, object state, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -48,13 +63,19 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
action(state);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask Run(Func<UniTask> action, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -70,13 +91,19 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
await action();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -92,12 +119,19 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
await action(state);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> Run<T>(Func<T> func, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -107,6 +141,7 @@ namespace Cysharp.Threading.Tasks
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -115,10 +150,15 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -127,20 +167,28 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return await func();
|
||||
var result = await func();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -150,6 +198,7 @@ namespace Cysharp.Threading.Tasks
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -158,11 +207,15 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true)
|
||||
/// <summary>[Obsolete]recommend to use RunOnThreadPool(or UniTask.Void(async void), UniTask.Create(async UniTask)).</summary>
|
||||
public static async UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
@@ -170,13 +223,246 @@ namespace Cysharp.Threading.Tasks
|
||||
return await func(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await func(state);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask RunOnThreadPool(Action action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return await func(state);
|
||||
action();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask RunOnThreadPool(Action<object> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
action(state);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask RunOnThreadPool(Func<UniTask> action, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await action();
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask RunOnThreadPool(Func<object, UniTask> action, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
await action(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await action(state);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> RunOnThreadPool<T>(Func<T> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return func();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> RunOnThreadPool<T>(Func<UniTask<T>> func, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await func();
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await func();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> RunOnThreadPool<T>(Func<object, T> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return func(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return func(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
|
||||
public static async UniTask<T> RunOnThreadPool<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (configureAwait)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await func(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await UniTask.Yield();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = await func(state);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,33 +15,41 @@ namespace Cysharp.Threading.Tasks
|
||||
/// <summary>
|
||||
/// If running on mainthread, do nothing. Otherwise, same as UniTask.Yield(PlayerLoopTiming.Update).
|
||||
/// </summary>
|
||||
public static SwitchToMainThreadAwaitable SwitchToMainThread()
|
||||
public static SwitchToMainThreadAwaitable SwitchToMainThread(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new SwitchToMainThreadAwaitable(PlayerLoopTiming.Update);
|
||||
return new SwitchToMainThreadAwaitable(PlayerLoopTiming.Update, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If running on mainthread, do nothing. Otherwise, same as UniTask.Yield(timing).
|
||||
/// </summary>
|
||||
public static SwitchToMainThreadAwaitable SwitchToMainThread(PlayerLoopTiming timing)
|
||||
public static SwitchToMainThreadAwaitable SwitchToMainThread(PlayerLoopTiming timing, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new SwitchToMainThreadAwaitable(timing);
|
||||
return new SwitchToMainThreadAwaitable(timing, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return to mainthread(same as await SwitchToMainThread) after using scope is closed.
|
||||
/// </summary>
|
||||
public static ReturnToMainThread ReturnToMainThread()
|
||||
public static ReturnToMainThread ReturnToMainThread(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new ReturnToMainThread(PlayerLoopTiming.Update);
|
||||
return new ReturnToMainThread(PlayerLoopTiming.Update, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return to mainthread(same as await SwitchToMainThread) after using scope is closed.
|
||||
/// </summary>
|
||||
public static ReturnToMainThread ReturnToMainThread(PlayerLoopTiming timing)
|
||||
public static ReturnToMainThread ReturnToMainThread(PlayerLoopTiming timing, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new ReturnToMainThread(timing);
|
||||
return new ReturnToMainThread(timing, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue the action to PlayerLoop.
|
||||
/// </summary>
|
||||
public static void Post(Action action, PlayerLoopTiming timing = PlayerLoopTiming.Update)
|
||||
{
|
||||
PlayerLoopHelper.AddContinuation(timing, action);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -59,20 +67,20 @@ namespace Cysharp.Threading.Tasks
|
||||
return new SwitchToTaskPoolAwaitable();
|
||||
}
|
||||
|
||||
public static SwitchToSynchronizationContextAwaitable SwitchToSynchronizationContext(SynchronizationContext synchronizationContext)
|
||||
public static SwitchToSynchronizationContextAwaitable SwitchToSynchronizationContext(SynchronizationContext synchronizationContext, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Error.ThrowArgumentNullException(synchronizationContext, nameof(synchronizationContext));
|
||||
return new SwitchToSynchronizationContextAwaitable(synchronizationContext);
|
||||
return new SwitchToSynchronizationContextAwaitable(synchronizationContext, cancellationToken);
|
||||
}
|
||||
|
||||
public static ReturnToSynchronizationContext ReturnToSynchronizationContext(SynchronizationContext synchronizationContext)
|
||||
public static ReturnToSynchronizationContext ReturnToSynchronizationContext(SynchronizationContext synchronizationContext, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new ReturnToSynchronizationContext(synchronizationContext, false);
|
||||
return new ReturnToSynchronizationContext(synchronizationContext, false, cancellationToken);
|
||||
}
|
||||
|
||||
public static ReturnToSynchronizationContext ReturnToCurrentSynchronizationContext(bool dontPostWhenSameContext = true)
|
||||
public static ReturnToSynchronizationContext ReturnToCurrentSynchronizationContext(bool dontPostWhenSameContext = true, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new ReturnToSynchronizationContext(SynchronizationContext.Current, dontPostWhenSameContext);
|
||||
return new ReturnToSynchronizationContext(SynchronizationContext.Current, dontPostWhenSameContext, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,21 +89,25 @@ namespace Cysharp.Threading.Tasks
|
||||
public struct SwitchToMainThreadAwaitable
|
||||
{
|
||||
readonly PlayerLoopTiming playerLoopTiming;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public SwitchToMainThreadAwaitable(PlayerLoopTiming playerLoopTiming)
|
||||
public SwitchToMainThreadAwaitable(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken)
|
||||
{
|
||||
this.playerLoopTiming = playerLoopTiming;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Awaiter GetAwaiter() => new Awaiter(playerLoopTiming);
|
||||
public Awaiter GetAwaiter() => new Awaiter(playerLoopTiming, cancellationToken);
|
||||
|
||||
public struct Awaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly PlayerLoopTiming playerLoopTiming;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public Awaiter(PlayerLoopTiming playerLoopTiming)
|
||||
public Awaiter(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken)
|
||||
{
|
||||
this.playerLoopTiming = playerLoopTiming;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public bool IsCompleted
|
||||
@@ -114,7 +126,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
public void GetResult() { }
|
||||
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
@@ -131,31 +143,35 @@ namespace Cysharp.Threading.Tasks
|
||||
public struct ReturnToMainThread
|
||||
{
|
||||
readonly PlayerLoopTiming playerLoopTiming;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public ReturnToMainThread(PlayerLoopTiming playerLoopTiming)
|
||||
public ReturnToMainThread(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken)
|
||||
{
|
||||
this.playerLoopTiming = playerLoopTiming;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Awaiter DisposeAsync()
|
||||
{
|
||||
return new Awaiter(playerLoopTiming); // run immediate.
|
||||
return new Awaiter(playerLoopTiming, cancellationToken); // run immediate.
|
||||
}
|
||||
|
||||
public readonly struct Awaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly PlayerLoopTiming timing;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public Awaiter(PlayerLoopTiming timing)
|
||||
public Awaiter(PlayerLoopTiming timing, CancellationToken cancellationToken)
|
||||
{
|
||||
this.timing = timing;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Awaiter GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => PlayerLoopHelper.MainThreadId == System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
public void GetResult() { }
|
||||
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
@@ -208,7 +224,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||
{
|
||||
static TaskPool<ThreadPoolWorkItem> pool;
|
||||
public ThreadPoolWorkItem NextNode { get; set; }
|
||||
ThreadPoolWorkItem nextNode;
|
||||
public ref ThreadPoolWorkItem NextNode => ref nextNode;
|
||||
|
||||
static ThreadPoolWorkItem()
|
||||
{
|
||||
@@ -277,26 +294,30 @@ namespace Cysharp.Threading.Tasks
|
||||
public struct SwitchToSynchronizationContextAwaitable
|
||||
{
|
||||
readonly SynchronizationContext synchronizationContext;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public SwitchToSynchronizationContextAwaitable(SynchronizationContext synchronizationContext)
|
||||
public SwitchToSynchronizationContextAwaitable(SynchronizationContext synchronizationContext, CancellationToken cancellationToken)
|
||||
{
|
||||
this.synchronizationContext = synchronizationContext;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Awaiter GetAwaiter() => new Awaiter(synchronizationContext);
|
||||
public Awaiter GetAwaiter() => new Awaiter(synchronizationContext, cancellationToken);
|
||||
|
||||
public struct Awaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
static readonly SendOrPostCallback switchToCallback = Callback;
|
||||
readonly SynchronizationContext synchronizationContext;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public Awaiter(SynchronizationContext synchronizationContext)
|
||||
public Awaiter(SynchronizationContext synchronizationContext, CancellationToken cancellationToken)
|
||||
{
|
||||
this.synchronizationContext = synchronizationContext;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public bool IsCompleted => false;
|
||||
public void GetResult() { }
|
||||
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
@@ -320,16 +341,18 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
readonly SynchronizationContext syncContext;
|
||||
readonly bool dontPostWhenSameContext;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public ReturnToSynchronizationContext(SynchronizationContext syncContext, bool dontPostWhenSameContext)
|
||||
public ReturnToSynchronizationContext(SynchronizationContext syncContext, bool dontPostWhenSameContext, CancellationToken cancellationToken)
|
||||
{
|
||||
this.syncContext = syncContext;
|
||||
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Awaiter DisposeAsync()
|
||||
{
|
||||
return new Awaiter(syncContext, dontPostWhenSameContext);
|
||||
return new Awaiter(syncContext, dontPostWhenSameContext, cancellationToken);
|
||||
}
|
||||
|
||||
public struct Awaiter : ICriticalNotifyCompletion
|
||||
@@ -338,11 +361,13 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
readonly SynchronizationContext synchronizationContext;
|
||||
readonly bool dontPostWhenSameContext;
|
||||
readonly CancellationToken cancellationToken;
|
||||
|
||||
public Awaiter(SynchronizationContext synchronizationContext, bool dontPostWhenSameContext)
|
||||
public Awaiter(SynchronizationContext synchronizationContext, bool dontPostWhenSameContext, CancellationToken cancellationToken)
|
||||
{
|
||||
this.synchronizationContext = synchronizationContext;
|
||||
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
||||
this.cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public Awaiter GetAwaiter() => this;
|
||||
@@ -365,7 +390,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
public void GetResult() { }
|
||||
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
|
||||
{
|
||||
static TaskPool<WaitUntilPromise> pool;
|
||||
public WaitUntilPromise NextNode { get; set; }
|
||||
WaitUntilPromise nextNode;
|
||||
public ref WaitUntilPromise NextNode => ref nextNode;
|
||||
|
||||
static WaitUntilPromise()
|
||||
{
|
||||
@@ -142,7 +143,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||
{
|
||||
static TaskPool<WaitWhilePromise> pool;
|
||||
public WaitWhilePromise NextNode { get; set; }
|
||||
WaitWhilePromise nextNode;
|
||||
public ref WaitWhilePromise NextNode => ref nextNode;
|
||||
|
||||
static WaitWhilePromise()
|
||||
{
|
||||
@@ -246,7 +248,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||
{
|
||||
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||
public WaitUntilCanceledPromise NextNode { get; set; }
|
||||
WaitUntilCanceledPromise nextNode;
|
||||
public ref WaitUntilCanceledPromise NextNode => ref nextNode;
|
||||
|
||||
static WaitUntilCanceledPromise()
|
||||
{
|
||||
@@ -334,7 +337,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedUnityObjectPromise<T, U>>
|
||||
{
|
||||
static TaskPool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool;
|
||||
public WaitUntilValueChangedUnityObjectPromise<T, U> NextNode { get; set; }
|
||||
WaitUntilValueChangedUnityObjectPromise<T, U> nextNode;
|
||||
public ref WaitUntilValueChangedUnityObjectPromise<T, U> NextNode => ref nextNode;
|
||||
|
||||
static WaitUntilValueChangedUnityObjectPromise()
|
||||
{
|
||||
@@ -457,7 +461,8 @@ namespace Cysharp.Threading.Tasks
|
||||
where T : class
|
||||
{
|
||||
static TaskPool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool;
|
||||
public WaitUntilValueChangedStandardObjectPromise<T, U> NextNode { get; set; }
|
||||
WaitUntilValueChangedStandardObjectPromise<T, U> nextNode;
|
||||
public ref WaitUntilValueChangedStandardObjectPromise<T, U> NextNode => ref nextNode;
|
||||
|
||||
static WaitUntilValueChangedStandardObjectPromise()
|
||||
{
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"name": "UniTask",
|
||||
"references": [
|
||||
"Unity.ResourceManager",
|
||||
"Unity.TextMeshPro",
|
||||
"DOTween.Modules"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
@@ -14,19 +11,9 @@
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"name": "com.unity.modules.assetbundle",
|
||||
"expression": "",
|
||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.textmeshpro",
|
||||
"expression": "",
|
||||
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||
},
|
||||
{
|
||||
"name": "com.demigiant.dotween",
|
||||
"expression": "",
|
||||
"define": "UNITASK_DOTWEEN_SUPPORT"
|
||||
"define": "UNITASK_ASSETBUNDLE_SUPPORT"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace Cysharp.Threading.Tasks
|
||||
ValidateToken(token);
|
||||
if (completedCount == 0)
|
||||
{
|
||||
throw new InvalidOperationException("not yet completed.");
|
||||
throw new InvalidOperationException("Not yet completed, UniTask only allow to use await.");
|
||||
}
|
||||
|
||||
if (error != null)
|
||||
@@ -288,7 +288,7 @@ namespace Cysharp.Threading.Tasks
|
||||
// It will cause call OnCompleted multiple time, invalid.
|
||||
if (!ReferenceEquals(oldContinuation, UniTaskCompletionSourceCoreShared.s_sentinel))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
throw new InvalidOperationException("Already continuation registered, can not await twice or get Status after await.");
|
||||
}
|
||||
|
||||
continuation(state);
|
||||
@@ -319,7 +319,8 @@ namespace Cysharp.Threading.Tasks
|
||||
public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise
|
||||
{
|
||||
static TaskPool<AutoResetUniTaskCompletionSource> pool;
|
||||
public AutoResetUniTaskCompletionSource NextNode { get; set; }
|
||||
AutoResetUniTaskCompletionSource nextNode;
|
||||
public ref AutoResetUniTaskCompletionSource NextNode => ref nextNode;
|
||||
|
||||
static AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
@@ -441,7 +442,8 @@ namespace Cysharp.Threading.Tasks
|
||||
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, ITaskPoolNode<AutoResetUniTaskCompletionSource<T>>, IPromise<T>
|
||||
{
|
||||
static TaskPool<AutoResetUniTaskCompletionSource<T>> pool;
|
||||
public AutoResetUniTaskCompletionSource<T> NextNode { get; set; }
|
||||
AutoResetUniTaskCompletionSource<T> nextNode;
|
||||
public ref AutoResetUniTaskCompletionSource<T> NextNode => ref nextNode;
|
||||
|
||||
static AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
|
||||
@@ -189,6 +189,174 @@ namespace Cysharp.Threading.Tasks
|
||||
return new AsyncLazy<T>(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore task result when cancel raised first.
|
||||
/// </summary>
|
||||
public static UniTask WithCancellation(this UniTask task, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!cancellationToken.CanBeCanceled)
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return UniTask.FromCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
if (task.Status.IsCompleted())
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
return new UniTask(new WithCancellationSource(task, cancellationToken), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore task result when cancel raised first.
|
||||
/// </summary>
|
||||
public static UniTask<T> WithCancellation<T>(this UniTask<T> task, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!cancellationToken.CanBeCanceled)
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return UniTask.FromCanceled<T>(cancellationToken);
|
||||
}
|
||||
|
||||
if (task.Status.IsCompleted())
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
return new UniTask<T>(new WithCancellationSource<T>(task, cancellationToken), 0);
|
||||
}
|
||||
|
||||
sealed class WithCancellationSource : IUniTaskSource
|
||||
{
|
||||
static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration tokenRegistration;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
public WithCancellationSource(UniTask task, CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
|
||||
RunTask(task).Forget();
|
||||
}
|
||||
|
||||
async UniTaskVoid RunTask(UniTask task)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
core.TrySetException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tokenRegistration.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WithCancellationSource)state;
|
||||
self.core.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WithCancellationSource<T> : IUniTaskSource<T>
|
||||
{
|
||||
static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration tokenRegistration;
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
public WithCancellationSource(UniTask<T> task, CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
|
||||
RunTask(task).Forget();
|
||||
}
|
||||
|
||||
async UniTaskVoid RunTask(UniTask<T> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
core.TrySetResult(await task);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
core.TrySetException(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tokenRegistration.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WithCancellationSource<T>)state;
|
||||
self.core.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
public static IEnumerator ToCoroutine<T>(this UniTask<T> task, Action<T> resultHandler = null, Action<Exception> exceptionHandler = null)
|
||||
@@ -201,10 +369,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return new ToCoroutineEnumerator(task, exceptionHandler);
|
||||
}
|
||||
|
||||
public static async UniTask Timeout(this UniTask task, TimeSpan timeout, bool ignoreTimeScale = true, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
public static async UniTask Timeout(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
{
|
||||
var delayCancellationTokenSource = new CancellationTokenSource();
|
||||
var timeoutTask = UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
|
||||
int winArgIndex;
|
||||
bool taskResultIsCanceled;
|
||||
@@ -242,10 +410,10 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
public static async UniTask<T> Timeout<T>(this UniTask<T> task, TimeSpan timeout, bool ignoreTimeScale = true, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
public static async UniTask<T> Timeout<T>(this UniTask<T> task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
{
|
||||
var delayCancellationTokenSource = new CancellationTokenSource();
|
||||
var timeoutTask = UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
|
||||
int winArgIndex;
|
||||
(bool IsCanceled, T Result) taskResult;
|
||||
@@ -288,10 +456,10 @@ namespace Cysharp.Threading.Tasks
|
||||
/// <summary>
|
||||
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
|
||||
/// </summary>
|
||||
public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, bool ignoreTimeScale = true, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
{
|
||||
var delayCancellationTokenSource = new CancellationTokenSource();
|
||||
var timeoutTask = UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
|
||||
int winArgIndex;
|
||||
bool taskResultIsCanceled;
|
||||
@@ -334,10 +502,10 @@ namespace Cysharp.Threading.Tasks
|
||||
/// <summary>
|
||||
/// Timeout with suppress OperationCanceledException. Returns (bool IsTimeout, T Result).
|
||||
/// </summary>
|
||||
public static async UniTask<(bool IsTimeout, T Result)> TimeoutWithoutException<T>(this UniTask<T> task, TimeSpan timeout, bool ignoreTimeScale = true, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
public static async UniTask<(bool IsTimeout, T Result)> TimeoutWithoutException<T>(this UniTask<T> task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
|
||||
{
|
||||
var delayCancellationTokenSource = new CancellationTokenSource();
|
||||
var timeoutTask = UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
|
||||
int winArgIndex;
|
||||
(bool IsCanceled, T Result) taskResult;
|
||||
@@ -564,10 +732,50 @@ namespace Cysharp.Threading.Tasks
|
||||
return await await task;
|
||||
}
|
||||
|
||||
public static async UniTask Unwrap<T>(this UniTask<UniTask> task)
|
||||
public static async UniTask Unwrap(this UniTask<UniTask> task)
|
||||
{
|
||||
await await task;
|
||||
}
|
||||
|
||||
public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task)
|
||||
{
|
||||
return await await task;
|
||||
}
|
||||
|
||||
public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task, bool continueOnCapturedContext)
|
||||
{
|
||||
return await await task.ConfigureAwait(continueOnCapturedContext);
|
||||
}
|
||||
|
||||
public static async UniTask Unwrap(this Task<UniTask> task)
|
||||
{
|
||||
await await task;
|
||||
}
|
||||
|
||||
public static async UniTask Unwrap(this Task<UniTask> task, bool continueOnCapturedContext)
|
||||
{
|
||||
await await task.ConfigureAwait(continueOnCapturedContext);
|
||||
}
|
||||
|
||||
public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task)
|
||||
{
|
||||
return await await task;
|
||||
}
|
||||
|
||||
public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task, bool continueOnCapturedContext)
|
||||
{
|
||||
return await (await task).ConfigureAwait(continueOnCapturedContext);
|
||||
}
|
||||
|
||||
public static async UniTask Unwrap(this UniTask<Task> task)
|
||||
{
|
||||
await await task;
|
||||
}
|
||||
|
||||
public static async UniTask Unwrap(this UniTask<Task> task, bool continueOnCapturedContext)
|
||||
{
|
||||
await (await task).ConfigureAwait(continueOnCapturedContext);
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public class UniTaskSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
const int MaxArrayLength = 0X7FEFFFFF;
|
||||
const int InitialSize = 16;
|
||||
|
||||
static SpinLock gate = new SpinLock();
|
||||
static bool dequing = false;
|
||||
|
||||
static int actionListCount = 0;
|
||||
static Callback[] actionList = new Callback[InitialSize];
|
||||
|
||||
static int waitingListCount = 0;
|
||||
static Callback[] waitingList = new Callback[InitialSize];
|
||||
|
||||
static int opCount;
|
||||
|
||||
public override void Send(SendOrPostCallback d, object state)
|
||||
{
|
||||
d(state);
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
gate.Enter(ref lockTaken);
|
||||
|
||||
if (dequing)
|
||||
{
|
||||
// Ensure Capacity
|
||||
if (waitingList.Length == waitingListCount)
|
||||
{
|
||||
var newLength = waitingListCount * 2;
|
||||
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
|
||||
|
||||
var newArray = new Callback[newLength];
|
||||
Array.Copy(waitingList, newArray, waitingListCount);
|
||||
waitingList = newArray;
|
||||
}
|
||||
waitingList[waitingListCount] = new Callback(d, state);
|
||||
waitingListCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure Capacity
|
||||
if (actionList.Length == actionListCount)
|
||||
{
|
||||
var newLength = actionListCount * 2;
|
||||
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
|
||||
|
||||
var newArray = new Callback[newLength];
|
||||
Array.Copy(actionList, newArray, actionListCount);
|
||||
actionList = newArray;
|
||||
}
|
||||
actionList[actionListCount] = new Callback(d, state);
|
||||
actionListCount++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) gate.Exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OperationStarted()
|
||||
{
|
||||
Interlocked.Increment(ref opCount);
|
||||
}
|
||||
|
||||
public override void OperationCompleted()
|
||||
{
|
||||
Interlocked.Decrement(ref opCount);
|
||||
}
|
||||
|
||||
public override SynchronizationContext CreateCopy()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// delegate entrypoint.
|
||||
internal static void Run()
|
||||
{
|
||||
{
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
gate.Enter(ref lockTaken);
|
||||
if (actionListCount == 0) return;
|
||||
dequing = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) gate.Exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < actionListCount; i++)
|
||||
{
|
||||
var action = actionList[i];
|
||||
actionList[i] = default;
|
||||
action.Invoke();
|
||||
}
|
||||
|
||||
{
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
gate.Enter(ref lockTaken);
|
||||
dequing = false;
|
||||
|
||||
var swapTempActionList = actionList;
|
||||
|
||||
actionListCount = waitingListCount;
|
||||
actionList = waitingList;
|
||||
|
||||
waitingListCount = 0;
|
||||
waitingList = swapTempActionList;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) gate.Exit(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
readonly struct Callback
|
||||
{
|
||||
readonly SendOrPostCallback callback;
|
||||
readonly object state;
|
||||
|
||||
public Callback(SendOrPostCallback callback, object state)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(state);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UnityEngine.Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abf3aae9813db2849bce518f8596e920
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,324 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
#if UNITY_2018_4 || UNITY_2019_4_OR_NEWER
|
||||
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class UnityAsyncExtensions
|
||||
{
|
||||
public static AssetBundleRequestAllAssetsAwaiter AwaitForAllAssets(this AssetBundleRequest asyncOperation)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
return new AssetBundleRequestAllAssetsAwaiter(asyncOperation);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult<UnityEngine.Object[]>(asyncOperation.allAssets);
|
||||
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets);
|
||||
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
AssetBundleRequest asyncOperation;
|
||||
Action<AsyncOperation> continuationAction;
|
||||
|
||||
public AssetBundleRequestAllAssetsAwaiter(AssetBundleRequest asyncOperation)
|
||||
{
|
||||
this.asyncOperation = asyncOperation;
|
||||
this.continuationAction = null;
|
||||
}
|
||||
|
||||
public AssetBundleRequestAllAssetsAwaiter GetAwaiter()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool IsCompleted => asyncOperation.isDone;
|
||||
|
||||
public UnityEngine.Object[] GetResult()
|
||||
{
|
||||
if (continuationAction != null)
|
||||
{
|
||||
asyncOperation.completed -= continuationAction;
|
||||
continuationAction = null;
|
||||
var result = asyncOperation.allAssets;
|
||||
asyncOperation = null;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = asyncOperation.allAssets;
|
||||
asyncOperation = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
UnsafeOnCompleted(continuation);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||
asyncOperation.completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AssetBundleRequestAllAssetsWithCancellationSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestAllAssetsWithCancellationSource> pool;
|
||||
AssetBundleRequestAllAssetsWithCancellationSource nextNode;
|
||||
public ref AssetBundleRequestAllAssetsWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleRequestAllAssetsWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestAllAssetsWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
AssetBundleRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||
|
||||
AssetBundleRequestAllAssetsWithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AssetBundleRequestAllAssetsWithCancellationSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
asyncOperation.completed -= continuationAction;
|
||||
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
core.TrySetResult(asyncOperation.allAssets);
|
||||
}
|
||||
}
|
||||
|
||||
public UnityEngine.Object[] GetResult(short token)
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completed = true;
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AssetBundleRequestAllAssetsConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsConfiguredSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestAllAssetsConfiguredSource> pool;
|
||||
AssetBundleRequestAllAssetsConfiguredSource nextNode;
|
||||
public ref AssetBundleRequestAllAssetsConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleRequestAllAssetsConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestAllAssetsConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AssetBundleRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||
|
||||
AssetBundleRequestAllAssetsConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AssetBundleRequestAllAssetsConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
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
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (progress != null)
|
||||
{
|
||||
progress.Report(asyncOperation.progress);
|
||||
}
|
||||
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
core.TrySetResult(asyncOperation.allAssets);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9147caba40da434da95b39709c13784
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,140 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class UnityAsyncExtensions
|
||||
{
|
||||
#region AsyncGPUReadbackRequest
|
||||
|
||||
public static UniTask<AsyncGPUReadbackRequest>.Awaiter GetAwaiter(this AsyncGPUReadbackRequest asyncOperation)
|
||||
{
|
||||
return ToUniTask(asyncOperation).GetAwaiter();
|
||||
}
|
||||
|
||||
public static UniTask<AsyncGPUReadbackRequest> WithCancellation(this AsyncGPUReadbackRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
|
||||
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncGPUReadbackRequestAwaiterConfiguredSource> pool;
|
||||
AsyncGPUReadbackRequestAwaiterConfiguredSource nextNode;
|
||||
public ref AsyncGPUReadbackRequestAwaiterConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncGPUReadbackRequestAwaiterConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncGPUReadbackRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
|
||||
|
||||
AsyncGPUReadbackRequestAwaiterConfiguredSource()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<AsyncGPUReadbackRequest>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncGPUReadbackRequestAwaiterConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public AsyncGPUReadbackRequest GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (asyncOperation.hasError)
|
||||
{
|
||||
core.TrySetException(new Exception("AsyncGPUReadbackRequest.hasError = true"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (asyncOperation.done)
|
||||
{
|
||||
core.TrySetResult(asyncOperation);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98f5fedb44749ab4688674d79126b46a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -24,6 +24,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.CompletedTask;
|
||||
return new UniTask(AsyncOperationWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -31,6 +32,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.CompletedTask;
|
||||
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -78,7 +80,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class AsyncOperationWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationWithCancellationSource> pool;
|
||||
public AsyncOperationWithCancellationSource NextNode { get; set; }
|
||||
AsyncOperationWithCancellationSource nextNode;
|
||||
public ref AsyncOperationWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncOperationWithCancellationSource()
|
||||
{
|
||||
@@ -134,6 +137,12 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
@@ -190,7 +199,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationConfiguredSource> pool;
|
||||
public AsyncOperationConfiguredSource NextNode { get; set; }
|
||||
AsyncOperationConfiguredSource nextNode;
|
||||
public ref AsyncOperationConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncOperationConfiguredSource()
|
||||
{
|
||||
@@ -306,6 +316,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(ResourceRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -313,6 +324,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -364,7 +376,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class ResourceRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestWithCancellationSource>
|
||||
{
|
||||
static TaskPool<ResourceRequestWithCancellationSource> pool;
|
||||
public ResourceRequestWithCancellationSource NextNode { get; set; }
|
||||
ResourceRequestWithCancellationSource nextNode;
|
||||
public ref ResourceRequestWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static ResourceRequestWithCancellationSource()
|
||||
{
|
||||
@@ -420,6 +433,12 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
core.TrySetResult(asyncOperation.asset);
|
||||
}
|
||||
}
|
||||
@@ -480,7 +499,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
|
||||
{
|
||||
static TaskPool<ResourceRequestConfiguredSource> pool;
|
||||
public ResourceRequestConfiguredSource NextNode { get; set; }
|
||||
ResourceRequestConfiguredSource nextNode;
|
||||
public ref ResourceRequestConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static ResourceRequestConfiguredSource()
|
||||
{
|
||||
@@ -589,6 +609,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
#endregion
|
||||
|
||||
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||
#region AssetBundleRequest
|
||||
|
||||
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
|
||||
@@ -600,6 +621,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -607,6 +629,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -658,7 +681,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class AssetBundleRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestWithCancellationSource> pool;
|
||||
public AssetBundleRequestWithCancellationSource NextNode { get; set; }
|
||||
AssetBundleRequestWithCancellationSource nextNode;
|
||||
public ref AssetBundleRequestWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleRequestWithCancellationSource()
|
||||
{
|
||||
@@ -714,6 +738,12 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
core.TrySetResult(asyncOperation.asset);
|
||||
}
|
||||
}
|
||||
@@ -774,7 +804,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestConfiguredSource> pool;
|
||||
public AssetBundleRequestConfiguredSource NextNode { get; set; }
|
||||
AssetBundleRequestConfiguredSource nextNode;
|
||||
public ref AssetBundleRequestConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleRequestConfiguredSource()
|
||||
{
|
||||
@@ -882,7 +913,9 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endif
|
||||
|
||||
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||
#region AssetBundleCreateRequest
|
||||
|
||||
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
|
||||
@@ -894,6 +927,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
|
||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -901,6 +935,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
|
||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
@@ -952,7 +987,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class AssetBundleCreateRequestWithCancellationSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AssetBundleCreateRequestWithCancellationSource> pool;
|
||||
public AssetBundleCreateRequestWithCancellationSource NextNode { get; set; }
|
||||
AssetBundleCreateRequestWithCancellationSource nextNode;
|
||||
public ref AssetBundleCreateRequestWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleCreateRequestWithCancellationSource()
|
||||
{
|
||||
@@ -1008,6 +1044,12 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
core.TrySetResult(asyncOperation.assetBundle);
|
||||
}
|
||||
}
|
||||
@@ -1068,7 +1110,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
|
||||
{
|
||||
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
|
||||
public AssetBundleCreateRequestConfiguredSource NextNode { get; set; }
|
||||
AssetBundleCreateRequestConfiguredSource nextNode;
|
||||
public ref AssetBundleCreateRequestConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleCreateRequestConfiguredSource()
|
||||
{
|
||||
@@ -1176,6 +1219,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endif
|
||||
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
#region UnityWebRequestAsyncOperation
|
||||
@@ -1189,14 +1233,30 @@ namespace Cysharp.Threading.Tasks
|
||||
public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.webRequest);
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.webRequest);
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
@@ -1221,7 +1281,7 @@ namespace Cysharp.Threading.Tasks
|
||||
continuationAction = null;
|
||||
var result = asyncOperation.webRequest;
|
||||
asyncOperation = null;
|
||||
if (result.isHttpError || result.isNetworkError)
|
||||
if (result.IsError())
|
||||
{
|
||||
throw new UnityWebRequestException(result);
|
||||
}
|
||||
@@ -1231,7 +1291,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
var result = asyncOperation.webRequest;
|
||||
asyncOperation = null;
|
||||
if (result.isHttpError || result.isNetworkError)
|
||||
if (result.IsError())
|
||||
{
|
||||
throw new UnityWebRequestException(result);
|
||||
}
|
||||
@@ -1255,7 +1315,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class UnityWebRequestAsyncOperationWithCancellationSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationWithCancellationSource>
|
||||
{
|
||||
static TaskPool<UnityWebRequestAsyncOperationWithCancellationSource> pool;
|
||||
public UnityWebRequestAsyncOperationWithCancellationSource NextNode { get; set; }
|
||||
UnityWebRequestAsyncOperationWithCancellationSource nextNode;
|
||||
public ref UnityWebRequestAsyncOperationWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static UnityWebRequestAsyncOperationWithCancellationSource()
|
||||
{
|
||||
@@ -1311,8 +1372,14 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var result = asyncOperation.webRequest;
|
||||
if (result.isHttpError || result.isNetworkError)
|
||||
if (result.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(result));
|
||||
}
|
||||
@@ -1380,7 +1447,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
|
||||
{
|
||||
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
|
||||
public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; }
|
||||
UnityWebRequestAsyncOperationConfiguredSource nextNode;
|
||||
public ref UnityWebRequestAsyncOperationConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static UnityWebRequestAsyncOperationConfiguredSource()
|
||||
{
|
||||
@@ -1470,7 +1538,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.isHttpError || asyncOperation.webRequest.isNetworkError)
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
|
||||
Func<string, string> ToIUniTaskSourceReturnType = x => (x == "void") ? "IUniTaskSource" : $"IUniTaskSource<{x}>";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsUnityWebRequest = x => x.returnType == "UnityWebRequest";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsAssetBundleModule = x => x.typeName == "AssetBundleRequest" || x.typeName == "AssetBundleCreateRequest";
|
||||
Func<(string typeName, string returnType, string returnField), bool> IsVoid = x => x.returnType == "void";
|
||||
#>
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
@@ -34,8 +36,10 @@ namespace Cysharp.Threading.Tasks
|
||||
public static partial class UnityAsyncExtensions
|
||||
{
|
||||
<# foreach(var t in types) { #>
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
<# } else if(IsAssetBundleModule(t)) { #>
|
||||
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||
<# } #>
|
||||
#region <#= t.typeName #>
|
||||
|
||||
@@ -48,14 +52,38 @@ namespace Cysharp.Threading.Tasks
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<#= IsVoid(t) ? "" : "<" + t.returnType + ">" #>(cancellationToken);
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
<# } else { #>
|
||||
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
|
||||
<# } #>
|
||||
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>WithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<#= IsVoid(t) ? "" : "<" + t.returnType + ">" #>(cancellationToken);
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
<# } else { #>
|
||||
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
|
||||
<# } #>
|
||||
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>ConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
@@ -81,8 +109,8 @@ namespace Cysharp.Threading.Tasks
|
||||
<# if (!IsVoid(t)) { #>
|
||||
var result = <#= $"asyncOperation.{t.returnField}" #>;
|
||||
asyncOperation = null;
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
if (result.isHttpError || result.isNetworkError)
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
if (result.IsError())
|
||||
{
|
||||
throw new UnityWebRequestException(result);
|
||||
}
|
||||
@@ -97,8 +125,8 @@ namespace Cysharp.Threading.Tasks
|
||||
<# if (!IsVoid(t)) { #>
|
||||
var result = <#= $"asyncOperation.{t.returnField}" #>;
|
||||
asyncOperation = null;
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
if (result.isHttpError || result.isNetworkError)
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
if (result.IsError())
|
||||
{
|
||||
throw new UnityWebRequestException(result);
|
||||
}
|
||||
@@ -126,7 +154,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class <#= t.typeName #>WithCancellationSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>WithCancellationSource>
|
||||
{
|
||||
static TaskPool<<#= t.typeName #>WithCancellationSource> pool;
|
||||
public <#= t.typeName #>WithCancellationSource NextNode { get; set; }
|
||||
<#= t.typeName #>WithCancellationSource nextNode;
|
||||
public ref <#= t.typeName #>WithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static <#= t.typeName #>WithCancellationSource()
|
||||
{
|
||||
@@ -182,9 +211,15 @@ namespace Cysharp.Threading.Tasks
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
var result = asyncOperation.webRequest;
|
||||
if (result.isHttpError || result.isNetworkError)
|
||||
if (result.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(result));
|
||||
}
|
||||
@@ -240,7 +275,7 @@ namespace Cysharp.Threading.Tasks
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completed = true;
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
asyncOperation.webRequest.Abort();
|
||||
<# } #>
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -263,7 +298,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>ConfiguredSource>
|
||||
{
|
||||
static TaskPool<<#= t.typeName #>ConfiguredSource> pool;
|
||||
public <#= t.typeName #>ConfiguredSource NextNode { get; set; }
|
||||
<#= t.typeName #>ConfiguredSource nextNode;
|
||||
public ref <#= t.typeName #>ConfiguredSource NextNode => ref nextNode;
|
||||
|
||||
static <#= t.typeName #>ConfiguredSource()
|
||||
{
|
||||
@@ -347,7 +383,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
asyncOperation.webRequest.Abort();
|
||||
<# } #>
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
@@ -361,8 +397,8 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
if (asyncOperation.webRequest.isHttpError || asyncOperation.webRequest.isNetworkError)
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
@@ -391,7 +427,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
#endregion
|
||||
<# if(t.returnType == "UnityWebRequest") { #>
|
||||
<# if(IsUnityWebRequest(t) || IsAssetBundleModule(t)) { #>
|
||||
#endif
|
||||
<# } #>
|
||||
|
||||
|
||||
@@ -296,6 +296,58 @@ namespace Cysharp.Threading.Tasks
|
||||
UniTask<T> OnEndEditAsync();
|
||||
}
|
||||
|
||||
// for TMP_PRO
|
||||
|
||||
public interface IAsyncEndTextSelectionEventHandler<T> : IDisposable
|
||||
{
|
||||
UniTask<T> OnEndTextSelectionAsync();
|
||||
}
|
||||
|
||||
public interface IAsyncTextSelectionEventHandler<T> : IDisposable
|
||||
{
|
||||
UniTask<T> OnTextSelectionAsync();
|
||||
}
|
||||
|
||||
public interface IAsyncDeselectEventHandler<T> : IDisposable
|
||||
{
|
||||
UniTask<T> OnDeselectAsync();
|
||||
}
|
||||
|
||||
public interface IAsyncSelectEventHandler<T> : IDisposable
|
||||
{
|
||||
UniTask<T> OnSelectAsync();
|
||||
}
|
||||
|
||||
public interface IAsyncSubmitEventHandler<T> : IDisposable
|
||||
{
|
||||
UniTask<T> OnSubmitAsync();
|
||||
}
|
||||
|
||||
internal class TextSelectionEventConverter : UnityEvent<(string, int, int)>, IDisposable
|
||||
{
|
||||
readonly UnityEvent<string, int, int> innerEvent;
|
||||
readonly UnityAction<string, int, int> invokeDelegate;
|
||||
|
||||
|
||||
public TextSelectionEventConverter(UnityEvent<string, int, int> unityEvent)
|
||||
{
|
||||
this.innerEvent = unityEvent;
|
||||
this.invokeDelegate = InvokeCore;
|
||||
|
||||
innerEvent.AddListener(invokeDelegate);
|
||||
}
|
||||
|
||||
void InvokeCore(string item1, int item2, int item3)
|
||||
{
|
||||
innerEvent.Invoke(item1, item2, item3);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
innerEvent.RemoveListener(invokeDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
public class AsyncUnityEventHandler : IUniTaskSource, IDisposable, IAsyncClickEventHandler
|
||||
{
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
@@ -402,6 +454,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
public class AsyncUnityEventHandler<T> : IUniTaskSource<T>, IDisposable, IAsyncValueChangedEventHandler<T>, IAsyncEndEditEventHandler<T>
|
||||
, IAsyncEndTextSelectionEventHandler<T>, IAsyncTextSelectionEventHandler<T>, IAsyncDeselectEventHandler<T>, IAsyncSelectEventHandler<T>, IAsyncSubmitEventHandler<T>
|
||||
{
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
@@ -464,6 +517,12 @@ namespace Cysharp.Threading.Tasks
|
||||
registration.Dispose();
|
||||
if (unityEvent != null)
|
||||
{
|
||||
// Dispose inner delegate for TextSelectionEventConverter
|
||||
if (unityEvent is IDisposable disp)
|
||||
{
|
||||
disp.Dispose();
|
||||
}
|
||||
|
||||
unityEvent.RemoveListener(action);
|
||||
}
|
||||
|
||||
@@ -481,6 +540,31 @@ namespace Cysharp.Threading.Tasks
|
||||
return OnInvokeAsync();
|
||||
}
|
||||
|
||||
UniTask<T> IAsyncEndTextSelectionEventHandler<T>.OnEndTextSelectionAsync()
|
||||
{
|
||||
return OnInvokeAsync();
|
||||
}
|
||||
|
||||
UniTask<T> IAsyncTextSelectionEventHandler<T>.OnTextSelectionAsync()
|
||||
{
|
||||
return OnInvokeAsync();
|
||||
}
|
||||
|
||||
UniTask<T> IAsyncDeselectEventHandler<T>.OnDeselectAsync()
|
||||
{
|
||||
return OnInvokeAsync();
|
||||
}
|
||||
|
||||
UniTask<T> IAsyncSelectEventHandler<T>.OnSelectAsync()
|
||||
{
|
||||
return OnInvokeAsync();
|
||||
}
|
||||
|
||||
UniTask<T> IAsyncSubmitEventHandler<T>.OnSubmitAsync()
|
||||
{
|
||||
return OnInvokeAsync();
|
||||
}
|
||||
|
||||
T IUniTaskSource<T>.GetResult(short token)
|
||||
{
|
||||
try
|
||||
@@ -718,6 +802,10 @@ namespace Cysharp.Threading.Tasks
|
||||
TaskTracker.RemoveTracking(this);
|
||||
registration1.Dispose();
|
||||
registration2.Dispose();
|
||||
if (unityEvent is IDisposable disp)
|
||||
{
|
||||
disp.Dispose();
|
||||
}
|
||||
unityEvent.RemoveListener(unityAction);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,65 +237,5 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TMP
|
||||
|
||||
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMPro.TMP_Text text, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||
}
|
||||
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMPro.TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||
{
|
||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, TMPro.TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||
{
|
||||
var repeat = false;
|
||||
BIND_AGAIN:
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool moveNext;
|
||||
try
|
||||
{
|
||||
moveNext = await e.MoveNextAsync();
|
||||
repeat = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
if (rebindOnError && !repeat)
|
||||
{
|
||||
repeat = true;
|
||||
goto BIND_AGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moveNext) return;
|
||||
|
||||
text.text = e.Current;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
|
||||
using System;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public class UnityWebRequestException : Exception
|
||||
{
|
||||
public UnityWebRequest UnityWebRequest { get; }
|
||||
public bool IsNetworkError { get; }
|
||||
public bool IsHttpError { get; }
|
||||
|
||||
public UnityWebRequestException(UnityWebRequest unityWebRequest)
|
||||
: base(unityWebRequest.error + Environment.NewLine + unityWebRequest.downloadHandler.text)
|
||||
{
|
||||
this.UnityWebRequest = unityWebRequest;
|
||||
this.IsNetworkError = unityWebRequest.isNetworkError;
|
||||
this.IsHttpError = unityWebRequest.isHttpError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
|
||||
using System;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public class UnityWebRequestException : Exception
|
||||
{
|
||||
public UnityWebRequest UnityWebRequest { get; }
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
public UnityWebRequest.Result Result { get; }
|
||||
#else
|
||||
public bool IsNetworkError { get; }
|
||||
public bool IsHttpError { get; }
|
||||
#endif
|
||||
public string Error { get; }
|
||||
public string Text { get; }
|
||||
public long ResponseCode { get; }
|
||||
|
||||
string msg;
|
||||
|
||||
public UnityWebRequestException(UnityWebRequest unityWebRequest)
|
||||
{
|
||||
this.UnityWebRequest = unityWebRequest;
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
this.Result = unityWebRequest.result;
|
||||
#else
|
||||
this.IsNetworkError = unityWebRequest.isNetworkError;
|
||||
this.IsHttpError = unityWebRequest.isHttpError;
|
||||
#endif
|
||||
this.Error = unityWebRequest.error;
|
||||
this.ResponseCode = unityWebRequest.responseCode;
|
||||
if (UnityWebRequest.downloadHandler != null)
|
||||
{
|
||||
if (unityWebRequest.downloadHandler is DownloadHandlerBuffer dhb)
|
||||
{
|
||||
this.Text = dhb.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
if (Text != null)
|
||||
{
|
||||
msg = Error + Environment.NewLine + Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = Error;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("UniTask.Linq")]
|
||||
[assembly: InternalsVisibleTo("UniTask.Linq")]
|
||||
[assembly: InternalsVisibleTo("UniTask.Addressables")]
|
||||
[assembly: InternalsVisibleTo("UniTask.DOTween")]
|
||||
[assembly: InternalsVisibleTo("UniTask.TextMeshPro")]
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "com.cysharp.unitask",
|
||||
"displayName": "UniTask",
|
||||
"version": "2.0.19",
|
||||
"version": "2.0.34",
|
||||
"unity": "2018.4",
|
||||
"description": "Provides an efficient async/await integration to Unity.",
|
||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||
|
||||
@@ -1,28 +1,58 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
// using UnityEngine.AddressableAssets;
|
||||
|
||||
/*UNniTastWhenAnyTester*/
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class ExceptionExamples : MonoBehaviour
|
||||
{
|
||||
|
||||
private void Start()
|
||||
public bool apply = false;
|
||||
|
||||
private async UniTaskVoid Update()
|
||||
{
|
||||
|
||||
//TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||
|
||||
//ThrowFromAsyncVoid();
|
||||
//_ = ThrowFromTask();
|
||||
//_ = ThrowFromUniTask();
|
||||
|
||||
//ThrowFromNonAsync();
|
||||
if (apply)
|
||||
{
|
||||
apply = false;
|
||||
await LaunchTasksAndDetectWhenAnyDone(5);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task Test()
|
||||
private async UniTask LaunchTasksAndDetectWhenAnyDone(int nbTasks)
|
||||
{
|
||||
var webRequest = UnityWebRequest.Get("http");
|
||||
var request = webRequest.SendWebRequest();
|
||||
await request;
|
||||
List<UniTask<int>> sleeptasks = new List<UniTask<int>>();
|
||||
for (int i = 0; i < nbTasks; i++)
|
||||
{
|
||||
sleeptasks.Add(SleepAndReturnTrue(i).ToAsyncLazy().Task);
|
||||
}
|
||||
while (sleeptasks.Count > 0)
|
||||
{
|
||||
Debug.Log(DateTime.Now.ToString() + " waiting for " + sleeptasks.Count + " tasks...");
|
||||
try
|
||||
{
|
||||
(int index, int taskID) = await UniTask.WhenAny(sleeptasks);
|
||||
Debug.Log(DateTime.Now.ToString() + " Sleep task " + taskID + " done");
|
||||
sleeptasks.RemoveAt(index);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
//Debug.Log("Error: " + e.Message);
|
||||
//return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask<int> SleepAndReturnTrue(int taskIndex)
|
||||
{
|
||||
await UniTask.Delay(100);
|
||||
return taskIndex;
|
||||
}
|
||||
|
||||
//void AddressablesTest()
|
||||
//{
|
||||
// Addressables.ClearDependencyCacheAsync("key", true);
|
||||
//}
|
||||
}
|
||||
@@ -121,6 +121,149 @@ NavMeshSettings:
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &542336983
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 542336986}
|
||||
- component: {fileID: 542336985}
|
||||
- component: {fileID: 542336984}
|
||||
m_Layer: 0
|
||||
m_Name: EventSystem
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &542336984
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 542336983}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_HorizontalAxis: Horizontal
|
||||
m_VerticalAxis: Vertical
|
||||
m_SubmitButton: Submit
|
||||
m_CancelButton: Cancel
|
||||
m_InputActionsPerSecond: 10
|
||||
m_RepeatDelay: 0.5
|
||||
m_ForceModuleActive: 0
|
||||
--- !u!114 &542336985
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 542336983}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_FirstSelected: {fileID: 0}
|
||||
m_sendNavigationEvents: 1
|
||||
m_DragThreshold: 10
|
||||
--- !u!4 &542336986
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 542336983}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &730559310
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 730559311}
|
||||
- component: {fileID: 730559313}
|
||||
- component: {fileID: 730559312}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &730559311
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 730559310}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1587363385}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &730559312
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 730559310}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 10
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: Button
|
||||
--- !u!222 &730559313
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 730559310}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &735985614
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -152,7 +295,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 329ff620b32b4ef4abdc99884242ee67, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_unobservedExceptionLogType: 0
|
||||
ButtonTest: {fileID: 1587363386}
|
||||
--- !u!81 &735985616
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -214,7 +357,225 @@ Transform:
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Children:
|
||||
- {fileID: 1323586517}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1323586516
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1323586517}
|
||||
- component: {fileID: 1323586520}
|
||||
- component: {fileID: 1323586519}
|
||||
- component: {fileID: 1323586518}
|
||||
m_Layer: 5
|
||||
m_Name: Canvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1323586517
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1323586516}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_Children:
|
||||
- {fileID: 1587363385}
|
||||
m_Father: {fileID: 735985618}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!114 &1323586518
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1323586516}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!114 &1323586519
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1323586516}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_UiScaleMode: 0
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 800, y: 600}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
--- !u!223 &1323586520
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1323586516}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 0
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!1 &1587363384
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1587363385}
|
||||
- component: {fileID: 1587363388}
|
||||
- component: {fileID: 1587363387}
|
||||
- component: {fileID: 1587363386}
|
||||
m_Layer: 5
|
||||
m_Name: Button
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1587363385
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1587363384}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 730559311}
|
||||
m_Father: {fileID: 1323586517}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 160, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1587363386
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1587363384}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 1587363387}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!114 &1587363387
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1587363384}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!222 &1587363388
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1587363384}
|
||||
m_CullTransparentMesh: 0
|
||||
|
||||
471
src/UniTask/Assets/Scenes/MiddlewareSample.cs
Normal file
471
src/UniTask/Assets/Scenes/MiddlewareSample.cs
Normal file
@@ -0,0 +1,471 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Sample
|
||||
{
|
||||
//public class Sample2
|
||||
//{
|
||||
// public Sample2()
|
||||
// {
|
||||
// // デコレーターの詰まったClientを生成(これは一度作ったらフィールドに保存可)
|
||||
// var client = new NetworkClient("http://localhost", TimeSpan.FromSeconds(10),
|
||||
// new QueueRequestDecorator(),
|
||||
// new LoggingDecorator(),
|
||||
// new AppendTokenDecorator(),
|
||||
// new SetupHeaderDecorator());
|
||||
|
||||
|
||||
// await client.PostAsync("/User/Register", new { Id = 100 });
|
||||
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
public class ReturnToTitleDecorator : IAsyncDecorator
|
||||
{
|
||||
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await next(context, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException)
|
||||
{
|
||||
// キャンセルはきっと想定されている処理なのでそのまんまスルー(呼び出し側でOperationCanceledExceptionとして飛んでいく)
|
||||
throw;
|
||||
}
|
||||
|
||||
if (ex is UnityWebRequestException uwe)
|
||||
{
|
||||
// ステータスコードを使って、タイトルに戻す例外です、とかリトライさせる例外です、とかハンドリングさせると便利
|
||||
// if (uwe.ResponseCode) { }...
|
||||
}
|
||||
|
||||
// サーバー例外のMessageを直接出すなんて乱暴なことはデバッグ時だけですよ勿論。
|
||||
var result = await MessageDialog.ShowAsync(ex.Message);
|
||||
|
||||
// OK か Cancelかで分岐するなら。今回はボタン一個、OKのみの想定なので無視
|
||||
// if (result == DialogResult.Ok) { }...
|
||||
|
||||
// シーン呼び出しはawaitしないこと!awaitして正常終了しちゃうと、この通信の呼び出し元に処理が戻って続行してしまいます
|
||||
// のでForget。
|
||||
SceneManager.LoadSceneAsync("TitleScene").ToUniTask().Forget();
|
||||
|
||||
|
||||
// そしてOperationCanceledExceptionを投げて、この通信の呼び出し元の処理はキャンセル扱いにして終了させる
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DialogResult
|
||||
{
|
||||
Ok,
|
||||
Cancel
|
||||
}
|
||||
|
||||
public static class MessageDialog
|
||||
{
|
||||
public static async UniTask<DialogResult> ShowAsync(string message)
|
||||
{
|
||||
// (例えば)Prefabで作っておいたダイアログを生成する
|
||||
var view = await Resources.LoadAsync("Prefabs/Dialog");
|
||||
|
||||
// Ok, Cancelボタンのどちらかが押されるのを待機
|
||||
return await (view as GameObject).GetComponent<MessageDialogView>().ClickResult;
|
||||
}
|
||||
}
|
||||
|
||||
public class MessageDialogView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] Button okButton = default;
|
||||
[SerializeField] Button closeButton = default;
|
||||
|
||||
UniTaskCompletionSource<DialogResult> taskCompletion;
|
||||
|
||||
// これでどちらかが押されるまで無限に待つを表現
|
||||
public UniTask<DialogResult> ClickResult => taskCompletion.Task;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
taskCompletion = new UniTaskCompletionSource<DialogResult>();
|
||||
|
||||
okButton.onClick.AddListener(() =>
|
||||
{
|
||||
taskCompletion.TrySetResult(DialogResult.Ok);
|
||||
});
|
||||
|
||||
closeButton.onClick.AddListener(() =>
|
||||
{
|
||||
taskCompletion.TrySetResult(DialogResult.Cancel);
|
||||
});
|
||||
}
|
||||
|
||||
// もしボタンが押されずに消滅した場合にネンノタメ。
|
||||
private void OnDestroy()
|
||||
{
|
||||
taskCompletion.TrySetResult(DialogResult.Cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public class MockDecorator : IAsyncDecorator
|
||||
{
|
||||
Dictionary<string, object> mock;
|
||||
|
||||
// Pathと型を1:1にして事前定義したオブジェクトを返す辞書を渡す
|
||||
public MockDecorator(Dictionary<string, object> mock)
|
||||
{
|
||||
this.mock = mock;
|
||||
}
|
||||
|
||||
public UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||
{
|
||||
if (mock.TryGetValue(context.Path, out var value))
|
||||
{
|
||||
// 一致したものがあればそれを返す(実際の通信は行わない)
|
||||
return new UniTask<ResponseContext>(new ResponseContext(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
return next(context, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LoggingDecorator : IAsyncDecorator
|
||||
{
|
||||
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
try
|
||||
{
|
||||
UnityEngine.Debug.Log("Start Network Request:" + context.Path);
|
||||
|
||||
var response = await next(context, cancellationToken);
|
||||
|
||||
UnityEngine.Debug.Log($"Complete Network Request: {context.Path} , Elapsed: {sw.Elapsed}, Size: {response.GetRawData().Length}");
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException)
|
||||
{
|
||||
UnityEngine.Debug.Log("Request Canceled:" + context.Path);
|
||||
}
|
||||
else if (ex is TimeoutException)
|
||||
{
|
||||
UnityEngine.Debug.Log("Request Timeout:" + context.Path);
|
||||
}
|
||||
else if (ex is UnityWebRequestException webex)
|
||||
{
|
||||
if (webex.IsHttpError)
|
||||
{
|
||||
UnityEngine.Debug.Log($"Request HttpError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}");
|
||||
}
|
||||
else if (webex.IsNetworkError)
|
||||
{
|
||||
UnityEngine.Debug.Log($"Request NetworkError: {context.Path} Code:{webex.ResponseCode} Message:{webex.Message}");
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
/* log other */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SetupHeaderDecorator : IAsyncDecorator
|
||||
{
|
||||
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||
{
|
||||
context.RequestHeaders["x-app-timestamp"] = context.Timestamp.ToString();
|
||||
context.RequestHeaders["x-user-id"] = "132141411"; // どこかから持ってくる
|
||||
context.RequestHeaders["x-access-token"] = "fafafawfafewaea"; // どこかから持ってくる2
|
||||
|
||||
var respsonse = await next(context, cancellationToken);
|
||||
|
||||
var nextToken = respsonse.ResponseHeaders["token"];
|
||||
// UserProfile.Token = nextToken; // どこかにセットするということにする
|
||||
|
||||
return respsonse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class AppendTokenDecorator : IAsyncDecorator
|
||||
{
|
||||
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||
{
|
||||
string token = "token"; // どっかから取ってくるということにする
|
||||
RETRY:
|
||||
try
|
||||
{
|
||||
context.RequestHeaders["x-accesss-token"] = token;
|
||||
return await next(context, cancellationToken);
|
||||
}
|
||||
catch (UnityWebRequestException ex)
|
||||
{
|
||||
// 例えば700はTokenを再取得してください的な意味だったとする
|
||||
if (ex.ResponseCode == 700)
|
||||
{
|
||||
// 別口でTokenを取得します的な処理
|
||||
var newToken = await new NetworkClient(context.BasePath, context.Timeout).PostAsync<string>("/Auth/GetToken", "access_token", cancellationToken);
|
||||
context.Reset(this);
|
||||
goto RETRY;
|
||||
}
|
||||
|
||||
goto RETRY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class QueueRequestDecorator : IAsyncDecorator
|
||||
{
|
||||
readonly Queue<(UniTaskCompletionSource<ResponseContext>, RequestContext, CancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>>)> q = new Queue<(UniTaskCompletionSource<ResponseContext>, RequestContext, CancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>>)>();
|
||||
bool running;
|
||||
|
||||
public async UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next)
|
||||
{
|
||||
if (q.Count == 0)
|
||||
{
|
||||
return await next(context, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
var completionSource = new UniTaskCompletionSource<ResponseContext>();
|
||||
q.Enqueue((completionSource, context, cancellationToken, next));
|
||||
if (!running)
|
||||
{
|
||||
Run().Forget();
|
||||
}
|
||||
return await completionSource.Task;
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid Run()
|
||||
{
|
||||
running = true;
|
||||
try
|
||||
{
|
||||
while (q.Count != 0)
|
||||
{
|
||||
var (tcs, context, cancellationToken, next) = q.Dequeue();
|
||||
try
|
||||
{
|
||||
var response = await next(context, cancellationToken);
|
||||
tcs.TrySetResult(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class RequestContext
|
||||
{
|
||||
int decoratorIndex;
|
||||
readonly IAsyncDecorator[] decorators;
|
||||
Dictionary<string, string> headers;
|
||||
|
||||
public string BasePath { get; }
|
||||
public string Path { get; }
|
||||
public object Value { get; }
|
||||
public TimeSpan Timeout { get; }
|
||||
public DateTimeOffset Timestamp { get; private set; }
|
||||
|
||||
public IDictionary<string, string> RequestHeaders
|
||||
{
|
||||
get
|
||||
{
|
||||
if (headers == null)
|
||||
{
|
||||
headers = new Dictionary<string, string>();
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
public RequestContext(string basePath, string path, object value, TimeSpan timeout, IAsyncDecorator[] filters)
|
||||
{
|
||||
this.decoratorIndex = -1;
|
||||
this.decorators = filters;
|
||||
this.BasePath = basePath;
|
||||
this.Path = path;
|
||||
this.Value = value;
|
||||
this.Timeout = timeout;
|
||||
this.Timestamp = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
internal Dictionary<string, string> GetRawHeaders() => headers;
|
||||
internal IAsyncDecorator GetNextDecorator() => decorators[++decoratorIndex];
|
||||
|
||||
public void Reset(IAsyncDecorator currentFilter)
|
||||
{
|
||||
decoratorIndex = Array.IndexOf(decorators, currentFilter);
|
||||
if (headers != null)
|
||||
{
|
||||
headers.Clear();
|
||||
}
|
||||
Timestamp = DateTimeOffset.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
public class ResponseContext
|
||||
{
|
||||
bool hasValue;
|
||||
object value;
|
||||
readonly byte[] bytes;
|
||||
|
||||
public long StatusCode { get; }
|
||||
public Dictionary<string, string> ResponseHeaders { get; }
|
||||
|
||||
public ResponseContext(object value, Dictionary<string, string> header = null)
|
||||
{
|
||||
this.hasValue = true;
|
||||
this.value = value;
|
||||
this.StatusCode = 200;
|
||||
this.ResponseHeaders = (header ?? new Dictionary<string, string>());
|
||||
}
|
||||
|
||||
public ResponseContext(byte[] bytes, long statusCode, Dictionary<string, string> responseHeaders)
|
||||
{
|
||||
this.hasValue = false;
|
||||
this.bytes = bytes;
|
||||
this.StatusCode = statusCode;
|
||||
this.ResponseHeaders = responseHeaders;
|
||||
}
|
||||
|
||||
public byte[] GetRawData() => bytes;
|
||||
|
||||
public T GetResponseAs<T>()
|
||||
{
|
||||
if (hasValue)
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
|
||||
value = JsonUtility.FromJson<T>(Encoding.UTF8.GetString(bytes));
|
||||
hasValue = true;
|
||||
return (T)value;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAsyncDecorator
|
||||
{
|
||||
UniTask<ResponseContext> SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next);
|
||||
}
|
||||
|
||||
|
||||
public class NetworkClient : IAsyncDecorator
|
||||
{
|
||||
readonly Func<RequestContext, CancellationToken, UniTask<ResponseContext>> next;
|
||||
readonly IAsyncDecorator[] decorators;
|
||||
readonly TimeSpan timeout;
|
||||
readonly IProgress<float> progress;
|
||||
readonly string basePath;
|
||||
|
||||
public NetworkClient(string basePath, TimeSpan timeout, params IAsyncDecorator[] decorators)
|
||||
: this(basePath, timeout, null, decorators)
|
||||
{
|
||||
}
|
||||
|
||||
public NetworkClient(string basePath, TimeSpan timeout, IProgress<float> progress, params IAsyncDecorator[] decorators)
|
||||
{
|
||||
this.next = InvokeRecursive; // setup delegate
|
||||
|
||||
this.basePath = basePath;
|
||||
this.timeout = timeout;
|
||||
this.progress = progress;
|
||||
this.decorators = new IAsyncDecorator[decorators.Length + 1];
|
||||
Array.Copy(decorators, this.decorators, decorators.Length);
|
||||
this.decorators[this.decorators.Length - 1] = this;
|
||||
}
|
||||
|
||||
public async UniTask<T> PostAsync<T>(string path, T value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new RequestContext(basePath, path, value, timeout, decorators);
|
||||
var response = await InvokeRecursive(request, cancellationToken);
|
||||
return response.GetResponseAs<T>();
|
||||
}
|
||||
|
||||
|
||||
UniTask<ResponseContext> InvokeRecursive(RequestContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
return context.GetNextDecorator().SendAsync(context, cancellationToken, next); // マジカル再帰処理
|
||||
}
|
||||
|
||||
async UniTask<ResponseContext> IAsyncDecorator.SendAsync(RequestContext context, CancellationToken cancellationToken, Func<RequestContext, CancellationToken, UniTask<ResponseContext>> _)
|
||||
{
|
||||
// Postしか興味ないからPostにしかしないよ!
|
||||
// パフォーマンスを最大限にしたい場合はuploadHandler, downloadHandlerをカスタマイズすること
|
||||
|
||||
// JSONでbodyに送るというパラメータで送るという雑設定。
|
||||
var data = JsonUtility.ToJson(context.Value);
|
||||
var formData = new Dictionary<string, string> { { "body", data } };
|
||||
|
||||
using (var req = UnityWebRequest.Post(basePath + context.Path, formData))
|
||||
{
|
||||
var header = context.GetRawHeaders();
|
||||
if (header != null)
|
||||
{
|
||||
foreach (var item in header)
|
||||
{
|
||||
req.SetRequestHeader(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// Timeout処理はCancellationTokenSourceのCancelAfterSlim(UniTask拡張)を使ってサクッと処理
|
||||
var linkToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
linkToken.CancelAfterSlim(timeout);
|
||||
try
|
||||
{
|
||||
// 完了待ちや終了処理はUniTaskの拡張自体に丸投げ
|
||||
await req.SendWebRequest().ToUniTask(progress: progress, cancellationToken: linkToken.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 元キャンセレーションソースがキャンセルしてなければTimeoutによるものと判定
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Timeoutに引っかからなかった場合にてるのでCancelAfterSlimの裏で回ってるループをこれで終わらせとく
|
||||
if (!linkToken.IsCancellationRequested)
|
||||
{
|
||||
linkToken.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// UnityWebRequestを先にDisposeしちゃうので先に必要なものを取得しておく(性能的には無駄なのでパフォーマンスを最大限にしたい場合は更に一工夫を)
|
||||
return new ResponseContext(req.downloadHandler.data, req.responseCode, req.GetResponseHeaders());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/UniTask/Assets/Scenes/MiddlewareSample.cs.meta
Normal file
11
src/UniTask/Assets/Scenes/MiddlewareSample.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fc39a4b35a8db44592cddc0b365942f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -15,6 +15,10 @@ using UnityEngine.LowLevel;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.Rendering;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using Cysharp.Threading.Tasks.Sample;
|
||||
|
||||
|
||||
// using DG.Tweening;
|
||||
@@ -117,6 +121,8 @@ public class AsyncMessageBroker<T> : IDisposable
|
||||
|
||||
public class SandboxMain : MonoBehaviour
|
||||
{
|
||||
public Camera mycamera;
|
||||
|
||||
public Button okButton;
|
||||
public Button cancelButton;
|
||||
|
||||
@@ -129,6 +135,7 @@ public class SandboxMain : MonoBehaviour
|
||||
UniTaskCompletionSource ucs;
|
||||
async UniTask<int> FooAsync()
|
||||
{
|
||||
|
||||
// use F10, will crash.
|
||||
var loop = int.Parse("9");
|
||||
await UniTask.DelayFrame(loop);
|
||||
@@ -161,6 +168,9 @@ public class SandboxMain : MonoBehaviour
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//setHp = Hp.GetSetter();
|
||||
}
|
||||
|
||||
@@ -178,15 +188,14 @@ public class SandboxMain : MonoBehaviour
|
||||
public Button button;
|
||||
|
||||
|
||||
void Start2()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async UniTask RunStandardDelayAsync()
|
||||
{
|
||||
|
||||
|
||||
|
||||
UnityEngine.Debug.Log("DEB");
|
||||
|
||||
await UniTask.DelayFrame(30);
|
||||
@@ -217,6 +226,11 @@ public class SandboxMain : MonoBehaviour
|
||||
async UniTaskVoid Update2()
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UnityEngine.Debug.Log("async linq!");
|
||||
|
||||
await UniTaskAsyncEnumerable.Range(1, 10)
|
||||
@@ -435,12 +449,60 @@ public class SandboxMain : MonoBehaviour
|
||||
}
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
_ = Foo(); // unhandled.
|
||||
Go();
|
||||
|
||||
UnityEngine.Debug.Log("Start:" + PlayerLoopInfo.CurrentLoopType);
|
||||
|
||||
async void Nanika()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
Debug.Log("Here");
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// PlayerLoopInfo.Inject();
|
||||
PrepareCamera();
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerable<int> MyEveryUpdate()
|
||||
{
|
||||
return UniTaskAsyncEnumerable.Create<int>(async (writer, token) =>
|
||||
{
|
||||
var frameCount = 0;
|
||||
await UniTask.Yield();
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
await writer.YieldAsync(frameCount++); // instead of `yield return`
|
||||
await UniTask.Yield();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async void RunStandardTaskAsync()
|
||||
{
|
||||
Debug.Log("Wait 3 seconds");
|
||||
await Task.Delay(TimeSpan.FromSeconds(3));
|
||||
|
||||
Debug.Log("Current SyncContext:" + SynchronizationContext.Current.GetType().FullName);
|
||||
}
|
||||
|
||||
async UniTaskVoid Start()
|
||||
{
|
||||
//Expression.Lambda<Func<int>>(null).Compile(true);
|
||||
|
||||
//RunStandardTaskAsync();
|
||||
|
||||
//UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
||||
|
||||
//var url = "http://google.com/404";
|
||||
//var webRequestAsyncOperation = UnityWebRequest.Get(url).SendWebRequest();
|
||||
//await webRequestAsyncOperation.ToUniTask();
|
||||
|
||||
//PlayerLoopInfo.Inject();
|
||||
|
||||
@@ -458,11 +520,30 @@ public class SandboxMain : MonoBehaviour
|
||||
//var cts = new CancellationTokenSource();
|
||||
|
||||
|
||||
// UniTask.Post(
|
||||
|
||||
// CancellationToken.
|
||||
|
||||
//UniTask.Delay(TimeSpan.FromSeconds(3)).
|
||||
|
||||
|
||||
|
||||
//okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||
//{
|
||||
|
||||
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||
{
|
||||
|
||||
var client = new NetworkClient("http://localhost:5000", TimeSpan.FromSeconds(2),
|
||||
new QueueRequestDecorator(),
|
||||
new LoggingDecorator());
|
||||
//new AppendTokenDecorator(),
|
||||
//new SetupHeaderDecorator());
|
||||
|
||||
|
||||
await client.PostAsync("", new { Id = 100 });
|
||||
|
||||
|
||||
}));
|
||||
|
||||
// _ = ExecuteAsync();
|
||||
|
||||
// await UniTask.Yield();
|
||||
@@ -643,7 +724,9 @@ public class SandboxMain : MonoBehaviour
|
||||
|
||||
//StartCoroutine(Coroutine());
|
||||
|
||||
//await UniTask.Delay(TimeSpan.FromSeconds(1));
|
||||
// PlayerLoopInfo.Inject();
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(1));
|
||||
PlayerLoopInfo.DumpPlayerLoop("current", PlayerLoop.GetCurrentPlayerLoop());
|
||||
|
||||
|
||||
// _ = ReturnToMainThreadTest();
|
||||
@@ -950,9 +1033,76 @@ public class SandboxMain : MonoBehaviour
|
||||
// e.SetObserved();
|
||||
// or other custom write code.
|
||||
UnityEngine.Debug.LogError("Unobserved:" + e.Exception.ToString());
|
||||
}
|
||||
|
||||
|
||||
// GPU Screenshot Sample
|
||||
|
||||
void PrepareCamera()
|
||||
{
|
||||
//Debug.Log("Support AsyncGPUReadback:" + SystemInfo.supportsAsyncGPUReadback);
|
||||
|
||||
//var width = 480;
|
||||
//var height = 240;
|
||||
//var depth = 24;
|
||||
|
||||
//mycamera.targetTexture = new RenderTexture(width, height, depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default)
|
||||
//{
|
||||
// antiAliasing = 8
|
||||
//};
|
||||
//mycamera.enabled = true;
|
||||
|
||||
//myRenderTexture = new RenderTexture(width, height, depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default)
|
||||
//{
|
||||
// antiAliasing = 8
|
||||
//};
|
||||
}
|
||||
|
||||
RenderTexture myRenderTexture;
|
||||
|
||||
async UniTask ShootAsync()
|
||||
{
|
||||
var rt = mycamera.targetTexture;
|
||||
|
||||
|
||||
|
||||
var req = await AsyncGPUReadback.Request(rt, 0);
|
||||
|
||||
Debug.Log("GPU Readback done?:" + req.done);
|
||||
|
||||
var rawByteArray = req.GetData<byte>().ToArray();
|
||||
var graphicsFormat = rt.graphicsFormat;
|
||||
var width = (uint)rt.width;
|
||||
var height = (uint)rt.height;
|
||||
|
||||
Debug.Log("BytesSize:" + rawByteArray.Length);
|
||||
|
||||
|
||||
var imageBytes = ImageConversion.EncodeArrayToPNG(rawByteArray, graphicsFormat, width, height);
|
||||
|
||||
|
||||
File.WriteAllBytes("my_screenshot.png", imageBytes); // test
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SyncContextInjecter
|
||||
{
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void Inject()
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new UniTaskSynchronizationContext());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class PlayerLoopInfo
|
||||
{
|
||||
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
@@ -987,7 +1137,7 @@ public class PlayerLoopInfo
|
||||
|
||||
public static Type CurrentLoopType { get; private set; }
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void Inject()
|
||||
{
|
||||
var system = PlayerLoop.GetCurrentPlayerLoop();
|
||||
|
||||
@@ -239,6 +239,80 @@ CanvasRenderer:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 16537670}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!1 &518730348
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 518730350}
|
||||
- component: {fileID: 518730349}
|
||||
m_Layer: 0
|
||||
m_Name: Camera
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!20 &518730349
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 518730348}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &518730350
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 518730348}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 488, y: 418, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &519420028
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -278,9 +352,11 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
camera: {fileID: 518730349}
|
||||
okButton: {fileID: 16537672}
|
||||
cancelButton: {fileID: 628393011}
|
||||
text: {fileID: 2101290655}
|
||||
button: {fileID: 0}
|
||||
--- !u!20 &519420031
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -597,7 +673,7 @@ Transform:
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1556045504
|
||||
GameObject:
|
||||
@@ -693,7 +769,7 @@ RectTransform:
|
||||
- {fileID: 628393010}
|
||||
- {fileID: 2101290654}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 2
|
||||
m_RootOrder: 3
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
|
||||
8
src/UniTask/Assets/TempAsm.meta
Normal file
8
src/UniTask/Assets/TempAsm.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56fb2352cb532934f82d1590ce377e5c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
27
src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs
Normal file
27
src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
public class FooMonoBehaviour : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async UniTask Download(UnityWebRequest req, string filePath)
|
||||
{
|
||||
var foo = req.SendWebRequest();
|
||||
|
||||
|
||||
|
||||
|
||||
var aaa = await foo;
|
||||
Debug.Log(aaa);
|
||||
|
||||
//File.WriteAllText(filePath, req.downloadHandler.text ?? string.Empty);
|
||||
}
|
||||
}
|
||||
11
src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs.meta
Normal file
11
src/UniTask/Assets/TempAsm/FooMonoBehaviour.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de703bd72a8720b47b7c3d993786aaae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
src/UniTask/Assets/TempAsm/TempAsm.asmdef
Normal file
16
src/UniTask/Assets/TempAsm/TempAsm.asmdef
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "TempAsm",
|
||||
"references": [
|
||||
"UniTask",
|
||||
""
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
src/UniTask/Assets/TempAsm/TempAsm.asmdef.meta
Normal file
7
src/UniTask/Assets/TempAsm/TempAsm.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d076e9cb44bf59e41ab73add08e510cf
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
192
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs
Normal file
192
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.Scripting;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Collections;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.TestTools;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Cysharp.Threading.TasksTests
|
||||
{
|
||||
public class CoroutineToUniTaskTest
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator EarlyUpdate() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.EarlyUpdate);
|
||||
|
||||
var l = new List<(int, int)>();
|
||||
var currentFrame = Time.frameCount;
|
||||
var t = Worker(l).ToUniTask();
|
||||
|
||||
l.Count.Should().Be(1);
|
||||
l[0].Should().Be((0, currentFrame));
|
||||
|
||||
await t;
|
||||
|
||||
l[1].Should().Be((1, Time.frameCount));
|
||||
l[1].Item2.Should().NotBe(currentFrame);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator LateUpdate() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
|
||||
var l = new List<(int, int)>();
|
||||
var currentFrame = Time.frameCount;
|
||||
var t = Worker(l).ToUniTask();
|
||||
|
||||
l.Count.Should().Be(1);
|
||||
l[0].Should().Be((0, currentFrame));
|
||||
|
||||
await t;
|
||||
|
||||
l[1].Should().Be((1, Time.frameCount));
|
||||
l[1].Item2.Should().NotBe(currentFrame);
|
||||
});
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TestCoroutine()
|
||||
//{
|
||||
// yield return UniTask.Yield(PlayerLoopTiming.EarlyUpdate).ToUniTask().ToCoroutine();
|
||||
|
||||
// var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour));
|
||||
|
||||
// var l = new List<(int, int)>();
|
||||
// var currentFrame = Time.frameCount;
|
||||
// var t = nanika.StartCoroutine(Worker(l));
|
||||
|
||||
// l.Count.Should().Be(1);
|
||||
// l[0].Should().Be((0, currentFrame));
|
||||
|
||||
// yield return t;
|
||||
|
||||
// l[1].Should().Be((1, Time.frameCount));
|
||||
// l[1].Item2.Should().NotBe(currentFrame);
|
||||
//}
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TestCoroutine2()
|
||||
//{
|
||||
// yield return UniTask.Yield(PlayerLoopTiming.PostLateUpdate).ToUniTask().ToCoroutine();
|
||||
|
||||
// var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour));
|
||||
|
||||
// var l = new List<(int, int)>();
|
||||
// var currentFrame = Time.frameCount;
|
||||
// var t = nanika.StartCoroutine(Worker(l));
|
||||
|
||||
// l.Count.Should().Be(1);
|
||||
// l[0].Should().Be((0, currentFrame));
|
||||
|
||||
// yield return t;
|
||||
|
||||
// l[1].Should().Be((1, Time.frameCount));
|
||||
// l[1].Item2.Should().NotBe(currentFrame);
|
||||
//}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ImmediateRunTest() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var l = new List<int>();
|
||||
var x1 = Immediate(l);
|
||||
var x2 = Immediate(l);
|
||||
var x3 = DelayOne(l);
|
||||
|
||||
var t1 = x1.ToUniTask();
|
||||
CollectionAssert.AreEqual(l, new[] { 1, 2, 3 });
|
||||
await t1;
|
||||
|
||||
var t2 = x2.ToUniTask();
|
||||
CollectionAssert.AreEqual(l, new[] { 1, 2, 3, 1, 2, 3 });
|
||||
|
||||
var t3 = x3.ToUniTask();
|
||||
CollectionAssert.AreEqual(l, new[] { 1, 2, 3, 1, 2, 3, 10 });
|
||||
|
||||
await UniTask.WhenAll(t2, t3);
|
||||
CollectionAssert.AreEqual(l, new[] { 1, 2, 3, 1, 2, 3, 10, 20, 30 });
|
||||
|
||||
});
|
||||
|
||||
IEnumerator Immediate(List<int> l)
|
||||
{
|
||||
l.Add(1);
|
||||
l.Add(2);
|
||||
l.Add(3);
|
||||
yield break;
|
||||
}
|
||||
|
||||
IEnumerator DelayOne(List<int> l)
|
||||
{
|
||||
l.Add(10);
|
||||
yield return null;
|
||||
l.Add(20);
|
||||
l.Add(30);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WaitForSecondsTest() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
|
||||
Time.timeScale = 0.5f;
|
||||
try
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
await WaitFor();
|
||||
|
||||
var elapsed = DateTimeOffset.UtcNow - now;
|
||||
|
||||
(5.8f <= elapsed.TotalSeconds && elapsed.TotalSeconds <= 6.2f).Should().BeTrue();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Time.timeScale = 1.0f;
|
||||
}
|
||||
});
|
||||
|
||||
IEnumerator WaitFor()
|
||||
{
|
||||
yield return new WaitForSeconds(3.0f);
|
||||
}
|
||||
|
||||
IEnumerator Worker(List<(int, int)> l)
|
||||
{
|
||||
l.Add((0, Time.frameCount));
|
||||
yield return null;
|
||||
l.Add((1, Time.frameCount));
|
||||
}
|
||||
|
||||
public async UniTask Foo()
|
||||
{
|
||||
var tasks = new List<UniTask>();
|
||||
var t = Bar<int>();
|
||||
tasks.Add(t);
|
||||
|
||||
t = Bar<int>();
|
||||
tasks.Add(t);
|
||||
|
||||
await UniTask.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public async UniTask<T> Bar<T>()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
11
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta
Normal file
11
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43ffb719370515746932af3732ce073e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -16,164 +16,164 @@ namespace Cysharp.Threading.TasksTests
|
||||
{
|
||||
public class DelayTest
|
||||
{
|
||||
//[UnityTest]
|
||||
//public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// for (int i = 1; i < 5; i++)
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var frameCount = Time.frameCount;
|
||||
// await UniTask.DelayFrame(i);
|
||||
// Time.frameCount.Should().Be(frameCount + i);
|
||||
// }
|
||||
[UnityTest]
|
||||
public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
for (int i = 1; i < 5; i++)
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var frameCount = Time.frameCount;
|
||||
await UniTask.DelayFrame(i);
|
||||
Time.frameCount.Should().Be(frameCount + i);
|
||||
}
|
||||
|
||||
// for (int i = 1; i < 5; i++)
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
// var frameCount = Time.frameCount;
|
||||
// await UniTask.DelayFrame(i);
|
||||
// Time.frameCount.Should().Be(frameCount + i);
|
||||
// }
|
||||
//});
|
||||
for (int i = 1; i < 5; i++)
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
var frameCount = Time.frameCount;
|
||||
await UniTask.DelayFrame(i);
|
||||
Time.frameCount.Should().Be(frameCount + i);
|
||||
}
|
||||
});
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var frameCount = Time.frameCount;
|
||||
// await UniTask.DelayFrame(0);
|
||||
// Time.frameCount.Should().Be(frameCount); // same frame
|
||||
// }
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
// var frameCount = Time.frameCount;
|
||||
// await UniTask.DelayFrame(0);
|
||||
// Time.frameCount.Should().Be(frameCount + 1); // next frame
|
||||
// }
|
||||
//});
|
||||
[UnityTest]
|
||||
public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var frameCount = Time.frameCount;
|
||||
await UniTask.DelayFrame(0);
|
||||
Time.frameCount.Should().Be(frameCount); // same frame
|
||||
}
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
var frameCount = Time.frameCount;
|
||||
await UniTask.DelayFrame(0);
|
||||
Time.frameCount.Should().Be(frameCount + 1); // next frame
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
[UnityTest]
|
||||
public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
|
||||
// xs[0].Should().Be(initialFrame + 2);
|
||||
// xs[1].Should().Be(initialFrame + 2 + (3 * 1));
|
||||
// xs[2].Should().Be(initialFrame + 2 + (3 * 2));
|
||||
// xs[3].Should().Be(initialFrame + 2 + (3 * 3));
|
||||
// xs[4].Should().Be(initialFrame + 2 + (3 * 4));
|
||||
//});
|
||||
xs[0].Should().Be(initialFrame + 2);
|
||||
xs[1].Should().Be(initialFrame + 2 + (3 * 1));
|
||||
xs[2].Should().Be(initialFrame + 2 + (3 * 2));
|
||||
xs[3].Should().Be(initialFrame + 2 + (3 * 3));
|
||||
xs[4].Should().Be(initialFrame + 2 + (3 * 4));
|
||||
});
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
[UnityTest]
|
||||
public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
|
||||
// xs[0].Should().Be(initialFrame + 2);
|
||||
// xs[1].Should().Be(initialFrame + 2 + (3 * 1));
|
||||
// xs[2].Should().Be(initialFrame + 2 + (3 * 2));
|
||||
// xs[3].Should().Be(initialFrame + 2 + (3 * 3));
|
||||
// xs[4].Should().Be(initialFrame + 2 + (3 * 4));
|
||||
//});
|
||||
xs[0].Should().Be(initialFrame + 2);
|
||||
xs[1].Should().Be(initialFrame + 2 + (3 * 1));
|
||||
xs[2].Should().Be(initialFrame + 2 + (3 * 2));
|
||||
xs[3].Should().Be(initialFrame + 2 + (3 * 3));
|
||||
xs[4].Should().Be(initialFrame + 2 + (3 * 4));
|
||||
});
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
[UnityTest]
|
||||
public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
|
||||
// xs[0].Should().Be(initialFrame);
|
||||
// xs[1].Should().Be(initialFrame + 1);
|
||||
// xs[2].Should().Be(initialFrame + 2);
|
||||
// xs[3].Should().Be(initialFrame + 3);
|
||||
// xs[4].Should().Be(initialFrame + 4);
|
||||
//});
|
||||
xs[0].Should().Be(initialFrame);
|
||||
xs[1].Should().Be(initialFrame + 1);
|
||||
xs[2].Should().Be(initialFrame + 2);
|
||||
xs[3].Should().Be(initialFrame + 3);
|
||||
xs[4].Should().Be(initialFrame + 4);
|
||||
});
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
// xs[0].Should().Be(initialFrame);
|
||||
[UnityTest]
|
||||
public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
xs[0].Should().Be(initialFrame);
|
||||
|
||||
// }
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
}
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ =>
|
||||
// {
|
||||
// var t = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ =>
|
||||
{
|
||||
var t = Time.frameCount;
|
||||
|
||||
// return t;
|
||||
// }).ToArrayAsync();
|
||||
return t;
|
||||
}).ToArrayAsync();
|
||||
|
||||
// xs[0].Should().Be(initialFrame + 1);
|
||||
// }
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
// xs[0].Should().Be(initialFrame + 2);
|
||||
// }
|
||||
//});
|
||||
xs[0].Should().Be(initialFrame + 1);
|
||||
}
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
xs[0].Should().Be(initialFrame + 2);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// {
|
||||
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
// //var initialFrame = Time.frameCount;
|
||||
// //var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
// //xs[0].Should().Be(initialFrame);
|
||||
// }
|
||||
// {
|
||||
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
// xs[0].Should().Be(initialFrame + 1);
|
||||
// }
|
||||
// {
|
||||
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
// xs[0].Should().Be(initialFrame + 2);
|
||||
// }
|
||||
//});
|
||||
[UnityTest]
|
||||
public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
{
|
||||
//await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
//var initialFrame = Time.frameCount;
|
||||
//var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
//xs[0].Should().Be(initialFrame);
|
||||
}
|
||||
{
|
||||
//await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
xs[0].Should().Be(initialFrame + 1);
|
||||
}
|
||||
{
|
||||
//await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
xs[0].Should().Be(initialFrame + 2);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator Timer() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
[UnityTest]
|
||||
public IEnumerator Timer() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
|
||||
// {
|
||||
// var initialSeconds = Time.realtimeSinceStartup;
|
||||
// var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync();
|
||||
{
|
||||
var initialSeconds = Time.realtimeSinceStartup;
|
||||
var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync();
|
||||
|
||||
// Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse();
|
||||
// Debug.Log("Init:" + initialSeconds);
|
||||
// Debug.Log("After:" + xs[0]);
|
||||
// }
|
||||
//});
|
||||
Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse();
|
||||
Debug.Log("Init:" + initialSeconds);
|
||||
Debug.Log("After:" + xs[0]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
[UnityTest]
|
||||
@@ -181,17 +181,24 @@ namespace Cysharp.Threading.TasksTests
|
||||
{
|
||||
await UniTask.Run(async () =>
|
||||
{
|
||||
Debug.Log("Go Delay?");
|
||||
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(2));
|
||||
|
||||
Debug.Log("OK?");
|
||||
});
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator DelayRealtime() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(2), DelayType.Realtime);
|
||||
|
||||
var elapsed = DateTimeOffset.UtcNow - now;
|
||||
|
||||
var okay1 = TimeSpan.FromSeconds(1.80) <= elapsed;
|
||||
var okay2 = elapsed <= TimeSpan.FromSeconds(2.20);
|
||||
|
||||
okay1.Should().Be(true);
|
||||
okay2.Should().Be(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,8 @@ PlayerSettings:
|
||||
switchNVNShaderPoolsGranularity: 33554432
|
||||
switchNVNDefaultPoolsGranularity: 16777216
|
||||
switchNVNOtherPoolsGranularity: 16777216
|
||||
stadiaPresentMode: 0
|
||||
stadiaTargetFramerate: 0
|
||||
vulkanNumSwapchainBuffers: 3
|
||||
vulkanEnableSetSRGBWrite: 0
|
||||
m_SupportedAspectRatios:
|
||||
@@ -191,22 +193,6 @@ PlayerSettings:
|
||||
uIStatusBarHidden: 1
|
||||
uIExitOnSuspend: 0
|
||||
uIStatusBarStyle: 0
|
||||
iPhoneSplashScreen: {fileID: 0}
|
||||
iPhoneHighResSplashScreen: {fileID: 0}
|
||||
iPhoneTallHighResSplashScreen: {fileID: 0}
|
||||
iPhone47inSplashScreen: {fileID: 0}
|
||||
iPhone55inPortraitSplashScreen: {fileID: 0}
|
||||
iPhone55inLandscapeSplashScreen: {fileID: 0}
|
||||
iPhone58inPortraitSplashScreen: {fileID: 0}
|
||||
iPhone58inLandscapeSplashScreen: {fileID: 0}
|
||||
iPadPortraitSplashScreen: {fileID: 0}
|
||||
iPadHighResPortraitSplashScreen: {fileID: 0}
|
||||
iPadLandscapeSplashScreen: {fileID: 0}
|
||||
iPadHighResLandscapeSplashScreen: {fileID: 0}
|
||||
iPhone65inPortraitSplashScreen: {fileID: 0}
|
||||
iPhone65inLandscapeSplashScreen: {fileID: 0}
|
||||
iPhone61inPortraitSplashScreen: {fileID: 0}
|
||||
iPhone61inLandscapeSplashScreen: {fileID: 0}
|
||||
appleTVSplashScreen: {fileID: 0}
|
||||
appleTVSplashScreen2x: {fileID: 0}
|
||||
tvOSSmallIconLayers: []
|
||||
@@ -566,7 +552,8 @@ PlayerSettings:
|
||||
scriptingRuntimeVersion: 1
|
||||
gcIncremental: 0
|
||||
gcWBarrierValidation: 0
|
||||
apiCompatibilityLevelPerPlatform: {}
|
||||
apiCompatibilityLevelPerPlatform:
|
||||
Standalone: 6
|
||||
m_RenderingPath: 1
|
||||
m_MobileRenderingPath: 1
|
||||
metroPackageName: Template_2D
|
||||
@@ -621,6 +608,7 @@ PlayerSettings:
|
||||
XboxOnePersistentLocalStorageSize: 0
|
||||
XboxOneXTitleMemory: 8
|
||||
XboxOneOverrideIdentityName:
|
||||
XboxOneOverrideIdentityPublisher:
|
||||
vrEditorSettings:
|
||||
daydream:
|
||||
daydreamIconForeground: {fileID: 0}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
m_EditorVersion: 2019.3.9f1
|
||||
m_EditorVersionWithRevision: 2019.3.9f1 (e6e740a1c473)
|
||||
m_EditorVersion: 2019.4.5f1
|
||||
m_EditorVersionWithRevision: 2019.4.5f1 (81610f64359c)
|
||||
|
||||
Reference in New Issue
Block a user