diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs
index 43625ab5..8c41d2cb 100644
--- a/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs
+++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/PlayerLoopRunner.cs
@@ -118,6 +118,9 @@ public void Run()
case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate();
break;
+ case PlayerLoopTiming.ManualUpdate:
+ ManualUpdate();
+ break;
#if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate:
TimeUpdate();
@@ -148,6 +151,7 @@ public void Run()
void LastPreLateUpdate() => RunCore();
void PostLateUpdate() => RunCore();
void LastPostLateUpdate() => RunCore();
+ void ManualUpdate() => RunCore();
#if UNITY_2020_2_OR_NEWER
void TimeUpdate() => RunCore();
void LastTimeUpdate() => RunCore();
@@ -178,7 +182,7 @@ void RunCore()
}
else
{
- continue; // next i
+ continue; // next i
}
}
catch (Exception ex)
diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs
index b17375e7..1c994649 100644
--- a/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs
+++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/PlayerLoopHelper.cs
@@ -96,6 +96,7 @@ public enum PlayerLoopTiming
TimeUpdate = 14,
LastTimeUpdate = 15,
#endif
+ ManualUpdate = 16,
}
[Flags]
@@ -192,6 +193,7 @@ public static class PlayerLoopHelper
static SynchronizationContext unitySynchronizationContext;
static ContinuationQueue[] yielders;
static PlayerLoopRunner[] runners;
+ static PlayerLoopRunner ManualRunner;
internal static bool IsEditorApplicationQuitting { get; private set; }
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
bool injectOnFirst,
@@ -251,6 +253,10 @@ static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
return dest;
}
+ public static void ManualUpdate()
+ {
+ ManualRunner.Run();
+ }
static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
{
@@ -302,7 +308,7 @@ static void Init()
catch { }
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
- // When domain reload is disabled, re-initialization is required when entering play mode;
+ // 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);
@@ -405,6 +411,8 @@ public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopT
runners = new PlayerLoopRunner[14];
#endif
+ ManualRunner = new PlayerLoopRunner(PlayerLoopTiming.ManualUpdate);
+
var copyList = playerLoop.subSystemList.ToArray();
// Initialization
@@ -491,6 +499,11 @@ public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopT
public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
{
+ if ((int)timing == (int)PlayerLoopTiming.ManualUpdate)
+ {
+ ManualRunner.AddAction(action);
+ return;
+ }
var runner = runners[(int)timing];
if (runner == null)
{
@@ -528,8 +541,8 @@ public static void DumpCurrentPlayerLoop()
{
sb.AppendFormat("------{0}------", header.type.Name);
sb.AppendLine();
-
- if (header.subSystemList is null)
+
+ if (header.subSystemList is null)
{
sb.AppendFormat("{0} has no subsystems!", header.ToString());
sb.AppendLine();
@@ -557,11 +570,11 @@ public static bool IsInjectedUniTaskPlayerLoop()
foreach (var header in playerLoop.subSystemList)
{
- if (header.subSystemList is null)
- {
+ if (header.subSystemList is null)
+ {
continue;
}
-
+
foreach (var subSystem in header.subSystemList)
{
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs
index 4ff699dd..91197209 100644
--- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs
+++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs
@@ -16,11 +16,14 @@ public enum DelayType
/// Ignore timescale, use Time.unscaledDeltaTime.
UnscaledDeltaTime,
/// use Stopwatch.GetTimestamp().
- Realtime
+ Realtime,
+ ManualTime
}
public partial struct UniTask
{
+ public static float deltaTime;
+ public static int frameCount;
public static YieldAwaitable Yield()
{
// optimized for single continuation
@@ -80,7 +83,7 @@ public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToke
{
await Awaitable.EndOfFrameAsync(cancellationToken);
}
-#else
+#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()
{
@@ -92,7 +95,7 @@ public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken, boo
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
}
-#endif
+#endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
{
@@ -179,6 +182,10 @@ public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken, bo
switch (delayType)
{
+ case DelayType.ManualTime:
+ {
+ return new UniTask(DelayManualPromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
+ }
case DelayType.UnscaledDeltaTime:
{
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
@@ -229,7 +236,7 @@ public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken c
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
-
+
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
@@ -320,6 +327,7 @@ static NextFramePromise()
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
+ PlayerLoopTiming timing = PlayerLoopTiming.Update;
NextFramePromise()
{
@@ -337,8 +345,9 @@ public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken c
result = new NextFramePromise();
}
- result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
+ result.frameCount = PlayerLoopHelper.IsMainThread ?(timing == PlayerLoopTiming.ManualUpdate ? UniTask.frameCount : Time.frameCount) : -1;
result.cancellationToken = cancellationToken;
+ result.timing = timing;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
@@ -400,7 +409,7 @@ public bool MoveNext()
return false;
}
- if (frameCount == Time.frameCount)
+ if (frameCount == (timing == PlayerLoopTiming.ManualUpdate ? UniTask.frameCount : Time.frameCount))
{
return true;
}
@@ -695,6 +704,138 @@ bool TryReturn()
}
}
+ sealed class DelayManualPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode
+ {
+ static TaskPool pool;
+ DelayManualPromise nextNode;
+ public ref DelayManualPromise NextNode => ref nextNode;
+
+ static DelayManualPromise()
+ {
+ TaskPool.RegisterSizeGetter(typeof(DelayManualPromise), () => pool.Size);
+ }
+
+ int initialFrame;
+ float delayTimeSpan;
+ float elapsed;
+ CancellationToken cancellationToken;
+ CancellationTokenRegistration cancellationTokenRegistration;
+ bool cancelImmediately;
+
+ UniTaskCompletionSourceCore