asr/game_engine/godot/scene/main/node.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
//! <https://github.com/godotengine/godot/blob/07cf36d21c9056fb4055f020949fb90ebd795afb/scene/main/node.h>
use core::fmt;
use crate::{
game_engine::godot::{HashMap, Object, Ptr, String, StringName},
Error, Process,
};
use super::SceneTree;
/// Base class for all scene objects.
///
/// [`Node`](https://docs.godotengine.org/en/4.2/classes/class_node.html)
///
/// Check the [`Ptr<Node>`] documentation to see all the methods you can call
/// on it.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Node;
extends!(Node: Object);
impl Ptr<Node> {
/// Returns this node's parent node, or [`None`] if the node doesn't have a parent.
///
/// [`Node.get_parent`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-get-parent)
pub fn get_parent(self, process: &Process) -> Result<Option<Ptr<Self>>, Error> {
self.read_at_byte_offset(0x128, process).map(
|ptr: Ptr<Self>| {
if ptr.is_null() {
None
} else {
Some(ptr)
}
},
)
}
/// The owner of this node. The owner must be an ancestor of this node. When
/// packing the owner node in a `PackedScene`, all the nodes it owns are
/// also saved with it.
///
/// [`Node.get_owner`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-property-owner)
pub fn get_owner(self, process: &Process) -> Result<Option<Ptr<Self>>, Error> {
self.read_at_byte_offset(0x130, process).map(
|ptr: Ptr<Self>| {
if ptr.is_null() {
None
} else {
Some(ptr)
}
},
)
}
/// Finds the first descendant of this node whose name matches the name
/// provided, returning [`None`] if no match is found. The matching is done
/// against node names, not their paths. As such, it is case-sensitive.
/// Unlike the Godot API, not wildcards are supported.
///
/// [`Node.find_child`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-find-child)
pub fn find_child<const N: usize>(
self,
name: &[u8; N],
process: &Process,
) -> Result<Option<Ptr<Node>>, Error> {
self.get_children()
.get(name, process)?
.map(|node| node.deref(process))
.transpose()
}
/// Fetches a child node by its index. Each child node has an index relative
/// its siblings (see [`get_index`](Self::get_index)). The first child is at
/// index 0. If no child exists at the given index, this method returns an
/// error.
///
/// [`Node.get_child`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-get-child)
///
/// # Warning
///
/// Prefer not using this function in loops, it has to iterate over a linked
/// list and is not actually O(1). Iterate over the children directly
/// instead in that case. Only use this function if you know the specific
/// index of the child node.
pub fn get_child(self, idx: usize, process: &Process) -> Result<Ptr<Node>, Error> {
self.get_children()
.iter(process)
.nth(idx)
.ok_or(Error {})?
.1
.deref(process)
}
/// Returns the number of children of this node.
///
/// [`Node.get_child_count`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-get-child-count)
pub fn get_child_count(self, process: &Process) -> Result<u32, Error> {
self.get_children().size(process)
}
/// Returns all children of this node inside a [`HashMap`].
///
/// [`Node.get_children`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-get-children)
pub fn get_children(self) -> Ptr<HashMap<StringName, Ptr<Node>>> {
Ptr::new(self.addr() + 0x138)
}
/// Returns this node's order among its siblings. The first node's index is
/// `0`. See also [`get_child`](Self::get_child).
///
/// [`Node.get_index`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-get-index)
pub fn get_index(self, process: &Process) -> Result<i32, Error> {
self.read_at_byte_offset(0x1C4, process)
}
/// The name of the node. This name must be unique among the siblings (other
/// child nodes from the same parent). When set to an existing sibling's
/// name, the node is automatically renamed.
///
/// [`Node.get_name`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-property-name)
pub fn get_name<const N: usize>(self, process: &Process) -> Result<String<N>, Error> {
let string_name: StringName = self.read_at_byte_offset(0x1D0, process)?;
string_name.read(process)
}
/// Prints the node and its children, recursively. The node does not have to
/// be inside the tree.
///
/// [`Node.print_tree`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-print-tree)
#[must_use]
pub fn print_tree<const N: usize>(self, process: &Process) -> PrintTree<'_, N> {
PrintTree(self, process)
}
/// Returns [`true`] if this node is currently inside [`SceneTree`]. See
/// also [`get_tree`](Self::get_tree).
///
/// [`Node.is_inside_tree`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-is-inside-tree)
pub fn is_inside_tree(self, process: &Process) -> Result<bool, Error> {
self.get_tree(process).map(|tree| tree.is_some())
}
/// Returns the [`SceneTree`] that contains this node. If this node is not
/// inside the tree, returns [`None`]. See also
/// [`is_inside_tree`](Self::is_inside_tree).
///
/// [`Node.get_tree`](https://docs.godotengine.org/en/4.2/classes/class_node.html#class-node-method-get-tree)
pub fn get_tree(self, process: &Process) -> Result<Option<Ptr<SceneTree>>, Error> {
self.read_at_byte_offset(0x1D8, process).map(
|ptr: Ptr<SceneTree>| {
if ptr.is_null() {
None
} else {
Some(ptr)
}
},
)
}
}
/// A recursive tree printer.
pub struct PrintTree<'p, const N: usize>(Ptr<Node>, &'p Process);
impl<'p, const N: usize> fmt::Debug for PrintTree<'p, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug_map = f.debug_map();
for (name, node) in self.0.get_children().iter(self.1) {
self.print_key(&mut debug_map, name);
match node.deref(self.1) {
Ok(node) => debug_map.value(&PrintTree::<N>(node, self.1)),
Err(_) => debug_map.value(&"<failed reading node>"),
};
}
debug_map.finish()
}
}
impl<'p, const N: usize> fmt::Display for PrintTree<'p, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#?}", self)
}
}
impl<'p, const N: usize> PrintTree<'p, N> {
#[inline(never)]
fn print_key(&self, debug_map: &mut fmt::DebugMap<'_, '_>, name: Ptr<StringName>) {
debug_map.key(
&name
.deref(self.1)
.ok()
.and_then(|name| Some(name.read::<N>(self.1).ok()?.to_array_string::<N>()))
.as_deref()
.unwrap_or("<failed reading name>"),
);
}
}