Skip to content

Gd::default_instance bypasses placeholder instances #1404

@TitanNano

Description

@TitanNano

Godot 4.3 introduced a runtime class system, and any gdext classes that are not marked as class(tool) are registered as runtime classes since 4.3. This system allows the engine to create placeholder instances for classes that are not supposed to be executed in the editor.

Our Gd::new_alloc and Gd::new_gd functions that are used to create new Godot class instances from inside Rust both call Gd::default_instance. That function in turn directly calls the extension's create_instance function. The entire placeholder logic on the other hand is handled in ClassDB::_instantiate_internal. This means all instances created from inside Rust skip the placeholder instance logic of ClassDB and never create a placeholder instance.

Effectively this means that runtime classes can accidentally be instantiated and executed by custom editor code / plugins or class(tool) classes, which is not expected by users.

Example by @Yarwin in #1399 (comment)
#[derive(GodotClass)]
#[class(init, base = Node)]
struct NonToolNode {}

#[godot_api]
impl INode for NonToolNode {
    fn ready(&mut self) {
        godot_print!("Hello from editor :)");
    }
}

#[derive(GodotClass)]
#[class(init, tool, base = Node)]
struct MyClass {
    base: Base<Node>,
}

#[godot_api]
impl INode for MyClass {
    fn ready(&mut self) {
        let mut non_tool_node = NonToolNode::new_alloc();
        self.base_mut().add_child(&non_tool_node);
        non_tool_node.set_owner(self.base().get_owner().as_ref());
    }
}

screenshot

Functions from NonToolNode should not be executed in an editor context.


This was identified in PR #1399 while implementing automatic singleton registration. For singletons, this currently means that they can never be instantiated as placeholders, which could lead to unexpected behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions