Compare commits

...

42 Commits
1.1.0 ... 1.3.1

Author SHA1 Message Date
neuecc
28e1fa98c9 1.3.1 2020-04-26 21:50:29 +09:00
neuecc
9f7b897837 Add ObjectIdForDebugger to allow IDE stepin debug, #66, #41 2020-04-26 21:49:07 +09:00
Yoshifumi Kawai
341953b441 Merge pull request #65 from vc-kusuha/fix_Timeout
Fix timeoutTask continues to remain.
2020-04-24 14:57:05 +09:00
くすは
623936c7b8 Fix timeoutTask continues to remain. 2020-04-24 12:32:58 +09:00
Yoshifumi Kawai
b4ec35aadd Update config.yml 2020-04-17 11:31:27 +09:00
Yoshifumi Kawai
6c64205292 add readme 2020-04-17 11:15:48 +09:00
Yoshifumi Kawai
e6734478c5 r 2020-04-16 21:08:56 +09:00
Yoshifumi Kawai
d5f607204b CI2 2020-04-16 20:55:27 +09:00
Yoshifumi Kawai
676aba7cce 1.3.0 2020-04-16 20:50:35 +09:00
Yoshifumi Kawai
745de32006 GetCancellationTokenOnDestroy is moved to UnIRx.Async namespace 2020-04-16 20:47:23 +09:00
Yoshifumi Kawai
a0ef75e797 Merge remote-tracking branch 'origin/master' 2020-04-16 20:37:26 +09:00
Yoshifumi Kawai
dda6cbd679 2019.3.9f1 2020-04-16 20:37:07 +09:00
Yoshifumi Kawai
141b447b30 Merge pull request #38 from BattlefieldNoob/master
Fix #37 and add possibility to use UniTasks in Edit Mode
2020-04-16 20:35:27 +09:00
Yoshifumi Kawai
8e7a89eff7 Add UPM Package document 2020-04-16 20:26:57 +09:00
Yoshifumi Kawai
7848f878d7 +meta 2020-04-16 20:19:50 +09:00
Yoshifumi Kawai
c3a02ffbe6 move path 2020-04-16 19:29:41 +09:00
Yoshifumi Kawai
d509317ed2 trial to add package.json 2020-04-16 19:23:36 +09:00
Yoshifumi Kawai
74738ab13e disable warning AsyncMethodBuilderAttribute conflict #53 2020-04-16 12:28:14 +09:00
Yoshifumi Kawai
de3d491375 Merge pull request #52 from Elringus/feature/support-disable-domain-reload
Support disable domain reload (fast enter play mode)
2020-04-15 21:30:22 +09:00
Yoshifumi Kawai
139f5f7914 more CI settings to release automatically 2020-04-15 15:29:29 +09:00
Yoshifumi Kawai
5e2a4934dd Merge remote-tracking branch 'origin/master' 2020-04-15 15:23:26 +09:00
Yoshifumi Kawai
4ef15f3a14 test streamingassets 2020-04-15 15:23:23 +09:00
Yoshifumi Kawai
6d56f8d2bb Merge pull request #46 from NewbieGameCoder/master
Add ToUniTask for AssetBundleCreateRequest.
2020-04-15 15:21:09 +09:00
Yoshifumi Kawai
6e441a2d14 Merge pull request #44 from vc-kusuha/fix_typo
Fix typo
2020-04-15 14:40:01 +09:00
neuecc
66ba4b9986 Improve document 2020-03-16 23:36:46 +09:00
Antonio
7e26573abb updated to unity 2019.3.2f1, fix missing UNITY_EDITOR preprocessor 2020-02-27 19:14:02 +01:00
Artyom Sovetnikov
9db6482f0a fix typo 2020-02-18 17:20:13 +03:00
Artyom Sovetnikov
9c257e44f0 fix formatting 2020-02-18 17:19:10 +03:00
Artyom Sovetnikov
ecd678117e support disable domain reload
When domain reload is disabled, re-initialization is required when entering play mode; otherwise, pending tasks will leak between play mode sessions.
2020-02-18 17:15:59 +03:00
NewbieGameCoder
ebce2e922d Add ToUniTask for AssetBundleCreateRequest. 2019-11-16 18:44:01 +08:00
くすは
e67562b823 Fix typo
OnDestory -> OnDestroy
2019-10-29 22:31:25 +09:00
Antonio
d639283f59 Add comments 2019-09-21 19:11:07 +02:00
Antonio
ecf6c1fba5 Fixed edit mode, clear continuations and runners on run mode change, edit mode unit tests 2019-09-21 19:11:07 +02:00
Yoshifumi Kawai
50ba93f951 Merge pull request #31 from JimmyLoveSiren/master
Fix #30 and add unit test
2019-09-20 20:55:35 +09:00
Yoshifumi Kawai
d6a7dd9fc5 Merge pull request #24 from yKimisaki/feature/ToUniTaskForAssetBundleResquest
Add ToUniTask for AssetBundleRequest.
2019-09-20 20:49:45 +09:00
Yoshifumi Kawai
1a2dfd1537 Merge pull request #32 from TORISOUP/implements_eventsystem_interfaces
Implements EventSystem interfaces.
2019-08-16 11:53:32 +09:00
TORISOUP
08913104a9 Implements EventSystem interfaces. 2019-08-13 23:33:00 +09:00
Js
85eeeb3dd5 UnitTest for UniTask.ToObservable() 2019-08-02 13:58:29 +09:00
Js
47b701eed0 fix #30 OnCompleted won't be called on UniTask.ToObservable()
when UniTask.IsCompleted == true
2019-08-02 13:57:19 +09:00
Yoshifumi Kawai
10ba7bcfde Merge pull request #28 from rarudo/fix/compile_error
Fixed compile error in some platform
2019-07-25 16:45:54 +09:00
Shunta Imai
89d7e7c5fb Fixed compile error in some platform 2019-07-24 15:49:53 +09:00
Yoshitaka Kimisaki
f7c95bcabd Add ToUniTask for AssetBundleRequest. 2019-07-05 14:41:42 +09:00
57 changed files with 1518 additions and 129 deletions

View File

@@ -6,6 +6,9 @@ executors:
version: {type: string}
docker:
- image: gableroux/unity3d:<< parameters.version >>
go:
docker:
- image: circleci/golang
commands:
unity_activate:
parameters:
@@ -57,6 +60,17 @@ jobs:
- store_artifacts:
path: ./UniRx.Async.unitypackage
destination: /UniRx.Async.unitypackage
# upload to github by ghr
upload-github:
executor: go
steps:
- attach_workspace:
at: .
- run: go get github.com/tcnksm/ghr
- run: ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} ${CIRCLE_TAG} .
- store_artifacts:
path: UniRx.Async.unitypackage
destination: UniRx.Async.unitypackage
workflows:
version: 2
build-unity:
@@ -68,12 +82,12 @@ workflows:
# - build-and-test:
# unity_version: 2019.2.0b2
# unity_license: ${UNITY_LICENSE_2019_2}
- build-and-create-package:
unity_version: 2019.1.2f1
unity_license: ${UNITY_LICENSE_2019_1}
- build-and-test:
unity_version: 2019.1.2f1
unity_license: ${UNITY_LICENSE_2019_1}
filters:
tags:
only: /.*/
# test asmdef will not found.
# - build-and-test:
# unity_version: 2018.4.0f1
@@ -81,4 +95,20 @@ workflows:
# # UniTask minimum support version is 2018.3(C# 7.x)
# - build-and-test:
# unity_version: 2018.3.12f1
# unity_license: ${UNITY_LICENSE_2018_3}
# unity_license: ${UNITY_LICENSE_2018_3}
- build-and-create-package:
unity_version: 2019.1.2f1
unity_license: ${UNITY_LICENSE_2019_1}
filters:
tags:
only: /^\d\.\d\.\d.*/
branches:
ignore: /.*/
- upload-github:
requires:
- build-and-create-package
filters:
tags:
only: /^\d\.\d\.\d.*/
branches:
ignore: /.*/

