mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 14:08:32 +00:00
props: migrate scenes to props. loading / saving worlds from / to props.
This commit is contained in:
parent
f36a67ee96
commit
4c306e6d48
12 changed files with 195 additions and 859 deletions
|
@ -1,32 +1,26 @@
|
|||
[
|
||||
(
|
||||
entity: 2309003120,
|
||||
entity: 3072676124,
|
||||
components: [
|
||||
(
|
||||
type: "Test",
|
||||
data: (
|
||||
x: 3,
|
||||
y: 4,
|
||||
),
|
||||
),
|
||||
(
|
||||
type: "Foo",
|
||||
data: (
|
||||
value: "hi",
|
||||
),
|
||||
),
|
||||
{
|
||||
"type": "load_scene::Test",
|
||||
"x": 3.0,
|
||||
"y": 4.0,
|
||||
},
|
||||
],
|
||||
),
|
||||
(
|
||||
entity: 4238063392,
|
||||
entity: 3949176536,
|
||||
components: [
|
||||
(
|
||||
type: "Test",
|
||||
data: (
|
||||
x: 3,
|
||||
y: 4,
|
||||
),
|
||||
),
|
||||
{
|
||||
"type": "load_scene::Test",
|
||||
"x": 1.0,
|
||||
"y": 2.0,
|
||||
},
|
||||
{
|
||||
"type": "load_scene::Foo",
|
||||
"value": "hello",
|
||||
},
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{DynamicProperties, Property, PropertyVal};
|
||||
use serde::{ser::SerializeMap, Serialize};
|
||||
|
||||
pub trait Properties {
|
||||
pub trait Properties: Property {
|
||||
fn type_name(&self) -> &str;
|
||||
fn prop(&self, name: &str) -> Option<&dyn Property>;
|
||||
fn prop_mut(&mut self, name: &str) -> Option<&mut dyn Property>;
|
||||
|
@ -63,11 +63,11 @@ impl<P> PropertiesVal for P
|
|||
where
|
||||
P: Properties,
|
||||
{
|
||||
// #[inline]
|
||||
#[inline]
|
||||
fn prop_val<T: 'static>(&self, name: &str) -> Option<&T> {
|
||||
self.prop(name).and_then(|p| p.any().downcast_ref::<T>())
|
||||
}
|
||||
// #[inline]
|
||||
#[inline]
|
||||
fn set_prop_val<T: 'static>(&mut self, name: &str, value: T) {
|
||||
if let Some(prop) = self.prop_mut(name) {
|
||||
prop.set_val(value);
|
||||
|
|
|
@ -12,5 +12,5 @@ legion = { path = "../bevy_legion", features = ["serialize"] }
|
|||
serde = { version = "1.0", features = ["derive"]}
|
||||
erased-serde = "0.3"
|
||||
ron = { path = "../ron" }
|
||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||
anyhow = "1.0"
|
||||
anyhow = "1.0"
|
||||
thiserror = "1.0"
|
|
@ -1,15 +1,17 @@
|
|||
use bevy_app::AppBuilder;
|
||||
use bevy_property::{Properties, Property};
|
||||
use legion::{
|
||||
prelude::{Entity, World},
|
||||
storage::{ArchetypeDescription, ComponentResourceSet, ComponentTypeId},
|
||||
storage::{Component, ComponentTypeId, ComponentResourceSet},
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use serde::{de::DeserializeSeed, ser::Serialize, Deserialize};
|
||||
use std::{collections::HashMap, marker::PhantomData, ptr::NonNull, sync::{RwLock, Arc}};
|
||||
use crate::world::ComponentSeqDeserializer;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ComponentRegistryContext {
|
||||
pub value: Arc<RwLock<ComponentRegistry>>,
|
||||
pub value: Arc<RwLock<ComponentRegistry>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -22,7 +24,7 @@ pub struct ComponentRegistry {
|
|||
impl ComponentRegistry {
|
||||
pub fn register<T>(&mut self)
|
||||
where
|
||||
T: Clone + Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>,
|
||||
T: Properties + Component + Default,
|
||||
{
|
||||
let registration = ComponentRegistration::of::<T>();
|
||||
self.short_names
|
||||
|
@ -52,52 +54,24 @@ impl ComponentRegistry {
|
|||
#[derive(Clone)]
|
||||
pub struct ComponentRegistration {
|
||||
pub ty: ComponentTypeId,
|
||||
pub comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||
pub individual_comp_serialize_fn:
|
||||
fn(&ComponentResourceSet, usize, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||
pub comp_deserialize_fn: fn(
|
||||
deserializer: &mut dyn erased_serde::Deserializer,
|
||||
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
) -> Result<(), erased_serde::Error>,
|
||||
pub individual_comp_deserialize_fn: fn(
|
||||
deserializer: &mut dyn erased_serde::Deserializer,
|
||||
&mut World,
|
||||
Entity,
|
||||
) -> Result<(), erased_serde::Error>,
|
||||
pub register_comp_fn: fn(&mut ArchetypeDescription),
|
||||
pub component_add_fn: fn(&mut World, Entity, &dyn Property),
|
||||
pub component_properties_fn: fn(&ComponentResourceSet, usize) -> &dyn Properties,
|
||||
pub short_name: &'static str,
|
||||
}
|
||||
|
||||
impl ComponentRegistration {
|
||||
pub fn of<T: Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static>() -> Self {
|
||||
pub fn of<T: Properties + Component + Default>() -> Self {
|
||||
let ty = ComponentTypeId::of::<T>();
|
||||
Self {
|
||||
ty,
|
||||
comp_serialize_fn: |comp_storage, serialize_fn| {
|
||||
// it's safe because we know this is the correct type due to lookup
|
||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||
serialize_fn(&*slice);
|
||||
},
|
||||
individual_comp_serialize_fn: |comp_storage, index: usize, serialize_fn| {
|
||||
// it's safe because we know this is the correct type due to lookup
|
||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||
serialize_fn(&slice[index]);
|
||||
},
|
||||
comp_deserialize_fn: |deserializer, get_next_storage_fn| {
|
||||
let comp_seq_deser = ComponentSeqDeserializer::<T> {
|
||||
get_next_storage_fn,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
comp_seq_deser.deserialize(deserializer)?;
|
||||
Ok(())
|
||||
},
|
||||
individual_comp_deserialize_fn: |deserializer, world, entity| {
|
||||
let component = erased_serde::deserialize::<T>(deserializer)?;
|
||||
component_add_fn: |world: &mut World, entity: Entity, property: &dyn Property| {
|
||||
let mut component = T::default();
|
||||
component.apply(property);
|
||||
world.add_component(entity, component).unwrap();
|
||||
Ok(())
|
||||
},
|
||||
register_comp_fn: |desc| {
|
||||
desc.register_component::<T>();
|
||||
component_properties_fn: |component_resource_set: &ComponentResourceSet, index: usize| {
|
||||
// the type has been looked up by the caller, so this is safe
|
||||
unsafe { &component_resource_set.data_slice::<T>()[index] }
|
||||
},
|
||||
short_name: ty.0.split("::").last().unwrap(),
|
||||
}
|
||||
|
@ -107,16 +81,19 @@ impl ComponentRegistration {
|
|||
pub trait RegisterComponent {
|
||||
fn register_component<T>(&mut self) -> &mut Self
|
||||
where
|
||||
T: Clone + Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>;
|
||||
T: Properties + Component + Default;
|
||||
}
|
||||
|
||||
impl RegisterComponent for AppBuilder {
|
||||
fn register_component<T>(&mut self) -> &mut Self
|
||||
where
|
||||
T: Clone + Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>,
|
||||
T: Properties + Component + Default,
|
||||
{
|
||||
{
|
||||
let registry_context = self.resources().get_mut::<ComponentRegistryContext>().unwrap();
|
||||
let registry_context = self
|
||||
.resources()
|
||||
.get_mut::<ComponentRegistryContext>()
|
||||
.unwrap();
|
||||
registry_context.value.write().unwrap().register::<T>();
|
||||
}
|
||||
self
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
mod component_registry;
|
||||
mod scene;
|
||||
mod serde;
|
||||
pub use crate::serde::*;
|
||||
pub use component_registry::*;
|
||||
pub use scene::*;
|
||||
|
||||
|
|
|
@ -1,59 +1,104 @@
|
|||
use crate::{ComponentRegistry, ComponentRegistryContext, SceneDeserializer};
|
||||
use crate::ComponentRegistry;
|
||||
use anyhow::Result;
|
||||
use bevy_app::FromResources;
|
||||
use bevy_asset::AssetLoader;
|
||||
use bevy_property::DynamicProperties;
|
||||
use legion::prelude::{Resources, World};
|
||||
use serde::de::DeserializeSeed;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use legion::prelude::{Entity, World};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{num::Wrapping, path::Path};
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct DynamicScene {
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
pub struct Scene {
|
||||
pub entities: Vec<SceneEntity>,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SceneAddError {
|
||||
#[error("Scene contains an unregistered component.")]
|
||||
UnregisteredComponent { type_name: String },
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn from_world(world: &World, component_registry: &ComponentRegistry) -> Self {
|
||||
let mut scene = Scene::default();
|
||||
for archetype in world.storage().archetypes() {
|
||||
for chunkset in archetype.chunksets() {
|
||||
for component_storage in chunkset.occupied() {
|
||||
let mut entities = Vec::new();
|
||||
for (component_type_id, _component_meta) in archetype.description().components()
|
||||
{
|
||||
if let Some(component_registration) =
|
||||
component_registry.get(component_type_id)
|
||||
{
|
||||
let component_resource_set =
|
||||
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(),
|
||||
components: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
let properties = (component_registration.component_properties_fn)(
|
||||
&component_resource_set,
|
||||
index,
|
||||
);
|
||||
|
||||
entities[index].components.push(properties.to_dynamic());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scene.entities.extend(entities.drain(..));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scene
|
||||
}
|
||||
|
||||
pub fn add_to_world(
|
||||
&self,
|
||||
world: &mut World,
|
||||
component_registry: &ComponentRegistry,
|
||||
) -> Result<(), SceneAddError> {
|
||||
world.entity_allocator.push_next_ids(
|
||||
self.entities
|
||||
.iter()
|
||||
.map(|e| Entity::new(e.entity, Wrapping(1))),
|
||||
);
|
||||
for scene_entity in self.entities.iter() {
|
||||
// TODO: use EntityEntry when legion refactor is finished
|
||||
let entity = world.insert((), vec![()])[0];
|
||||
for component in scene_entity.components.iter() {
|
||||
let component_registration = component_registry
|
||||
.get_with_full_name(&component.type_name)
|
||||
.ok_or_else(|| SceneAddError::UnregisteredComponent {
|
||||
type_name: component.type_name.to_string(),
|
||||
})?;
|
||||
(component_registration.component_add_fn)(world, entity, component);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SceneEntity {
|
||||
pub entity: u32,
|
||||
pub components: Vec<DynamicProperties>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Scene {
|
||||
pub world: World,
|
||||
}
|
||||
|
||||
pub struct SceneLoader {
|
||||
component_registry: Arc<RwLock<ComponentRegistry>>,
|
||||
}
|
||||
|
||||
impl FromResources for SceneLoader {
|
||||
fn from_resources(resources: &Resources) -> Self {
|
||||
let component_registry = resources
|
||||
.get::<ComponentRegistryContext>()
|
||||
.expect("SceneLoader requires the ComponentRegistry resource.");
|
||||
SceneLoader {
|
||||
component_registry: component_registry.value.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct SceneLoader;
|
||||
|
||||
impl AssetLoader<Scene> for SceneLoader {
|
||||
fn from_bytes(&self, _asset_path: &Path, bytes: Vec<u8>) -> Result<Scene> {
|
||||
let mut deserializer = ron::de::Deserializer::from_bytes(&bytes).unwrap();
|
||||
let mut scene = Scene::default();
|
||||
let scene_deserializer = SceneDeserializer {
|
||||
component_registry: &self.component_registry.read().unwrap(),
|
||||
scene: &mut scene,
|
||||
};
|
||||
|
||||
scene_deserializer.deserialize(&mut deserializer).unwrap();
|
||||
|
||||
Ok(scene)
|
||||
let entities = Vec::<SceneEntity>::deserialize(&mut deserializer).unwrap();
|
||||
Ok(Scene { entities })
|
||||
}
|
||||
fn extensions(&self) -> &[&str] {
|
||||
static EXTENSIONS: &[&str] = &["scn"];
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
mod scene_de;
|
||||
mod scene_ser;
|
||||
pub mod world;
|
||||
|
||||
pub use scene_de::*;
|
||||
pub use scene_ser::*;
|
|
@ -1,288 +0,0 @@
|
|||
use crate::{ComponentRegistration, ComponentRegistry, Scene};
|
||||
use legion::prelude::{Entity, World};
|
||||
use serde::{
|
||||
de::{DeserializeSeed, Error, MapAccess, SeqAccess, Visitor},
|
||||
Deserialize,
|
||||
};
|
||||
use std::num::Wrapping;
|
||||
|
||||
pub struct SceneDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub scene: &'a mut Scene,
|
||||
}
|
||||
|
||||
impl<'de> DeserializeSeed<'de> for SceneDeserializer<'de> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(EntitySeqVisiter {
|
||||
world: &mut self.scene.world,
|
||||
component_registry: &self.component_registry,
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct EntitySeqVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for EntitySeqVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("list of entities")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
while let Some(()) = seq.next_element_seed(EntityDeserializer {
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})? {}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
}
|
||||
|
||||
|
||||
pub const ENTITY_FIELD_ENTITY: &str = "entity";
|
||||
pub const ENTITY_FIELD_COMPONENTS: &str = "components";
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for EntityDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_struct(
|
||||
"Entity",
|
||||
&[ENTITY_FIELD_ENTITY, ENTITY_FIELD_COMPONENTS],
|
||||
EntityVisiter {
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for EntityVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("entity struct")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<(), V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
let mut entity = None;
|
||||
let mut components = false;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
EntityField::Entity => {
|
||||
if entity.is_some() {
|
||||
return Err(Error::duplicate_field(ENTITY_FIELD_ENTITY));
|
||||
}
|
||||
let id = map.next_value()?;
|
||||
self.world
|
||||
.entity_allocator
|
||||
.push_next_ids((&[Entity::new(id, Wrapping(1))]).iter().map(|e| (*e)));
|
||||
entity = Some(self.world.insert((), vec![()])[0]);
|
||||
}
|
||||
EntityField::Components => {
|
||||
if components {
|
||||
return Err(Error::duplicate_field(ENTITY_FIELD_COMPONENTS));
|
||||
}
|
||||
|
||||
let entity = entity.ok_or_else(|| Error::missing_field(ENTITY_FIELD_ENTITY))?;
|
||||
// this is just a placeholder value to protect against duplicates
|
||||
components = true;
|
||||
map.next_value_seed(ComponentSeqDeserializer {
|
||||
entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "lowercase")]
|
||||
enum EntityField {
|
||||
Entity,
|
||||
Components,
|
||||
}
|
||||
|
||||
struct ComponentSeqDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for ComponentSeqDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(ComponentSeqVisiter {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentSeqVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for ComponentSeqVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("list of components")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
while let Some(()) = seq.next_element_seed(ComponentDeserializer {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
})? {}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
struct ComponentDeserializer<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for ComponentDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_struct(
|
||||
"Component",
|
||||
&[COMPONENT_FIELD_TYPE, COMPONENT_FIELD_DATA],
|
||||
ComponentVisiter {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registry: self.component_registry,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "lowercase")]
|
||||
enum ComponentField {
|
||||
Type,
|
||||
Data,
|
||||
}
|
||||
|
||||
pub const COMPONENT_FIELD_TYPE: &str = "type";
|
||||
pub const COMPONENT_FIELD_DATA: &str = "data";
|
||||
|
||||
struct ComponentVisiter<'a> {
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> Visitor<'de> for ComponentVisiter<'a> {
|
||||
type Value = ();
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("component")
|
||||
}
|
||||
|
||||
fn visit_map<V>(self, mut map: V) -> Result<(), V::Error>
|
||||
where
|
||||
V: MapAccess<'de>,
|
||||
{
|
||||
let mut component_type = None;
|
||||
let mut component_data = false;
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
ComponentField::Type => {
|
||||
if component_type.is_some() {
|
||||
return Err(Error::duplicate_field(COMPONENT_FIELD_TYPE));
|
||||
}
|
||||
component_type = Some(map.next_value::<String>()?);
|
||||
}
|
||||
ComponentField::Data => {
|
||||
if component_data {
|
||||
return Err(Error::duplicate_field(COMPONENT_FIELD_DATA));
|
||||
}
|
||||
|
||||
let component_type = component_type
|
||||
.as_ref()
|
||||
.ok_or_else(|| Error::missing_field(COMPONENT_FIELD_TYPE))?;
|
||||
let component_registration = self
|
||||
.component_registry
|
||||
.get_with_short_name(component_type)
|
||||
.ok_or_else(|| Error::custom(format!("Component '{}' has not been registered. Consider registering it with AppBuilder::register_component::<{}>()", component_type, component_type)))?;
|
||||
// this is just a placeholder value to protect against duplicates
|
||||
component_data = true;
|
||||
map.next_value_seed(ComponentDataDeserializer {
|
||||
entity: self.entity,
|
||||
world: self.world,
|
||||
component_registration,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentDataDeserializer<'a> {
|
||||
pub component_registration: &'a ComponentRegistration,
|
||||
pub world: &'a mut World,
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
impl<'a, 'de> DeserializeSeed<'de> for ComponentDataDeserializer<'a> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
if let Err(err) = (self.component_registration.individual_comp_deserialize_fn)(
|
||||
&mut erased_serde::Deserializer::erase(deserializer),
|
||||
self.world,
|
||||
self.entity,
|
||||
) {
|
||||
return Err(Error::custom(err.to_string()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
use crate::{ComponentRegistry, Scene, ComponentRegistration};
|
||||
use legion::{
|
||||
prelude::Entity,
|
||||
storage::{ComponentMeta, ComponentResourceSet, ComponentStorage, ComponentTypeId},
|
||||
};
|
||||
use serde::ser::{Serialize, SerializeSeq, SerializeStruct};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct SerializableScene<'a> {
|
||||
pub scene: &'a Scene,
|
||||
pub component_registry: &'a ComponentRegistry,
|
||||
}
|
||||
|
||||
impl<'a> SerializableScene<'a> {
|
||||
pub fn new(scene: &'a Scene, component_registry: &'a ComponentRegistry) -> Self {
|
||||
SerializableScene {
|
||||
scene,
|
||||
component_registry,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for SerializableScene<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(self.scene.world.iter_entities().count()))?;
|
||||
for archetype in self.scene.world.storage().archetypes() {
|
||||
for chunkset in archetype.chunksets() {
|
||||
for component_storage in chunkset.occupied() {
|
||||
for (index, entity) in component_storage.entities().iter().enumerate() {
|
||||
seq.serialize_element(&WorldEntity {
|
||||
index,
|
||||
archetype_components: archetype.description().components(),
|
||||
component_registry: &self.component_registry,
|
||||
component_storage,
|
||||
entity: *entity,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct WorldEntity<'a> {
|
||||
archetype_components: &'a [(ComponentTypeId, ComponentMeta)],
|
||||
component_registry: &'a ComponentRegistry,
|
||||
component_storage: &'a ComponentStorage,
|
||||
entity: Entity,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for WorldEntity<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Entity", 2)?;
|
||||
state.serialize_field("entity", &self.entity.index())?;
|
||||
state.serialize_field(
|
||||
"components",
|
||||
&EntityComponents {
|
||||
archetype_components: self.archetype_components,
|
||||
component_registry: self.component_registry,
|
||||
component_storage: self.component_storage,
|
||||
index: self.index,
|
||||
},
|
||||
)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityComponents<'a> {
|
||||
index: usize,
|
||||
archetype_components: &'a [(ComponentTypeId, ComponentMeta)],
|
||||
component_storage: &'a ComponentStorage,
|
||||
component_registry: &'a ComponentRegistry,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for EntityComponents<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(Some(self.archetype_components.len()))?;
|
||||
for (component_type, _) in self.archetype_components.iter() {
|
||||
seq.serialize_element(&EntityComponent {
|
||||
index: self.index,
|
||||
component_resource_set: self.component_storage.components(*component_type).unwrap(),
|
||||
component_registration: self.component_registry.get(component_type).unwrap(),
|
||||
})?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct EntityComponent<'a> {
|
||||
index: usize,
|
||||
component_resource_set: &'a ComponentResourceSet,
|
||||
component_registration: &'a ComponentRegistration,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for EntityComponent<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut state = serializer.serialize_struct("Component", 2)?;
|
||||
state.serialize_field(
|
||||
"type",
|
||||
&ComponentName(self.component_registration.short_name),
|
||||
)?;
|
||||
state.serialize_field(
|
||||
"data",
|
||||
&ComponentData {
|
||||
index: self.index,
|
||||
component_registration: self.component_registration,
|
||||
component_resource_set: self.component_resource_set,
|
||||
},
|
||||
)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
struct ComponentName(&'static str);
|
||||
|
||||
impl<'a> Serialize for ComponentName {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.0)
|
||||
}
|
||||
}
|
||||
struct ComponentData<'a> {
|
||||
index: usize,
|
||||
component_resource_set: &'a ComponentResourceSet,
|
||||
component_registration: &'a ComponentRegistration,
|
||||
}
|
||||
|
||||
impl<'a> Serialize for ComponentData<'a> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let mut result = None;
|
||||
let serializer = RefCell::new(Some(serializer));
|
||||
(self.component_registration.individual_comp_serialize_fn)(
|
||||
self.component_resource_set,
|
||||
self.index,
|
||||
&mut |serialize| {
|
||||
result = Some(erased_serde::serialize(
|
||||
serialize,
|
||||
serializer.borrow_mut().take().unwrap(),
|
||||
));
|
||||
},
|
||||
);
|
||||
|
||||
result.unwrap()
|
||||
}
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
// adapted from https://github.com/TomGillen/legion/blob/master/examples/serde.rs
|
||||
|
||||
use crate::ComponentRegistry;
|
||||
use legion::{
|
||||
entity::EntityIndex,
|
||||
guid_entity_allocator::GuidEntityAllocator,
|
||||
prelude::*,
|
||||
storage::{
|
||||
ArchetypeDescription, ComponentMeta, ComponentResourceSet, ComponentTypeId, TagMeta,
|
||||
TagStorage, TagTypeId,
|
||||
},
|
||||
};
|
||||
use serde::{
|
||||
de::{self, DeserializeSeed, IgnoredAny, Visitor},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
use std::{cell::RefCell, marker::PhantomData, num::Wrapping, ptr::NonNull};
|
||||
|
||||
struct ComponentDeserializer<'de, T: Deserialize<'de>> {
|
||||
ptr: *mut T,
|
||||
_marker: PhantomData<&'de T>,
|
||||
}
|
||||
|
||||
impl<'de, T: Deserialize<'de> + 'static> DeserializeSeed<'de> for ComponentDeserializer<'de, T> {
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = <T as Deserialize<'de>>::deserialize(deserializer)?;
|
||||
unsafe {
|
||||
std::ptr::write(self.ptr, value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ComponentSeqDeserializer<'a, T> {
|
||||
pub get_next_storage_fn: &'a mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
pub _marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> DeserializeSeed<'de>
|
||||
for ComponentSeqDeserializer<'a, T>
|
||||
{
|
||||
type Value = ();
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(self)
|
||||
}
|
||||
}
|
||||
impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> Visitor<'de>
|
||||
for ComponentSeqDeserializer<'a, T>
|
||||
{
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("sequence of objects")
|
||||
}
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
let size = seq.size_hint();
|
||||
for _ in 0..size.unwrap_or(std::usize::MAX) {
|
||||
match (self.get_next_storage_fn)() {
|
||||
Some((storage_ptr, storage_len)) => {
|
||||
let storage_ptr = storage_ptr.as_ptr() as *mut T;
|
||||
for idx in 0..storage_len {
|
||||
let element_ptr = unsafe { storage_ptr.offset(idx as isize) };
|
||||
|
||||
if let None = seq.next_element_seed(ComponentDeserializer {
|
||||
ptr: element_ptr,
|
||||
_marker: PhantomData,
|
||||
})? {
|
||||
panic!(
|
||||
"expected {} elements in chunk but only {} found",
|
||||
storage_len, idx
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(_) = seq.next_element::<IgnoredAny>()? {
|
||||
panic!("unexpected element when there was no storage space available");
|
||||
} else {
|
||||
// No more elements and no more storage - that's what we want!
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SerializedArchetypeDescription {
|
||||
tag_types: Vec<String>,
|
||||
component_types: Vec<String>,
|
||||
}
|
||||
|
||||
impl legion::serialize::ser::WorldSerializer for ComponentRegistry {
|
||||
fn can_serialize_tag(&self, _ty: &TagTypeId, _meta: &TagMeta) -> bool {
|
||||
false
|
||||
}
|
||||
fn can_serialize_component(&self, ty: &ComponentTypeId, _meta: &ComponentMeta) -> bool {
|
||||
self.get(ty).is_some()
|
||||
}
|
||||
fn serialize_archetype_description<S: Serializer>(
|
||||
&self,
|
||||
serializer: S,
|
||||
archetype_desc: &ArchetypeDescription,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
let tags_to_serialize = archetype_desc
|
||||
.tags()
|
||||
.iter()
|
||||
.map(|(tag_type_id, _)| tag_type_id.0.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
let components_to_serialize = archetype_desc
|
||||
.components()
|
||||
.iter()
|
||||
.map(|(component_type_id, _)| component_type_id.0.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
SerializedArchetypeDescription {
|
||||
tag_types: tags_to_serialize,
|
||||
component_types: components_to_serialize,
|
||||
}
|
||||
.serialize(serializer)
|
||||
}
|
||||
fn serialize_components<S: Serializer>(
|
||||
&self,
|
||||
serializer: S,
|
||||
component_type: &ComponentTypeId,
|
||||
_component_meta: &ComponentMeta,
|
||||
components: &ComponentResourceSet,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
if let Some(reg) = self.get(component_type) {
|
||||
let result = RefCell::new(None);
|
||||
let serializer = RefCell::new(Some(serializer));
|
||||
{
|
||||
let mut result_ref = result.borrow_mut();
|
||||
(reg.comp_serialize_fn)(components, &mut |serialize| {
|
||||
result_ref.replace(erased_serde::serialize(
|
||||
serialize,
|
||||
serializer.borrow_mut().take().unwrap(),
|
||||
));
|
||||
});
|
||||
}
|
||||
return result.borrow_mut().take().unwrap();
|
||||
}
|
||||
panic!(
|
||||
"received unserializable type {:?}, this should be filtered by can_serialize",
|
||||
component_type
|
||||
);
|
||||
}
|
||||
fn serialize_tags<S: Serializer>(
|
||||
&self,
|
||||
_serializer: S,
|
||||
tag_type: &TagTypeId,
|
||||
_tag_meta: &TagMeta,
|
||||
_tags: &TagStorage,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
panic!(
|
||||
"received unserializable type {:?}, this should be filtered by can_serialize",
|
||||
tag_type
|
||||
);
|
||||
}
|
||||
fn serialize_entities<S: Serializer>(
|
||||
&self,
|
||||
serializer: S,
|
||||
entities: &[Entity],
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
serializer.collect_seq(entities.iter().map(|e| e.index()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> legion::serialize::de::WorldDeserializer for ComponentRegistry {
|
||||
fn deserialize_archetype_description<'de, D: Deserializer<'de>>(
|
||||
&self,
|
||||
deserializer: D,
|
||||
) -> Result<ArchetypeDescription, <D as Deserializer<'de>>::Error> {
|
||||
let serialized_desc =
|
||||
<SerializedArchetypeDescription as Deserialize>::deserialize(deserializer)?;
|
||||
let mut desc = ArchetypeDescription::default();
|
||||
|
||||
for comp in serialized_desc.component_types {
|
||||
if let Some(reg) = self.get_with_full_name(&comp) {
|
||||
(reg.register_comp_fn)(&mut desc);
|
||||
}
|
||||
}
|
||||
Ok(desc)
|
||||
}
|
||||
fn deserialize_components<'de, D: Deserializer<'de>>(
|
||||
&self,
|
||||
deserializer: D,
|
||||
component_type: &ComponentTypeId,
|
||||
_component_meta: &ComponentMeta,
|
||||
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||
) -> Result<(), <D as Deserializer<'de>>::Error> {
|
||||
if let Some(reg) = self.get(component_type) {
|
||||
let mut erased = erased_serde::Deserializer::erase(deserializer);
|
||||
(reg.comp_deserialize_fn)(&mut erased, get_next_storage_fn)
|
||||
.map_err(<<D as serde::Deserializer<'de>>::Error as serde::de::Error>::custom)?;
|
||||
} else {
|
||||
<IgnoredAny>::deserialize(deserializer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn deserialize_tags<'de, D: Deserializer<'de>>(
|
||||
&self,
|
||||
deserializer: D,
|
||||
_tag_type: &TagTypeId,
|
||||
_tag_meta: &TagMeta,
|
||||
_tags: &mut TagStorage,
|
||||
) -> Result<(), <D as Deserializer<'de>>::Error> {
|
||||
<IgnoredAny>::deserialize(deserializer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn deserialize_entities<'de, D: Deserializer<'de>>(
|
||||
&self,
|
||||
deserializer: D,
|
||||
entity_allocator: &GuidEntityAllocator,
|
||||
entities: &mut Vec<Entity>,
|
||||
) -> Result<(), <D as Deserializer<'de>>::Error> {
|
||||
let entity_indices = <Vec<EntityIndex> as Deserialize>::deserialize(deserializer)?;
|
||||
entity_allocator.push_next_ids(entity_indices.iter().map(|i| Entity::new(*i, Wrapping(0))));
|
||||
for _index in entity_indices {
|
||||
let entity = entity_allocator.create_entity();
|
||||
entities.push(entity);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,36 +1,73 @@
|
|||
use bevy::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use bevy_scene::ComponentRegistryContext;
|
||||
use serde::Serialize;
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_default_plugins()
|
||||
// Registering components informs Bevy that they exist. This allows them to be used when loading/saving scenes
|
||||
// This step is only required if you want to load/save your components.
|
||||
// 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.
|
||||
.register_component::<Test>()
|
||||
.register_component::<Foo>()
|
||||
// .add_startup_system(setup)
|
||||
.add_startup_system(load_scene)
|
||||
// .add_startup_system(serialize_scene)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Properties, Default)]
|
||||
struct Test {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Properties, Default)]
|
||||
struct Foo {
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
fn load_scene(_world: &mut World, resources: &mut Resources) {
|
||||
#[derive(Serialize)]
|
||||
struct Ahh {
|
||||
pub x: Vec<A>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct A {
|
||||
pub x: f32,
|
||||
}
|
||||
|
||||
fn load_scene(world: &mut World, resources: &mut Resources) {
|
||||
let asset_server = resources.get::<AssetServer>().unwrap();
|
||||
let mut scenes = resources.get_mut::<Assets<Scene>>().unwrap();
|
||||
let component_registry = resources.get::<ComponentRegistryContext>().unwrap();
|
||||
|
||||
let scene_handle: Handle<Scene> = asset_server
|
||||
.load_sync(&mut scenes, "assets/scene/load_scene_example.scn")
|
||||
.unwrap();
|
||||
let _scene= scenes.get(&scene_handle).unwrap();
|
||||
// world.merge(scene)
|
||||
let scene= scenes.get(&scene_handle).unwrap();
|
||||
scene.add_to_world(world, &component_registry.value.read().unwrap()).unwrap();
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn serialize_scene(world: &mut World, resources: &mut Resources) {
|
||||
let component_registry = resources.get::<ComponentRegistryContext>().unwrap();
|
||||
world.build()
|
||||
.build_entity()
|
||||
.add(Test {
|
||||
x: 1.0,
|
||||
y: 2.0,
|
||||
})
|
||||
.add(Foo {
|
||||
value: "hello".to_string()
|
||||
})
|
||||
.build_entity()
|
||||
.add(Test {
|
||||
x: 3.0,
|
||||
y: 4.0,
|
||||
});
|
||||
|
||||
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();
|
||||
println!("{}", ron_string);
|
||||
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
use bevy::{
|
||||
prelude::*,
|
||||
property::SerializableProperties,
|
||||
scene::{DynamicScene, SceneEntity},
|
||||
};
|
||||
use serde::{de::Deserialize, ser::Serialize};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
|
@ -15,71 +13,53 @@ fn main() {
|
|||
#[derive(Properties, Default)]
|
||||
pub struct Test {
|
||||
a: usize,
|
||||
b: String,
|
||||
c: f32,
|
||||
nest: Nested,
|
||||
nested: Nested,
|
||||
}
|
||||
|
||||
#[derive(Properties, Default)]
|
||||
pub struct Nested {
|
||||
d: usize,
|
||||
b: usize,
|
||||
}
|
||||
|
||||
fn setup() {
|
||||
let mut test = Test {
|
||||
a: 1,
|
||||
b: "hi".to_string(),
|
||||
c: 1.0,
|
||||
nest: Nested {
|
||||
d: 8,
|
||||
nested: Nested {
|
||||
b: 8,
|
||||
}
|
||||
};
|
||||
|
||||
// You can set a property value like this. The type must match exactly or this will fail.
|
||||
test.set_prop_val::<usize>("a", 2);
|
||||
assert_eq!(test.a, 2);
|
||||
|
||||
// You can also set properties dynamically. set_prop accepts any type that implements Property
|
||||
let x: u32 = 3;
|
||||
test.set_prop("a", &x);
|
||||
assert_eq!(test.a, 3);
|
||||
|
||||
test.set_prop_val::<f32>("c", 2.0);
|
||||
let x: f64 = 3.0;
|
||||
test.set_prop("c", &x);
|
||||
assert_eq!(test.c, 3.0);
|
||||
|
||||
// DynamicProperties also implements the Properties trait.
|
||||
let mut patch = DynamicProperties::default();
|
||||
patch.set::<usize>("a", 3);
|
||||
patch.set::<usize>("a", 4);
|
||||
|
||||
// You can "apply" Properties on top of other Properties. This will only set properties with the same name and type.
|
||||
// You can use this to "patch" your components with new values.
|
||||
test.apply(&patch);
|
||||
assert_eq!(test.a, 4);
|
||||
|
||||
assert_eq!(test.a, 3);
|
||||
|
||||
// Properties implement the serde Serialize trait. You don't need to derive it yourself!
|
||||
let ser = SerializableProperties { props: &test };
|
||||
let pretty_config = ron::ser::PrettyConfig::default().with_decimal_floats(true);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
let mut serializer =
|
||||
ron::ser::Serializer::new(&mut buf, Some(pretty_config.clone()), false).unwrap();
|
||||
ser.serialize(&mut serializer).unwrap();
|
||||
let ron_string = String::from_utf8(buf).unwrap();
|
||||
println!("{}", ron_string);
|
||||
let ron_string = ron::ser::to_string_pretty(&ser, pretty_config.clone()).unwrap();
|
||||
println!("{}\n", ron_string);
|
||||
|
||||
// let dynamic_scene = DynamicScene {
|
||||
// entities: vec![SceneEntity {
|
||||
// entity: 12345,
|
||||
// components: vec![patch],
|
||||
// }],
|
||||
// };
|
||||
|
||||
// let mut serializer = ron::ser::Serializer::new(Some(ron::ser::PrettyConfig::default()), false);
|
||||
// dynamic_scene.entities.serialize(&mut serializer).unwrap();
|
||||
// println!("{}", serializer.into_output_string());
|
||||
|
||||
let mut deserializer = ron::de::Deserializer::from_str(&ron_string).unwrap();
|
||||
let dynamic_properties = DynamicProperties::deserialize(&mut deserializer).unwrap();
|
||||
let mut buf = Vec::new();
|
||||
let mut serializer = ron::ser::Serializer::new(&mut buf, Some(pretty_config), false).unwrap();
|
||||
dynamic_properties.serialize(&mut serializer).unwrap();
|
||||
let round_tripped = String::from_utf8(buf).unwrap();
|
||||
println!();
|
||||
// Dynamic properties can be deserialized
|
||||
let dynamic_properties = ron::from_str::<DynamicProperties>(&ron_string).unwrap();
|
||||
let round_tripped = ron::ser::to_string_pretty(&dynamic_properties, pretty_config).unwrap();
|
||||
println!("{}", round_tripped);
|
||||
assert_eq!(ron_string, round_tripped);
|
||||
|
||||
// This means you can patch Properties with dynamic properties deserialized from a string
|
||||
test.apply(&dynamic_properties);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue