Skip to content

feat: add CancellationSource class attribute#185

Open
roflmuffin wants to merge 1 commit intoCat-Lips:mainfrom
roflmuffin:feature/add-cancellation-source
Open

feat: add CancellationSource class attribute#185
roflmuffin wants to merge 1 commit intoCat-Lips:mainfrom
roflmuffin:feature/add-cancellation-source

Conversation

@roflmuffin
Copy link
Copy Markdown

@roflmuffin roflmuffin commented Apr 7, 2026

This PR adds a new CancellationSource class attribute which adds an underlying public CancellationTokenSource Cts that is automatically cancelled and disposed when the node is exiting the tree. The Cts is lazily initialised and re-created when the node re-enters the tree.

I am also open to modifying this PR to use a partial property, i.e.

[CancellationSource]
public partial CancellationTokenSource Cts { get; }

It seems unlikely that you would ever need more than one cancellation token source per Node, so I've gone with the class attribute approach. With that being said I can see the benefit of flexibility of being able to name the Cts whatever you want and with whatever accessibility level.

My main use case for this attribute is when I have a VFX node that may do some long running animations or tweens, and is killed early. This lets you just pass the Cts.Token into the tweening code and allow it to gracefully handle the disposal of the node.

I'm not super experienced with source generators in general, so open to any feedback on this one.

@Cat-Lips
Copy link
Copy Markdown
Owner

I think Godot already does this when you call Node.CreateTween().

https://docs.godotengine.org/en/stable/classes/class_tween.html#class-tween-method-bind-node

Does that work for you?

@roflmuffin
Copy link
Copy Markdown
Author

That does work when I am using a basic tween, but I also have other async logic that would be nice to bind to an easily accessible cancellation token source; though I suppose this is probably something Godot themselves should expose a method for rather than having to wire this up manually?

@Cat-Lips
Copy link
Copy Markdown
Owner

Cat-Lips commented Apr 28, 2026

We could add some sort of Bind or BindTree attribute that does something similar to tween binding. It could be configured to call a function (Cancel/Close) then set to null when exiting tree, but just not sure how useful it is when one can do (in this case):

public partial class TestCTS : Node
{
    CancellationTokenSource cts => field ??= new();

    public override void _Ready()
        => TreeExiting += () => cts.Cancel();
}

I've also done something like this before, which could be changed to check if in tree instead of just is valid: https://github.com/Cat-Lips/F00F.Core/blob/ffa5b85b80213e51b4fcb366a40163f8037360de/addons/F00F.Core/Utilities/Extensions/AsyncExtensions.cs

Usage:

public partial class TestCTS : Node
{
    private CancellationTokenSource cts;
    public void DoThingAsync<T>(Action<T> OnDone)
    {
        cts?.Cancel();
        cts = this.RunAsync(DoThing, OnDone);

        static T DoThing(CancellationToken ct)
        {
            // Do long running thing, cancelling as required
            return default; // Return result
        }
    }

    public override void _Ready()
        => TreeExiting += () => cts?.Cancel();
}

PS: Happy to do, just need to vet it first :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants