mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-16 20:20:45 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d935b226c0 | ||
|
|
d9e20de8a5 | ||
|
|
23997f0f93 | ||
|
|
529272d11b | ||
|
|
1194c38568 | ||
|
|
f0d2ee2beb | ||
|
|
68cdda086a | ||
|
|
54ceca6ceb | ||
|
|
50bdf7460c | ||
|
|
c06e45d0bb | ||
|
|
3ed6e28a00 | ||
|
|
ab76098895 | ||
|
|
0a447e43b0 | ||
|
|
8df44f2768 | ||
|
|
a7ec64d644 |
18
README.md
18
README.md
@@ -136,7 +136,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.
|
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.
|
UniTask provides three pattern of extension methods.
|
||||||
|
|
||||||
@@ -386,7 +386,7 @@ PlayerLoopHelper.Initialize(ref playerLoop);
|
|||||||
|
|
||||||
async void vs async UniTaskVoid
|
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
|
```csharp
|
||||||
public async UniTaskVoid FireAndForgetMethod()
|
public async UniTaskVoid FireAndForgetMethod()
|
||||||
@@ -431,6 +431,18 @@ actEvent += UniTask.Action(async () => { await UniTask.Yield(); });
|
|||||||
unityEvent += UniTask.UnityAction(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
|
UniTaskTracker
|
||||||
---
|
---
|
||||||
useful for check(leak) UniTasks. You can open tracker window in `Window -> UniTask Tracker`.
|
useful for check(leak) UniTasks. You can open tracker window in `Window -> UniTask Tracker`.
|
||||||
@@ -800,7 +812,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`.
|
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.22`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.22`.
|
||||||
|
|
||||||
### Install via OpenUPM
|
### Install via OpenUPM
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,7 @@
|
|||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Bridge.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.WaitUntil.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.*;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs;
|
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs;
|
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
|
||||||
" />
|
" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace NetCoreTests.Linq
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task TakeUntil()
|
public async Task TakeUntilCanceled()
|
||||||
{
|
{
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ namespace NetCoreTests.Linq
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SkipUntil()
|
public async Task SkipUntilCanceled()
|
||||||
{
|
{
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ namespace NetCoreTests.Linq
|
|||||||
await c;
|
await c;
|
||||||
var foo = await xs;
|
var foo = await xs;
|
||||||
|
|
||||||
foo.Should().BeEquivalentTo(new[] { 30, 40 });
|
foo.Should().BeEquivalentTo(new[] { 20, 30, 40 });
|
||||||
|
|
||||||
async Task CancelAsync()
|
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.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,55 @@ namespace Cysharp.Threading.Tasks
|
|||||||
static readonly Action<object> cancellationTokenCallback = Callback;
|
static readonly Action<object> cancellationTokenCallback = Callback;
|
||||||
static readonly Action<object> disposeCallback = DisposeCallback;
|
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 = new CancellationTokenSource();
|
||||||
|
ToCancellationTokenCore(task, cts).Forget();
|
||||||
|
|
||||||
|
return CancellationTokenSource.CreateLinkedTokenSource(linkToken).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)
|
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
public static class CancellationTokenSourceExtensions
|
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();
|
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();
|
CancelAfterCore(cts, delay).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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>
|
sealed class _SkipUntilCanceled : MoveNextSource, IUniTaskAsyncEnumerator<TSource>
|
||||||
{
|
{
|
||||||
|
static readonly Action<object> CancelDelegate1 = OnCanceled1;
|
||||||
|
static readonly Action<object> CancelDelegate2 = OnCanceled2;
|
||||||
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
static readonly Action<object> MoveNextCoreDelegate = MoveNextCore;
|
||||||
|
|
||||||
readonly IUniTaskAsyncEnumerable<TSource> source;
|
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||||
CancellationToken cancellationToken1;
|
CancellationToken cancellationToken1;
|
||||||
CancellationToken cancellationToken2;
|
CancellationToken cancellationToken2;
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||||
|
CancellationTokenRegistration cancellationTokenRegistration2;
|
||||||
|
|
||||||
bool isCanceled;
|
int isCanceled;
|
||||||
IUniTaskAsyncEnumerator<TSource> enumerator;
|
IUniTaskAsyncEnumerator<TSource> enumerator;
|
||||||
UniTask<bool>.Awaiter awaiter;
|
UniTask<bool>.Awaiter awaiter;
|
||||||
bool continueNext;
|
bool continueNext;
|
||||||
@@ -48,6 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
this.source = source;
|
this.source = source;
|
||||||
this.cancellationToken1 = cancellationToken1;
|
this.cancellationToken1 = cancellationToken1;
|
||||||
this.cancellationToken2 = cancellationToken2;
|
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);
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,15 +67,18 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
public UniTask<bool> MoveNextAsync()
|
||||||
{
|
{
|
||||||
if (cancellationToken1.IsCancellationRequested) isCanceled = true;
|
|
||||||
if (cancellationToken2.IsCancellationRequested) isCanceled = true;
|
|
||||||
|
|
||||||
if (enumerator == null)
|
if (enumerator == null)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken1.IsCancellationRequested) isCanceled = 1;
|
||||||
|
if (cancellationToken2.IsCancellationRequested) isCanceled = 1;
|
||||||
enumerator = source.GetAsyncEnumerator(cancellationToken2); // use only AsyncEnumerator provided token.
|
enumerator = source.GetAsyncEnumerator(cancellationToken2); // use only AsyncEnumerator provided token.
|
||||||
}
|
}
|
||||||
completionSource.Reset();
|
completionSource.Reset();
|
||||||
SourceMoveNext();
|
|
||||||
|
if (isCanceled != 0)
|
||||||
|
{
|
||||||
|
SourceMoveNext();
|
||||||
|
}
|
||||||
return new UniTask<bool>(this, completionSource.Version);
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,25 +117,11 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
AGAIN:
|
self.Current = self.enumerator.Current;
|
||||||
|
self.completionSource.TrySetResult(true);
|
||||||
if (self.isCanceled)
|
if (self.continueNext)
|
||||||
{
|
{
|
||||||
self.continueNext = false;
|
self.SourceMoveNext();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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()
|
public UniTask DisposeAsync()
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
|
cancellationTokenRegistration1.Dispose();
|
||||||
|
cancellationTokenRegistration2.Dispose();
|
||||||
if (enumerator != null)
|
if (enumerator != null)
|
||||||
{
|
{
|
||||||
return enumerator.DisposeAsync();
|
return enumerator.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:
|
||||||
@@ -8,6 +8,16 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
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 partial struct UniTask
|
||||||
{
|
{
|
||||||
public static YieldAwaitable Yield(PlayerLoopTiming timing = PlayerLoopTiming.Update)
|
public static YieldAwaitable Yield(PlayerLoopTiming timing = PlayerLoopTiming.Update)
|
||||||
@@ -74,36 +84,44 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
|
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
|
||||||
if (delayTimeSpan < TimeSpan.Zero)
|
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
if (delayTimeSpan < TimeSpan.Zero)
|
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
|
||||||
{
|
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask DelayRealtime(TimeSpan delayTimeSpan, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(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)
|
if (delayTimeSpan < TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan);
|
throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var 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>
|
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
|
||||||
|
|||||||
@@ -15,33 +15,33 @@ namespace Cysharp.Threading.Tasks
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// If running on mainthread, do nothing. Otherwise, same as UniTask.Yield(PlayerLoopTiming.Update).
|
/// If running on mainthread, do nothing. Otherwise, same as UniTask.Yield(PlayerLoopTiming.Update).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static SwitchToMainThreadAwaitable SwitchToMainThread()
|
public static SwitchToMainThreadAwaitable SwitchToMainThread(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return new SwitchToMainThreadAwaitable(PlayerLoopTiming.Update);
|
return new SwitchToMainThreadAwaitable(PlayerLoopTiming.Update, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If running on mainthread, do nothing. Otherwise, same as UniTask.Yield(timing).
|
/// If running on mainthread, do nothing. Otherwise, same as UniTask.Yield(timing).
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Return to mainthread(same as await SwitchToMainThread) after using scope is closed.
|
/// Return to mainthread(same as await SwitchToMainThread) after using scope is closed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ReturnToMainThread ReturnToMainThread()
|
public static ReturnToMainThread ReturnToMainThread(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return new ReturnToMainThread(PlayerLoopTiming.Update);
|
return new ReturnToMainThread(PlayerLoopTiming.Update, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return to mainthread(same as await SwitchToMainThread) after using scope is closed.
|
/// Return to mainthread(same as await SwitchToMainThread) after using scope is closed.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
@@ -67,20 +67,20 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new SwitchToTaskPoolAwaitable();
|
return new SwitchToTaskPoolAwaitable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SwitchToSynchronizationContextAwaitable SwitchToSynchronizationContext(SynchronizationContext synchronizationContext)
|
public static SwitchToSynchronizationContextAwaitable SwitchToSynchronizationContext(SynchronizationContext synchronizationContext, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Error.ThrowArgumentNullException(synchronizationContext, nameof(synchronizationContext));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,21 +89,25 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public struct SwitchToMainThreadAwaitable
|
public struct SwitchToMainThreadAwaitable
|
||||||
{
|
{
|
||||||
readonly PlayerLoopTiming playerLoopTiming;
|
readonly PlayerLoopTiming playerLoopTiming;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public SwitchToMainThreadAwaitable(PlayerLoopTiming playerLoopTiming)
|
public SwitchToMainThreadAwaitable(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.playerLoopTiming = playerLoopTiming;
|
this.playerLoopTiming = playerLoopTiming;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Awaiter GetAwaiter() => new Awaiter(playerLoopTiming);
|
public Awaiter GetAwaiter() => new Awaiter(playerLoopTiming, cancellationToken);
|
||||||
|
|
||||||
public struct Awaiter : ICriticalNotifyCompletion
|
public struct Awaiter : ICriticalNotifyCompletion
|
||||||
{
|
{
|
||||||
readonly PlayerLoopTiming playerLoopTiming;
|
readonly PlayerLoopTiming playerLoopTiming;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public Awaiter(PlayerLoopTiming playerLoopTiming)
|
public Awaiter(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.playerLoopTiming = playerLoopTiming;
|
this.playerLoopTiming = playerLoopTiming;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCompleted
|
public bool IsCompleted
|
||||||
@@ -122,7 +126,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetResult() { }
|
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
public void OnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
@@ -139,31 +143,35 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public struct ReturnToMainThread
|
public struct ReturnToMainThread
|
||||||
{
|
{
|
||||||
readonly PlayerLoopTiming playerLoopTiming;
|
readonly PlayerLoopTiming playerLoopTiming;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public ReturnToMainThread(PlayerLoopTiming playerLoopTiming)
|
public ReturnToMainThread(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.playerLoopTiming = playerLoopTiming;
|
this.playerLoopTiming = playerLoopTiming;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Awaiter DisposeAsync()
|
public Awaiter DisposeAsync()
|
||||||
{
|
{
|
||||||
return new Awaiter(playerLoopTiming); // run immediate.
|
return new Awaiter(playerLoopTiming, cancellationToken); // run immediate.
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly struct Awaiter : ICriticalNotifyCompletion
|
public readonly struct Awaiter : ICriticalNotifyCompletion
|
||||||
{
|
{
|
||||||
readonly PlayerLoopTiming timing;
|
readonly PlayerLoopTiming timing;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public Awaiter(PlayerLoopTiming timing)
|
public Awaiter(PlayerLoopTiming timing, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.timing = timing;
|
this.timing = timing;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Awaiter GetAwaiter() => this;
|
public Awaiter GetAwaiter() => this;
|
||||||
|
|
||||||
public bool IsCompleted => PlayerLoopHelper.MainThreadId == System.Threading.Thread.CurrentThread.ManagedThreadId;
|
public bool IsCompleted => PlayerLoopHelper.MainThreadId == System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||||
|
|
||||||
public void GetResult() { }
|
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
public void OnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
@@ -285,26 +293,30 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public struct SwitchToSynchronizationContextAwaitable
|
public struct SwitchToSynchronizationContextAwaitable
|
||||||
{
|
{
|
||||||
readonly SynchronizationContext synchronizationContext;
|
readonly SynchronizationContext synchronizationContext;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public SwitchToSynchronizationContextAwaitable(SynchronizationContext synchronizationContext)
|
public SwitchToSynchronizationContextAwaitable(SynchronizationContext synchronizationContext, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.synchronizationContext = synchronizationContext;
|
this.synchronizationContext = synchronizationContext;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Awaiter GetAwaiter() => new Awaiter(synchronizationContext);
|
public Awaiter GetAwaiter() => new Awaiter(synchronizationContext, cancellationToken);
|
||||||
|
|
||||||
public struct Awaiter : ICriticalNotifyCompletion
|
public struct Awaiter : ICriticalNotifyCompletion
|
||||||
{
|
{
|
||||||
static readonly SendOrPostCallback switchToCallback = Callback;
|
static readonly SendOrPostCallback switchToCallback = Callback;
|
||||||
readonly SynchronizationContext synchronizationContext;
|
readonly SynchronizationContext synchronizationContext;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public Awaiter(SynchronizationContext synchronizationContext)
|
public Awaiter(SynchronizationContext synchronizationContext, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.synchronizationContext = synchronizationContext;
|
this.synchronizationContext = synchronizationContext;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCompleted => false;
|
public bool IsCompleted => false;
|
||||||
public void GetResult() { }
|
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
public void OnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
@@ -328,16 +340,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
readonly SynchronizationContext syncContext;
|
readonly SynchronizationContext syncContext;
|
||||||
readonly bool dontPostWhenSameContext;
|
readonly bool dontPostWhenSameContext;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public ReturnToSynchronizationContext(SynchronizationContext syncContext, bool dontPostWhenSameContext)
|
public ReturnToSynchronizationContext(SynchronizationContext syncContext, bool dontPostWhenSameContext, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.syncContext = syncContext;
|
this.syncContext = syncContext;
|
||||||
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Awaiter DisposeAsync()
|
public Awaiter DisposeAsync()
|
||||||
{
|
{
|
||||||
return new Awaiter(syncContext, dontPostWhenSameContext);
|
return new Awaiter(syncContext, dontPostWhenSameContext, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Awaiter : ICriticalNotifyCompletion
|
public struct Awaiter : ICriticalNotifyCompletion
|
||||||
@@ -346,11 +360,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
readonly SynchronizationContext synchronizationContext;
|
readonly SynchronizationContext synchronizationContext;
|
||||||
readonly bool dontPostWhenSameContext;
|
readonly bool dontPostWhenSameContext;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
|
||||||
public Awaiter(SynchronizationContext synchronizationContext, bool dontPostWhenSameContext)
|
public Awaiter(SynchronizationContext synchronizationContext, bool dontPostWhenSameContext, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.synchronizationContext = synchronizationContext;
|
this.synchronizationContext = synchronizationContext;
|
||||||
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Awaiter GetAwaiter() => this;
|
public Awaiter GetAwaiter() => this;
|
||||||
@@ -373,7 +389,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetResult() { }
|
public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); }
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
public void OnCompleted(Action continuation)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -201,10 +201,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new ToCoroutineEnumerator(task, exceptionHandler);
|
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 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;
|
int winArgIndex;
|
||||||
bool taskResultIsCanceled;
|
bool taskResultIsCanceled;
|
||||||
@@ -242,10 +242,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 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;
|
int winArgIndex;
|
||||||
(bool IsCanceled, T Result) taskResult;
|
(bool IsCanceled, T Result) taskResult;
|
||||||
@@ -288,10 +288,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
|
/// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
|
||||||
/// </summary>
|
/// </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 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;
|
int winArgIndex;
|
||||||
bool taskResultIsCanceled;
|
bool taskResultIsCanceled;
|
||||||
@@ -334,10 +334,10 @@ namespace Cysharp.Threading.Tasks
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timeout with suppress OperationCanceledException. Returns (bool IsTimeout, T Result).
|
/// Timeout with suppress OperationCanceledException. Returns (bool IsTimeout, T Result).
|
||||||
/// </summary>
|
/// </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 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;
|
int winArgIndex;
|
||||||
(bool IsCanceled, T Result) taskResult;
|
(bool IsCanceled, T Result) taskResult;
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#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;
|
||||||
|
public AsyncGPUReadbackRequestAwaiterConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
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:
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"version": "2.0.20",
|
"version": "2.0.22",
|
||||||
"unity": "2018.4",
|
"unity": "2018.4",
|
||||||
"description": "Provides an efficient async/await integration to Unity.",
|
"description": "Provides an efficient async/await integration to Unity.",
|
||||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ using UnityEngine.LowLevel;
|
|||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
|
||||||
// using DG.Tweening;
|
// using DG.Tweening;
|
||||||
@@ -117,6 +119,8 @@ public class AsyncMessageBroker<T> : IDisposable
|
|||||||
|
|
||||||
public class SandboxMain : MonoBehaviour
|
public class SandboxMain : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
public Camera mycamera;
|
||||||
|
|
||||||
public Button okButton;
|
public Button okButton;
|
||||||
public Button cancelButton;
|
public Button cancelButton;
|
||||||
|
|
||||||
@@ -161,6 +165,9 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//setHp = Hp.GetSetter();
|
//setHp = Hp.GetSetter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,10 +185,6 @@ public class SandboxMain : MonoBehaviour
|
|||||||
public Button button;
|
public Button button;
|
||||||
|
|
||||||
|
|
||||||
void Start2()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -435,12 +438,40 @@ 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async UniTaskVoid Start()
|
||||||
|
{
|
||||||
|
okButton.onClick.AddListener(() =>
|
||||||
|
{
|
||||||
|
ShootAsync().Forget();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Nanika();
|
||||||
|
|
||||||
|
|
||||||
|
await UniTask.Yield();
|
||||||
|
// this.GetCancellationTokenOnDestroy()
|
||||||
|
|
||||||
//PlayerLoopInfo.Inject();
|
//PlayerLoopInfo.Inject();
|
||||||
|
|
||||||
@@ -458,7 +489,11 @@ public class SandboxMain : MonoBehaviour
|
|||||||
//var cts = new CancellationTokenSource();
|
//var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
|
||||||
|
// UniTask.Post(
|
||||||
|
|
||||||
|
// CancellationToken.
|
||||||
|
|
||||||
|
//UniTask.Delay(TimeSpan.FromSeconds(3)).
|
||||||
|
|
||||||
|
|
||||||
//okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
//okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||||
@@ -950,6 +985,62 @@ public class SandboxMain : MonoBehaviour
|
|||||||
// e.SetObserved();
|
// e.SetObserved();
|
||||||
// or other custom write code.
|
// or other custom write code.
|
||||||
UnityEngine.Debug.LogError("Unobserved:" + e.Exception.ToString());
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,80 @@ CanvasRenderer:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 16537670}
|
m_GameObject: {fileID: 16537670}
|
||||||
m_CullTransparentMesh: 0
|
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
|
--- !u!1 &519420028
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -278,9 +352,11 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
m_Script: {fileID: 11500000, guid: f0bc6c75abb2e0b47a25aa49bfd488ed, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
|
camera: {fileID: 518730349}
|
||||||
okButton: {fileID: 16537672}
|
okButton: {fileID: 16537672}
|
||||||
cancelButton: {fileID: 628393011}
|
cancelButton: {fileID: 628393011}
|
||||||
text: {fileID: 2101290655}
|
text: {fileID: 2101290655}
|
||||||
|
button: {fileID: 0}
|
||||||
--- !u!20 &519420031
|
--- !u!20 &519420031
|
||||||
Camera:
|
Camera:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -597,7 +673,7 @@ Transform:
|
|||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 1
|
m_RootOrder: 2
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &1556045504
|
--- !u!1 &1556045504
|
||||||
GameObject:
|
GameObject:
|
||||||
@@ -693,7 +769,7 @@ RectTransform:
|
|||||||
- {fileID: 628393010}
|
- {fileID: 628393010}
|
||||||
- {fileID: 2101290654}
|
- {fileID: 2101290654}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 2
|
m_RootOrder: 3
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
{
|
{
|
||||||
var now = DateTimeOffset.UtcNow;
|
var now = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
await UniTask.DelayRealtime(TimeSpan.FromSeconds(2));
|
await UniTask.Delay(TimeSpan.FromSeconds(2), DelayType.Realtime);
|
||||||
|
|
||||||
var elapsed = DateTimeOffset.UtcNow - now;
|
var elapsed = DateTimeOffset.UtcNow - now;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user