Attribute Macro godot::register::godot_api

#[godot_api]
Expand description

Proc-macro attribute to be used with impl blocks of #[derive(GodotClass)] structs.

Can be used in two ways:

#[derive(GodotClass)]
#[class(init, base=Node)]
struct MyClass {}

// 1) inherent impl block: user-defined, custom API.
#[godot_api]
impl MyClass { /* ... */ }

// 2) trait impl block: implement Godot-specific APIs.
#[godot_api]
impl INode for MyClass { /* ... */ }

The second case works by implementing the corresponding trait I* for the base class of your class (for example IRefCounted or INode3D). Then, you can add functionality such as:

  • init constructors
  • lifecycle methods like ready or process
  • on_notification method
  • to_string method

Neither of the two #[godot_api] blocks is required. For small data bundles inheriting RefCounted, you may be fine with accessing properties directly from GDScript.

See also book chapter Registering functions and following.

Table of contents

§Constructors

Note that init (the Godot default constructor) can be either provided by overriding it, or generated with a #[class(init)] attribute on the struct. Classes without init cannot be instantiated from GDScript.

§User-defined init

#[derive(GodotClass)]
// no #[class(init)] here, since init() is overridden below.
// #[class(base=RefCounted)] is implied if no base is specified.
struct MyStruct;

#[godot_api]
impl IRefCounted for MyStruct {
    fn init(_base: Base<RefCounted>) -> Self {
        MyStruct
    }
}

§Generated init

This initializes the Base<T> field, and every other field with either Default::default() or the value specified in #[init(default = ...)].

#[derive(GodotClass)]
#[class(init, base=Node)]
pub struct MyNode {
    base: Base<Node>,

    #[init(default = 42)]
    some_integer: i64,
}

§Lifecycle functions

You can override the lifecycle functions ready, process, physics_process and so on, by implementing the trait corresponding to the base class.

#[derive(GodotClass)]
#[class(init, base=Node)]
pub struct MyNode;

#[godot_api]
impl INode for MyNode {
    fn ready(&mut self) {
        godot_print!("Hello World!");
    }
}

Using any trait other than the one corresponding with the base class will result in compilation failure.

#[derive(GodotClass)]
#[class(init, base=Node3D)]
pub struct My3DNode;

#[godot_api]
impl INode for My3DNode {
    fn ready(&mut self) {
        godot_print!("Hello World!");
    }
}

§User-defined functions

You can use the #[func] attribute to declare your own functions. These are exposed to Godot and callable from GDScript.

§Associated functions and methods

If #[func] functions are called from the engine, they implicitly bind the surrounding Gd<T> pointer: Gd::bind() in case of &self, Gd::bind_mut() in case of &mut self. To avoid that, use #[func(gd_self)], which requires an explicit first argument of type Gd<T>.

Functions without a receiver become static functions in Godot. They can be called from GDScript using MyStruct.static_function(). If they return Gd<Self>, they are effectively constructors that allow taking arguments.

#[derive(GodotClass)]
#[class(init)]
struct MyStruct {
    field: i64,
    base: Base<RefCounted>,
}

#[godot_api]
impl MyStruct {
    #[func]
    pub fn hello_world(&mut self) {
        godot_print!("Hello World!")
    }

    #[func]
    pub fn static_function(constructor_arg: i64) -> Gd<Self> {
        Gd::from_init_fn(|base| {
           MyStruct { field: constructor_arg, base }
        })
    }

    #[func(gd_self)]
    pub fn explicit_receiver(mut this: Gd<Self>, other_arg: bool) {
        // Only bind Gd pointer if needed.
        if other_arg {
            this.bind_mut().field = 55;
        }
    }
}

§Virtual methods

Functions with the #[func(virtual)] attribute are virtual functions, meaning attached scripts can override them.

#[derive(GodotClass)]
#[class(init)]
struct MyStruct {
    // Virtual functions require base object.
    base: Base<RefCounted>,
}

#[godot_api]
impl MyStruct {
    #[func(virtual)]
    fn language(&self) -> GString {
        "Rust".into()
    }
}

In GDScript, your method is available with a _ prefix, following Godot convention for virtual methods:

extends MyStruct

func _language():
   return "GDScript"

Now, obj.language() from Rust will dynamically dispatch the call.

Make sure you understand the limitations in the tutorial.

§Constants and signals

Please refer to the book.