| @@ -550,6 +550,7 @@ version = "0.1.0" | |||
| dependencies = [ | |||
| "gl", | |||
| "imagefmt", | |||
| "serde", | |||
| "thiserror", | |||
| ] | |||
| @@ -1529,6 +1530,7 @@ dependencies = [ | |||
| "glc", | |||
| "log", | |||
| "log4rs", | |||
| "serde", | |||
| "serde_yaml", | |||
| "shred", | |||
| "shrev", | |||
| @@ -1553,6 +1555,7 @@ dependencies = [ | |||
| "hibitset", | |||
| "log", | |||
| "rayon", | |||
| "serde", | |||
| "shred", | |||
| "shrev", | |||
| "tuple_utils", | |||
| @@ -4,7 +4,11 @@ version = "0.1.0" | |||
| authors = ["Bergmann89 <info@bergmann89.de>"] | |||
| edition = "2018" | |||
| [features] | |||
| default = [ ] | |||
| [dependencies] | |||
| gl = { version = "0.1", features = [ "generate_global" ] } | |||
| imagefmt = "4.0" | |||
| serde = { version = "1.0", optional = true } | |||
| thiserror = "1.0" | |||
| @@ -5,10 +5,16 @@ use std::convert::{AsMut, AsRef}; | |||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | |||
| 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}; | |||
| macro_rules! first_ptr { | |||
| ($this:ident, $first:ident $(,$other:ident)*) => { | |||
| ($this:ident, $first:ident $(, $other:ident)*) => { | |||
| 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::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub}; | |||
| #[cfg(feature = "serde")] | |||
| use serde::{ | |||
| de::{Deserialize, Deserializer, Error}, | |||
| ser::{Serialize, Serializer}, | |||
| }; | |||
| macro_rules! first_ptr { | |||
| ($this:ident, $first:ident $(,$other:ident)*) => { | |||
| ($this:ident, $first:ident $(, $other:ident)*) => { | |||
| 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 app = App::new(&mut world)?; | |||
| create_test_world(&mut world); | |||
| load_world(&mut world, WORLD_FILEPATH)?; | |||
| while app.is_running() { | |||
| world.maintain(); | |||
| common.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(()) | |||
| } | |||
| 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" | |||
| [dependencies] | |||
| glc = "0.1" | |||
| glc = { version = "0.1", features = [ "serde" ] } | |||
| log = { version = "0.4", features = [ "max_level_trace", "release_max_level_warn" ] } | |||
| log4rs = "0.13" | |||
| serde = "1.0" | |||
| serde_yaml = "0.8" | |||
| shred = { version = "0.10", features = [ "shred-derive" ] } | |||
| shrev = "1.1" | |||
| specs = "0.16" | |||
| specs = { version = "0.16", features = [ "serde" ] } | |||
| thiserror = "1.0" | |||
| vfs = "0.4" | |||
| vfs-zip = "0.2" | |||
| @@ -1,7 +1,8 @@ | |||
| use serde::{Deserialize, Serialize}; | |||
| use specs::{Component, NullStorage}; | |||
| #[derive(Default)] | |||
| pub struct Planet; | |||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
| pub struct Planet {} | |||
| impl Component for Planet { | |||
| type Storage = NullStorage<Self>; | |||
| @@ -1,6 +1,8 @@ | |||
| use glc::vector::Vector2f; | |||
| use serde::{Deserialize, Serialize}; | |||
| use specs::{Component, VecStorage}; | |||
| #[derive(Clone, Debug, Default, Serialize, Deserialize)] | |||
| pub struct Position { | |||
| pub pos: Vector2f, | |||
| pub size: f32, | |||
| @@ -1,7 +1,9 @@ | |||
| mod log; | |||
| mod persistence; | |||
| mod vfs; | |||
| mod world; | |||
| pub use self::log::init as init_logger; | |||
| 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 serde::{ | |||
| de::{DeserializeOwned, Deserializer}, | |||
| ser::{Serialize, Serializer}, | |||
| }; | |||
| use shred::{Fetch, FetchMut, Resource}; | |||
| 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; | |||
| /* WorldHelper */ | |||
| pub trait WorldHelper { | |||
| fn resource<R>(&self) -> Result<Fetch<R>, Error> | |||
| where | |||
| @@ -18,6 +28,16 @@ pub trait WorldHelper { | |||
| fn register_event_reader<E>(&self) -> Result<ReaderId<E>, Error> | |||
| where | |||
| 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 { | |||
| @@ -43,4 +63,125 @@ impl WorldHelper for World { | |||
| { | |||
| 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); | |||