From eb86221f297d959b2453ed5a9e0241bc4978ff1d Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 7 Nov 2023 14:25:13 +1100 Subject: [PATCH 1/3] Added Serde + Postcard snapshot strategy --- Cargo.toml | 4 ++++ src/lib.rs | 30 ++++++++++++++++++++++++++++++ src/snapshot/strategy.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e24544d..9388563 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,9 @@ categories = ["network-programming", "game-development"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +default = ["serde"] wasm-bindgen = ["instant/wasm-bindgen", "ggrs/wasm-bindgen"] +serde = ["dep:serde", "dep:postcard"] [dependencies] bevy = { version = "0.12", default-features = false } @@ -22,6 +24,8 @@ instant = { version = "0.1", optional = true } log = "0.4" #ggrs = { version= "0.9.4", features=["sync-send"]} ggrs = { git = "https://github.com/gschup/ggrs", features=["sync-send"]} +serde = { version = "1.0.130", optional = true } +postcard = { version = "1.0.8", optional = true, features = ["use-std", "alloc"] } [dev-dependencies] bevy = { version = "0.12", default-features = true } diff --git a/src/lib.rs b/src/lib.rs index 5f3f4fb..1c9c8d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,6 +228,20 @@ impl Plugin for GgrsPlugin { /// Extension trait to add the GGRS plugin idiomatically to Bevy Apps pub trait GgrsApp { + /// Registers a component type for saving and loading from the world. This + /// uses [Serde](`serde`) and [Postcard](`postcard`). + #[cfg(feature = "serde")] + fn rollback_component_with_postcard(&mut self) -> &mut Self + where + Type: Component + serde::Serialize + serde::de::DeserializeOwned; + + /// Registers a resource type for saving and loading from the world. This + /// uses [Serde](`serde`) and [Postcard](`postcard`). + #[cfg(feature = "serde")] + fn rollback_resource_with_postcard(&mut self) -> &mut Self + where + Type: Resource + serde::Serialize + serde::de::DeserializeOwned; + /// Registers a component type for saving and loading from the world. This /// uses [`Copy`] based snapshots for rollback. fn rollback_component_with_copy(&mut self) -> &mut Self @@ -396,4 +410,20 @@ impl GgrsApp for App { { self.add_plugins(ResourceChecksumPlugin::(hasher)) } + + #[cfg(feature = "serde")] + fn rollback_component_with_postcard(&mut self) -> &mut Self + where + Type: Component + serde::Serialize + serde::de::DeserializeOwned, + { + self.add_plugins(ComponentSnapshotPlugin::>::default()) + } + + #[cfg(feature = "serde")] + fn rollback_resource_with_postcard(&mut self) -> &mut Self + where + Type: Resource + serde::Serialize + serde::de::DeserializeOwned, + { + self.add_plugins(ResourceSnapshotPlugin::>::default()) + } } diff --git a/src/snapshot/strategy.rs b/src/snapshot/strategy.rs index 0fb6f27..f4b0095 100644 --- a/src/snapshot/strategy.rs +++ b/src/snapshot/strategy.rs @@ -92,3 +92,35 @@ impl Strategy for ReflectStrategy { target } } + +#[cfg(feature = "serde")] +mod serde_strategy { + use std::marker::PhantomData; + + use postcard::{from_bytes, to_allocvec}; + use serde::{de::DeserializeOwned, Serialize}; + + use crate::Strategy; + + /// A [`Strategy`] based on [`Reflect`] and [`FromWorld`] + pub struct PostcardStrategy(PhantomData); + + impl Strategy for PostcardStrategy { + type Target = T; + + type Stored = Vec; + + #[inline(always)] + fn store(target: &Self::Target) -> Self::Stored { + to_allocvec(target).unwrap() + } + + #[inline(always)] + fn load(stored: &Self::Stored) -> Self::Target { + from_bytes(stored).unwrap() + } + } +} + +#[cfg(feature = "serde")] +pub use serde_strategy::*; From f30a67a80b201128cad923fb0440011fc18a318b Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Fri, 10 Nov 2023 08:32:54 +1100 Subject: [PATCH 2/3] Switch to `ron` and `bincode` as `serde` strategies --- Cargo.toml | 13 ++++++---- src/lib.rs | 54 +++++++++++++++++++++++++++++++--------- src/snapshot/strategy.rs | 50 +++++++++++++++++++++++++++++-------- 3 files changed, 90 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9388563..0b972b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,11 @@ categories = ["network-programming", "game-development"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["serde"] +default = ["serde", "ron", "bincode"] wasm-bindgen = ["instant/wasm-bindgen", "ggrs/wasm-bindgen"] -serde = ["dep:serde", "dep:postcard"] +serde = ["dep:serde"] +ron = ["serde", "dep:ron"] +bincode = ["serde", "dep:bincode"] [dependencies] bevy = { version = "0.12", default-features = false } @@ -24,15 +26,16 @@ instant = { version = "0.1", optional = true } log = "0.4" #ggrs = { version= "0.9.4", features=["sync-send"]} ggrs = { git = "https://github.com/gschup/ggrs", features=["sync-send"]} -serde = { version = "1.0.130", optional = true } -postcard = { version = "1.0.8", optional = true, features = ["use-std", "alloc"] } +serde = { version = "1", optional = true } +ron = { version = "0.8", optional = true } +bincode = { version = "1.3", optional = true } [dev-dependencies] bevy = { version = "0.12", default-features = true } clap = { version = "4.4", features = ["derive"] } rand = "0.8.4" rand_xoshiro = "0.6" -serde = "1.0.130" +serde = "1" serde_json = "1.0" serial_test = "2.0" diff --git a/src/lib.rs b/src/lib.rs index 1c9c8d6..571439d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,16 +229,30 @@ impl Plugin for GgrsPlugin { /// Extension trait to add the GGRS plugin idiomatically to Bevy Apps pub trait GgrsApp { /// Registers a component type for saving and loading from the world. This - /// uses [Serde](`serde`) and [Postcard](`postcard`). - #[cfg(feature = "serde")] - fn rollback_component_with_postcard(&mut self) -> &mut Self + /// uses [Serde](`serde`) and [RON](`ron`). + #[cfg(feature = "ron")] + fn rollback_component_with_ron(&mut self) -> &mut Self where Type: Component + serde::Serialize + serde::de::DeserializeOwned; /// Registers a resource type for saving and loading from the world. This - /// uses [Serde](`serde`) and [Postcard](`postcard`). - #[cfg(feature = "serde")] - fn rollback_resource_with_postcard(&mut self) -> &mut Self + /// uses [Serde](`serde`) and [RON](`ron`). + #[cfg(feature = "ron")] + fn rollback_resource_with_ron(&mut self) -> &mut Self + where + Type: Resource + serde::Serialize + serde::de::DeserializeOwned; + + /// Registers a component type for saving and loading from the world. This + /// uses [Serde](`serde`) and [bincode](`bincode`). + #[cfg(feature = "bincode")] + fn rollback_component_with_bincode(&mut self) -> &mut Self + where + Type: Component + serde::Serialize + serde::de::DeserializeOwned; + + /// Registers a resource type for saving and loading from the world. This + /// uses [Serde](`serde`) and [bincode](`bincode`). + #[cfg(feature = "bincode")] + fn rollback_resource_with_bincode(&mut self) -> &mut Self where Type: Resource + serde::Serialize + serde::de::DeserializeOwned; @@ -411,19 +425,35 @@ impl GgrsApp for App { self.add_plugins(ResourceChecksumPlugin::(hasher)) } - #[cfg(feature = "serde")] - fn rollback_component_with_postcard(&mut self) -> &mut Self + #[cfg(feature = "ron")] + fn rollback_component_with_ron(&mut self) -> &mut Self + where + Type: Component + serde::Serialize + serde::de::DeserializeOwned, + { + self.add_plugins(ComponentSnapshotPlugin::>::default()) + } + + #[cfg(feature = "ron")] + fn rollback_resource_with_ron(&mut self) -> &mut Self + where + Type: Resource + serde::Serialize + serde::de::DeserializeOwned, + { + self.add_plugins(ResourceSnapshotPlugin::>::default()) + } + + #[cfg(feature = "bincode")] + fn rollback_component_with_bincode(&mut self) -> &mut Self where Type: Component + serde::Serialize + serde::de::DeserializeOwned, { - self.add_plugins(ComponentSnapshotPlugin::>::default()) + self.add_plugins(ComponentSnapshotPlugin::>::default()) } - #[cfg(feature = "serde")] - fn rollback_resource_with_postcard(&mut self) -> &mut Self + #[cfg(feature = "bincode")] + fn rollback_resource_with_bincode(&mut self) -> &mut Self where Type: Resource + serde::Serialize + serde::de::DeserializeOwned, { - self.add_plugins(ResourceSnapshotPlugin::>::default()) + self.add_plugins(ResourceSnapshotPlugin::>::default()) } } diff --git a/src/snapshot/strategy.rs b/src/snapshot/strategy.rs index f4b0095..6e6b029 100644 --- a/src/snapshot/strategy.rs +++ b/src/snapshot/strategy.rs @@ -93,34 +93,64 @@ impl Strategy for ReflectStrategy { } } -#[cfg(feature = "serde")] -mod serde_strategy { +#[cfg(feature = "ron")] +mod ron_strategy { use std::marker::PhantomData; - use postcard::{from_bytes, to_allocvec}; use serde::{de::DeserializeOwned, Serialize}; use crate::Strategy; - /// A [`Strategy`] based on [`Reflect`] and [`FromWorld`] - pub struct PostcardStrategy(PhantomData); + /// A [`Strategy`] based on [`serde`] and [`ron`] + pub struct RonStrategy(PhantomData); - impl Strategy for PostcardStrategy { + impl Strategy for RonStrategy { + type Target = T; + + type Stored = String; + + #[inline(always)] + fn store(target: &Self::Target) -> Self::Stored { + ron::to_string(target).unwrap() + } + + #[inline(always)] + fn load(stored: &Self::Stored) -> Self::Target { + ron::from_str(stored).unwrap() + } + } +} + +#[cfg(feature = "ron")] +pub use ron_strategy::*; + +#[cfg(feature = "bincode")] +mod bincode_strategy { + use std::marker::PhantomData; + + use serde::{de::DeserializeOwned, Serialize}; + + use crate::Strategy; + + /// A [`Strategy`] based on [`serde`] and [`bincode`] + pub struct BincodeStrategy(PhantomData); + + impl Strategy for BincodeStrategy { type Target = T; type Stored = Vec; #[inline(always)] fn store(target: &Self::Target) -> Self::Stored { - to_allocvec(target).unwrap() + bincode::serialize(target).unwrap() } #[inline(always)] fn load(stored: &Self::Stored) -> Self::Target { - from_bytes(stored).unwrap() + bincode::deserialize(stored).unwrap() } } } -#[cfg(feature = "serde")] -pub use serde_strategy::*; +#[cfg(feature = "bincode")] +pub use bincode_strategy::*; From 1ef99e55b7348293f55e7f987b2f8436d8c81c6c Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Fri, 10 Nov 2023 08:32:54 +1100 Subject: [PATCH 3/3] Switch to `ron` and `bincode` as `serde` strategies --- Cargo.toml | 13 ++++++---- src/lib.rs | 56 ++++++++++++++++++++++++++++++---------- src/snapshot/strategy.rs | 50 ++++++++++++++++++++++++++++------- 3 files changed, 91 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9388563..0b972b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,11 @@ categories = ["network-programming", "game-development"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["serde"] +default = ["serde", "ron", "bincode"] wasm-bindgen = ["instant/wasm-bindgen", "ggrs/wasm-bindgen"] -serde = ["dep:serde", "dep:postcard"] +serde = ["dep:serde"] +ron = ["serde", "dep:ron"] +bincode = ["serde", "dep:bincode"] [dependencies] bevy = { version = "0.12", default-features = false } @@ -24,15 +26,16 @@ instant = { version = "0.1", optional = true } log = "0.4" #ggrs = { version= "0.9.4", features=["sync-send"]} ggrs = { git = "https://github.com/gschup/ggrs", features=["sync-send"]} -serde = { version = "1.0.130", optional = true } -postcard = { version = "1.0.8", optional = true, features = ["use-std", "alloc"] } +serde = { version = "1", optional = true } +ron = { version = "0.8", optional = true } +bincode = { version = "1.3", optional = true } [dev-dependencies] bevy = { version = "0.12", default-features = true } clap = { version = "4.4", features = ["derive"] } rand = "0.8.4" rand_xoshiro = "0.6" -serde = "1.0.130" +serde = "1" serde_json = "1.0" serial_test = "2.0" diff --git a/src/lib.rs b/src/lib.rs index 1c9c8d6..16f1760 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,16 +229,30 @@ impl Plugin for GgrsPlugin { /// Extension trait to add the GGRS plugin idiomatically to Bevy Apps pub trait GgrsApp { /// Registers a component type for saving and loading from the world. This - /// uses [Serde](`serde`) and [Postcard](`postcard`). - #[cfg(feature = "serde")] - fn rollback_component_with_postcard(&mut self) -> &mut Self + /// uses [Serde](`serde`) and [RON](`ron`). + #[cfg(feature = "ron")] + fn rollback_component_with_ron(&mut self) -> &mut Self where Type: Component + serde::Serialize + serde::de::DeserializeOwned; /// Registers a resource type for saving and loading from the world. This - /// uses [Serde](`serde`) and [Postcard](`postcard`). - #[cfg(feature = "serde")] - fn rollback_resource_with_postcard(&mut self) -> &mut Self + /// uses [Serde](`serde`) and [RON](`ron`). + #[cfg(feature = "ron")] + fn rollback_resource_with_ron(&mut self) -> &mut Self + where + Type: Resource + serde::Serialize + serde::de::DeserializeOwned; + + /// Registers a component type for saving and loading from the world. This + /// uses [Serde](`serde`) and [bincode](`bincode`). + #[cfg(feature = "bincode")] + fn rollback_component_with_bincode(&mut self) -> &mut Self + where + Type: Component + serde::Serialize + serde::de::DeserializeOwned; + + /// Registers a resource type for saving and loading from the world. This + /// uses [Serde](`serde`) and [bincode](`bincode`). + #[cfg(feature = "bincode")] + fn rollback_resource_with_bincode(&mut self) -> &mut Self where Type: Resource + serde::Serialize + serde::de::DeserializeOwned; @@ -410,20 +424,36 @@ impl GgrsApp for App { { self.add_plugins(ResourceChecksumPlugin::(hasher)) } - - #[cfg(feature = "serde")] - fn rollback_component_with_postcard(&mut self) -> &mut Self + + #[cfg(feature = "ron")] + fn rollback_component_with_ron(&mut self) -> &mut Self + where + Type: Component + serde::Serialize + serde::de::DeserializeOwned, + { + self.add_plugins(ComponentSnapshotPlugin::>::default()) + } + + #[cfg(feature = "ron")] + fn rollback_resource_with_ron(&mut self) -> &mut Self + where + Type: Resource + serde::Serialize + serde::de::DeserializeOwned, + { + self.add_plugins(ResourceSnapshotPlugin::>::default()) + } + + #[cfg(feature = "bincode")] + fn rollback_component_with_bincode(&mut self) -> &mut Self where Type: Component + serde::Serialize + serde::de::DeserializeOwned, { - self.add_plugins(ComponentSnapshotPlugin::>::default()) + self.add_plugins(ComponentSnapshotPlugin::>::default()) } - #[cfg(feature = "serde")] - fn rollback_resource_with_postcard(&mut self) -> &mut Self + #[cfg(feature = "bincode")] + fn rollback_resource_with_bincode(&mut self) -> &mut Self where Type: Resource + serde::Serialize + serde::de::DeserializeOwned, { - self.add_plugins(ResourceSnapshotPlugin::>::default()) + self.add_plugins(ResourceSnapshotPlugin::>::default()) } } diff --git a/src/snapshot/strategy.rs b/src/snapshot/strategy.rs index f4b0095..6e6b029 100644 --- a/src/snapshot/strategy.rs +++ b/src/snapshot/strategy.rs @@ -93,34 +93,64 @@ impl Strategy for ReflectStrategy { } } -#[cfg(feature = "serde")] -mod serde_strategy { +#[cfg(feature = "ron")] +mod ron_strategy { use std::marker::PhantomData; - use postcard::{from_bytes, to_allocvec}; use serde::{de::DeserializeOwned, Serialize}; use crate::Strategy; - /// A [`Strategy`] based on [`Reflect`] and [`FromWorld`] - pub struct PostcardStrategy(PhantomData); + /// A [`Strategy`] based on [`serde`] and [`ron`] + pub struct RonStrategy(PhantomData); - impl Strategy for PostcardStrategy { + impl Strategy for RonStrategy { + type Target = T; + + type Stored = String; + + #[inline(always)] + fn store(target: &Self::Target) -> Self::Stored { + ron::to_string(target).unwrap() + } + + #[inline(always)] + fn load(stored: &Self::Stored) -> Self::Target { + ron::from_str(stored).unwrap() + } + } +} + +#[cfg(feature = "ron")] +pub use ron_strategy::*; + +#[cfg(feature = "bincode")] +mod bincode_strategy { + use std::marker::PhantomData; + + use serde::{de::DeserializeOwned, Serialize}; + + use crate::Strategy; + + /// A [`Strategy`] based on [`serde`] and [`bincode`] + pub struct BincodeStrategy(PhantomData); + + impl Strategy for BincodeStrategy { type Target = T; type Stored = Vec; #[inline(always)] fn store(target: &Self::Target) -> Self::Stored { - to_allocvec(target).unwrap() + bincode::serialize(target).unwrap() } #[inline(always)] fn load(stored: &Self::Stored) -> Self::Target { - from_bytes(stored).unwrap() + bincode::deserialize(stored).unwrap() } } } -#[cfg(feature = "serde")] -pub use serde_strategy::*; +#[cfg(feature = "bincode")] +pub use bincode_strategy::*;