| Crates.io | gdnative_export_node_as_path |
| lib.rs | gdnative_export_node_as_path |
| version | 0.1.2 |
| created_at | 2024-01-18 07:42:39.123153+00 |
| updated_at | 2024-01-18 07:42:39.123153+00 |
| description | Boilerplate-code replacement macros when exporting node references through NodePath. |
| homepage | |
| repository | https://github.com/Houtamelo/gdnative_export_node_macro |
| max_upload_size | |
| id | 1103937 |
| size | 64,050 |
Reduces boilerplate code when acquiring references through NodePath.
Usage consists of (full example on a few paragraphs bellow):
#[derive(NativeClass, Default)] #[inherit(Node)] with #[extends(Node)]NodePath fields marked with #[property]#[export_path] behind the fields you wish to acquire through NodePathfn new(&mut self, _owner: &Node)self.grab_nodes_by_path(_owner); on your _ready() declaration#[extends] attribute macro:#[derive(NativeClass)] #[inherit(Node)]#[export_path]:
path_ prefix and NodePath as type, as well as a regular #[property] attribute. (Vec<Ref<Node>> uses a Vec<NodePath> type instead)#[export_path] node: Option<Ref<Node>> / #[property] path_node: NodePath, node: Option<Ref<Node>>,fn grab_nodes_by_path(&mut self, _owner: &Node) { // searches for all the nodes/instances from the NodePath fields generated, assigning each to their original field in self }fn new(_owner: &Node) -> Self { Self::default() }Option<Ref<T>> where T is a Godot's built-in type that inherits Node (such as: Node2D, Control, ProgressBar, KinematicBody, ...)
Vec<Ref<T>> where T is a Godot's built-in type that inherits Node
Option<Instance<T>> where T is a custom native script defined by you, as long as the script inherits a Godot's built-in type that inherits Node
Vec<Instance<T>> where T is a custom native script defined by you, as long as the script inherits a Godot's built-in type that inherits Node
PS 1: Note that Vec<Ref<T>>/Vec<Instance<T>> uses Ref<T>/Instance<T> directly instead of Option<Ref<T>>/Option<Instance<T>>
PS 2: Not related to this crate, but to gdnative-rust itself: In the editor, Vec<NodePath> will be shown as an array of Variant, you have to click on each element of the array, chose NodePath, then you'll be able to drag nodes in.
The base of the implementation was taken from gdrust.
#[derive(NativeClass)]
#[inherit(Node)]
struct MyGodotScript {
#[property] path_exported_node: NodePath,
exported_node: Option<Ref<Node>>,
#[property] path_exported_instance: NodePath,
exported_instance: Option<Instance<NativeScriptTest>>,
#[property] paths_exported_nodes: Vec<NodePath>,
vec_nodes: Vec<Ref<Node>>,
#[property] paths_exported_instances: Vec<NodePath>,
vec_instances: Vec<Instance<NativeScriptTest>>,
}
impl MyGodotScript {
fn new(_owner: &Node) -> Self {
return Self {
path_exported_node: NodePath::default(),
exported_node: None,
path_exported_instance: NodePath::default(),
exported_instance: None,
paths_exported_nodes: Vec::new(),
vec_nodes: Vec::new(),
paths_exported_instances: Vec::new(),
vec_instances: Vec::new(),
};
}
}
#[methods]
impl MyGodotScript {
#[method]
fn _ready(&mut self, #[base] _owner: &Node) {
self.exported_node = Some(unsafe {_owner.get_node_as::<Node>(self.path_exported_node.new_ref()).unwrap().assume_shared()});
self.exported_instance = Some(unsafe {_owner.get_node_as_instance::<NativeScriptTest>(self.path_exported_instance.new_ref()).unwrap().claim()});
for path in self.paths_exported_nodes.iter() {
self.vec_nodes.push(unsafe { _owner.get_node_as::<Node>(path.new_ref()).unwrap().assume_shared()});
}
for path in self.paths_exported_instances.iter() {
self.vec_instances.push(unsafe { _owner.get_node_as_instance::<NativeScriptTest>(path.new_ref()).unwrap().claim()});
}
}
}
#[derive(NativeClass)]
#[inherit(Node)]
pub struct NativeScriptTest { }
impl NativeScriptTest {
fn new(_owner: &Node) -> Self {
return Self {};
}
}
#[extends(Node)] // you can replace Node with any other Godot built-in node type
struct MyGodotScript {
#[export_path] exported_node: Option<Ref<Node>>, // you can replace Node with any other Godot built-in node type
#[export_path] exported_instance: Option<Instance<NativeScriptTest>>, // replace NativeScriptTest with your own type
#[export_path] vec_nodes: Vec<Ref<Node>>, // you can replace Node with any other Godot built-in node type
#[export_path] vec_instances: Vec<Instance<NativeScriptTest>>, // replace NativeScriptTest with your own type
}
#[methods]
impl MyGodotScript {
#[method]
fn _ready(&mut self, #[base] _owner: &Node) { // replace Node with the extended type
self.grab_nodes_by_path(_owner); // you must call this manually, it replaces your old _ready() call
}
}
#[extends(Node)]
pub struct NativeScriptTest { }
#[derive(gdnative::prelude::NativeClass, Default)]
#[inherit(Node)]
struct MyGodotScript {
#[property] path_vec_instances: Vec<gdnative::prelude::NodePath>,
#[property] path_vec_nodes : Vec<gdnative::prelude::NodePath>,
#[property] path_exported_instance: gdnative::prelude::NodePath,
#[property] path_exported_node : gdnative::prelude::NodePath,
exported_node: Option<Ref<Node>>,
exported_instance: Option<Instance<NativeScriptTest>>,
vec_nodes: Vec<Ref<Node>>,
vec_instances: Vec<Instance<NativeScriptTest>>,
}
impl MyGodotScript {
fn new(_owner: &Node) -> Self { Self::default() }
fn grab_nodes_by_path(&mut self, owner: &Node) {
self.exported_node = Some(unsafe { owner.get_node_as::<Node>(self.path_exported_node.new_ref()).unwrap().assume_shared() });
self.exported_instance = Some(unsafe { owner.get_node_as_instance::<NativeScriptTest>(self.path_exported_instance.new_ref()).unwrap().claim() });
for path in self.path_vec_nodes.iter() {
self.vec_nodes.push(unsafe { owner.get_node_as::<Node>(path.new_ref()).unwrap().assume_shared() });
}
for path in self.path_vec_instances.iter() {
self.vec_instances.push(unsafe { owner.get_node_as_instance::<NativeScriptTest>(path.new_ref()).unwrap().claim() });
}
}
}
gdnative attributes like #[register_with] #[no_constructor] #[user_data] #[property]. Just make sure to always place them bellow #[extends], except #[property] which still goes behind fields.grab_nodes_by_path(&mut self, owner: &Node) will panic if it fails to validate any of the exported paths.Self::new()._owner in grab_nodes_by_path(&mut self, owner: &Node) uses hardcoded &, so you cannot declare owner in _ready(&mut self, #[base] _owner: &Node) as owner: TRef<Node>.