godot::register

Attribute Macro 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(val = ...)].

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

    #[init(val = 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 {
        GString::from("Rust")
    }
}

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.

§RPC attributes

You can use the #[rpc] attribute to let your functions act as remote procedure calls (RPCs) in Godot. This is the Rust equivalent of GDScript’s @rpc annotation. #[rpc] is only supported for classes inheriting Node, and they need to declare a Base<T> field.

The syntax follows GDScript’a @rpc. You can optionally specify up to four keys; omitted ones use their default value. Here’s an overview:

SettingTypePossible values (first is default)
RPC modeRpcModeauthority, any_peer
Syncboolcall_remote, call_local
Transfer modeTransferModeunreliable, unreliable_ordered, reliable
Channelu32any

You can also use #[rpc(config = value)], with value being an expression of type RpcConfig in scope, for example a const or the call to a function. This can be useful to reuse configurations across multiple RPCs.

#[rpc] implies #[func]. You can use both attributes together, if you need to configure other #[func]-specific keys.

For example, the following method declarations are all equivalent:

use godot::classes::multiplayer_api::RpcMode;
use godot::classes::multiplayer_peer::TransferMode;
use godot::prelude::*;
use godot::register::RpcConfig;

#[godot_api]
impl MyStruct {
    #[rpc(unreliable_ordered, channel = 2)]
    fn with_defaults(&mut self) {}

    #[rpc(authority, unreliable_ordered, call_remote, channel = 2)]
    fn explicit(&mut self) {}

    #[rpc(config = MY_RPC_CONFIG)]
    fn external_config_const(&mut self) {}

    #[rpc(config = my_rpc_provider())]
    fn external_config_fn(&mut self) {}
}

const MY_RPC_CONFIG: RpcConfig = RpcConfig {
    rpc_mode: RpcMode::AUTHORITY,
    transfer_mode: TransferMode::UNRELIABLE_ORDERED,
    call_local: false,
    channel: 2,
};

fn my_rpc_provider() -> RpcConfig {
    RpcConfig {
        transfer_mode: TransferMode::UNRELIABLE_ORDERED,
        channel: 2,
        ..Default::default() // only possible in fn, not in const.
    }
}

§Constants and signals

Please refer to the book.

§Multiple inherent impl blocks

Just like with regular structs, you can have multiple inherent impl blocks. This can be useful for code organization or when you want to generate code from a proc-macro. For implementation reasons, all but one impl blocks must have the key secondary. There is no difference between implementing all functions in one block or splitting them up between multiple blocks.

#[godot_api]
impl MyStruct {
    #[func]
    pub fn one(&self) { }
}

#[godot_api(secondary)]
impl MyStruct {
    #[func]
    pub fn two(&self) { }
}