Compare commits

..

2 Commits

Author SHA1 Message Date
weicai995
ed988d1a28 Merge 9c4bab6e0a into 73a63b7f67 2025-10-01 10:04:05 -04:00
weicai995
9c4bab6e0a Add Manual Update 2025-07-04 17:39:35 +08:00
6 changed files with 173 additions and 23 deletions

View File

@@ -5,10 +5,6 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" # Check for updates to GitHub Actions every week interval: "weekly" # Check for updates to GitHub Actions every week
groups:
dependencies:
patterns:
- "*"
cooldown: cooldown:
default-days: 14 # Wait 14 days before creating another PR for the same dependency. This will prevent vulnerability on the package impact. default-days: 14 # Wait 14 days before creating another PR for the same dependency. This will prevent vulnerability on the package impact.
ignore: ignore:

View File

@@ -10,11 +10,6 @@ using UnityEditor.IMGUI.Controls;
using Cysharp.Threading.Tasks.Internal; using Cysharp.Threading.Tasks.Internal;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
#if UNITY_6000_2_OR_NEWER
using TreeView = UnityEditor.IMGUI.Controls.TreeView<int>;
using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem<int>;
using TreeViewState = UnityEditor.IMGUI.Controls.TreeViewState<int>;
#endif
namespace Cysharp.Threading.Tasks.Editor namespace Cysharp.Threading.Tasks.Editor
{ {
@@ -184,3 +179,4 @@ namespace Cysharp.Threading.Tasks.Editor
} }
} }

View File