2
.gitignore vendored
View File

@@ -145,3 +145,5 @@ RuntimeUnitTestToolkit\.csproj
Assembly-CSharp-Editor\.csproj
UniRx\.Async\.unitypackage
UniRx.Async.Tests.Editor.csproj

View File

@@ -17,7 +17,7 @@ public static class PackageExporter
var path = Path.Combine(Application.dataPath, root);
var assets = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
.Where(x => Path.GetExtension(x) == ".cs" || Path.GetExtension(x) == ".asmdef" || Path.GetExtension(x) == ".json")
.Where(x => Path.GetExtension(x) == ".cs" || Path.GetExtension(x) == ".asmdef" || Path.GetExtension(x) == ".json" || Path.GetExtension(x) == ".meta")
.Select(x => "Assets" + x.Replace(Application.dataPath, "").Replace(@"\", "/"))
.ToArray();

View File

@@ -169,21 +169,21 @@ Switch,
SaveSettings(settings);
}
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = true, priority = 3)]
static bool ValidateBuildTargetStandaloneLinux()
{
Menu.SetChecked("Test/Settings/BuildTarget/StandaloneLinux", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneLinux);
return true;
}
//[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = true, priority = 3)]
//static bool ValidateBuildTargetStandaloneLinux()
//{
// Menu.SetChecked("Test/Settings/BuildTarget/StandaloneLinux", LoadOrGetDefaultSettings().BuildTarget == BuildTarget.StandaloneLinux);
// return true;
//}
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = false, priority = 3)]
static void BuildTargetStandaloneLinux()
{
var settings = LoadOrGetDefaultSettings();
settings.UseCurrentBuildTarget = false;
settings.BuildTarget = BuildTarget.StandaloneLinux;
SaveSettings(settings);
}
//[MenuItem("Test/Settings/BuildTarget/StandaloneLinux", validate = false, priority = 3)]
//static void BuildTargetStandaloneLinux()
//{
// var settings = LoadOrGetDefaultSettings();
// settings.UseCurrentBuildTarget = false;
// settings.BuildTarget = BuildTarget.StandaloneLinux;
// SaveSettings(settings);
//}
[MenuItem("Test/Settings/BuildTarget/StandaloneLinux64", validate = true, priority = 4)]
static bool ValidateBuildTargetStandaloneLinux64()

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using UniRx.Async;
using UnityEngine;
@@ -13,21 +14,47 @@ public class SandboxMain : MonoBehaviour
public Button cancelButton;
CancellationTokenSource cts;
async void Start()
void Start()
{
await UniTask.CompletedTask; // ok
// var subject = new Subject<Unit>();
//subject.OnCompleted();
IObservable<AsyncUnit> subject = default;
try
okButton.onClick.AddListener(() =>
{
await subject.ToUniTask(); // exception
}
catch (Exception exception)
FooAsync().Forget();
});
cancelButton.onClick.AddListener(() =>
{
Debug.Log(exception);
}
BarAsync().Forget();
});
}
async UniTask<int> FooAsync()
{
// use F10, will crash.
var loop = int.Parse("9");
await UniTask.DelayFrame(loop);
Debug.Log("OK");
await UniTask.DelayFrame(loop);
Debug.Log("Again");
return 10;
}
async UniTaskVoid BarAsync()
{
var loop = int.Parse("10");
var foo = await UniTask.FromResult(100);
Debug.Log("OK");
Debug.Log("Again");
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7bb6ff9f1f0d0cd4da5ba7623f10dd6b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1 @@
MyTEST

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7fc83f79aef22a2449d5e9ca4964b2e0
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -395,6 +395,40 @@ namespace UniRx.AsyncTests
yield return new WaitForSeconds(3);
}
[UnityTest]
public IEnumerator ToObservable() => UniTask.ToCoroutine(async () =>
{
var completedTaskObserver = new ToObservableObserver<AsyncUnit>();
completedTaskObserver.OnNextCalled.Should().BeFalse();
completedTaskObserver.OnCompletedCalled.Should().BeFalse();
completedTaskObserver.OnErrorCalled.Should().BeFalse();
UniTask.CompletedTask.ToObservable().Subscribe(completedTaskObserver);
completedTaskObserver.OnNextCalled.Should().BeTrue();
completedTaskObserver.OnCompletedCalled.Should().BeTrue();
completedTaskObserver.OnErrorCalled.Should().BeFalse();
var delayFrameTaskObserver = new ToObservableObserver<int>();
UniTask.DelayFrame(1).ToObservable().Subscribe(delayFrameTaskObserver);
delayFrameTaskObserver.OnNextCalled.Should().BeFalse();
delayFrameTaskObserver.OnCompletedCalled.Should().BeFalse();
delayFrameTaskObserver.OnErrorCalled.Should().BeFalse();
await UniTask.DelayFrame(1);
delayFrameTaskObserver.OnNextCalled.Should().BeTrue();
delayFrameTaskObserver.OnCompletedCalled.Should().BeTrue();
delayFrameTaskObserver.OnErrorCalled.Should().BeFalse();
});
class ToObservableObserver<T> : IObserver<T>
{
public bool OnNextCalled { get; private set; }
public bool OnCompletedCalled { get; private set; }
public bool OnErrorCalled { get; private set; }
public void OnNext(T value) => OnNextCalled = true;
public void OnCompleted() => OnCompletedCalled = true;
public void OnError(Exception error) => OnErrorCalled = true;
}
#endif
#endif
}

