// ... PRIMITIVE TYPES ... use crate::*; use crate::utils::*; use crate::uuid::UUID4; #[cfg(test)] use crate::protocol::TestRandom; // bool impl Serialize for bool { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_byte(if *self { 1 } else { 0 }) } } impl Deserialize for bool { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { read_one_byte(data)?.try_map(move |b| { match b { 0x00 => Ok(false), 0x01 => Ok(true), other => Err(DeserializeErr::InvalidBool(other)) } }) } } #[cfg(test)] impl TestRandom for bool { fn test_gen_random() -> Self { rand::random() } } // u8 impl Serialize for u8 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_byte(*self) } } impl Deserialize for u8 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { read_one_byte(data) } } #[cfg(test)] impl TestRandom for u8 { fn test_gen_random() -> Self { rand::random() } } // i8 impl Serialize for i8 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_byte(*self as u8) } } impl Deserialize for i8 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(read_one_byte(data)?.map(move |byte| byte as i8)) } } #[cfg(test)] impl TestRandom for i8 { fn test_gen_random() -> Self { rand::random() } } // u16 impl Serialize for u16 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let data = write_short(*self); to.serialize_bytes(&data[..]) } } impl Deserialize for u16 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { read_short(data) } } #[cfg(test)] impl TestRandom for u16 { fn test_gen_random() -> Self { rand::random() } } // i16 impl Serialize for i16 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { (*self as u16).mc_serialize(to) } } impl Deserialize for i16 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { u16::mc_deserialize(data)?.map(move |other| other as i16).into() } } #[cfg(test)] impl TestRandom for i16 { fn test_gen_random() -> Self { rand::random() } } // int impl Serialize for i32 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let data = write_int(*self as u32); to.serialize_bytes(&data[..]) } } impl Deserialize for i32 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(read_int(data)?.map(move |v| v as i32)) } } #[cfg(test)] impl TestRandom for i32 { fn test_gen_random() -> Self { rand::random() } } // long impl Serialize for i64 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let data = write_long(*self as u64); to.serialize_bytes(&data[..]) } } impl Deserialize for i64 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(read_long(data)?.map(move |v| v as i64)) } } #[cfg(test)] impl TestRandom for i64 { fn test_gen_random() -> Self { rand::random() } } // float impl Serialize for f32 { //noinspection ALL fn mc_serialize(&self, to: &mut S) -> SerializeResult { let data = (*self).to_be_bytes(); to.serialize_bytes(&data[..]) } } impl Deserialize for f32 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { i32::mc_deserialize(data)?.map(move |r| f32::from_bits(r as u32)).into() } } #[cfg(test)] impl TestRandom for f32 { fn test_gen_random() -> Self { rand::random() } } // double impl Serialize for f64 { //noinspection ALL fn mc_serialize(&self, to: &mut S) -> SerializeResult { let data = (*self).to_be_bytes(); to.serialize_bytes(&data[..]) } } impl Deserialize for f64 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { i64::mc_deserialize(data)?.map(move |r| f64::from_bits(r as u64)).into() } } #[cfg(test)] impl TestRandom for f64 { fn test_gen_random() -> Self { rand::random() } } // VAR INT AND VAR LONG const VAR_INT_BYTES: usize = 5; const VAR_LONG_BYTES: usize = 10; const DESERIALIZE_VAR_INT: impl for<'b> Fn(&'b [u8]) -> DeserializeResult<'b, u64> = deserialize_var_num(VAR_INT_BYTES); const DESERIALIZE_VAR_LONG: impl for<'b> Fn(&'b [u8]) -> DeserializeResult<'b, u64> = deserialize_var_num(VAR_LONG_BYTES); #[derive(Copy, Clone, PartialOrd, PartialEq, Debug, Default, Hash, Ord, Eq)] pub struct VarInt(pub i32); impl Serialize for VarInt { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let mut data = [0u8; VAR_INT_BYTES]; to.serialize_bytes(serialize_var_num((self.0 as u32) as u64, &mut data)) } } impl Deserialize for VarInt { fn mc_deserialize(orig_data: &[u8]) -> DeserializeResult { Ok(DESERIALIZE_VAR_INT(orig_data)?.map(move |v| VarInt(v as i32))) } } impl Into for VarInt { fn into(self) -> i32 { self.0 } } impl From for VarInt { fn from(v: i32) -> Self { Self(v) } } impl Into for VarInt { fn into(self) -> usize { self.0 as usize } } impl From for VarInt { fn from(v: usize) -> Self { Self(v as i32) } } impl std::fmt::Display for VarInt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "VarInt({})", self.0) } } #[cfg(test)] impl TestRandom for VarInt { fn test_gen_random() -> Self { let out: i32 = rand::random(); Self(out) } } #[derive(Copy, Clone, PartialOrd, PartialEq, Debug, Default, Hash, Ord, Eq)] pub struct VarLong(pub i64); impl Serialize for VarLong { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let mut data = [0u8; VAR_LONG_BYTES]; to.serialize_bytes(serialize_var_num(self.0 as u64, &mut data)) } } impl Deserialize for VarLong { fn mc_deserialize(orig_data: &[u8]) -> DeserializeResult<'_, Self> { Ok(DESERIALIZE_VAR_LONG(orig_data)?.map(move |v| VarLong(v as i64))) } } #[cfg(test)] impl TestRandom for VarLong { fn test_gen_random() -> Self { let out: i64 = rand::random(); Self(out) } } fn serialize_var_num(data: u64, out: &mut [u8]) -> &[u8] { let mut v: u64 = data; let mut byte_idx = 0; let mut has_more = true; while has_more { if byte_idx == out.len() { panic!("tried to write too much data for Var num"); } let mut v_byte = (v & 0x7F) as u8; v >>= 7; has_more = v != 0; if has_more { v_byte |= 0x80; } out[byte_idx] = v_byte; byte_idx += 1; } &out[..byte_idx] } const fn deserialize_var_num(max_bytes: usize) -> impl for<'b> Fn(&'b [u8]) -> DeserializeResult<'b, u64> { move |orig_data| { let mut data = orig_data; let mut v: u64 = 0; let mut bit_place: usize = 0; let mut i: usize = 0; let mut has_more = true; while has_more { if i == max_bytes { return DeserializeErr::VarNumTooLong(Vec::from(&orig_data[..i])).into(); } let Deserialized { value: byte, data: rest } = read_one_byte(data)?; data = rest; has_more = byte & 0x80 != 0; v |= ((byte as u64) & 0x7F) << bit_place; bit_place += 7; i += 1; } Deserialized::ok(v, data) } } // STRING impl Serialize for String { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_other(&VarInt(self.len() as i32))?; to.serialize_bytes(self.as_bytes()) } } impl Deserialize for String { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { VarInt::mc_deserialize(data)?.and_then(move |length, rest| { if length.0 < 0 { Err(DeserializeErr::NegativeLength(length)) } else { take(length.0 as usize)(rest)?.try_map(move |taken| { String::from_utf8(taken.to_vec()) .map_err(DeserializeErr::BadStringEncoding) }) } }) } } #[cfg(test)] impl TestRandom for String { fn test_gen_random() -> Self { let raw_len: u8 = rand::random(); let len = raw_len as usize; let mut out = String::with_capacity(len); for _ in 0..len { let c_idx: u8 = rand::random::() % 36; let c = if c_idx <= 10 { (48 + c_idx) as char } else { ((c_idx - 10) + 65) as char }; out.push(c) } out } } // position #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub struct IntPosition { pub x: i32, pub y: i16, pub z: i32, } impl Serialize for IntPosition { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let x_raw = if self.x < 0 { (self.x + 0x2000000) as u64 | 0x2000000 } else { self.x as u64 } & 0x3FFFFFF; let z_raw = if self.z < 0 { (self.z + 0x2000000) as u64 | 0x2000000 } else { self.z as u64 } & 0x3FFFFFF; let y_raw = if self.y < 0 { (self.y + 0x800) as u64 | 0x800 } else { self.y as u64 } & 0xFFF; let data_raw = ((x_raw << 38) | (z_raw << 12) | y_raw) as u64; let data_i64 = data_raw as i64; to.serialize_other(&data_i64) } } impl Deserialize for IntPosition { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { let Deserialized{ value: raw, data } = i64::mc_deserialize(data)?; let raw_unsigned = raw as u64; let mut x = ((raw_unsigned >> 38) as u32) & 0x3FFFFFF; let mut z = ((raw_unsigned >> 12) & 0x3FFFFFF) as u32; let mut y = ((raw_unsigned & 0xFFF) as u16) & 0xFFF; if (x & 0x2000000) != 0 { // is the 26th bit set // if so, treat the rest as a positive integer, and treat 26th bit as -2^25 // 2^25 == 0x2000000 // 0x1FFFFFF == 2^26 - 1 (all places set to 1 except 26th place) x = (((x & 0x1FFFFFF) as i32) - 0x2000000) as u32; } if (y & 0x800) != 0 { y = (((y & 0x7FF) as i16) - 0x800) as u16; } if (z & 0x2000000) != 0 { z = (((z & 0x1FFFFFF) as i32) - 0x2000000) as u32; } Deserialized::ok(IntPosition{ x: x as i32, y: y as i16, z: z as i32 }, data) } } #[cfg(test)] impl TestRandom for IntPosition { fn test_gen_random() -> Self { let x: i32 = ((rand::random::() % (1 << 26)) as i32) - (1 << 25); let z: i32 = ((rand::random::() % (1 << 26)) as i32) - (1 << 25); let y: i16 = ((rand::random::() % (1 << 12)) as i16) - (1 << 11); Self{ x, y, z } } } // angle #[derive(Copy, Clone, PartialEq, Hash, Debug)] pub struct Angle { pub value: u8 } impl Serialize for Angle { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_byte(self.value) } } impl Deserialize for Angle { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(read_one_byte(data)?.map(move |b| { Angle { value: b } })) } } #[cfg(test)] impl TestRandom for Angle { fn test_gen_random() -> Self { Self{ value: rand::random() } } } // UUID impl Serialize for UUID4 { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let bytes = self.to_u128().to_be_bytes(); to.serialize_bytes(&bytes[..]) } } impl Deserialize for UUID4 { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { take(16)(data)?.map(move |bytes| { let raw = (bytes[0] as u128) << 120 | (bytes[1] as u128) << 112 | (bytes[2] as u128) << 104 | (bytes[3] as u128) << 96 | (bytes[4] as u128) << 88 | (bytes[5] as u128) << 80 | (bytes[6] as u128) << 72 | (bytes[7] as u128) << 64 | (bytes[8] as u128) << 56 | (bytes[9] as u128) << 48 | (bytes[10] as u128) << 40 | (bytes[11] as u128) << 32 | (bytes[12] as u128) << 24 | (bytes[13] as u128) << 16 | (bytes[14] as u128) << 8 | bytes[15] as u128; UUID4::from(raw) }).into() } } #[cfg(test)] impl TestRandom for UUID4 { fn test_gen_random() -> Self { UUID4::random() } } // NBT #[derive(Clone, PartialEq, Debug)] pub struct NamedNbtTag { pub root: nbt::NamedTag } impl Serialize for NamedNbtTag { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let bytes = self.root.bytes(); to.serialize_bytes(bytes.as_slice()) } } impl Deserialize for NamedNbtTag { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(nbt::NamedTag::root_compound_tag_from_bytes(data)?.map(move |root| NamedNbtTag { root })) } } impl From for NamedNbtTag { fn from(root: nbt::NamedTag) -> Self { Self { root } } } impl Into for NamedNbtTag { fn into(self) -> nbt::NamedTag { self.root } } #[cfg(test)] impl TestRandom for NamedNbtTag { fn test_gen_random() -> Self { Self { root: nbt::NamedTag::test_gen_random() } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct FixedInt { raw: i32 } impl Serialize for FixedInt { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_other(&self.raw) } } impl Deserialize for FixedInt { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(i32::mc_deserialize(data)?.map(move |raw| { FixedInt{ raw } })) } } impl FixedInt { pub fn new(data: f64, fractional_bytes: usize) -> Self { Self { raw: (data * ((1 << fractional_bytes) as f64)) as i32 } } pub fn into_float(self, fractional_bytes: usize) -> f64 { (self.raw as f64) / ((1 << fractional_bytes) as f64) } } #[cfg(test)] impl TestRandom for FixedInt { fn test_gen_random() -> Self { FixedInt::new(f64::test_gen_random(), 16) } } // chat #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] pub struct Chat { pub text: String, #[serde(skip_serializing_if = "Option::is_none")] pub bold: Option, #[serde(skip_serializing_if = "Option::is_none")] pub italic: Option, #[serde(skip_serializing_if = "Option::is_none")] pub underlined: Option, #[serde(skip_serializing_if = "Option::is_none")] pub strikethrough: Option, #[serde(skip_serializing_if = "Option::is_none")] pub obfuscated: Option, #[serde(skip_serializing_if = "Option::is_none")] pub color: Option, #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option> } impl ToString for Chat { fn to_string(&self) -> String { self.extra.as_ref() .into_iter() .flat_map(|v| v.into_iter()) .map(|item| item.to_string()) .fold(self.text.clone(), |acc, v| acc + v.as_str()) } } const SECTION_SYMBOL: char = 'ยง'; #[derive(PartialOrd, PartialEq, Debug, Copy, Clone)] pub enum ColorCode { Black, DarkBlue, DarkGreen, DarkAqua, DarkRed, DarkPurple, Gold, Gray, DarkGray, Blue, Green, Aqua, Red, LightPurple, Yellow, White } impl ColorCode { pub fn from_code(i: &char) -> Option { match i { '0' => Some(ColorCode::Black), '1' => Some(ColorCode::DarkBlue), '2' => Some(ColorCode::DarkGreen), '3' => Some(ColorCode::DarkAqua), '4' => Some(ColorCode::DarkRed), '5' => Some(ColorCode::DarkPurple), '6' => Some(ColorCode::Gold), '7' => Some(ColorCode::Gray), '8' => Some(ColorCode::DarkGray), '9' => Some(ColorCode::Blue), 'a' => Some(ColorCode::Green), 'b' => Some(ColorCode::Aqua), 'c' => Some(ColorCode::Red), 'd' => Some(ColorCode::LightPurple), 'e' => Some(ColorCode::Yellow), 'f' => Some(ColorCode::White), _ => None } } pub fn to_code(&self) -> char { match self { ColorCode::Black => '0', ColorCode::DarkBlue => '1', ColorCode::DarkGreen => '2', ColorCode::DarkAqua => '3', ColorCode::DarkRed => '4', ColorCode::DarkPurple => '5', ColorCode::Gold => '6', ColorCode::Gray => '7', ColorCode::DarkGray => '8', ColorCode::Blue => '9', ColorCode::Green => 'a', ColorCode::Aqua => 'b', ColorCode::Red => 'c', ColorCode::LightPurple => 'd', ColorCode::Yellow => 'e', ColorCode::White => 'f', } } pub fn from_name(name: &str) -> Option { match name.to_ascii_lowercase().as_str() { "black" => Some(ColorCode::Black), "dark_blue" => Some(ColorCode::DarkBlue), "dark_green" => Some(ColorCode::DarkGreen), "dark_aqua" => Some(ColorCode::DarkAqua), "dark_red" => Some(ColorCode::DarkRed), "dark_purple" => Some(ColorCode::DarkPurple), "gold" => Some(ColorCode::Gold), "gray" => Some(ColorCode::Gray), "dark_gray" => Some(ColorCode::DarkGray), "blue" => Some(ColorCode::Blue), "green" => Some(ColorCode::Green), "aqua" => Some(ColorCode::Aqua), "red" => Some(ColorCode::Red), "light_purple" => Some(ColorCode::LightPurple), "yellow" => Some(ColorCode::Yellow), "white" => Some(ColorCode::White), _ => None } } pub fn name(&self) -> &str { match self { ColorCode::Black => "black", ColorCode::DarkBlue => "dark_blue", ColorCode::DarkGreen => "dark_green", ColorCode::DarkAqua => "dark_aqua", ColorCode::DarkRed => "dark_red", ColorCode::DarkPurple => "dark_purple", ColorCode::Gold => "gold", ColorCode::Gray => "gray", ColorCode::DarkGray => "dark_gray", ColorCode::Blue => "blue", ColorCode::Green => "green", ColorCode::Aqua => "aqua", ColorCode::Red => "red", ColorCode::LightPurple => "light_purple", ColorCode::Yellow => "yellow", ColorCode::White => "white", } } } #[derive(PartialOrd, PartialEq, Debug, Copy, Clone)] pub enum Formatter { Color(ColorCode), Obfuscated, Bold, Strikethrough, Underline, Italic, Reset } impl Formatter { pub fn from_code(i: &char) -> Option { match i.to_ascii_lowercase() { 'k' => Some(Formatter::Obfuscated), 'l' => Some(Formatter::Bold), 'm' => Some(Formatter::Strikethrough), 'n' => Some(Formatter::Underline), 'o' => Some(Formatter::Italic), 'r' => Some(Formatter::Reset), _ => ColorCode::from_code(i).map(Formatter::Color) } } pub fn code(&self) -> char { match self { Formatter::Color(c) => c.to_code(), Formatter::Obfuscated => 'k', Formatter::Bold => 'l', Formatter::Strikethrough => 'm', Formatter::Underline => 'n', Formatter::Italic => 'o', Formatter::Reset => 'r' } } pub fn from_name(name: &str) -> Option { match name.to_ascii_lowercase().as_str() { "obfuscated" => Some(Formatter::Obfuscated), "bold" => Some(Formatter::Bold), "strikethrough" => Some(Formatter::Strikethrough), "underline" => Some(Formatter::Underline), "italic" => Some(Formatter::Italic), "reset" => Some(Formatter::Reset), _ => ColorCode::from_name(name).map(Formatter::Color) } } pub fn name(&self) -> &str { match self { Formatter::Obfuscated => "obfuscated", Formatter::Bold => "bold", Formatter::Strikethrough => "strikethrough", Formatter::Underline => "underline", Formatter::Italic => "italic", Formatter::Reset => "reset", Formatter::Color(c) => c.name(), } } } impl ToString for Formatter { fn to_string(&self) -> String { vec!(SECTION_SYMBOL, self.code()).into_iter().collect() } } impl Chat { pub fn to_traditional(&self) -> String { self.to_traditional_parts(Vec::::new().as_ref(), None) } fn to_traditional_parts(&self, formatters: &Vec, color: Option) -> String { let mut own_formatters = formatters.clone(); Self::update_formatter(&mut own_formatters, Formatter::Bold, &self.bold); Self::update_formatter(&mut own_formatters, Formatter::Italic, &self.italic); Self::update_formatter(&mut own_formatters, Formatter::Underline, &self.underlined); Self::update_formatter(&mut own_formatters, Formatter::Strikethrough, &self.strikethrough); Self::update_formatter(&mut own_formatters, Formatter::Obfuscated, &self.obfuscated); let own_color_option = self.color.as_ref() .map(String::as_str) .and_then(ColorCode::from_name) .or(color); let own_color = own_color_option .map(Formatter::Color) .map(|f| f.to_string()); let own_formatter = own_formatters .clone() .into_iter() .map(|f| f.to_string()) .fold(String::new(), |acc, v| acc + v.as_str()); let own_color_str = match own_color { Some(v) => v, None => String::new() }; let own_out = own_formatter + own_color_str.as_str() + self.text.as_str(); self.extra.as_ref() .into_iter() .flat_map(|v| v.into_iter()) .map(|child| child.to_traditional_parts(&own_formatters, own_color_option)) .fold(own_out, |acc, next| acc + next.as_str()) } fn update_formatter(to: &mut Vec, formatter: Formatter, v: &Option) { if !to.contains(&formatter) && v.unwrap_or(false) { to.push(formatter) } } pub fn from_text(text: &str) -> Chat { Chat{ text: text.to_owned(), bold: None, italic: None, underlined: None, strikethrough: None, obfuscated: None, color: None, extra: None, } } } impl Serialize for Chat { fn mc_serialize(&self, to: &mut S) -> SerializeResult { serde_json::to_string(self).map_err(move |err| { SerializeErr::FailedJsonEncode(format!("failed to serialize chat {:?}", err)) })?.mc_serialize(to) } } impl Deserialize for Chat { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { String::mc_deserialize(data)?.try_map(move |str| { serde_json::from_str(str.as_str()).map_err(move |err| { DeserializeErr::FailedJsonDeserialize(format!("failed to deserialize chat {:?}", err)) }) }) } } #[cfg(test)] impl TestRandom for Chat { fn test_gen_random() -> Self { let str = String::test_gen_random(); Chat::from_text(str.as_str()) } } #[derive(Default)] pub struct BytesSerializer { data: Vec } impl Serializer for BytesSerializer { fn serialize_bytes(&mut self, data: &[u8]) -> SerializeResult { self.data.extend_from_slice(data); Ok(()) } } impl BytesSerializer { pub fn with_capacity(cap: usize) -> Self { BytesSerializer{ data: Vec::with_capacity(cap), } } pub fn into_bytes(self) -> Vec { self.data } } impl Serialize for Option where T: Serialize { fn mc_serialize(&self, to: &mut S) -> SerializeResult { match self { Some(value) => { to.serialize_other(&true)?; to.serialize_other(value) }, None => { to.serialize_other(&false) } } } } impl Deserialize for Option where T: Deserialize { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { bool::mc_deserialize(data)?.and_then(move |is_present, data| { if is_present { Ok(T::mc_deserialize(data)?.map(move |component| Some(component))) } else { Deserialized::ok(None, data) } }) } } #[cfg(test)] impl TestRandom for Option where T: TestRandom { fn test_gen_random() -> Self { let is_present: bool = rand::random(); if is_present { Some(T::test_gen_random()) } else { None } } } // SLOT #[derive(Debug, PartialEq, Clone)] pub struct Slot { pub item_id: VarInt, pub item_count: i8, pub nbt: Option, } impl Serialize for Slot { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_other(&self.item_id)?; to.serialize_other(&self.item_count)?; match self.nbt.as_ref() { Some(nbt) => to.serialize_bytes(nbt.bytes().as_slice()), None => to.serialize_byte(nbt::Tag::End.id()), } } } impl Deserialize for Slot { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { let Deserialized{ value: item_id, data } = VarInt::mc_deserialize(data)?; let Deserialized{ value: item_count, data } = i8::mc_deserialize(data)?; if data.is_empty() { return Err(DeserializeErr::Eof); } let id = data[0]; let rest = &data[1..]; Ok(match id { 0x00 => Deserialized{ value: None, data: rest }, _ => nbt::read_named_tag(data)?.map(move |tag| Some(tag)) }.map(move |nbt| { Slot{ item_id, item_count, nbt } })) } } #[cfg(test)] impl TestRandom for Slot { fn test_gen_random() -> Self { let item_id = VarInt::test_gen_random(); let item_count = i8::test_gen_random() % 65; let nbt = >::test_gen_random(); Self{ item_id, item_count, nbt } } } #[cfg(test)] mod tests { use super::*; use std::fmt::Debug; #[test] fn test_bool() { test_type(true); test_type(false); } #[test] fn test_signed_byte() { test_type(0i8); test_type(127i8); test_type(-15i8); } #[test] fn test_unsigned_byte() { test_type(0u8); test_type(128u8); test_type(255u8); } #[test] fn test_signed_short() { test_type(0i16); test_type(-88i16); test_type(25521i16); } #[test] fn test_unsigned_short() { test_type(0u16); test_type(1723u16); test_type(65534u16); } #[test] fn test_signed_int() { test_type(0i32); test_type(123127i32); test_type(-171238i32); test_type(2147483647i32); } #[test] fn test_signed_long() { test_type(0i64); test_type(123127i64); test_type(-12123127i64); test_type(2147483647i64); test_type(-10170482028482i64); } #[test] fn test_float() { test_type(0.2313f32); test_type(0f32); test_type(123123213f32); test_type(-123123f32); } #[test] fn test_double() { test_type(0.2313f64); test_type(0f64); test_type(123123213f64); test_type(-123123f64); } #[test] fn test_var_int() { test_type(VarInt(0)); test_type(VarInt(1231231)); test_type(VarInt(2147483647)); test_type(VarInt(-2147483648)); test_type(VarInt(-1)); test_type(VarInt(-1001237)); } #[test] fn test_var_long() { test_type(VarLong(0)); test_type(VarLong(1231231)); test_type(VarLong(12312319123)); test_type(VarLong(9223372036854775807)); test_type(VarLong(-1)); test_type(VarLong(-12312319123)); test_type(VarLong(-9223372036854775808)); test_type(VarLong(-1001237)); } #[test] fn test_string() { test_type(String::from("hello my name is joey 123")); test_type(String::from("")); test_type(String::from("AAAA")); test_type(String::from("hello my name is joey 123").repeat(1000)); } #[test] fn test_nbt() { test_type(NamedNbtTag {root: nbt::Tag::Compound(vec!( nbt::Tag::String("test 123".to_owned()).with_name("abc 123") )).with_name("root")}) } #[test] fn test_int_position() { test_type(IntPosition{ x: 12312, y: -32, z: 321312, }); test_type(IntPosition{ x: 12312, y: -32, z: -321312, }); test_type(IntPosition{ x: -12312, y: -32, z: -321312, }); test_type(IntPosition{ x: -12312, y: 32, z: 321312, }); test_type(IntPosition{ x: 0, y: 0, z: 0, }); test_type(IntPosition{ x: 48, y: 232, z: 12, }); test_type(IntPosition{ x: 33554431, y: 2047, z: 33554431, }); test_type(IntPosition{ x: -33554432, y: -2048, z: -33554432, }); test_type(IntPosition{ x: 3, y: 0, z: 110655, }); } #[test] fn test_uuid() { for _ in 0..5 { test_type(UUID4::random()); } } #[test] fn test_angle() { test_type(Angle{ value: 0, }); test_type(Angle{ value: 24, }); test_type(Angle{ value: 255, }); test_type(Angle{ value: 8, }); } fn test_type(value: S) { let bytes = { let mut test = BytesSerializer::default(); value.mc_serialize(&mut test).expect("serialization should succeed"); test.into_bytes() }; let deserialized = S::mc_deserialize(bytes.as_slice()).expect("deserialization should succeed"); assert!(deserialized.data.is_empty()); assert_eq!(deserialized.value, value, "deserialized value == serialized value"); let re_serialized = { let mut test = BytesSerializer::default(); deserialized.value.mc_serialize(&mut test).expect("serialization should succeed"); test.into_bytes() }; assert_eq!(re_serialized, bytes, "serialized value == original serialized bytes"); } }