gdext icon indicating copy to clipboard operation
gdext copied to clipboard

[Prototype][Feature] OnReady attribute (#[onready] field: OnReady<T>)

Open Houtamelo opened this issue 7 months ago • 4 comments

This feature aims to mimic GDScript's @onready annotation in a more ergonomic way.

It still uses the type OnReady<T>, but the initialization closure now accepts an argument of type Gd<Node>, which makes it easier to express the "classic" GDScript pattern of fetching a node reference before _ready (var node = $NodePath).

This is achieved by adding the #[onready] attribute to the pool of possible ways the user can customize their Rust "class"'s fields. The attribute supports the following arguments, only one must be provided at a time:

  • node = "NodePath"
  • fn = |base| -> T { .. }

Example

#[derive(GodotClass)]
#[class(init, base = Node)]
struct OnReadyAttribute {
    base: Base<Node>,
    #[onready(node = "child")] // Runs `self.auto_node = self.base().get_node_as("child")`
    auto_node: OnReady<Gd<Node>>,
    #[onready(fn = |b| b.get_name())] // Runs `self.auto_primitive = self.base().get_name()`
    auto_primitive: OnReady<GString>,
}

Restrictions

  • The class must have an explicit base field.
  • The attribute is mutually exclusive with #[init(default)]
  • The initialization closure does not support typed Base<T>, it's always Gd<Node>

Caveats

Since the attribute essentially de-sugars into #[init(default)], it only works with the macro-generated init, the #[onready] attribute does nothing if the user manually creates the class (by overriding INode::init, or calling Gd::with_init_fn, etc).

Houtamelo avatar Jul 22 '24 07:07 Houtamelo