8
Assets/Tests/Editor.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 649f696fcc0c3104a8de82a2550d248c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,405 @@
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#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 UniRx;
using UniRx.Async;
using UnityEngine.SceneManagement;
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
using System.Threading.Tasks;
#endif
using UnityEngine.Networking;
#if !UNITY_2019_3_OR_NEWER
using UnityEngine.Experimental.LowLevel;
#else
using UnityEngine.LowLevel;
#endif
#if !UNITY_WSA
using Unity.Jobs;
#endif
using Unity.Collections;
using System.Threading;
using NUnit.Framework;
using UnityEngine.TestTools;
using FluentAssertions;
namespace UniRx.AsyncTests
{
public class AsyncTest
{
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#if !UNITY_WSA
public struct MyJob : IJob
{
public int loopCount;
public NativeArray<int> inOut;
public int result;
public void Execute()
{
result = 0;
for (int i = 0; i < loopCount; i++)
{
result++;
}
inOut[0] = result;
}
}
[UnityTest]
public IEnumerator DelayAnd() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var time = Time.realtimeSinceStartup;
Time.timeScale = 0.5f;
try
{
await UniTask.Delay(TimeSpan.FromSeconds(3));
var elapsed = Time.realtimeSinceStartup - time;
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(6);
}
finally
{
Time.timeScale = 1.0f;
}
});
[UnityTest]
public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
{
var time = Time.realtimeSinceStartup;
Time.timeScale = 0.5f;
try
{
await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true);
var elapsed = Time.realtimeSinceStartup - time;
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3);
}
finally
{
Time.timeScale = 1.0f;
}
});
[UnityTest]
public IEnumerator WhenAll() => UniTask.ToCoroutine(async () =>
{
var a = UniTask.FromResult(999);
var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask();
var c = UniTask.DelayFrame(99);
var (a2, b2, c2) = await UniTask.WhenAll(a, b, c);
a2.Should().Be(999);
b2.Should().Be(AsyncUnit.Default);
c2.Should().Be(99);
});
[UnityTest]
public IEnumerator WhenAny() => UniTask.ToCoroutine(async () =>
{
var a = UniTask.FromResult(999);
var b = UniTask.Yield(PlayerLoopTiming.Update, CancellationToken.None).AsAsyncUnitUniTask();
var c = UniTask.DelayFrame(99);
var (win, a2, b2, c2) = await UniTask.WhenAny(a, b, c);
win.Should().Be(0);
a2.hasResult.Should().Be(true);
a2.result0.Should().Be(999);
b2.hasResult.Should().Be(false);
c2.hasResult.Should().Be(false);
});
[UnityTest]
public IEnumerator BothEnumeratorCheck() => UniTask.ToCoroutine(async () =>
{
await ToaruCoroutineEnumerator(); // wait 5 frame:)
await ToaruCoroutineEnumerator().ConfigureAwait(PlayerLoopTiming.PostLateUpdate);
});
[UnityTest]
public IEnumerator JobSystem() => UniTask.ToCoroutine(async () =>
{
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
JobHandle.ScheduleBatchedJobs();
await job.Schedule();
job.inOut[0].Should().Be(999);
job.inOut.Dispose();
});
class MyMyClass
{
public int MyProperty { get; set; }
}
[UnityTest]
public IEnumerator WaitUntil() => UniTask.ToCoroutine(async () =>
{
bool t = false;
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
UniTask.DelayFrame(10,PlayerLoopTiming.PostLateUpdate).ContinueWith(_ => t = true).Forget();
var startFrame = Time.frameCount;
await UniTask.WaitUntil(() => t, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame;
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator WaitWhile() => UniTask.ToCoroutine(async () =>
{
bool t = true;
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(_ => t = false).Forget();
var startFrame = Time.frameCount;
await UniTask.WaitWhile(() => t, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame;
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator WaitUntilValueChanged() => UniTask.ToCoroutine(async () =>
{
var v = new MyMyClass { MyProperty = 99 };
UniTask.DelayFrame(10, PlayerLoopTiming.PostLateUpdate).ContinueWith(_ => v.MyProperty = 1000).Forget();
var startFrame = Time.frameCount;
await UniTask.WaitUntilValueChanged(v, x => x.MyProperty, PlayerLoopTiming.EarlyUpdate);
var diff = Time.frameCount - startFrame;
diff.Should().Be(11);
});
[UnityTest]
public IEnumerator SwitchTo() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield();
var currentThreadId = Thread.CurrentThread.ManagedThreadId;
await UniTask.SwitchToThreadPool();
//await UniTask.SwitchToThreadPool();
//await UniTask.SwitchToThreadPool();
var switchedThreadId = Thread.CurrentThread.ManagedThreadId;
currentThreadId.Should().NotBe(switchedThreadId);
await UniTask.Yield();
var switchedThreadId2 = Thread.CurrentThread.ManagedThreadId;
currentThreadId.Should().Be(switchedThreadId2);
});
//[UnityTest]
//public IEnumerator ObservableConversion() => UniTask.ToCoroutine(async () =>
//{
// var v = await Observable.Range(1, 10).ToUniTask();
// v.Is(10);
// v = await Observable.Range(1, 10).ToUniTask(useFirstValue: true);
// v.Is(1);
// v = await UniTask.DelayFrame(10).ToObservable().ToTask();
// v.Is(10);
// v = await UniTask.FromResult(99).ToObservable();
// v.Is(99);
//});
//[UnityTest]
//public IEnumerator AwaitableReactiveProperty() => UniTask.ToCoroutine(async () =>
//{
// var rp1 = new ReactiveProperty<int>(99);
// UniTask.DelayFrame(100).ContinueWith(x => rp1.Value = x).Forget();
// await rp1;
// rp1.Value.Is(100);
// // var delay2 = UniTask.DelayFrame(10);
// // var (a, b ) = await UniTask.WhenAll(rp1.WaitUntilValueChangedAsync(), delay2);
//});
//[UnityTest]
//public IEnumerator AwaitableReactiveCommand() => UniTask.ToCoroutine(async () =>
//{
// var rc = new ReactiveCommand<int>();
// UniTask.DelayFrame(100).ContinueWith(x => rc.Execute(x)).Forget();
// var v = await rc;
// v.Is(100);
//});
[UnityTest]
public IEnumerator ExceptionlessCancellation() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
UniTask.DelayFrame(10).ContinueWith(_ => cts.Cancel()).Forget();
var first = Time.frameCount;
var (canceled, value) = await UniTask.DelayFrame(100, cancellationToken: cts.Token).SuppressCancellationThrow();
(Time.frameCount - first).Should().Be(11); // 10 frame canceled
canceled.Should().Be(true);
});
[UnityTest]
public IEnumerator ExceptionCancellation() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
UniTask.DelayFrame(10).ContinueWith(_ => cts.Cancel()).Forget();
bool occur = false;
try
{
var value = await UniTask.DelayFrame(100, cancellationToken: cts.Token);
}
catch (OperationCanceledException)
{
occur = true;
}
occur.Should().BeTrue();
});
IEnumerator ToaruCoroutineEnumerator()
{
yield return null;
yield return null;
yield return null;
yield return null;
yield return null;
}
[UnityTest]
public IEnumerator ExceptionUnobserved1() => UniTask.ToCoroutine(async () =>
{
bool calledEx = false;
Action<Exception> action = exx =>
{
calledEx = true;
exx.Message.Should().Be("MyException");
};
UniTaskScheduler.UnobservedTaskException += action;
var ex = InException1();
ex = default(UniTask);
await UniTask.DelayFrame(3);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
await UniTask.DelayFrame(1);
calledEx.Should().BeTrue();
UniTaskScheduler.UnobservedTaskException -= action;
});
[UnityTest]
public IEnumerator ExceptionUnobserved2() => UniTask.ToCoroutine(async () =>
{
bool calledEx = false;
Action<Exception> action = exx =>
{
calledEx = true;
exx.Message.Should().Be("MyException");
};
UniTaskScheduler.UnobservedTaskException += action;
var ex = InException2();
ex = default(UniTask<int>);
await UniTask.DelayFrame(3);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
await UniTask.DelayFrame(1);
calledEx.Should().BeTrue();
UniTaskScheduler.UnobservedTaskException -= action;
});
async UniTask InException1()
{
await UniTask.Yield();
throw new Exception("MyException");
}
async UniTask<int> InException2()
{
await UniTask.Yield();
throw new Exception("MyException");
}
[UnityTest]
public IEnumerator NestedEnumerator() => UniTask.ToCoroutine(async () =>
{
var time = Time.realtimeSinceStartup;
await ParentCoroutineEnumerator();
var elapsed = Time.realtimeSinceStartup - time;
((int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven)).Should().Be(3);
});
IEnumerator ParentCoroutineEnumerator()
{
yield return ChildCoroutineEnumerator();
}
IEnumerator ChildCoroutineEnumerator()
{
yield return new WaitForSeconds(3);
}
#endif
#endif
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 851899ba3337ac24a8331cb18fabe771
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,96 @@
#if !(UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2)
#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 UniRx;
using UniRx.Async;
using UnityEngine.SceneManagement;
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
using System.Threading.Tasks;
#endif
using UnityEngine.Networking;
#if !UNITY_2019_3_OR_NEWER
using UnityEngine.Experimental.LowLevel;
#else
using UnityEngine.LowLevel;
#endif
#if !UNITY_WSA
using Unity.Jobs;
#endif
using Unity.Collections;
using System.Threading;
using NUnit.Framework;
using UnityEngine.TestTools;
using FluentAssertions;
namespace UniRx.AsyncTests
{
public class RunTest
{
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#if !UNITY_WSA
//[UnityTest]
//public IEnumerator RunThread() => UniTask.ToCoroutine(async () =>
//{
// var main = Thread.CurrentThread.ManagedThreadId;
// var v = await UniTask.Run(() => { return System.Threading.Thread.CurrentThread.ManagedThreadId; }, false);
// UnityEngine.Debug.Log("Ret Value is:" + v);
// UnityEngine.Debug.Log("Run Here and id:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
// //v.Should().Be(3);
// main.Should().NotBe(Thread.CurrentThread.ManagedThreadId);
//});
[UnityTest]
public IEnumerator RunThreadConfigure() => UniTask.ToCoroutine(async () =>
{
var main = Thread.CurrentThread.ManagedThreadId;
var v = await UniTask.Run(() => 3, true);
v.Should().Be(3);
main.Should().Be(Thread.CurrentThread.ManagedThreadId);
});
//[UnityTest]
//public IEnumerator RunThreadException() => UniTask.ToCoroutine(async () =>
//{
// var main = Thread.CurrentThread.ManagedThreadId;
// try
// {
// await UniTask.Run<int>(() => throw new Exception(), false);
// }
// catch
// {
// main.Should().NotBe(Thread.CurrentThread.ManagedThreadId);
// }
//});
[UnityTest]
public IEnumerator RunThreadExceptionConfigure() => UniTask.ToCoroutine(async () =>
{
var main = Thread.CurrentThread.ManagedThreadId;
try
{
await UniTask.Run<int>(() => throw new Exception(), true);
}
catch
{
main.Should().Be(Thread.CurrentThread.ManagedThreadId);
}
});
#endif
#endif
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 76d078e5d960ac2429ce67a930c29ade
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
{
"name": "UniRx.Async.Tests.Editor",
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"UniRx.Async",
"UniRx.Async.Tests"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c2431de67d1d97a48afcaf18f333a0b4
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
#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 UniRx;
using UniRx.Async;
using Unity.Collections;
using System.Threading;
using NUnit.Framework;
using UnityEngine.TestTools;
using FluentAssertions;
namespace UniRx.AsyncTests
{
public class WhenAnyTest
{
[UnityTest]
public IEnumerator WhenAnyCanceled() => UniTask.ToCoroutine(async () =>
{
var cts = new CancellationTokenSource();
var successDelayTask = UniTask.Delay(TimeSpan.FromSeconds(1));
var cancelTask = UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: cts.Token);
cts.CancelAfterSlim(200);
try
{
var r = await UniTask.WhenAny(new[] { successDelayTask, cancelTask });
}
catch (Exception ex)
{
ex.Should().BeAssignableTo<OperationCanceledException>();
}
});
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5addd9aa1a794441af032a71208b495
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -40,7 +40,7 @@ namespace UniRx.Async
public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, GameObject gameObject)
{
var trigger = gameObject.GetAsyncDestroyTrigger();
trigger.AddCancellationTriggerOnDestory(cts);
trigger.AddCancellationTriggerOnDestroy(cts);
}
}
}

View File

@@ -1,6 +1,7 @@
#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
#pragma warning disable CS0436
namespace System.Runtime.CompilerServices
{

View File

@@ -136,6 +136,22 @@ namespace UniRx.Async.CompilerServices
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
#if UNITY_EDITOR
// Important for IDE debugger.
object debuggingId;
private object ObjectIdForDebugger
{
get
{
if (debuggingId == null)
{
debuggingId = new object();
}
return debuggingId;
}
}
#endif
}
@@ -268,6 +284,22 @@ namespace UniRx.Async.CompilerServices
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
#if UNITY_EDITOR
// Important for IDE debugger.
object debuggingId;
private object ObjectIdForDebugger
{
get
{
if (debuggingId == null)
{
debuggingId = new object();
}
return debuggingId;
}
}
#endif
}
}

