scenes: datatype and serialization
This commit is contained in:
parent
64ce5b42c0
commit
553b754492
@ -1,3 +1,4 @@
|
|||||||
mod world;
|
mod world;
|
||||||
|
mod scene;
|
||||||
pub use world::*;
|
pub use world::*;
|
||||||
|
pub use scene::*;
|
||||||
|
|||||||
161
crates/bevy_serialization/src/scene.rs
Normal file
161
crates/bevy_serialization/src/scene.rs
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
use crate::ComponentRegistration;
|
||||||
|
use legion::{
|
||||||
|
prelude::{Entity, World},
|
||||||
|
storage::{ComponentMeta, ComponentStorage, ComponentTypeId, ComponentResourceSet},
|
||||||
|
};
|
||||||
|
use serde::{
|
||||||
|
ser::{Serialize, SerializeSeq, SerializeStruct},
|
||||||
|
Deserialize,
|
||||||
|
};
|
||||||
|
use std::{cell::RefCell, collections::HashMap};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Scene {
|
||||||
|
pub world: World,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ComponentRegistry {
|
||||||
|
pub registrations: HashMap<ComponentTypeId, ComponentRegistration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentRegistry {
|
||||||
|
pub fn register<T>(&mut self)
|
||||||
|
where
|
||||||
|
T: Send + Sync + 'static + Serialize + for<'de> Deserialize<'de>,
|
||||||
|
{
|
||||||
|
let registration = ComponentRegistration::of::<T>();
|
||||||
|
self.registrations.insert(registration.ty, registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, type_id: ComponentTypeId) -> Option<&ComponentRegistration> {
|
||||||
|
self.registrations.get(&type_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for entity in self.scene.world.iter_entities() {
|
||||||
|
// seq.serialize_element(&WorldEntity {
|
||||||
|
// world: &self.scene.world,
|
||||||
|
// component_registry: &self.component_registry,
|
||||||
|
// 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("id", &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 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,7 +1,7 @@
|
|||||||
// adapted from https://github.com/TomGillen/legion/blob/master/examples/serde.rs
|
// adapted from https://github.com/TomGillen/legion/blob/master/examples/serde.rs
|
||||||
|
|
||||||
use legion::{
|
use legion::{
|
||||||
entity::EntityAllocator,
|
entity::{EntityIndex, GuidEntityAllocator},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
storage::{
|
storage::{
|
||||||
ArchetypeDescription, ComponentMeta, ComponentResourceSet, ComponentTypeId, TagMeta,
|
ArchetypeDescription, ComponentMeta, ComponentResourceSet, ComponentTypeId, TagMeta,
|
||||||
@ -13,7 +13,7 @@ use serde::{
|
|||||||
Deserialize, Deserializer, Serialize, Serializer,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
any::type_name, cell::RefCell, collections::HashMap, iter::FromIterator, marker::PhantomData,
|
cell::RefCell, collections::HashMap, iter::FromIterator, marker::PhantomData, num::Wrapping,
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,24 +99,31 @@ impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> Visitor<'de>
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ComponentRegistration {
|
pub struct ComponentRegistration {
|
||||||
ty: &'static str,
|
pub ty: ComponentTypeId,
|
||||||
comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
pub comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)),
|
||||||
comp_deserialize_fn: fn(
|
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,
|
deserializer: &mut dyn erased_serde::Deserializer,
|
||||||
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull<u8>, usize)>,
|
||||||
) -> Result<(), erased_serde::Error>,
|
) -> Result<(), erased_serde::Error>,
|
||||||
register_comp_fn: fn(&mut ArchetypeDescription),
|
pub register_comp_fn: fn(&mut ArchetypeDescription),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentRegistration {
|
impl ComponentRegistration {
|
||||||
pub fn of<T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static>() -> Self {
|
pub fn of<T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static>() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ty: type_name::<T>(),
|
ty: ComponentTypeId::of::<T>(),
|
||||||
comp_serialize_fn: |comp_storage, serialize_fn| {
|
comp_serialize_fn: |comp_storage, serialize_fn| {
|
||||||
// it's safe because we know this is the correct type due to lookup
|
// it's safe because we know this is the correct type due to lookup
|
||||||
let slice = unsafe { comp_storage.data_slice::<T>() };
|
let slice = unsafe { comp_storage.data_slice::<T>() };
|
||||||
serialize_fn(&*slice);
|
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| {
|
comp_deserialize_fn: |deserializer, get_next_storage_fn| {
|
||||||
let comp_seq_deser = ComponentSeqDeserializer::<T> {
|
let comp_seq_deser = ComponentSeqDeserializer::<T> {
|
||||||
get_next_storage_fn,
|
get_next_storage_fn,
|
||||||
@ -140,36 +147,16 @@ struct SerializedArchetypeDescription {
|
|||||||
|
|
||||||
pub struct SerializeImpl {
|
pub struct SerializeImpl {
|
||||||
pub comp_types: HashMap<String, ComponentRegistration>,
|
pub comp_types: HashMap<String, ComponentRegistration>,
|
||||||
pub entity_map: RefCell<HashMap<Entity, uuid::Bytes>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerializeImpl {
|
impl SerializeImpl {
|
||||||
pub fn new(
|
pub fn new(component_registrations: &[ComponentRegistration]) -> Self {
|
||||||
component_registrations: &[ComponentRegistration],
|
|
||||||
) -> Self {
|
|
||||||
SerializeImpl {
|
SerializeImpl {
|
||||||
comp_types: HashMap::from_iter(
|
comp_types: HashMap::from_iter(
|
||||||
component_registrations
|
component_registrations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|reg| (reg.ty.to_string(), reg.clone())),
|
.map(|reg| (reg.ty.0.to_string(), reg.clone())),
|
||||||
),
|
),
|
||||||
entity_map: RefCell::new(HashMap::new()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_map(
|
|
||||||
component_registrations: &[ComponentRegistration],
|
|
||||||
entity_map: HashMap<uuid::Bytes, Entity>,
|
|
||||||
) -> Self {
|
|
||||||
SerializeImpl {
|
|
||||||
comp_types: HashMap::from_iter(
|
|
||||||
component_registrations
|
|
||||||
.iter()
|
|
||||||
.map(|reg| (reg.ty.to_string(), reg.clone())),
|
|
||||||
),
|
|
||||||
entity_map: RefCell::new(HashMap::from_iter(
|
|
||||||
entity_map.into_iter().map(|(uuid, e)| (e, uuid)),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,34 +232,18 @@ impl legion::serialize::ser::WorldSerializer for SerializeImpl {
|
|||||||
serializer: S,
|
serializer: S,
|
||||||
entities: &[Entity],
|
entities: &[Entity],
|
||||||
) -> Result<S::Ok, S::Error> {
|
) -> Result<S::Ok, S::Error> {
|
||||||
let mut uuid_map = self.entity_map.borrow_mut();
|
serializer.collect_seq(entities.iter().map(|e| e.index()))
|
||||||
serializer.collect_seq(entities.iter().map(|e| {
|
|
||||||
*uuid_map
|
|
||||||
.entry(*e)
|
|
||||||
.or_insert_with(|| *uuid::Uuid::new_v4().as_bytes())
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeserializeImpl<'a> {
|
pub struct DeserializeImpl<'a> {
|
||||||
pub comp_types: &'a HashMap<String, ComponentRegistration>,
|
pub comp_types: &'a HashMap<String, ComponentRegistration>,
|
||||||
pub entity_map: RefCell<HashMap<uuid::Bytes, Entity>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeserializeImpl<'a> {
|
impl<'a> DeserializeImpl<'a> {
|
||||||
pub fn new(
|
pub fn new(component_types: &'a HashMap<String, ComponentRegistration>) -> Self {
|
||||||
component_types: &'a HashMap<String, ComponentRegistration>,
|
|
||||||
entity_map: RefCell<HashMap<Entity, uuid::Bytes>>,
|
|
||||||
) -> Self {
|
|
||||||
DeserializeImpl {
|
DeserializeImpl {
|
||||||
comp_types: component_types,
|
comp_types: component_types,
|
||||||
// re-use the entity-uuid mapping
|
|
||||||
entity_map: RefCell::new(HashMap::from_iter(
|
|
||||||
entity_map
|
|
||||||
.into_inner()
|
|
||||||
.into_iter()
|
|
||||||
.map(|(e, uuid)| (uuid, e)),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,14 +293,13 @@ impl<'a> legion::serialize::de::WorldDeserializer for DeserializeImpl<'a> {
|
|||||||
fn deserialize_entities<'de, D: Deserializer<'de>>(
|
fn deserialize_entities<'de, D: Deserializer<'de>>(
|
||||||
&self,
|
&self,
|
||||||
deserializer: D,
|
deserializer: D,
|
||||||
entity_allocator: &EntityAllocator,
|
entity_allocator: &GuidEntityAllocator,
|
||||||
entities: &mut Vec<Entity>,
|
entities: &mut Vec<Entity>,
|
||||||
) -> Result<(), <D as Deserializer<'de>>::Error> {
|
) -> Result<(), <D as Deserializer<'de>>::Error> {
|
||||||
let entity_uuids = <Vec<uuid::Bytes> as Deserialize>::deserialize(deserializer)?;
|
let entity_indices = <Vec<EntityIndex> as Deserialize>::deserialize(deserializer)?;
|
||||||
let mut entity_map = self.entity_map.borrow_mut();
|
entity_allocator.push_next_ids(entity_indices.iter().map(|i| Entity::new(*i, Wrapping(0))));
|
||||||
for id in entity_uuids {
|
for _index in entity_indices {
|
||||||
let entity = entity_allocator.create_entity();
|
let entity = entity_allocator.create_entity();
|
||||||
entity_map.insert(id, entity);
|
|
||||||
entities.push(entity);
|
entities.push(entity);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
fn main() {
|
fn main() {
|
||||||
App::build()
|
App::build()
|
||||||
.add_plugin(ScheduleRunnerPlugin::run_once())
|
.add_plugin(ScheduleRunnerPlugin::run_once())
|
||||||
.add_startup_system(setup)
|
// .add_startup_system(setup)
|
||||||
|
.add_startup_system(setup_scene.system())
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,7 +16,28 @@ struct Test {
|
|||||||
pub y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(world: &mut World, resources: &mut Resources) {
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Foo {
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_scene() {
|
||||||
|
let mut component_registry = ComponentRegistry::default();
|
||||||
|
component_registry.register::<Test>();
|
||||||
|
component_registry.register::<Foo>();
|
||||||
|
|
||||||
|
let mut scene = Scene::default();
|
||||||
|
scene.world.insert((), vec![(Test { x: 3.0, y: 4.0 }, Foo { value: "hi".to_string()}),]);
|
||||||
|
scene.world.insert((), vec![(Test { x: 3.0, y: 4.0 },)]);
|
||||||
|
|
||||||
|
let serializable_scene = SerializableScene::new(&scene, &component_registry);
|
||||||
|
|
||||||
|
let mut serializer = ron::ser::Serializer::new(Some(ron::ser::PrettyConfig::default()), true);
|
||||||
|
serializable_scene.serialize(&mut serializer).unwrap();
|
||||||
|
println!("{}", serializer.into_output_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _setup(world: &mut World, resources: &mut Resources) {
|
||||||
world.insert((), vec![(Test { x: 3.0, y: 4.0 },)]);
|
world.insert((), vec![(Test { x: 3.0, y: 4.0 },)]);
|
||||||
|
|
||||||
let comp_registrations = [ComponentRegistration::of::<Test>()];
|
let comp_registrations = [ComponentRegistration::of::<Test>()];
|
||||||
@ -41,24 +63,24 @@ fn setup(world: &mut World, resources: &mut Resources) {
|
|||||||
|
|
||||||
let universe = resources.get_mut::<Universe>().unwrap();
|
let universe = resources.get_mut::<Universe>().unwrap();
|
||||||
println!("JSON (Round Trip)");
|
println!("JSON (Round Trip)");
|
||||||
let de_helper = DeserializeImpl::new(&ser_helper.comp_types, ser_helper.entity_map.clone());
|
let de_helper = DeserializeImpl::new(&ser_helper.comp_types);
|
||||||
let mut new_world = universe.create_world();
|
let mut new_world = universe.create_world();
|
||||||
let mut deserializer = serde_json::Deserializer::from_str(&serialized_data);
|
let mut deserializer = serde_json::Deserializer::from_str(&serialized_data);
|
||||||
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
|
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
|
||||||
let round_trip_ser_helper =
|
let round_trip_ser_helper =
|
||||||
SerializeImpl::new_with_map(&comp_registrations, de_helper.entity_map.into_inner());
|
SerializeImpl::new(&comp_registrations);
|
||||||
let serializable = serializable_world(&new_world, &round_trip_ser_helper);
|
let serializable = serializable_world(&new_world, &round_trip_ser_helper);
|
||||||
let roundtrip_data = serde_json::to_string(&serializable).unwrap();
|
let roundtrip_data = serde_json::to_string(&serializable).unwrap();
|
||||||
println!("{}", roundtrip_data);
|
println!("{}", roundtrip_data);
|
||||||
assert_eq!(roundtrip_data, serialized_data);
|
assert_eq!(roundtrip_data, serialized_data);
|
||||||
|
|
||||||
println!("RON (Round Trip)");
|
println!("RON (Round Trip)");
|
||||||
let de_helper = DeserializeImpl::new(&ser_helper.comp_types, ser_helper.entity_map.clone());
|
let de_helper = DeserializeImpl::new(&ser_helper.comp_types);
|
||||||
let mut new_world = universe.create_world();
|
let mut new_world = universe.create_world();
|
||||||
let mut deserializer = ron::de::Deserializer::from_str(&s).unwrap();
|
let mut deserializer = ron::de::Deserializer::from_str(&s).unwrap();
|
||||||
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
|
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
|
||||||
let round_trip_ser_helper =
|
let round_trip_ser_helper =
|
||||||
SerializeImpl::new_with_map(&comp_registrations, de_helper.entity_map.into_inner());
|
SerializeImpl::new(&comp_registrations);
|
||||||
let serializable = serializable_world(&new_world, &round_trip_ser_helper);
|
let serializable = serializable_world(&new_world, &round_trip_ser_helper);
|
||||||
let roundtrip_data = ron::ser::to_string_pretty(&serializable, pretty).expect("Serialization failed");
|
let roundtrip_data = ron::ser::to_string_pretty(&serializable, pretty).expect("Serialization failed");
|
||||||
println!("{}", roundtrip_data);
|
println!("{}", roundtrip_data);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user