Godot Version
4.7.stable.mono
TL;DR Question
A [Tool] Node using a [Tool] Resource (created by following docs) creates a new hanging connection in Editor (no such issue in Game, due to cleanup in _ExitTree()) on each rebuild. How should I disconnect it?
Or maybe a better question is how do I make a node that reacts to resource changes in-editor (like some built-in nodes react to texture resource changes in editor), without having this issue with signals/connections?
In detail
In my game I’ve created a [Tool] node which changes, when a [Tool] resource changes. To do that I’ve followed a section from docs. I’ve noticed I was getting an increasing amount of System.NullReferenceException in editor errors on each rebuild. I investigated and found that each rebuild created a new hanging connection, which is confirmed by logging GetIncomingConnections().Count.
I’ve created a new project with just those elements to isolate the issue.
ToolResource.cs
using System;
using Godot;
[Tool]
[GlobalClass]
public partial class ToolResource : Resource
{
private int _value;
[Export]
public int Value
{
get => _value;
set
{
_value = value;
EmitChanged();
}
}
}
ToolNode.cs
using System;
using Godot;
[Tool]
public partial class ToolNode : CsgBox3D
{
private ToolResource _resource;
[Export]
public ToolResource Resource
{
get => _resource;
set
{
if (_resource != null)
{
_resource.Changed -= OnResourceChanged;
GD.Print($"-- {GetIncomingConnections().Count}");
}
_resource = value;
if (_resource != null)
{
_resource.Changed += OnResourceChanged;
GD.Print($"++ {GetIncomingConnections().Count}");
OnResourceChanged();
}
}
}
private void OnResourceChanged()
{
Scale = new Vector3(_resource.Value, _resource.Value, _resource.Value);
GD.Print($"== {GetIncomingConnections().Count}");
}
public override void _ExitTree()
{
if (_resource != null)
{
_resource.Changed -= OnResourceChanged;
GD.Print($"-- {GetIncomingConnections().Count}");
}
base._ExitTree();
}
}
As I’ve said, in-game the amount of connections is as expected:
++ 1
== 1
-- 0
While in-editor I get an increasing amount of errors and an increasing logged amount of connections:
++ 6
== 6
Attempted solutions
Disconnecting all incoming connections in the property setter
private void DisconnectIncomingConnections()
{
foreach (Godot.Collections.Dictionary connection in GetIncomingConnections())
{
Signal signal = connection["signal"].As<Signal>();
Callable callable = connection["callable"].As<Callable>();
signal.Owner.Disconnect(signal.Name, callable);
}
}
Returns an error for each of those connections: ERROR: Attempt to disconnect a nonexistent connection from '<Resource#-9223370292259120180>'. Signal: 'changed', callable: 'Delegate::Invoke'.
Using Connect() and Disconnect(), instead of += and -=
In this docs article it says that Connect() disconnects automatically, so I tried using it:
// _resource.Changed += OnResourceChanged;
_resource.Connect(
ToolResource.SignalName.Changed,
Callable.From(OnResourceChanged)
);
No noticeable difference, unfortunately. Number of connections in-editor continues to increase.