diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/EnumeratorAsyncExtensions.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/EnumeratorAsyncExtensions.cs index 91d3240..4bd7f6d 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/EnumeratorAsyncExtensions.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/EnumeratorAsyncExtensions.cs @@ -44,6 +44,7 @@ namespace Cysharp.Threading.Tasks IEnumerator innerEnumerator; CancellationToken cancellationToken; + int initialFrame; UniTaskCompletionSourceCore core; @@ -66,10 +67,13 @@ namespace Cysharp.Threading.Tasks result.innerEnumerator = ConsumeEnumerator(innerEnumerator); result.cancellationToken = cancellationToken; + result.initialFrame = -1; PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; + + result.MoveNext(); // run immediately. return result; } @@ -108,6 +112,19 @@ namespace Cysharp.Threading.Tasks return false; } + if (initialFrame == -1) + { + // Time can not touch in threadpool. + if (PlayerLoopHelper.IsMainThread) + { + initialFrame = Time.frameCount; + } + } + else if (initialFrame == Time.frameCount) + { + return true; // already executed in first frame, skip. + } + try { if (innerEnumerator.MoveNext()) diff --git a/src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs b/src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs new file mode 100644 index 0000000..de50ba4 --- /dev/null +++ b/src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs @@ -0,0 +1,126 @@ +#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine.UI; +using UnityEngine.Scripting; +using Cysharp.Threading.Tasks; +using Unity.Collections; +using System.Threading; +using NUnit.Framework; +using UnityEngine.TestTools; +using FluentAssertions; + +namespace Cysharp.Threading.TasksTests +{ + public class CoroutineToUniTaskTest + { + [UnityTest] + public IEnumerator EarlyUpdate() => UniTask.ToCoroutine(async () => + { + await UniTask.Yield(PlayerLoopTiming.EarlyUpdate); + + var l = new List<(int, int)>(); + var currentFrame = Time.frameCount; + var t = Worker(l).ToUniTask(); + + l.Count.Should().Be(1); + l[0].Should().Be((0, currentFrame)); + + await t; + + l[1].Should().Be((1, Time.frameCount)); + l[1].Item2.Should().NotBe(currentFrame); + }); + + [UnityTest] + public IEnumerator LateUpdate() => UniTask.ToCoroutine(async () => + { + await UniTask.Yield(PlayerLoopTiming.PostLateUpdate); + + var l = new List<(int, int)>(); + var currentFrame = Time.frameCount; + var t = Worker(l).ToUniTask(); + + l.Count.Should().Be(1); + l[0].Should().Be((0, currentFrame)); + + await t; + + l[1].Should().Be((1, Time.frameCount)); + l[1].Item2.Should().NotBe(currentFrame); + }); + + //[UnityTest] + //public IEnumerator TestCoroutine() + //{ + // yield return UniTask.Yield(PlayerLoopTiming.EarlyUpdate).ToUniTask().ToCoroutine(); + + // var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour)); + + // var l = new List<(int, int)>(); + // var currentFrame = Time.frameCount; + // var t = nanika.StartCoroutine(Worker(l)); + + // l.Count.Should().Be(1); + // l[0].Should().Be((0, currentFrame)); + + // yield return t; + + // l[1].Should().Be((1, Time.frameCount)); + // l[1].Item2.Should().NotBe(currentFrame); + //} + + //[UnityTest] + //public IEnumerator TestCoroutine2() + //{ + // yield return UniTask.Yield(PlayerLoopTiming.PostLateUpdate).ToUniTask().ToCoroutine(); + + // var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour)); + + // var l = new List<(int, int)>(); + // var currentFrame = Time.frameCount; + // var t = nanika.StartCoroutine(Worker(l)); + + // l.Count.Should().Be(1); + // l[0].Should().Be((0, currentFrame)); + + // yield return t; + + // l[1].Should().Be((1, Time.frameCount)); + // l[1].Item2.Should().NotBe(currentFrame); + //} + + IEnumerator Worker(List<(int, int)> l) + { + l.Add((0, Time.frameCount)); + yield return null; + l.Add((1, Time.frameCount)); + } + + public async UniTask Foo() + { + var tasks = new List(); + var t = Bar(); + tasks.Add(t); + + t = Bar(); + tasks.Add(t); + + await UniTask.WhenAll(tasks); + } + + public async UniTask Bar() + { + await UniTask.Yield(); + return default(T); + } + } +} + +#endif \ No newline at end of file diff --git a/src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta b/src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta new file mode 100644 index 0000000..f5821a1 --- /dev/null +++ b/src/UniTask/Assets/Tests/CoroutineToUniTaskTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43ffb719370515746932af3732ce073e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: