Sfoglia il codice sorgente

Implemented persistance for world

raster
Bergmann89 4 anni fa
parent
commit
6ba58cdcd5
12 ha cambiato i file con 326 aggiunte e 22 eliminazioni
  1. +3
    -0
      Cargo.lock
  2. +4
    -0
      glc/Cargo.toml
  3. +83
    -1
      glc/src/matrix.rs
  4. +37
    -1
      glc/src/vector.rs
  5. +1
    -0
      space-crush-app/resources/world.json
  6. +32
    -14
      space-crush-app/src/main.rs
  7. +3
    -2
      space-crush-common/Cargo.toml
  8. +3
    -2
      space-crush-common/src/components/planet.rs
  9. +2
    -0
      space-crush-common/src/components/position.rs
  10. +3
    -1
      space-crush-common/src/misc/mod.rs
  11. +13
    -0
      space-crush-common/src/misc/persistence.rs
  12. +142
    -1
      space-crush-common/src/misc/world.rs

+ 3
- 0
Cargo.lock Vedi File

@@ -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
- 0
glc/Cargo.toml Vedi File

@@ -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"

+ 83
- 1
glc/src/matrix.rs Vedi File

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



+ 37
- 1
glc/src/vector.rs Vedi File

@@ -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!"))?,)+
})
}
}
};
}



+ 1
- 0
space-crush-app/resources/world.json Vedi File

@@ -0,0 +1 @@
[{"marker":[0],"components":[{"pos":[0.0,0.0],"size":500.0},{}]}]

+ 32
- 14
space-crush-app/src/main.rs Vedi File

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

+ 3
- 2
space-crush-common/Cargo.toml Vedi File

@@ -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"

+ 3
- 2
space-crush-common/src/components/planet.rs Vedi File

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


+ 2
- 0
space-crush-common/src/components/position.rs Vedi File

@@ -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,


+ 3
- 1
space-crush-common/src/misc/mod.rs Vedi File

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

+ 13
- 0
space-crush-common/src/misc/persistence.rs Vedi File

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

+ 142
- 1
space-crush-common/src/misc/world.rs Vedi File

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

Caricamento…
Annulla
Salva