@@ -118,6 +118,9 @@ namespace Cysharp.Threading.Tasks.Internal
case PlayerLoopTiming.LastPostLateUpdate: case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate(); LastPostLateUpdate();
break; break;
case PlayerLoopTiming.ManualUpdate:
ManualUpdate();
break;
#if UNITY_2020_2_OR_NEWER #if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate: case PlayerLoopTiming.TimeUpdate:
TimeUpdate(); TimeUpdate();
@@ -148,6 +151,7 @@ namespace Cysharp.Threading.Tasks.Internal
void LastPreLateUpdate() => RunCore(); void LastPreLateUpdate() => RunCore();
void PostLateUpdate() => RunCore(); void PostLateUpdate() => RunCore();
void LastPostLateUpdate() => RunCore(); void LastPostLateUpdate() => RunCore();
void ManualUpdate() => RunCore();
#if UNITY_2020_2_OR_NEWER #if UNITY_2020_2_OR_NEWER
void TimeUpdate() => RunCore(); void TimeUpdate() => RunCore();
void LastTimeUpdate() => RunCore(); void LastTimeUpdate() => RunCore();
@@ -178,7 +182,7 @@ namespace Cysharp.Threading.Tasks.Internal
} }
else else
{ {
continue; // next i continue; // next i
} }
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -96,6 +96,7 @@ namespace Cysharp.Threading.Tasks
TimeUpdate = 14, TimeUpdate = 14,
LastTimeUpdate = 15, LastTimeUpdate = 15,
#endif #endif
ManualUpdate = 16,
} }
[Flags] [Flags]
@@ -192,6 +193,7 @@ namespace Cysharp.Threading.Tasks
static SynchronizationContext unitySynchronizationContext; static SynchronizationContext unitySynchronizationContext;
static ContinuationQueue[] yielders; static ContinuationQueue[] yielders;
static PlayerLoopRunner[] runners; static PlayerLoopRunner[] runners;
static PlayerLoopRunner ManualRunner;
internal static bool IsEditorApplicationQuitting { get; private set; } internal static bool IsEditorApplicationQuitting { get; private set; }
static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem,
bool injectOnFirst, bool injectOnFirst,
@@ -251,6 +253,10 @@ namespace Cysharp.Threading.Tasks
return dest; return dest;
} }
public static void ManualUpdate()
{
ManualRunner.Run();
}
static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType) static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
{ {
@@ -302,7 +308,7 @@ namespace Cysharp.Threading.Tasks
catch { } catch { }
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER #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. // otherwise, pending tasks will leak between play mode sessions.
var domainReloadDisabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled && var domainReloadDisabled = UnityEditor.EditorSettings.enterPlayModeOptionsEnabled &&
UnityEditor.EditorSettings.enterPlayModeOptions.HasFlag(UnityEditor.EnterPlayModeOptions.DisableDomainReload); UnityEditor.EditorSettings.enterPlayModeOptions.HasFlag(UnityEditor.EnterPlayModeOptions.DisableDomainReload);
@@ -405,6 +411,8 @@ namespace Cysharp.Threading.Tasks
runners = new PlayerLoopRunner[14]; runners = new PlayerLoopRunner[14];
#endif #endif
ManualRunner = new PlayerLoopRunner(PlayerLoopTiming.ManualUpdate);
var copyList = playerLoop.subSystemList.ToArray(); var copyList = playerLoop.subSystemList.ToArray();
// Initialization // Initialization
@@ -491,6 +499,11 @@ namespace Cysharp.Threading.Tasks
public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action) public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
{ {
if ((int)timing == (int)PlayerLoopTiming.ManualUpdate)
{
ManualRunner.AddAction(action);
return;
}
var runner = runners[(int)timing]; var runner = runners[(int)timing];
if (runner == null) if (runner == null)
{ {
@@ -528,8 +541,8 @@ namespace Cysharp.Threading.Tasks
{ {
sb.AppendFormat("------{0}------", header.type.Name); sb.AppendFormat("------{0}------", header.type.Name);
sb.AppendLine(); sb.AppendLine();
if (header.subSystemList is null) if (header.subSystemList is null)
{ {
sb.AppendFormat("{0} has no subsystems!", header.ToString()); sb.AppendFormat("{0} has no subsystems!", header.ToString());
sb.AppendLine(); sb.AppendLine();
@@ -557,11 +570,11 @@ namespace Cysharp.Threading.Tasks
foreach (var header in playerLoop.subSystemList) foreach (var header in playerLoop.subSystemList)
{ {
if (header.subSystemList is null) if (header.subSystemList is null)
{ {
continue; continue;
} }
foreach (var subSystem in header.subSystemList) foreach (var subSystem in header.subSystemList)
{ {
if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization)) if (subSystem.type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))

View File

@@ -16,11 +16,14 @@ namespace Cysharp.Threading.Tasks
/// <summary>Ignore timescale, use Time.unscaledDeltaTime.</summary> /// <summary>Ignore timescale, use Time.unscaledDeltaTime.</summary>
UnscaledDeltaTime, UnscaledDeltaTime,
/// <summary>use Stopwatch.GetTimestamp().</summary> /// <summary>use Stopwatch.GetTimestamp().</summary>
Realtime Realtime,
ManualTime
} }
public partial struct UniTask public partial struct UniTask
{ {
public static float deltaTime;
public static int frameCount;
public static YieldAwaitable Yield() public static YieldAwaitable Yield()
{ {
// optimized for single continuation // optimized for single continuation
@@ -80,7 +83,7 @@ namespace Cysharp.Threading.Tasks
{ {
await Awaitable.EndOfFrameAsync(cancellationToken); 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).")] [Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static YieldAwaitable WaitForEndOfFrame() public static YieldAwaitable WaitForEndOfFrame()
{ {
@@ -92,7 +95,7 @@ namespace Cysharp.Threading.Tasks
{ {
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately); return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
} }
#endif #endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner) public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
{ {
@@ -179,6 +182,10 @@ namespace Cysharp.Threading.Tasks
switch (delayType) switch (delayType)
{ {
case DelayType.ManualTime:
{
return new UniTask(DelayManualPromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
}
case DelayType.UnscaledDeltaTime: case DelayType.UnscaledDeltaTime:
{ {
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token); return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
@@ -229,7 +236,7 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately; result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled) if (cancelImmediately && cancellationToken.CanBeCanceled)
{ {
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state => result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
@@ -320,6 +327,7 @@ namespace Cysharp.Threading.Tasks
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration; CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately; bool cancelImmediately;
PlayerLoopTiming timing = PlayerLoopTiming.Update;
NextFramePromise() NextFramePromise()
{ {
@@ -337,8 +345,9 @@ namespace Cysharp.Threading.Tasks
result = new NextFramePromise(); 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.cancellationToken = cancellationToken;
result.timing = timing;
result.cancelImmediately = cancelImmediately; result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled) if (cancelImmediately && cancellationToken.CanBeCanceled)
@@ -400,7 +409,7 @@ namespace Cysharp.Threading.Tasks
return false; return false;
} }
if (frameCount == Time.frameCount) if (frameCount == (timing == PlayerLoopTiming.ManualUpdate ? UniTask.frameCount : Time.frameCount))
{ {
return true; return true;
} }
@@ -695,6 +704,138 @@ namespace Cysharp.Threading.Tasks
} }
} }
sealed class DelayManualPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayManualPromise>
{
static TaskPool<DelayManualPromise> 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<object> core;
DelayManualPromise()
{
}
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
if (!pool.TryPop(out var result))
{
result = new DelayManualPromise();
}
result.elapsed = 0.0f;
result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds;
result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? frameCount : -1;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayManualPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
return result;
}
public void GetResult(short token)
{
try
{
core.GetResult(token);
}
finally
{
if (!(cancelImmediately && cancellationToken.IsCancellationRequested))
{
TryReturn();
}
else
{
TaskTracker.RemoveTracking(this);
}
}
}
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
core.TrySetCanceled(cancellationToken);
return false;
}
if (elapsed == 0.0f)
{
if (initialFrame == Time.frameCount)
{
return true;
}
}
elapsed += Time.deltaTime;
if (elapsed >= delayTimeSpan)
{
core.TrySetResult(null);
return false;
}
return true;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
delayTimeSpan = default;
elapsed = default;
cancellationToken = default;
cancellationTokenRegistration.Dispose();
cancelImmediately = default;
return pool.TryPush(this);
}
}
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise> sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
{ {
static TaskPool<DelayPromise> pool; static TaskPool<DelayPromise> pool;

View File

@@ -2,7 +2,7 @@
"name": "com.cysharp.unitask", "name": "com.cysharp.unitask",
"displayName": "UniTask", "displayName": "UniTask",
"author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" }, "author": { "name": "Cysharp, Inc.", "url": "https://cysharp.co.jp/en/" },
"version": "2.5.11", "version": "2.5.10",
"unity": "2018.4", "unity": "2018.4",
"description": "Provides an efficient async/await integration to Unity.", "description": "Provides an efficient async/await integration to Unity.",
"keywords": [ "async/await", "async", "Task", "UniTask" ], "keywords": [ "async/await", "async", "Task", "UniTask" ],