From 0826d741635d6ecdd0016e83abd96bfab0171e6e Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 25 May 2020 12:03:50 -0700 Subject: [PATCH] props: remove specialization, ignore fields, impl for Handle, fix world round tripping --- assets/scene/load_scene_example.scn | 24 +- crates/bevy_asset/Cargo.toml | 2 + crates/bevy_asset/src/assets.rs | 4 +- crates/bevy_asset/src/handle.rs | 42 +- crates/bevy_asset/src/load_request.rs | 1 + crates/bevy_asset/src/loader.rs | 4 +- .../legion_core/src/guid_entity_allocator.rs | 6 +- .../bevy_property_derive/src/lib.rs | 45 +- crates/bevy_property/src/lib.rs | 2 - crates/bevy_property/src/property.rs | 426 +++++++++++++++--- crates/bevy_scene/src/lib.rs | 4 + crates/bevy_scene/src/scene.rs | 248 +--------- crates/bevy_scene/src/scene_loader.rs | 45 ++ crates/bevy_scene/src/serde.rs | 194 ++++++++ examples/scene/load_scene.rs | 20 +- examples/scene/properties.rs | 31 +- 16 files changed, 768 insertions(+), 330 deletions(-) create mode 100644 crates/bevy_scene/src/scene_loader.rs create mode 100644 crates/bevy_scene/src/serde.rs diff --git a/assets/scene/load_scene_example.scn b/assets/scene/load_scene_example.scn index 3285aaa4c8..c34cf15576 100644 --- a/assets/scene/load_scene_example.scn +++ b/assets/scene/load_scene_example.scn @@ -1,26 +1,30 @@ [ - ( - entity: 1279729879, + + Entity( + id: 1401014920, components: [ + { "type": "load_scene::Test", "x": 3.0, "y": 4.0, - }, - ], + }, ], ), - ( - entity: 1639302665, + Entity( + id: 99763910, components: [ + { "type": "load_scene::Test", "x": 1.0, "y": 2.0, }, + { + "type": "bevy_asset::handle::Handle", + "id": HandleId("edcdd23f-5be5-4dbf-9a6e-9f46b2185570"), + }, { "type": "load_scene::Foo", "value": "hello", - }, - ], - ), -] \ No newline at end of file + }, ], + ),] \ No newline at end of file diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index 9762c9ef91..c96c69c71b 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -11,9 +11,11 @@ filesystem_watcher = ["notify"] [dependencies] bevy_app = { path = "../bevy_app" } bevy_core = { path = "../bevy_core" } +bevy_property = { path = "../bevy_property" } legion = { path = "../bevy_legion" } uuid = { version = "0.8", features = ["v4", "serde"] } +serde = { version = "1", features = ["derive"] } crossbeam-channel = "0.4.2" anyhow = "1.0" thiserror = "1.0" diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index cdb6878c48..b61968ab9f 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -10,13 +10,13 @@ use std::{ path::{Path, PathBuf}, }; -pub enum AssetEvent { +pub enum AssetEvent { Created { handle: Handle }, Modified { handle: Handle }, Removed { handle: Handle }, } -pub struct Assets { +pub struct Assets { assets: HashMap, T>, paths: HashMap>, events: Events>, diff --git a/crates/bevy_asset/src/handle.rs b/crates/bevy_asset/src/handle.rs index f7a4886ba6..870554225a 100644 --- a/crates/bevy_asset/src/handle.rs +++ b/crates/bevy_asset/src/handle.rs @@ -4,9 +4,11 @@ use std::{ }; use std::{any::TypeId, marker::PhantomData}; +use serde::{Serialize, Deserialize}; use uuid::Uuid; +use bevy_property::{Properties, Property, AsProperties}; -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct HandleId(pub Uuid); pub const DEFAULT_HANDLE_ID: HandleId = HandleId(Uuid::from_u128(240940089166493627844978703213080810552)); @@ -17,8 +19,40 @@ impl HandleId { } } -pub struct Handle { +impl Property for HandleId { + fn any(&self) -> &dyn std::any::Any { + self + } + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + fn set(&mut self, value: &dyn Property) { + let value = value.any(); + if let Some(prop) = value.downcast_ref::() { + *self = *prop; + } else { + panic!("prop value is not {}", std::any::type_name::()); + } + } + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } +} + +impl AsProperties for HandleId { + fn as_properties(&self) -> Option<&dyn Properties> { + None + } + +} + +#[derive(Properties)] +pub struct Handle where T: 'static { pub id: HandleId, + #[prop(ignore)] marker: PhantomData, } @@ -137,6 +171,10 @@ impl Clone for Handle { } impl Copy for Handle {} +// SAFE: T is phantom data and Handle::id is an integer +unsafe impl Send for Handle {} +unsafe impl Sync for Handle {} + #[derive(Hash, Copy, Clone, Eq, PartialEq, Debug)] pub struct HandleUntyped { pub id: HandleId, diff --git a/crates/bevy_asset/src/load_request.rs b/crates/bevy_asset/src/load_request.rs index d3eb361a67..183bfa4f57 100644 --- a/crates/bevy_asset/src/load_request.rs +++ b/crates/bevy_asset/src/load_request.rs @@ -20,6 +20,7 @@ pub trait AssetLoadRequestHandler: Send + Sync + 'static { pub struct ChannelAssetHandler where TLoader: AssetLoader, + TAsset: 'static, { sender: Sender>, loader: TLoader, diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 2e3142212f..f0601fdeab 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -30,13 +30,13 @@ pub trait AssetLoader: Send + Sync + 'static { } } -pub struct AssetResult { +pub struct AssetResult { pub result: Result, pub handle: Handle, pub path: PathBuf, } -pub struct AssetChannel { +pub struct AssetChannel { pub sender: Sender>, pub receiver: Receiver>, } diff --git a/crates/bevy_legion/legion_core/src/guid_entity_allocator.rs b/crates/bevy_legion/legion_core/src/guid_entity_allocator.rs index a1b6a7c5a2..b0e9e52320 100644 --- a/crates/bevy_legion/legion_core/src/guid_entity_allocator.rs +++ b/crates/bevy_legion/legion_core/src/guid_entity_allocator.rs @@ -1,11 +1,11 @@ use crate::entity::Entity; use parking_lot::RwLock; -use std::{collections::HashSet, num::Wrapping, sync::Arc}; +use std::{collections::{VecDeque, HashSet}, num::Wrapping, sync::Arc}; #[derive(Default, Debug, Clone)] pub struct GuidEntityAllocator { entities: Arc>>, - next_ids: Arc>>, + next_ids: Arc>>, } impl GuidEntityAllocator { @@ -18,7 +18,7 @@ impl GuidEntityAllocator { /// Allocates a new unused `Entity` ID. pub fn create_entity(&self) -> Entity { let entity = if !self.next_ids.read().is_empty() { - self.next_ids.write().pop().unwrap() + self.next_ids.write().pop_front().unwrap() } else { Entity::new(rand::random::(), Wrapping(1)) }; diff --git a/crates/bevy_property/bevy_property_derive/src/lib.rs b/crates/bevy_property/bevy_property_derive/src/lib.rs index bafbe93ad5..bf9a5227d9 100644 --- a/crates/bevy_property/bevy_property_derive/src/lib.rs +++ b/crates/bevy_property/bevy_property_derive/src/lib.rs @@ -2,10 +2,19 @@ extern crate proc_macro; mod modules; +use darling::FromMeta; use modules::{get_modules, get_path}; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields}; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Field, Fields}; + +#[derive(FromMeta, Debug, Default)] +struct PropAttributeArgs { + #[darling(default)] + pub ignore: Option, +} + +static PROP_ATTRIBUTE_NAME: &str = "prop"; #[proc_macro_derive(Properties, attributes(prop, module))] pub fn derive_properties(input: TokenStream) -> TokenStream { @@ -17,19 +26,47 @@ pub fn derive_properties(input: TokenStream) -> TokenStream { }) => &fields.named, _ => panic!("expected a struct with named fields"), }; + let fields_and_args = fields + .iter() + .map(|f| { + ( + f, + f.attrs + .iter() + .find(|a| { + a.path.get_ident().as_ref().unwrap().to_string() == PROP_ATTRIBUTE_NAME + }) + .map(|a| { + PropAttributeArgs::from_meta(&a.parse_meta().unwrap()) + .unwrap_or_else(|_err| PropAttributeArgs::default()) + }), + ) + }) + .collect::)>>(); + let active_fields = fields_and_args + .iter() + .filter(|(_field, attrs)| { + attrs.is_none() + || match attrs.as_ref().unwrap().ignore { + Some(ignore) => !ignore, + None => true, + } + }) + .map(|(f, _attr)| *f) + .collect::>(); let modules = get_modules(&ast); let bevy_property_path = get_path(&modules.bevy_property); - let field_names = fields + let field_names = active_fields .iter() .map(|field| field.ident.as_ref().unwrap().to_string()) .collect::>(); - let field_idents = fields + let field_idents = active_fields .iter() .map(|field| field.ident.as_ref().unwrap()) .collect::>(); - let field_count = fields.len(); + let field_count = active_fields.len(); let field_indices = (0..field_count).collect::>(); let generics = ast.generics; diff --git a/crates/bevy_property/src/lib.rs b/crates/bevy_property/src/lib.rs index 18f660181f..c5703e6a37 100644 --- a/crates/bevy_property/src/lib.rs +++ b/crates/bevy_property/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(min_specialization)] - mod property; mod properties; mod dynamic_properties; diff --git a/crates/bevy_property/src/property.rs b/crates/bevy_property/src/property.rs index ed0a608413..87a654af3e 100644 --- a/crates/bevy_property/src/property.rs +++ b/crates/bevy_property/src/property.rs @@ -1,5 +1,4 @@ use crate::Properties; -use serde::Serialize; use std::any::Any; pub trait Property: erased_serde::Serialize + Send + Sync + Any + AsProperties + 'static { @@ -23,12 +22,12 @@ pub trait PropertyVal { impl PropertyVal for dyn Property { #[inline] - default fn val(&self) -> Option<&T> { + fn val(&self) -> Option<&T> { self.any().downcast_ref::() } #[inline] - default fn set_val(&mut self, value: T) { + fn set_val(&mut self, value: T) { if let Some(prop) = self.any_mut().downcast_mut::() { *prop = value; } else { @@ -37,81 +36,83 @@ impl PropertyVal for dyn Property { } } -// TODO: remove specialization -impl AsProperties for T -where - T: Clone + Serialize + Send + Sync + Any + 'static, +impl Property for usize { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + + fn set(&mut self, value: &dyn Property) { + let value = value.any(); + if let Some(prop) = value.downcast_ref::() { + *self = *prop; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else if let Some(prop) = value.downcast_ref::() { + *self = *prop as Self; + } else { + panic!("prop value is not {}", std::any::type_name::()); + } + } +} + +impl AsProperties for usize { fn as_properties(&self) -> Option<&dyn Properties> { None } } - -impl Property for T -where - T: Clone + Serialize + Send + Sync + Any + 'static, -{ +impl Property for u64 { #[inline] - default fn any(&self) -> &dyn Any { + fn any(&self) -> &dyn Any { self } #[inline] - default fn any_mut(&mut self) -> &mut dyn Any { + fn any_mut(&mut self) -> &mut dyn Any { self } #[inline] - default fn clone_prop(&self) -> Box { + fn clone_prop(&self) -> Box { Box::new(self.clone()) } #[inline] - default fn set(&mut self, value: &dyn Property) { - if let Some(prop) = value.any().downcast_ref::() { - *self = prop.clone(); - } else { - panic!("prop value is not {}", std::any::type_name::()); - } - } - - #[inline] - default fn apply(&mut self, value: &dyn Property) { + fn apply(&mut self, value: &dyn Property) { self.set(value); } -} -impl Property for usize { - fn set(&mut self, value: &dyn Property) { - let value = value.any(); - if let Some(prop) = value.downcast_ref::() { - *self = *prop; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else if let Some(prop) = value.downcast_ref::() { - *self = *prop as Self; - } else { - panic!("prop value is not {}", std::any::type_name::()); - } - } -} - -impl Property for u64 { fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -140,7 +141,34 @@ impl Property for u64 { } } +impl AsProperties for u64 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for u32 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -169,7 +197,34 @@ impl Property for u32 { } } +impl AsProperties for u32 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for u16 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -198,7 +253,34 @@ impl Property for u16 { } } +impl AsProperties for u16 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for u8 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -227,7 +309,34 @@ impl Property for u8 { } } +impl AsProperties for u8 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for isize { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -256,7 +365,34 @@ impl Property for isize { } } +impl AsProperties for isize +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for i64 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -285,7 +421,34 @@ impl Property for i64 { } } +impl AsProperties for i64 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for i32 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -314,7 +477,34 @@ impl Property for i32 { } } +impl AsProperties for i32 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for i16 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -343,7 +533,34 @@ impl Property for i16 { } } +impl AsProperties for i16 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for i8 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -372,7 +589,34 @@ impl Property for i8 { } } +impl AsProperties for i8 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for f32 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -385,7 +629,34 @@ impl Property for f32 { } } +impl AsProperties for f32 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + impl Property for f64 { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + fn set(&mut self, value: &dyn Property) { let value = value.any(); if let Some(prop) = value.downcast_ref::() { @@ -397,3 +668,46 @@ impl Property for f64 { } } } + +impl AsProperties for f64 +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + +impl Property for String { + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + + #[inline] + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } + + fn set(&mut self, value: &dyn Property) { + let value = value.any(); + if let Some(prop) = value.downcast_ref::() { + *self = prop.clone(); + } + } +} + +impl AsProperties for String +{ + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} \ No newline at end of file diff --git a/crates/bevy_scene/src/lib.rs b/crates/bevy_scene/src/lib.rs index 77551e3c35..eee2f8b292 100644 --- a/crates/bevy_scene/src/lib.rs +++ b/crates/bevy_scene/src/lib.rs @@ -1,7 +1,11 @@ mod component_registry; mod scene; +mod scene_loader; +pub mod serde; + pub use component_registry::*; pub use scene::*; +pub use scene_loader::*; use bevy_app::{AppBuilder, AppPlugin}; use bevy_asset::AddAsset; diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 5fe0019eb7..8f074b3fb9 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -1,25 +1,19 @@ -use crate::{ComponentRegistry, PropertyTypeRegistryContext}; +use crate::ComponentRegistry; use anyhow::Result; -use bevy_app::FromResources; -use bevy_asset::AssetLoader; -use bevy_property::{DynamicProperties, PropertyTypeRegistry, DynamicPropertiesDeserializer}; -use legion::prelude::{Entity, Resources, World}; -use serde::{ - de::{DeserializeSeed, SeqAccess, Visitor, MapAccess, Error}, - Serialize, - Deserialize -}; -use std::{cell::RefCell, num::Wrapping, path::Path, rc::Rc}; +use bevy_property::DynamicProperties; +use legion::prelude::World; +use serde::Serialize; +use std::num::Wrapping; use thiserror::Error; #[derive(Default)] pub struct Scene { - pub entities: Vec, + pub entities: Vec, } #[derive(Serialize)] -pub struct SceneEntity { - pub entity: u32, +pub struct Entity { + pub id: u32, pub components: Vec, } @@ -45,8 +39,8 @@ impl Scene { component_storage.components(*component_type_id).unwrap(); for (index, entity) in component_storage.entities().iter().enumerate() { if index == entities.len() { - entities.push(SceneEntity { - entity: entity.index(), + entities.push(Entity { + id: entity.index(), components: Vec::new(), }) } @@ -77,7 +71,7 @@ impl Scene { world.entity_allocator.push_next_ids( self.entities .iter() - .map(|e| Entity::new(e.entity, Wrapping(1))), + .map(|e| legion::prelude::Entity::new(e.id, Wrapping(1))), ); for scene_entity in self.entities.iter() { // TODO: use EntityEntry when legion refactor is finished @@ -95,223 +89,3 @@ impl Scene { Ok(()) } } - -impl Serialize for Scene { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.entities.serialize(serializer) - } -} - -pub struct SceneDeserializer<'a> { - pub property_type_registry: &'a PropertyTypeRegistry, - pub current_type_name: Rc>>, -} - -impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> { - type Value = Scene; - fn deserialize(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let mut scene = Scene::default(); - scene.entities = deserializer.deserialize_seq(SceneEntitySeqVisiter { - property_type_registry: self.property_type_registry, - current_type_name: self.current_type_name, - })?; - - Ok(scene) - } -} - -struct SceneEntitySeqVisiter<'a> { - pub property_type_registry: &'a PropertyTypeRegistry, - pub current_type_name: Rc>>, -} - -impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisiter<'a> { - type Value = Vec; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("list of entities") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut entities = Vec::new(); - while let Some(entity) = seq.next_element_seed(SceneEntityDeserializer { - property_type_registry: self.property_type_registry, - current_type_name: self.current_type_name.clone(), - })? { - entities.push(entity); - } - - Ok(entities) - } -} - -pub struct SceneEntityDeserializer<'a> { - pub property_type_registry: &'a PropertyTypeRegistry, - pub current_type_name: Rc>>, -} - -impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> { - type Value = SceneEntity; - fn deserialize(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_struct("", &["entity", "components"], SceneEntityVisiter { - property_type_registry: self.property_type_registry, - current_type_name: self.current_type_name, - }) - } -} - - -#[derive(Deserialize)] -#[serde(field_identifier, rename_all = "lowercase")] -enum EntityField { - Entity, - Components, -} - -pub const ENTITY_FIELD_ENTITY: &str = "entity"; -pub const ENTITY_FIELD_COMPONENTS: &str = "components"; - -struct SceneEntityVisiter<'a> { - pub property_type_registry: &'a PropertyTypeRegistry, - pub current_type_name: Rc>>, -} - -impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> { - type Value = SceneEntity; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("entities") - } - - fn visit_map(self, mut map: A) -> Result - where A: MapAccess<'de> { - let mut entity = None; - let mut components = None; - while let Some(key) = map.next_key()? { - match key { - EntityField::Entity => { - if entity.is_some() { - return Err(Error::duplicate_field(ENTITY_FIELD_ENTITY)); - } - entity = Some(map.next_value::()?); - } - EntityField::Components => { - if components.is_some() { - return Err(Error::duplicate_field(ENTITY_FIELD_COMPONENTS)); - } - - components = Some(map.next_value_seed(ComponentVecDeserializer { - current_type_name: self.current_type_name.clone(), - property_type_registry: self.property_type_registry - })?); - } - } - } - - let entity = entity - .as_ref() - .ok_or_else(|| Error::missing_field(ENTITY_FIELD_ENTITY))?; - - let components = components - .take() - .ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?; - Ok(SceneEntity { - entity: *entity, - components, - }) - } -} - -pub struct ComponentVecDeserializer<'a> { - pub property_type_registry: &'a PropertyTypeRegistry, - pub current_type_name: Rc>>, -} - -impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> { - type Value = Vec; - fn deserialize(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_seq(ComponentSeqVisiter { - property_type_registry: self.property_type_registry, - current_type_name: self.current_type_name, - }) - } -} - - -struct ComponentSeqVisiter<'a> { - pub property_type_registry: &'a PropertyTypeRegistry, - pub current_type_name: Rc>>, -} - -impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> { - type Value = Vec; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("list of components") - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut dynamic_properties = Vec::new(); - while let Some(entity) = seq.next_element_seed(DynamicPropertiesDeserializer { - current_type_name: self.current_type_name.clone(), - property_type_registry: self.property_type_registry - })? { - dynamic_properties.push(entity); - } - - Ok(dynamic_properties) - } -} - - -pub struct SceneLoader { - property_type_registry: PropertyTypeRegistryContext, -} -impl FromResources for SceneLoader { - fn from_resources(resources: &Resources) -> Self { - let property_type_registry = resources.get::().unwrap(); - SceneLoader { - property_type_registry: property_type_registry.clone(), - } - } -} - -impl AssetLoader for SceneLoader { - fn from_bytes(&self, _asset_path: &Path, bytes: Vec) -> Result { - let registry = self.property_type_registry.value.read().unwrap(); - let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap(); - let current_type_name = Rc::new(RefCell::new(None)); - let scene_deserializer = SceneDeserializer { - property_type_registry: ®istry, - current_type_name: current_type_name.clone(), - }; - let mut callback = |ident: &Option<&[u8]>| { - let mut last_type_name = current_type_name.borrow_mut(); - *last_type_name = ident.map(|i| String::from_utf8(i.to_vec()).unwrap()); - }; - deserializer.set_callback(&mut callback); - - - let scene = scene_deserializer.deserialize(&mut deserializer).unwrap(); - Ok(scene) - } - fn extensions(&self) -> &[&str] { - static EXTENSIONS: &[&str] = &["scn"]; - EXTENSIONS - } -} diff --git a/crates/bevy_scene/src/scene_loader.rs b/crates/bevy_scene/src/scene_loader.rs new file mode 100644 index 0000000000..f454b7a359 --- /dev/null +++ b/crates/bevy_scene/src/scene_loader.rs @@ -0,0 +1,45 @@ +use crate::{serde::SceneDeserializer, PropertyTypeRegistryContext, Scene}; +use anyhow::Result; +use bevy_app::FromResources; +use bevy_asset::AssetLoader; +use legion::prelude::Resources; +use serde::de::DeserializeSeed; +use std::{cell::RefCell, path::Path, rc::Rc}; + +pub struct SceneLoader { + property_type_registry: PropertyTypeRegistryContext, +} +impl FromResources for SceneLoader { + fn from_resources(resources: &Resources) -> Self { + let property_type_registry = resources.get::().unwrap(); + SceneLoader { + property_type_registry: property_type_registry.clone(), + } + } +} + +impl AssetLoader for SceneLoader { + fn from_bytes(&self, _asset_path: &Path, bytes: Vec) -> Result { + let registry = self.property_type_registry.value.read().unwrap(); + let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap(); + let current_type_name = Rc::new(RefCell::new(None)); + let scene_deserializer = SceneDeserializer { + property_type_registry: ®istry, + current_type_name: current_type_name.clone(), + }; + + // this callback is executed whenever an explicit type name is encountered in a map + let mut callback = |ident: &Option<&[u8]>| { + let mut last_type_name = current_type_name.borrow_mut(); + *last_type_name = ident.map(|i| String::from_utf8(i.to_vec()).unwrap()); + }; + deserializer.set_callback(&mut callback); + + let scene = scene_deserializer.deserialize(&mut deserializer).unwrap(); + Ok(scene) + } + fn extensions(&self) -> &[&str] { + static EXTENSIONS: &[&str] = &["scn"]; + EXTENSIONS + } +} diff --git a/crates/bevy_scene/src/serde.rs b/crates/bevy_scene/src/serde.rs new file mode 100644 index 0000000000..4383f21db9 --- /dev/null +++ b/crates/bevy_scene/src/serde.rs @@ -0,0 +1,194 @@ +use crate::{Entity, Scene}; +use anyhow::Result; +use bevy_property::{DynamicProperties, DynamicPropertiesDeserializer, PropertyTypeRegistry}; +use serde::{ + de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor}, + Deserialize, Serialize, +}; +use std::{cell::RefCell, rc::Rc}; + +impl Serialize for Scene { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.entities.serialize(serializer) + } +} + +pub struct SceneDeserializer<'a> { + pub property_type_registry: &'a PropertyTypeRegistry, + pub current_type_name: Rc>>, +} + +impl<'a, 'de> DeserializeSeed<'de> for SceneDeserializer<'a> { + type Value = Scene; + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let mut scene = Scene::default(); + scene.entities = deserializer.deserialize_seq(SceneEntitySeqVisiter { + property_type_registry: self.property_type_registry, + current_type_name: self.current_type_name, + })?; + + Ok(scene) + } +} + +struct SceneEntitySeqVisiter<'a> { + pub property_type_registry: &'a PropertyTypeRegistry, + pub current_type_name: Rc>>, +} + +impl<'a, 'de> Visitor<'de> for SceneEntitySeqVisiter<'a> { + type Value = Vec; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("list of entities") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut entities = Vec::new(); + while let Some(entity) = seq.next_element_seed(SceneEntityDeserializer { + property_type_registry: self.property_type_registry, + current_type_name: self.current_type_name.clone(), + })? { + entities.push(entity); + } + + Ok(entities) + } +} + +pub struct SceneEntityDeserializer<'a> { + pub property_type_registry: &'a PropertyTypeRegistry, + pub current_type_name: Rc>>, +} + +impl<'a, 'de> DeserializeSeed<'de> for SceneEntityDeserializer<'a> { + type Value = Entity; + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_struct( + "Entity", + &["id", "components"], + SceneEntityVisiter { + property_type_registry: self.property_type_registry, + current_type_name: self.current_type_name, + }, + ) + } +} + +#[derive(Deserialize)] +#[serde(field_identifier, rename_all = "lowercase")] +enum EntityField { + Id, + Components, +} + +pub const ENTITY_FIELD_ID: &str = "id"; +pub const ENTITY_FIELD_COMPONENTS: &str = "components"; + +struct SceneEntityVisiter<'a> { + pub property_type_registry: &'a PropertyTypeRegistry, + pub current_type_name: Rc>>, +} + +impl<'a, 'de> Visitor<'de> for SceneEntityVisiter<'a> { + type Value = Entity; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("entities") + } + + fn visit_map(self, mut map: A) -> Result + where + A: MapAccess<'de>, + { + let mut id = None; + let mut components = None; + while let Some(key) = map.next_key()? { + match key { + EntityField::Id => { + if id.is_some() { + return Err(Error::duplicate_field(ENTITY_FIELD_ID)); + } + id = Some(map.next_value::()?); + } + EntityField::Components => { + if components.is_some() { + return Err(Error::duplicate_field(ENTITY_FIELD_COMPONENTS)); + } + + components = Some(map.next_value_seed(ComponentVecDeserializer { + current_type_name: self.current_type_name.clone(), + property_type_registry: self.property_type_registry, + })?); + } + } + } + + let entity = id + .as_ref() + .ok_or_else(|| Error::missing_field(ENTITY_FIELD_ID))?; + + let components = components + .take() + .ok_or_else(|| Error::missing_field(ENTITY_FIELD_COMPONENTS))?; + Ok(Entity { + id: *entity, + components, + }) + } +} + +pub struct ComponentVecDeserializer<'a> { + pub property_type_registry: &'a PropertyTypeRegistry, + pub current_type_name: Rc>>, +} + +impl<'a, 'de> DeserializeSeed<'de> for ComponentVecDeserializer<'a> { + type Value = Vec; + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_seq(ComponentSeqVisiter { + property_type_registry: self.property_type_registry, + current_type_name: self.current_type_name, + }) + } +} + +struct ComponentSeqVisiter<'a> { + pub property_type_registry: &'a PropertyTypeRegistry, + pub current_type_name: Rc>>, +} + +impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> { + type Value = Vec; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("list of components") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut dynamic_properties = Vec::new(); + while let Some(entity) = seq.next_element_seed(DynamicPropertiesDeserializer { + current_type_name: self.current_type_name.clone(), + property_type_registry: self.property_type_registry, + })? { + dynamic_properties.push(entity); + } + + Ok(dynamic_properties) + } +} diff --git a/examples/scene/load_scene.rs b/examples/scene/load_scene.rs index 5bdd64d7dc..e3aa0e26e6 100644 --- a/examples/scene/load_scene.rs +++ b/examples/scene/load_scene.rs @@ -1,14 +1,18 @@ use bevy::prelude::*; use bevy_scene::ComponentRegistryContext; use serde::Serialize; +use bevy_asset::HandleId; fn main() { App::build() .add_default_plugins() // Registering components informs Bevy that they exist. This allows them to be used when loading scenes // This step is only required if you want to load your components from scene files. + // In the future registered components will also be usable from the Bevy editor. .register_component::() .register_component::() + .register_component::>() + .register_property_type::() .add_startup_system(load_scene) // .add_startup_system(serialize_scene) .run(); @@ -25,16 +29,6 @@ struct Foo { pub value: String, } -#[derive(Serialize)] -struct Ahh { - pub x: Vec, -} - -#[derive(Serialize)] -struct A { - pub x: f32, -} - fn load_scene(world: &mut World, resources: &mut Resources) { let asset_server = resources.get::().unwrap(); let mut scenes = resources.get_mut::>().unwrap(); @@ -56,6 +50,7 @@ fn serialize_scene(world: &mut World, resources: &mut Resources) { x: 1.0, y: 2.0, }) + .add(Handle::::new()) .add(Foo { value: "hello".to_string() }) @@ -67,6 +62,9 @@ fn serialize_scene(world: &mut World, resources: &mut Resources) { let scene = Scene::from_world(world, &component_registry.value.read().unwrap()); let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true); - let ron_string = ron::ser::to_string_pretty(&scene, pretty_config).unwrap(); + let mut buf = Vec::new(); + let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), true).unwrap(); + scene.serialize(&mut serializer).unwrap(); + let ron_string = String::from_utf8(buf).unwrap(); println!("{}", ron_string); } \ No newline at end of file diff --git a/examples/scene/properties.rs b/examples/scene/properties.rs index b4840b9c79..d5bd152267 100644 --- a/examples/scene/properties.rs +++ b/examples/scene/properties.rs @@ -1,5 +1,5 @@ use bevy::prelude::*; -use bevy_property::ron::deserialize_dynamic_properties; +use bevy_property::{AsProperties, ron::deserialize_dynamic_properties}; use bevy_scene::PropertyTypeRegistryContext; use serde::{Deserialize, Serialize}; @@ -29,6 +29,35 @@ pub struct CustomProperty { a: usize, } +impl Property for CustomProperty { + fn any(&self) -> &dyn std::any::Any { + self + } + fn any_mut(&mut self) -> &mut dyn std::any::Any { + self + } + fn clone_prop(&self) -> Box { + Box::new(self.clone()) + } + fn set(&mut self, value: &dyn Property) { + let value = value.any(); + if let Some(prop) = value.downcast_ref::() { + *self = prop.clone(); + } else { + panic!("prop value is not {}", std::any::type_name::()); + } + } + fn apply(&mut self, value: &dyn Property) { + self.set(value); + } +} + +impl AsProperties for CustomProperty { + fn as_properties(&self) -> Option<&dyn Properties> { + None + } +} + fn setup(property_type_registry: Res) { let mut test = Test { a: 1,