Skip to content

Commit

Permalink
Implemented the scene! macro and NodeScene!
Browse files Browse the repository at this point in the history
  • Loading branch information
LunaticWyrm467 committed Sep 21, 2024
1 parent aa6a640 commit 25474fc
Show file tree
Hide file tree
Showing 18 changed files with 487 additions and 87 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,34 @@ fn main() -> () {
}
```

You may also input a `NodeScene` when initializing a `NodeTree` or adding a child via `add_child`:
```rust
use node_tree::prelude::*;


let scene: NodeScene = scene! {
NodeA("Root") { // Nodes must have a constructor named `new()` in order for this to work!
NodeA("1_Node") {
NodeA("2_Node") {
NodeA("3_Node"),
NodeA("3_Node"),
NodeA("3_Node")
},
NodeA("2_Node") {
NodeA("3_Node"),
NodeA("3_Node"),
NodeA("3_Node")
},
NodeA("2_Node") {
NodeA("3_Node"),
NodeA("3_Node"),
NodeA("3_Node")
}
}
}
};
```

Logging is also supported. Here is an example setup with an output of a few warnings and a crash. Note that the crash header/footer are customizable, and that the output is actually colored in a real terminal.
```rust
/// Root Node
Expand Down Expand Up @@ -228,4 +256,4 @@ Goodbye World! (Program Exited)
- 👪 The ability to manage nodes with `add_child()` and `remove_child()`.
- 📝 Includes a dynamic logging system that is deeply integrated with the node framework.
- 🌲 Allows for the direct referencing of the `NodeTree` through a node's `root()` function.
- 📜 TODO: Includes a method to save and handle individual node scenes, such as the handy visual macro `Scene!`.
- 📜 Includes a method to save (TODO) and handle individual node scenes, such as the handy visual macro `scene!`.
4 changes: 2 additions & 2 deletions node_tree_core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "node_tree"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
rust-version = "1.78"

Expand All @@ -20,4 +20,4 @@ license = "MIT OR Apache-2.0"

[dependencies]
chrono = "0.4.38"
node_tree_derive = { path = "../node_tree_derive", version = "0.3.0" }
node_tree_derive = { path = "../node_tree_derive", version = "0.4.0" }
30 changes: 29 additions & 1 deletion node_tree_core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,34 @@ fn main() -> () {
}
```

You may also input a `NodeScene` when initializing a `NodeTree` or adding a child via `add_child`:
```rust
use node_tree::prelude::*;


let scene: NodeScene = scene! {
NodeA("Root") { // Nodes must have a constructor named `new()` in order for this to work!
NodeA("1_Node") {
NodeA("2_Node") {
NodeA("3_Node"),
NodeA("3_Node"),
NodeA("3_Node")
},
NodeA("2_Node") {
NodeA("3_Node"),
NodeA("3_Node"),
NodeA("3_Node")
},
NodeA("2_Node") {
NodeA("3_Node"),
NodeA("3_Node"),
NodeA("3_Node")
}
}
}
};
```

Logging is also supported. Here is an example setup with an output of a few warnings and a crash. Note that the crash header/footer are customizable, and that the output is actually colored in a real terminal.
```rust
/// Root Node
Expand Down Expand Up @@ -228,4 +256,4 @@ Goodbye World! (Program Exited)
- 👪 The ability to manage nodes with `add_child()` and `remove_child()`.
- 📝 Includes a dynamic logging system that is deeply integrated with the node framework.
- 🌲 Allows for the direct referencing of the `NodeTree` through a node's `root()` function.
- 📜 TODO: Includes a method to save and handle individual node scenes, such as the handy visual macro `Scene!`.
- 📜 Includes a method to save (TODO) and handle individual node scenes, such as the handy visual macro `scene!`.
10 changes: 6 additions & 4 deletions node_tree_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,19 @@ pub mod prelude {
//! You'll probably want to import all from this module.
pub use std::rc::Rc;
pub use node_tree_derive::Abstract;
pub use node_tree_derive::{ Abstract, Tree, scene };
pub use crate::structs::{
rid::RID,
logger::{ LoggerVerbosity, Log },
node_base::NodeBase,
node_path::NodePath,
node_tree_base::{ NodeTreeBase, TreeStatus, TreeProcess, ProcessMode },
tree_pointer::{ Tp, TpDyn }
node_tree_base::{ NodeTreeBase, TreeStatus, TreeProcess, ProcessMode, initialize_base },
tree_pointer::{ Tp, TpDyn },
node_scene::NodeScene
};
pub use crate::traits::{
node::{ Node, NodeAbstract },
node_tree::{ NodeTree, init_base }
node_tree::NodeTree,
instanceable::Instanceable
};
}
3 changes: 3 additions & 0 deletions node_tree_core/src/structs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ pub mod node_path;
pub mod node_tree_base;
pub mod tree_pointer;
pub mod rid;

#[macro_use]
pub mod node_scene;
43 changes: 35 additions & 8 deletions node_tree_core/src/structs/node_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use super::{
rid::RID
};

