use crate::VarInt; use pumpkin_world::item::Item; use serde::ser::SerializeSeq; use serde::{ de::{self, SeqAccess}, Deserialize, Serialize, Serializer, }; #[derive(Debug, Clone)] pub struct Slot { item_count: VarInt, item_id: Option, num_components_to_add: Option, num_components_to_remove: Option, components_to_add: Option>, // The second type depends on the varint components_to_remove: Option>, } impl<'de> Deserialize<'de> for Slot { fn deserialize(deserializer: D) -> Result where D: de::Deserializer<'de>, { struct Visitor; impl<'de> de::Visitor<'de> for Visitor { type Value = Slot; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a valid VarInt encoded in a byte sequence") } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let item_count = seq .next_element::()? .ok_or(de::Error::custom("Failed to decode VarInt"))?; if item_count.0 == 0 { return Ok(Slot { item_count: 0.into(), item_id: None, num_components_to_add: None, num_components_to_remove: None, components_to_add: None, components_to_remove: None, }); } let item_id = seq .next_element::()? .ok_or(de::Error::custom("Failed to decode VarInt"))?; let num_components_to_add = seq .next_element::()? .ok_or(de::Error::custom("Failed to decode VarInt"))?; let num_components_to_remove = seq .next_element::()? .ok_or(de::Error::custom("Failed to decode VarInt"))?; if num_components_to_add.0 != 0 || num_components_to_remove.0 != 0 { return Err(de::Error::custom( "Slot components are currently unsupported", )); } Ok(Slot { item_count, item_id: Some(item_id), num_components_to_add: Some(num_components_to_add), num_components_to_remove: Some(num_components_to_remove), components_to_add: None, components_to_remove: None, }) } } deserializer.deserialize_seq(Visitor) } } impl Serialize for Slot { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if self.item_count == 0.into() { let mut s = serializer.serialize_seq(Some(1))?; s.serialize_element(&self.item_count)?; s.end() } else { match (&self.num_components_to_add, &self.num_components_to_remove) { (Some(to_add), Some(to_remove)) => { let mut s = serializer.serialize_seq(Some(6))?; s.serialize_element(&self.item_count)?; s.serialize_element(self.item_id.as_ref().unwrap())?; s.serialize_element(to_add)?; s.serialize_element(to_remove)?; s.serialize_element(self.components_to_add.as_ref().unwrap())?; s.serialize_element(self.components_to_remove.as_ref().unwrap())?; s.end() } (None, Some(to_remove)) => { let mut s = serializer.serialize_seq(Some(5))?; s.serialize_element(&self.item_count)?; s.serialize_element(self.item_id.as_ref().unwrap())?; s.serialize_element(&VarInt(0))?; s.serialize_element(to_remove)?; s.serialize_element(self.components_to_remove.as_ref().unwrap())?; s.end() } (Some(to_add), None) => { let mut s = serializer.serialize_seq(Some(5))?; s.serialize_element(&self.item_count)?; s.serialize_element(self.item_id.as_ref().unwrap())?; s.serialize_element(to_add)?; s.serialize_element(&VarInt(0))?; s.serialize_element(self.components_to_add.as_ref().unwrap())?; s.end() } (None, None) => { let mut s = serializer.serialize_seq(Some(4))?; s.serialize_element(&self.item_count)?; s.serialize_element(&self.item_id.as_ref().unwrap())?; s.serialize_element(&VarInt(0))?; s.serialize_element(&VarInt(0))?; s.end() } } } } } impl Slot { pub fn to_item(self) -> Option { let item_id = self.item_id?.0.try_into().unwrap(); Some(Item { item_id, item_count: self.item_count.0.try_into().unwrap(), }) } pub const fn empty() -> Self { Slot { item_count: VarInt(0), item_id: None, num_components_to_add: None, num_components_to_remove: None, components_to_add: None, components_to_remove: None, } } } impl From<&Item> for Slot { fn from(item: &Item) -> Self { Slot { item_count: item.item_count.into(), item_id: Some(item.item_id.into()), // TODO: add these num_components_to_add: None, num_components_to_remove: None, components_to_add: None, components_to_remove: None, } } } impl From> for Slot { fn from(item: Option<&Item>) -> Self { item.map(Slot::from).unwrap_or(Slot::empty()) } }