diff --git a/assets/editor/entities/camera.entity b/assets/editor/entities/camera.entity index 431e0d0..62fdcbb 100644 --- a/assets/editor/entities/camera.entity +++ b/assets/editor/entities/camera.entity @@ -1,6 +1,5 @@ -uuid 739619d7-b8a1-42b4-8803-2b8cfedeebf1 name "Editor Camera" -editor_tag -camera render_target window b90f31a2-34d9-42c2-9e53-646d9c9c6c70 -fly_camera -transform transform 10.0 10.0 10.0 \ No newline at end of file +editorTag +camera target window "window.entity" +flyCamera +transform translation 10.0 10.0 10.0 rotation 0.0 0.0 0.0 1.0 scale 1.0 1.0 1.0 diff --git a/assets/editor/entities/ui_container.entity b/assets/editor/entities/ui_container.entity index d773f03..a048f52 100644 --- a/assets/editor/entities/ui_container.entity +++ b/assets/editor/entities/ui_container.entity @@ -1,4 +1,3 @@ -uuid 08e1a4d9-6c76-471d-af02-1aa7db1b435a -editor_tag -ui_node -target_camera 739619d7-b8a1-42b4-8803-2b8cfedeebf1 \ No newline at end of file +editorTag +uiNode +targetCamera "camera.entity" diff --git a/assets/editor/entities/ui_title.entity b/assets/editor/entities/ui_title.entity index c5e5b78..3cbe8bf 100644 --- a/assets/editor/entities/ui_title.entity +++ b/assets/editor/entities/ui_title.entity @@ -1,4 +1,3 @@ -uuid 0088bc7d-851e-402b-9d20-fadfe5cab106 -editor_tag -ui_text text "Welcome to the editor" color 1.0 1.0 1.0 1.0 -parent 08e1a4d9-6c76-471d-af02-1aa7db1b435a \ No newline at end of file +editorTag +uiText "Welcome to the editor" color #ffffff size 12.0 +parent "ui_container.entity" diff --git a/assets/editor/entities/window.entity b/assets/editor/entities/window.entity index f04551a..830a94f 100644 --- a/assets/editor/entities/window.entity +++ b/assets/editor/entities/window.entity @@ -1,4 +1,3 @@ -uuid b90f31a2-34d9-42c2-9e53-646d9c9c6c70 -editor_tag +editorTag name "Editor Window" -window title "Editor" visible false \ No newline at end of file +window "Editor" visible false diff --git a/assets/levels/00/entities/camera.entity b/assets/levels/00/entities/camera.entity index bc5622c..057a2af 100644 --- a/assets/levels/00/entities/camera.entity +++ b/assets/levels/00/entities/camera.entity @@ -1,4 +1,3 @@ name camera -uuid 2e45b7e9-6722-4d50-8ea5-67f25b8b0f62 transform translation 2.0 2.0 0.0 rotation 0.0 0.0 0.0 1.0 scale 1.0 1.0 1.0 -camera \ No newline at end of file +camera diff --git a/assets/levels/00/entities/van.entity b/assets/levels/00/entities/van.entity index b74cf27..8ef3600 100644 --- a/assets/levels/00/entities/van.entity +++ b/assets/levels/00/entities/van.entity @@ -1,4 +1,3 @@ name van -uuid 5c270e84-814c-4d51-9ccd-ab79d9e01f1d transform translation 0.0 0.0 0.0 rotation 0.0 0.0 0.0 1.0 scale 1.0 1.0 1.0 -model "models/van.glb" "Scene" \ No newline at end of file +model "models/van.glb" "Scene" diff --git a/src/editor.rs b/src/editor.rs index d31f877..7122b4c 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -53,8 +53,9 @@ impl std::convert::From<&EditorState> for bool { } /// Tag component for editor entities -#[derive(Component)] -struct EditorTag; +#[derive(Component, Reflect, Debug, Default)] +#[reflect(Component, Default)] +pub(crate) struct EditorTag; fn toggle_editor_state( curr_state: Res>, @@ -73,15 +74,11 @@ fn toggle_editor_state( } } -fn spawn_editor( - mut _commands: Commands, -) { +fn spawn_editor(mut _commands: Commands) { todo!("Spawn editor"); } -fn despawn_editor( - mut _comands: Commands, -) { +fn despawn_editor(mut _comands: Commands) { todo!("Despawn editor"); } @@ -123,4 +120,4 @@ fn plane_gizmos(mut gizmos: Gizmos) { gizmos.arrow(Vec3::ZERO, Vec3::Y, DARK_GREEN); gizmos.arrow(Vec3::ZERO, Vec3::Z, BLUE); } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 9f0df45..32b2b34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,4 +32,4 @@ fn main() { .add_plugins(save::SavePlugin) .add_plugins(window::WindowPlugin) .run(); -} \ No newline at end of file +} diff --git a/src/parser.rs b/src/parser.rs index 18d7971..d281aba 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,8 +2,6 @@ use crate::prelude::*; #[derive(Error, Debug)] pub(crate) enum SaveEntityParseError { - #[error("Failed to parse Uuid: {0}")] - Uuid(#[from] uuid::Error), #[error("Failed to parse name")] Name, #[error("Failed to parse Transform")] @@ -134,42 +132,21 @@ fn test_parse_name() { } } -#[derive(Component, Clone, Debug, Reflect, PartialEq)] -#[reflect(Component)] -pub(crate) struct EntityUuid { - id: String, -} - -/// -/// Returns a reflected `EntityUuid` -/// -pub(crate) fn parse_save_uuid(line: &str) -> Result, SaveEntityParseError> { - let (remainder, _) = tag("uuid")(line)?; - let id = remainder.trim().into(); - Ok(EntityUuid { id }.clone_value()) -} - -#[test] -fn test_parse_uuid() { - let line = "uuid 1c16ab9a-5f79-4340-8469-4086f69c64f2"; - let parsed = parse_save_uuid(line).unwrap(); - let expected = EntityUuid { - id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into(), - }; - - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); -} - -#[derive(Component, Debug, Default, Reflect, PartialEq)] +#[derive(Debug, Default, Reflect, PartialEq)] #[reflect(Component, PartialEq)] pub(crate) struct SaveModel { gltf_file: PathBuf, scene_name: String, } +impl Component for SaveModel { + const STORAGE_TYPE: StorageType = StorageType::Table; + + fn register_component_hooks(hooks: &mut ComponentHooks) { + todo!("Assign Scene Handle for SaveModel") + } +} + /// /// Returns a reflected `SaveModel` /// @@ -201,12 +178,20 @@ fn test_parse_model() { .unwrap()); } -#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)] +#[derive(Debug, Default, PartialEq, Reflect, Clone)] #[reflect_value(Component, Default, PartialEq)] pub(crate) enum SaveCameraRenderTarget { #[default] Default, - Window(Uuid), + Window(PathBuf), +} + +impl Component for SaveCameraRenderTarget { + const STORAGE_TYPE: StorageType = StorageType::Table; + + fn register_component_hooks(hooks: &mut ComponentHooks) { + todo!("Assign Render Target") + } } /// @@ -217,11 +202,12 @@ pub(crate) fn parse_save_camera(line: &str) -> Result, SaveEnti if let Ok((rem, (_, _target))) = tuple((space1::<&str, ()>, tag("target")))(rem) { if let Ok((rem, (_, _window))) = tuple((space1::<&str, ()>, tag("window")))(rem) { // Camera + target + window + UUID - if let Ok((rem, (_, uuid))) = tuple((space1::<&str, ()>, take(36usize)))(rem) { + if let Ok((rem, (_, path))) = + tuple((space1::<&str, nom::error::Error<&str>>, parse_string))(rem) + { debug_assert!(rem == ""); - let parsed_uuid = Uuid::parse_str(uuid)?; - Ok(SaveCameraRenderTarget::Window(parsed_uuid).clone_value()) + Ok(SaveCameraRenderTarget::Window(path.into()).clone_value()) // Camera + target + widow } else { debug_assert!(rem == ""); @@ -272,10 +258,9 @@ fn test_parse_camera() { assert!(parsed.is_err()); } { - let line = "camera target window 9a1367e0-71e5-4c79-b4ad-02aa44b68af0"; - let target_uuid = Uuid::parse_str("9a1367e0-71e5-4c79-b4ad-02aa44b68af0").unwrap(); + let line = "camera target window \"some.entity\""; let parsed = parse_save_camera(line).unwrap(); - let expected = SaveCameraRenderTarget::Window(target_uuid); + let expected = SaveCameraRenderTarget::Window("some.entity".into()); assert!(expected .clone_value() .reflect_partial_eq(parsed.as_reflect()) @@ -290,10 +275,18 @@ fn test_parse_camera() { /// SaveParent entity which is a reference to which entity this is a child of /// A run-time system converts this to a bevy Parent component -#[derive(Component, PartialEq, Debug, Reflect, Clone)] +#[derive(PartialEq, Debug, Reflect, Clone)] #[reflect_value(Component, PartialEq)] pub(crate) struct SaveParent(String); +impl Component for SaveParent { + const STORAGE_TYPE: StorageType = StorageType::Table; + + fn register_component_hooks(hooks: &mut ComponentHooks) { + todo!("Assign parent for entity") + } +} + /// /// Parses a parent entity with this format: /// ```text @@ -360,13 +353,13 @@ fn test_parse_window() { /// /// The UI Text bundle specified as a sparse subset of a bundle /// ```text -/// text "This is the text" color #abc123 size 12.34 +/// uiText "This is the text" color #abc123 size 12.34 /// ``` /// /// Returns a reflected `Text` /// pub(crate) fn parse_save_ui_text(line: &str) -> Result, SaveEntityParseError> { - let (rem, (_tag_text, _space1, text)) = tuple((tag("text"), space1, parse_string))(line)?; + let (rem, (_tag_text, _space1, text)) = tuple((tag("uiText"), space1, parse_string))(line)?; let (rem, (_space, _tag_color, _space1, _hash, hex_color)) = tuple((space1, tag("color"), space1, char('#'), hex_digit1))(rem)?; @@ -386,7 +379,7 @@ pub(crate) fn parse_save_ui_text(line: &str) -> Result, SaveEnt #[test] fn test_save_ui_text() { - let line = "text \"This is the text\" color #caffee size 14.6"; + let line = "uiText \"This is the text\" color #caffee size 14.6"; let parsed = parse_save_ui_text(line).unwrap(); let expected = Text::from_section( "This is the text", @@ -408,8 +401,10 @@ fn test_save_ui_text() { /// pub(crate) fn parse_save_tag( t: &str, -) -> impl FnOnce(&str) -> Result + '_ { - move |line: &str| -> Result { Ok(tag(t)(line).map(|_| T::default())?) } +) -> impl FnOnce(&str) -> Result, SaveEntityParseError> + '_ { + move |line: &str| -> Result, SaveEntityParseError> { + Ok(tag(t)(line).map(|_| T::default().clone_value())?) + } } #[derive(Component, Reflect, PartialEq, Debug, Default)] @@ -427,13 +422,21 @@ fn test_save_tag() { .unwrap()); } -#[derive(Component, Clone, Debug, Reflect, PartialEq)] +#[derive(Clone, Debug, Reflect, PartialEq)] #[reflect(Component)] pub(crate) struct SaveTargetCamera(String); +impl Component for SaveTargetCamera { + const STORAGE_TYPE: StorageType = StorageType::Table; + + fn register_component_hooks(hooks: &mut ComponentHooks) { + todo!("Assign target camera") + } +} + /// Parses the a SaveTargetCamera which at runtime is converted to a TargetCamera /// ```text -/// target-camera "./level-camera.entity" +/// targetCamera "./level-camera.entity" /// ``` /// /// Returns reflected `SaveTargetCamera` @@ -441,7 +444,7 @@ pub(crate) fn parse_save_target_camera( line: &str, ) -> Result, SaveEntityParseError> { Ok( - tuple((tag("target-camera"), space1, parse_string))(line).map( + tuple((tag("targetCamera"), space1, parse_string))(line).map( |(_, (_, _, target_camera_entity_file))| { SaveTargetCamera(target_camera_entity_file.into()).clone_value() }, @@ -451,7 +454,7 @@ pub(crate) fn parse_save_target_camera( #[test] fn test_target_camera() { - let line = "target-camera \"./level-camera.entity\""; + let line = "targetCamera \"./level-camera.entity\""; let parsed = parse_save_target_camera(line).unwrap(); let expected = SaveTargetCamera("./level-camera.entity".into()); diff --git a/src/prelude.rs b/src/prelude.rs index f745efb..b6c6746 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,7 +9,6 @@ pub(crate) use bevy::{ render::camera::RenderTarget, window::{PrimaryWindow, WindowCloseRequested, WindowRef}, }; -pub(crate) use nom::bytes::complete::take; pub(crate) use nom::character::complete::hex_digit1; pub(crate) use nom::{ branch::alt, @@ -21,6 +20,7 @@ pub(crate) use nom::{ }; pub(crate) use std::path::PathBuf; pub(crate) use thiserror::Error; -pub(crate) use uuid::Uuid; pub(crate) use crate::{conditions::*, parser::*}; + +pub(crate) use bevy::ecs::component::{ComponentHooks, StorageType}; diff --git a/src/save.rs b/src/save.rs index 35ba23c..6b85db4 100644 --- a/src/save.rs +++ b/src/save.rs @@ -5,9 +5,9 @@ pub(crate) struct SavePlugin; impl Plugin for SavePlugin { fn build(&self, app: &mut App) { - app.register_type::() - .register_type::() + app.register_type::() .register_type::() + .register_type::() .init_asset::() .init_asset_loader::() .init_asset_loader::() @@ -32,36 +32,44 @@ pub(crate) struct SaveEntity { impl SaveEntity { fn parse( text: &str, - _load_context: &mut LoadContext, + load_context: &mut LoadContext, ) -> Result { let lines = text.split('\n'); let mut entity = SaveEntity { ..default() }; let fns = [ parse_save_name, parse_save_transform, - parse_save_uuid, parse_save_model, parse_save_camera, parse_save_parent, parse_save_window, parse_save_target_camera, + parse_save_ui_text, + // parse_save_tag::("editor_tag"), ]; - lines.into_iter().for_each(|line| { - // track if this line matched any components - let mut good = false; - - // Run line against all parsers - for f in fns { - if let Ok(v) = f(line) { - entity.components.push(v); - good = true; + lines + .into_iter() + .filter(|line| !line.is_empty()) + .for_each(|line| { + // track if this line matched any components + let mut good = false; + + // Run line against all parsers + for f in fns { + if let Ok(v) = f(line) { + entity.components.push(v); + good = true; + } } - } - if !good { - error!("failed to parse component from line {:?}", line); - } - }); + if !good { + error!( + file = load_context.path().to_str().unwrap(), + line = line, + "failed to parse component", + ); + } + }); Ok(entity) } }