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”.