Derive Macro godot::prelude::GodotClass

#[derive(GodotClass)]
{
    // Attributes available to this derive:
    #[class]
    #[base]
    #[var]
    #[export]
    #[init]
    #[signal]
}
Expand description

Derive macro for the GodotClass trait on structs.

You must use this macro; manual implementations of the GodotClass trait are not supported.

Construction

To generate a constructor that will let you call MyStruct.new() from GDScript, annotate your struct with #[class(init)]:

#[derive(GodotClass)]
#[class(init)]
struct MyStruct {
    // ...
}

The generated init function will initialize each struct field (except the field annotated with #[base], if any) using Default::default(). To assign some other value, annotate the field with #[init(default = ...)]:

#[derive(GodotClass)]
#[class(init)]
struct MyStruct {
    #[init(default = 42)]
    my_field: i64
}

The given value can be any Rust expression that can be evaluated in the scope where you write the attribute. However, due to limitations in the parser, some complex expressions must be surrounded by parentheses. This is the case if the expression includes a , that is not inside any pair of (...), [...] or {...} (even if it is, for example, inside <...> or |...|). A contrived example:

    #[init(default = (HashMap::<i64, i64>::new()))]
    //                             ^ parentheses needed due to this comma

Inheritance

Unlike C++, Rust doesn’t really have inheritance, but the GDExtension API lets us “inherit” from a built-in engine class.

By default, classes created with this library inherit from RefCounted.

To specify a different class to inherit from, add #[class(base = Base)] as an annotation on your struct:

use godot::prelude::*;

#[derive(GodotClass)]
#[class(base = Node2D)]
struct MyStruct {
    // ...
}

If you need a reference to the base class, you can add a field of type Gd<Base> and annotate it with #[base]:

use godot::prelude::*;

#[derive(GodotClass)]
#[class(base = Node2D)]
struct MyStruct {
    #[base]
    base: Base<Node2D>,
}

Properties and exports

In GDScript, there is a distinction between properties (fields with a get or set declaration) and exports (fields annotated with @export). In the GDExtension API, these two concepts are represented with #[var] and #[export] attributes respectively.

To create a property, you can use the #[var] annotation:

use godot::prelude::*;

#[derive(GodotClass)]
struct MyStruct {
    #[var]
    my_field: i64,
}

This makes the field accessible in GDScript using my_struct.my_field syntax. Additionally, it generates a trivial getter and setter named get_my_field and set_my_field, respectively. These are pub in Rust, since they’re exposed from GDScript anyway.

If you want to implement your own getter and/or setter, write those as a function on your Rust type, expose it using #[func], and annotate the field with #[export(get = ..., set = ...)]:

use godot::prelude::*;

#[derive(GodotClass)]
struct MyStruct {
    #[var(get = get_my_field, set = set_my_field)]
    my_field: i64,
}

#[godot_api]
impl MyStruct {
    #[func]
    pub fn get_my_field(&self) -> i64 {
        self.my_field
    }

    #[func]
    pub fn set_my_field(&mut self, value: i64) {
        self.my_field = value;
    }
}

If you specify only get, no setter is generated, making the field read-only. If you specify only set, no getter is generated, making the field write-only (rarely useful). To add a generated getter or setter in these cases anyway, use get or set without a value:

use godot::prelude::*;

#[derive(GodotClass)]
struct MyStruct {
    // Default getter, custom setter.
    #[var(get, set = set_my_field)]
    my_field: i64,
}

#[godot_api]
impl MyStruct {
    #[func]
    pub fn set_my_field(&mut self, value: i64) {
        self.my_field = value;
    }
}

For exporting properties to the editor, you can use the #[export] attribute:

use godot::prelude::*;

#[derive(GodotClass)]
struct MyStruct {
    #[export]
    my_field: i64,
}

If you dont also include a #[var] attribute, then a default one will be generated. #[export] also supports all of GDScript’s annotations, in a slightly different format. The format is translated from an annotation by following these four rules:

  • @export becomes #[export]
  • @export_{name} becomes #[export(name)]
  • @export_{name}(elem1, ...) becomes #[export(name = (elem1, ...))]
  • @export_{flags/enum}("elem1", "elem2:key2", ...) becomes #[export(flags/enum = (elem1, elem2 = key2, ...))]

As an example of some different export attributes:

use godot::prelude::*;

#[derive(GodotClass)]
struct MyStruct {
    // @export
    #[export]
    float: f64,
     
    // @export_range(0.0, 10.0, or_greater)
    #[export(range = (0.0, 10.0, or_greater))]
    range_f64: f64,

    // @export_file
    #[export(file)]
    file: GString,

    // @export_file("*.gd")
    #[export(file = "*.gd")]
    gdscript_file: GString,

    // @export_flags_3d_physics
    #[export(flags_3d_physics)]
    physics: u32,

    // @export_exp_easing
    #[export(exp_easing)]
    ease: f64,

    // @export_enum("One", "Two", "Ten:10", "Twelve:12", "Thirteen")
    #[export(enum = (One, Two, Ten = 10, Twelve = 12, Thirteen))]
    exported_enum: i64,

    // @export_flags("A:1", "B:2", "AB:3")
    #[export(flags = (A = 1, B = 2, AB = 3))]
    flags: u32,
}

Most values in expressions like key = value, can be an arbitrary expression that evaluates to the right value. Meaning you can use constants or variables, as well as any other rust syntax you’d like in the export attributes.

use godot::prelude::*;

const MAX_HEALTH: f64 = 100.0;

#[derive(GodotClass)]
struct MyStruct {
    #[export(range = (0.0, MAX_HEALTH))]
    health: f64,

    #[export(flags = (A = 0b0001, B = 0b0010, C = 0b0100, D = 0b1000))]
    flags: u32,
}

You can specify custom property hints, hint strings, and usage flags in a #[var] attribute using the hint, hint_string, and usage_flags keys in the attribute:

use godot::prelude::*;

#[derive(GodotClass)]
struct MyStruct {
    // Treated as an enum with two values: "One" and "Two"
    // Displayed in the editor
    // Treated as read-only by the editor
    #[var(
        hint = PROPERTY_HINT_ENUM,
        hint_string = "One,Two",
        usage_flags = [PROPERTY_USAGE_EDITOR, PROPERTY_USAGE_READ_ONLY]
    )]
    my_field: i64,
}

