| @@ -550,6 +550,7 @@ version = "0.1.0" | |||||
| dependencies = [ | dependencies = [ | ||||
| "gl", | "gl", | ||||
| "imagefmt", | "imagefmt", | ||||
| "serde", | |||||
| "thiserror", | "thiserror", | ||||
| ] | ] | ||||
| @@ -1529,6 +1530,7 @@ dependencies = [ | |||||
| "glc", | "glc", | ||||
| "log", | "log", | ||||
| "log4rs", | "log4rs", | ||||
| "serde", | |||||
| "serde_yaml", | "serde_yaml", | ||||
| "shred", | "shred", | ||||
| "shrev", | "shrev", | ||||
| @@ -1553,6 +1555,7 @@ dependencies = [ | |||||
| "hibitset", | "hibitset", | ||||
| "log", | "log", | ||||
| "rayon", | "rayon", | ||||
| "serde", | |||||
| "shred", | "shred", | ||||
| "shrev", | "shrev", | ||||
| "tuple_utils", | "tuple_utils", | ||||
| @@ -4,7 +4,11 @@ version = "0.1.0" | |||||
| authors = ["Bergmann89 <info@bergmann89.de>"] | authors = ["Bergmann89 <info@bergmann89.de>"] | ||||
| edition = "2018" | edition = "2018" | ||||
| [features] | |||||
| default = [ ] | |||||
| [dependencies] | [dependencies] | ||||
| gl = { version = "0.1", features = [ "generate_global" ] } | gl = { version = "0.1", features = [ "generate_global" ] } | ||||
| imagefmt = "4.0" | imagefmt = "4.0" | ||||
| serde = { version = "1.0", optional = true } | |||||
| thiserror = "1.0" | thiserror = "1.0" | ||||
| @@ -5,10 +5,16 @@ use std::convert::{AsMut, AsRef}; | |||||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | use std::fmt::{Debug, Formatter, Result as FmtResult}; | ||||
| use std::ops::{Deref, DerefMut, Mul}; | use std::ops::{Deref, DerefMut, Mul}; | ||||
| #[cfg(feature = "serde")] | |||||
| use serde::{ | |||||
| de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}, | |||||
| ser::{Serialize, SerializeStruct, Serializer}, | |||||
| }; | |||||
| use super::vector::{Element, Vector2, Vector3, Vector4}; | use super::vector::{Element, Vector2, Vector3, Vector4}; | ||||
| macro_rules! first_ptr { | macro_rules! first_ptr { | ||||
| ($this:ident, $first:ident $(,$other:ident)*) => { | |||||
| ($this:ident, $first:ident $(, $other:ident)*) => { | |||||
| unsafe { $this.$first.as_ptr() } | unsafe { $this.$first.as_ptr() } | ||||
| }; | }; | ||||
| } | } | ||||
| @@ -143,6 +149,82 @@ macro_rules! define_mat { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #[cfg(feature = "serde")] | |||||
| impl<T> Serialize for $Name<T> | |||||
| where | |||||
| T: Serialize, | |||||
| { | |||||
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |||||
| where | |||||
| S: Serializer | |||||
| { | |||||
| let mut s = serializer.serialize_struct(stringify!($Name), $size)?; | |||||
| unsafe { $(s.serialize_field(stringify!($f), &self.$f)?;)+ } | |||||
| s.end() | |||||
| } | |||||
| } | |||||
| #[cfg(feature = "serde")] | |||||
| impl<'de, T> Deserialize<'de> for $Name<T> | |||||
| where | |||||
| T: Deserialize<'de>, | |||||
| { | |||||
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |||||
| where | |||||
| D: Deserializer<'de> | |||||
| { | |||||
| struct MatrixVisitor<T>(std::marker::PhantomData<T>); | |||||
| impl<'de, X> Visitor<'de> for MatrixVisitor<X> | |||||
| where X: Deserialize<'de>, | |||||
| { | |||||
| type Value = $Name<X>; | |||||
| fn expecting(&self, formatter: &mut Formatter) -> FmtResult { | |||||
| formatter.write_fmt(format_args!("struct {}", stringify!($Name))) | |||||
| } | |||||
| fn visit_seq<V>(self, mut seq: V) -> Result<$Name<X>, V::Error> | |||||
| where | |||||
| V: SeqAccess<'de>, | |||||
| { | |||||
| Ok($Name { | |||||
| $($f: seq.next_element()?.ok_or_else(|| Error::invalid_length($i, &self))?,)+ | |||||
| }) | |||||
| } | |||||
| fn visit_map<V>(self, mut map: V) -> Result<$Name<X>, V::Error> | |||||
| where | |||||
| V: MapAccess<'de>, | |||||
| { | |||||
| $(let mut $f = None;)+ | |||||
| while let Some(key) = map.next_key()? { | |||||
| match key { | |||||
| $( | |||||
| stringify!($f) => { | |||||
| if $f.is_some() { | |||||
| return Err(Error::duplicate_field(stringify!($f))); | |||||
| } | |||||
| $f = Some(map.next_value()?); | |||||
| } | |||||
| )+ | |||||
| value => return Err(Error::unknown_field(value, FIELDS)), | |||||
| } | |||||
| } | |||||
| Ok($Name { | |||||
| $($f: $f.ok_or_else(|| Error::missing_field(stringify!($f)))?,)+ | |||||
| }) | |||||
| } | |||||
| } | |||||
| const FIELDS: &'static [&'static str] = &[$(stringify!($f),)+]; | |||||
| deserializer.deserialize_struct(stringify!($Name), FIELDS, MatrixVisitor::<T>(std::marker::PhantomData)) | |||||
| } | |||||
| } | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -4,8 +4,14 @@ use std::convert::{AsMut, AsRef}; | |||||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | use std::fmt::{Debug, Formatter, Result as FmtResult}; | ||||
| use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub}; | use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub}; | ||||
| #[cfg(feature = "serde")] | |||||
| use serde::{ | |||||
| de::{Deserialize, Deserializer, Error}, | |||||
| ser::{Serialize, Serializer}, | |||||
| }; | |||||
| macro_rules! first_ptr { | macro_rules! first_ptr { | ||||
| ($this:ident, $first:ident $(,$other:ident)*) => { | |||||
| ($this:ident, $first:ident $(, $other:ident)*) => { | |||||
| unsafe { &$this.$first } | unsafe { &$this.$first } | ||||
| }; | }; | ||||
| } | } | ||||
| @@ -155,6 +161,36 @@ macro_rules! define_vec { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #[cfg(feature = "serde")] | |||||
| impl<T> Serialize for $Name<T> | |||||
| where | |||||
| T: Serialize, | |||||
| { | |||||
| fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |||||
| where | |||||
| S: Serializer | |||||
| { | |||||
| unsafe { vec![$(&self.$f,)+].serialize(serializer) } | |||||
| } | |||||
| } | |||||
| #[cfg(feature = "serde")] | |||||
| impl<'de, T> Deserialize<'de> for $Name<T> | |||||
| where | |||||
| T: Deserialize<'de>, | |||||
| { | |||||
| fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |||||
| where | |||||
| D: Deserializer<'de> | |||||
| { | |||||
| let mut data = Vec::<T>::deserialize(deserializer)?.into_iter(); | |||||
| Ok(Self { | |||||
| $($f: data.next().ok_or_else(|| D::Error::custom("Vector is missing some elements!"))?,)+ | |||||
| }) | |||||
| } | |||||
| } | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -0,0 +1 @@ | |||||
| [{"marker":[0],"components":[{"pos":[0.0,0.0],"size":500.0},{}]}] | |||||
| @@ -33,27 +33,45 @@ fn run(vfs: Vfs) -> Result<(), Error> { | |||||
| let mut common = Dispatcher::new(&mut world); | let mut common = Dispatcher::new(&mut world); | ||||
| let mut app = App::new(&mut world)?; | let mut app = App::new(&mut world)?; | ||||
| create_test_world(&mut world); | |||||
| load_world(&mut world, WORLD_FILEPATH)?; | |||||
| while app.is_running() { | while app.is_running() { | ||||
| world.maintain(); | |||||
| common.process(&world); | common.process(&world); | ||||
| app.process(&world)?; | app.process(&world)?; | ||||
| } | } | ||||
| save_world(&mut world, WORLD_FILEPATH)?; | |||||
| Ok(()) | |||||
| } | |||||
| fn load_world(world: &mut World, path: &str) -> Result<(), Error> { | |||||
| use serde_json::de::{Deserializer, IoRead}; | |||||
| use space_crush_common::misc::{PersistWorld, Persistence, WorldHelper}; | |||||
| PersistWorld::setup(world); | |||||
| let vfs = world.resource::<Vfs>()?; | |||||
| let mut file = vfs.join(path)?.open_file()?; | |||||
| let mut read = IoRead::new(&mut file); | |||||
| let mut deserializer = Deserializer::new(&mut read); | |||||
| world.deserialize(PersistWorld, &mut deserializer)?; | |||||
| Ok(()) | Ok(()) | ||||
| } | } | ||||
| fn create_test_world(world: &mut World) { | |||||
| use glc::vector::Vector2f; | |||||
| use space_crush_common::components::{Planet, Position}; | |||||
| use specs::Builder; | |||||
| world | |||||
| .create_entity() | |||||
| .with(Position { | |||||
| pos: Vector2f::default(), | |||||
| size: 500.0, | |||||
| }) | |||||
| .with(Planet) | |||||
| .build(); | |||||
| fn save_world(world: &mut World, path: &str) -> Result<(), Error> { | |||||
| use serde_json::Serializer; | |||||
| use space_crush_common::misc::{PersistWorld, WorldHelper}; | |||||
| let vfs = world.resource::<Vfs>()?; | |||||
| let mut file = vfs.join(path)?.create_file()?; | |||||
| let mut serializer = Serializer::new(&mut file); | |||||
| world.serialize(PersistWorld, &mut serializer)?; | |||||
| Ok(()) | |||||
| } | } | ||||
| const WORLD_FILEPATH: &str = "resources/world.json"; | |||||
| @@ -5,13 +5,14 @@ authors = ["Bergmann89 <info@bergmann89.de>"] | |||||
| edition = "2018" | edition = "2018" | ||||
| [dependencies] | [dependencies] | ||||
| glc = "0.1" | |||||
| glc = { version = "0.1", features = [ "serde" ] } | |||||
| log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | ||||
| log4rs = "0.13" | log4rs = "0.13" | ||||
| serde = "1.0" | |||||
| serde_yaml = "0.8" | serde_yaml = "0.8" | ||||
| shred = { version = "0.10", features = [ "shred-derive" ] } | shred = { version = "0.10", features = [ "shred-derive" ] } | ||||
| shrev = "1.1" | shrev = "1.1" | ||||
| specs = "0.16" | |||||
| specs = { version = "0.16", features = [ "serde" ] } | |||||
| thiserror = "1.0" | thiserror = "1.0" | ||||
| vfs = "0.4" | vfs = "0.4" | ||||
| vfs-zip = "0.2" | vfs-zip = "0.2" | ||||
| @@ -1,7 +1,8 @@ | |||||
| use serde::{Deserialize, Serialize}; | |||||
| use specs::{Component, NullStorage}; | use specs::{Component, NullStorage}; | ||||
| #[derive(Default)] | |||||
| pub struct Planet; | |||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||||
| pub struct Planet {} | |||||
| impl Component for Planet { | impl Component for Planet { | ||||
| type Storage = NullStorage<Self>; | type Storage = NullStorage<Self>; | ||||
| @@ -1,6 +1,8 @@ | |||||
| use glc::vector::Vector2f; | use glc::vector::Vector2f; | ||||
| use serde::{Deserialize, Serialize}; | |||||
| use specs::{Component, VecStorage}; | use specs::{Component, VecStorage}; | ||||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||||
| pub struct Position { | pub struct Position { | ||||
| pub pos: Vector2f, | pub pos: Vector2f, | ||||
| pub size: f32, | pub size: f32, | ||||
| @@ -1,7 +1,9 @@ | |||||
| mod log; | mod log; | ||||
| mod persistence; | |||||
| mod vfs; | mod vfs; | ||||
| mod world; | mod world; | ||||
| pub use self::log::init as init_logger; | pub use self::log::init as init_logger; | ||||
| pub use self::vfs::{Vfs, VfsError}; | pub use self::vfs::{Vfs, VfsError}; | ||||
| pub use world::WorldHelper; | |||||
| pub use persistence::PersistWorld; | |||||
| pub use world::{Persistence, WorldHelper}; | |||||
| @@ -0,0 +1,13 @@ | |||||
| use specs::saveload::SimpleMarker; | |||||
| use crate::components::{Planet, Position}; | |||||
| use super::Persistence; | |||||
| pub struct PersistWorld; | |||||
| pub struct PersistWorldMarker; | |||||
| impl Persistence for PersistWorld { | |||||
| type Marker = SimpleMarker<PersistWorldMarker>; | |||||
| type Components = (Position, Planet); | |||||
| } | |||||
| @@ -1,11 +1,21 @@ | |||||
| use std::any::type_name; | use std::any::type_name; | ||||
| use serde::{ | |||||
| de::{DeserializeOwned, Deserializer}, | |||||
| ser::{Serialize, Serializer}, | |||||
| }; | |||||
| use shred::{Fetch, FetchMut, Resource}; | use shred::{Fetch, FetchMut, Resource}; | ||||
| use shrev::{Event, EventChannel, ReaderId}; | use shrev::{Event, EventChannel, ReaderId}; | ||||
| use specs::World; | |||||
| use specs::{ | |||||
| error::NoError, | |||||
| saveload::{DeserializeComponents, Marker, SerializeComponents}, | |||||
| Component, Entities, ReadStorage, World, WorldExt, Write, WriteStorage, | |||||
| }; | |||||
| use crate::Error; | use crate::Error; | ||||
| /* WorldHelper */ | |||||
| pub trait WorldHelper { | pub trait WorldHelper { | ||||
| fn resource<R>(&self) -> Result<Fetch<R>, Error> | fn resource<R>(&self) -> Result<Fetch<R>, Error> | ||||
| where | where | ||||
| @@ -18,6 +28,16 @@ pub trait WorldHelper { | |||||
| fn register_event_reader<E>(&self) -> Result<ReaderId<E>, Error> | fn register_event_reader<E>(&self) -> Result<ReaderId<E>, Error> | ||||
| where | where | ||||
| E: Event; | E: Event; | ||||
| fn serialize<T, S>(&self, persistence: T, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| T: Persistence, | |||||
| S: Serializer; | |||||
| fn deserialize<'de, T, D>(&self, persistence: T, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| T: Persistence, | |||||
| D: Deserializer<'de>; | |||||
| } | } | ||||
| impl WorldHelper for World { | impl WorldHelper for World { | ||||
| @@ -43,4 +63,125 @@ impl WorldHelper for World { | |||||
| { | { | ||||
| Ok(self.resource_mut::<EventChannel<E>>()?.register_reader()) | Ok(self.resource_mut::<EventChannel<E>>()?.register_reader()) | ||||
| } | } | ||||
| fn serialize<T, S>(&self, persistence: T, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| T: Persistence, | |||||
| S: Serializer, | |||||
| { | |||||
| persistence.serialize(self, serializer) | |||||
| } | |||||
| fn deserialize<'de, T, D>(&self, persistence: T, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| T: Persistence, | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| persistence.deserialize(self, deserializer) | |||||
| } | |||||
| } | |||||
| /* Persistence */ | |||||
| pub trait Persistence { | |||||
| type Marker: Marker; | |||||
| type Components: PersistenceComponents<Self::Marker>; | |||||
| fn setup(world: &mut World) | |||||
| where | |||||
| <Self::Marker as Component>::Storage: Default, | |||||
| <Self::Marker as Marker>::Allocator: Default, | |||||
| { | |||||
| world.register::<Self::Marker>(); | |||||
| world.insert(<Self::Marker as Marker>::Allocator::default()); | |||||
| } | |||||
| fn serialize<S>(&self, world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer, | |||||
| { | |||||
| Self::Components::serialize(world, serializer) | |||||
| } | |||||
| fn deserialize<'de, D>(&self, world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| Self::Components::deserialize(world, deserializer) | |||||
| } | |||||
| } | } | ||||
| /* PersistenceComponents */ | |||||
| pub trait PersistenceComponents<M> | |||||
| where | |||||
| M: Marker, | |||||
| { | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer; | |||||
| fn deserialize<'de, D>(world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>; | |||||
| } | |||||
| macro_rules! define_persistence_components { | |||||
| ($($T:ident),*) => { | |||||
| #[allow(non_snake_case)] | |||||
| impl<M $(,$T)+> PersistenceComponents<M> for ($($T,)+) | |||||
| where | |||||
| M: Marker, | |||||
| M::Allocator: Default, | |||||
| $($T: Component + Serialize + DeserializeOwned + Clone,)+ | |||||
| { | |||||
| fn serialize<S>(world: &World, serializer: S) -> Result<(), S::Error> | |||||
| where | |||||
| S: Serializer, | |||||
| { | |||||
| let (entities, marker, $($T,)+) = | |||||
| world.system_data::<(Entities, ReadStorage<M>, $(ReadStorage<$T>,)+)>(); | |||||
| SerializeComponents::<NoError, M>::serialize(&($($T,)+), &entities, &marker, serializer)?; | |||||
| Ok(()) | |||||
| } | |||||
| fn deserialize<'de, D>(world: &World, deserializer: D) -> Result<(), D::Error> | |||||
| where | |||||
| D: Deserializer<'de>, | |||||
| { | |||||
| let (entities, mut marker, mut allocator, $($T,)+) = world.system_data::<( | |||||
| Entities, | |||||
| WriteStorage<M>, | |||||
| Write<M::Allocator>, | |||||
| $(WriteStorage<$T>,)+ | |||||
| )>(); | |||||
| DeserializeComponents::<NoError, M>::deserialize( | |||||
| &mut ($($T,)+), | |||||
| &entities, | |||||
| &mut marker, | |||||
| &mut allocator, | |||||
| deserializer, | |||||
| ) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| define_persistence_components!(T1); | |||||
| define_persistence_components!(T1, T2); | |||||
| define_persistence_components!(T1, T2, T3); | |||||
| define_persistence_components!(T1, T2, T3, T4); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); | |||||
| define_persistence_components!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); | |||||