|
|
|
@ -5,258 +5,72 @@ 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.init_asset::<SaveEntity>()
|
|
|
|
app
|
|
|
|
|
|
|
|
.register_type::<EntityUuid>()
|
|
|
|
|
|
|
|
.register_type::<SaveCameraRenderTarget>()
|
|
|
|
|
|
|
|
.register_type::<GltfScene>()
|
|
|
|
|
|
|
|
.init_asset::<SaveEntity>()
|
|
|
|
.init_asset_loader::<SaveEntityLoader>()
|
|
|
|
.init_asset_loader::<SaveEntityLoader>()
|
|
|
|
.add_systems(Startup, test_save_entity)
|
|
|
|
.init_asset_loader::<SaveSceneLoader>()
|
|
|
|
|
|
|
|
.add_systems(Startup, test_load_entity)
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
check_loaded_entity_assets.run_if(on_event::<AssetEvent<SaveEntity>>()),
|
|
|
|
spawn_loaded_entities.run_if(on_event::<AssetEvent<SaveEntity>>()),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Asset, TypePath, Debug, Default)]
|
|
|
|
#[derive(Asset, TypePath, Default)]
|
|
|
|
pub(crate) struct SaveEntity {
|
|
|
|
pub(crate) struct SaveEntity {
|
|
|
|
transform: Option<Transform>,
|
|
|
|
components: Vec<Box<dyn Reflect>>,
|
|
|
|
name: Option<Name>,
|
|
|
|
|
|
|
|
uuid: Option<EntityUuid>,
|
|
|
|
|
|
|
|
model: Option<(Handle<Gltf>, String)>,
|
|
|
|
|
|
|
|
// TODO: Option<bool> feels like an antipattern as this is either Some(true) or None and never Some(false).
|
|
|
|
|
|
|
|
// Either encode more Camera data in this or replace it with Option<()> or just bool.
|
|
|
|
|
|
|
|
camera: Option<bool>,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: SCALABILITY: SaveEntity should maybe be a HashSet or Vec of Box<into Bundle>
|
|
|
|
|
|
|
|
// Then we tell the parse "For each line, run through each of these concrete parsers"
|
|
|
|
|
|
|
|
// If it matches, add it to the set of Box<Bundle>
|
|
|
|
|
|
|
|
// Ironically we basically want DynamicEntity: https://docs.rs/bevy/latest/bevy/scene/struct.DynamicEntity.html
|
|
|
|
|
|
|
|
|
|
|
|
impl SaveEntity {
|
|
|
|
impl SaveEntity {
|
|
|
|
fn parse(
|
|
|
|
fn parse(
|
|
|
|
text: &str,
|
|
|
|
text: &str,
|
|
|
|
load_context: &mut LoadContext,
|
|
|
|
load_context: &mut LoadContext,
|
|
|
|
) -> Result<SaveEntity, parse::SaveEntityParseError> {
|
|
|
|
) -> Result<SaveEntity, SaveEntityParseError> {
|
|
|
|
let lines = text.split('\n');
|
|
|
|
let lines = text.split('\n');
|
|
|
|
let mut entity = SaveEntity { ..default() };
|
|
|
|
let mut entity = SaveEntity { ..default() };
|
|
|
|
lines.into_iter().for_each(|line| {
|
|
|
|
lines.into_iter().for_each(|line| {
|
|
|
|
if let Ok(name) = parse::parse_save_name(line) {
|
|
|
|
|
|
|
|
entity.name = Some(name);
|
|
|
|
if let Ok(name) = parse_save_name(line) {
|
|
|
|
} else if let Ok(transform) = parse::parse_save_transform(line) {
|
|
|
|
entity.components.push(name.clone_value());
|
|
|
|
entity.transform = Some(transform);
|
|
|
|
} else if let Ok(transform) = parse_save_transform(line) {
|
|
|
|
} else if let Ok(uuid) = parse::parse_save_uuid(line) {
|
|
|
|
entity.components.push(transform.clone_value());
|
|
|
|
entity.uuid = Some(EntityUuid(uuid));
|
|
|
|
} else if let Ok(uuid) = parse_save_uuid(line) {
|
|
|
|
} else if let Ok((gltf_path, scene_name)) = parse::parse_save_model(line) {
|
|
|
|
entity.components.push(uuid.clone_value());
|
|
|
|
let handle = load_context.load(gltf_path);
|
|
|
|
} else if let Ok((gltf_file, scene_name)) = parse_save_model(line) {
|
|
|
|
entity.model = Some((handle, scene_name));
|
|
|
|
let gltf_scene = GltfScene { gltf: load_context.load(gltf_file), name: scene_name };
|
|
|
|
} else if let Ok(true) = parse::parse_save_camera(line) {
|
|
|
|
entity.components.push(gltf_scene.clone_value());
|
|
|
|
entity.camera = Some(true);
|
|
|
|
} else if let Ok(target) = parse_save_camera(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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Component, Clone, Debug)]
|
|
|
|
#[derive(Component, Clone, Debug, Reflect, PartialEq)]
|
|
|
|
struct EntityUuid(Uuid);
|
|
|
|
#[reflect(Component)]
|
|
|
|
|
|
|
|
struct GltfScene {
|
|
|
|
mod parse {
|
|
|
|
gltf: Handle<Gltf>,
|
|
|
|
use super::*;
|
|
|
|
name: String,
|
|
|
|
|
|
|
|
|
|
|
|
#[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")]
|
|
|
|
|
|
|
|
Transform,
|
|
|
|
|
|
|
|
#[error("Failed to parse Entity")]
|
|
|
|
|
|
|
|
Nom(nom::Err<nom::error::Error<Box<str>>>),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Convert Nom error to parse error
|
|
|
|
|
|
|
|
// https://stackoverflow.com/a/77974858/3096574
|
|
|
|
|
|
|
|
impl From<nom::Err<nom::error::Error<&str>>> for SaveEntityParseError {
|
|
|
|
|
|
|
|
fn from(err: nom::Err<nom::error::Error<&str>>) -> Self {
|
|
|
|
|
|
|
|
SaveEntityParseError::Nom(err.map_input(|input| input.into()))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_word<'a>(w: &'a str) -> impl Fn(&'a str) -> IResult<&'a str, &'a str> {
|
|
|
|
|
|
|
|
move |i: &'a str| {
|
|
|
|
|
|
|
|
tag(w)(i)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_xyz(i: &str) -> IResult<&str, (f32, f32, f32)> {
|
|
|
|
|
|
|
|
tuple((float, space1, float, space1, float))(i)
|
|
|
|
|
|
|
|
.map(|(s, (x, _, y, _, z))| (s, (x, y, z)))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_wxyz(i: &str) -> IResult<&str, (f32, f32, f32, f32)> {
|
|
|
|
|
|
|
|
tuple((
|
|
|
|
|
|
|
|
float,
|
|
|
|
|
|
|
|
space1,
|
|
|
|
|
|
|
|
float,
|
|
|
|
|
|
|
|
space1,
|
|
|
|
|
|
|
|
float,
|
|
|
|
|
|
|
|
space1,
|
|
|
|
|
|
|
|
float,
|
|
|
|
|
|
|
|
))(i)
|
|
|
|
|
|
|
|
.map(|(s, (w, _, x, _, y, _, z))| (s, (w, x, y, z)))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn parse_string(i: &str) -> IResult<&str, &str> {
|
|
|
|
|
|
|
|
let (rem, (_, out, _)) = tuple((tag("\""), take_until1("\""), tag("\"")))(i)?;
|
|
|
|
|
|
|
|
Ok((rem, out))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// let parsed = parse_save_transform("transform translation 1.0 2.0 3.0 rotation 1.0 0.0 0.0 0.0 scale 1.0 1.0 1.0").unwrap();
|
|
|
|
|
|
|
|
/// let expected = Transform { translation: Vec3::new(1.0, 1.0, 1.0), rotation: Quat::from_xzyw(1.0, 0.0, 0.0, 0.0), scale: Vec3::ONE };
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
pub(crate) fn parse_save_transform(line: &str) -> Result<Transform, SaveEntityParseError> {
|
|
|
|
|
|
|
|
let (rem, _) = tag("transform")(line)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut transform = Transform::default();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut curr = rem.trim_start();
|
|
|
|
|
|
|
|
for _ in 0..3 {
|
|
|
|
|
|
|
|
println!("Curr: {:?}", curr);
|
|
|
|
|
|
|
|
if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("translation"), space1, parse_xyz))(curr.trim_start()) {
|
|
|
|
|
|
|
|
transform.translation = Vec3::new(x, y, z);
|
|
|
|
|
|
|
|
curr = rem.trim_start();
|
|
|
|
|
|
|
|
} else if let Ok((rem, (_, _, (x, y, z, w)))) = tuple((parse_word("rotation"), space1, parse_wxyz))(curr.trim_start()) {
|
|
|
|
|
|
|
|
transform.rotation = Quat::from_xyzw(x, y, z, w);
|
|
|
|
|
|
|
|
curr = rem.trim_start();
|
|
|
|
|
|
|
|
} else if let Ok((rem, (_, _, (x, y, z)))) = tuple((parse_word("scale"), space1, parse_xyz))(curr.trim_start()) {
|
|
|
|
|
|
|
|
transform.scale = Vec3::new(x, y, z);
|
|
|
|
|
|
|
|
curr = rem.trim_start();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return Err(SaveEntityParseError::Transform);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Assert there are no trailing characters on the line
|
|
|
|
|
|
|
|
debug_assert_eq!(curr, "");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(transform)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_parse_transform() {
|
|
|
|
|
|
|
|
let line = "transform translation 1.0 2.0 3.0 rotation 0.1 0.2 0.3 1.0 scale 1.1 1.2 1.3";
|
|
|
|
|
|
|
|
let parsed = parse_save_transform(line).unwrap();
|
|
|
|
|
|
|
|
let expected = Transform {
|
|
|
|
|
|
|
|
translation: Vec3::new(1.0, 2.0, 3.0),
|
|
|
|
|
|
|
|
rotation: Quat::from_xyzw(0.1, 0.2, 0.3, 1.0),
|
|
|
|
|
|
|
|
scale: Vec3::new(1.1, 1.2, 1.3),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// let parsed = parse_save_name("name asfd").unwrap();
|
|
|
|
|
|
|
|
/// let expected = Name::new("asdf");
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
pub(crate) fn parse_save_name(line: &str) -> Result<Name, SaveEntityParseError> {
|
|
|
|
|
|
|
|
let (remainder, _) = tag("name")(line)?;
|
|
|
|
|
|
|
|
let n = remainder.trim().to_string();
|
|
|
|
|
|
|
|
if n.is_empty() {
|
|
|
|
|
|
|
|
Err(SaveEntityParseError::Name)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
let name = Name::new(n);
|
|
|
|
|
|
|
|
Ok(name)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_parse_name() {
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let line = "name Van";
|
|
|
|
|
|
|
|
let parsed = parse_save_name(line).unwrap();
|
|
|
|
|
|
|
|
let expected = Name::new("Van");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let line = "name Big Mike";
|
|
|
|
|
|
|
|
let parsed = parse_save_name(line).unwrap();
|
|
|
|
|
|
|
|
let expected = Name::new("Big Mike");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// let parsed = parse_save_uuid("uuid 339dd18f-761a-4997-b515-ef57f4dc2447").unwrap();
|
|
|
|
|
|
|
|
/// let expected = Uuid::parse_str("339dd18f-761a-4997-b515-ef57f4dc2447").unwrap();
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
pub(crate) fn parse_save_uuid(line: &str) -> Result<Uuid, SaveEntityParseError> {
|
|
|
|
|
|
|
|
let (remainder, _) = tag("uuid")(line)?;
|
|
|
|
|
|
|
|
let uuid = Uuid::try_parse(remainder.trim())?;
|
|
|
|
|
|
|
|
Ok(uuid)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_parse_uuid() {
|
|
|
|
|
|
|
|
let line = "uuid 1c16ab9a-5f79-4340-8469-4086f69c64f2";
|
|
|
|
|
|
|
|
let parsed = parse_save_uuid(line).unwrap();
|
|
|
|
|
|
|
|
let expected = Uuid::parse_str("1c16ab9a-5f79-4340-8469-4086f69c64f2").unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn parse_save_model(line: &str) -> Result<(String, String), SaveEntityParseError> {
|
|
|
|
|
|
|
|
let (rem, (_, _, gltf_name, _, scene_name)) = tuple((
|
|
|
|
|
|
|
|
tag("model"),
|
|
|
|
|
|
|
|
space1,
|
|
|
|
|
|
|
|
parse_string,
|
|
|
|
|
|
|
|
space1,
|
|
|
|
|
|
|
|
parse_string,
|
|
|
|
|
|
|
|
))(line)?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
debug_assert_eq!(rem, "");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok((String::from(gltf_name), String::from(scene_name)))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_parse_model() {
|
|
|
|
|
|
|
|
let line = "model \"models/foo.glb\" \"My Scene\"";
|
|
|
|
|
|
|
|
let parsed = parse_save_model(line).unwrap();
|
|
|
|
|
|
|
|
let expected = (String::from("models/foo.glb"), String::from("My Scene"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn parse_save_camera(line: &str) -> Result<bool, SaveEntityParseError> {
|
|
|
|
|
|
|
|
let (_rem, cam) = tag("camera")(line)?;
|
|
|
|
|
|
|
|
Ok(!cam.is_empty())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn test_parse_camera() {
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let line = "camera";
|
|
|
|
|
|
|
|
let parsed = parse_save_camera(line).unwrap();
|
|
|
|
|
|
|
|
let expected = true;
|
|
|
|
|
|
|
|
assert_eq!(parsed, expected);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let line = "notcamera";
|
|
|
|
|
|
|
|
let parsed = parse_save_camera(line);
|
|
|
|
|
|
|
|
assert!(parsed.is_err());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
#[derive(Default)]
|
|
|
|
@ -267,7 +81,7 @@ enum SaveEntityLoaderError {
|
|
|
|
#[error("Could not load asset: {0}")]
|
|
|
|
#[error("Could not load asset: {0}")]
|
|
|
|
Io(#[from] std::io::Error),
|
|
|
|
Io(#[from] std::io::Error),
|
|
|
|
#[error("Could not parse entity: {0}")]
|
|
|
|
#[error("Could not parse entity: {0}")]
|
|
|
|
Parse(#[from] parse::SaveEntityParseError),
|
|
|
|
Parse(#[from] SaveEntityParseError),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl AssetLoader for SaveEntityLoader {
|
|
|
|
impl AssetLoader for SaveEntityLoader {
|
|
|
|
@ -294,7 +108,44 @@ impl AssetLoader for SaveEntityLoader {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn test_save_entity(loader: Res<AssetServer>, mut commands: Commands) {
|
|
|
|
#[derive(Default)]
|
|
|
|
|
|
|
|
struct SaveSceneLoader;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl AssetLoader for SaveSceneLoader {
|
|
|
|
|
|
|
|
type Asset = DynamicScene;
|
|
|
|
|
|
|
|
type Settings = ();
|
|
|
|
|
|
|
|
type Error = SaveEntityLoaderError;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async fn load<'a>(
|
|
|
|
|
|
|
|
&'a self,
|
|
|
|
|
|
|
|
reader: &'a mut Reader<'_>,
|
|
|
|
|
|
|
|
_settings: &'a (),
|
|
|
|
|
|
|
|
load_context: &'a mut LoadContext<'_>,
|
|
|
|
|
|
|
|
) -> Result<Self::Asset, Self::Error> {
|
|
|
|
|
|
|
|
let mut bytes = Vec::new();
|
|
|
|
|
|
|
|
reader.read_to_end(&mut bytes).await?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let s = std::str::from_utf8(bytes.as_slice()).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let asset_path = load_context.path().to_path_buf();
|
|
|
|
|
|
|
|
let parent_dir = asset_path.parent().unwrap();
|
|
|
|
|
|
|
|
let _sub_assets: Vec<Handle<SaveEntity>> = s.lines().map(|line| {
|
|
|
|
|
|
|
|
parent_dir.join(line)
|
|
|
|
|
|
|
|
}).map(|path| {
|
|
|
|
|
|
|
|
load_context.load(path)
|
|
|
|
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(DynamicScene::default())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn extensions(&self) -> &[&str] {
|
|
|
|
|
|
|
|
&["scene"]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn test_load_entity(loader: Res<AssetServer>, mut commands: Commands) {
|
|
|
|
|
|
|
|
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() },
|
|
|
|
SpatialBundle { ..default() },
|
|
|
|
@ -302,12 +153,11 @@ fn test_save_entity(loader: Res<AssetServer>, mut commands: Commands) {
|
|
|
|
));
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn check_loaded_entity_assets(
|
|
|
|
fn spawn_loaded_entities(
|
|
|
|
query: Query<(Entity, &Handle<SaveEntity>)>,
|
|
|
|
query: Query<(Entity, &Handle<SaveEntity>)>,
|
|
|
|
mut events: EventReader<AssetEvent<SaveEntity>>,
|
|
|
|
mut events: EventReader<AssetEvent<SaveEntity>>,
|
|
|
|
save_entities: Res<Assets<SaveEntity>>,
|
|
|
|
save_entities: Res<Assets<SaveEntity>>,
|
|
|
|
mut commands: Commands,
|
|
|
|
mut commands: Commands,
|
|
|
|
gltfs: Res<Assets<Gltf>>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
events.read().for_each(|event| {
|
|
|
|
events.read().for_each(|event| {
|
|
|
|
if let AssetEvent::LoadedWithDependencies { id } = event {
|
|
|
|
if let AssetEvent::LoadedWithDependencies { id } = event {
|
|
|
|
@ -316,51 +166,15 @@ fn check_loaded_entity_assets(
|
|
|
|
.filter(|(_, handle)| handle.id() == *id)
|
|
|
|
.filter(|(_, handle)| handle.id() == *id)
|
|
|
|
.for_each(|(entity, _handle)| {
|
|
|
|
.for_each(|(entity, _handle)| {
|
|
|
|
let saved = save_entities.get(*id).unwrap();
|
|
|
|
let saved = save_entities.get(*id).unwrap();
|
|
|
|
debug!(
|
|
|
|
|
|
|
|
"Updating entity {:?} ({:?}) because asset changed",
|
|
|
|
|
|
|
|
saved.name, saved.uuid
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get entity with SaveEntity handle
|
|
|
|
let mut e = commands.entity(entity);
|
|
|
|
let mut e = commands.entity(entity);
|
|
|
|
// Apply camera
|
|
|
|
// Clear the entity
|
|
|
|
// Should be applied early to avoid clobbering transform
|
|
|
|
e.despawn_descendants();
|
|
|
|
if let Some(is_camera) = &saved.camera {
|
|
|
|
// Populate with reflected components
|
|
|
|
if *is_camera {
|
|
|
|
saved.components.iter().for_each(|dc| {
|
|
|
|
e.insert(Camera3dBundle { ..default() });
|
|
|
|
e.insert_reflect(dc.clone_value());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
|
|
|
|
e.remove::<(Camera, Camera3d)>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply transform
|
|
|
|
|
|
|
|
if let Some(transform) = &saved.transform {
|
|
|
|
|
|
|
|
// TODO: Only update if different
|
|
|
|
|
|
|
|
e.insert(*transform);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
e.remove::<Transform>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply Name
|
|
|
|
|
|
|
|
if let Some(name) = &saved.name {
|
|
|
|
|
|
|
|
// TODO: Only update if different
|
|
|
|
|
|
|
|
e.insert(name.clone());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
e.remove::<Name>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply Uuid
|
|
|
|
|
|
|
|
if let Some(uuid) = &saved.uuid {
|
|
|
|
|
|
|
|
// TODO: Only update if different
|
|
|
|
|
|
|
|
e.insert(uuid.clone());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
e.remove::<EntityUuid>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply Model
|
|
|
|
|
|
|
|
if let Some((gltf_handle, scene_name)) = &saved.model {
|
|
|
|
|
|
|
|
// Find scene and update
|
|
|
|
|
|
|
|
let gltf = gltfs.get(gltf_handle).unwrap();
|
|
|
|
|
|
|
|
let scene_handle = gltf.named_scenes.get(scene_name.as_str().into()).unwrap();
|
|
|
|
|
|
|
|
e.insert(scene_handle.clone());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
e.remove::<Handle<Scene>>();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|