GDTask 0.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package GDTask --version 0.0.1                
NuGet\Install-Package GDTask -Version 0.0.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GDTask" Version="0.0.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add GDTask --version 0.0.1                
#r "nuget: GDTask, 0.0.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install GDTask as a Cake Addin
#addin nuget:?package=GDTask&version=0.0.1

// Install GDTask as a Cake Tool
#tool nuget:?package=GDTask&version=0.0.1                

GDTask.Nuget

Abstract

Clarification: Contents in the abstract section is 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.
  • PlayerLoop based task(GDTask.Yield, GDTask.Delay, GDT~~~~ask.DelayFrame, etc..).
  • Provides awaitable functionality for certain Engine event functions.
  • Runs completely on Godot PlayerLoop so doesn't use threads.
  • Highly compatible behaviour with Task/ValueTask/IValueTaskSource.

GDTask Under the hood

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();
}

Compare with Standard .Net Task API

Clarification: Contents in the compare section is 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.

Version Downloads Last updated
1.2.2 306 3/29/2024
1.2.1 119 3/28/2024
1.2.0 129 2/27/2024
1.1.0 122 2/26/2024
1.0.0 123 2/22/2024
0.0.3 350 2/2/2024
0.0.2 121 1/29/2024
0.0.1 114 1/28/2024

The initial release of the GDTask nuget package.