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