commit
c9bebd6550
136
README.md
136
README.md
|
@ -24,6 +24,7 @@ For advanced tips, see blog post: [Extends UnityWebRequest via async decorator p
|
|||
- [Getting started](#getting-started)
|
||||
- [Basics of UniTask and AsyncOperation](#basics-of-unitask-and-asyncoperation)
|
||||
- [Cancellation and Exception handling](#cancellation-and-exception-handling)
|
||||
- [Timeout handling](#timeout-handling)
|
||||
- [Progress](#progress)
|
||||
- [PlayerLoop](#playerloop)
|
||||
- [async void vs async UniTaskVoid](#async-void-vs-async-unitaskvoid)
|
||||
|
@ -128,9 +129,6 @@ async UniTask<string> DemoAsync()
|
|||
// shorthand of WhenAll, tuple can await directly
|
||||
var (google2, bing2, yahoo2) = await (task1, task2, task3);
|
||||
|
||||
// You can handle timeouts easily
|
||||
await GetTextAsync(UnityWebRequest.Get("http://unity.com")).Timeout(TimeSpan.FromMilliseconds(300));
|
||||
|
||||
// return async-value.(or you can use `UniTask`(no result), `UniTaskVoid`(fire and forget)).
|
||||
return (asset as TextAsset)?.text ?? throw new InvalidOperationException("Asset not found");
|
||||
}
|
||||
|
@ -154,7 +152,7 @@ UniTask provides three pattern of extension methods.
|
|||
|
||||
`WithCancellation` is a simple version of `ToUniTask`, both return `UniTask`. For details of cancellation, see: [Cancellation and Exception handling](#cancellation-and-exception-handling) section.
|
||||
|
||||
> Note: WithCancellation is returned from native timing of PlayerLoop but ToUniTask is returned from specified PlayerLoopTiming. For details of timing, see: [PlayerLoop](#playerloop) section.
|
||||
> Note: await directly is returned from native timing of PlayerLoop but WithCancellation and ToUniTask are returned from specified PlayerLoopTiming. For details of timing, see: [PlayerLoop](#playerloop) section.
|
||||
|
||||
> Note: AssetBundleRequest has `asset` and `allAssets`, default await returns `asset`. If you want to get `allAssets`, you can use `AwaitForAllAssets()` method.
|
||||
|
||||
|
@ -286,6 +284,100 @@ if (isCanceled)
|
|||
|
||||
Note: Only suppress throws if you call directly into the most source method. Otherwise, the return value will be converted, but the entire pipeline will not suppress throws.
|
||||
|
||||
Timeout handling
|
||||
---
|
||||
Timeout is a variation of cancellation. You can set timeout by `CancellationTokenSouce.CancelAfterSlim(TimeSpan)` and pass CancellationToken to async methods.
|
||||
|
||||
```csharp
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
|
||||
|
||||
try
|
||||
{
|
||||
await UnityWebRequest.Get("http://foo").SendWebRequest().WithCancellation(cts.Token);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
if (ex.CancellationToken == cts.Token)
|
||||
{
|
||||
UnityEngine.Debug.Log("Timeout");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `CancellationTokenSouce.CancelAfter` is a standard api. However in Unity you should not use it because it depends threading timer. `CancelAfterSlim` is UniTask's extension methods, it uses PlayerLoop instead.
|
||||
|
||||
If you want to use timeout with other source of cancellation, use `CancellationTokenSource.CreateLinkedTokenSource`.
|
||||
|
||||
```csharp
|
||||
var cancelToken = new CancellationTokenSource();
|
||||
cancelButton.onClick.AddListener(()=>
|
||||
{
|
||||
cancelToken.Cancel(); // cancel from button click.
|
||||
});
|
||||
|
||||
var timeoutToken = new CancellationTokenSource();
|
||||
timeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
|
||||
|
||||
try
|
||||
{
|
||||
// combine token
|
||||
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, timeoutToken.Token);
|
||||
|
||||
await UnityWebRequest.Get("http://foo").SendWebRequest().WithCancellation(linkedTokenSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
if (timeoutToken.IsCancellationRequested)
|
||||
{
|
||||
UnityEngine.Debug.Log("Timeout.");
|
||||
}
|
||||
else if (cancelToken.IsCancellationRequested)
|
||||
{
|
||||
UnityEngine.Debug.Log("Cancel clicked.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Optimize for reduce allocation of CancellationTokenSource for timeout per call async method, you can use UniTask's `TimeoutController`.
|
||||
|
||||
```csharp
|
||||
TimeoutController timeoutController = new TimeoutController(); // setup to field for reuse.
|
||||
|
||||
async UniTask FooAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// you can pass timeoutController.Timeout(TimeSpan) to cancellationToken.
|
||||
await UnityWebRequest.Get("http://foo").SendWebRequest()
|
||||
.WithCancellation(timeoutController.Timeout(TimeSpan.FromSeconds(5)));
|
||||
timeoutController.Reset(); // call Reset(Stop timeout timer and ready for reuse) when succeed.
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
if (timeoutController.IsTimeout())
|
||||
{
|
||||
UnityEngine.Debug.Log("timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you want to use timeout with other source of cancellation, use `new TimeoutController(CancellationToken)`.
|
||||
|
||||
```csharp
|
||||
TimeoutController timeoutController;
|
||||
CancellationTokenSource clickCancelSource;
|
||||
|
||||
void Start()
|
||||
{
|
||||
this.clickCancelSource = new CancellationTokenSource();
|
||||
this.timeoutController = new TimeoutController(clickCancelSource);
|
||||
}
|
||||
```
|
||||
|
||||
Note: UniTask has `.Timeout`, `.TimeoutWithoutException` methods however, if possible, do not use these, please pass `CancellationToken`. Because `.Timeout` work from external of task, can not stop timeoutted task. `.Timeout` means ignore result when timeout. If you pass a `CancellationToken` to the method, it will act from inside of the task, so it is possible to stop a running task.
|
||||
|
||||
Progress
|
||||
---
|
||||
Some async operations for unity have `ToUniTask(IProgress<float> progress = null, ...)` extension methods.
|
||||
|
@ -366,7 +458,7 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.
|
|||
|
||||
`AsyncOperation` is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after being called, the loaded scene's `Start` is called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`.
|
||||
|
||||
In UniTask, await directly and `WithCancellation` use native timing, `ToUniTask` uses specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
|
||||
In UniTask, await directly uses native timing, `WithCancellation` and `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, it causes a different order of Start and continuation after await. So it is recommended not to use `LoadSceneAsync.ToUniTask`.
|
||||
|
||||
In the stacktrace, you can check where it is running in playerloop.
|
||||
|
||||
|
@ -408,6 +500,37 @@ void Start()
|
|||
}
|
||||
```
|
||||
|
||||
You can optimize loop cost slightly by remove unuse PlayerLoopTiming injection. You can call `PlayerLoopHelper.Initialize(InjectPlayerLoopTimings)` on initialize.
|
||||
|
||||
```csharp
|
||||
var loop = PlayerLoop.GetCurrentPlayerLoop();
|
||||
PlayerLoopHelper.Initialize(ref loop, InjectPlayerLoopTimings.Minimum); // minimum is Update | FixedUpdate | LastPostLateUpdate
|
||||
```
|
||||
|
||||
`InjectPlayerLoopTimings` has three preset, `All` and `Standard`(All without last except LastPostLateUpdate), `Minimum`(`Update | FixedUpdate | LastPostLateUpdate`). Default is All and you can combine custom inject timings like `InjectPlayerLoopTimings.Update | InjectPlayerLoopTimings.FixedUpdate | InjectPlayerLoopTimings.PreLateUpdate`.
|
||||
|
||||
You can make error to use uninjected `PlayerLoopTiming` by [Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.BannedApiAnalyzers/BannedApiAnalyzers.Help.md). For example, you can setup `BannedSymbols.txt` like this for `InjectPlayerLoopTimings.Minimum`.
|
||||
|
||||
```txt
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.Initialization; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastInitialization; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.EarlyUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastEarlyUpdate; Isn't injected this PlayerLoop in this project.d
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastFixedUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PreUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PreLateUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastPreLateUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.PostLateUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.TimeUpdate; Isn't injected this PlayerLoop in this project.
|
||||
F:Cysharp.Threading.Tasks.PlayerLoopTiming.LastTimeUpdate; Isn't injected this PlayerLoop in this project.
|
||||
```
|
||||
|
||||
You can configure `RS0030` severity to error.
|
||||
|
||||
![image](https://user-images.githubusercontent.com/46207/109150837-bb933880-77ac-11eb-85ba-4fd15819dbd0.png)
|
||||
|
||||
async void vs async UniTaskVoid
|
||||
---
|
||||
`async void` is a standard C# task system so it does not run on UniTask systems. It is better not to use it. `async UniTaskVoid` is a lightweight version of `async UniTask` because it does not have awaitable completion and reports errors immediately to `UniTaskScheduler.UnobservedTaskException`. If you don't require awaiting (fire and forget), using `UniTaskVoid` is better. Unfortunately to dismiss warning, you're required to call `Forget()`.
|
||||
|
@ -812,8 +935,9 @@ For UnityEditor
|
|||
---
|
||||
UniTask can run on Unity Editor like an Editor Coroutine. However, there are some limitations.
|
||||
|
||||
* Delay, DelayFrame do not work correctly because they can not get deltaTime in editor. Return the result of the await immediately; you can use `DelayType.Realtime` to wait for the right time.
|
||||
* UniTask.Delay's DelayType.DeltaTime, UnscaledDeltaTime do not work correctly because they can not get deltaTime in editor. Therefore run on EditMode, automatically change DelayType to `DelayType.Realtime` that wait for the right time.
|
||||
* All PlayerLoopTiming run on the timing `EditorApplication.update`.
|
||||
* `-batchmode` with `-quit` does not work because does not run `EditorApplication.update`(quit on single frame) so should not use `-quit` and quit manually with `Environment.Exit(0)`.
|
||||
|
||||
Compare with Standard Task API
|
||||
---
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTaskSynchronizationContext.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\CancellationTokenSourceExtensions.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\EnumeratorAsyncExtensions.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\TimeoutController.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\PlayerLoopHelper.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Delay.cs;
|
||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UniTask.Run.cs;
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace NetCoreTests
|
|||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
var v = await UniTask.Run(() => 10).WithCancellation(cts.Token);
|
||||
var v = await UniTask.Run(() => 10).IgnoreWhenCanceled(cts.Token);
|
||||
|
||||
v.Should().Be(10);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace NetCoreTests
|
|||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
return 10;
|
||||
}).WithCancellation(cts.Token);
|
||||
}).IgnoreWhenCanceled(cts.Token);
|
||||
|
||||
cts.Cancel();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using System;
|
|||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
|
||||
public static class CancellationTokenSourceExtensions
|
||||
{
|
||||
public static void CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
|
||||
|
|
|
@ -98,6 +98,79 @@ namespace Cysharp.Threading.Tasks
|
|||
#endif
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum InjectPlayerLoopTimings
|
||||
{
|
||||
/// <summary>
|
||||
/// Preset: All loops(default).
|
||||
/// </summary>
|
||||
All =
|
||||
Initialization | LastInitialization |
|
||||
EarlyUpdate | LastEarlyUpdate |
|
||||
FixedUpdate | LastFixedUpdate |
|
||||
PreUpdate | LastPreUpdate |
|
||||
Update | LastUpdate |
|
||||
PreLateUpdate | LastPreLateUpdate |
|
||||
PostLateUpdate | LastPostLateUpdate
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
| TimeUpdate | LastTimeUpdate,
|
||||
#else
|
||||
,
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Preset: All without last except LastPostLateUpdate.
|
||||
/// </summary>
|
||||
Standard =
|
||||
Initialization |
|
||||
EarlyUpdate |
|
||||
FixedUpdate |
|
||||
PreUpdate |
|
||||
Update |
|
||||
PreLateUpdate |
|
||||
PostLateUpdate | LastPostLateUpdate
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
| TimeUpdate
|
||||
#endif
|
||||
,
|
||||
|
||||
/// <summary>
|
||||
/// Preset: Minimum pattern, Update | FixedUpdate | LastPostLateUpdate
|
||||
/// </summary>
|
||||
Minimum =
|
||||
Update | FixedUpdate | LastPostLateUpdate,
|
||||
|
||||
// PlayerLoopTiming
|
||||
|
||||
Initialization = 1,
|
||||
LastInitialization = 2,
|
||||
|
||||
EarlyUpdate = 4,
|
||||
LastEarlyUpdate = 8,
|
||||
|
||||
FixedUpdate = 16,
|
||||
LastFixedUpdate = 32,
|
||||
|
||||
PreUpdate = 64,
|
||||
LastPreUpdate = 128,
|
||||
|
||||
Update = 256,
|
||||
LastUpdate = 512,
|
||||
|
||||
PreLateUpdate = 1024,
|
||||
LastPreLateUpdate = 2048,
|
||||
|
||||
PostLateUpdate = 4096,
|
||||
LastPostLateUpdate = 8192
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
,
|
||||
// Unity 2020.2 added TimeUpdate https://docs.unity3d.com/2020.2/Documentation/ScriptReference/PlayerLoop.TimeUpdate.html
|
||||
TimeUpdate = 16384,
|
||||
LastTimeUpdate = 32768
|
||||
#endif
|
||||
}
|
||||
|
||||
public interface IPlayerLoopItem
|
||||
{
|
||||
bool MoveNext();
|
||||
|
@ -105,6 +178,9 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static class PlayerLoopHelper
|
||||
{
|
||||
static readonly ContinuationQueue ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);
|
||||
static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);
|
||||
|
||||
public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContetext;
|
||||
public static int MainThreadId => mainThreadId;
|
||||
internal static string ApplicationDataPath => applicationDataPath;
|
||||
|
@ -118,8 +194,9 @@ namespace Cysharp.Threading.Tasks
|
|||
static PlayerLoopRunner[] runners;
|
||||
internal static bool IsEditorApplicationQuitting { get; private set; }
|
||||
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
|
||||
Type loopRunnerYieldType, ContinuationQueue cq, Type lastLoopRunnerYieldType, ContinuationQueue lastCq,
|
||||
Type loopRunnerType, PlayerLoopRunner runner, Type lastLoopRunnerType, PlayerLoopRunner lastRunner)
|
||||
bool injectOnFirst,
|
||||
Type loopRunnerYieldType, ContinuationQueue cq,
|
||||
Type loopRunnerType, PlayerLoopRunner runner)
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
@ -134,22 +211,11 @@ namespace Cysharp.Threading.Tasks
|
|||
runner.Run();
|
||||
runner.Clear();
|
||||
}
|
||||
if (lastRunner != null)
|
||||
{
|
||||
lastRunner.Run();
|
||||
lastRunner.Clear();
|
||||
}
|
||||
|
||||
if (cq != null)
|
||||
{
|
||||
cq.Run();
|
||||
cq.Clear();
|
||||
}
|
||||
if (lastCq != null)
|
||||
{
|
||||
lastCq.Run();
|
||||
lastCq.Clear();
|
||||
}
|
||||
IsEditorApplicationQuitting = false;
|
||||
}
|
||||
};
|
||||
|
@ -161,40 +227,38 @@ namespace Cysharp.Threading.Tasks
|
|||
updateDelegate = cq.Run
|
||||
};
|
||||
|
||||
var lastYieldLoop = new PlayerLoopSystem
|
||||
{
|
||||
type = lastLoopRunnerYieldType,
|
||||
updateDelegate = lastCq.Run
|
||||
};
|
||||
|
||||
var runnerLoop = new PlayerLoopSystem
|
||||
{
|
||||
type = loopRunnerType,
|
||||
updateDelegate = runner.Run
|
||||
};
|
||||
|
||||
var lastRunnerLoop = new PlayerLoopSystem
|
||||
{
|
||||
type = lastLoopRunnerType,
|
||||
updateDelegate = lastRunner.Run
|
||||
};
|
||||
|
||||
// Remove items from previous initializations.
|
||||
var source = loopSystem.subSystemList
|
||||
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType && ls.type != lastLoopRunnerYieldType && ls.type != lastLoopRunnerType)
|
||||
.ToArray();
|
||||
var source = RemoveRunner(loopSystem, loopRunnerYieldType, loopRunnerType);
|
||||
var dest = new PlayerLoopSystem[source.Length + 2];
|
||||
|
||||
var dest = new PlayerLoopSystem[source.Length + 4];
|
||||
|
||||
Array.Copy(source, 0, dest, 2, source.Length);
|
||||
dest[0] = yieldLoop;
|
||||
dest[1] = runnerLoop;
|
||||
dest[dest.Length - 2] = lastYieldLoop;
|
||||
dest[dest.Length - 1] = lastRunnerLoop;
|
||||
Array.Copy(source, 0, dest, injectOnFirst ? 2 : 0, source.Length);
|
||||
if (injectOnFirst)
|
||||
{
|
||||
dest[0] = yieldLoop;
|
||||
dest[1] = runnerLoop;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[dest.Length - 2] = yieldLoop;
|
||||
dest[dest.Length - 1] = runnerLoop;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
|
||||
{
|
||||
return loopSystem.subSystemList
|
||||
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
|
||||
{
|
||||
var loop = new PlayerLoopSystem
|
||||
|
@ -311,7 +375,23 @@ namespace Cysharp.Threading.Tasks
|
|||
throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
|
||||
}
|
||||
|
||||
public static void Initialize(ref PlayerLoopSystem playerLoop)
|
||||
static void InsertLoop(PlayerLoopSystem[] copyList, InjectPlayerLoopTimings injectTimings, Type loopType, InjectPlayerLoopTimings targetTimings,
|
||||
int index, bool injectOnFirst, Type loopRunnerYieldType, Type loopRunnerType, PlayerLoopTiming playerLoopTiming)
|
||||
{
|
||||
var i = FindLoopSystemIndex(copyList, loopType);
|
||||
if ((injectTimings & targetTimings) == targetTimings)
|
||||
{
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], injectOnFirst,
|
||||
loopRunnerYieldType, yielders[index] = new ContinuationQueue(playerLoopTiming),
|
||||
loopRunnerType, runners[index] = new PlayerLoopRunner(playerLoopTiming));
|
||||
}
|
||||
else
|
||||
{
|
||||
copyList[i].subSystemList = RemoveRunner(copyList[i], loopRunnerYieldType, loopRunnerType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopTimings injectTimings = InjectPlayerLoopTimings.All)
|
||||
{
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
yielders = new ContinuationQueue[16];
|
||||
|
@ -323,58 +403,82 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
var copyList = playerLoop.subSystemList.ToArray();
|
||||
|
||||
var i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Initialization));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), yielders[0] = new ContinuationQueue(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), yielders[1] = new ContinuationQueue(PlayerLoopTiming.LastInitialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), runners[0] = new PlayerLoopRunner(PlayerLoopTiming.Initialization),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), runners[1] = new PlayerLoopRunner(PlayerLoopTiming.LastInitialization));
|
||||
// Initialization
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
|
||||
InjectPlayerLoopTimings.Initialization, 0, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), PlayerLoopTiming.Initialization);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Initialization),
|
||||
InjectPlayerLoopTimings.LastInitialization, 1, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), PlayerLoopTiming.LastInitialization);
|
||||
|
||||
// EarlyUpdate
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.EarlyUpdate));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), yielders[2] = new ContinuationQueue(PlayerLoopTiming.EarlyUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), yielders[3] = new ContinuationQueue(PlayerLoopTiming.LastEarlyUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), runners[2] = new PlayerLoopRunner(PlayerLoopTiming.EarlyUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), runners[3] = new PlayerLoopRunner(PlayerLoopTiming.LastEarlyUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
|
||||
InjectPlayerLoopTimings.EarlyUpdate, 2, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), PlayerLoopTiming.EarlyUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.EarlyUpdate),
|
||||
InjectPlayerLoopTimings.LastEarlyUpdate, 3, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), PlayerLoopTiming.LastEarlyUpdate);
|
||||
|
||||
// FixedUpdate
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.FixedUpdate));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), yielders[4] = new ContinuationQueue(PlayerLoopTiming.FixedUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), yielders[5] = new ContinuationQueue(PlayerLoopTiming.LastFixedUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), runners[4] = new PlayerLoopRunner(PlayerLoopTiming.FixedUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), runners[5] = new PlayerLoopRunner(PlayerLoopTiming.LastFixedUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
|
||||
InjectPlayerLoopTimings.FixedUpdate, 4, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), PlayerLoopTiming.FixedUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.FixedUpdate),
|
||||
InjectPlayerLoopTimings.LastFixedUpdate, 5, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), PlayerLoopTiming.LastFixedUpdate);
|
||||
|
||||
// PreUpdate
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.PreUpdate));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), yielders[6] = new ContinuationQueue(PlayerLoopTiming.PreUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), yielders[7] = new ContinuationQueue(PlayerLoopTiming.LastPreUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), runners[6] = new PlayerLoopRunner(PlayerLoopTiming.PreUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), runners[7] = new PlayerLoopRunner(PlayerLoopTiming.LastPreUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
|
||||
InjectPlayerLoopTimings.PreUpdate, 6, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), PlayerLoopTiming.PreUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreUpdate),
|
||||
InjectPlayerLoopTimings.LastPreUpdate, 7, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), PlayerLoopTiming.LastPreUpdate);
|
||||
|
||||
// Update
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), yielders[8] = new ContinuationQueue(PlayerLoopTiming.Update),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), yielders[9] = new ContinuationQueue(PlayerLoopTiming.LastUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), runners[8] = new PlayerLoopRunner(PlayerLoopTiming.Update),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), runners[9] = new PlayerLoopRunner(PlayerLoopTiming.LastUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
|
||||
InjectPlayerLoopTimings.Update, 8, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), PlayerLoopTiming.Update);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.Update),
|
||||
InjectPlayerLoopTimings.LastUpdate, 9, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), PlayerLoopTiming.LastUpdate);
|
||||
|
||||
// PreLateUpdate
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.PreLateUpdate));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), yielders[10] = new ContinuationQueue(PlayerLoopTiming.PreLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), yielders[11] = new ContinuationQueue(PlayerLoopTiming.LastPreLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), runners[10] = new PlayerLoopRunner(PlayerLoopTiming.PreLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), runners[11] = new PlayerLoopRunner(PlayerLoopTiming.LastPreLateUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
|
||||
InjectPlayerLoopTimings.PreLateUpdate, 10, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), PlayerLoopTiming.PreLateUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PreLateUpdate),
|
||||
InjectPlayerLoopTimings.LastPreLateUpdate, 11, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), PlayerLoopTiming.LastPreLateUpdate);
|
||||
|
||||
// PostLateUpdate
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.PostLateUpdate));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), yielders[12] = new ContinuationQueue(PlayerLoopTiming.PostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), yielders[13] = new ContinuationQueue(PlayerLoopTiming.LastPostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), runners[12] = new PlayerLoopRunner(PlayerLoopTiming.PostLateUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), runners[13] = new PlayerLoopRunner(PlayerLoopTiming.LastPostLateUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
|
||||
InjectPlayerLoopTimings.PostLateUpdate, 12, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), PlayerLoopTiming.PostLateUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.PostLateUpdate),
|
||||
InjectPlayerLoopTimings.LastPostLateUpdate, 13, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), PlayerLoopTiming.LastPostLateUpdate);
|
||||
|
||||
#if UNITY_2020_2_OR_NEWER
|
||||
// TimeUpdate
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.TimeUpdate));
|
||||
copyList[i].subSystemList = InsertRunner(copyList[i], typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), yielders[14] = new ContinuationQueue(PlayerLoopTiming.TimeUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), yielders[15] = new ContinuationQueue(PlayerLoopTiming.LastTimeUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), runners[14] = new PlayerLoopRunner(PlayerLoopTiming.TimeUpdate),
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), runners[15] = new PlayerLoopRunner(PlayerLoopTiming.LastTimeUpdate));
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
|
||||
InjectPlayerLoopTimings.TimeUpdate, 14, true,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), PlayerLoopTiming.TimeUpdate);
|
||||
|
||||
InsertLoop(copyList, injectTimings, typeof(PlayerLoopType.TimeUpdate),
|
||||
InjectPlayerLoopTimings.LastTimeUpdate, 15, false,
|
||||
typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), PlayerLoopTiming.LastTimeUpdate);
|
||||
#endif
|
||||
|
||||
// Insert UniTaskSynchronizationContext to Update loop
|
||||
i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
|
||||
var i = FindLoopSystemIndex(copyList, typeof(PlayerLoopType.Update));
|
||||
copyList[i].subSystemList = InsertUniTaskSynchronizationContext(copyList[i]);
|
||||
|
||||
playerLoop.subSystemList = copyList;
|
||||
|
@ -383,12 +487,27 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
|
||||
{
|
||||
runners[(int)timing].AddAction(action);
|
||||
var runner = runners[(int)timing];
|
||||
if (runner == null)
|
||||
{
|
||||
ThrowInvalidLoopTiming(timing);
|
||||
}
|
||||
runner.AddAction(action);
|
||||
}
|
||||
|
||||
static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming)
|
||||
{
|
||||
throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming);
|
||||
}
|
||||
|
||||
public static void AddContinuation(PlayerLoopTiming timing, Action continuation)
|
||||
{
|
||||
yielders[(int)timing].Enqueue(continuation);
|
||||
var q = yielders[(int)timing];
|
||||
if (q == null)
|
||||
{
|
||||
ThrowInvalidLoopTiming(timing);
|
||||
}
|
||||
q.Enqueue(continuation);
|
||||
}
|
||||
|
||||
// Diagnostics helper
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System.Threading;
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
// CancellationTokenSource itself can not reuse but CancelAfter(Timeout.InfiniteTimeSpan) allows reuse if did not reach timeout.
|
||||
// Similar discussion:
|
||||
// https://github.com/dotnet/runtime/issues/4694
|
||||
// https://github.com/dotnet/runtime/issues/48492
|
||||
// This TimeoutController emulate similar implementation, using CancelAfterSlim; to achieve zero allocation timeout.
|
||||
|
||||
public sealed class TimeoutController : IDisposable
|
||||
{
|
||||
CancellationTokenSource timeoutSource;
|
||||
CancellationTokenSource linkedSource;
|
||||
StoppableDelayRealtimePromise timeoutDelay;
|
||||
|
||||
readonly CancellationTokenSource originalLinkCancellationTokenSource;
|
||||
|
||||
public TimeoutController()
|
||||
{
|
||||
this.timeoutSource = new CancellationTokenSource();
|
||||
this.originalLinkCancellationTokenSource = null;
|
||||
this.linkedSource = null;
|
||||
this.timeoutDelay = null;
|
||||
}
|
||||
|
||||
public TimeoutController(CancellationTokenSource linkCancellationTokenSource)
|
||||
{
|
||||
this.timeoutSource = new CancellationTokenSource();
|
||||
this.originalLinkCancellationTokenSource = linkCancellationTokenSource;
|
||||
this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, linkCancellationTokenSource.Token);
|
||||
this.timeoutDelay = null;
|
||||
}
|
||||
|
||||
public CancellationToken Timeout(TimeSpan timeout)
|
||||
{
|
||||
if (originalLinkCancellationTokenSource != null && originalLinkCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
return originalLinkCancellationTokenSource.Token;
|
||||
}
|
||||
|
||||
if (timeoutSource.IsCancellationRequested)
|
||||
{
|
||||
timeoutSource.Dispose();
|
||||
timeoutSource = new CancellationTokenSource();
|
||||
if (linkedSource != null)
|
||||
{
|
||||
this.linkedSource.Cancel();
|
||||
this.linkedSource.Dispose();
|
||||
this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, originalLinkCancellationTokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeoutDelay == null)
|
||||
{
|
||||
RunDelayAsync(timeout).Forget(); // timeoutDelay = ... in RunDelayAsync(immediately, before await)
|
||||
}
|
||||
else
|
||||
{
|
||||
timeoutDelay.RestartStopwatch(); // already running RunDelayAsync
|
||||
}
|
||||
|
||||
return (linkedSource != null) ? linkedSource.Token : timeoutSource.Token;
|
||||
}
|
||||
|
||||
public bool IsTimeout()
|
||||
{
|
||||
return timeoutSource.IsCancellationRequested;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (timeoutDelay != null)
|
||||
{
|
||||
timeoutDelay.Stop(); // stop delay, will finish RunDelayAsync
|
||||
timeoutDelay = null;
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid RunDelayAsync(TimeSpan timeout)
|
||||
{
|
||||
timeoutDelay = StoppableDelayRealtimePromise.Create(timeout, PlayerLoopTiming.Update, (linkedSource == null) ? CancellationToken.None : linkedSource.Token, out var version);
|
||||
try
|
||||
{
|
||||
var reason = await new UniTask<DelayResult>(timeoutDelay, version);
|
||||
if (reason == DelayResult.DelayCompleted)
|
||||
{
|
||||
// UnityEngine.Debug.Log("DEBUG:Timeout Complete, try to call timeoutSource.Cancel");
|
||||
timeoutSource.Cancel();
|
||||
}
|
||||
else if (reason == DelayResult.LinkedTokenCanceled)
|
||||
{
|
||||
// UnityEngine.Debug.Log("DEBUG:LinkedSource IsCancellationRequested");
|
||||
}
|
||||
else if (reason == DelayResult.ExternalStopped)
|
||||
{
|
||||
// Reset(Promise.Stop) called, do nothing.
|
||||
// UnityEngine.Debug.Log("DEBUG:Reset called");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
timeoutDelay = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (timeoutDelay != null)
|
||||
{
|
||||
timeoutDelay.Stop();
|
||||
}
|
||||
timeoutSource.Dispose();
|
||||
if (linkedSource != null)
|
||||
{
|
||||
linkedSource.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
enum DelayResult
|
||||
{
|
||||
LinkedTokenCanceled,
|
||||
ExternalStopped,
|
||||
DelayCompleted, // as Timeout.
|
||||
}
|
||||
|
||||
// Stop + SuppressCancellationThrow.
|
||||
sealed class StoppableDelayRealtimePromise : IUniTaskSource<DelayResult>, IPlayerLoopItem, ITaskPoolNode<StoppableDelayRealtimePromise>
|
||||
{
|
||||
static OperationCanceledException ExterenalStopException = new OperationCanceledException();
|
||||
|
||||
static TaskPool<StoppableDelayRealtimePromise> pool;
|
||||
StoppableDelayRealtimePromise nextNode;
|
||||
public ref StoppableDelayRealtimePromise NextNode => ref nextNode;
|
||||
|
||||
static StoppableDelayRealtimePromise()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(StoppableDelayRealtimePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
long delayTimeSpanTicks;
|
||||
ValueStopwatch stopwatch;
|
||||
CancellationToken cancellationToken;
|
||||
bool externalStop;
|
||||
|
||||
UniTaskCompletionSourceCore<DelayResult> core;
|
||||
|
||||
StoppableDelayRealtimePromise()
|
||||
{
|
||||
}
|
||||
|
||||
public static StoppableDelayRealtimePromise Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new StoppableDelayRealtimePromise();
|
||||
}
|
||||
|
||||
result.stopwatch = ValueStopwatch.StartNew();
|
||||
result.delayTimeSpanTicks = delayTimeSpan.Ticks;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.externalStop = false;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
externalStop = true;
|
||||
}
|
||||
|
||||
public void RestartStopwatch()
|
||||
{
|
||||
stopwatch = ValueStopwatch.StartNew();
|
||||
}
|
||||
|
||||
public DelayResult 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.TrySetResult(DelayResult.LinkedTokenCanceled);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (externalStop)
|
||||
{
|
||||
core.TrySetResult(DelayResult.ExternalStopped);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stopwatch.IsInvalid)
|
||||
{
|
||||
core.TrySetResult(DelayResult.DelayCompleted);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stopwatch.ElapsedTicks >= delayTimeSpanTicks)
|
||||
{
|
||||
core.TrySetResult(DelayResult.DelayCompleted);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
stopwatch = default;
|
||||
cancellationToken = default;
|
||||
externalStop = false;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6347ab34d2db6d744a654e8d62d96b96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -106,6 +106,14 @@ namespace Cysharp.Threading.Tasks
|
|||
throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// force use Realtime.
|
||||
if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying)
|
||||
{
|
||||
delayType = DelayType.Realtime;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (delayType)
|
||||
{
|
||||
case DelayType.UnscaledDeltaTime:
|
||||
|
|
|
@ -192,7 +192,7 @@ namespace Cysharp.Threading.Tasks
|
|||
/// <summary>
|
||||
/// Ignore task result when cancel raised first.
|
||||
/// </summary>
|
||||
public static UniTask WithCancellation(this UniTask task, CancellationToken cancellationToken)
|
||||
public static UniTask IgnoreWhenCanceled(this UniTask task, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!cancellationToken.CanBeCanceled)
|
||||
{
|
||||
|
@ -209,13 +209,13 @@ namespace Cysharp.Threading.Tasks
|
|||
return task;
|
||||
}
|
||||
|
||||
return new UniTask(new WithCancellationSource(task, cancellationToken), 0);
|
||||
return new UniTask(new IgnoreWhenCanceledSource(task, cancellationToken), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ignore task result when cancel raised first.
|
||||
/// </summary>
|
||||
public static UniTask<T> WithCancellation<T>(this UniTask<T> task, CancellationToken cancellationToken)
|
||||
public static UniTask<T> IgnoreWhenCanceled<T>(this UniTask<T> task, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!cancellationToken.CanBeCanceled)
|
||||
{
|
||||
|
@ -232,10 +232,10 @@ namespace Cysharp.Threading.Tasks
|
|||
return task;
|
||||
}
|
||||
|
||||
return new UniTask<T>(new WithCancellationSource<T>(task, cancellationToken), 0);
|
||||
return new UniTask<T>(new IgnoreWhenCanceledSource<T>(task, cancellationToken), 0);
|
||||
}
|
||||
|
||||
sealed class WithCancellationSource : IUniTaskSource
|
||||
sealed class IgnoreWhenCanceledSource : IUniTaskSource
|
||||
{
|
||||
static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
|
||||
|
||||
|
@ -243,7 +243,7 @@ namespace Cysharp.Threading.Tasks
|
|||
CancellationTokenRegistration tokenRegistration;
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
public WithCancellationSource(UniTask task, CancellationToken cancellationToken)
|
||||
public IgnoreWhenCanceledSource(UniTask task, CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
|
||||
|
@ -269,7 +269,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WithCancellationSource)state;
|
||||
var self = (IgnoreWhenCanceledSource)state;
|
||||
self.core.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class WithCancellationSource<T> : IUniTaskSource<T>
|
||||
sealed class IgnoreWhenCanceledSource<T> : IUniTaskSource<T>
|
||||
{
|
||||
static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
|
||||
|
||||
|
@ -302,7 +302,7 @@ namespace Cysharp.Threading.Tasks
|
|||
CancellationTokenRegistration tokenRegistration;
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
public WithCancellationSource(UniTask<T> task, CancellationToken cancellationToken)
|
||||
public IgnoreWhenCanceledSource(UniTask<T> task, CancellationToken cancellationToken)
|
||||
{
|
||||
this.cancellationToken = cancellationToken;
|
||||
this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
|
||||
|
@ -327,7 +327,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
static void CancellationCallback(object state)
|
||||
{
|
||||
var self = (WithCancellationSource<T>)state;
|
||||
var self = (IgnoreWhenCanceledSource<T>)state;
|
||||
self.core.TrySetCanceled(self.cancellationToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
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);
|
||||
return AwaitForAllAssets(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -84,129 +81,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AssetBundleRequestAllAssetsWithCancellationSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestAllAssetsWithCancellationSource> pool;
|
||||
AssetBundleRequestAllAssetsWithCancellationSource nextNode;
|
||||
public ref AssetBundleRequestAllAssetsWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleRequestAllAssetsWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestAllAssetsWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
AssetBundleRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
|
||||
|
||||
AssetBundleRequestAllAssetsWithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object[]>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AssetBundleRequestAllAssetsWithCancellationSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.cancellationToken = cancellationToken;
|
||||
result.completed = false;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, result);
|
||||
|
||||
asyncOperation.completed += result.continuationAction;
|
||||
|
||||
token = result.core.Version;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Continuation(AsyncOperation _)
|
||||
{
|
||||
asyncOperation.completed -= continuationAction;
|
||||
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
else
|
||||
{
|
||||
completed = true;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
core.TrySetResult(asyncOperation.allAssets);
|
||||
}
|
||||
}
|
||||
|
||||
public UnityEngine.Object[] GetResult(short token)
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
GetResult(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (completed)
|
||||
{
|
||||
TryReturn();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
completed = true;
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AssetBundleRequestAllAssetsConfiguredSource : IUniTaskSource<UnityEngine.Object[]>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestAllAssetsConfiguredSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestAllAssetsConfiguredSource> pool;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#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
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
|
|
@ -23,10 +23,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.CompletedTask;
|
||||
return new UniTask(AsyncOperationWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -77,125 +74,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationWithCancellationSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationWithCancellationSource> pool;
|
||||
AsyncOperationWithCancellationSource nextNode;
|
||||
public ref AsyncOperationWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AsyncOperationWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AsyncOperationWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
AsyncOperation asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncOperationWithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(AsyncOperation asyncOperation, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationWithCancellationSource();
|
||||
}
|
||||
|
||||
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(AsyncUnit.Default);
|
||||
}
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
|
||||
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public 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 AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
|
||||
{
|
||||
static TaskPool<AsyncOperationConfiguredSource> pool;
|
||||
|
@ -315,10 +193,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static UniTask<UnityEngine.Object> WithCancellation(this ResourceRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(ResourceRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this ResourceRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -373,129 +248,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class ResourceRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestWithCancellationSource>
|
||||
{
|
||||
static TaskPool<ResourceRequestWithCancellationSource> pool;
|
||||
ResourceRequestWithCancellationSource nextNode;
|
||||
public ref ResourceRequestWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static ResourceRequestWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(ResourceRequestWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
ResourceRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
||||
|
||||
ResourceRequestWithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest 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 ResourceRequestWithCancellationSource();
|
||||
}
|
||||
|
||||
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.asset);
|
||||
}
|
||||
}
|
||||
|
||||
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 ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
|
||||
{
|
||||
static TaskPool<ResourceRequestConfiguredSource> pool;
|
||||
|
@ -620,10 +372,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static UniTask<UnityEngine.Object> WithCancellation(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.asset);
|
||||
return new UniTask<UnityEngine.Object>(AssetBundleRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -678,129 +427,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AssetBundleRequestWithCancellationSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestWithCancellationSource> pool;
|
||||
AssetBundleRequestWithCancellationSource nextNode;
|
||||
public ref AssetBundleRequestWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleRequestWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AssetBundleRequestWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
AssetBundleRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityEngine.Object> core;
|
||||
|
||||
AssetBundleRequestWithCancellationSource()
|
||||
{
|
||||
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 AssetBundleRequestWithCancellationSource();
|
||||
}
|
||||
|
||||
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.asset);
|
||||
}
|
||||
}
|
||||
|
||||
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 AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
|
||||
{
|
||||
static TaskPool<AssetBundleRequestConfiguredSource> pool;
|
||||
|
@ -926,10 +552,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static UniTask<AssetBundle> WithCancellation(this AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<AssetBundle>(cancellationToken);
|
||||
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.assetBundle);
|
||||
return new UniTask<AssetBundle>(AssetBundleCreateRequestWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -984,129 +607,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AssetBundleCreateRequestWithCancellationSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestWithCancellationSource>
|
||||
{
|
||||
static TaskPool<AssetBundleCreateRequestWithCancellationSource> pool;
|
||||
AssetBundleCreateRequestWithCancellationSource nextNode;
|
||||
public ref AssetBundleCreateRequestWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static AssetBundleCreateRequestWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(AssetBundleCreateRequestWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
AssetBundleCreateRequest asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<AssetBundle> core;
|
||||
|
||||
AssetBundleCreateRequestWithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<AssetBundle> Create(AssetBundleCreateRequest asyncOperation, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AssetBundleCreateRequestWithCancellationSource();
|
||||
}
|
||||
|
||||
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.assetBundle);
|
||||
}
|
||||
}
|
||||
|
||||
public AssetBundle 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 AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
|
||||
{
|
||||
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
|
||||
|
@ -1232,17 +732,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationWithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -1312,138 +802,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class UnityWebRequestAsyncOperationWithCancellationSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationWithCancellationSource>
|
||||
{
|
||||
static TaskPool<UnityWebRequestAsyncOperationWithCancellationSource> pool;
|
||||
UnityWebRequestAsyncOperationWithCancellationSource nextNode;
|
||||
public ref UnityWebRequestAsyncOperationWithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static UnityWebRequestAsyncOperationWithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(UnityWebRequestAsyncOperationWithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
UnityWebRequestAsyncOperation asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<UnityWebRequest> core;
|
||||
|
||||
UnityWebRequestAsyncOperationWithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new UnityWebRequestAsyncOperationWithCancellationSource();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var result = asyncOperation.webRequest;
|
||||
if (result.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UnityWebRequest 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;
|
||||
asyncOperation.webRequest.Abort();
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
|
||||
{
|
||||
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
("ResourceRequest", "UnityEngine.Object", "asset"),
|
||||
("AssetBundleRequest", "UnityEngine.Object", "asset"), // allAssets?
|
||||
("AssetBundleCreateRequest", "AssetBundle", "assetBundle"),
|
||||
("UnityWebRequestAsyncOperation", "UnityWebRequest", "webRequest") // -> #if ENABLE_UNITYWEBREQUEST
|
||||
("UnityWebRequestAsyncOperation", "UnityWebRequest", "webRequest") // -> #if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
|
||||
};
|
||||
|
||||
Func<string, string> ToUniTaskReturnType = x => (x == "void") ? "UniTask" : $"UniTask<{x}>";
|
||||
|
@ -27,7 +27,7 @@ using System.Runtime.CompilerServices;
|
|||
using System.Threading;
|
||||
using UnityEngine;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
|
||||
using UnityEngine.Networking;
|
||||
#endif
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace Cysharp.Threading.Tasks
|
|||
{
|
||||
<# foreach(var t in types) { #>
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT)
|
||||
<# } else if(IsAssetBundleModule(t)) { #>
|
||||
#if UNITASK_ASSETBUNDLE_SUPPORT
|
||||
<# } #>
|
||||
|
@ -51,21 +51,7 @@ namespace Cysharp.Threading.Tasks
|
|||
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> WithCancellation(this <#= t.typeName #> asyncOperation, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
|
||||
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<#= IsVoid(t) ? "" : "<" + t.returnType + ">" #>(cancellationToken);
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
if (asyncOperation.isDone)
|
||||
{
|
||||
if (asyncOperation.webRequest.IsError())
|
||||
{
|
||||
return UniTask.FromException<UnityWebRequest>(new UnityWebRequestException(asyncOperation.webRequest));
|
||||
}
|
||||
return UniTask.FromResult(asyncOperation.webRequest);
|
||||
}
|
||||
<# } else { #>
|
||||
if (asyncOperation.isDone) return <#= IsVoid(t) ? "UniTask.CompletedTask" : $"UniTask.FromResult(asyncOperation.{t.returnField})" #>;
|
||||
<# } #>
|
||||
return new <#= ToUniTaskReturnType(t.returnType) #>(<#= t.typeName #>WithCancellationSource.Create(asyncOperation, cancellationToken, out var token), token);
|
||||
return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public static <#= ToUniTaskReturnType(t.returnType) #> ToUniTask(this <#= t.typeName #> asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
|
@ -151,150 +137,6 @@ namespace Cysharp.Threading.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
sealed class <#= t.typeName #>WithCancellationSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>WithCancellationSource>
|
||||
{
|
||||
static TaskPool<<#= t.typeName #>WithCancellationSource> pool;
|
||||
<#= t.typeName #>WithCancellationSource nextNode;
|
||||
public ref <#= t.typeName #>WithCancellationSource NextNode => ref nextNode;
|
||||
|
||||
static <#= t.typeName #>WithCancellationSource()
|
||||
{
|
||||
TaskPool.RegisterSizeGetter(typeof(<#= t.typeName #>WithCancellationSource), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<AsyncOperation> continuationAction;
|
||||
<#= t.typeName #> asyncOperation;
|
||||
CancellationToken cancellationToken;
|
||||
bool completed;
|
||||
|
||||
UniTaskCompletionSourceCore<<#= IsVoid(t) ? "AsyncUnit" : t.returnType #>> core;
|
||||
|
||||
<#= t.typeName #>WithCancellationSource()
|
||||
{
|
||||
continuationAction = Continuation;
|
||||
}
|
||||
|
||||
public static <#= ToIUniTaskSourceReturnType(t.returnType) #> Create(<#= t.typeName #> asyncOperation, CancellationToken cancellationToken, out short token)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return AutoResetUniTaskCompletionSource<#= IsVoid(t) ? "" : $"<{t.returnType}>" #>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new <#= t.typeName #>WithCancellationSource();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
var result = asyncOperation.webRequest;
|
||||
if (result.IsError())
|
||||
{
|
||||
core.TrySetException(new UnityWebRequestException(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetResult(result);
|
||||
}
|
||||
<# } else { #>
|
||||
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
|
||||
<# } #>
|
||||
}
|
||||
}
|
||||
|
||||
public <#= t.returnType #> GetResult(short token)
|
||||
{
|
||||
<# if (!IsVoid(t)) { #>
|
||||
return core.GetResult(token);
|
||||
<# } else { #>
|
||||
core.GetResult(token);
|
||||
<# } #>
|
||||
}
|
||||
|
||||
<# if (!IsVoid(t)) { #>
|
||||
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;
|
||||
<# if(IsUnityWebRequest(t)) { #>
|
||||
asyncOperation.webRequest.Abort();
|
||||
<# } #>
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>ConfiguredSource>
|
||||
{
|
||||
static TaskPool<<#= t.typeName #>ConfiguredSource> pool;
|
||||
|
|
|
@ -11,30 +11,33 @@ public class Test1
|
|||
public static async UniTaskVoid TestFunc()
|
||||
{
|
||||
await DoSomeThing();
|
||||
string[] scenes = new string[]
|
||||
{
|
||||
"Assets/Scenes/SandboxMain.unity",
|
||||
};
|
||||
//string[] scenes = new string[]
|
||||
//{
|
||||
// "Assets/Scenes/SandboxMain.unity",
|
||||
//};
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Log("Build Begin");
|
||||
BuildPipeline.BuildPlayer(scenes, Application.dataPath + "../target", BuildTarget.StandaloneWindows, BuildOptions.CompressWithLz4);
|
||||
Debug.Log("Build After");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e.Message);
|
||||
}
|
||||
//try
|
||||
//{
|
||||
// Debug.Log("Build Begin");
|
||||
// BuildPipeline.BuildPlayer(scenes, Application.dataPath + "../target", BuildTarget.StandaloneWindows, BuildOptions.CompressWithLz4);
|
||||
// Debug.Log("Build After");
|
||||
//}
|
||||
//catch (Exception e)
|
||||
//{
|
||||
// Debug.LogError(e.Message);
|
||||
//}
|
||||
}
|
||||
|
||||
public static async UniTask DoSomeThing()
|
||||
{
|
||||
Debug.Log("Dosomething");
|
||||
await UniTask.Delay(1500, DelayType.Realtime);
|
||||
await UniTask.Delay(1500, DelayType.DeltaTime);
|
||||
Debug.Log("Dosomething 2");
|
||||
await UniTask.Delay(1000, DelayType.Realtime);
|
||||
await UniTask.Delay(1000, DelayType.DeltaTime);
|
||||
Debug.Log("Dosomething 3");
|
||||
Debug.Log("and Quit.");
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -542,26 +542,116 @@ public class SandboxMain : MonoBehaviour
|
|||
{
|
||||
Debug.LogError(e);
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Debug.Log("TestAsync Finished.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
async UniTaskVoid Start()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
TestAsync(cts.Token).Forget();
|
||||
// UniTask.Delay(TimeSpan.FromSeconds(1)).TimeoutWithoutException
|
||||
|
||||
|
||||
var currentLoop = PlayerLoop.GetDefaultPlayerLoop();
|
||||
PlayerLoopHelper.Initialize(ref currentLoop, InjectPlayerLoopTimings.Minimum); // minimum is Update | FixedUpdate | LastPostLateUpdate
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var cancelToken = new CancellationTokenSource();
|
||||
cancelButton.onClick.AddListener(()=>
|
||||
{
|
||||
cancelToken.Cancel(); // cancel from button click.
|
||||
});
|
||||
|
||||
var timeoutToken = new CancellationTokenSource();
|
||||
timeoutToken.CancelAfterSlim(TimeSpan.FromSeconds(5)); // 5sec timeout.
|
||||
|
||||
try
|
||||
{
|
||||
// combine token
|
||||
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, timeoutToken.Token);
|
||||
|
||||
await UnityWebRequest.Get("http://foo").SendWebRequest().WithCancellation(linkedTokenSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
if (timeoutToken.IsCancellationRequested)
|
||||
{
|
||||
UnityEngine.Debug.Log("Timeout.");
|
||||
}
|
||||
else if (cancelToken.IsCancellationRequested)
|
||||
{
|
||||
UnityEngine.Debug.Log("Cancel clicked.");
|
||||
}
|
||||
_ = ex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TestAsync(cts.Token).Forget();
|
||||
|
||||
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||
{
|
||||
cts.Cancel();
|
||||
// try timeout
|
||||
try
|
||||
{
|
||||
//await UniTask.Delay(TimeSpan.FromSeconds(2), cancellationToken: timeoutController.Timeout(TimeSpan.FromSeconds(3)));
|
||||
UnityEngine.Debug.Log("Delay Complete, Reset(and reuse).");
|
||||
//timeoutController.Reset();
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
//UnityEngine.Debug.Log("Timeout! FromTimeout?:" + timeoutController.IsTimeout());
|
||||
_ = ex;
|
||||
}
|
||||
|
||||
await UniTask.Yield();
|
||||
}));
|
||||
|
||||
cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>
|
||||
{
|
||||
//clickCancelSource.Cancel();
|
||||
|
||||
//RunCheck(PlayerLoopTiming.Initialization).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastInitialization).Forget();
|
||||
//RunCheck(PlayerLoopTiming.EarlyUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastEarlyUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.FixedUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastFixedUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.PreUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastPreUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.Update).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.PreLateUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastPreLateUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.PostLateUpdate).Forget();
|
||||
//RunCheck(PlayerLoopTiming.LastPostLateUpdate).Forget();
|
||||
|
||||
await UniTask.Yield();
|
||||
}));
|
||||
|
||||
await UniTask.Yield();
|
||||
}
|
||||
|
||||
async UniTaskVoid RunCheck(PlayerLoopTiming timing)
|
||||
{
|
||||
//await UniTask.Yield(timing);
|
||||
//UnityEngine.Debug.Log("Yield:" + timing);
|
||||
await UniTask.DelayFrame(1, timing);
|
||||
UnityEngine.Debug.Log("Delay:" + timing);
|
||||
}
|
||||
|
||||
private void Application_logMessageReceived2(string condition, string stackTrace, LogType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
|
@ -12,16 +12,16 @@ public class FooMonoBehaviour : MonoBehaviour
|
|||
|
||||
}
|
||||
|
||||
private async UniTask Download(UnityWebRequest req, string filePath)
|
||||
{
|
||||
_ = req.SendWebRequest();
|
||||
//private async UniTask Download(UnityWebRequest req, string filePath)
|
||||
//{
|
||||
// _ = req.SendWebRequest();
|
||||
|
||||
|
||||
|
||||
|
||||
// var aaa = await foo;
|
||||
// Debug.Log(aaa);
|
||||
await UniTask.Yield();
|
||||
//File.WriteAllText(filePath, req.downloadHandler.text ?? string.Empty);
|
||||
}
|
||||
// // var aaa = await foo;
|
||||
// // Debug.Log(aaa);
|
||||
// await UniTask.Yield();
|
||||
// //File.WriteAllText(filePath, req.downloadHandler.text ?? string.Empty);
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
m_EditorVersion: 2020.2.0f1
|
||||
m_EditorVersionWithRevision: 2020.2.0f1 (3721df5a8b28)
|
||||
m_EditorVersion: 2020.2.1f1
|
||||
m_EditorVersionWithRevision: 2020.2.1f1 (270dd8c3da1c)
|
||||
|
|
Loading…
Reference in New Issue