Skip to content

Commit

Permalink
Implemented more type support + glam support!
Browse files Browse the repository at this point in the history
  • Loading branch information
LunaticWyrm467 committed Nov 10, 2024
1 parent c60fe18 commit f06d951
Show file tree
Hide file tree
Showing 11 changed files with 1,142 additions and 146 deletions.
58 changes: 9 additions & 49 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,10 @@ pub struct SpecializedNode {
}
```

## Features
## Supported Features
- `glam` - Enables support with glam's types when it comes with saving and loading.

## Highlights
- 🏗️ An easy abstraction framework for different processes to communicate and interact with each other in a scalable manner. Inspired by Godot!
- ⏯️ The ability to `pause()` and `unpause()` the `NodeTree`, and fine tune individual `Node` behaviours for when a tree is paused/unpaused.
- 📡 Various methods to communicate with other nodes, such as `owner()`, `parent()`, `get_child()`, `children()`, and `get_node()`, as well as methods to automate the process such as signals.
Expand Down
10 changes: 7 additions & 3 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.9.0"
version = "0.9.1"
edition = "2021"
rust-version = "1.78"

Expand All @@ -22,6 +22,10 @@ license = "MIT OR Apache-2.0"
node_tree_derive = { path = "../node_tree_derive", version = "0.7.0" }
chrono = "0.4.38"
dashmap = "6.1.0"
serde = { version = "1.0.214", features = ["derive"] }
ctor = "0.2.8"
toml = "0.8.19"
toml_edit = "0.22.22"
glam = { version = "0.29.2", optional = true }

[features]
default = []
glam = ["dep:glam"]
2 changes: 1 addition & 1 deletion node_tree_core/src/services/node_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use std::collections::HashMap;

use dashmap::DashMap;

pub use toml::Value;
pub use toml_edit::Value;

use crate::traits::node::Node;
use crate::traits::serializable::Serializable;
Expand Down
8 changes: 7 additions & 1 deletion node_tree_core/src/structs/cloneable_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@
use std::ops::{ Deref, DerefMut };

use toml_edit as toml;

use crate::traits::serializable::Serializable;


/// `Doc<T>` (Default on Clone), simply returns the default type when cloned.
///
/// # Note
/// This automatically implements `Serializable`, and will always yield the default value when
/// serialized.
#[derive(Debug, Default)]
pub struct Doc<T: Default>(T);

Expand Down Expand Up @@ -69,7 +75,7 @@ impl <T: Default> DerefMut for Doc<T> {

impl <T: Default + 'static> Serializable for Doc<T> {
fn to_value(&self) -> toml::Value {
toml::Value::Array(Vec::new())
toml::Value::Array(toml::Array::new())
}

fn from_value(_value: toml::Value) -> Option<Self> where Self: Sized {
Expand Down
75 changes: 35 additions & 40 deletions node_tree_core/src/structs/node_scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ use std::path::PathBuf;
use std::collections::HashMap;
use std::hash::{ self, Hash, Hasher };

use serde::{ Serialize, Deserialize };
use toml::Table;
use toml_edit as toml;

use crate::structs::rid::RID;
use crate::traits::{ node::Node, instanceable::Instanceable };
Expand All @@ -44,18 +43,6 @@ use crate::services::node_registry::{ self, FieldMap, SFieldMap };
*/


/// Used to represent a node's data.
///
/// # Note
/// The `ID` is stored as the key to this data, not in the data itself.
#[derive(Serialize, Deserialize)]
struct NodeData {
type_name: String,
parent: Option<RID>,
is_owner: bool,
fields: Table
}

/// A recursive structure that allows for the storage, saving, and loading of a dormant scene of nodes.
/// The root node is what every node in the scene will have its owner set to.
#[derive(Debug)]
Expand Down Expand Up @@ -102,26 +89,34 @@ impl NodeScene {
drop(file);

// Attempt to parse the file as a table.
let document: String = String::from_utf8(buffer).map_err(|err| format!("{err}"))?;
let document: Table = toml::from_str(&document).map_err(|err| format!("{err}"))?;
let document: String = String::from_utf8(buffer).map_err(|err| format!("{err}"))?;
let document: toml::DocumentMut = document.parse().map_err(|err| format!("{err}"))?;

// Go through each node and deserialize it:
let mut node_scene: Option<NodeScene> = None;
let mut traversal: HashMap<RID, Vec<usize>> = HashMap::new(); // Cache used for quick traversal.

for (key, node_data) in document {

for (key, node_data) in document.iter() {

// Deserialize the node's metadata.
let node_data: &toml::Table = node_data.as_table().ok_or(format!("Failed to parse {}'s data", key))?;
let metadata: &toml::InlineTable = node_data.get("metadata").map(|nd| nd.as_inline_table()).flatten().ok_or(format!("Failed to parse {}'s metadata", key))?;
let type_name: String = metadata.get("type_name").map(|tn| tn.as_str().map(|s| s.to_string())).flatten().ok_or(format!("Failed to parse {}'s type name", key))?;
let is_owner: bool = metadata.get("is_owner").map(|tn| tn.as_bool()).flatten().ok_or(format!("Failed to parse {}'s ownership status", key))?;
let parent: Option<RID> = metadata.get("parent").map(|p| p.as_integer().map(|rid| rid as RID)).flatten();

// Deserialize the node data back into its respective type.
let NodeData {
type_name,
is_owner,
parent,
fields
} = toml::from_str(&toml::to_string(&node_data).unwrap()).unwrap();

let node_fields: SFieldMap = fields.into_iter().map(|(key, value)| (key.into(), value)).collect();
let node: Box<dyn Node> = node_registry::deserialize(&type_name, node_fields)?;
let local_rid: RID = key.split_once('_')
let node_fields: Option<SFieldMap> = node_data.into_iter()
.filter(|(field, _)| *field != "metadata")
.map(|(field, value)| {
match value {
toml::Item::Value(value) => Some((field.into(), value.to_owned())),
_ => None
}
}).collect();

let node: Box<dyn Node> = node_registry::deserialize(&type_name, node_fields.ok_or("Could not parse node fields".to_string())?)?;
let local_rid: RID = key.split_once('_')
.ok_or("Failed to parse Node key".to_string())?
.1.parse()
.map_err(|err| format!("{err}"))?;
Expand Down Expand Up @@ -188,7 +183,7 @@ impl NodeScene {
pub fn save(&self, path: &Path, name: &str) -> Result<(), String> {

// Constuct a buffer for the toml format.
let mut document: Table = Table::new();
let mut document: toml::DocumentMut = toml::DocumentMut::new();

// Go through each node and serialize it:
self.update_internal(0);
Expand All @@ -197,22 +192,22 @@ impl NodeScene {
let parent: Option<&dyn Node> = parent.map(|x| unsafe { &*x });

// Format the metadata.
let mut node_data: NodeData = NodeData {
type_name: node.name_as_type(),
is_owner,
parent: parent.map(|p| p.rid()),
fields: Table::new()
};
let node_key: String = format!("Node_{}", node.rid());

document[&node_key] = toml::Item::Table(toml::Table::new());
document[&node_key]["metadata"] = toml::InlineTable::new().into();
document[&node_key]["metadata"]["type_name"] = node.name_as_type().into();
document[&node_key]["metadata"]["is_owner"] = is_owner.into();

if let Some(parent_rid) = parent.map(|p| p.rid()) {
document[&node_key]["metadata"]["parent"] = (parent_rid as i64).into();
}

// Save the fields.
let node_fields: FieldMap = node.save_from_owned();
for (field_name, value) in node_fields {
node_data.fields.insert(field_name.to_string(), value.to_value());
document[&node_key][&field_name.to_string()] = toml::Item::Value(value.to_value());
}

// Serialize this as a table and insert it into a document.
let node_table: Table = toml::from_str(&toml::to_string(&node_data).unwrap()).unwrap();
document.insert(format!("Node_{}", node.rid()), node_table.into());
});

// Write the saved scene data to disk.
Expand Down
Loading

0 comments on commit f06d951

Please sign in to comment.