mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 03:20:16 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbfb8354bb | ||
|
|
2f68e47443 | ||
|
|
89339ffb29 | ||
|
|
0535862fe6 | ||
|
|
a9e5fd4589 | ||
|
|
a3f3a28ea1 | ||
|
|
59020df965 | ||
|
|
ac01be79bf | ||
|
|
de5951f208 | ||
|
|
ded9a561db | ||
|
|
a2c18eb343 | ||
|
|
0b27c3a342 | ||
|
|
9c86cfb508 | ||
|
|
7e5e6ed6c2 | ||
|
|
d081e5f40b | ||
|
|
344ae0738c | ||
|
|
1b553f67b0 | ||
|
|
bf0adad427 | ||
|
|
11ca42a527 | ||
|
|
4898e4c7bf | ||
|
|
d494e0b9e3 | ||
|
|
be26ab249b | ||
|
|
611d8d5513 | ||
|
|
95c93b7c3d | ||
|
|
1dd0c49eec | ||
|
|
5d8e0e61ad | ||
|
|
478126e256 |
7
.github/workflows/build-debug.yml
vendored
7
.github/workflows/build-debug.yml
vendored
@@ -26,9 +26,10 @@ jobs:
|
||||
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
|
||||
|
||||
build-unity:
|
||||
if: "(github.event == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')"
|
||||
strategy:
|
||||
matrix:
|
||||
unity: ['2019.3.9f1', '2020.1.0b5']
|
||||
unity: ["2019.3.9f1", "2020.1.0b5"]
|
||||
include:
|
||||
- unity: 2019.3.9f1
|
||||
license: UNITY_2019_3
|
||||
@@ -66,8 +67,8 @@ jobs:
|
||||
run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
|
||||
working-directory: src/UniTask
|
||||
|
||||
# Store artifacts.
|
||||
# Store artifacts.
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UniTask.unitypackage.zip
|
||||
path: ./src/UniTask/*.unitypackage
|
||||
path: ./src/UniTask/*.unitypackage
|
||||
|
||||
83
README.md
83
README.md
@@ -2,7 +2,7 @@ UniTask
|
||||
===
|
||||
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases)
|
||||
|
||||
Provides an efficient async/await integration to Unity.
|
||||
Provides an efficient allocation free async/await integration to Unity.
|
||||
|
||||
* Struct based `UniTask<T>` and custom AsyncMethodBuilder to achive zero allocation
|
||||
* All Unity AsyncOperations and Coroutine to awaitable
|
||||
@@ -13,6 +13,9 @@ Provides an efficient async/await integration to Unity.
|
||||
* TaskTracker window to prevent memory leak
|
||||
* 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)
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
## Table of Contents
|
||||
@@ -29,6 +32,7 @@ Provides an efficient async/await integration to Unity.
|
||||
- [Awaitable Events](#awaitable-events)
|
||||
- [Channel](#channel)
|
||||
- [For Unit Testing](#for-unit-testing)
|
||||
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
||||
- [Pooling Configuration](#pooling-configuration)
|
||||
- [API References](#api-references)
|
||||
- [UPM Package](#upm-package)
|
||||
@@ -346,7 +350,7 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.
|
||||
|
||||
> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and faster.
|
||||
|
||||
AsyncOperation is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after called, loaded scene called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
|
||||
AsyncOperation is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after called, loaded scene's `Start` called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
|
||||
|
||||
In UniTask, await directly and `WithCancellation` use native timing, `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, causes different order of Start and continuation after await. so recommend not to use `LoadSceneAsync.ToUniTask`.
|
||||
|
||||
@@ -583,9 +587,30 @@ await this.GetAsyncMoveTrigger().ForEachAsync(axisEventData =>
|
||||
});
|
||||
```
|
||||
|
||||
`AsyncReactiveProperty`, `AsyncReadOnlyReactiveProperty` is UniTask version of UniTask's ReactiveProperty.
|
||||
`AsyncReactiveProperty`, `AsyncReadOnlyReactiveProperty` is UniTask version of UniTask's ReactiveProperty. `BindTo` extension method of `IUniTaskAsyncEnumerable<T>` for binding asynchronous stream values to Unity components(Text/Selectable/TMP/Text).
|
||||
|
||||
`BindTo` extension method of `IUniTaskAsyncEnumerable<T>` for binding asynchronous stream values to Unity components(Text/Selectable/TMP/Text).
|
||||
```csharp
|
||||
var rp = new AsyncReactiveProperty<int>(99);
|
||||
|
||||
// AsyncReactiveProperty itself is IUniTaskAsyncEnumerable, you can query by LINQ
|
||||
rp.ForEachAsync(x =>
|
||||
{
|
||||
Debug.Log(x);
|
||||
}, this.GetCancellationTokenOnDestroy()).Forget();
|
||||
|
||||
rp.Value = 10; // push 10 to all subscriber
|
||||
rp.Value = 11; // push 11 to all subscriber
|
||||
|
||||
// WithoutCurrent ignore initial value
|
||||
// BindTo bind stream value to unity components.
|
||||
rp.WithoutCurrent().BindTo(this.textComponent);
|
||||
|
||||
await rp.WaitAsync(); // wait until next value set
|
||||
|
||||
// also exists ToReadOnlyReactiveProperty
|
||||
var rp2 = new AsyncReactiveProperty<int>(99);
|
||||
var rorp = rp.CombineLatest(rp2, (x, y) => (x, y)).ToReadOnlyReactiveProperty();
|
||||
```
|
||||
|
||||
A pull-type asynchronous stream does not get the next values until the asynchronous processing in the sequence is complete. This could spill data from push-type events such as buttons.
|
||||
|
||||
@@ -679,6 +704,52 @@ 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.
|
||||
|
||||
Compare with Standard Task API
|
||||
---
|
||||
UniTask has many standard Task-like APIs. This table shows what is the alternative apis.
|
||||
|
||||
Use standard type.
|
||||
|
||||
| .NET Type | UniTask Type |
|
||||
| --- | --- |
|
||||
| `IProgress<T>` | --- |
|
||||
| `CancellationToken` | --- |
|
||||
| `CancellationTokenSource` | --- |
|
||||
|
||||
Use UniTask type.
|
||||
|
||||
| .NET Type | UniTask Type |
|
||||
| --- | --- |
|
||||
| `Task`/`ValueTask` | `UniTask` |
|
||||
| `Task<T>`/`ValueTask<T>` | `UniTask<T>` |
|
||||
| `async void` | `async UniTaskVoid` |
|
||||
| `+= async () => { }` | `UniTask.Void`, `UniTask.Action`, `UniTask.UnityAction` |
|
||||
| --- | `UniTaskCompletionSource` |
|
||||
| `TaskCompletionSource<T>` | `UniTaskCompletionSource<T>`/`AutoResetUniTaskCompletionSource<T>` |
|
||||
| `ManualResetValueTaskSourceCore<T>` | `UniTaskCompletionSourceCore<T>` |
|
||||
| `IValueTaskSource` | `IUniTaskSource` |
|
||||
| `IValueTaskSource<T>` | `IUniTaskSource<T>` |
|
||||
| `ValueTask.IsCompleted` | `UniTask.Status.IsCompleted()` |
|
||||
| `ValueTask<T>.IsCompleted` | `UniTask<T>.Status.IsCompleted()` |
|
||||
| `new Progress<T>` | `Progress.Create<T>` |
|
||||
| `CancellationToken.Register(UnsafeRegister)` | `CancellationToken.RegisterWithoutCaptureExecutionContext` |
|
||||
| `CancellationTokenSource.CancelAfter` | `CancellationTokenSource.CancelAfterSlim` |
|
||||
| `Channel.CreateUnbounded<T>(false){ SingleReader = true }` | `Channel.CreateSingleConsumerUnbounded<T>` |
|
||||
| `IAsyncEnumerable<T>` | `IUniTaskAsyncEnumerable<T>` |
|
||||
| `IAsyncEnumerator<T>` | `IUniTaskAsyncEnumerator<T>` |
|
||||
| `IAsyncDisposable` | `IUniTaskAsyncDisposable` |
|
||||
| `Task.Delay` | `UniTask.Delay` |
|
||||
| `Task.Yield` | `UniTask.Yield` |
|
||||
| `Task.Run` | `UniTask.Run` |
|
||||
| `Task.WhenAll` | `UniTask.WhenAll` |
|
||||
| `Task.WhenAny` | `UniTask.WhenAny` |
|
||||
| `Task.CompletedTask` | `UniTask.CompletedTask` |
|
||||
| `Task.FromException` | `UniTask.FromException` |
|
||||
| `Task.FromResult` | `UniTask.FromResult` |
|
||||
| `Task.FromCanceled` | `UniTask.FromCanceled` |
|
||||
| `Task.ContinueWith` | `UniTask.ContinueWith` |
|
||||
| `TaskScheduler.UnobservedTaskException` | `UniTaskScheduler.UnobservedTaskException` |
|
||||
|
||||
Pooling Configuration
|
||||
---
|
||||
UniTask is aggressively caching async promise object to achive zero allocation. In default, cache all promises but you can configure `TaskPool.SetMaxPoolSize` to your value, the value indicates cache size per type. `TaskPool.GetCacheSizeInfo` returns current cached object in pool.
|
||||
@@ -690,7 +761,7 @@ 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. And also currently due to IL2CPP limitation, in IL2CPP build, UniTask do boxing AsyncStateMachine when needed so sometimes exists `one` allocation.
|
||||
> 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.
|
||||
|
||||
API References
|
||||
---
|
||||
@@ -710,7 +781,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.13`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.13`.
|
||||
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.15`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.15`.
|
||||
|
||||
### Install via OpenUPM
|
||||
|
||||
|
||||
@@ -112,6 +112,85 @@ namespace NetCoreTests
|
||||
state.Value.Should().Be(20);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WaitAsyncTest()
|
||||
{
|
||||
var rp = new AsyncReactiveProperty<int>(128);
|
||||
|
||||
var f = await rp.FirstAsync();
|
||||
f.Should().Be(128);
|
||||
|
||||
{
|
||||
var t = rp.WaitAsync();
|
||||
rp.Value = 99;
|
||||
rp.Value = 100;
|
||||
var v = await t;
|
||||
|
||||
v.Should().Be(99);
|
||||
}
|
||||
|
||||
{
|
||||
var t = rp.WaitAsync();
|
||||
rp.Value = 99;
|
||||
rp.Value = 100;
|
||||
var v = await t;
|
||||
|
||||
v.Should().Be(99);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task WaitAsyncCancellationTest()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var rp = new AsyncReactiveProperty<int>(128);
|
||||
|
||||
var t = rp.WaitAsync(cts.Token);
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
rp.Value = 99;
|
||||
rp.Value = 100;
|
||||
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => { await t; });
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ReadOnlyWaitAsyncTest()
|
||||
{
|
||||
var rp = new AsyncReactiveProperty<int>(128);
|
||||
var rrp = rp.ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
|
||||
|
||||
var t = rrp.WaitAsync();
|
||||
rp.Value = 99;
|
||||
rp.Value = 100;
|
||||
var v = await t;
|
||||
|
||||
v.Should().Be(99);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ReadOnlyWaitAsyncCancellationTest()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var rp = new AsyncReactiveProperty<int>(128);
|
||||
var rrp = rp.ToReadOnlyAsyncReactiveProperty(CancellationToken.None);
|
||||
|
||||
var t = rrp.WaitAsync(cts.Token);
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
rp.Value = 99;
|
||||
rp.Value = 100;
|
||||
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => { await t; });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
T Value { get; }
|
||||
IUniTaskAsyncEnumerable<T> WithoutCurrent();
|
||||
UniTask<T> WaitAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>
|
||||
@@ -69,6 +70,11 @@ namespace Cysharp.Threading.Tasks
|
||||
return latestValue?.ToString();
|
||||
}
|
||||
|
||||
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
static bool isValueType;
|
||||
|
||||
static AsyncReactiveProperty()
|
||||
@@ -76,7 +82,143 @@ namespace Cysharp.Threading.Tasks
|
||||
isValueType = typeof(T).IsValueType;
|
||||
}
|
||||
|
||||
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
||||
sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
|
||||
{
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
static TaskPool<WaitAsyncSource> pool;
|
||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
||||
|
||||
static WaitAsyncSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncReactiveProperty<T> parent;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
WaitAsyncSource()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitAsyncSource();
|
||||
}
|
||||
|
||||
result.parent = parent;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
|
||||
}
|
||||
|
||||
result.parent.triggerEvent.Add(result);
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancellationTokenRegistration = default;
|
||||
parent.triggerEvent.Remove(this);
|
||||
parent = null;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitAsyncSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WaitAsyncSource)state;
|
||||
self.OnCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
// IUniTaskSource
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
GetResult(token);
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
// ITriggerHandler
|
||||
|
||||
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
||||
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
||||
|
||||
public void OnCanceled(CancellationToken cancellationToken)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
// Complete as Cancel.
|
||||
core.TrySetCanceled(CancellationToken.None);
|
||||
}
|
||||
|
||||
public void OnError(Exception ex)
|
||||
{
|
||||
core.TrySetException(ex);
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
{
|
||||
core.TrySetResult(value);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
readonly AsyncReactiveProperty<T> parent;
|
||||
|
||||
@@ -253,6 +395,11 @@ namespace Cysharp.Threading.Tasks
|
||||
return latestValue?.ToString();
|
||||
}
|
||||
|
||||
public UniTask<T> WaitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
static bool isValueType;
|
||||
|
||||
static ReadOnlyAsyncReactiveProperty()
|
||||
@@ -260,7 +407,143 @@ namespace Cysharp.Threading.Tasks
|
||||
isValueType = typeof(T).IsValueType;
|
||||
}
|
||||
|
||||
class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
||||
sealed class WaitAsyncSource : IUniTaskSource<T>, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
|
||||
{
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
static TaskPool<WaitAsyncSource> pool;
|
||||
WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode { get; set; }
|
||||
|
||||
static WaitAsyncSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
|
||||
}
|
||||
|
||||
ReadOnlyAsyncReactiveProperty<T> parent;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration cancellationTokenRegistration;
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
WaitAsyncSource()
|
||||
{
|
||||
}
|
||||
|
||||
public static IUniTaskSource<T> Create(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitAsyncSource();
|
||||
}
|
||||
|
||||
result.parent = parent;
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
|
||||
}
|
||||
|
||||
result.parent.triggerEvent.Add(result);
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationTokenRegistration.Dispose();
|
||||
cancellationTokenRegistration = default;
|
||||
parent.triggerEvent.Remove(this);
|
||||
parent = null;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitAsyncSource()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WaitAsyncSource)state;
|
||||
self.OnCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
// IUniTaskSource
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
GetResult(token);
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
// ITriggerHandler
|
||||
|
||||
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
||||
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
||||
|
||||
public void OnCanceled(CancellationToken cancellationToken)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
// Complete as Cancel.
|
||||
core.TrySetCanceled(CancellationToken.None);
|
||||
}
|
||||
|
||||
public void OnError(Exception ex)
|
||||
{
|
||||
core.TrySetException(ex);
|
||||
}
|
||||
|
||||
public void OnNext(T value)
|
||||
{
|
||||
core.TrySetResult(value);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
readonly ReadOnlyAsyncReactiveProperty<T> parent;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Cysharp.Threading.Tasks
|
||||
public static class CancellationTokenExtensions
|
||||
{
|
||||
static readonly Action<object> cancellationTokenCallback = Callback;
|
||||
static readonly Action<object> disposeCallback = DisposeCallback;
|
||||
|
||||
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -75,6 +76,17 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken)
|
||||
{
|
||||
return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable);
|
||||
}
|
||||
|
||||
static void DisposeCallback(object state)
|
||||
{
|
||||
var d = (IDisposable)state;
|
||||
d.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public struct CancellationTokenAwaitable
|
||||
|
||||
@@ -41,7 +41,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
// runner is finished, return first.
|
||||
if (runner != null)
|
||||
{
|
||||
#if ENABLE_IL2CPP
|
||||
// workaround for IL2CPP bug.
|
||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
|
||||
#else
|
||||
runner.Return();
|
||||
#endif
|
||||
runner = null;
|
||||
}
|
||||
|
||||
@@ -56,7 +61,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
// runner is finished, return.
|
||||
if (runner != null)
|
||||
{
|
||||
#if ENABLE_IL2CPP
|
||||
// workaround for IL2CPP bug.
|
||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
|
||||
#else
|
||||
runner.Return();
|
||||
#endif
|
||||
runner = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
Action MoveNext { get; }
|
||||
void Return();
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
Action ReturnAction { get; }
|
||||
#endif
|
||||
}
|
||||
|
||||
internal interface IStateMachineRunnerPromise : IUniTaskSource
|
||||
@@ -32,6 +36,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
|
||||
internal static class StateMachineUtility
|
||||
{
|
||||
// Get AsyncStateMachine internal state to check IL2CPP bug
|
||||
public static int GetState(IAsyncStateMachine stateMachine)
|
||||
{
|
||||
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
||||
@@ -46,16 +51,19 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
|
||||
#else
|
||||
TStateMachine stateMachine;
|
||||
public Action ReturnAction { get; }
|
||||
#endif
|
||||
|
||||
TStateMachine stateMachine;
|
||||
|
||||
public Action MoveNext { get; }
|
||||
|
||||
public AsyncUniTaskVoid()
|
||||
{
|
||||
MoveNext = Run;
|
||||
#if ENABLE_IL2CPP
|
||||
ReturnAction = Return;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
|
||||
@@ -118,18 +126,19 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
|
||||
#else
|
||||
TStateMachine stateMachine;
|
||||
readonly Action returnDelegate;
|
||||
#endif
|
||||
|
||||
public Action MoveNext { get; }
|
||||
|
||||
TStateMachine stateMachine;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncUniTask()
|
||||
{
|
||||
MoveNext = Run;
|
||||
#if ENABLE_IL2CPP
|
||||
returnDelegate = Return;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
|
||||
@@ -151,6 +160,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
||||
}
|
||||
|
||||
void Return()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
stateMachine = default;
|
||||
pool.TryPush(this);
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
@@ -196,7 +213,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if ENABLE_IL2CPP
|
||||
// workaround for IL2CPP bug.
|
||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
||||
#else
|
||||
TryReturn();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,18 +255,20 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
IAsyncStateMachine stateMachine; // unfortunatelly boxed to fix IL2CPP issue.
|
||||
#else
|
||||
TStateMachine stateMachine;
|
||||
readonly Action returnDelegate;
|
||||
#endif
|
||||
|
||||
public Action MoveNext { get; }
|
||||
|
||||
TStateMachine stateMachine;
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncUniTask()
|
||||
{
|
||||
MoveNext = Run;
|
||||
#if ENABLE_IL2CPP
|
||||
returnDelegate = Return;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
|
||||
@@ -257,11 +281,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
|
||||
runnerPromiseFieldRef = result; // set runner before copied.
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
|
||||
// UnityEngine.Debug.Log($"SetStateMachine State:" + StateMachineUtility.GetState(stateMachine));
|
||||
}
|
||||
|
||||
|
||||
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
||||
|
||||
static AsyncUniTask()
|
||||
@@ -269,6 +290,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
||||
}
|
||||
|
||||
void Return()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
stateMachine = default;
|
||||
pool.TryPush(this);
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
@@ -315,7 +344,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if ENABLE_IL2CPP
|
||||
// workaround for IL2CPP bug.
|
||||
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
||||
#else
|
||||
TryReturn();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
263
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Subscribe.cs
Normal file
263
src/UniTask/Assets/Plugins/UniTask/Runtime/Linq/Subscribe.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Subscribes = Cysharp.Threading.Tasks.Linq.Subscribe;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Linq
|
||||
{
|
||||
public static partial class UniTaskAsyncEnumerable
|
||||
{
|
||||
// OnNext
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> action)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> action, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(action, nameof(action));
|
||||
|
||||
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// OnNext, OnError
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onError, nameof(onError));
|
||||
|
||||
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// OnNext, OnCompleted
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action onCompleted)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(onNext, nameof(onNext));
|
||||
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
|
||||
|
||||
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
|
||||
}
|
||||
|
||||
// IObserver
|
||||
|
||||
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(observer, nameof(observer));
|
||||
|
||||
var cts = new CancellationTokenDisposable();
|
||||
Subscribes.SubscribeCore(source, observer, cts.Token).Forget();
|
||||
return cts;
|
||||
}
|
||||
|
||||
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(source, nameof(source));
|
||||
Error.ThrowArgumentNullException(observer, nameof(observer));
|
||||
|
||||
Subscribes.SubscribeCore(source, observer, cancellationToken).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class CancellationTokenDisposable : IDisposable
|
||||
{
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
public CancellationToken Token => cts.Token;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!cts.IsCancellationRequested)
|
||||
{
|
||||
cts.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Subscribe
|
||||
{
|
||||
public static readonly Action<Exception> NopError = _ => { };
|
||||
public static readonly Action NopCompleted = () => { };
|
||||
|
||||
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current);
|
||||
}
|
||||
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 SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
onNext(e.Current).Forget();
|
||||
}
|
||||
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 SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer, CancellationToken cancellationToken)
|
||||
{
|
||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||
try
|
||||
{
|
||||
while (await e.MoveNextAsync())
|
||||
{
|
||||
observer.OnNext(e.Current);
|
||||
}
|
||||
observer.OnCompleted();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException) return;
|
||||
|
||||
observer.OnError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
await e.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,15 +248,18 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
return current;
|
||||
}
|
||||
|
||||
if (queuedResult.Count != 0)
|
||||
lock (queuedResult)
|
||||
{
|
||||
current = queuedResult.Dequeue();
|
||||
useCachedCurrent = true;
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default; // undefined.
|
||||
if (queuedResult.Count != 0)
|
||||
{
|
||||
current = queuedResult.Dequeue();
|
||||
useCachedCurrent = true;
|
||||
return current;
|
||||
}
|
||||
else
|
||||
{
|
||||
return default; // undefined.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
|
||||
{
|
||||
this.updateTiming = updateTiming;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
|
||||
@@ -104,6 +104,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.dueTimePhase = true;
|
||||
this.updateTiming = updateTiming;
|
||||
this.ignoreTimeScale = ignoreTimeScale;
|
||||
this.cancellationToken = cancellationToken;
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
}
|
||||
@@ -223,6 +224,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||
this.dueTimePhase = true;
|
||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||
this.periodFrameCount = periodFrameCount;
|
||||
this.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 2);
|
||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "com.cysharp.unitask",
|
||||
"displayName": "UniTask",
|
||||
"version": "2.0.15",
|
||||
"version": "2.0.17",
|
||||
"unity": "2018.4",
|
||||
"description": "Provides an efficient async/await integration to Unity.",
|
||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||
|
||||
@@ -429,7 +429,9 @@ public class SandboxMain : MonoBehaviour
|
||||
|
||||
void Start()
|
||||
{
|
||||
PlayerLoopInfo.Inject();
|
||||
UnityEngine.Debug.Log("Start:" + PlayerLoopInfo.CurrentLoopType);
|
||||
|
||||
//PlayerLoopInfo.Inject();
|
||||
|
||||
//_ = AsyncFixedUpdate();
|
||||
//StartCoroutine(CoroutineFixedUpdate());
|
||||
@@ -438,8 +440,13 @@ public class SandboxMain : MonoBehaviour
|
||||
|
||||
// Application.logMessageReceived += Application_logMessageReceived;
|
||||
|
||||
// var rp = new AsyncReactiveProperty<int>();
|
||||
|
||||
|
||||
// rp.AddTo(this.GetCancellationTokenOnDestroy());
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -969,6 +976,7 @@ public class PlayerLoopInfo
|
||||
|
||||
public static Type CurrentLoopType { get; private set; }
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void Inject()
|
||||
{
|
||||
var system = PlayerLoop.GetCurrentPlayerLoop();
|
||||
|
||||
@@ -443,6 +443,7 @@ namespace Cysharp.Threading.TasksTests
|
||||
public void OnError(Exception error) => OnErrorCalled = true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -83,8 +83,7 @@ namespace Cysharp.Threading.TasksTests
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,379 +16,170 @@ 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);
|
||||
// }
|
||||
//});
|
||||
|
||||
//[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);
|
||||
|
||||
// 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));
|
||||
//});
|
||||
|
||||
|
||||
//[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();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
//});
|
||||
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 TimerFrameSinglePre2() => UniTask.ToCoroutine(async () =>
|
||||
public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
||||
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
|
||||
}
|
||||
//Debug.Log("------------------");
|
||||
//{
|
||||
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
||||
//}
|
||||
});
|
||||
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFrameSinglePre2() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// {
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await new MyTimerFrame(0, null)/*.Select(_ => Time.frameCount)*/.ToArrayAsync();
|
||||
// Debug.Log("OK 0 ------------------");
|
||||
// }
|
||||
// {
|
||||
// var xs = await new MyTimerFrame(1, null)/*.Select(_ =>
|
||||
// {
|
||||
// var t = Time.frameCount;
|
||||
// UnityEngine.Debug.Log("store frameCount:" + t);
|
||||
// return t;
|
||||
// })*/.ToArrayAsync();
|
||||
// }
|
||||
//});
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
// var xs = await UniTaskAsyncEnumerable.Return(UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None))/*.Select(_ => Time.frameCount)*/.ToArrayAsync();
|
||||
// xs[0].Should().Be(initialFrame);
|
||||
// Debug.Log("OK 0 ------------------");
|
||||
// }
|
||||
// {
|
||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
// var initialFrame = Time.frameCount;
|
||||
// Debug.Log("initialFrame:" + initialFrame);
|
||||
// var xs = await UniTaskAsyncEnumerable.Return(UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None))/*.Select(_ =>
|
||||
// {
|
||||
// var t = Time.frameCount;
|
||||
// UnityEngine.Debug.Log("store frameCount:" + t);
|
||||
// return t;
|
||||
// })*/.ToArrayAsync();
|
||||
// Debug.Log("xs len:" + xs.Length);
|
||||
// Debug.Log("xs[0]:" + xs[0]);
|
||||
|
||||
// xs[0].Should().Be(initialFrame + 1);
|
||||
// Debug.Log("OK 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);
|
||||
// Debug.Log("OK 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);
|
||||
|
||||
// {
|
||||
// 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]);
|
||||
// }
|
||||
//});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class DelayTest2
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator TimerFrameSinglePre2() => UniTask.ToCoroutine(async () =>
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
});
|
||||
|
||||
|
||||
[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();
|
||||
|
||||
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 () =>
|
||||
{
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
|
||||
xs[0].Should().Be(initialFrame);
|
||||
|
||||
}
|
||||
Debug.Log("------------------");
|
||||
{
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
||||
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||
var initialFrame = Time.frameCount;
|
||||
|
||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ =>
|
||||
{
|
||||
var t = Time.frameCount;
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
[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);
|
||||
|
||||
{
|
||||
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]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class ThreadRunner
|
||||
{
|
||||
Thread thread;
|
||||
|
||||
public void Start(IPlayerLoopItem runner)
|
||||
{
|
||||
thread = new Thread(() =>
|
||||
{
|
||||
Thread.Sleep(30);
|
||||
while (runner.MoveNext())
|
||||
{
|
||||
Thread.Sleep(30);
|
||||
}
|
||||
});
|
||||
|
||||
thread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
internal class MyTimerFrame : IUniTaskAsyncEnumerable<AsyncUnit>
|
||||
{
|
||||
//readonly PlayerLoopTiming updateTiming;
|
||||
readonly int dueTimeFrameCount;
|
||||
readonly int? periodFrameCount;
|
||||
|
||||
public MyTimerFrame(int dueTimeFrameCount, int? periodFrameCount)
|
||||
{
|
||||
//this.updateTiming = updateTiming;
|
||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||
this.periodFrameCount = periodFrameCount;
|
||||
}
|
||||
|
||||
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, cancellationToken);
|
||||
}
|
||||
|
||||
class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
|
||||
{
|
||||
readonly int dueTimeFrameCount;
|
||||
readonly int? periodFrameCount;
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
int initialFrame;
|
||||
int currentFrame;
|
||||
bool dueTimePhase;
|
||||
bool completed;
|
||||
bool disposed;
|
||||
ThreadRunner runner;
|
||||
|
||||
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, CancellationToken cancellationToken)
|
||||
{
|
||||
if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0;
|
||||
if (periodFrameCount != null)
|
||||
{
|
||||
if (periodFrameCount <= 0) periodFrameCount = 1;
|
||||
}
|
||||
|
||||
//this.initialFrame = Time.frameCount;
|
||||
this.dueTimePhase = true;
|
||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||
this.periodFrameCount = periodFrameCount;
|
||||
|
||||
//TaskTracker.TrackActiveTask(this, 2);
|
||||
//PlayerLoopHelper.AddAction(updateTiming, this);
|
||||
|
||||
runner = new ThreadRunner();
|
||||
runner.Start(this);
|
||||
}
|
||||
|
||||
public AsyncUnit Current => default;
|
||||
|
||||
public UniTask<bool> MoveNextAsync()
|
||||
{
|
||||
// return false instead of throw
|
||||
if (disposed || cancellationToken.IsCancellationRequested || completed) return default;
|
||||
|
||||
|
||||
// reset value here.
|
||||
this.currentFrame = 0;
|
||||
|
||||
completionSource.Reset();
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
disposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
UnityEngine.Debug.Log("Called MoveNext");
|
||||
if (disposed || cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
UnityEngine.Debug.Log("Disposing");
|
||||
completionSource.TrySetResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dueTimePhase)
|
||||
{
|
||||
UnityEngine.Debug.Log("In DueTime Phase");
|
||||
if (currentFrame == 0)
|
||||
{
|
||||
if (dueTimeFrameCount == 0)
|
||||
{
|
||||
dueTimePhase = false;
|
||||
completionSource.TrySetResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// skip in initial frame.
|
||||
/*
|
||||
UnityEngine.Debug.Log("(Init, frameConut)" + (initialFrame, Time.frameCount));
|
||||
if (initialFrame == Time.frameCount)
|
||||
{
|
||||
UnityEngine.Debug.Log("Skip Here");
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
UnityEngine.Debug.Log("Which Go?");
|
||||
if (++currentFrame >= dueTimeFrameCount)
|
||||
{
|
||||
UnityEngine.Debug.Log("END Go?");
|
||||
dueTimePhase = false;
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.Log("NG Go?");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (periodFrameCount == null)
|
||||
{
|
||||
UnityEngine.Debug.Log("PERIOD");
|
||||
completed = true;
|
||||
completionSource.TrySetResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (++currentFrame >= periodFrameCount)
|
||||
{
|
||||
completionSource.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -556,6 +556,7 @@ PlayerSettings:
|
||||
scriptingDefineSymbols: {}
|
||||
platformArchitecture: {}
|
||||
scriptingBackend:
|
||||
Android: 1
|
||||
Standalone: 1
|
||||
il2cppCompilerConfiguration: {}
|
||||
managedStrippingLevel: {}
|
||||
|
||||
Reference in New Issue
Block a user