View File

@@ -84,6 +84,22 @@ namespace UniRx.Async.CompilerServices
public void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
#if UNITY_EDITOR
// Important for IDE debugger.
object debuggingId;
private object ObjectIdForDebugger
{
get
{
if (debuggingId == null)
{
debuggingId = new object();
}
return debuggingId;
}
}
#endif
}
}

View File

@@ -18,7 +18,7 @@ namespace UniRx.Async.Editor
static UniTaskTrackerWindow window;
[MenuItem("Window/UniRx/UniTask Tracker")]
[MenuItem("Window/UniTask Tracker")]
public static void OpenWindow()
{
if (window != null)

View File

@@ -64,6 +64,15 @@ namespace UniRx.Async.Internal
}
}
public void Clear()
{
actionListCount = 0;
actionList = new Action[InitialSize];
waitingListCount = 0;
waitingList = new Action[InitialSize];
}
public void Run()
{
{

View File

@@ -45,6 +45,17 @@ namespace UniRx.Async.Internal
}
}
public void Clear()
{
lock (arrayLock)
{
for (var index = 0; index < loopItems.Length; index++)
{
loopItems[index] = null;
}
}
}
public void Run()
{
lock (runningAndQueueLock)

View File

@@ -391,5 +391,5 @@ namespace UniRx.Async.Internal
public abstract bool MoveNext();
}
}
#endif
}

View File

