mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 03:20:16 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5f607204b | ||
|
|
676aba7cce | ||
|
|
745de32006 | ||
|
|
a0ef75e797 | ||
|
|
dda6cbd679 | ||
|
|
141b447b30 | ||
|
|
8e7a89eff7 | ||
|
|
7848f878d7 | ||
|
|
c3a02ffbe6 | ||
|
|
d509317ed2 | ||
|
|
74738ab13e | ||
|
|
de3d491375 | ||
|
|
139f5f7914 | ||
|
|
5e2a4934dd | ||
|
|
4ef15f3a14 | ||
|
|
6d56f8d2bb | ||
|
|
6e441a2d14 | ||
|
|
66ba4b9986 | ||
|
|
7e26573abb | ||
|
|
9db6482f0a | ||
|
|
9c257e44f0 | ||
|
|
ecd678117e | ||
|
|
ebce2e922d | ||
|
|
e67562b823 | ||
|
|
d639283f59 | ||
|
|
ecf6c1fba5 | ||
|
|
50ba93f951 | ||
|
|
d6a7dd9fc5 | ||
|
|
1a2dfd1537 | ||
|
|
08913104a9 | ||
|
|
85eeeb3dd5 | ||
|
|
47b701eed0 | ||
|
|
10ba7bcfde | ||
|
|
89d7e7c5fb | ||
|
|
f7c95bcabd |
@@ -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:
|
||||
@@ -71,9 +85,15 @@ workflows:
|
||||
- build-and-create-package:
|
||||
unity_version: 2019.1.2f1
|
||||
unity_license: ${UNITY_LICENSE_2019_1}
|
||||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
- 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 +101,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-release:
|
||||
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-release
|
||||
filters:
|
||||
tags:
|
||||
only: /^\d\.\d\.\d.*/
|
||||
branches:
|
||||
ignore: /.*/
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -145,3 +145,5 @@ RuntimeUnitTestToolkit\.csproj
|
||||
Assembly-CSharp-Editor\.csproj
|
||||
|
||||
UniRx\.Async\.unitypackage
|
||||
|
||||
UniRx.Async.Tests.Editor.csproj
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using UniRx.Async;
|
||||
using UnityEngine;
|
||||
@@ -15,19 +16,11 @@ public class SandboxMain : MonoBehaviour
|
||||
|
||||
async void Start()
|
||||
{
|
||||
await UniTask.CompletedTask; // ok
|
||||
UnityEngine.Debug.Log("DOWNLOAD START:" + Time.frameCount);
|
||||
|
||||
// var subject = new Subject<Unit>();
|
||||
//subject.OnCompleted();
|
||||
IObservable<AsyncUnit> subject = default;
|
||||
try
|
||||
{
|
||||
await subject.ToUniTask(); // exception
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.Log(exception);
|
||||
}
|
||||
var req = await UnityWebRequest.Get(Path.Combine(Application.streamingAssetsPath, "test.txt")).SendWebRequest();
|
||||
|
||||
UnityEngine.Debug.Log("DOWNLOAD RESULT:" + Time.frameCount + ", " + req.downloadHandler.text);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
Assets/StreamingAssets.meta
Normal file
8
Assets/StreamingAssets.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bb6ff9f1f0d0cd4da5ba7623f10dd6b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1
Assets/StreamingAssets/test.txt
Normal file
1
Assets/StreamingAssets/test.txt
Normal file
@@ -0,0 +1 @@
|
||||
MyTEST
|
||||
7
Assets/StreamingAssets/test.txt.meta
Normal file
7
Assets/StreamingAssets/test.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fc83f79aef22a2449d5e9ca4964b2e0
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
8
Assets/Tests/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 649f696fcc0c3104a8de82a2550d248c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
405
Assets/Tests/Editor/AsyncTestEditor.cs
Normal file
405
Assets/Tests/Editor/AsyncTestEditor.cs
Normal 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
|
||||
11
Assets/Tests/Editor/AsyncTestEditor.cs.meta
Normal file
11
Assets/Tests/Editor/AsyncTestEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 851899ba3337ac24a8331cb18fabe771
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
96
Assets/Tests/Editor/RunTestEditor.cs
Normal file
96
Assets/Tests/Editor/RunTestEditor.cs
Normal 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
|
||||
11
Assets/Tests/Editor/RunTestEditor.cs.meta
Normal file
11
Assets/Tests/Editor/RunTestEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76d078e5d960ac2429ce67a930c29ade
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Tests/Editor/UniRx.Async.Tests.Editor.asmdef
Normal file
23
Assets/Tests/Editor/UniRx.Async.Tests.Editor.asmdef
Normal 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": []
|
||||
}
|
||||
7
Assets/Tests/Editor/UniRx.Async.Tests.Editor.asmdef.meta
Normal file
7
Assets/Tests/Editor/UniRx.Async.Tests.Editor.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2431de67d1d97a48afcaf18f333a0b4
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/Tests/Editor/WhenAnyTestEditor.cs
Normal file
44
Assets/Tests/Editor/WhenAnyTestEditor.cs
Normal 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
|
||||
11
Assets/Tests/Editor/WhenAnyTestEditor.cs.meta
Normal file
11
Assets/Tests/Editor/WhenAnyTestEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5addd9aa1a794441af032a71208b495
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -391,5 +391,5 @@ namespace UniRx.Async.Internal
|
||||
public abstract bool MoveNext();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -257,6 +257,7 @@ namespace UniRx.Async
|
||||
public IDisposable Subscribe(IObserver<T> observer)
|
||||
{
|
||||
observer.OnNext(value);
|
||||
observer.OnCompleted();
|
||||
return EmptyDisposable.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
11
Assets/UniRx.Async/package.json
Normal file
11
Assets/UniRx.Async/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "com.cysharp.unitask",
|
||||
"displayName": "UniTask",
|
||||
"version": "1.3.0",
|
||||
"unity": "2018.3",
|
||||
"description": "Provides an efficient async/await integration to Unity.",
|
||||
"keywords": ["async/await", "async", "Task", "UniTask"],
|
||||
"license": "MIT",
|
||||
"category": "Task",
|
||||
"dependencies": {}
|
||||
}
|
||||
7
Assets/UniRx.Async/package.json.meta
Normal file
7
Assets/UniRx.Async/package.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1a9a71f68bb0d04db91ddaa3329abf9
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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: {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
181
README.md
@@ -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 -> UniRx -> UniTask Tracker`.
|
||||
|
||||

|
||||
|
||||
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,16 @@ 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
|
||||
---
|
||||

|
||||
|
||||
Progress
|
||||
---
|
||||

|
||||
|
||||
For Unit Testing
|
||||
---
|
||||
|
||||
Reference
|
||||
---
|
||||
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=Assets/UniRx.Async"` to `Packages/manifest.json`.
|
||||
|
||||
License
|
||||
---
|
||||
This library is under the MIT License.
|
||||
This library is under the MIT License.
|
||||
Reference in New Issue
Block a user