Signals

The #[signal] attribute is accepted, but not yet implemented. See issue #8.

Running code in the editor

If you annotate a class with #[class(tool)], its lifecycle methods (ready(), process() etc.) will be invoked in the editor. This is useful for writing custom editor plugins, as opposed to classes running simply in-game.

See ExtensionLibrary::editor_run_behavior() for more information and further customization.

This is very similar to GDScript’s @tool feature.

Editor Plugins

If you annotate a class with #[class(editor_plugin)], it will be turned into an editor plugin. The class must then inherit from EditorPlugin, and an instance of that class will be automatically added to the editor when launched.

See Godot’s documentation of editor plugins for more information about editor plugins. But note that you do not need to create and enable the plugin through Godot’s Create New Plugin menu for it to work, simply annotating the class with editor_plugin automatically enables it when the library is loaded.

This should usually be combined with #[class(tool)] so that the code you write will actually run in the editor.

Class Renaming

You may want to have structs with the same name. With Rust, this is allowed using mod. However in GDScript, there are no modules, namespaces, or any such disambiguation. Therefore, you need to change the names before they can get to Godot. You can use the rename key while defining your GodotClass for this.

mod animal {
    #[derive(GodotClass)]
    #[class(init, rename=AnimalToad)]
    pub struct Toad {}
}

mod npc {
    #[derive(GodotClass)]
    #[class(init, rename=NpcToad)]
    pub struct Toad {}
}

These classes will appear in the Godot editor and GDScript as “AnimalToad” or “NpcToad”.