Skip to content

Engine signals with Gd<T> parameters can receive null #1663

Description

@Bromeon

Signal parameters of object type are generated as Gd<T>, which is non-nullable. But Godot passes null for some of them, so
connecting a handler to such a signal can panic and isn't easily avoidable by the user.

The clearest case is EditorPlugin::scene_changed, whose scene_root is null when the last scene tab is closed:

#[godot_api]
impl IEditorPlugin for MyPlugin {
    fn enter_tree(&mut self) {
        self.signals()
            .scene_changed()
            .connect(|scene_root: Gd<Node>| {
                // Never runs -- closing the last scene tab passes null, and conversion panics before we get here.
                godot_print!("now editing {scene_root}");
            });
    }
}

EditorPlugin::resource_saved (resource: Resource) has the same problem. There are likely more.


Some ideas:

  1. Use Option<Gd<T>> everywhere.

    • Technically correct, but requires unwrap() even if object parameters are guaranteed non-null.
  2. Keep Gd<T>, add a *_nullable overload with Option<Gd<T>>, deprecating the original.

    • Can be added incrementally, as users report problems.
    • Increases API surface, deprecation churn.
    • Note: nullability is per-object, not per-signal. Needs decision on what to do for signals with multiple object parameters.
  3. Same signal uses either Gd or Option<Gd> (exclusive).

    • Hand-maintained list of affected (class, signal, parameter) triples in godot-codegen/src/special_cases.rs (but also true for other approaches).
    • Needs ahead-of-time work to find out which are nullable and which not; hard to correct later without minor version bump.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugc: engineGodot classes (nodes, resources, ...)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions