Last active
April 24, 2021 03:29
-
-
Save matthewjberger/27182fd293b4ab9211f7b99c0669fb18 to your computer and use it in GitHub Desktop.
serialization/deserialization of legion ecs as a member of another struct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[dependencies] | |
legion = "0.4.0" | |
serde = "1.0.125" | |
serde_json = "1.0.64" | |
lazy_static = "1.4.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use lazy_static::lazy_static; | |
use legion::{ | |
serialize::{set_entity_serializer, Canon}, | |
*, | |
}; | |
use serde::{de::DeserializeSeed, Deserialize, Deserializer, Serialize, Serializer}; | |
use std::{ | |
result::Result, | |
sync::{Arc, RwLock}, | |
}; | |
lazy_static! { | |
pub static ref COMPONENT_REGISTRY: Arc<RwLock<Registry<String>>> = { | |
let mut registry = Registry::default(); | |
registry.register::<Position>("position".to_string()); | |
// Purposefully excluding 'Velocity' here, | |
// so it can be added later in main by mutating the registry | |
registry.register::<f32>("f32".to_string()); | |
Arc::new(RwLock::new(registry)) | |
}; | |
pub static ref ENTITY_SERIALIZER: Canon = Canon::default(); | |
} | |
// a component is any type that is 'static, sized, send and sync | |
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] | |
struct Position { | |
x: f32, | |
y: f32, | |
} | |
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] | |
struct Velocity { | |
dx: f32, | |
dy: f32, | |
} | |
pub type Ecs = legion::World; | |
pub type Entity = legion::Entity; | |
#[derive(Debug, Default, Serialize, Deserialize)] | |
pub struct World { | |
#[serde(serialize_with = "ecs_serialize", deserialize_with = "ecs_deserialize")] | |
pub ecs: Ecs, | |
pub number: f32, | |
pub entities: Vec<Entity>, | |
} | |
fn ecs_serialize<S>(ecs: &Ecs, serializer: S) -> Result<S::Ok, S::Error> | |
where | |
S: Serializer, | |
{ | |
let registry = (&*COMPONENT_REGISTRY) | |
.read() | |
.expect("Failed to get the component registry lock!"); | |
ecs.as_serializable(legion::any(), &*registry, &*ENTITY_SERIALIZER) | |
.serialize(serializer) | |
} | |
fn ecs_deserialize<'de, D>(deserializer: D) -> Result<Ecs, D::Error> | |
where | |
D: Deserializer<'de>, | |
{ | |
(&*COMPONENT_REGISTRY) | |
.read() | |
.expect("Failed to get the component registry lock!") | |
.as_deserialize(&*ENTITY_SERIALIZER) | |
.deserialize(deserializer) | |
} | |
fn main() { | |
let mut world = World::default(); | |
world | |
.ecs | |
.push((Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 })); | |
world.entities.push(world.ecs.push(())); | |
// Register the velocity component by mutating the registry | |
{ | |
(&*COMPONENT_REGISTRY) | |
.write() | |
.expect("Failed to get the component registry lock!") | |
.register::<Velocity>("velocity".to_string()); | |
} | |
let json = set_entity_serializer(&*ENTITY_SERIALIZER, || { | |
serde_json::to_value(world).expect("Failed to serialize the world!") | |
}); | |
println!("Serialized world: {}", json); | |
let world: World = set_entity_serializer(&*ENTITY_SERIALIZER, || { | |
serde_json::from_str(&json.to_string()).expect("Failed to deserialize world!") | |
}); | |
println!("Deserialized world: {:#?}", world); | |
// Bonus: Immutable access to an entity | |
if let Ok(entry) = world.ecs.entry_ref(entity) { | |
println!("{:#?}", entry.get_component::<Position>()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment