Hi all, I'm trying to use a custom signal in C# but I'm having some problems.

I have a class NoteHandler that defines a signal ShowNote. It looks like this:

public partial class NoteHandler : Node2D
{
    [Signal]
    public delegate void ShowNoteEventHandler(int input, double time);
}

And in my Player class, I want to Emit it with this line:

EmitSignal(NoteHandler.SignalName.ShowNote, 1, 1.0);

But I'm getting the error Can't emit non-existing signal "ShowNote" ... Condition "!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name)" is true. Returning: ERR_UNAVAILABLE meaning that the signal isn't properly defined. I've logged all the signals from both NoteHandler and Player, and NoteHandler by using this.GetSignalList and NoteHandler.GetGodotSignalList respectively, and NoteHandler does properly print out ShowNote, while Player does not. I assume this is some sort of access problem?

I've tried adding this method to NoteHandlers as well:

public void EmitShowNote(int input,  double time)
{
    this.EmitSignal(SignalName.ShowNote, input, time);
}

and emitting the signal by doing

NoteHandler noteHandler = new NoteHandler();
noteHandler.EmitShowNote(1, 1.0);

And although this does not throw an error, nothing happens despite me defining a callback on NoteHandler to just print its arguments. They are in the same scene as well, so I am confused about what is going on. Any help is much appreciated, thanks!

  • That's just a constant of the signal name from what I understand, so it doesn't have any effect on whether your node has the signal defined (imagine you just put the signal name as a string "ShowNote", that wouldn't define the signal). The signal still needs to exist on the node that you're calling EmitSignal on. If you want to keep the classes separate, I think you would want to get an instance of NoteHandler from the scene (that is inside the tree), and call myInstance.EmitSignal(NoteHandler.SignalName.ShowNote, 1, 1.0)

I haven't used 4.0 much yet but it seems to me that you only defined the signal on the NoteHandler class, and since Player doesn't derive from NoteHandler (I'm assuming), it doesn't have the signal defined on the player node.

    dogboydog I'm accessing NoteHandler's SignalName though, not Player's, so shouldn't it be accessible from there?

    That's just a constant of the signal name from what I understand, so it doesn't have any effect on whether your node has the signal defined (imagine you just put the signal name as a string "ShowNote", that wouldn't define the signal). The signal still needs to exist on the node that you're calling EmitSignal on. If you want to keep the classes separate, I think you would want to get an instance of NoteHandler from the scene (that is inside the tree), and call myInstance.EmitSignal(NoteHandler.SignalName.ShowNote, 1, 1.0)

      Okay I got it working by accessing the NoteHandler Node on the scene and storing it in player with

      this.noteHandler = this.GetParent().GetNode<NoteHandler>("note_handler");

      and then calling EmitSignal on that. I guess it makes sense why I have to do this, but it is still confusing that the signal is an instance type / variable instead of being static / accessible outside of NoteHandler, especially since SignalName isn't even accessible from this in NoteHandler. I'll keep this up in case anyone else ever has this same question, and if anyone wanted to explain any further, I would appreciate it a lot!

        dogboydog That's just a constant of the signal name from what I understand, so it doesn't have any effect on whether your node has the signal defined (imagine you just put the signal name as a string "ShowNote", that wouldn't define the signal). The signal still needs to exist on the node that you're calling EmitSignal on. If you want to keep the classes separate, I think you would want to get an instance of NoteHandler (that is inside the tree) from the scene , and call myInstance.EmitSignal(NoteHandler.SignalName.ShowNote, 1, 1.0)

        declspecl

        SignalName is a static field, so it wouldn't be available on "this" which refers to an instance. If you wrote just SignalName from inside NoteHandler I think it would work. I think your misunderstanding is that you think just accessing this static field will define the signal somehow or route it to the right object, but it's just a string giving you the signal name, it doesn't do anything to actually set up the signal. Furthermore you could have any number of NoteHandler objects in the scene that all could emit their own ShowNote signal, so it wouldn't know which instance to use unless you do what you ended up doing

        dogboydog That makes sense about it just being the constant of the signal name, and I assume creating an instance by doing new NoteHandler() doesnt work because _Ready is never called on it since it is never actually added to the SceneTree. Thanks!

        EmitSignal should be called as a method of an object that emits the signal. If you call this.EmitSignal from the player class it means that you want player object to emit the signal. This raises the 'non existing signal' error since this signal is not defined in the player class. So what @dogboydog said - you'll need an instance of NoteHandler to properly call EmitSignal

        6 months later

        Sorry if it is too late.
        I already have this issue and by reading the error, it has to add a user signal first.

        public override void _Ready()
        {
            ...
            AddUserSignal(SignalName.ShowNote);
            ...
        }

        something like this, it solved my problem.