diff --git a/Cargo.toml b/Cargo.toml index 1371871b4..c0da23ef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ divan.workspace = true flume.workspace = true noise.workspace = true # For the terrain example. tracing.workspace = true +serde_json.workspace = true # For serialization tests. [dev-dependencies.reqwest] workspace = true diff --git a/crates/valence_generated/Cargo.toml b/crates/valence_generated/Cargo.toml index 3cc9f4a4e..0c13460ab 100644 --- a/crates/valence_generated/Cargo.toml +++ b/crates/valence_generated/Cargo.toml @@ -16,6 +16,7 @@ workspace = true valence_math.workspace = true valence_ident.workspace = true uuid.workspace = true +serde = { workspace = true, features = ["derive"] } [build-dependencies] anyhow.workspace = true diff --git a/crates/valence_generated/build/item.rs b/crates/valence_generated/build/item.rs index 248212982..74e670cf7 100644 --- a/crates/valence_generated/build/item.rs +++ b/crates/valence_generated/build/item.rs @@ -193,6 +193,27 @@ pub(crate) fn build() -> anyhow::Result { pub snack: bool, } + impl serde::Serialize for ItemKind { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(self.to_str()) + } + } + + impl<'de> serde::Deserialize<'de> for ItemKind { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s: &str = serde::Deserialize::deserialize(deserializer)?; + ItemKind::from_str(s).ok_or_else(|| { + serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &"the snake case item name, like \"white_wool\"") + }) + } + } + impl ItemKind { /// Constructs a item kind from a raw item ID. /// diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 057ea632d..0cb6fd415 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -1,12 +1,13 @@ use std::io::Write; +use serde::{Deserialize, Serialize}; pub use valence_generated::item::ItemKind; use valence_nbt::Compound; use crate::{Decode, Encode}; /// A stack of items in an inventory. -#[derive(Clone, PartialEq, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)] pub struct ItemStack { pub item: ItemKind, pub count: i8, diff --git a/src/tests.rs b/src/tests.rs index e82971210..0693a4497 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,5 +7,6 @@ mod layer; mod player_list; mod potions; mod scoreboard; +mod serialization; mod weather; mod world_border; diff --git a/src/tests/serialization.rs b/src/tests/serialization.rs new file mode 100644 index 000000000..986a1e178 --- /dev/null +++ b/src/tests/serialization.rs @@ -0,0 +1,35 @@ +use crate::ItemKind; + +#[test] +fn test_serialize_item_kind() { + let item = ItemKind::WhiteWool; + let serialized = serde_json::to_string(&item).unwrap(); + assert_eq!(serialized, "\"white_wool\""); + + let item = ItemKind::GoldenSword; + let serialized = serde_json::to_string(&item).unwrap(); + assert_eq!(serialized, "\"golden_sword\""); + + let item = ItemKind::NetheriteAxe; + let serialized = serde_json::to_string(&item).unwrap(); + assert_eq!(serialized, "\"netherite_axe\""); + + let item = ItemKind::WaxedWeatheredCutCopperStairs; + let serialized = serde_json::to_string(&item).unwrap(); + assert_eq!(serialized, "\"waxed_weathered_cut_copper_stairs\""); +} + +#[test] +fn test_deserialize_item_kind() { + let id = "\"diamond_shovel\""; + let deserialized: ItemKind = serde_json::from_str(id).unwrap(); + assert_eq!(deserialized, ItemKind::DiamondShovel); + + let id = "\"minecart\""; + let deserialized: ItemKind = serde_json::from_str(id).unwrap(); + assert_eq!(deserialized, ItemKind::Minecart); + + let id = "\"vindicator_spawn_egg\""; + let deserialized: ItemKind = serde_json::from_str(id).unwrap(); + assert_eq!(deserialized, ItemKind::VindicatorSpawnEgg); +}