scenes: datatype and serialization

This commit is contained in:
Carter Anderson 2020-05-20 10:40:23 -07:00
parent 64ce5b42c0
commit 553b754492
4 changed files with 213 additions and 59 deletions

View File

@ -1,3 +1,4 @@
mod world;
mod scene;
pub use world::*;
pub use scene::*;

View 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()
}
}

View File

@ -1,7 +1,7 @@
// adapted from https://github.com/TomGillen/legion/blob/master/examples/serde.rs
use legion::{
entity::EntityAllocator,
entity::{EntityIndex, GuidEntityAllocator},
prelude::*,
storage::{
ArchetypeDescription, ComponentMeta, ComponentResourceSet, ComponentTypeId, TagMeta,
@ -13,7 +13,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer,
};
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,
};
@ -99,24 +99,31 @@ impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> Visitor<'de>
#[derive(Clone)]
pub struct ComponentRegistration {
ty: &'static str,
comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)),
comp_deserialize_fn: fn(
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>,
register_comp_fn: fn(&mut ArchetypeDescription),
pub register_comp_fn: fn(&mut ArchetypeDescription),
}
impl ComponentRegistration {
pub fn of<T: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static>() -> Self {
Self {
ty: type_name::<T>(),
ty: ComponentTypeId::of::<T>(),
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,
@ -140,36 +147,16 @@ struct SerializedArchetypeDescription {
pub struct SerializeImpl {
pub comp_types: HashMap<String, ComponentRegistration>,
pub entity_map: RefCell<HashMap<Entity, uuid::Bytes>>,
}
impl SerializeImpl {
pub fn new(
component_registrations: &[ComponentRegistration],
) -> Self {
pub fn new(component_registrations: &[ComponentRegistration]) -> Self {
SerializeImpl {
comp_types: HashMap::from_iter(
component_registrations
.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,
entities: &[Entity],
) -> Result<S::Ok, S::Error> {
let mut uuid_map = self.entity_map.borrow_mut();
serializer.collect_seq(entities.iter().map(|e| {
*uuid_map
.entry(*e)
.or_insert_with(|| *uuid::Uuid::new_v4().as_bytes())
}))
serializer.collect_seq(entities.iter().map(|e| e.index()))
}
}
pub struct DeserializeImpl<'a> {
pub comp_types: &'a HashMap<String, ComponentRegistration>,
pub entity_map: RefCell<HashMap<uuid::Bytes, Entity>>,
}
impl<'a> DeserializeImpl<'a> {
pub fn new(
component_types: &'a HashMap<String, ComponentRegistration>,
entity_map: RefCell<HashMap<Entity, uuid::Bytes>>,
) -> Self {
pub fn new(component_types: &'a HashMap<String, ComponentRegistration>) -> Self {
DeserializeImpl {
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>>(
&self,
deserializer: D,
entity_allocator: &EntityAllocator,
entity_allocator: &GuidEntityAllocator,
entities: &mut Vec<Entity>,
) -> Result<(), <D as Deserializer<'de>>::Error> {
let entity_uuids = <Vec<uuid::Bytes> as Deserialize>::deserialize(deserializer)?;
let mut entity_map = self.entity_map.borrow_mut();
for id in entity_uuids {
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();
entity_map.insert(id, entity);
entities.push(entity);
}
Ok(())

View File

@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize};
fn main() {
App::build()
.add_plugin(ScheduleRunnerPlugin::run_once())
.add_startup_system(setup)
// .add_startup_system(setup)
.add_startup_system(setup_scene.system())
.run();
}
@ -15,7 +16,28 @@ struct Test {
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 },)]);
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();
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 deserializer = serde_json::Deserializer::from_str(&serialized_data);
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
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 roundtrip_data = serde_json::to_string(&serializable).unwrap();
println!("{}", roundtrip_data);
assert_eq!(roundtrip_data, serialized_data);
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 deserializer = ron::de::Deserializer::from_str(&s).unwrap();
deserialize(&mut new_world, &de_helper, &mut deserializer).unwrap();
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 roundtrip_data = ron::ser::to_string_pretty(&serializable, pretty).expect("Serialization failed");
println!("{}", roundtrip_data);