mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-16 12:00:10 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b64f31eb0b | ||
|
|
38d159b69e | ||
|
|
d5455f3716 | ||
|
|
a72ceeba11 | ||
|
|
c6b7d332b2 | ||
|
|
f37278f2a6 | ||
|
|
3f3e03b83d | ||
|
|
c99d3eb3c3 | ||
|
|
08d5183e7e | ||
|
|
51769b2224 | ||
|
|
6ec0ed8d61 | ||
|
|
2e35324403 | ||
|
|
e9474649c4 | ||
|
|
a8e0ce50c8 | ||
|
|
db7ddba735 | ||
|
|
1999d94b33 | ||
|
|
44af123b6c |
7
.github/workflows/build-debug.yml
vendored
7
.github/workflows/build-debug.yml
vendored
@@ -42,13 +42,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- run: apt update && apt install git -y
|
- run: apt update && apt install git -y
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
# create unity activation file and store to artifacts.
|
|
||||||
- run: /opt/Unity/Editor/Unity -quit -batchmode -nographics -logFile -createManualActivationFile || exit 0
|
|
||||||
- uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: Unity_v${{ matrix.unity }}.alf
|
|
||||||
path: ./Unity_v${{ matrix.unity }}.alf
|
|
||||||
# activate Unity from manual license file(ulf)
|
|
||||||
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
|
- run: echo -n "$UNITY_LICENSE" >> .Unity.ulf
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
UNITY_LICENSE: ${{ secrets[matrix.license] }}
|
||||||
|
|||||||
40
.gitignore
vendored
40
.gitignore
vendored
@@ -213,3 +213,43 @@ src/UniTask/UniTask.Addressables.csproj
|
|||||||
src/UniTask/UniTask.DOTween.csproj
|
src/UniTask/UniTask.DOTween.csproj
|
||||||
|
|
||||||
src/UniTask/UniTask.TextMeshPro.csproj
|
src/UniTask/UniTask.TextMeshPro.csproj
|
||||||
|
|
||||||
|
src/UniTask/RuntimeUnitTestToolkit.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/TempAsm.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UniTask.Addressables.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UniTask.DOTween.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UniTask.Linq.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UniTask.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UniTask.Tests.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UniTask.TextMeshPro.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.Addressables.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.Analytics.DataPrivacy.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.ResourceManager.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.ScriptableBuildPipeline.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.TextMeshPro.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Unity.Timeline.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UnityEngine.Advertisements.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UnityEngine.Monetization.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UnityEngine.TestRunner.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/UnityEngine.UI.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/DOTween.Modules.Player.csproj
|
||||||
|
|
||||||
|
src/UniTask/Assembly-CSharp.Player.csproj
|
||||||
|
|||||||
66
README.md
66
README.md
@@ -34,6 +34,8 @@ Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await f
|
|||||||
- [For Unit Testing](#for-unit-testing)
|
- [For Unit Testing](#for-unit-testing)
|
||||||
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
- [Compare with Standard Task API](#compare-with-standard-task-api)
|
||||||
- [Pooling Configuration](#pooling-configuration)
|
- [Pooling Configuration](#pooling-configuration)
|
||||||
|
- [Allocation on Profiler](#allocation-on-profiler)
|
||||||
|
- [UniTaskSynchronizationContext](#unitasksynchronizationcontext)
|
||||||
- [API References](#api-references)
|
- [API References](#api-references)
|
||||||
- [UPM Package](#upm-package)
|
- [UPM Package](#upm-package)
|
||||||
- [Install via git URL](#install-via-git-url)
|
- [Install via git URL](#install-via-git-url)
|
||||||
@@ -150,25 +152,24 @@ UniTask provides three pattern of extension methods.
|
|||||||
|
|
||||||
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. Details of timing, see: [PlayerLoop](#playerloop) section.
|
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. Details of timing, see: [PlayerLoop](#playerloop) section.
|
||||||
|
|
||||||
|
> Note: AssetBundleRequest has `asset` and `allAssets`, in default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
|
||||||
|
|
||||||
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
|
The type of `UniTask` can use utility like `UniTask.WhenAll`, `UniTask.WhenAny`. It is like Task.WhenAll/WhenAny but return type is more useful, returns value tuple so can deconsrtuct each result and pass multiple type.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
public class SceneAssets
|
public async UniTaskVoid LoadManyAsync()
|
||||||
{
|
{
|
||||||
public SceneAssets()
|
// parallel load.
|
||||||
{
|
var (a, b, c) = await UniTask.WhenAll(
|
||||||
// parallel load.
|
LoadAsSprite("foo"),
|
||||||
var (a, b, c) = await UniTask.WhenAll(
|
LoadAsSprite("bar"),
|
||||||
LoadAsSprite("foo"),
|
LoadAsSprite("baz"));
|
||||||
LoadAsSprite("bar"),
|
}
|
||||||
LoadAsSprite("baz"));
|
|
||||||
}
|
|
||||||
|
|
||||||
async UniTask<Sprite> LoadAsSprite(string path)
|
async UniTask<Sprite> LoadAsSprite(string path)
|
||||||
{
|
{
|
||||||
var resource = await Resources.LoadAsync<Sprite>(path);
|
var resource = await Resources.LoadAsync<Sprite>(path);
|
||||||
return (resource as Sprite);
|
return (resource as Sprite);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -384,6 +385,16 @@ var playerLoop = ScriptBehaviourUpdateOrder.CurrentPlayerLoop;
|
|||||||
PlayerLoopHelper.Initialize(ref playerLoop);
|
PlayerLoopHelper.Initialize(ref playerLoop);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can diagnostic UniTask's player loop is ready by `PlayerLoopHelper.IsInjectedUniTaskPlayerLoop()`. And also `PlayerLoopHelper.DumpCurrentPlayerLoop` shows current all playerloop to console.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
||||||
|
PlayerLoopHelper.DumpCurrentPlayerLoop();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
async void vs async UniTaskVoid
|
async void vs async UniTaskVoid
|
||||||
---
|
---
|
||||||
`async void` is a standard C# task system so does not run on UniTask systems. It is better not to use. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and report error immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require to await it(fire and forget), use `UniTaskVoid` is better. Unfortunately to dismiss warning, require to using with `Forget()`.
|
`async void` is a standard C# task system so does not run on UniTask systems. It is better not to use. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and report error immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require to await it(fire and forget), use `UniTaskVoid` is better. Unfortunately to dismiss warning, require to using with `Forget()`.
|
||||||
@@ -824,7 +835,32 @@ foreach (var (type, size) in TaskPool.GetCacheSizeInfo())
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> In UnityEditor profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generate AsyncStateMachine as class on Debug build and as struct on Release build.
|
Allocation on Profiler
|
||||||
|
---
|
||||||
|
In UnityEditor profiler shows allocation of compiler generated AsyncStateMachine but it only occurs in debug(development) build. C# Compiler generate AsyncStateMachine as class on Debug build and as struct on Release build.
|
||||||
|
|
||||||
|
After Unity 2020.1 supports Code Optimization option on UnityEditor(right, footer).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can change C# compiler optimization to release, it removes AsyncStateMachine allocation. Andalso optimization option can set via `Compilation.CompilationPipeline-codeOptimization`, and `Compilation.CodeOptimization`.
|
||||||
|
|
||||||
|
UniTaskSynchronizationContext
|
||||||
|
---
|
||||||
|
Unity's default SynchronizationContext(`UnitySynchronizationContext`) is poor implementation for performance. UniTask itself is bypass `SynchronizationContext`(and `ExecutionContext`) so does not use it but if exists in `async Task`, still used it. `UniTaskSynchronizationContext` is replacement of `UnitySynchronizationContext`, it is better for performance.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class SyncContextInjecter
|
||||||
|
{
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
public static void Inject()
|
||||||
|
{
|
||||||
|
SynchronizationContext.SetSynchronizationContext(new UniTaskSynchronizationContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is an optional choice and is not always recommended; `UniTaskSynchronizationContext` is less performance than `async UniTask` and is not a complete UniTask replacement. It also does not guarantee full behavioral compatibility with the `UnitySynchronizationContext`.
|
||||||
|
|
||||||
API References
|
API References
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\ContinuationQueue.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\Internal\UnityWebRequestExtensions.cs;
|
||||||
|
|
||||||
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
|
||||||
|
|||||||
40
src/UniTask.NetCoreTests/WithCancellationTest.cs
Normal file
40
src/UniTask.NetCoreTests/WithCancellationTest.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace NetCoreTests
|
||||||
|
{
|
||||||
|
public class WithCancellationTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Standard()
|
||||||
|
{
|
||||||
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var v = await UniTask.Run(() => 10).WithCancellation(cts.Token);
|
||||||
|
|
||||||
|
v.Should().Be(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Cancel()
|
||||||
|
{
|
||||||
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var t = UniTask.Create(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||||
|
return 10;
|
||||||
|
}).WithCancellation(cts.Token);
|
||||||
|
|
||||||
|
cts.Cancel();
|
||||||
|
|
||||||
|
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await t)).CancellationToken.Should().Be(cts.Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
IEnumerator innerEnumerator;
|
IEnumerator innerEnumerator;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
|
int initialFrame;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<object> core;
|
UniTaskCompletionSourceCore<object> core;
|
||||||
|
|
||||||
@@ -66,10 +67,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.initialFrame = -1;
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
token = result.core.Version;
|
token = result.core.Version;
|
||||||
|
|
||||||
|
result.MoveNext(); // run immediately.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +112,19 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initialFrame == -1)
|
||||||
|
{
|
||||||
|
// Time can not touch in threadpool.
|
||||||
|
if (PlayerLoopHelper.IsMainThread)
|
||||||
|
{
|
||||||
|
initialFrame = Time.frameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (initialFrame == Time.frameCount)
|
||||||
|
{
|
||||||
|
return true; // already executed in first frame, skip.
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (innerEnumerator.MoveNext())
|
if (innerEnumerator.MoveNext())
|
||||||
|
|||||||
@@ -15,29 +15,25 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
#region AsyncOperationHandle
|
#region AsyncOperationHandle
|
||||||
|
|
||||||
public static AsyncOperationHandleAwaiter GetAwaiter(this AsyncOperationHandle handle)
|
public static UniTask.Awaiter GetAwaiter(this AsyncOperationHandle handle)
|
||||||
{
|
{
|
||||||
return new AsyncOperationHandleAwaiter(handle);
|
return ToUniTask(handle).GetAwaiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
public static UniTask WithCancellation(this AsyncOperationHandle handle, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||||
if (handle.IsDone)
|
|
||||||
{
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
return UniTask.FromException(handle.OperationException);
|
|
||||||
}
|
|
||||||
return UniTask.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UniTask(AsyncOperationHandleWithCancellationSource.Create(handle, cancellationToken, out var token), token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
public static UniTask ToUniTask(this AsyncOperationHandle handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||||
|
|
||||||
|
if (!handle.IsValid())
|
||||||
|
{
|
||||||
|
throw new Exception("Attempting to use an invalid operation handle");
|
||||||
|
}
|
||||||
|
|
||||||
if (handle.IsDone)
|
if (handle.IsDone)
|
||||||
{
|
{
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
if (handle.Status == AsyncOperationStatus.Failed)
|
||||||
@@ -95,29 +91,30 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class AsyncOperationHandleWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource>
|
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||||
{
|
{
|
||||||
static TaskPool<AsyncOperationHandleWithCancellationSource> pool;
|
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||||
public AsyncOperationHandleWithCancellationSource NextNode { get; set; }
|
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
static AsyncOperationHandleWithCancellationSource()
|
static AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource), () => pool.Size);
|
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly Action<AsyncOperationHandle> continuationAction;
|
readonly Action<AsyncOperationHandle> continuationAction;
|
||||||
AsyncOperationHandle handle;
|
AsyncOperationHandle handle;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
|
IProgress<float> progress;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
AsyncOperationHandleWithCancellationSource()
|
AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
continuationAction = Continuation;
|
continuationAction = Continuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource Create(AsyncOperationHandle handle, CancellationToken cancellationToken, out short token)
|
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -126,16 +123,17 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
if (!pool.TryPop(out var result))
|
||||||
{
|
{
|
||||||
result = new AsyncOperationHandleWithCancellationSource();
|
result = new AsyncOperationHandleConfiguredSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
result.handle = handle;
|
result.handle = handle;
|
||||||
|
result.progress = progress;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
handle.Completed += result.continuationAction;
|
handle.Completed += result.continuationAction;
|
||||||
|
|
||||||
@@ -204,125 +202,18 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (progress != null && handle.IsValid())
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
handle = default;
|
|
||||||
cancellationToken = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
|
||||||
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
|
||||||
|
|
||||||
static AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncOperationHandle handle;
|
|
||||||
IProgress<float> progress;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
|
||||||
|
|
||||||
AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource Create(AsyncOperationHandle handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncOperationHandleConfiguredSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.handle = handle;
|
|
||||||
result.progress = progress;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress != null)
|
|
||||||
{
|
{
|
||||||
progress.Report(handle.PercentComplete);
|
progress.Report(handle.PercentComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle.IsDone)
|
|
||||||
{
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
core.TrySetException(handle.OperationException);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
core.TrySetResult(AsyncUnit.Default);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryReturn()
|
bool TryReturn()
|
||||||
{
|
{
|
||||||
core.Reset();
|
|
||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
handle = default;
|
handle = default;
|
||||||
progress = default;
|
progress = default;
|
||||||
cancellationToken = default;
|
cancellationToken = default;
|
||||||
@@ -334,28 +225,25 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
#region AsyncOperationHandle_T
|
#region AsyncOperationHandle_T
|
||||||
|
|
||||||
public static AsyncOperationHandleAwaiter<T> GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
public static UniTask<T>.Awaiter GetAwaiter<T>(this AsyncOperationHandle<T> handle)
|
||||||
{
|
{
|
||||||
return new AsyncOperationHandleAwaiter<T>(handle);
|
return ToUniTask(handle).GetAwaiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
public static UniTask<T> WithCancellation<T>(this AsyncOperationHandle<T> handle, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
return ToUniTask(handle, cancellationToken: cancellationToken);
|
||||||
if (handle.IsDone)
|
|
||||||
{
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
return UniTask.FromException<T>(handle.OperationException);
|
|
||||||
}
|
|
||||||
return UniTask.FromResult(handle.Result);
|
|
||||||
}
|
|
||||||
return new UniTask<T>(AsyncOperationHandleWithCancellationSource<T>.Create(handle, cancellationToken, out var token), token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<T>(cancellationToken);
|
||||||
|
|
||||||
|
if (!handle.IsValid())
|
||||||
|
{
|
||||||
|
throw new Exception("Attempting to use an invalid operation handle");
|
||||||
|
}
|
||||||
|
|
||||||
if (handle.IsDone)
|
if (handle.IsDone)
|
||||||
{
|
{
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
if (handle.Status == AsyncOperationStatus.Failed)
|
||||||
@@ -368,75 +256,30 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion
|
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||||
{
|
{
|
||||||
AsyncOperationHandle<T> handle;
|
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||||
Action<AsyncOperationHandle> continuationAction;
|
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
||||||
|
|
||||||
public AsyncOperationHandleAwaiter(AsyncOperationHandle<T> handle)
|
static AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
this.handle = handle;
|
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||||
this.continuationAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCompleted => handle.IsDone;
|
|
||||||
|
|
||||||
public T GetResult()
|
|
||||||
{
|
|
||||||
if (continuationAction != null)
|
|
||||||
{
|
|
||||||
handle.CompletedTypeless -= continuationAction;
|
|
||||||
continuationAction = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
var e = handle.OperationException;
|
|
||||||
handle = default;
|
|
||||||
ExceptionDispatchInfo.Capture(e).Throw();
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = handle.Result;
|
|
||||||
handle = default;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
UnsafeOnCompleted(continuation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnsafeOnCompleted(Action continuation)
|
|
||||||
{
|
|
||||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
|
||||||
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
|
||||||
handle.CompletedTypeless += continuationAction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AsyncOperationHandleWithCancellationSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleWithCancellationSource<T>>
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncOperationHandleWithCancellationSource<T>> pool;
|
|
||||||
public AsyncOperationHandleWithCancellationSource<T> NextNode { get; set; }
|
|
||||||
|
|
||||||
static AsyncOperationHandleWithCancellationSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleWithCancellationSource<T>), () => pool.Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly Action<AsyncOperationHandle<T>> continuationAction;
|
readonly Action<AsyncOperationHandle<T>> continuationAction;
|
||||||
AsyncOperationHandle<T> handle;
|
AsyncOperationHandle<T> handle;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
|
IProgress<float> progress;
|
||||||
bool completed;
|
bool completed;
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
UniTaskCompletionSourceCore<T> core;
|
||||||
|
|
||||||
AsyncOperationHandleWithCancellationSource()
|
AsyncOperationHandleConfiguredSource()
|
||||||
{
|
{
|
||||||
continuationAction = Continuation;
|
continuationAction = Continuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, CancellationToken cancellationToken, out short token)
|
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -445,16 +288,17 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
if (!pool.TryPop(out var result))
|
||||||
{
|
{
|
||||||
result = new AsyncOperationHandleWithCancellationSource<T>();
|
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
result.handle = handle;
|
result.handle = handle;
|
||||||
result.cancellationToken = cancellationToken;
|
result.cancellationToken = cancellationToken;
|
||||||
result.completed = false;
|
result.completed = false;
|
||||||
|
result.progress = progress;
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
handle.Completed += result.continuationAction;
|
handle.Completed += result.continuationAction;
|
||||||
|
|
||||||
@@ -462,7 +306,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Continuation(AsyncOperationHandle<T> _)
|
void Continuation(AsyncOperationHandle<T> argHandle)
|
||||||
{
|
{
|
||||||
handle.Completed -= continuationAction;
|
handle.Completed -= continuationAction;
|
||||||
|
|
||||||
@@ -477,13 +321,13 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
core.TrySetCanceled(cancellationToken);
|
core.TrySetCanceled(cancellationToken);
|
||||||
}
|
}
|
||||||
else if (handle.Status == AsyncOperationStatus.Failed)
|
else if (argHandle.Status == AsyncOperationStatus.Failed)
|
||||||
{
|
{
|
||||||
core.TrySetException(handle.OperationException);
|
core.TrySetException(argHandle.OperationException);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
core.TrySetResult(handle.Result);
|
core.TrySetResult(argHandle.Result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -528,122 +372,11 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (progress != null && handle.IsValid())
|
||||||
}
|
|
||||||
|
|
||||||
bool TryReturn()
|
|
||||||
{
|
|
||||||
TaskTracker.RemoveTracking(this);
|
|
||||||
core.Reset();
|
|
||||||
handle = default;
|
|
||||||
cancellationToken = default;
|
|
||||||
return pool.TryPush(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
|
||||||
{
|
|
||||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
|
||||||
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
|
||||||
|
|
||||||
static AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncOperationHandle<T> handle;
|
|
||||||
IProgress<float> progress;
|
|
||||||
CancellationToken cancellationToken;
|
|
||||||
|
|
||||||
UniTaskCompletionSourceCore<T> core;
|
|
||||||
|
|
||||||
AsyncOperationHandleConfiguredSource()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IUniTaskSource<T> Create(AsyncOperationHandle<T> handle, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pool.TryPop(out var result))
|
|
||||||
{
|
|
||||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.handle = handle;
|
|
||||||
result.progress = progress;
|
|
||||||
result.cancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(result, 3);
|
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(timing, result);
|
|
||||||
|
|
||||||
token = result.core.Version;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetResult(short token)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return core.GetResult(token);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
TryReturn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IUniTaskSource.GetResult(short token)
|
|
||||||
{
|
|
||||||
GetResult(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus GetStatus(short token)
|
|
||||||
{
|
|
||||||
return core.GetStatus(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTaskStatus UnsafeGetStatus()
|
|
||||||
{
|
|
||||||
return core.UnsafeGetStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
||||||
{
|
|
||||||
core.OnCompleted(continuation, state, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
core.TrySetCanceled(cancellationToken);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (progress != null)
|
|
||||||
{
|
{
|
||||||
progress.Report(handle.PercentComplete);
|
progress.Report(handle.PercentComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle.IsDone)
|
|
||||||
{
|
|
||||||
if (handle.Status == AsyncOperationStatus.Failed)
|
|
||||||
{
|
|
||||||
core.TrySetException(handle.OperationException);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
core.TrySetResult(handle.Result);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,32 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
|
||||||
|
{
|
||||||
|
var loop = new PlayerLoopSystem
|
||||||
|
{
|
||||||
|
type = typeof(UniTaskSynchronizationContext),
|
||||||
|
updateDelegate = UniTaskSynchronizationContext.Run
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove items from previous initializations.
|
||||||
|
var source = loopSystem.subSystemList
|
||||||
|
.Where(ls => ls.type != typeof(UniTaskSynchronizationContext))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var dest = new System.Collections.Generic.List<PlayerLoopSystem>(source);
|
||||||
|
|
||||||
|
var index = dest.FindIndex(x => x.type.Name == "ScriptRunDelayedTasks");
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
index = dest.FindIndex(x => x.type.Name == "UniTaskLoopRunnerUpdate");
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.Insert(index + 1, loop);
|
||||||
|
|
||||||
|
return dest.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
static void Init()
|
static void Init()
|
||||||
{
|
{
|
||||||
@@ -246,6 +272,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
if (item != null) item.Run();
|
if (item != null) item.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniTaskSynchronizationContext.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -293,6 +321,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate),
|
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate),
|
||||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate));
|
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate));
|
||||||
|
|
||||||
|
// Insert UniTaskSynchronizationContext to Update loop
|
||||||
|
copyList[4].subSystemList = InsertUniTaskSynchronizationContext(copyList[4]);
|
||||||
|
|
||||||
playerLoop.subSystemList = copyList;
|
playerLoop.subSystemList = copyList;
|
||||||
PlayerLoop.SetPlayerLoop(playerLoop);
|
PlayerLoop.SetPlayerLoop(playerLoop);
|
||||||
}
|
}
|
||||||
@@ -306,6 +337,56 @@ namespace Cysharp.Threading.Tasks
|
|||||||
{
|
{
|
||||||
yielders[(int)timing].Enqueue(continuation);
|
yielders[(int)timing].Enqueue(continuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diagnostics helper
|
||||||
|
|
||||||
|
#if UNITY_2019_3_OR_NEWER
|
||||||
|
|
||||||
|
public static void DumpCurrentPlayerLoop()
|
||||||
|
{
|
||||||
|
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||||
|
|
||||||
|
var sb = new System.Text.StringBuilder();
|
||||||
|
sb.AppendLine($"PlayerLoop List");
|
||||||
|
foreach (var header in playerLoop.subSystemList)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("------{0}------", header.type.Name);
|
||||||
|
sb.AppendLine();
|
||||||
|
foreach (var subSystem in header.subSystemList)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("{0}", subSystem.type.Name);
|
||||||
|
sb.AppendLine();
|
||||||
|
|
||||||
|
if (subSystem.subSystemList != null)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogWarning("More Subsystem:" + subSystem.subSystemList.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInjectedUniTaskPlayerLoop()
|
||||||
|
{
|
||||||
|
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||||
|
|
||||||
|
foreach (var header in playerLoop.subSystemList)
|
||||||
|
{
|
||||||
|
foreach (var subSystem in header.subSystemList)
|
||||||
|
{
|
||||||
|
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,11 @@
|
|||||||
"autoReferenced": true,
|
"autoReferenced": true,
|
||||||
"defineConstraints": [],
|
"defineConstraints": [],
|
||||||
"versionDefines": [
|
"versionDefines": [
|
||||||
|
{
|
||||||
|
"name": "com.unity.modules.assetbundle",
|
||||||
|
"expression": "",
|
||||||
|
"define": "UNITASK_ASSETBUNDLE_SUPPORT"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"noEngineReferences": false
|
"noEngineReferences": false
|
||||||
}
|
}
|
||||||
@@ -189,6 +189,174 @@ namespace Cysharp.Threading.Tasks
|
|||||||
return new AsyncLazy<T>(task);
|
return new AsyncLazy<T>(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore task result when cancel raised first.
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask WithCancellation(this UniTask task, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return UniTask.FromCanceled(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.Status.IsCompleted())
|
||||||
|
{
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UniTask(new WithCancellationSource(task, cancellationToken), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore task result when cancel raised first.
|
||||||
|
/// </summary>
|
||||||
|
public static UniTask<T> WithCancellation<T>(this UniTask<T> task, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return UniTask.FromCanceled<T>(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.Status.IsCompleted())
|
||||||
|
{
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UniTask<T>(new WithCancellationSource<T>(task, cancellationToken), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class WithCancellationSource : IUniTaskSource
|
||||||
|
{
|
||||||
|
static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
|
||||||
|
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration tokenRegistration;
|
||||||
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||||
|
|
||||||
|
public WithCancellationSource(UniTask task, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
|
||||||
|
RunTask(task).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid RunTask(UniTask task)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await task;
|
||||||
|
core.TrySetResult(AsyncUnit.Default);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
core.TrySetException(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
tokenRegistration.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (WithCancellationSource)state;
|
||||||
|
self.core.TrySetCanceled(self.cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
core.GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class WithCancellationSource<T> : IUniTaskSource<T>
|
||||||
|
{
|
||||||
|
static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
|
||||||
|
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration tokenRegistration;
|
||||||
|
UniTaskCompletionSourceCore<T> core;
|
||||||
|
|
||||||
|
public WithCancellationSource(UniTask<T> task, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
|
||||||
|
RunTask(task).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
async UniTaskVoid RunTask(UniTask<T> task)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core.TrySetResult(await task);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
core.TrySetException(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
tokenRegistration.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (WithCancellationSource<T>)state;
|
||||||
|
self.core.TrySetCanceled(self.cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
core.GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetResult(short token)
|
||||||
|
{
|
||||||
|
return core.GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
public static IEnumerator ToCoroutine<T>(this UniTask<T> task, Action<T> resultHandler = null, Action<Exception> exceptionHandler = null)
|
public static IEnumerator ToCoroutine<T>(this UniTask<T> task, Action<T> resultHandler = null, Action<Exception> exceptionHandler = null)
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public class UniTaskSynchronizationContext : SynchronizationContext
|
||||||
|
{
|
||||||
|
const int MaxArrayLength = 0X7FEFFFFF;
|
||||||
|
const int InitialSize = 16;
|
||||||
|
|
||||||
|
static SpinLock gate = new SpinLock();
|
||||||
|
static bool dequing = false;
|
||||||
|
|
||||||
|
static int actionListCount = 0;
|
||||||
|
static Callback[] actionList = new Callback[InitialSize];
|
||||||
|
|
||||||
|
static int waitingListCount = 0;
|
||||||
|
static Callback[] waitingList = new Callback[InitialSize];
|
||||||
|
|
||||||
|
static int opCount;
|
||||||
|
|
||||||
|
public override void Send(SendOrPostCallback d, object state)
|
||||||
|
{
|
||||||
|
d(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Post(SendOrPostCallback d, object state)
|
||||||
|
{
|
||||||
|
bool lockTaken = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gate.Enter(ref lockTaken);
|
||||||
|
|
||||||
|
if (dequing)
|
||||||
|
{
|
||||||
|
// Ensure Capacity
|
||||||
|
if (waitingList.Length == waitingListCount)
|
||||||
|
{
|
||||||
|
var newLength = waitingListCount * 2;
|
||||||
|
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
|
||||||
|
|
||||||
|
var newArray = new Callback[newLength];
|
||||||
|
Array.Copy(waitingList, newArray, waitingListCount);
|
||||||
|
waitingList = newArray;
|
||||||
|
}
|
||||||
|
waitingList[waitingListCount] = new Callback(d, state);
|
||||||
|
waitingListCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ensure Capacity
|
||||||
|
if (actionList.Length == actionListCount)
|
||||||
|
{
|
||||||
|
var newLength = actionListCount * 2;
|
||||||
|
if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength;
|
||||||
|
|
||||||
|
var newArray = new Callback[newLength];
|
||||||
|
Array.Copy(actionList, newArray, actionListCount);
|
||||||
|
actionList = newArray;
|
||||||
|
}
|
||||||
|
actionList[actionListCount] = new Callback(d, state);
|
||||||
|
actionListCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (lockTaken) gate.Exit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OperationStarted()
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref opCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OperationCompleted()
|
||||||
|
{
|
||||||
|
Interlocked.Decrement(ref opCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SynchronizationContext CreateCopy()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delegate entrypoint.
|
||||||
|
internal static void Run()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
bool lockTaken = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gate.Enter(ref lockTaken);
|
||||||
|
if (actionListCount == 0) return;
|
||||||
|
dequing = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (lockTaken) gate.Exit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < actionListCount; i++)
|
||||||
|
{
|
||||||
|
var action = actionList[i];
|
||||||
|
actionList[i] = default;
|
||||||
|
action.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
bool lockTaken = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gate.Enter(ref lockTaken);
|
||||||
|
dequing = false;
|
||||||
|
|
||||||
|
var swapTempActionList = actionList;
|
||||||
|
|
||||||
|
actionListCount = waitingListCount;
|
||||||
|
actionList = waitingList;
|
||||||
|
|
||||||
|
waitingListCount = 0;
|
||||||
|
waitingList = swapTempActionList;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (lockTaken) gate.Exit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
readonly struct Callback
|
||||||
|
{
|
||||||
|
readonly SendOrPostCallback callback;
|
||||||
|
readonly object state;
|
||||||
|
|
||||||
|
public Callback(SendOrPostCallback callback, object state)
|
||||||
|
{
|
||||||
|
this.callback = callback;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Invoke()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback(state);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: abf3aae9813db2849bce518f8596e920
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
|
#if UNITY_2018_4 || UNITY_2019_4_OR_NEWER
|
||||||
|
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||||
|
|
||||||
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public static partial class UnityAsyncExtensions
|
||||||
|
{
|
||||||
|
public static AssetBundleRequestAllAssetsAwaiter AwaitForAllAssets(this AssetBundleRequest asyncOperation)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
return new AssetBundleRequestAllAssetsAwaiter(asyncOperation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult<UnityEngine.Object[]>(asyncOperation.allAssets);
|
||||||
|
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||||
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
|
||||||
|
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets);
|
||||||
|
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
AssetBundleRequest asyncOperation;
|
||||||
|
Action<AsyncOperation> continuationAction;
|
||||||
|
|
||||||
|
public AssetBundleRequestAllAssetsAwaiter(AssetBundleRequest asyncOperation)
|
||||||
|
{
|
||||||
|
this.asyncOperation = asyncOperation;
|
||||||
|
this.continuationAction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCompleted => asyncOperation.isDone;
|
||||||
|
|
||||||
|
public UnityEngine.Object[] GetResult()
|
||||||
|
{
|
||||||
|
if (continuationAction != null)
|
||||||
|
{
|
||||||
|
asyncOperation.completed -= continuationAction;
|
||||||
|
continuationAction = null;
|
||||||
|
var result = asyncOperation.allAssets;
|
||||||
|
asyncOperation = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = asyncOperation.allAssets;
|
||||||
|
asyncOperation = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
UnsafeOnCompleted(continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||||
|
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||||
|
asyncOperation.completed += continuationAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class AssetBundleRequestAllAssetsWithCancellationSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsWithCancellationSource>
|
||||||
|
{
|
||||||
|
static TaskPool<AssetBundleRequestAllAssetsWithCancellationSource> pool;
|
||||||
|
public AssetBundleRequestAllAssetsWithCancellationSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AssetBundleRequestAllAssetsWithCancellationSource()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestAllAssetsWithCancellationSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly Action<AsyncOperation> continuationAction;
|
||||||
|
AssetBundleRequest asyncOperation;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
bool completed;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||||
|
|
||||||
|
AssetBundleRequestAllAssetsWithCancellationSource()
|
||||||
|
{
|
||||||
|
continuationAction = Continuation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, CancellationToken cancellationToken, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AssetBundleRequestAllAssetsWithCancellationSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.asyncOperation = asyncOperation;
|
||||||
|
result.cancellationToken = cancellationToken;
|
||||||
|
result.completed = false;
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||||
|
|
||||||
|
asyncOperation.completed += result.continuationAction;
|
||||||
|
|
||||||
|
token = result.core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Continuation(AsyncOperation _)
|
||||||
|
{
|
||||||
|
asyncOperation.completed -= continuationAction;
|
||||||
|
|
||||||
|
if (completed)
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completed = true;
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.TrySetResult(asyncOperation.allAssets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEngine.Object[] GetResult(short token)
|
||||||
|
{
|
||||||
|
return core.GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (completed)
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
completed = true;
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
asyncOperation = default;
|
||||||
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class AssetBundleRequestAllAssetsConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsConfiguredSource>
|
||||||
|
{
|
||||||
|
static TaskPool<AssetBundleRequestAllAssetsConfiguredSource> pool;
|
||||||
|
public AssetBundleRequestAllAssetsConfiguredSource NextNode { get; set; }
|
||||||
|
|
||||||
|
static AssetBundleRequestAllAssetsConfiguredSource()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestAllAssetsConfiguredSource), () => pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetBundleRequest asyncOperation;
|
||||||
|
IProgress<float> progress;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||||
|
|
||||||
|
AssetBundleRequestAllAssetsConfiguredSource()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AssetBundleRequestAllAssetsConfiguredSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.asyncOperation = asyncOperation;
|
||||||
|
result.progress = progress;
|
||||||
|
result.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
|
||||||
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
|
token = result.core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEngine.Object[] GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUniTaskSource.GetResult(short token)
|
||||||
|
{
|
||||||
|
GetResult(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
core.TrySetCanceled(cancellationToken);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress != null)
|
||||||
|
{
|
||||||
|
progress.Report(asyncOperation.progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asyncOperation.isDone)
|
||||||
|
{
|
||||||
|
core.TrySetResult(asyncOperation.allAssets);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
core.Reset();
|
||||||
|
asyncOperation = default;
|
||||||
|
progress = default;
|
||||||
|
cancellationToken = default;
|
||||||
|
return pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e9147caba40da434da95b39709c13784
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -605,6 +605,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||||
#region AssetBundleRequest
|
#region AssetBundleRequest
|
||||||
|
|
||||||
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
|
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
|
||||||
@@ -906,7 +907,9 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||||
#region AssetBundleCreateRequest
|
#region AssetBundleCreateRequest
|
||||||
|
|
||||||
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
|
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
|
||||||
@@ -1208,6 +1211,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLE_UNITYWEBREQUEST
|
#if ENABLE_UNITYWEBREQUEST
|
||||||
#region UnityWebRequestAsyncOperation
|
#region UnityWebRequestAsyncOperation
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
|
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
|
||||||
Func<string, string> ToIUniTaskSourceReturnType = x => (x == "void") ? "IUniTaskSource" : $"IUniTaskSource<{x}>";
|
Func<string, string> ToIUniTaskSourceReturnType = x => (x == "void") ? "IUniTaskSource" : $"IUniTaskSource<{x}>";
|
||||||
Func<(string typeName, string returnType, string returnField), bool> IsUnityWebRequest = x => x.returnType == "UnityWebRequest";
|
Func<(string typeName, string returnType, string returnField), bool> IsUnityWebRequest = x => x.returnType == "UnityWebRequest";
|
||||||
|
Func<(string typeName, string returnType, string returnField), bool> IsAssetBundleModule = x => x.typeName == "AssetBundleRequest" || x.typeName == "AssetBundleCreateRequest";
|
||||||
Func<(string typeName, string returnType, string returnField), bool> IsVoid = x => x.returnType == "void";
|
Func<(string typeName, string returnType, string returnField), bool> IsVoid = x => x.returnType == "void";
|
||||||
#>
|
#>
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
@@ -37,6 +38,8 @@ namespace Cysharp.Threading.Tasks
|
|||||||
<# foreach(var t in types) { #>
|
<# foreach(var t in types) { #>
|
||||||
<# if(IsUnityWebRequest(t)) { #>
|
<# if(IsUnityWebRequest(t)) { #>
|
||||||
#if ENABLE_UNITYWEBREQUEST
|
#if ENABLE_UNITYWEBREQUEST
|
||||||
|
<# } else if(IsAssetBundleModule(t)) { #>
|
||||||
|
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||||
<# } #>
|
<# } #>
|
||||||
#region <#= t.typeName #>
|
#region <#= t.typeName #>
|
||||||
|
|
||||||
@@ -422,7 +425,7 @@ namespace Cysharp.Threading.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
<# if(IsUnityWebRequest(t)) { #>
|
<# if(IsUnityWebRequest(t) || IsAssetBundleModule(t)) { #>
|
||||||
#endif
|
#endif
|
||||||
<# } #>
|
<# } #>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "com.cysharp.unitask",
|
"name": "com.cysharp.unitask",
|
||||||
"displayName": "UniTask",
|
"displayName": "UniTask",
|
||||||
"version": "2.0.26",
|
"version": "2.0.28",
|
||||||
"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" ],
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ public class SandboxMain : MonoBehaviour
|
|||||||
UniTaskCompletionSource ucs;
|
UniTaskCompletionSource ucs;
|
||||||
async UniTask<int> FooAsync()
|
async UniTask<int> FooAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
// use F10, will crash.
|
// use F10, will crash.
|
||||||
var loop = int.Parse("9");
|
var loop = int.Parse("9");
|
||||||
await UniTask.DelayFrame(loop);
|
await UniTask.DelayFrame(loop);
|
||||||
@@ -190,6 +191,9 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
async UniTask RunStandardDelayAsync()
|
async UniTask RunStandardDelayAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log("DEB");
|
UnityEngine.Debug.Log("DEB");
|
||||||
|
|
||||||
await UniTask.DelayFrame(30);
|
await UniTask.DelayFrame(30);
|
||||||
@@ -220,6 +224,11 @@ public class SandboxMain : MonoBehaviour
|
|||||||
async UniTaskVoid Update2()
|
async UniTaskVoid Update2()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UnityEngine.Debug.Log("async linq!");
|
UnityEngine.Debug.Log("async linq!");
|
||||||
|
|
||||||
await UniTaskAsyncEnumerable.Range(1, 10)
|
await UniTaskAsyncEnumerable.Range(1, 10)
|
||||||
@@ -455,7 +464,7 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
PlayerLoopInfo.Inject();
|
// PlayerLoopInfo.Inject();
|
||||||
PrepareCamera();
|
PrepareCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,12 +482,24 @@ public class SandboxMain : MonoBehaviour
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async void RunStandardTaskAsync()
|
||||||
|
{
|
||||||
|
Debug.Log("Wait 3 seconds");
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(3));
|
||||||
|
|
||||||
|
Debug.Log("Current SyncContext:" + SynchronizationContext.Current.GetType().FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async UniTaskVoid Start()
|
async UniTaskVoid Start()
|
||||||
{
|
{
|
||||||
var url = "http://google.com/404";
|
RunStandardTaskAsync();
|
||||||
var webRequestAsyncOperation = UnityWebRequest.Get(url).SendWebRequest();
|
|
||||||
await webRequestAsyncOperation.ToUniTask();
|
UnityEngine.Debug.Log("UniTaskPlayerLoop ready? " + PlayerLoopHelper.IsInjectedUniTaskPlayerLoop());
|
||||||
|
|
||||||
|
//var url = "http://google.com/404";
|
||||||
|
//var webRequestAsyncOperation = UnityWebRequest.Get(url).SendWebRequest();
|
||||||
|
//await webRequestAsyncOperation.ToUniTask();
|
||||||
|
|
||||||
//PlayerLoopInfo.Inject();
|
//PlayerLoopInfo.Inject();
|
||||||
|
|
||||||
@@ -685,7 +706,9 @@ public class SandboxMain : MonoBehaviour
|
|||||||
|
|
||||||
//StartCoroutine(Coroutine());
|
//StartCoroutine(Coroutine());
|
||||||
|
|
||||||
//await UniTask.Delay(TimeSpan.FromSeconds(1));
|
// PlayerLoopInfo.Inject();
|
||||||
|
await UniTask.Delay(TimeSpan.FromSeconds(1));
|
||||||
|
PlayerLoopInfo.DumpPlayerLoop("current", PlayerLoop.GetCurrentPlayerLoop());
|
||||||
|
|
||||||
|
|
||||||
// _ = ReturnToMainThreadTest();
|
// _ = ReturnToMainThreadTest();
|
||||||
@@ -1051,6 +1074,17 @@ public class SandboxMain : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SyncContextInjecter
|
||||||
|
{
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
public static void Inject()
|
||||||
|
{
|
||||||
|
SynchronizationContext.SetSynchronizationContext(new UniTaskSynchronizationContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class PlayerLoopInfo
|
public class PlayerLoopInfo
|
||||||
{
|
{
|
||||||
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
@@ -1085,7 +1119,7 @@ public class PlayerLoopInfo
|
|||||||
|
|
||||||
public static Type CurrentLoopType { get; private set; }
|
public static Type CurrentLoopType { get; private set; }
|
||||||
|
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
public static void Inject()
|
public static void Inject()
|
||||||
{
|
{
|
||||||
var system = PlayerLoop.GetCurrentPlayerLoop();
|
var system = PlayerLoop.GetCurrentPlayerLoop();
|
||||||
|
|||||||
126
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs
Normal file
126
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
|
||||||
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityEngine.Scripting;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Unity.Collections;
|
||||||
|
using System.Threading;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.TasksTests
|
||||||
|
{
|
||||||
|
public class CoroutineToUniTaskTest
|
||||||
|
{
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator EarlyUpdate() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.EarlyUpdate);
|
||||||
|
|
||||||
|
var l = new List<(int, int)>();
|
||||||
|
var currentFrame = Time.frameCount;
|
||||||
|
var t = Worker(l).ToUniTask();
|
||||||
|
|
||||||
|
l.Count.Should().Be(1);
|
||||||
|
l[0].Should().Be((0, currentFrame));
|
||||||
|
|
||||||
|
await t;
|
||||||
|
|
||||||
|
l[1].Should().Be((1, Time.frameCount));
|
||||||
|
l[1].Item2.Should().NotBe(currentFrame);
|
||||||
|
});
|
||||||
|
|
||||||
|
[UnityTest]
|
||||||
|
public IEnumerator LateUpdate() => UniTask.ToCoroutine(async () =>
|
||||||
|
{
|
||||||
|
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
|
||||||
|
|
||||||
|
var l = new List<(int, int)>();
|
||||||
|
var currentFrame = Time.frameCount;
|
||||||
|
var t = Worker(l).ToUniTask();
|
||||||
|
|
||||||
|
l.Count.Should().Be(1);
|
||||||
|
l[0].Should().Be((0, currentFrame));
|
||||||
|
|
||||||
|
await t;
|
||||||
|
|
||||||
|
l[1].Should().Be((1, Time.frameCount));
|
||||||
|
l[1].Item2.Should().NotBe(currentFrame);
|
||||||
|
});
|
||||||
|
|
||||||
|
//[UnityTest]
|
||||||
|
//public IEnumerator TestCoroutine()
|
||||||
|
//{
|
||||||
|
// yield return UniTask.Yield(PlayerLoopTiming.EarlyUpdate).ToUniTask().ToCoroutine();
|
||||||
|
|
||||||
|
// var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour));
|
||||||
|
|
||||||
|
// var l = new List<(int, int)>();
|
||||||
|
// var currentFrame = Time.frameCount;
|
||||||
|
// var t = nanika.StartCoroutine(Worker(l));
|
||||||
|
|
||||||
|
// l.Count.Should().Be(1);
|
||||||
|
// l[0].Should().Be((0, currentFrame));
|
||||||
|
|
||||||
|
// yield return t;
|
||||||
|
|
||||||
|
// l[1].Should().Be((1, Time.frameCount));
|
||||||
|
// l[1].Item2.Should().NotBe(currentFrame);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[UnityTest]
|
||||||
|
//public IEnumerator TestCoroutine2()
|
||||||
|
//{
|
||||||
|
// yield return UniTask.Yield(PlayerLoopTiming.PostLateUpdate).ToUniTask().ToCoroutine();
|
||||||
|
|
||||||
|
// var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour));
|
||||||
|
|
||||||
|
// var l = new List<(int, int)>();
|
||||||
|
// var currentFrame = Time.frameCount;
|
||||||
|
// var t = nanika.StartCoroutine(Worker(l));
|
||||||
|
|
||||||
|
// l.Count.Should().Be(1);
|
||||||
|
// l[0].Should().Be((0, currentFrame));
|
||||||
|
|
||||||
|
// yield return t;
|
||||||
|
|
||||||
|
// l[1].Should().Be((1, Time.frameCount));
|
||||||
|
// l[1].Item2.Should().NotBe(currentFrame);
|
||||||
|
//}
|
||||||
|
|
||||||
|
IEnumerator Worker(List<(int, int)> l)
|
||||||
|
{
|
||||||
|
l.Add((0, Time.frameCount));
|
||||||
|
yield return null;
|
||||||
|
l.Add((1, Time.frameCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask Foo()
|
||||||
|
{
|
||||||
|
var tasks = new List<UniTask>();
|
||||||
|
var t = Bar<int>();
|
||||||
|
tasks.Add(t);
|
||||||
|
|
||||||
|
t = Bar<int>();
|
||||||
|
tasks.Add(t);
|
||||||
|
|
||||||
|
await UniTask.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask<T> Bar<T>()
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
11
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta
Normal file
11
src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 43ffb719370515746932af3732ce073e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
m_EditorVersion: 2019.3.9f1
|
m_EditorVersion: 2019.4.5f1
|
||||||
m_EditorVersionWithRevision: 2019.3.9f1 (e6e740a1c473)
|
m_EditorVersionWithRevision: 2019.4.5f1 (81610f64359c)
|
||||||
|
|||||||
Reference in New Issue
Block a user