diff --git a/src/vvlib/s_structure_asset.rs b/src/vvlib/s_structure_asset.rs index d248023..8394c4a 100644 --- a/src/vvlib/s_structure_asset.rs +++ b/src/vvlib/s_structure_asset.rs @@ -102,8 +102,37 @@ pub mod serialization { use super::super::{StructureAsset, StructureLoadError}; - pub fn load_detect_version(_bytes: Vec) -> Result { - return Err(StructureLoadError::FileDataInvalid("".to_string())); + pub fn load_detect_version(bytes: Vec) -> Result { + const NEWLINE: &str = "\n"; + let data_str = std::str::from_utf8(bytes.as_slice()); + if data_str.is_err() { + return Err(StructureLoadError::FileDataInvalid("".to_string())); + } + let data: String = data_str.unwrap().into(); + let lines: std::str::Lines<'_> = data.lines(); + let mut iter: std::str::Lines<'_> = lines.into_iter(); + let first: Option<&str> = iter.next(); + let version = determine_version(first); + let mut the_rest = "".to_string(); + let mut first = true; + for each in iter { + if first { + first = false; + } else { + the_rest += NEWLINE; + } + the_rest += each; + } + match version { + StructureVersions::Version1 => { + return versions::version_1::load(the_rest); + } + StructureVersions::Error => { + return Err(StructureLoadError::FileDataInvalid( + "invalid version data".into(), + )) + } + } } pub fn write_latest_version(path: &String, asset: &StructureAsset) -> bool { @@ -155,14 +184,276 @@ pub mod serialization { pub mod version_1 { - use bevy::transform::components::Transform; + use bevy::{ + math::{Quat, Vec3}, + transform::components::Transform, + }; - use crate::vvedit::s_string_tree::StringTree; + use crate::{ + vvedit::s_string_tree::StringTree, vvlib::s_structure_asset::ElementData, + }; use super::super::super::super::{StructureAsset, StructureLoadError}; - pub fn load( - _data: std::str::Lines<'_>, - ) -> Result { + pub fn load(data: String) -> Result { + let mut result = StructureAsset { + layout: StringTree::new(), + default_pose_positions: Default::default(), + element_data: Default::default(), + }; + let mut sides = data.split("||"); + let string_tree_data = sides.next(); + let node_transforms = sides.next(); + let node_attachments = sides.next(); + // v STRING TREE (tree that defines shape/structure of it) + { + if string_tree_data.is_none() { + return Err(StructureLoadError::FileDataInvalid( + "error: lack of string tree data".to_string(), + )); + } + let lines = string_tree_data.unwrap().lines(); + for each in lines { + let mut tokens = each.split("|"); + let parent = tokens.next(); + if parent.is_none() { + return Err(StructureLoadError::FileDataInvalid( + "error in string tree data: parent not present".to_string(), + )); + } + let parent = parent.unwrap().trim().to_string(); + if !result.layout.is_present(&parent) { + result.layout.add_root_level(&parent); + } + while let Some(each) = tokens.next() { + let each = each.trim().to_string(); + result.layout.add_child(&each, &parent); + } + } + } + // ^ STRING TREE (tree that defines shape/structure of it) + // v NODE ELEMENTS BY STRING NAME, FOLLOWED BY TRANSFORM DATA (optional) + 'node_transforms: { + if node_transforms.is_none() { + break 'node_transforms; + } + let mut node_transforms = + node_transforms.unwrap().trim().lines().peekable(); + let mut name = Option::::None; + let mut position = Option::::None; + let mut scale = Option::::None; + let mut rotation = Option::::None; + fn commit_node_transform( + asset: &mut StructureAsset, + name: &Option, + position: &Option, + scale: &Option, + rotation: &Option, + ) { + let pos = if position.is_some() { + position.clone().unwrap() + } else { + Vec3::ZERO + }; + let sca = if scale.is_some() { + scale.clone().unwrap() + } else { + Vec3::ONE + }; + let rot = if rotation.is_some() { + rotation.clone().unwrap() + } else { + Quat::IDENTITY + }; + let str = name.clone().unwrap(); + asset.default_pose_positions.insert( + str, + Transform::with_translation(Transform::IDENTITY, pos) + .with_rotation(rot) + .with_scale(sca), + ); + } + 'readloop: while node_transforms.peek().is_some() { + //load in node transforms + let next_line = node_transforms.next(); + if next_line.is_none() { + break 'readloop; + } + let mut tokens = next_line.unwrap().split("|"); + let identifier = tokens.next().unwrap().trim().to_lowercase(); + let identifier = identifier.as_str(); + match identifier { + //v indicates we are getting the name to be created. should be first, before data relevant to said element + "element" => { + let next_name = tokens.next(); + if next_name.is_none() { + return Err(StructureLoadError::FileDataInvalid( + "error: lack of name after name token".to_string(), + )); + } + let next_name = next_name.unwrap().trim().to_lowercase(); + if name.is_some() + & (position.is_some() + | scale.is_some() + | rotation.is_some()) + { + commit_node_transform( + &mut result, + &name, + &position, + &scale, + &rotation, + ); + } + name = Some(next_name); + if position.is_some() { + position = None; + } + if scale.is_some() { + scale = None; + } + if rotation.is_some() { + rotation = None; + } + } + "position" => { + if name.is_none() { + return Err(StructureLoadError::FileDataInvalid( + "error: name was not supplied before position" + .to_string(), + )); + } + let x = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at X" + .to_string(), + )); + }; + let y = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Y" + .to_string(), + )); + }; + let z = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Z" + .to_string(), + )); + }; + position = Some(Vec3::new(x, y, z)); + } + "scale" => { + if name.is_none() { + return Err(StructureLoadError::FileDataInvalid( + "error: name was not supplied before scale".to_string(), + )); + } + let x = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at X" + .to_string(), + )); + }; + let y = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Y" + .to_string(), + )); + }; + let z = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Z" + .to_string(), + )); + }; + scale = Some(Vec3::new(x, y, z)); + } + "rotation" => { + if name.is_none() { + return Err(StructureLoadError::FileDataInvalid( + "error: name was not supplied before rotation" + .to_string(), + )); + } + let x = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at X" + .to_string(), + )); + }; + let y = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Y" + .to_string(), + )); + }; + let z = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Z" + .to_string(), + )); + }; + let w = if let Ok(res) = tokens.next().unwrap().parse::() { + res + } else { + return Err(StructureLoadError::FileDataInvalid( + "error: structure of positions in node transforms incorrect at Z" + .to_string(), + )); + }; + rotation = Some(Quat::from_array([x, y, z, w])); + } + _ => {} + } + } + if name.is_some() + & (position.is_some() | scale.is_some() | rotation.is_some()) + { + commit_node_transform(&mut result, &name, &position, &scale, &rotation); + } + } + // ^ NODE ELEMENTS BY STRING NAME, FOLLOWED BY TRANSFORM DATA (optional) + // v NODE DATA SUCH AS RELIANT GRIDS (optional) + 'node_attachments: { + if node_attachments.is_none() { + break 'node_attachments; + } + let lines = node_attachments.unwrap().lines(); + for each in lines { + let mut tokens = each.trim().split("|").peekable(); + let name = tokens.next(); + if name.is_none() { + continue; + } + let mut the_rest = String::new(); + while tokens.peek().is_some() { + the_rest += ("|".to_owned() + tokens.next().unwrap()).as_str(); + } + result.element_data.insert( + name.unwrap().to_owned(), + ElementData::Unprocessed(the_rest), + ); + } + } + // ^ NODE DATA SUCH AS RELIANT GRIDS (optional) Err(StructureLoadError::FileDataInvalid("".to_string())) } pub fn save(asset: &StructureAsset) -> Option> { @@ -234,16 +525,19 @@ pub mod serialization { // error if bool is true fn transform_to_file(pos: &Transform, data: &mut String) -> bool { let [x, y, z] = pos.translation.to_array(); - *data += format!("{x}|{y}|{z}").as_str(); + *data += NEWLINE; + *data += format!("position|{x}|{y}|{z}").as_str(); + *data += NEWLINE; let [x, y, z] = pos.scale.to_array(); - *data += format!("|{x}|{y}|{z}").as_str(); + *data += format!("scale|{x}|{y}|{z}").as_str(); + *data += NEWLINE; let [x, y, z, w] = pos.rotation.to_array(); - *data += format!("|{x}|{y}|{z}|{w}").as_str(); + *data += format!("rotation|{x}|{y}|{z}|{w}").as_str(); true } for (name, pos) in &asset.default_pose_positions { data += NEWLINE; - data += format!("{name}|").as_str(); + data += format!("element|{name}").as_str(); if !transform_to_file(pos, &mut data) { return None; }