use crate::traits::{ node::Node, node_tree::NodeTree, node_getter::NodeGetter };
use crate::traits::{ node::Node, node_tree::NodeTree, node_getter::NodeGetter, instanceable::Instanceable };
use crate::utils::functions::ensure_unique_name;


Expand Down Expand Up @@ -121,18 +121,46 @@ impl NodeBase {

/// Adds a child to the node, automatically renaming it if its name is not unique in the
/// node's children vector.
///
/// # Note
/// `_ready()` will automatically be propogated through the added child node.
///
/// # Panics
/// Panics if this Node is not connected to a `NodeTree`.
pub fn add_child<N: Node>(&mut self, mut child: N) {
pub fn add_child<I: Instanceable>(&mut self, child: I) {
child.iterate(|parent, node| {
if let Some(parent) = parent {
unsafe {
let parent: &mut dyn Node = &mut *parent;
parent.add_child_from_ptr(node, false);
}
} else {
unsafe {
self.add_child_from_ptr(node, true);
}
}
});
}

/// Adds a child to the node via a passed in pointer, automatically renaming it if its
/// name is not unique in the node's children vector.
///
/// # Note
/// `_ready()` will automatically be propogated through the added child node.
///
/// # Safety
/// Cannot guarantee that the raw pointer that is passed in is valid.
///
/// # Panics
/// Panics if this Node is not connected to a `NodeTree`.
pub unsafe fn add_child_from_ptr(&mut self, child_ptr: *mut dyn Node, owner_is_self: bool) {
if self.tree.is_none() {
panic!("Cannot add a child to a node that is not in a `NodeTree`!");
}

// Ensure that the child's name within the context of this node's children is unique.
let names_of_children: &[String] = &self.children().iter().map(|c| c.name().to_string()).collect::<Vec<_>>();
let child_name: &str = child.name();
let child_name: &str = unsafe { &*child_ptr }.name();
let unique_name: String = ensure_unique_name(&child_name, names_of_children);

// Add the child to this node's children and connect it to its parent and owner nodes,
Expand All @@ -143,17 +171,16 @@ impl NodeBase {
let new_depth: usize = self.depth() + 1;
let tree_raw: *mut dyn NodeTree = self.tree.unwrap_unchecked();
let tree: &mut dyn NodeTree = self.tree_mut().unwrap_unchecked();

let rid: RID = tree.register_node(child_ptr);
let child: &mut dyn Node = tree.get_node_mut(rid).unwrap_unchecked();

child.set_name_unchecked(&unique_name);
child.set_parent(parent_rid);
child.set_owner(owner_rid); // For now, we just propagate the root as the owner for all nodes.
child.set_owner(if owner_is_self { rid } else { owner_rid });
child.set_tree(tree_raw);
child.set_depth(new_depth); // This is the only place where depth is updated.

let child_ptr: Box<dyn Node> = child.to_dyn_box();
let rid: RID = tree.register_node(child_ptr);
let child: &mut dyn Node = tree.get_node_mut(rid).unwrap_unchecked();

child.set_rid(rid);
rid
};
Expand Down
73 changes: 73 additions & 0 deletions node_tree_core/src/structs/node_scene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::traits::{ node::Node, instanceable::Instanceable };


/*
* Node Scene
* Struct
*/


/// A recursive structure that allows for the storage of a dormant scene of nodes.
/// The root node is what every node in the scene will have its owner set to.
#[derive(Debug)]
pub struct NodeScene {
this: *mut dyn Node,
children: Vec<NodeScene>
}

impl NodeScene {

/// Creates a new `NodeScene` with a root node.
pub fn new<N: Node>(root: N) -> Self {
NodeScene {
this: Box::into_raw(root.to_dyn_box()),
children: Vec::new()
}
}

/// Appends a `NodeScene` as a child.
pub fn append(&mut self, child: NodeScene) {
self.children.push(child);
}

/// Returns this `NodeScene` instance's associated node.
///
/// # Safety
/// This is marked unsafe as if the resulting `Box<T>` is dropped, the internal pointer could
/// be invalidated.
pub unsafe fn get_node(&self) -> Box<dyn Node> {
Box::from_raw(self.this)
}

/// Gets the children.
pub fn children(&self) -> &[NodeScene] {
&self.children
}
}

impl Instanceable for NodeScene {
fn iterate<F: FnMut(Option<*mut dyn Node>, *mut dyn Node)>(self, mut iterator: F) {
iterator(None, self.this);

// Recursive function to traverse the tree
fn traverse<F: FnMut(Option<*mut dyn Node>, *mut dyn Node)>(
node: NodeScene,
parent: *mut dyn Node,
iterator: &mut F
) {
for child in node.children {

// Call the iterator for the child node
iterator(Some(parent), child.this);

// Recursively traverse the child's children
let child_this: *mut dyn Node = child.this;
traverse(child, child_this, iterator);
}
}

// Start the traversal from the root.
let self_this: *mut dyn Node = self.this;
traverse(self, self_this, &mut iterator);
}
}
Loading

0 comments on commit 25474fc

Please sign in to comment.