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: "/"
schedule:
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:
# I just want update action when major/minor version is updated. patch updates are too noisy.
- dependency-name: '*'
- dependency-name: "*"
update-types:
- version-update:semver-patch

View File

@@ -8,25 +8,49 @@ on:
jobs:
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:
contents: write
pages: write
runs-on: ubuntu-24.04
timeout-minutes: 10
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
# 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
with:
repository: Cysharp/DocfxTemplate
path: docs/_DocfxTemplate
- uses: Kirbyrawr/docfx-action@db9a22c8fe1e8693a2a21be54cb0b87dfaa72cc4
name: Docfx metadata
with:
args: metadata docs/docfx.json
- uses: Kirbyrawr/docfx-action@db9a22c8fe1e8693a2a21be54cb0b87dfaa72cc4
name: Docfx build
with:
args: build docs/docfx.json
- uses: Cysharp/Actions/.github/actions/setup-dotnet@main
- name: dotnet tool restore
run: dotnet tool restore
- name: Docfx metadata
run: dotnet docfx metadata docs/docfx.json
- name: Docfx build
run: dotnet docfx build docs/docfx.json
- name: Publish to GitHub Pages
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
with:

View File

@@ -4,7 +4,11 @@
"src": [
{
"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"
}
@@ -54,7 +58,6 @@
}
],
"dest": "_site",
"globalMetadataFiles": [],
"fileMetadataFiles": [],
"template": [
@@ -67,4 +70,4 @@
"keepFileLink": false,
"cleanupCacheHistory": false
}
}
}

View File

@@ -118,6 +118,9 @@ namespace Cysharp.Threading.Tasks.Internal
case PlayerLoopTiming.LastPostLateUpdate:
LastPostLateUpdate();
break;
case PlayerLoopTiming.ManualUpdate:
ManualUpdate();
break;
#if UNITY_2020_2_OR_NEWER
case PlayerLoopTiming.TimeUpdate:
TimeUpdate();
@@ -148,6 +151,7 @@ namespace Cysharp.Threading.Tasks.Internal
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 @@ namespace Cysharp.Threading.Tasks.Internal
}
else
{
continue; // next i
continue; // next i
}
}
catch (Exception ex)

View File

@@ -96,6 +96,7 @@ namespace Cysharp.Threading.Tasks
TimeUpdate = 14,
LastTimeUpdate = 15,
#endif
ManualUpdate = 16,
}
[Flags]
@@ -192,6 +193,7 @@ namespace Cysharp.Threading.Tasks
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 @@ namespace Cysharp.Threading.Tasks
return dest;
}
public static void ManualUpdate()
{
ManualRunner.Run();
}
static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
{
@@ -302,7 +308,7 @@ namespace Cysharp.Threading.Tasks
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 @@ namespace Cysharp.Threading.Tasks
runners = new PlayerLoopRunner[14];
#endif
ManualRunner = new PlayerLoopRunner(PlayerLoopTiming.ManualUpdate);
var copyList = playerLoop.subSystemList.ToArray();
// Initialization
@@ -491,6 +499,11 @@ namespace Cysharp.Threading.Tasks
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 @@ namespace Cysharp.Threading.Tasks
{
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 @@ namespace Cysharp.Threading.Tasks
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))

View File

@@ -16,11 +16,14 @@ namespace Cysharp.Threading.Tasks
/// <summary>Ignore timescale, use Time.unscaledDeltaTime.</summary>
UnscaledDeltaTime,
/// <summary>use Stopwatch.GetTimestamp().</summary>
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 @@ namespace Cysharp.Threading.Tasks
{
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 @@ namespace Cysharp.Threading.Tasks
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
}
#endif
#endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
{
@@ -179,6 +182,10 @@ namespace Cysharp.Threading.Tasks
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 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken;
result.cancelImmediately = cancelImmediately;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
@@ -320,6 +327,7 @@ namespace Cysharp.Threading.Tasks
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
bool cancelImmediately;
PlayerLoopTiming timing = PlayerLoopTiming.Update;
NextFramePromise()
{
@@ -337,8 +345,9 @@ namespace Cysharp.Threading.Tasks
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 @@ namespace Cysharp.Threading.Tasks
return false;
}
if (frameCount == Time.frameCount)
if (frameCount == (timing == PlayerLoopTiming.ManualUpdate ? UniTask.frameCount : Time.frameCount))
{
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>
{
static TaskPool<DelayPromise> pool;