Converted all functions to return Box<dyn Reflect>

this is nice because it makes things a little more uniform.
attempt/001
Elijah Voigt 1 year ago
parent 7947be5cfb
commit 2f9664940d

@ -1,5 +1,3 @@
use nom::character::complete::hex_digit1;
use crate::prelude::*; use crate::prelude::*;
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -14,8 +12,6 @@ pub(crate) enum SaveEntityParseError {
Nom(nom::Err<nom::error::Error<Box<str>>>), Nom(nom::Err<nom::error::Error<Box<str>>>),
#[error("Failed to parse camera")] #[error("Failed to parse camera")]
Camera, Camera,
#[error("Failed to parse marker component")]
Marker,
} }
// Convert Nom error to parse error // Convert Nom error to parse error
@ -49,8 +45,9 @@ fn parse_string(i: &str) -> IResult<&str, &str> {
} }
/// ///
/// Returns reflected `Transform`
/// ///
pub(crate) fn parse_save_transform(line: &str) -> Result<Transform, SaveEntityParseError> { pub(crate) fn parse_save_transform(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (rem, _) = tag("transform")(line)?; let (rem, _) = tag("transform")(line)?;
let mut transform = Transform::default(); let mut transform = Transform::default();
@ -80,7 +77,7 @@ pub(crate) fn parse_save_transform(line: &str) -> Result<Transform, SaveEntityPa
// Assert there are no trailing characters on the line // Assert there are no trailing characters on the line
debug_assert_eq!(curr, ""); debug_assert_eq!(curr, "");
Ok(transform) Ok(transform.clone_value())
} }
#[test] #[test]
@ -93,19 +90,23 @@ fn test_parse_transform() {
scale: Vec3::new(1.1, 1.2, 1.3), scale: Vec3::new(1.1, 1.2, 1.3),
}; };
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
/// ///
/// Returns a reflected `Name`
/// ///
pub(crate) fn parse_save_name(line: &str) -> Result<Name, SaveEntityParseError> { pub(crate) fn parse_save_name(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (remainder, _) = tag("name")(line)?; let (remainder, _) = tag("name")(line)?;
let n = remainder.trim().to_string(); let n = remainder.trim().to_string();
if n.is_empty() { if n.is_empty() {
Err(SaveEntityParseError::Name) Err(SaveEntityParseError::Name)
} else { } else {
let name = Name::new(n); let name = Name::new(n);
Ok(name) Ok(name.clone_value())
} }
} }
@ -116,14 +117,20 @@ fn test_parse_name() {
let parsed = parse_save_name(line).unwrap(); let parsed = parse_save_name(line).unwrap();
let expected = Name::new("Van"); let expected = Name::new("Van");
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
{ {
let line = "name Big Mike"; let line = "name Big Mike";
let parsed = parse_save_name(line).unwrap(); let parsed = parse_save_name(line).unwrap();
let expected = Name::new("Big Mike"); let expected = Name::new("Big Mike");
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
} }
@ -134,11 +141,12 @@ pub(crate) struct EntityUuid {
} }
/// ///
/// Returns a reflected `EntityUuid`
/// ///
pub(crate) fn parse_save_uuid(line: &str) -> Result<EntityUuid, SaveEntityParseError> { pub(crate) fn parse_save_uuid(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (remainder, _) = tag("uuid")(line)?; let (remainder, _) = tag("uuid")(line)?;
let id = remainder.trim().into(); let id = remainder.trim().into();
Ok(EntityUuid { id }) Ok(EntityUuid { id }.clone_value())
} }
#[test] #[test]
@ -149,40 +157,62 @@ fn test_parse_uuid() {
id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into(), id: "1c16ab9a-5f79-4340-8469-4086f69c64f2".into(),
}; };
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
}
#[derive(Component, Debug, Default, Reflect, PartialEq)]
#[reflect(Component, PartialEq)]
pub(crate) struct SaveModel {
gltf_file: PathBuf,
scene_name: String,
} }
/// ///
/// Returns a reflected `SaveModel`
/// ///
pub(crate) fn parse_save_model(line: &str) -> Result<(String, String), SaveEntityParseError> { pub(crate) fn parse_save_model(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (rem, (_, _, gltf_path, _, scene_name)) = let (rem, (_, _, gltf_path, _, scene_name)) =
tuple((tag("model"), space1, parse_string, space1, parse_string))(line)?; tuple((tag("model"), space1, parse_string, space1, parse_string))(line)?;
debug_assert!(rem == ""); debug_assert!(rem == "");
Ok((gltf_path.into(), scene_name.into())) Ok(SaveModel {
gltf_file: gltf_path.into(),
scene_name: scene_name.into(),
}
.clone_value())
} }
#[test] #[test]
fn test_parse_model() { fn test_parse_model() {
let line = "model \"models/foo.glb\" \"My Scene\""; let line = "model \"models/foo.glb\" \"My Scene\"";
let parsed = parse_save_model(line).unwrap(); let parsed = parse_save_model(line).unwrap();
let expected = (String::from("models/foo.glb"), String::from("My Scene")); let expected = SaveModel {
gltf_file: "models/foo.glb".into(),
scene_name: "My Scene".into(),
};
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)] #[derive(Component, Debug, Default, PartialEq, Reflect, Clone)]
#[reflect_value(Component, Default)] #[reflect_value(Component, Default, PartialEq)]
pub(crate) enum SaveCameraRenderTarget { pub(crate) enum SaveCameraRenderTarget {
#[default] #[default]
Default, Default,
Window(Uuid), Window(Uuid),
} }
pub(crate) fn parse_save_camera( ///
line: &str, /// Returns a reflected `SaveCameraRenderTarget
) -> Result<SaveCameraRenderTarget, SaveEntityParseError> { ///
pub(crate) fn parse_save_camera(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
if let Ok((rem, _camera)) = tag::<&str, &str, ()>("camera")(line) { if let Ok((rem, _camera)) = tag::<&str, &str, ()>("camera")(line) {
if let Ok((rem, (_, _target))) = tuple((space1::<&str, ()>, tag("target")))(rem) { if let Ok((rem, (_, _target))) = tuple((space1::<&str, ()>, tag("target")))(rem) {
if let Ok((rem, (_, _window))) = tuple((space1::<&str, ()>, tag("window")))(rem) { if let Ok((rem, (_, _window))) = tuple((space1::<&str, ()>, tag("window")))(rem) {
@ -191,12 +221,12 @@ pub(crate) fn parse_save_camera(
debug_assert!(rem == ""); debug_assert!(rem == "");
let parsed_uuid = Uuid::parse_str(uuid)?; let parsed_uuid = Uuid::parse_str(uuid)?;
Ok(SaveCameraRenderTarget::Window(parsed_uuid)) Ok(SaveCameraRenderTarget::Window(parsed_uuid).clone_value())
// Camera + target + widow // Camera + target + widow
} else { } else {
debug_assert!(rem == ""); debug_assert!(rem == "");
Ok(SaveCameraRenderTarget::Default) Ok(SaveCameraRenderTarget::Default.clone_value())
} }
// camera + target // camera + target
} else { } else {
@ -208,7 +238,7 @@ pub(crate) fn parse_save_camera(
} else { } else {
debug_assert!(rem == ""); debug_assert!(rem == "");
Ok(SaveCameraRenderTarget::Default) Ok(SaveCameraRenderTarget::Default.clone_value())
} }
// Nothing parsed well // Nothing parsed well
} else { } else {
@ -222,13 +252,19 @@ fn test_parse_camera() {
let line = "camera"; let line = "camera";
let parsed = parse_save_camera(line).unwrap(); let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Default; let expected = SaveCameraRenderTarget::Default;
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
{ {
let line = "camera target window"; let line = "camera target window";
let parsed = parse_save_camera(line).unwrap(); let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Default; let expected = SaveCameraRenderTarget::Default;
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
{ {
let line = "camera target"; let line = "camera target";
@ -240,7 +276,10 @@ fn test_parse_camera() {
let target_uuid = Uuid::parse_str("9a1367e0-71e5-4c79-b4ad-02aa44b68af0").unwrap(); let target_uuid = Uuid::parse_str("9a1367e0-71e5-4c79-b4ad-02aa44b68af0").unwrap();
let parsed = parse_save_camera(line).unwrap(); let parsed = parse_save_camera(line).unwrap();
let expected = SaveCameraRenderTarget::Window(target_uuid); let expected = SaveCameraRenderTarget::Window(target_uuid);
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
{ {
let line = "notcamera"; let line = "notcamera";
@ -252,19 +291,23 @@ fn test_parse_camera() {
/// SaveParent entity which is a reference to which entity this is a child of /// 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 /// A run-time system converts this to a bevy Parent component
#[derive(Component, PartialEq, Debug, Reflect, Clone)] #[derive(Component, PartialEq, Debug, Reflect, Clone)]
#[reflect_value(Component)] #[reflect_value(Component, PartialEq)]
pub(crate) struct SaveParent(String); pub(crate) struct SaveParent(String);
///
/// Parses a parent entity with this format: /// Parses a parent entity with this format:
/// ```text /// ```text
/// parent some_other_file.entity /// parent some_other_file.entity
/// ``` /// ```
pub(crate) fn parse_save_parent(line: &str) -> Result<SaveParent, SaveEntityParseError> { ///
/// Returns a reflected `SaveParent`
///
pub(crate) fn parse_save_parent(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (rem, (_, _, parent_file)) = tuple((tag("parent"), space1, parse_string))(line)?; let (rem, (_, _, parent_file)) = tuple((tag("parent"), space1, parse_string))(line)?;
debug_assert!(rem.is_empty()); debug_assert!(rem.is_empty());
Ok(SaveParent(parent_file.into())) Ok(SaveParent(parent_file.into()).clone_value())
} }
#[test] #[test]
@ -272,14 +315,19 @@ fn test_parse_parent() {
let line = "parent \"some_other_file.entity\""; let line = "parent \"some_other_file.entity\"";
let parsed = parse_save_parent(line).unwrap(); let parsed = parse_save_parent(line).unwrap();
let expected = SaveParent("some_other_file.entity".into()); let expected = SaveParent("some_other_file.entity".into());
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
/// ///
/// Parse the Window component (which is very big!) /// Parse the Window component (which is very big!)
/// We only sparsely define the bits that we want to edit (for now) /// We only sparsely define the bits that we want to edit (for now)
/// ///
pub(crate) fn parse_save_window(line: &str) -> Result<Window, SaveEntityParseError> { /// Returns a reflected `Window`
///
pub(crate) fn parse_save_window(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (rem, (_, _, window_title)) = tuple((tag("window"), space1, parse_string))(line)?; let (rem, (_, _, window_title)) = tuple((tag("window"), space1, parse_string))(line)?;
let (rem, (_, _, _, visibility)) = tuple((space1, tag("visible"), space1, parse_bool))(rem)?; let (rem, (_, _, _, visibility)) = tuple((space1, tag("visible"), space1, parse_bool))(rem)?;
@ -290,7 +338,8 @@ pub(crate) fn parse_save_window(line: &str) -> Result<Window, SaveEntityParseErr
title: window_title.into(), title: window_title.into(),
visible: visibility, visible: visibility,
..default() ..default()
}) }
.clone_value())
} }
#[test] #[test]
@ -302,8 +351,10 @@ fn test_parse_window() {
title: "Editor".into(), title: "Editor".into(),
..default() ..default()
}; };
assert_eq!(parsed.visible, expected.visible); assert!(expected
assert_eq!(parsed.title, expected.title); .clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
/// ///
@ -311,7 +362,10 @@ fn test_parse_window() {
/// ```text /// ```text
/// text "This is the text" color #abc123 size 12.34 /// text "This is the text" color #abc123 size 12.34
/// ``` /// ```
pub(crate) fn parse_save_ui_text(line: &str) -> Result<TextBundle, SaveEntityParseError> { ///
/// Returns a reflected `Text`
///
pub(crate) fn parse_save_ui_text(line: &str) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
let (rem, (_tag_text, _space1, text)) = tuple((tag("text"), space1, parse_string))(line)?; let (rem, (_tag_text, _space1, text)) = tuple((tag("text"), space1, parse_string))(line)?;
let (rem, (_space, _tag_color, _space1, _hash, hex_color)) = let (rem, (_space, _tag_color, _space1, _hash, hex_color)) =
@ -327,10 +381,7 @@ pub(crate) fn parse_save_ui_text(line: &str) -> Result<TextBundle, SaveEntityPar
font_size, font_size,
..default() ..default()
}; };
Ok(TextBundle { Ok(Text::from_section(text, style).clone_value())
text: Text::from_section(text, style),
..default()
})
} }
#[test] #[test]
@ -345,20 +396,16 @@ fn test_save_ui_text() {
..default() ..default()
}, },
); );
assert_eq!(parsed.text.sections[0].value, expected.sections[0].value); assert!(expected
assert_eq!( .clone_value()
parsed.text.sections[0].style.color, .reflect_partial_eq(parsed.as_reflect())
expected.sections[0].style.color, .unwrap());
);
assert_eq!(
parsed.text.sections[0].style.font_size,
expected.sections[0].style.font_size,
);
} }
/// ///
/// Returns a parser function for a basic stand-alone tag /// Returns a parser function for a basic stand-alone tag
/// e.g., "editor_tag" or "ui_node" /// e.g., "editor_tag" or "ui_node"
///
pub(crate) fn parse_save_tag<T: Component + Reflect + Default>( pub(crate) fn parse_save_tag<T: Component + Reflect + Default>(
t: &str, t: &str,
) -> impl FnOnce(&str) -> Result<T, SaveEntityParseError> + '_ { ) -> impl FnOnce(&str) -> Result<T, SaveEntityParseError> + '_ {
@ -374,7 +421,10 @@ fn test_save_tag() {
let line = "testing"; let line = "testing";
let parsed = parse_save_tag::<TestingTag>("testing")(line).unwrap(); let parsed = parse_save_tag::<TestingTag>("testing")(line).unwrap();
let expected = TestingTag; let expected = TestingTag;
assert_eq!(parsed, expected); assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }
#[derive(Component, Clone, Debug, Reflect, PartialEq)] #[derive(Component, Clone, Debug, Reflect, PartialEq)]
@ -385,13 +435,15 @@ pub(crate) struct SaveTargetCamera(String);
/// ```text /// ```text
/// target-camera "./level-camera.entity" /// target-camera "./level-camera.entity"
/// ``` /// ```
///
/// Returns reflected `SaveTargetCamera`
pub(crate) fn parse_save_target_camera( pub(crate) fn parse_save_target_camera(
line: &str, line: &str,
) -> Result<SaveTargetCamera, SaveEntityParseError> { ) -> Result<Box<dyn Reflect>, SaveEntityParseError> {
Ok( Ok(
tuple((tag("target-camera"), space1, parse_string))(line).map( tuple((tag("target-camera"), space1, parse_string))(line).map(
|(_, (_, _, target_camera_entity_file))| { |(_, (_, _, target_camera_entity_file))| {
SaveTargetCamera(target_camera_entity_file.into()) SaveTargetCamera(target_camera_entity_file.into()).clone_value()
}, },
)?, )?,
) )
@ -402,5 +454,9 @@ fn test_target_camera() {
let line = "target-camera \"./level-camera.entity\""; let line = "target-camera \"./level-camera.entity\"";
let parsed = parse_save_target_camera(line).unwrap(); let parsed = parse_save_target_camera(line).unwrap();
let expected = SaveTargetCamera("./level-camera.entity".into()); let expected = SaveTargetCamera("./level-camera.entity".into());
assert_eq!(parsed, expected);
assert!(expected
.clone_value()
.reflect_partial_eq(parsed.as_reflect())
.unwrap());
} }

@ -10,14 +10,16 @@ pub(crate) use bevy::{
window::{PrimaryWindow, WindowCloseRequested, WindowRef}, window::{PrimaryWindow, WindowCloseRequested, WindowRef},
}; };
pub(crate) use nom::bytes::complete::take; pub(crate) use nom::bytes::complete::take;
pub(crate) use nom::character::complete::hex_digit1;
pub(crate) use nom::{ pub(crate) use nom::{
branch::{alt, permutation}, branch::alt,
bytes::complete::{tag, take_until1}, bytes::complete::{tag, take_until1},
character::complete::{char, hex_digit1, space1}, character::complete::{char, space1},
number::complete::float, number::complete::float,
sequence::tuple, sequence::tuple,
IResult, IResult,
}; };
pub(crate) use std::path::PathBuf;
pub(crate) use thiserror::Error; pub(crate) use thiserror::Error;
pub(crate) use uuid::Uuid; pub(crate) use uuid::Uuid;

@ -5,8 +5,7 @@ pub(crate) struct SavePlugin;
impl Plugin for SavePlugin { impl Plugin for SavePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app app.register_type::<EntityUuid>()
.register_type::<EntityUuid>()
.register_type::<SaveCameraRenderTarget>() .register_type::<SaveCameraRenderTarget>()
.register_type::<GltfScene>() .register_type::<GltfScene>()
.init_asset::<SaveEntity>() .init_asset::<SaveEntity>()
@ -33,33 +32,34 @@ pub(crate) struct SaveEntity {
impl SaveEntity { impl SaveEntity {
fn parse( fn parse(
text: &str, text: &str,
load_context: &mut LoadContext, _load_context: &mut LoadContext,
) -> Result<SaveEntity, SaveEntityParseError> { ) -> Result<SaveEntity, SaveEntityParseError> {
let lines = text.split('\n'); let lines = text.split('\n');
let mut entity = SaveEntity { ..default() }; 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,
];
lines.into_iter().for_each(|line| { lines.into_iter().for_each(|line| {
// track if this line matched any components
let mut good = false;
if let Ok(name) = parse_save_name(line) { // Run line against all parsers
entity.components.push(name.clone_value()); for f in fns {
} else if let Ok(transform) = parse_save_transform(line) { if let Ok(v) = f(line) {
entity.components.push(transform.clone_value()); entity.components.push(v);
} else if let Ok(uuid) = parse_save_uuid(line) { good = true;
entity.components.push(uuid.clone_value()); }
} else if let Ok((gltf_file, scene_name)) = parse_save_model(line) { }
let gltf_scene = GltfScene { gltf: load_context.load(gltf_file), name: scene_name };
entity.components.push(gltf_scene.clone_value()); if !good {
} else if let Ok(target) = parse_save_camera(line) { error!("failed to parse component from line {:?}", line);
entity.components.push(target.clone_value());
} else if let Ok(parent) = parse_save_parent(line) {
entity.components.push(parent.clone_value());
} else if let Ok(window) = parse_save_window(line) {
entity.components.push(window.clone_value());
// } else if let Ok(ui_text_bundle) = parse_save_ui_text(line) {
// entity.components.push(ui_text_bundle.clone_value());
} else if let Ok(target_camera) = parse_save_target_camera(line) {
entity.components.push(target_camera.clone_value());
} else {
error!("Failed to parse line component `{:?}`", line);
} }
}); });
Ok(entity) Ok(entity)
@ -129,11 +129,11 @@ impl AssetLoader for SaveSceneLoader {
let asset_path = load_context.path().to_path_buf(); let asset_path = load_context.path().to_path_buf();
let parent_dir = asset_path.parent().unwrap(); let parent_dir = asset_path.parent().unwrap();
let _sub_assets: Vec<Handle<SaveEntity>> = s.lines().map(|line| { let _sub_assets: Vec<Handle<SaveEntity>> = s
parent_dir.join(line) .lines()
}).map(|path| { .map(|line| parent_dir.join(line))
load_context.load(path) .map(|path| load_context.load(path))
}).collect(); .collect();
Ok(DynamicScene::default()) Ok(DynamicScene::default())
} }
@ -143,14 +143,10 @@ impl AssetLoader for SaveSceneLoader {
} }
} }
fn test_load_entity(loader: Res<AssetServer>, mut commands: Commands) { fn test_load_entity(loader: Res<AssetServer>, mut commands: Commands) {
let _: Handle<DynamicScene> = loader.load("editor/_.scene"); let _: Handle<DynamicScene> = loader.load("editor/_.scene");
let handle: Handle<SaveEntity> = loader.load("levels/00/entities/van.entity"); let handle: Handle<SaveEntity> = loader.load("levels/00/entities/van.entity");
commands.spawn(( commands.spawn((SpatialBundle { ..default() }, handle));
SpatialBundle { ..default() },
handle,
));
} }
fn spawn_loaded_entities( fn spawn_loaded_entities(

Loading…
Cancel
Save