GDTask 1.2.2
dotnet add package GDTask --version 1.2.2
NuGet\Install-Package GDTask -Version 1.2.2
<PackageReference Include="GDTask" Version="1.2.2" />
paket add GDTask --version 1.2.2
#r "nuget: GDTask, 1.2.2"
// Install GDTask as a Cake Addin #addin nuget:?package=GDTask&version=1.2.2 // Install GDTask as a Cake Tool #tool nuget:?package=GDTask&version=1.2.2
GDTask.Nuget
- Ported and Tested in Godot 4.2 with .Net module.
- This is the Nuget Package version based on code from:
Table of Contents
Abstract
Clarification: Contents in the abstract section are mostly migrated from the Cysharp's UniTask library for Unity
Efficient allocation free async/await integration for Godot
- Struct-based
GDTask<T>
and custom AsyncMethodBuilder to achieve zero allocation. - Provides
awaitable
functionality for certain Engine event functions. - Runs completely on Godot PlayerLoop so doesn't use threads.
- Highly compatible behavior with Task/ValueTask/IValueTaskSource.
GDTask Under the hood
- Based on the task-like custom async method builder feature. of C# 7.0, GDTask does not use Threads, SynchronizationContext, or ExecutionContext. Instead, it dispatches the asynchronous tasks onto a standalone singleton node GDTaskPlayerLoopRunner, which results in better performance, and lower allocation.
Installation via Nuget
For .Net CLI
dotnet add package GDTask
For Package Manager Console:
NuGet\Install-Package GDTask
Basic API usage
For more detailed usage, see Unit Tests.
using GodotTasks.Tasks;
// Use GDTaskVoid if this task is only used with ApiUsage().Forget();
public async GDTask ApiUsage()
{
// Delay the execution after frame(s).
await GDTask.DelayFrame(100);
// Delay the execution after delayTimeSpan.
await GDTask.Delay(TimeSpan.FromSeconds(10), DelayType.Realtime);
// Delay the execution until the next Process.
await GDTask.Yield(PlayerLoopTiming.Process);
// Delay the execution until the next PhysicsProcess.
await GDTask.WaitForPhysicsProcess();
// Creates a task that will complete at the next provided PlayerLoopTiming when the supplied predicate evaluates to true
await GDTask.WaitUntil(() => Time.GetTimeDictFromSystem()["minute"].AsInt32() % 2 == 0);
// Creates a task that will complete at the next provided PlayerLoopTiming when the provided monitorFunction returns a different value.
await GDTask.WaitUntilValueChanged(Time.Singleton, timeInstance => timeInstance.GetTimeDictFromSystem()["minute"]);
// Creates an awaitable that asynchronously yields to ThreadPool when awaited.
await GDTask.SwitchToThreadPool();
/* Threaded work */
// Creates an awaitable that asynchronously yields back to the next Process from the main thread when awaited.
await GDTask.SwitchToMainThread();
/* Main thread work */
await GDTask.NextFrame();
// Creates a continuation that executes when the target GDTask completes.
int taskResult = await GDTask.Delay(10).ContinueWith(() => 5);
GDTask<int> task1 = GDTask.Delay(10).ContinueWith(() => 5);
GDTask<string> task2 = GDTask.Delay(20).ContinueWith(() => "Task Result");
GDTask<bool> task3 = GDTask.Delay(30).ContinueWith(() => true);
// Creates a task that will complete when all of the supplied tasks have completed.
var (task1Result, task2Result, task3Result) = await GDTask.WhenAll(task1, task2, task3);
try
{
// Creates a GDTask that has completed with the specified exception.
await GDTask.FromException(new ExpectedException());
}
catch (ExpectedException) { }
try
{
// Creates a GDTask that has completed due to cancellation with the specified cancellation token.
await GDTask.FromCanceled(CancellationToken.None);
}
catch (TaskCanceledException) { }
try
{
var source = new CancellationTokenSource();
source.CancelAfter(100);
// Creates a task that never completes, with specified CancellationToken.
await GDTask.Never(source.Token);
}
catch (TaskCanceledException) { }
// Queues the specified work to run on the ThreadPool and returns a GDTask handle for that work.
await GDTask.RunOnThreadPool(
() => GD.Print(Environment.CurrentManagedThreadId.ToString()),
configureAwait: true,
cancellationToken: CancellationToken.None
);
// Create a GDTask that wraps around this task.
await Task.Delay(5).AsGDTask(useCurrentSynchronizationContext: true);
// Associate a time out to the current GDTask.
await GDTask.Never(CancellationToken.None).Timeout(TimeSpan.FromMilliseconds(5));
var node = new Node();
((SceneTree)Engine.GetMainLoop()).Root.CallDeferred(Node.MethodName.AddChild, node);
// Creates a task that will complete when the _EnterTree() is called.
await node.OnEnterTreeAsync();
// Creates a task that will complete when the _Ready() is called.
await node.OnReadyAsync();
// Gets an instance of IAsyncProcessHandler for making repeatedly calls on OnProcessAsync().
var processTrigger = node.GetAsyncProcessTrigger();
// Creates a task that will complete when the next _Process(double) is called.
await processTrigger.OnProcessAsync();
await processTrigger.OnProcessAsync();
await processTrigger.OnProcessAsync();
await processTrigger.OnProcessAsync();
// Gets an instance of IAsyncPhysicsProcessHandler for making repeatedly calls on OnPhysicsProcessAsync().
var physicsProcessTrigger = node.GetAsyncPhysicsProcessTrigger();
await physicsProcessTrigger.OnPhysicsProcessAsync();
await physicsProcessTrigger.OnPhysicsProcessAsync();
await physicsProcessTrigger.OnPhysicsProcessAsync();
await physicsProcessTrigger.OnPhysicsProcessAsync();
node.QueueFree();
// Creates a task that will complete when the Node is receiving NotificationPredelete.
await node.OnPredeleteAsync();
}
Task Profiling
Clarification: Contents in the task profiling section are mostly migrated from the Cysharp's UniTask library for Unity
When calling TaskTracker.ShowTrackerWindow()
in your code base, the GDTask system will create(or reuse) a GDTask Tracker
window for inspecting/diagnosing (leaked) GDTasks
.
Name | Description |
---|---|
Enable Tracking | Enable the tracking system for collecting status for future started GDTasks , this is on by default when calling TaskTracker.ShowTrackerWindow() , you may also alter this value through TaskTracker.EnableTracking . |
Enable StackTrace | Records and show stack traces for the active GDTasks , you may also alter this value through TaskTracker.EnableStackTrace . |
GC Collect | Invokes GC.Collect() manually. |
- Do keep in mind this feature is for debugging purposes and it has performance penalties, so stay cautious when calling
TaskTracker.ShowTrackerWindow()
under the production environment.- The background status collection system does not start if you have never called
TaskTracker.ShowTrackerWindow()
.- Closing an active
GDTask Tracker
window does not stop the background status collection system, remember to toggle offEnable Tracking
or setTaskTracker.EnableTracking
tofalse
in your code.- Godot Games embeds sub-windows by default, you can disable the
Embed Subwindows
option located inProjectSettings (Advanced Settings enabled)Display/Window/Subwindows/Embed Subwindows
for them to become Standalone Windows.- This window reacts to the
window closing command
(NotificationWMCloseRequest
) correctly so it closes itself when you click the close button, to relaunch this window simply callTaskTracker.ShowTrackerWindow()
again.
Compare with Standard .Net Task API
Clarification: Contents in the compare section are mostly migrated from the Cysharp's UniTask library for Unity
Same as the Standard .Net Task APIs
, CancellationToken
and CancellationTokenSource
are widely used by the GDTask APIs as well.<br>
Otherwise, the following table shows the GDTask APIs provided that are meant to replace the usage of standard .Net Task APIs.
.NET Type | GDTask Type |
---|---|
Task /ValueTask |
GDTask |
Task<T> /ValueTask<T> |
GDTask<T> |
async void |
async GDTaskVoid |
+= async () => { } |
GDTask.Void , GDTask.Action |
--- | GDTaskCompletionSource |
TaskCompletionSource<T> |
GDTaskCompletionSource<T> /AutoResetGDTaskCompletionSource<T> |
ManualResetValueTaskSourceCore<T> |
GDTaskCompletionSourceCore<T> |
IValueTaskSource |
IGDTaskSource |
IValueTaskSource<T> |
IGDTaskSource<T> |
ValueTask.IsCompleted |
GDTask.Status.IsCompleted() |
ValueTask<T>.IsCompleted |
GDTask<T>.Status.IsCompleted() |
CancellationToken.Register(UnsafeRegister) |
CancellationToken.RegisterWithoutCaptureExecutionContext |
CancellationTokenSource.CancelAfter |
CancellationTokenSource.CancelAfterSlim |
Task.Delay |
GDTask.Delay |
Task.Yield |
GDTask.Yield |
Task.Run |
GDTask.RunOnThreadPool |
Task.WhenAll |
GDTask.WhenAll |
Task.WhenAny |
GDTask.WhenAny |
Task.CompletedTask |
GDTask.CompletedTask |
Task.FromException |
GDTask.FromException |
Task.FromResult |
GDTask.FromResult |
Task.FromCanceled |
GDTask.FromCanceled |
Task.ContinueWith |
GDTask.ContinueWith |
TaskScheduler.UnobservedTaskException |
GDTaskExceptionHandler.UnobservedTaskException |
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Godot.SourceGenerators (>= 4.1.0)
- GodotSharp (>= 4.1.0)
-
net7.0
- Godot.SourceGenerators (>= 4.1.0)
- GodotSharp (>= 4.1.0)
-
net8.0
- Godot.SourceGenerators (>= 4.1.0)
- GodotSharp (>= 4.1.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on GDTask:
Package | Downloads |
---|---|
BenchmarkDotNetGodot
BenchmarkDotNet.Godot allows developers to easily conduct performance testing and benchmarking within the Godot engine, enabling them to assess the efficiency of their code and identify potential performance bottlenecks. |
|
BenchmarkDotNetGodot.GDTask
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
Remove unused Awake/EnterTreeMonitor, and adds extra checks to make sure calling GDTask APIs under editor environment throws an Exception instead of crashing the editor.