diff --git a/Cargo.lock b/Cargo.lock index ae40df69e3..a9bc358e08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6884,6 +6884,15 @@ dependencies = [ "veloren-plugin-derive", ] +[[package]] +name = "veloren-rtsim" +version = "0.10.0" +dependencies = [ + "ron 0.7.0", + "serde", + "veloren-common", +] + [[package]] name = "veloren-server" version = "0.14.0" diff --git a/Cargo.toml b/Cargo.toml index 5b61b4528a..e428f0d722 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "plugin/api", "plugin/derive", "plugin/rt", + "rtsim", "server", "server/agent", "server-cli", diff --git a/rtsim/Cargo.toml b/rtsim/Cargo.toml new file mode 100644 index 0000000000..370da5a0d1 --- /dev/null +++ b/rtsim/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "veloren-rtsim" +version = "0.10.0" +edition = "2021" + +[dependencies] +common = { package = "veloren-common", path = "../common" } +ron = "0.7" +serde = { version = "1.0.110", features = ["derive"] } diff --git a/rtsim/src/data/helper.rs b/rtsim/src/data/helper.rs new file mode 100644 index 0000000000..703d666d3f --- /dev/null +++ b/rtsim/src/data/helper.rs @@ -0,0 +1,54 @@ +use serde::{ + de::{DeserializeOwned, Error}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +pub struct V(pub T); + +impl Serialize for V { + fn serialize(&self, serializer: S) -> Result { + self.0.serialize(serializer) + } +} + +impl<'de, T: Version> Deserialize<'de> for V { + fn deserialize>(deserializer: D) -> Result { + T::try_from_value_compat(ron::Value::deserialize(deserializer)?) + .map(Self) + .map_err(|e| D::Error::custom(e)) + } +} + +impl> Latest for V { + fn to_unversioned(self) -> U { self.0.to_unversioned() } + + fn from_unversioned(x: U) -> Self { Self(T::from_unversioned(x)) } +} + +pub trait Latest { + fn to_unversioned(self) -> T; + fn from_unversioned(x: T) -> Self; +} + +pub trait Version: Sized + DeserializeOwned { + type Prev: Version; + + fn migrate(prev: Self::Prev) -> Self; + + fn try_from_value_compat(value: ron::Value) -> Result { + value.clone().into_rust().or_else(|e| { + Ok(Self::migrate( + ::Prev::try_from_value_compat(value).map_err(|_| e)?, + )) + }) + } +} + +#[derive(Deserialize)] +pub enum Bottom {} + +impl Version for Bottom { + type Prev = Self; + + fn migrate(prev: Self::Prev) -> Self { prev } +} diff --git a/rtsim/src/data/mod.rs b/rtsim/src/data/mod.rs new file mode 100644 index 0000000000..140a0eb0f0 --- /dev/null +++ b/rtsim/src/data/mod.rs @@ -0,0 +1,10 @@ +pub mod helper; +pub mod version; + +pub mod world; + +pub use self::world::World; + +pub struct Data { + world: World, +} diff --git a/rtsim/src/data/version/mod.rs b/rtsim/src/data/version/mod.rs new file mode 100644 index 0000000000..af563e3403 --- /dev/null +++ b/rtsim/src/data/version/mod.rs @@ -0,0 +1,72 @@ +// # Hey, you! Yes, you! +// +// Don't touch anything in this module, or any sub-modules. No, really. Bad +// stuff will happen. +// +// You're only an exception to this rule if you fulfil the following criteria: +// +// - You *really* understand exactly how the versioning system in `helper.rs` +// works, what assumptions it makes, and how all of this can go badly wrong. +// +// - You are creating a new version of a data structure, and *not* modifying an +// existing one. +// +// - You've thought really carefully about things and you've come to the +// conclusion that there's just no way to add the feature you want to add +// without creating a new version of the data structure in question. +// +// That said, here's how to make a change to one of the structures in this +// module, or submodules. +// +// 1) Duplicate the latest version of the data structure and the `Version` impl +// for it (later versions should be kept at the top of each file). +// +// 2) Rename the duplicated version, incrementing the version number (i.e: V0 +// becomes V1). +// +// 3) Change the `type Prev =` associated type in the new `Version` impl to the +// previous versions' type. You will need to write an implementation of +// `migrate` that migrates from the old version to the new version. +// +// 4) *Change* the existing `Latest` impl so that it uses the new version you +// have created. +// +// 5) If your data structure is contained within another data structure, you +// will need to similarly update the parent data structure too, also +// following these instructions. +// +// The *golden rule* is that, once merged to master, an old version's type must +// not be changed! + +pub mod world; + +use super::{ + helper::{Bottom, Latest, Version, V}, + Data, +}; +use serde::{Deserialize, Serialize}; + +impl Latest for DataV0 { + fn to_unversioned(self) -> Data { + Data { + world: self.world.to_unversioned(), + } + } + + fn from_unversioned(data: Data) -> Self { + Self { + world: Latest::from_unversioned(data.world), + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct DataV0 { + world: V, +} + +impl Version for DataV0 { + type Prev = Bottom; + + fn migrate(x: Self::Prev) -> Self { match x {} } +} diff --git a/rtsim/src/data/version/world.rs b/rtsim/src/data/version/world.rs new file mode 100644 index 0000000000..3c15eeb31e --- /dev/null +++ b/rtsim/src/data/version/world.rs @@ -0,0 +1,17 @@ +use super::*; +use crate::data::World; + +impl Latest for WorldV0 { + fn to_unversioned(self) -> World { World {} } + + fn from_unversioned(world: World) -> Self { Self {} } +} + +#[derive(Serialize, Deserialize)] +pub struct WorldV0 {} + +impl Version for WorldV0 { + type Prev = Bottom; + + fn migrate(x: Self::Prev) -> Self { match x {} } +} diff --git a/rtsim/src/data/world.rs b/rtsim/src/data/world.rs new file mode 100644 index 0000000000..36b2386888 --- /dev/null +++ b/rtsim/src/data/world.rs @@ -0,0 +1 @@ +pub struct World {} diff --git a/rtsim/src/lib.rs b/rtsim/src/lib.rs new file mode 100644 index 0000000000..dd3133d228 --- /dev/null +++ b/rtsim/src/lib.rs @@ -0,0 +1,7 @@ +pub mod data; + +/* +pub struct RtState<'a> { + +} +*/