Compare commits

...

7 Commits

Author SHA1 Message Date
weicai995
5157d78be8 Merge 9c4bab6e0a into 98538ef7c7 2025-09-13 01:24:48 +09:00
Ikiru Yoshizaki
98538ef7c7 Merge pull request #677 from Cysharp/feature/docs
ci: replace docfx build from container to docfx command
2025-09-13 01:23:03 +09:00
Ikiru Yoshizaki
519590ca6e chore: exclude tests assemblies 2025-09-10 18:38:31 +09:00
Ikiru Yoshizaki
dce4366f3e ci: change docfx target from source code to Unity built assemblies 2025-09-10 18:20:17 +09:00
Ikiru Yoshizaki
88026ab14a ci: replace docfx build from container to docfx command 2025-09-10 17:20:43 +09:00
Ikiru Yoshizaki
95998ff3f2 ci: dependabot cooldown 65d2ae 2025-09-10 12:34:40 +09:00
weicai995
9c4bab6e0a Add Manual Update 2025-07-04 17:39:35 +08:00
7 changed files with 225 additions and 25 deletions

13
.config/dotnet-tools.json Normal file
View File

@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"docfx": {
"version": "2.78.3",
"commands": [
"docfx"
],
"rollForward": false
}
}
}

View File

@@ -5,8 +5,10 @@ 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
cooldown:
default-days: 14 # Wait 14 days before creating another PR for the same dependency. This will prevent vulnerability on the package impact.
ignore: ignore:
# I just want update action when major/minor version is updated. patch updates are too noisy. # I just want update action when major/minor version is updated. patch updates are too noisy.
- dependency-name: '*' - dependency-name: "*"
update-types: update-types:
- version-update:semver-patch - version-update:semver-patch

View File

@@ -8,25 +8,49 @@ on:
jobs: jobs:
run-docfx: run-docfx:
if: ${{ ((github.event_name == 'push' && github.repository_owner == 'Cysharp') || startsWith(github.event.pull_request.head.label, 'Cysharp:')) && github.triggering_actor != 'dependabot[bot]' }}
permissions: permissions:
contents: write contents: write
pages: write pages: write
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- name: Load secrets
id: op-load-secret
uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 # v2.0.0
with:
export-env: false
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN_PUBLIC }}
UNITY_EMAIL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/username"
UNITY_PASSWORD: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/credential"
UNITY_SERIAL: "op://${{ vars.OP_VAULT_ACTIONS_PUBLIC }}/UNITY_LICENSE/serial"
- uses: Cysharp/Actions/.github/actions/checkout@main - uses: Cysharp/Actions/.github/actions/checkout@main
# Execute scripts: Export Package
# /opt/Unity/Editor/Unity -quit -batchmode -nographics -silent-crashes -logFile -projectPath . -executeMethod PackageExporter.Export
- name: Build Unity (.unitypackage)
uses: Cysharp/Actions/.github/actions/unity-builder@main
env:
UNITY_EMAIL: ${{ steps.op-load-secret.outputs.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ steps.op-load-secret.outputs.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ steps.op-load-secret.outputs.UNITY_SERIAL }}
with:
projectPath: src/UniTask
unityVersion: "2022.3.39f1"
targetPlatform: StandaloneLinux64
buildMethod: PackageExporter.Export
- uses: Cysharp/Actions/.github/actions/checkout@main - uses: Cysharp/Actions/.github/actions/checkout@main
with: with:
repository: Cysharp/DocfxTemplate repository: Cysharp/DocfxTemplate
path: docs/_DocfxTemplate path: docs/_DocfxTemplate
- uses: Kirbyrawr/docfx-action@db9a22c8fe1e8693a2a21be54cb0b87dfaa72cc4 - uses: Cysharp/Actions/.github/actions/setup-dotnet@main
name: Docfx metadata - name: dotnet tool restore
with: run: dotnet tool restore
args: metadata docs/docfx.json - name: Docfx metadata
- uses: Kirbyrawr/docfx-action@db9a22c8fe1e8693a2a21be54cb0b87dfaa72cc4 run: dotnet docfx metadata docs/docfx.json
name: Docfx build - name: Docfx build
with: run: dotnet docfx build docs/docfx.json
args: build docs/docfx.json
- name: Publish to GitHub Pages - name: Publish to GitHub Pages
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
with: with:

View File

@@ -4,7 +4,11 @@
"src": [ "src": [
{ {
"files": [ "files": [
"UniTask/Assets/Plugins/UniTask/Runtime/**/*.cs" "UniTask/Library/ScriptAssemblies/UniTask*.dll"
],
"exclude": [
"UniTask/Library/ScriptAssemblies/UniTask.Tests.dll",
"UniTask/Library/ScriptAssemblies/UniTask.Tests.Editor.dll"
], ],
"src": "../src" "src": "../src"
} }
@@ -54,7 +58,6 @@
} }
], ],
"dest": "_site", "dest": "_site",
"globalMetadataFiles": [], "globalMetadataFiles": [],
"fileMetadataFiles": [], "fileMetadataFiles": [],
"template": [ "template": [
@@ -67,4 +70,4 @@
"keepFileLink": false, "keepFileLink": false,
"cleanupCacheHistory": false "cleanupCacheHistory": false
} }
} }

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;