6/6 load/save functions (untested)

TODO: UI rework to allow loading arbitrary files and saving them. described in what its like to load a file.md
This commit is contained in:
Lillian Vixe 2024-05-29 13:29:05 -07:00
parent 1bb0987120
commit 51805dcbcb

View file

@ -102,8 +102,37 @@ pub mod serialization {
use super::super::{StructureAsset, StructureLoadError};
pub fn load_detect_version(_bytes: Vec<u8>) -> Result<StructureAsset, StructureLoadError> {
return Err(StructureLoadError::FileDataInvalid("".to_string()));
pub fn load_detect_version(bytes: Vec<u8>) -> Result<StructureAsset, StructureLoadError> {
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<StructureAsset, StructureLoadError> {
pub fn load(data: String) -> Result<StructureAsset, StructureLoadError> {
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::<String>::None;
let mut position = Option::<Vec3>::None;
let mut scale = Option::<Vec3>::None;
let mut rotation = Option::<Quat>::None;
fn commit_node_transform(
asset: &mut StructureAsset,
name: &Option<String>,
position: &Option<Vec3>,
scale: &Option<Vec3>,
rotation: &Option<Quat>,
) {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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::<f32>() {
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<Vec<u8>> {
@ -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;
}