@@ -13,6 +13,10 @@ using UnityEngine.LowLevel;
using UnityEngine.Experimental.LowLevel;
#endif
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UniRx.Async
{
public static class UniTaskLoopRunners
@@ -62,42 +66,38 @@ namespace UniRx.Async
static ContinuationQueue[] yielders;
static PlayerLoopRunner[] runners;
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, ContinuationQueue cq, Type loopRunnerType, PlayerLoopRunner runner)
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType,
ContinuationQueue cq, Type loopRunnerType, PlayerLoopRunner runner)
{
#if UNITY_EDITOR
EditorApplication.playModeStateChanged += (state) =>
{
if (state == PlayModeStateChange.EnteredEditMode ||
state == PlayModeStateChange.EnteredPlayMode) return;
if (runner != null)
runner.Clear();
if (cq != null)
cq.Clear();
};
#endif
var yieldLoop = new PlayerLoopSystem
{
type = loopRunnerYieldType,
#if UNITY_EDITOR
updateDelegate = () =>
{
if (Application.isPlaying)
{
cq.Run();
}
}
#else
updateDelegate = cq.Run
#endif
};
var runnerLoop = new PlayerLoopSystem
{
type = loopRunnerType,
#if UNITY_EDITOR
updateDelegate = () =>
{
if (Application.isPlaying)
{
runner.Run();
}
}
#else
updateDelegate = runner.Run
#endif
};
var dest = new PlayerLoopSystem[loopSystem.subSystemList.Length + 2];
Array.Copy(loopSystem.subSystemList, 0, dest, 2, loopSystem.subSystemList.Length);
var source = loopSystem.subSystemList // Remove items from previous initializations.
.Where(ls => ls.type != loopRunnerYieldType && ls.type != loopRunnerType).ToArray();
var dest = new PlayerLoopSystem[source.Length + 2];
Array.Copy(source, 0, dest, 2, source.Length);
dest[0] = yieldLoop;
dest[1] = runnerLoop;
return dest;
@@ -110,7 +110,15 @@ namespace UniRx.Async
unitySynchronizationContetext = SynchronizationContext.Current;
mainThreadId = Thread.CurrentThread.ManagedThreadId;
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
// When domain reload is disabled, re-initialization is required when entering play mode;
// otherwise, pending tasks will leak between play mode sessions.
var domainReloadDisabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled &&
UnityEditor.EditorSettings.enterPlayModeOptions.HasFlag(UnityEditor.EnterPlayModeOptions.DisableDomainReload);
if (!domainReloadDisabled && runners != null) return;
#else
if (runners != null) return; // already initialized
#endif
var playerLoop =
#if UNITY_2019_3_OR_NEWER
@@ -122,6 +130,34 @@ namespace UniRx.Async
Initialize(ref playerLoop);
}
#if UNITY_EDITOR
[InitializeOnLoadMethod]
static void InitOnEditor()
{
//Execute the play mode init method
Init();
//register an Editor update delegate, used to forcing playerLoop update
EditorApplication.update += ForceEditorPlayerLoopUpdate;
}
private static void ForceEditorPlayerLoopUpdate()
{
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling ||
EditorApplication.isUpdating)
{
// Not in Edit mode, don't interfere
return;
}
//force unity to update PlayerLoop callbacks
EditorApplication.QueuePlayerLoopUpdate();
}
#endif
public static void Initialize(ref PlayerLoopSystem playerLoop)
{
yielders = new ContinuationQueue[7];

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncBeginDragTrigger : AsyncTriggerBase
public class AsyncBeginDragTrigger : AsyncTriggerBase, IBeginDragHandler
{
AsyncTriggerPromise<PointerEventData> onBeginDrag;
AsyncTriggerPromiseDictionary<PointerEventData> onBeginDrags;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnBeginDrag(PointerEventData eventData)
void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
{
TrySetResult(onBeginDrag, onBeginDrags, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncCancelTrigger : AsyncTriggerBase
public class AsyncCancelTrigger : AsyncTriggerBase, ICancelHandler
{
AsyncTriggerPromise<BaseEventData> onCancel;
AsyncTriggerPromiseDictionary<BaseEventData> onCancels;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnCancel(BaseEventData eventData)
void ICancelHandler.OnCancel(BaseEventData eventData)
{
TrySetResult(onCancel, onCancels, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncDeselectTrigger : AsyncTriggerBase
public class AsyncDeselectTrigger : AsyncTriggerBase, IDeselectHandler
{
AsyncTriggerPromise<BaseEventData> onDeselect;
AsyncTriggerPromiseDictionary<BaseEventData> onDeselects;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnDeselect(BaseEventData eventData)
void IDeselectHandler.OnDeselect(BaseEventData eventData)
{
TrySetResult(onDeselect, onDeselects, eventData);
}

View File

@@ -13,7 +13,7 @@ namespace UniRx.Async.Triggers
bool called = false;
UniTaskCompletionSource promise;
CancellationTokenSource cancellationTokenSource; // main cancellation
object canellationTokenSourceOrQueue; // external from AddCancellationTriggerOnDestory
object canellationTokenSourceOrQueue; // external from AddCancellationTriggerOnDestroy
public CancellationToken CancellationToken
{
@@ -63,7 +63,7 @@ namespace UniRx.Async.Triggers
}
/// <summary>Add Cancellation Triggers on destroy</summary>
public void AddCancellationTriggerOnDestory(CancellationTokenSource cts)
public void AddCancellationTriggerOnDestroy(CancellationTokenSource cts)
{
if (called)
{

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncDragTrigger : AsyncTriggerBase
public class AsyncDragTrigger : AsyncTriggerBase, IDragHandler
{
AsyncTriggerPromise<PointerEventData> onDrag;
AsyncTriggerPromiseDictionary<PointerEventData> onDrags;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnDrag(PointerEventData eventData)
void IDragHandler.OnDrag(PointerEventData eventData)
{
TrySetResult(onDrag, onDrags, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncDropTrigger : AsyncTriggerBase
public class AsyncDropTrigger : AsyncTriggerBase, IDropHandler
{
AsyncTriggerPromise<PointerEventData> onDrop;
AsyncTriggerPromiseDictionary<PointerEventData> onDrops;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnDrop(PointerEventData eventData)
void IDropHandler.OnDrop(PointerEventData eventData)
{
TrySetResult(onDrop, onDrops, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncEndDragTrigger : AsyncTriggerBase
public class AsyncEndDragTrigger : AsyncTriggerBase, IEndDragHandler
{
AsyncTriggerPromise<PointerEventData> onEndDrag;
AsyncTriggerPromiseDictionary<PointerEventData> onEndDrags;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnEndDrag(PointerEventData eventData)
void IEndDragHandler.OnEndDrag(PointerEventData eventData)
{
TrySetResult(onEndDrag, onEndDrags, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncInitializePotentialDragTrigger : AsyncTriggerBase
public class AsyncInitializePotentialDragTrigger : AsyncTriggerBase, IInitializePotentialDragHandler
{
AsyncTriggerPromise<PointerEventData> onInitializePotentialDrag;
AsyncTriggerPromiseDictionary<PointerEventData> onInitializePotentialDrags;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnInitializePotentialDrag(PointerEventData eventData)
void IInitializePotentialDragHandler.OnInitializePotentialDrag(PointerEventData eventData)
{
TrySetResult(onInitializePotentialDrag, onInitializePotentialDrags, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncMoveTrigger : AsyncTriggerBase
public class AsyncMoveTrigger : AsyncTriggerBase, IMoveHandler
{
AsyncTriggerPromise<AxisEventData> onMove;
AsyncTriggerPromiseDictionary<AxisEventData> onMoves;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnMove(AxisEventData eventData)
void IMoveHandler.OnMove(AxisEventData eventData)
{
TrySetResult(onMove, onMoves, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncPointerClickTrigger : AsyncTriggerBase
public class AsyncPointerClickTrigger : AsyncTriggerBase, IPointerClickHandler
{
AsyncTriggerPromise<PointerEventData> onPointerClick;
AsyncTriggerPromiseDictionary<PointerEventData> onPointerClicks;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnPointerClick(PointerEventData eventData)
void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
{
TrySetResult(onPointerClick, onPointerClicks, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncPointerDownTrigger : AsyncTriggerBase
public class AsyncPointerDownTrigger : AsyncTriggerBase, IPointerDownHandler
{
AsyncTriggerPromise<PointerEventData> onPointerDown;
AsyncTriggerPromiseDictionary<PointerEventData> onPointerDowns;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnPointerDown(PointerEventData eventData)
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
{
TrySetResult(onPointerDown, onPointerDowns, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncPointerEnterTrigger : AsyncTriggerBase
public class AsyncPointerEnterTrigger : AsyncTriggerBase, IPointerEnterHandler
{
AsyncTriggerPromise<PointerEventData> onPointerEnter;
AsyncTriggerPromiseDictionary<PointerEventData> onPointerEnters;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnPointerEnter(PointerEventData eventData)
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
{
TrySetResult(onPointerEnter, onPointerEnters, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncPointerExitTrigger : AsyncTriggerBase
public class AsyncPointerExitTrigger : AsyncTriggerBase, IPointerExitHandler
{
AsyncTriggerPromise<PointerEventData> onPointerExit;
AsyncTriggerPromiseDictionary<PointerEventData> onPointerExits;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnPointerExit(PointerEventData eventData)
void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
{
TrySetResult(onPointerExit, onPointerExits, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncPointerUpTrigger : AsyncTriggerBase
public class AsyncPointerUpTrigger : AsyncTriggerBase, IPointerUpHandler
{
AsyncTriggerPromise<PointerEventData> onPointerUp;
AsyncTriggerPromiseDictionary<PointerEventData> onPointerUps;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnPointerUp(PointerEventData eventData)
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
{
TrySetResult(onPointerUp, onPointerUps, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncScrollTrigger : AsyncTriggerBase
public class AsyncScrollTrigger : AsyncTriggerBase, IScrollHandler
{
AsyncTriggerPromise<PointerEventData> onScroll;
AsyncTriggerPromiseDictionary<PointerEventData> onScrolls;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnScroll(PointerEventData eventData)
void IScrollHandler.OnScroll(PointerEventData eventData)
{
TrySetResult(onScroll, onScrolls, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncSelectTrigger : AsyncTriggerBase
public class AsyncSelectTrigger : AsyncTriggerBase, ISelectHandler
{
AsyncTriggerPromise<BaseEventData> onSelect;
AsyncTriggerPromiseDictionary<BaseEventData> onSelects;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnSelect(BaseEventData eventData)
void ISelectHandler.OnSelect(BaseEventData eventData)
{
TrySetResult(onSelect, onSelects, eventData);
}

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncSubmitTrigger : AsyncTriggerBase
public class AsyncSubmitTrigger : AsyncTriggerBase, ISubmitHandler
{
AsyncTriggerPromise<BaseEventData> onSubmit;
AsyncTriggerPromiseDictionary<BaseEventData> onSubmits;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnSubmit(BaseEventData eventData)
void ISubmitHandler.OnSubmit(BaseEventData eventData)
{
TrySetResult(onSubmit, onSubmits, eventData);
}

View File

@@ -3,6 +3,25 @@
using System.Threading;
using UnityEngine;
using UniRx.Async.Triggers;
namespace UniRx.Async
{
public static class UniTaskCancellationExtensions
{
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this GameObject gameObject)
{
return gameObject.GetAsyncDestroyTrigger().CancellationToken;
}
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this Component component)
{
return component.GetAsyncDestroyTrigger().CancellationToken;
}
}
}
namespace UniRx.Async.Triggers
{
@@ -36,18 +55,6 @@ namespace UniRx.Async.Triggers
return component.GetAsyncDestroyTrigger().OnDestroyAsync();
}
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this GameObject gameObject)
{
return gameObject.GetAsyncDestroyTrigger().CancellationToken;
}
/// <summary>This CancellationToken is canceled when the MonoBehaviour will be destroyed.</summary>
public static CancellationToken GetCancellationTokenOnDestroy(this Component component)
{
return component.GetAsyncDestroyTrigger().CancellationToken;
}
public static UniTask StartAsync(this GameObject gameObject)
{
return gameObject.GetAsyncStartTrigger().StartAsync();

View File

@@ -10,7 +10,7 @@ using UnityEngine.EventSystems;
namespace UniRx.Async.Triggers
{
[DisallowMultipleComponent]
public class AsyncUpdateSelectedTrigger : AsyncTriggerBase
public class AsyncUpdateSelectedTrigger : AsyncTriggerBase, IUpdateSelectedHandler
{
AsyncTriggerPromise<BaseEventData> onUpdateSelected;
AsyncTriggerPromiseDictionary<BaseEventData> onUpdateSelecteds;
@@ -22,7 +22,7 @@ namespace UniRx.Async.Triggers
}
void OnUpdateSelected(BaseEventData eventData)
void IUpdateSelectedHandler.OnUpdateSelected(BaseEventData eventData)
{
TrySetResult(onUpdateSelected, onUpdateSelecteds, eventData);
}

View File

@@ -1,5 +1,6 @@
#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
#pragma warning disable CS0436
using System;
using System.Collections.Generic;

View File

@@ -101,7 +101,7 @@ namespace UniRx.Async
// left, right both suppress operation canceled exception.
var delayCancellationTokenSource = new CancellationTokenSource();
var timeoutTask = (UniTask)UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming).SuppressCancellationThrow();
var timeoutTask = (UniTask)UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
var (hasValue, value) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
@@ -147,7 +147,7 @@ namespace UniRx.Async
// left, right both suppress operation canceled exception.
var delayCancellationTokenSource = new CancellationTokenSource();
var timeoutTask = (UniTask)UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming).SuppressCancellationThrow();
var timeoutTask = (UniTask)UniTask.Delay(timeout, ignoreTimeScale, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
var (hasValue, value) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);

View File

@@ -257,6 +257,7 @@ namespace UniRx.Async
public IDisposable Subscribe(IObserver<T> observer)
{
observer.OnNext(value);
observer.OnCompleted();
return EmptyDisposable.Instance;
}
}

View File

@@ -1,5 +1,6 @@
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#pragma warning disable CS1591
#pragma warning disable CS0436
using System;
using System.Diagnostics;

View File

@@ -59,6 +59,54 @@ namespace UniRx.Async
return new UniTask<UnityEngine.Object>(awaiter);
}
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new AssetBundleRequestAwaiter(resourceRequest);
}
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new UniTask<UnityEngine.Object>(new AssetBundleRequestAwaiter(resourceRequest));
}
public static UniTask<UnityEngine.Object> ConfigureAwait(this AssetBundleRequest resourceRequest, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
var awaiter = new AssetBundleRequestConfiguredAwaiter(resourceRequest, progress, cancellation);
if (!awaiter.IsCompleted)
{
PlayerLoopHelper.AddAction(timing, awaiter);
}
return new UniTask<UnityEngine.Object>(awaiter);
}
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new AssetBundleCreateRequestAwaiter(resourceRequest);
}
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new UniTask<AssetBundle>(new AssetBundleCreateRequestAwaiter(resourceRequest));
}
public static UniTask<AssetBundle> ConfigureAwait(this AssetBundleCreateRequest resourceRequest, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
var awaiter = new AssetBundleCreateRequestConfiguredAwaiter(resourceRequest, progress, cancellation);
if (!awaiter.IsCompleted)
{
PlayerLoopHelper.AddAction(timing, awaiter);
}
return new UniTask<AssetBundle>(awaiter);
}
#if ENABLE_WWW
#if UNITY_2018_3_OR_NEWER
@@ -443,6 +491,325 @@ namespace UniRx.Async
}
}
public struct AssetBundleRequestAwaiter : IAwaiter<UnityEngine.Object>
{
AssetBundleRequest asyncOperation;
Action<AsyncOperation> continuationAction;
AwaiterStatus status;
UnityEngine.Object result;
public AssetBundleRequestAwaiter(AssetBundleRequest asyncOperation)
{
this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending;
this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation;
this.result = (this.status.IsCompletedSuccessfully()) ? asyncOperation.asset : null;
this.continuationAction = null;
}
public bool IsCompleted => status.IsCompleted();
public AwaiterStatus Status => status;
public UnityEngine.Object GetResult()
{
if (status == AwaiterStatus.Succeeded) return this.result;
if (status == AwaiterStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = AwaiterStatus.Succeeded;
}
else
{
Error.ThrowNotYetCompleted();
}
}
this.result = asyncOperation.asset;
if (continuationAction != null)
{
asyncOperation.completed -= continuationAction;
asyncOperation = null; // remove reference.
continuationAction = null;
}
else
{
asyncOperation = null; // remove reference.
}
return this.result;
}
void IAwaiter.GetResult() => GetResult();
public void OnCompleted(Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>();
asyncOperation.completed += continuationAction;
}
}
class AssetBundleRequestConfiguredAwaiter : IAwaiter<UnityEngine.Object>, IPlayerLoopItem
{
AssetBundleRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
AwaiterStatus status;
Action continuation;
UnityEngine.Object result;
public AssetBundleRequestConfiguredAwaiter(AssetBundleRequest asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled
: asyncOperation.isDone ? AwaiterStatus.Succeeded
: AwaiterStatus.Pending;
if (this.status.IsCompletedSuccessfully()) this.result = asyncOperation.asset;
if (this.status.IsCompleted()) return;
this.asyncOperation = asyncOperation;
this.progress = progress;
this.cancellationToken = cancellationToken;
this.continuation = null;
this.result = null;
TaskTracker.TrackActiveTask(this, 2);
}
public bool IsCompleted => status.IsCompleted();
public AwaiterStatus Status => status;
void IAwaiter.GetResult() => GetResult();
public UnityEngine.Object GetResult()
{
if (status == AwaiterStatus.Succeeded) return this.result;
if (status == AwaiterStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
return Error.ThrowNotYetCompleted<UnityEngine.Object>();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(AwaiterStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
this.result = asyncOperation.asset;
InvokeContinuation(AwaiterStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(AwaiterStatus status)
{
this.status = status;
var cont = this.continuation;
// cleanup
TaskTracker.RemoveTracking(this);
this.continuation = null;
this.cancellationToken = CancellationToken.None;
this.progress = null;
this.asyncOperation = null;
if (cont != null) cont.Invoke();
}
public void OnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation);
this.continuation = continuation;
}
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation);
this.continuation = continuation;
}
}
public struct AssetBundleCreateRequestAwaiter : IAwaiter<AssetBundle>
{
AssetBundleCreateRequest asyncOperation;
Action<AsyncOperation> continuationAction;
AwaiterStatus status;
AssetBundle result;
public AssetBundleCreateRequestAwaiter(AssetBundleCreateRequest asyncOperation)
{
this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending;
this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation;
this.result = (this.status.IsCompletedSuccessfully()) ? asyncOperation.assetBundle : null;
this.continuationAction = null;
}
public bool IsCompleted => status.IsCompleted();
public AwaiterStatus Status => status;
public AssetBundle GetResult()
{
if (status == AwaiterStatus.Succeeded) return this.result;
if (status == AwaiterStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = AwaiterStatus.Succeeded;
}
else
{
Error.ThrowNotYetCompleted();
}
}
this.result = asyncOperation.assetBundle;
if (continuationAction != null)
{
asyncOperation.completed -= continuationAction;
asyncOperation = null; // remove reference.
continuationAction = null;
}
else
{
asyncOperation = null; // remove reference.
}
return this.result;
}
void IAwaiter.GetResult() => GetResult();
public void OnCompleted(Action continuation)
{
UnsafeOnCompleted(continuation);
}
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>();
asyncOperation.completed += continuationAction;
}
}
class AssetBundleCreateRequestConfiguredAwaiter : IAwaiter<AssetBundle>, IPlayerLoopItem
{
AssetBundleCreateRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
AwaiterStatus status;
Action continuation;
AssetBundle result;
public AssetBundleCreateRequestConfiguredAwaiter(AssetBundleCreateRequest asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled
: asyncOperation.isDone ? AwaiterStatus.Succeeded
: AwaiterStatus.Pending;
if (this.status.IsCompletedSuccessfully()) this.result = asyncOperation.assetBundle;
if (this.status.IsCompleted()) return;
this.asyncOperation = asyncOperation;
this.progress = progress;
this.cancellationToken = cancellationToken;
this.continuation = null;
this.result = null;
TaskTracker.TrackActiveTask(this, 2);
}
public bool IsCompleted => status.IsCompleted();
public AwaiterStatus Status => status;
void IAwaiter.GetResult() => GetResult();
public AssetBundle GetResult()
{
if (status == AwaiterStatus.Succeeded) return this.result;
if (status == AwaiterStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
return Error.ThrowNotYetCompleted<AssetBundle>();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(AwaiterStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
this.result = asyncOperation.assetBundle;
InvokeContinuation(AwaiterStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(AwaiterStatus status)
{
this.status = status;
var cont = this.continuation;
// cleanup
TaskTracker.RemoveTracking(this);
this.continuation = null;
this.cancellationToken = CancellationToken.None;
this.progress = null;
this.asyncOperation = null;
if (cont != null) cont.Invoke();
}
public void OnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation);
this.continuation = continuation;
}
public void UnsafeOnCompleted(Action continuation)
{
Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation);
this.continuation = continuation;
}
}
#if ENABLE_WWW
#if UNITY_2018_3_OR_NEWER

View File

@@ -0,0 +1,11 @@
{
"name": "com.cysharp.unitask",
"displayName": "UniTask",
"version": "1.3.1",
"unity": "2018.3",
"description": "Provides an efficient async/await integration to Unity.",
"keywords": ["async/await", "async", "Task", "UniTask"],
"license": "MIT",
"category": "Task",
"dependencies": {}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d1a9a71f68bb0d04db91ddaa3329abf9
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,4 +8,7 @@ EditorBuildSettings:
- enabled: 1
path: Assets/Scenes/SandboxMain.unity
guid: 2cda990e2423bbf4892e6590ba056729
- enabled: 1
path: Assets/Scenes/NextScene.unity
guid: dfced9d8875377c44a1d53620d36f0d5
m_configObjects: {}

View File

@@ -3,19 +3,33 @@
--- !u!159 &1
EditorSettings:
m_ObjectHideFlags: 0
serializedVersion: 7
serializedVersion: 9
m_ExternalVersionControlSupport: Visible Meta Files
m_SerializationMode: 2
m_LineEndingsForNewScripts: 2
m_DefaultBehaviorMode: 1
m_PrefabRegularEnvironment: {fileID: 0}
m_PrefabUIEnvironment: {fileID: 0}
m_SpritePackerMode: 4
m_SpritePackerPaddingPower: 1
m_EtcTextureCompressorBehavior: 1
m_EtcTextureFastCompressor: 1
m_EtcTextureNormalCompressor: 2
m_EtcTextureBestCompressor: 4
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmref
m_ProjectGenerationRootNamespace:
m_UserGeneratedProjectSuffix:
m_CollabEditorSettings:
inProgressEnabled: 1
m_EnableTextureStreamingInEditMode: 1
m_EnableTextureStreamingInPlayMode: 1
m_AsyncShaderCompilation: 1
m_EnterPlayModeOptionsEnabled: 0
m_EnterPlayModeOptions: 3
m_ShowLightmapResolutionOverlay: 1
m_UseLegacyProbeSampleCount: 1
m_AssetPipelineMode: 1
m_CacheServerMode: 0
m_CacheServerEndpoint:
m_CacheServerNamespacePrefix: default
m_CacheServerEnableDownload: 1
m_CacheServerEnableUpload: 1

View File

@@ -1,2 +1,2 @@
m_EditorVersion: 2019.3.0a2
m_EditorVersionWithRevision: 2019.3.0a2 (fa7740529556)
m_EditorVersion: 2019.3.9f1
m_EditorVersionWithRevision: 2019.3.9f1 (e6e740a1c473)

181
README.md
View File

@@ -73,11 +73,14 @@ UniTask feature rely on C# 7.0([task-like custom async method builder feature](h
Why UniTask(custom task-like object) is required? Because Task is too heavy, not matched to Unity threading(single-thread). UniTask does not use thread and SynchronizationContext because almost Unity's asynchronous object is automaticaly dispatched by Unity's engine layer. It acquires more fast and more less allocation, completely integrated with Unity.
> More details, please see this slide: [Deep Dive async/await in Unity with UniTask(EN)
](https://www.slideshare.net/neuecc/deep-dive-asyncawait-in-unity-with-unitasken)
You can await `AsyncOperation`, `ResourceRequest`, `UnityWebRequestAsyncOperation`, `IEnumerator` and others when using `UniRx.Async`.
`UniTask.Delay`, `UniTask.Yield`, `UniTask.Timeout` that is frame-based timer operators(no uses thread so works on WebGL publish) driven by custom PlayerLoop(Unity 2018 experimental feature). In default, UniTask initialize automatically when application begin, but it is override all. If you want to append PlayerLoop, please call `PlayerLoopHelper.Initialize(ref yourCustomizedPlayerLoop)` manually.
> Before Unity 2019.3, Unity does not have `PlayerLooop.GetCurrentlayerLoop` so you can't use with Unity ECS package in default. If you want to use with ECS and before Unity 2019.3, you can use this hack below.
> Before Unity 2019.3, Unity does not have `PlayerLooop.GetCurrentPlayerLoop` so you can't use with Unity ECS package in default. If you want to use with ECS and before Unity 2019.3, you can use this hack below.
```csharp
// Get ECS Loop.
@@ -134,23 +137,142 @@ You can convert Task -> UniTask: `AsUniTask`, `UniTask` -> `UniTask<AsyncUnit>`:
If you want to convert async to coroutine, you can use `UniTask.ToCoroutine`, this is useful to use only allow coroutine system.
Reusable Promises
Cancellation and Exception handling
---
Some UniTask factory methods have `CancellationToken cancellation = default(CancellationToken)` parameter. Andalso some async operation for unity have `ConfigureAwait(..., CancellationToken cancellation = default(CancellationToken))` extension methods.
Exception handling
You can pass `CancellationToken` to parameter by standard [`CancellationTokenSource`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource).
```csharp
var cts = new CancellationTokenSource();
cancelButton.onClick.AddListener(() =>
{
cts.Cancel();
});
await UnityWebRequest.Get("http://google.co.jp").SendWebRequest().ConfigureAwait(cancellation: cts.Token);
await UniTask.DelayFrame(1000, cancellationToken: cts.Token);
```
CancellationToken can create by `CancellationTokenSource` or MonoBehaviour's extension method `GetCancellationTokenOnDestroy`.
```csharp
// this CancellationToken lifecycle is same as GameObject.
await UniTask.DelayFrame(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
```
When detect cancellation, all methods throws `OperationCanceledException` and propagate to upstream. `OperationCanceledException` is special exception, if not handled this exception, finally it is propagated to `UniTaskScheduler.UnobservedTaskException`.
Default behaviour of received unhandled exception is write log as warning. Log level can change by `UniTaskScheduler.UnobservedExceptionWriteLogType`. If you want to change custom beavhiour, set action to `UniTaskScheduler.UnobservedTaskException.`
If you want to cancel behaviour in async UniTask method, throws `OperationCanceledException` manually.
```csharp
public async UniTask<int> FooAsync()
{
await UniTask.Yield();
throw new OperationCanceledException();
}
```
If you handle exception but want to ignore(propagete to global cancellation handling), use exception filter.
```csharp
public async UniTask<int> BarAsync()
{
try
{
var x = await FooAsync();
return x * 2;
}
catch (Exception ex) when (!(ex is OperationCanceledException))
{
return -1;
}
}
```
throws/catch `OperationCanceledException` is slightly heavy, if you want to care performance, use `UniTask.SuppressCancellationThrow` to avoid OperationCanceledException throw. It returns `(bool IsCanceled, T Result)` instead of throw.
```csharp
var (isCanceled, _) = await UniTask.DelayFrame(10, cancellationToken: cts.Token).SuppressCancellationThrow();
if (isCanceled)
{
// ...
}
```
Note: Only suppress throws if you call it directly into the most source method.
Progress
---
`OperationCanceledException` and `UniTaskScheduler.UnobservedTaskException`, `UniTaskVoid`. and what is `UniTask.SuppressCancellationThrow`.
Some async operation for unity have `ConfigureAwait(IProgress<float> progress = null, ...)` extension methods.
```csharp
var progress = Progress.Create<float>(x => Debug.Log(x));
var request = await UnityWebRequest.Get("http://google.co.jp")
.SendWebRequest()
.ConfigureAwait(progress: progress);
```
Should not use `new System.Progress<T>`, because it allocate every times. Use `UniRx.Async.Progress` instead. Progress factory has two methods, `Create` and `CreateOnlyValueChanged`. `CreateOnlyValueChanged` calls only when progress value changed. Should not use `new System.Progress<T>`, it allocate every times.
Implements interface is more better.
```csharp
public class Foo : MonoBehaviour, IProgress<float>
{
public void Report(float value)
{
UnityEngine.Debug.Log(value);
}
public async UniTaskVoid WebRequest()
{
var request = await UnityWebRequest.Get("http://google.co.jp")
.SendWebRequest()
.ConfigureAwait(progress: this); // pass this
}
}
```
UniTaskTracker
---
useful for check(leak) UniTasks.
useful for check(leak) UniTasks. You can open tracker window in `Window -> UniTask Tracker`.
![](https://user-images.githubusercontent.com/46207/50421527-abf1cf80-0883-11e9-928a-ffcd47b8c454.png)
awaitable Events
* Enable AutoReload(Toggle) - Reload automatically.
* Reload - Reload view.
* GC.Collect - Invoke GC.Collect.
* Enable Tracking(Toggle) - Start to track async/await UniTask. Performance impact: low.
* Enable StackTrace(Toggle) - Capture StackTrace when task is started. Performance impact: high.
For debug use, enable tracking and capture stacktrace is useful but it it decline performance. Recommended usage is enable both to find task leak, and when done, finally disable both.
Reusable Promises
---
Some UniTask factory can reuse to reduce allocation. The list is `Yield`, `Delay`, `DelayFrame`, `WaitUntil`, `WaitWhile`, `WaitUntilValueChanged`.
```csharp
var reusePromise = UniTask.DelayFrame(10);
for (int i = 0; i < 10; i++)
{
await reusePromise;
}
```
awaitable Events
---
Unity events can await like `OnClickAsync`, `OnCollisionEnterAsync`. It can use by `UniRx.Async.Triggers`.
```csharp
using UniRx.Async.Triggers;
async UniTask TripleClick(CancellationToken token)
{
await button.OnClickAsync(token);
@@ -172,13 +294,41 @@ async UniTask TripleClick(CancellationToken token)
}
```
async void vs async UniTask/UniTaskVoid
---
`async void` is standard C# system so does not run on UniTask systems. It is better not to use. `async UniTaskVoid` is lightweight version of `async UniTask` because it does not have awaitable completion. If you don't require to await it(fire and forget), use `UniTaskVoid` is better. Unfortunately to dismiss warning, require to using with `Forget()`.
For Unit Testing
---
Unity's `[UnityTest]` attribute can test coroutine(IEnumerator) but can not test async. `UniTask.ToCoroutine` bridges async/await to coroutine so you can test async method.
```csharp
[UnityTest]
public IEnumerator DelayIgnore() => UniTask.ToCoroutine(async () =>
{
var time = Time.realtimeSinceStartup;
Time.timeScale = 0.5f;
try
{
await UniTask.Delay(TimeSpan.FromSeconds(3), ignoreTimeScale: true);
var elapsed = Time.realtimeSinceStartup - time;
Assert.AreEqual(3, (int)Math.Round(TimeSpan.FromSeconds(elapsed).TotalSeconds, MidpointRounding.ToEven));
}
finally
{
Time.timeScale = 1.0f;
}
});
```
Method List
---
```csharp
UniTask.WaitUntil
UniTask.WaitWhile
UniTask.WaitUntilValueChanged
UniTask.WaitUntilValueChangedWithIsDestroyed
UniTask.SwitchToThreadPool
UniTask.SwitchToTaskPool
UniTask.SwitchToMainThread
@@ -192,21 +342,18 @@ UniTask.DelayFrame
UniTask.Delay(..., bool ignoreTimeScale = false, ...) parameter
```
Cancellation
UPM Package
---
After Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of git package. You can add `https://github.com/Cysharp/UniTask.git?path=Assets/UniRx.Async` to Package Manager
async void vs async UniTask/UniTaskVoid
---
![image](https://user-images.githubusercontent.com/46207/79450714-3aadd100-8020-11ea-8aae-b8d87fc4d7be.png)
Progress
---
![image](https://user-images.githubusercontent.com/46207/79450774-56b17280-8020-11ea-91eb-21e1f51eb60c.png)
For Unit Testing
---
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=Assets/UniRx.Async"` to `Packages/manifest.json`.
Reference
---
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#1.3.0`. For example `https://github.com/Cysharp/UniTask.git?path=Assets/UniRx.Async#1.3.1`.
License
---
This library is under the MIT License.
This library is under the MIT License.