Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for statically typed signals in C# #3471

Closed
lfshr opened this issue Oct 27, 2021 · 5 comments
Closed

Add support for statically typed signals in C# #3471

lfshr opened this issue Oct 27, 2021 · 5 comments

Comments

@lfshr
Copy link

lfshr commented Oct 27, 2021

Describe the project you are working on

MMO style game

Describe the problem or limitation you are having in your project

Currently the only method of sending/receiving signals is pass magic strings to the SceneTree.Connect method. This achieves the purpose of decoupling game objects from each other, but loses some of the compile time assurances that a strict language like C# gives you.

I propose an abstraction layer be created around the SceneTree.Connect method that keeps the current implementation but adds the ability to create compile-time assured signals.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Open to other ideas here, just firing one out:

Rather than calling SceneTree.Connect, a node can declare that it receives a signal via the IReceiveSignal<TSignal> interface. This creates a contract that can be reflected upon on node instantiation and the underpinning SceneTree.Connect calls can be called at this time. This way the node does not use magic strings. If the class name ever changes, or features are removed from the signal message, a compilation error would occur.

Naming convention is a big contributor here, MySignal would be (by convention) "my_signal".

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

public class MySignal
{
	int Property1 { get; }
	int Property2 { get; }

    public MySignal(int property1, int property2)
    {
        Property1 = property1;
        Property2 = property2;
    }
}

public class MyOtherSignal
{

}

public class Player : Area2D, IReceiveSignal<MySignal>, IReceiveSignal<MyOtherSignal>
{
	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
                // emit signals by supplying the message type
		EmitSignal(new MySignal(10, 10));
	}

    // binds to my_signal
    public void OnSignal(MySignal message)
    {
        // do stuff		
    }

    // binds to my_other_signal
    public void OnSignal(MyOtherSignal message)
    {
        // do stuff
    }
}

If this enhancement will not be used often, can it be worked around with a few lines of script?

Not to my knowledge

Is there a reason why this should be core and not an add-on in the asset library?

Too low level

@Calinou
Copy link
Member

Calinou commented Oct 27, 2021

Signals are first-class in Godot 4.0, which means there's a Signal type and strings are no longer used for signal connections in GDScript. However, I don't know if this was translated to C# yet.

@Calinou Calinou changed the title Support strongly typed Signals (C#) Add support for statically typed signals in C# Oct 27, 2021
@AaronRecord
Copy link

Signals are first-class in Godot 4.0, which means there's a Signal type and strings are no longer used for signal connections in GDScript. However, I don't know if this was translated to C# yet.

See godotengine/godot#54333 (I opened a new issue since I couldn't find a duplicate)
and #2557

@raulsntos
Copy link
Member

In Godot 4.0, signals are now C# events so:

class MyNode : Node
{
	delegate void TextChangedHandler(string text);
	[Signal] event TextChangedHandler TextChanged;
}

You don't need to define a delegate, can also use System.Action.

To subscribe to the event, just like with any other C# event:

void Foo()
{
	TextChanged += MyCallback;
}

void MyCallback(string text)
{
	// Do something with text
}

Since it's a C# event it won't compile if the MyCallback method doesn't have the right parameters.

As for emitting the signal, I believe the intention is to be able to use Invoke like you do with normal C# events, but currently I think that's still not implemented and you still have to use EmitSignal like so:

EmitSignal(nameof(TextChanged), "some text");

You can read more about it in the Godot blog that announced this and godotengine/godot#15558.

@lfshr
Copy link
Author

lfshr commented Oct 28, 2021

In Godot 4.0, signals are now C# events so:

class MyNode : Node
{
	delegate void TextChangedHandler(string text);
	[Signal] event TextChangedHandler TextChanged;
}

You don't need to define a delegate, can also use System.Action.

To subscribe to the event, just like with any other C# event:

void Foo()
{
	TextChanged += MyCallback;
}

void MyCallback(string text)
{
	// Do something with text
}

Since it's a C# event it won't compile if the MyCallback method doesn't have the right parameters.

As for emitting the signal, I believe the intention is to be able to use Invoke like you do with normal C# events, but currently I think that's still not implemented and you still have to use EmitSignal like so:

EmitSignal(nameof(TextChanged), "some text");

You can read more about it in the Godot blog that announced this and godotengine/godot#15558.

That's absolutely awesome! Great work! Going to close this issue off then since it's already implemented. Is there an issue open to track the emitting?

@lfshr lfshr closed this as completed Oct 28, 2021
@raulsntos
Copy link
Member

Is there an issue open to track the emitting?

None that I'm aware of.

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

No branches or pull requests

4 participants