From a67beb77bd2fcf0d98f33304c053984b8d4c495b Mon Sep 17 00:00:00 2001 From: Lillian Vixe Date: Mon, 3 Jun 2024 15:13:47 -0700 Subject: [PATCH] finished proof of file load and save. port to multi-grid and multi-structure modality. remaining: selector for structure, selector for grid, exclusivity between the two. transform editor and node-data-editor (grid or light or structure nesting (test for infiniite loop!!)) --- src/vvedit/mod.rs | 10 +- src/vvedit/s_editor_ui.rs | 242 +++++++++++++++++-------------- src/vvedit/s_ui_details.rs | 255 --------------------------------- src/vvlib/s_oct_asset.rs | 1 + src/vvlib/s_structure_asset.rs | 12 +- 5 files changed, 155 insertions(+), 365 deletions(-) delete mode 100644 src/vvedit/s_ui_details.rs diff --git a/src/vvedit/mod.rs b/src/vvedit/mod.rs index 65fc486..7c2a487 100644 --- a/src/vvedit/mod.rs +++ b/src/vvedit/mod.rs @@ -2,14 +2,16 @@ use bevy::{diagnostic::FrameTimeDiagnosticsPlugin, prelude::*, window::WindowResolution}; -use crate::vvlib::s_oct_asset::{self, OctAssetMarker, OctTreeAsset}; +use crate::vvlib::{ + s_oct_asset::{self, OctAssetMarker, OctTreeAsset}, + s_structure_asset::StructureAssetPlugin, +}; mod s_editor_bevy_input_shim; pub mod s_editor_ui; mod s_orbit_camera; pub mod s_string_tree; -pub mod s_ui_details; - +pub mod s_ui_helpers_and_popup; pub fn setup(app: &mut App) -> &mut App { app.add_plugins(DefaultPlugins.set(WindowPlugin { @@ -21,7 +23,6 @@ pub fn setup(app: &mut App) -> &mut App { ..default() })) .add_plugins(s_oct_asset::OctAssetPlugin) - .init_asset::() .add_systems(Startup, crate::vvlib::s_fps_display::setup_fps_counter) .add_systems( Update, @@ -31,6 +32,7 @@ pub fn setup(app: &mut App) -> &mut App { ), ) .add_plugins(FrameTimeDiagnosticsPlugin::default()) + .add_plugins(StructureAssetPlugin) .add_systems(Startup, startup); s_editor_ui::register_edit_ui(app) } diff --git a/src/vvedit/s_editor_ui.rs b/src/vvedit/s_editor_ui.rs index cabaa65..3209e2b 100644 --- a/src/vvedit/s_editor_ui.rs +++ b/src/vvedit/s_editor_ui.rs @@ -9,8 +9,7 @@ use bevy::{ math::Vec3, prelude::default, render::{camera::Camera, color::Color}, - transform::components::{GlobalTransform, Transform}, - utils::hashbrown::HashMap, + transform::components::GlobalTransform, window::{PrimaryWindow, Window}, }; use bevy_egui::{ @@ -21,11 +20,8 @@ use bevy_egui::{ use crate::{ vvedit::s_editor_bevy_input_shim::keybind_codes::REMOVE_VOXEL, vvlib::{ - s_inputs::InputRegister, - s_intersections::octtree_ray_overlap, - s_obb::OBB, - s_oct_asset::OctAssetMarker, - s_structure_asset::{self, StructureAsset}, + s_inputs::InputRegister, s_intersections::octtree_ray_overlap, s_obb::OBB, + s_oct_asset::OctAssetMarker, s_structure_asset::StructureAsset, }, }; use crate::{ @@ -36,36 +32,44 @@ use crate::{ use super::{ s_editor_bevy_input_shim::setup_inputs, s_orbit_camera::orbit_camera::{pan_orbit_camera, spawn_camera}, - s_string_tree::StringTree, - s_ui_details::*, + s_ui_helpers_and_popup::*, }; use std::fmt::Write; -pub struct OctAssetEditData { - path: String, - id: Handle, - has_changed_since_last_save: bool, +pub struct GridEditData { + pub path: String, + pub id: Handle, + pub has_changed_since_last_save: bool, +} +pub struct StructureEditData { + pub path: String, + pub id: Handle, + pub has_changed_since_last_save: bool, } #[derive(Resource)] pub struct EditWindowUIState { brush_color: Hsva, - meshes: Vec, - pub structure: StringTree, + pub grids: Vec, + pub structures: Vec, pub egui: EditWindowEguiState, pub popup: PopupWindowMode, pub selected_structure_element: String, + pub selected_structure: String, + pub selected_grid: String, } impl Default for EditWindowUIState { fn default() -> Self { Self { brush_color: Default::default(), - meshes: Default::default(), - structure: Default::default(), + grids: Default::default(), + structures: Default::default(), egui: Default::default(), popup: Default::default(), selected_structure_element: "".into(), + selected_structure: "".into(), + selected_grid: "".into(), } } } @@ -73,8 +77,9 @@ impl Default for EditWindowUIState { pub enum PopupWindowMode { #[default] None, - EditStructureElement(String, String), // rename from and to, otherwise second string is unused - CreateStructureElement(String, String), // node name, parent node + EditStructureElement(String, String, String), // structure subject, rename from and to, otherwise second string is unused + CreateStructureElement(String, String, String), // structure subject, node name, parent node + LoadFile(String, i32, Vec), // string is current selection from list discovered from disk, number is a timer for refreshing asset list via disk scan } impl PopupWindowMode { pub fn is_none(&self) -> bool { @@ -103,7 +108,7 @@ impl Default for EditWindowEguiState { // refactor into hashmaps of the AssetId impl EditWindowUIState { pub fn name_from_handle(&self, id: Handle) -> Option { - for each in &self.meshes { + for each in &self.grids { if &each.id == &id { return Some(each.path.clone()); } @@ -111,7 +116,7 @@ impl EditWindowUIState { None } pub fn has_changed_from_name(&self, name: &String) -> Option { - for each in &self.meshes { + for each in &self.grids { if &each.path == name { return Some(each.has_changed_since_last_save); } @@ -119,7 +124,7 @@ impl EditWindowUIState { None } pub fn has_changed_from_handle(&self, id: Handle) -> Option { - for each in &self.meshes { + for each in &self.grids { if &each.id == &id { return Some(each.has_changed_since_last_save); } @@ -127,7 +132,7 @@ impl EditWindowUIState { None } pub fn handle_from_name(&self, name: &String) -> Option> { - for each in &self.meshes { + for each in &self.grids { if &each.path == name { return Some(each.id.clone()); } @@ -141,7 +146,7 @@ impl EditWindowUIState { has_changed: bool, ) -> bool { let mut match_count: usize = 0; - for each in &self.meshes { + for each in &self.grids { if &each.path == path { match_count += 1; } else if &each.id == &id { @@ -149,7 +154,7 @@ impl EditWindowUIState { } } if match_count == 1 { - for each in &mut self.meshes { + for each in &mut self.grids { if &each.path == path { each.id = id.clone(); each.has_changed_since_last_save = has_changed; @@ -160,7 +165,7 @@ impl EditWindowUIState { } return true; } else if match_count == 0 { - self.meshes.push(OctAssetEditData { + self.grids.push(GridEditData { path: path.clone(), id, has_changed_since_last_save: has_changed, @@ -178,8 +183,7 @@ pub fn register_edit_ui( ) -> &mut bevy::prelude::App { app.insert_resource(EditWindowUIState { brush_color: egui_color_from(Color::RED), - meshes: Vec::new(), - structure: StringTree::new(), + grids: Vec::new(), ..default() }); app.add_plugins(EguiPlugin); @@ -196,29 +200,17 @@ pub fn startup_system_edit_ui( // formatting comment commands: Commands, mut shared_ui_state: ResMut, + asset_server: ResMut, ) { spawn_camera(commands); - shared_ui_state - .structure - .add_root_level(&String::from("example")); - shared_ui_state - .structure - .add_root_level(&String::from("example2")); - shared_ui_state - .structure - .add(&String::from("c1"), Some(&String::from("example"))); - shared_ui_state - .structure - .add(&String::from("c2"), Some(&String::from("c1"))); - let asset_test = StructureAsset { - layout: shared_ui_state.structure.clone(), - default_pose_positions: HashMap::::new(), - element_data: Default::default(), + let str = "test.vvs"; + let handle = asset_server.load::(str); + let data = StructureEditData { + path: str.into(), + id: handle, + has_changed_since_last_save: false, }; - s_structure_asset::serialization::structures::write_latest_version( - &"test.vvs".to_string(), - &asset_test, - ); + shared_ui_state.structures.push(data); } fn update_ui_scale_factor( mut egui_settings: ResMut, @@ -234,7 +226,7 @@ pub fn edit_click_events( camera_query: Query<(&Camera, &GlobalTransform)>, oct_tree: Query<(&GlobalTransform, &OctAssetMarker)>, windows: Query<&Window>, - mut oct_assets: ResMut>, + mut grid_assets: ResMut>, mut shared_ui_state: ResMut, egui_settings: Res, ) { @@ -252,7 +244,7 @@ pub fn edit_click_events( continue; }; let obb = OBB::from_transform(trans.compute_transform()); - let octtree = oct_assets.get_mut(oct.oct_handle.clone()); + let octtree = grid_assets.get_mut(oct.oct_handle.clone()); if octtree.is_none() { continue; } @@ -373,10 +365,12 @@ pub fn update_asset_mesh_list( pub fn edit_window_ui( mut shared_ui_state: ResMut, mut contexts: EguiContexts, - mut oct_assets: ResMut>, + mut grid_assets: ResMut>, + mut structure_assets: ResMut>, mut pairs: ResMut, windows: Query>, window: Query<&Window>, + mut asset_server: ResMut, ) { shared_ui_state.egui.windows.clear(); let title = String::from("VVEdit"); @@ -407,12 +401,9 @@ pub fn edit_window_ui( } else { for window_entity in &windows { let ctx = contexts.ctx_for_window_mut(window_entity); - let pos = ctx.memory(|memory| { - if let PopupWindowMode::EditStructureElement(_, _) = shared_ui_state.popup { - memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap()) - } else { - None - } + let pos = ctx.memory(|memory| match &shared_ui_state.popup { + PopupWindowMode::None => None, + _ => memory.area_rect(shared_ui_state.egui.popup_identifier.unwrap()), }); if let Some(pos) = pos { shared_ui_state.egui.windows.push(pos); @@ -430,6 +421,9 @@ pub fn edit_window_ui( } response.show(contexts.ctx_mut(), |ui: &mut egui::Ui| { + if ui.button("test directory list popup").clicked() { + shared_ui_state.popup = PopupWindowMode::LoadFile("".into(), 0, Vec::new()); + } ui.label("This tool is in early development."); ScrollArea::vertical().show(ui, |ui| { ui.collapsing("Mesh Tools", |ui| { @@ -445,11 +439,11 @@ pub fn edit_window_ui( ); ui.label(label); let mut color_to_set: Option = None; - for each in &shared_ui_state.meshes { + for each in &shared_ui_state.grids { ui.vertical(|ui| { //color palette clickables. let handle = each.id.clone(); - let asset = oct_assets.get(handle); + let asset = grid_assets.get(handle); if asset.is_some() { let list = { let eoct = asset.unwrap().model.read().unwrap(); @@ -496,7 +490,7 @@ pub fn edit_window_ui( // for pair in &mut pairs.handles { let id = pair.oct_handle.clone(); - let tree = oct_assets.get_mut(id); + let tree = grid_assets.get_mut(id); if tree.is_some() { let tree = tree.unwrap(); { @@ -510,59 +504,94 @@ pub fn edit_window_ui( } } }); - ui.collapsing("Model Structure", |ui| { - ui.vertical(|ui| { - if ui.button("add element").clicked() { - shared_ui_state.popup = PopupWindowMode::CreateStructureElement( - "unnamed".to_owned(), - "".to_owned(), - ); + let mut selected_structure = false; + let mut selection = None; + if shared_ui_state.selected_structure != "" { + for structure in &shared_ui_state.structures { + if structure.path == shared_ui_state.selected_structure { + let asset = structure_assets.get_mut(structure.id.clone()); + if asset.is_some() { + selection = Some(&mut asset.unwrap().layout); + selected_structure = true; + } + break; } - ui.separator(); - if shared_ui_state.selected_structure_element != "" { - if ui.button("Edit Structure of Node").clicked() { - let selection = shared_ui_state.selected_structure_element.clone(); - let mut should_close = false; - if let PopupWindowMode::EditStructureElement(val, _) = - &shared_ui_state.popup - { - if val == &selection { - should_close = true; - } - } - if should_close { - shared_ui_state.popup = PopupWindowMode::None; - } else { - shared_ui_state.popup = PopupWindowMode::EditStructureElement( - shared_ui_state.selected_structure_element.clone(), - shared_ui_state.selected_structure_element.clone(), - ) - } - ui.label( - "Tree Element Selection: ".to_owned() - + &shared_ui_state.selected_structure_element, + } + } + if selected_structure { + let selection = selection.unwrap(); + ui.collapsing("Model Structure", |ui| { + ui.vertical(|ui| { + if ui.button("add element").clicked() { + shared_ui_state.popup = PopupWindowMode::CreateStructureElement( + shared_ui_state.selected_structure.clone(), + "unnamed".to_owned(), + "".to_owned(), ); } - if ui.button("deselect").clicked() { - shared_ui_state.selected_structure_element = "".into(); - } ui.separator(); + if shared_ui_state.selected_structure_element != "" { + if ui.button("Edit Structure of Node").clicked() { + let selection = shared_ui_state.selected_structure_element.clone(); + let mut should_close = false; + if let PopupWindowMode::EditStructureElement(_, val, _) = + &shared_ui_state.popup + { + if val == &selection { + should_close = true; + } + } + if should_close { + shared_ui_state.popup = PopupWindowMode::None; + } else { + shared_ui_state.popup = PopupWindowMode::EditStructureElement( + shared_ui_state.selected_structure.clone(), + shared_ui_state.selected_structure_element.clone(), + shared_ui_state.selected_structure_element.clone(), + ) + } + ui.label( + "Tree Element Selection: ".to_owned() + + &shared_ui_state.selected_structure_element, + ); + } + if ui.button("deselect").clicked() { + shared_ui_state.selected_structure_element = "".into(); + } + ui.separator(); + } + let mut string_selection = + shared_ui_state.selected_structure_element.clone(); + + show_stringtree_selector(ui, selection, &mut string_selection); + shared_ui_state.selected_structure_element = string_selection; + }) + }); + } + ui.collapsing("grid assets", |ui| { + // + for (id, _asset) in (&grid_assets).iter() { + let path = asset_server.get_path(id.untyped()); + if let Some(path) = path { + ui.label(path.to_string().as_str()); } - let mut string_selection = shared_ui_state.selected_structure_element.clone(); - show_stringtree_selector( - ui, - &mut shared_ui_state.structure, - &mut string_selection, - ); - shared_ui_state.selected_structure_element = string_selection; - }) + } + }); + ui.collapsing("structure assets", |ui| { + // + for (id, _asset) in (&structure_assets).iter() { + let path = asset_server.get_path(id.untyped()); + if let Some(path) = path { + ui.label(path.to_string().as_str()); + } + } }); if ui.button("Save Any Changes").clicked() { - for each in &mut shared_ui_state.meshes { + for each in &mut shared_ui_state.grids { if each.has_changed_since_last_save { let handle = each.id.clone(); let path = each.path.clone() + ".vvg"; - let asset = oct_assets.get(handle); + let asset = grid_assets.get(handle); if asset.is_some() { let result = crate::vvlib::s_oct_asset::serialization::meshes::write_latest_version( @@ -578,5 +607,10 @@ pub fn edit_window_ui( } }); }); - show_popup(&mut shared_ui_state, &mut contexts); + show_popup( + &mut shared_ui_state, + &mut contexts, + &mut asset_server, + &mut structure_assets, + ); } diff --git a/src/vvedit/s_ui_details.rs b/src/vvedit/s_ui_details.rs deleted file mode 100644 index 5738613..0000000 --- a/src/vvedit/s_ui_details.rs +++ /dev/null @@ -1,255 +0,0 @@ -use std::mem; - -use bevy::render::color::Color; -use bevy_egui::{ - egui::{ - self, - ecolor::{hsv_from_rgb, rgb_from_hsv}, - epaint::Hsva, - }, - EguiContexts, -}; - -use crate::vvlib::s_identifier_validation::{self, is_valid}; - -use super::{ - s_editor_ui::{EditWindowUIState, PopupWindowMode}, - s_string_tree::{StringTree, StringTreeElement}, -}; - -pub fn color_from(egui_color: Hsva) -> Color { - let rgb = rgb_from_hsv((egui_color.h, egui_color.s, egui_color.v)); - return Color::rgb_from_array(rgb); -} - -pub fn egui_color_from(color: Color) -> Hsva { - let x = hsv_from_rgb([color.r(), color.g(), color.b()]); - - return Hsva::new(x.0, x.1, x.2, 1.); -} - -#[test] -pub fn round_trip_color() { - use rand::Rng; - let mut rng = rand::thread_rng(); - let min = 0.; - let max = 1.; - for _ in 0..10000 { - let r = rng.gen_range(min..max); - let g = rng.gen_range(min..max); - let b = rng.gen_range(min..max); - let mut color = Color::rgb(r, g, b); - let mut egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - egui_color = egui_color_from(color); - color = color_from(egui_color); - assert_eq!((color.r() * 255.).floor(), (r * 255.).floor()); - assert_eq!((color.g() * 255.).floor(), (g * 255.).floor()); - assert_eq!((color.b() * 255.).floor(), (b * 255.).floor()); - } -} - -pub fn show_popup(state: &mut EditWindowUIState, contexts: &mut EguiContexts) { - enum PopupStateChange { - None, - RemoveStructureElement(bool), //keep children(reparenting upward) or drop - } - let mut state_change = PopupStateChange::None; - let mut change_state = None; - let mut reparent = None; - let mut rename_complete = false; - let mut added_valid_name = false; - match &mut state.popup { - PopupWindowMode::None => return, - PopupWindowMode::EditStructureElement(name, rename) => { - //formatting comment - let response = egui::Window::new("edit structure element ".to_owned() + &name.clone()) - .id(state.egui.popup_identifier.unwrap()); - response.show(contexts.ctx_mut(), |ui| { - //formatting comment - let cur = name.clone(); - ui.label("what do you want to do with ".to_owned() + &name + "?"); - ui.horizontal(|ui| { - //. - ui.label("rename element: "); - let mut rename_string = rename.clone(); - ui.text_edit_singleline(&mut rename_string); - if s_identifier_validation::is_valid(rename_string.clone()) { - *rename = rename_string; - } - if ui.button("Confirm and change name").clicked() { - //. - rename_complete = true; - } - }); - ui.horizontal(|ui| { - if ui.button("remove and reparent to parent").clicked() { - state_change = PopupStateChange::RemoveStructureElement(true); - } - if ui.button("remove and drop children").clicked() { - state_change = PopupStateChange::RemoveStructureElement(false); - } - }); - enum Tasks { - MoveElement, - RemoveElement, - DeleteElementWithChildren, - DeleteElementAndReparent, - } - ui.collapsing("Reparent to child of", |ui| { - ui.vertical(|ui| { - for each in state.structure.list_of_elements() { - if each != cur - && Some(&each) != state.structure.parent_of(&cur.clone()) - && !state.structure.is_upstream_of(&cur, &each) - { - if ui.button(&each).clicked() { - reparent = Some((cur.clone(), each)); - change_state = Some(PopupWindowMode::None); - } - } - } - if state.structure.parent_of(&cur).is_some() { - if ui.button("None").clicked() { - reparent = Some((cur.clone(), "".into())); - change_state = Some(PopupWindowMode::None); - } - } - }); - }); - // todo: rename action. edit subject action (mesh, light), remove action (with, without reparenting) - if ui.button("Cancel").clicked() { - change_state = Some(PopupWindowMode::None); - } - }); - } - PopupWindowMode::CreateStructureElement(name, parent) => { - // - let response = egui::Window::new("new structure element ".to_owned() + &name.clone()) - .id(state.egui.popup_identifier.unwrap()); - response.show(contexts.ctx_mut(), |ui| { - ui.label("please name the new structure node."); - let mut newname = name.clone(); - ui.text_edit_singleline(&mut newname); - if is_valid(newname.clone()) && !state.structure.is_present(&newname) { - *name = newname; - } - if ui.button("Confirm and add.").clicked() { - added_valid_name = true; - } - ui.collapsing( - "parent status: ".to_owned() + parent.clone().as_str(), - |ui| { - ui.vertical(|ui| { - ui.radio_value(parent, "".into(), "Root level - no parent"); - for each in state.structure.list_of_elements() { - ui.radio_value(parent, each.clone(), each.clone()); - } - }); - }, - ); - }); - } - } - if change_state.is_some() { - state.popup = change_state.unwrap(); - } - if let Some((cur, next)) = reparent { - if next != "" { - state.structure.move_branch(&cur, &next); - } else { - state.structure.deparent(&cur); - } - return; - } - if rename_complete { - if let PopupWindowMode::EditStructureElement(old, new) = &state.popup { - state.structure.rename(old, new); - if &state.selected_structure_element == old { - state.selected_structure_element = new.clone(); - } - } - state.popup = PopupWindowMode::None; - } - if added_valid_name { - if let PopupWindowMode::CreateStructureElement(name, parent) = &state.popup { - let par = if parent == "" { None } else { Some(parent) }; - state.structure.add(name, par); - } else { - return; - } - state.popup = PopupWindowMode::None; - } - match state_change { - PopupStateChange::None => {} // nothing to do if state does not change - PopupStateChange::RemoveStructureElement(keep_children) => { - let mut consumed = PopupWindowMode::None; - mem::swap(&mut state.popup, &mut consumed); - if let PopupWindowMode::EditStructureElement(subject, _) = consumed { - if keep_children { - state.structure.remove_element_preserve_branch(&subject); - } else { - state.structure.remove_branch(&subject); - } - } - } - } -} - -pub fn show_stringtree_selector(ui: &mut egui::Ui, tree: &StringTree, selection: &mut String) { - for each in &tree.root { - match each { - super::s_string_tree::StringTreeElement::None => {} - super::s_string_tree::StringTreeElement::Element(name, children) => { - ui.horizontal(|ui| { - ui.label(">".to_owned()); - //ui.label(name.clone()); - ui.radio_value(selection, name.clone(), name.clone()); - }); - for each in children.as_ref() { - show_child(ui, each, 1, selection); - } - } - } - } -} -pub fn show_child( - ui: &mut egui::Ui, - subject: &StringTreeElement, - depth: usize, - selection: &mut String, -) { - match subject { - StringTreeElement::None => {} - StringTreeElement::Element(name, children) => { - let mut prec = String::from(""); - for i in 0..depth { - if i == 0 { - prec = prec + "+"; - } else { - prec = prec + "+"; - } - } - prec = prec + ">"; - ui.horizontal(|ui| { - ui.label(prec); - ui.radio_value(selection, name.clone(), name.clone()); - }); - for each in children.as_ref() { - show_child(ui, each, depth + 1, selection); - } - } - } -} diff --git a/src/vvlib/s_oct_asset.rs b/src/vvlib/s_oct_asset.rs index 40726bd..9fe5479 100644 --- a/src/vvlib/s_oct_asset.rs +++ b/src/vvlib/s_oct_asset.rs @@ -384,6 +384,7 @@ pub struct OctAssetPlugin; impl Plugin for OctAssetPlugin { fn build(&self, app: &mut App) { app.init_asset_loader::(); + app.init_asset::(); app.add_systems(Update, (attach_mesh_handle, oct_asset_to_mesh)); app.insert_resource(MeshingOctTreePairs { handles: Vec::new(), diff --git a/src/vvlib/s_structure_asset.rs b/src/vvlib/s_structure_asset.rs index 8394c4a..42ee527 100644 --- a/src/vvlib/s_structure_asset.rs +++ b/src/vvlib/s_structure_asset.rs @@ -1,5 +1,6 @@ use bevy::{ - asset::{Asset, AssetLoader, AssetServer, AsyncReadExt, Handle}, + app::{App, Plugin}, + asset::{Asset, AssetApp, AssetLoader, AssetServer, AsyncReadExt, Handle}, reflect::TypePath, transform::components::Transform, utils::{hashbrown::HashMap, thiserror}, @@ -76,6 +77,13 @@ impl ElementData { } } +pub struct StructureAssetPlugin; +impl Plugin for StructureAssetPlugin { + fn build(&self, app: &mut App) { + app.init_asset_loader::(); + app.init_asset::(); + } +} #[derive(Default)] pub struct StructureLoader { //can anything even be put in here? @@ -454,7 +462,7 @@ pub mod serialization { } } // ^ NODE DATA SUCH AS RELIANT GRIDS (optional) - Err(StructureLoadError::FileDataInvalid("".to_string())) + return Ok(result); } pub fn save(asset: &StructureAsset) -> Option> { const NEWLINE: &str = "\n";