@@ -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); |