mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 11:30:09 +00:00
Compare commits
30 Commits
test_il2cp
...
2.0.17
| 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 | ||
|
|
80704e489d | ||
|
|
3c0aa03643 | ||
|
|
37cd00d347 |
3
.github/workflows/build-debug.yml
vendored
3
.github/workflows/build-debug.yml
vendored
@@ -26,9 +26,10 @@ jobs:
|
|||||||
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
|
- run: dotnet test -c Debug ./src/UniTask.NetCoreTests/UniTask.NetCoreTests.csproj
|
||||||
|
|
||||||
build-unity:
|
build-unity:
|
||||||
|
if: "(github.event == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
unity: ['2019.3.9f1', '2020.1.0b5']
|
unity: ["2019.3.9f1", "2020.1.0b5"]
|
||||||
include:
|
include:
|
||||||
- unity: 2019.3.9f1
|
- unity: 2019.3.9f1
|
||||||
license: UNITY_2019_3
|
license: UNITY_2019_3
|
||||||
|
|||||||
83
README.md
83
README.md
@@ -2,7 +2,7 @@ UniTask
|
|||||||
===
|
===
|
||||||
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases)
|
[](https://github.com/Cysharp/UniTask/actions) [](https://github.com/Cysharp/UniTask/releases)
|
||||||
|
|
||||||
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
|
* Struct based `UniTask<T>` and custom AsyncMethodBuilder to achive zero allocation
|
||||||
* All Unity AsyncOperations and Coroutine to awaitable
|
* 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
|
* TaskTracker window to prevent memory leak
|
||||||
* Highly compatible behaviour with Task/ValueTask/IValueTaskSource
|
* 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 -->
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
@@ -29,6 +32,7 @@ Provides an efficient async/await integration to Unity.
|
|||||||
- [Awaitable Events](#awaitable-events)
|
- [Awaitable Events](#awaitable-events)
|
||||||
- [Channel](#channel)
|
- [Channel](#channel)
|
||||||
- [For Unit Testing](#for-unit-testing)
|
- [For Unit Testing](#for-unit-testing)
|
||||||
|
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
||||||
- [Pooling Configuration](#pooling-configuration)
|
- [Pooling Configuration](#pooling-configuration)
|
||||||
- [API References](#api-references)
|
- [API References](#api-references)
|
||||||
- [UPM Package](#upm-package)
|
- [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.
|
> 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`.
|
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.
|
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.
|
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
|
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.
|
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,6 +761,8 @@ 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.
|
||||||
|
|
||||||
API References
|
API References
|
||||||
---
|
---
|
||||||
UniTask's API References is hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate).
|
UniTask's API References is hosted at [cysharp.github.io/UniTask](https://cysharp.github.io/UniTask/api/Cysharp.Threading.Tasks.html) by [DocFX](https://dotnet.github.io/docfx/) and [Cysharp/DocfXTemplate](https://github.com/Cysharp/DocfxTemplate).
|
||||||
@@ -708,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`.
|
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
|
### Install via OpenUPM
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,85 @@ namespace NetCoreTests
|
|||||||
state.Value.Should().Be(20);
|
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; }
|
T Value { get; }
|
||||||
IUniTaskAsyncEnumerable<T> WithoutCurrent();
|
IUniTaskAsyncEnumerable<T> WithoutCurrent();
|
||||||
|
UniTask<T> WaitAsync(CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>
|
public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>
|
||||||
@@ -69,6 +70,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return latestValue?.ToString();
|
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 bool isValueType;
|
||||||
|
|
||||||
static AsyncReactiveProperty()
|
static AsyncReactiveProperty()
|
||||||
@@ -76,7 +82,143 @@ namespace Cysharp.Threading.Tasks
|
|||||||
isValueType = typeof(T).IsValueType;
|
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;
|
readonly AsyncReactiveProperty<T> parent;
|
||||||
|
|
||||||
@@ -253,6 +395,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return latestValue?.ToString();
|
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 bool isValueType;
|
||||||
|
|
||||||
static ReadOnlyAsyncReactiveProperty()
|
static ReadOnlyAsyncReactiveProperty()
|
||||||
@@ -260,7 +407,143 @@ namespace Cysharp.Threading.Tasks
|
|||||||
isValueType = typeof(T).IsValueType;
|
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;
|
readonly ReadOnlyAsyncReactiveProperty<T> parent;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
public static class CancellationTokenExtensions
|
public static class CancellationTokenExtensions
|
||||||
{
|
{
|
||||||
static readonly Action<object> cancellationTokenCallback = Callback;
|
static readonly Action<object> cancellationTokenCallback = Callback;
|
||||||
|
static readonly Action<object> disposeCallback = DisposeCallback;
|
||||||
|
|
||||||
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
|
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
|
public struct CancellationTokenAwaitable
|
||||||
|
|||||||
@@ -41,7 +41,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
// runner is finished, return first.
|
// runner is finished, return first.
|
||||||
if (runner != null)
|
if (runner != null)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
// workaround for IL2CPP bug.
|
||||||
|
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
|
||||||
|
#else
|
||||||
runner.Return();
|
runner.Return();
|
||||||
|
#endif
|
||||||
runner = null;
|
runner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +61,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
// runner is finished, return.
|
// runner is finished, return.
|
||||||
if (runner != null)
|
if (runner != null)
|
||||||
{
|
{
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
// workaround for IL2CPP bug.
|
||||||
|
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, runner.ReturnAction);
|
||||||
|
#else
|
||||||
runner.Return();
|
runner.Return();
|
||||||
|
#endif
|
||||||
runner = null;
|
runner = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
Action MoveNext { get; }
|
Action MoveNext { get; }
|
||||||
void Return();
|
void Return();
|
||||||
|
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
Action ReturnAction { get; }
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface IStateMachineRunnerPromise : IUniTaskSource
|
internal interface IStateMachineRunnerPromise : IUniTaskSource
|
||||||
@@ -32,6 +36,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
|
|
||||||
internal static class StateMachineUtility
|
internal static class StateMachineUtility
|
||||||
{
|
{
|
||||||
|
// Get AsyncStateMachine internal state to check IL2CPP bug
|
||||||
public static int GetState(IAsyncStateMachine stateMachine)
|
public static int GetState(IAsyncStateMachine stateMachine)
|
||||||
{
|
{
|
||||||
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
||||||
@@ -45,6 +50,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
||||||
|
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
public Action ReturnAction { get; }
|
||||||
|
#endif
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
TStateMachine stateMachine;
|
||||||
|
|
||||||
public Action MoveNext { get; }
|
public Action MoveNext { get; }
|
||||||
@@ -52,6 +61,9 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
public AsyncUniTaskVoid()
|
public AsyncUniTaskVoid()
|
||||||
{
|
{
|
||||||
MoveNext = Run;
|
MoveNext = Run;
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
ReturnAction = Return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
|
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
|
||||||
@@ -113,15 +125,20 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
#if ENABLE_IL2CPP
|
||||||
|
readonly Action returnDelegate;
|
||||||
|
#endif
|
||||||
public Action MoveNext { get; }
|
public Action MoveNext { get; }
|
||||||
|
|
||||||
|
TStateMachine stateMachine;
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
AsyncUniTask()
|
AsyncUniTask()
|
||||||
{
|
{
|
||||||
MoveNext = Run;
|
MoveNext = Run;
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
returnDelegate = Return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
|
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
|
||||||
@@ -143,6 +160,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Return()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
stateMachine = default;
|
||||||
|
pool.TryPush(this);
|
||||||
|
}
|
||||||
|
|
||||||
bool TryReturn()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
@@ -188,7 +213,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
// workaround for IL2CPP bug.
|
||||||
|
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
||||||
|
#else
|
||||||
TryReturn();
|
TryReturn();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,15 +254,21 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
{
|
{
|
||||||
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
||||||
|
|
||||||
TStateMachine stateMachine;
|
#if ENABLE_IL2CPP
|
||||||
|
readonly Action returnDelegate;
|
||||||
|
#endif
|
||||||
|
|
||||||
public Action MoveNext { get; }
|
public Action MoveNext { get; }
|
||||||
|
|
||||||
|
TStateMachine stateMachine;
|
||||||
UniTaskCompletionSourceCore<T> core;
|
UniTaskCompletionSourceCore<T> core;
|
||||||
|
|
||||||
AsyncUniTask()
|
AsyncUniTask()
|
||||||
{
|
{
|
||||||
MoveNext = Run;
|
MoveNext = Run;
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
returnDelegate = Return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
|
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
|
||||||
@@ -245,10 +281,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
|
|
||||||
runnerPromiseFieldRef = result; // set runner before copied.
|
runnerPromiseFieldRef = result; // set runner before copied.
|
||||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||||
UnityEngine.Debug.Log($"SetStateMachine State:" + StateMachineUtility.GetState(stateMachine));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
||||||
|
|
||||||
static AsyncUniTask()
|
static AsyncUniTask()
|
||||||
@@ -256,6 +290,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Return()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
stateMachine = default;
|
||||||
|
pool.TryPush(this);
|
||||||
|
}
|
||||||
|
|
||||||
bool TryReturn()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
@@ -268,7 +310,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
void Run()
|
void Run()
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
|
// UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
|
||||||
stateMachine.MoveNext();
|
stateMachine.MoveNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +344,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
#if ENABLE_IL2CPP
|
||||||
|
// workaround for IL2CPP bug.
|
||||||
|
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
||||||
|
#else
|
||||||
TryReturn();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
{
|
{
|
||||||
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
internal static async UniTask<TSource[]> ToArrayAsync<TSource>(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
UnityEngine.Debug.Log("Called ToArray");
|
// UnityEngine.Debug.Log("Called ToArray");
|
||||||
|
|
||||||
var pool = ArrayPool<TSource>.Shared;
|
var pool = ArrayPool<TSource>.Shared;
|
||||||
var array = pool.Rent(16);
|
var array = pool.Rent(16);
|
||||||
|
|||||||
@@ -248,15 +248,18 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queuedResult.Count != 0)
|
lock (queuedResult)
|
||||||
{
|
{
|
||||||
current = queuedResult.Dequeue();
|
if (queuedResult.Count != 0)
|
||||||
useCachedCurrent = true;
|
{
|
||||||
return current;
|
current = queuedResult.Dequeue();
|
||||||
}
|
useCachedCurrent = true;
|
||||||
else
|
return current;
|
||||||
{
|
}
|
||||||
return default; // undefined.
|
else
|
||||||
|
{
|
||||||
|
return default; // undefined.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
|
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.updateTiming = updateTiming;
|
this.updateTiming = updateTiming;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(this, 2);
|
TaskTracker.TrackActiveTask(this, 2);
|
||||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
this.dueTimePhase = true;
|
this.dueTimePhase = true;
|
||||||
this.updateTiming = updateTiming;
|
this.updateTiming = updateTiming;
|
||||||
this.ignoreTimeScale = ignoreTimeScale;
|
this.ignoreTimeScale = ignoreTimeScale;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
TaskTracker.TrackActiveTask(this, 2);
|
TaskTracker.TrackActiveTask(this, 2);
|
||||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||||
}
|
}
|
||||||
@@ -223,6 +224,7 @@ namespace Cysharp.Threading.Tasks.Linq
|
|||||||
this.dueTimePhase = true;
|
this.dueTimePhase = true;
|
||||||
this.dueTimeFrameCount = dueTimeFrameCount;
|
this.dueTimeFrameCount = dueTimeFrameCount;
|
||||||
this.periodFrameCount = periodFrameCount;
|
this.periodFrameCount = periodFrameCount;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(this, 2);
|
TaskTracker.TrackActiveTask(this, 2);
|
||||||
PlayerLoopHelper.AddAction(updateTiming, this);
|
PlayerLoopHelper.AddAction(updateTiming, this);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"version": "2.0.14",
|
"version": "2.0.17",
|
||||||
"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" ],
|
||||||
|
|||||||
@@ -413,18 +413,38 @@ public class SandboxMain : MonoBehaviour
|
|||||||
Debug.Log("after");
|
Debug.Log("after");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async UniTaskVoid ExecuteAsync()
|
||||||
|
{
|
||||||
|
Debug.Log("1");
|
||||||
|
{
|
||||||
|
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
||||||
|
}
|
||||||
|
Debug.Log("------------------");
|
||||||
|
{
|
||||||
|
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
||||||
|
Debug.Log("2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
PlayerLoopInfo.Inject();
|
UnityEngine.Debug.Log("Start:" + PlayerLoopInfo.CurrentLoopType);
|
||||||
|
|
||||||
|
//PlayerLoopInfo.Inject();
|
||||||
|
|
||||||
//_ = AsyncFixedUpdate();
|
//_ = AsyncFixedUpdate();
|
||||||
//StartCoroutine(CoroutineFixedUpdate());
|
//StartCoroutine(CoroutineFixedUpdate());
|
||||||
|
|
||||||
//StartCoroutine(TestCoroutine().ToCoroutine());
|
//StartCoroutine(TestCoroutine().ToCoroutine());
|
||||||
|
|
||||||
Application.logMessageReceived += Application_logMessageReceived;
|
// Application.logMessageReceived += Application_logMessageReceived;
|
||||||
|
|
||||||
|
// var rp = new AsyncReactiveProperty<int>();
|
||||||
|
|
||||||
|
|
||||||
|
// rp.AddTo(this.GetCancellationTokenOnDestroy());
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -432,13 +452,9 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||||
{
|
{
|
||||||
{
|
_ = ExecuteAsync();
|
||||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
|
||||||
}
|
await UniTask.Yield();
|
||||||
Debug.Log("------------------");
|
|
||||||
{
|
|
||||||
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
//await DelayCheck();
|
//await DelayCheck();
|
||||||
/*
|
/*
|
||||||
@@ -960,6 +976,7 @@ public class PlayerLoopInfo
|
|||||||
|
|
||||||
public static Type CurrentLoopType { get; private set; }
|
public static Type CurrentLoopType { get; private set; }
|
||||||
|
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
public static void Inject()
|
public static void Inject()
|
||||||
{
|
{
|
||||||
var system = PlayerLoop.GetCurrentPlayerLoop();
|
var system = PlayerLoop.GetCurrentPlayerLoop();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 370f60b2e4cd92d4faafda153c9c5f8a
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -443,6 +443,7 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
public void OnError(Exception error) => OnErrorCalled = true;
|
public void OnError(Exception error) => OnErrorCalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,379 +16,170 @@ namespace Cysharp.Threading.TasksTests
|
|||||||
{
|
{
|
||||||
public class DelayTest
|
public class DelayTest
|
||||||
{
|
{
|
||||||
//[UnityTest]
|
[UnityTest]
|
||||||
//public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
|
public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
|
||||||
//{
|
{
|
||||||
// for (int i = 1; i < 5; i++)
|
for (int i = 1; i < 5; i++)
|
||||||
// {
|
{
|
||||||
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
|
||||||
// var frameCount = Time.frameCount;
|
var frameCount = Time.frameCount;
|
||||||
// await UniTask.DelayFrame(i);
|
await UniTask.DelayFrame(i);
|
||||||
// Time.frameCount.Should().Be(frameCount + i);
|
Time.frameCount.Should().Be(frameCount + i);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// for (int i = 1; i < 5; i++)
|
for (int i = 1; i < 5; i++)
|
||||||
// {
|
{
|
||||||
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||||
// var frameCount = Time.frameCount;
|
var frameCount = Time.frameCount;
|
||||||
// await UniTask.DelayFrame(i);
|
await UniTask.DelayFrame(i);
|
||||||
// Time.frameCount.Should().Be(frameCount + 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);
|
|
||||||
//});
|
|
||||||
|
|
||||||
[UnityTest]
|
[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]
|
[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: {}
|
scriptingDefineSymbols: {}
|
||||||
platformArchitecture: {}
|
platformArchitecture: {}
|
||||||
scriptingBackend:
|
scriptingBackend:
|
||||||
|
Android: 1
|
||||||
Standalone: 1
|
Standalone: 1
|
||||||
il2cppCompilerConfiguration: {}
|
il2cppCompilerConfiguration: {}
|
||||||
managedStrippingLevel: {}
|
managedStrippingLevel: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user