From c65f9c3497a817b36e0afd70042e671482e2534f Mon Sep 17 00:00:00 2001 From: hadashiA Date: Thu, 7 Sep 2023 17:36:06 +0900 Subject: [PATCH 1/2] Add EndOfFrame implementation using UnityEngine.Awaitable --- .../Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs index ccd688b..fadd63c 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs @@ -75,6 +75,12 @@ namespace Cysharp.Threading.Tasks return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token); } +#if UNITY_2023_1_OR_NEWER + public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToken = default) + { + await Awaitable.EndOfFrameAsync(cancellationToken); + } +#else [Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")] public static YieldAwaitable WaitForEndOfFrame() { @@ -86,6 +92,7 @@ namespace Cysharp.Threading.Tasks { return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken); } +#endif public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken = default) { From ffbadbcc4c94708833e3d7bfe188e7dee76bdfe9 Mon Sep 17 00:00:00 2001 From: hadashiA Date: Fri, 8 Sep 2023 18:00:39 +0900 Subject: [PATCH 2/2] Update README about WaitForEndOfFrame --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ff1bf63..5f4374d 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,13 @@ async UniTask DemoAsync() await UniTask.Yield(); await UniTask.NextFrame(); - // replacement of WaitForEndOfFrame(requires MonoBehaviour(CoroutineRunner)) + // replacement of WaitForEndOfFrame +#if UNITY_2023_1_OR_NEWER + await UniTask.WaitForEndOfFrame(); +#else + // requires MonoBehaviour(CoroutineRunner)) await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour +#endif // replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate)) await UniTask.WaitForFixedUpdate(); @@ -499,6 +504,8 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github. `PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`. > `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`. +> +> Note: In Unity 2023.1 or newer, `await UniTask.WaitForEndOfFrame();` no longer requires MonoBehaviour. It uses `UnityEngine.Awaitable.EndOfFrameAsync`. `yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.