From 7b6b7e49215933644dbd0e1bb51919947aa6ff08 Mon Sep 17 00:00:00 2001 From: Vladislavs Golubs <vladislavs.golubs@yandex.ru> Date: Sun, 12 Sep 2021 17:08:04 +0300 Subject: [PATCH] Change project layout --- protocol-derive/src/lib.rs | 18 +- protocol/src/{ => data}/chat.rs | 6 +- protocol/src/data/mod.rs | 2 + protocol/src/data/server_status.rs | 32 + protocol/src/decoder.rs | 285 +++++++++ protocol/src/encoder.rs | 253 ++++++++ protocol/src/error.rs | 106 ++++ protocol/src/lib.rs | 630 +------------------ protocol/src/version/mod.rs | 1 + protocol/src/{ => version/v1_14_4}/game.rs | 49 +- protocol/src/{ => version/v1_14_4}/login.rs | 58 +- protocol/src/version/v1_14_4/mod.rs | 3 + protocol/src/{ => version/v1_14_4}/status.rs | 56 +- 13 files changed, 779 insertions(+), 720 deletions(-) rename protocol/src/{ => data}/chat.rs (98%) create mode 100644 protocol/src/data/mod.rs create mode 100644 protocol/src/data/server_status.rs create mode 100644 protocol/src/decoder.rs create mode 100644 protocol/src/encoder.rs create mode 100644 protocol/src/error.rs create mode 100644 protocol/src/version/mod.rs rename protocol/src/{ => version/v1_14_4}/game.rs (89%) rename protocol/src/{ => version/v1_14_4}/login.rs (86%) create mode 100644 protocol/src/version/v1_14_4/mod.rs rename protocol/src/{ => version/v1_14_4}/status.rs (77%) diff --git a/protocol-derive/src/lib.rs b/protocol-derive/src/lib.rs index a497019..ef4bafc 100644 --- a/protocol-derive/src/lib.rs +++ b/protocol-derive/src/lib.rs @@ -39,7 +39,7 @@ fn impl_encoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { // This is special case because max length are used only for strings. if let Some(max_length) = parsed_meta.max_length { return quote! { - crate::EncoderWriteExt::write_string(writer, &self.#name, #max_length)?; + crate::encoder::EncoderWriteExt::write_string(writer, &self.#name, #max_length)?; }; } @@ -47,14 +47,14 @@ fn impl_encoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { let module_ident = Ident::new(&module, Span::call_site()); quote! { - crate::#module_ident::encode(&self.#name, writer)?; + crate::encoder::#module_ident::encode(&self.#name, writer)?; } }); quote! { #[automatically_derived] - impl crate::Encoder for #name { - fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::EncodeError> { + impl crate::encoder::Encoder for #name { + fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::error::EncodeError> { #encode Ok(()) @@ -74,7 +74,7 @@ fn impl_decoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { // This is special case because max length are used only for strings. if let Some(max_length) = parsed_meta.max_length { return quote! { - let #name = crate::DecoderReadExt::read_string(reader, #max_length)?; + let #name = crate::decoder::DecoderReadExt::read_string(reader, #max_length)?; }; } @@ -83,12 +83,12 @@ fn impl_decoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { let module_ident = Ident::new(&module, Span::call_site()); quote! { - let #name = crate::#module_ident::decode(reader)?; + let #name = crate::decoder::#module_ident::decode(reader)?; } } None => { quote! { - let #name = <#ty as crate::Decoder>::decode(reader)?; + let #name = <#ty as crate::decoder::Decoder>::decode(reader)?; } } } @@ -104,10 +104,10 @@ fn impl_decoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { quote! { #[automatically_derived] - impl crate::Decoder for #name { + impl crate::decoder::Decoder for #name { type Output = Self; - fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> { + fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::error::DecodeError> { #decode Ok(#name { diff --git a/protocol/src/chat.rs b/protocol/src/data/chat.rs similarity index 98% rename from protocol/src/chat.rs rename to protocol/src/data/chat.rs index 8ad49c6..1f7774e 100644 --- a/protocol/src/chat.rs +++ b/protocol/src/data/chat.rs @@ -6,7 +6,7 @@ //! ## Serialize //! //! ``` -//! use minecraft_protocol::chat::{Payload, Color, MessageBuilder}; +//! use minecraft_protocol::data::chat::{MessageBuilder, Payload, Color}; //! //! let message = MessageBuilder::builder(Payload::text("Hello")) //! .color(Color::Yellow) @@ -25,7 +25,7 @@ //! ## Deserialize //! //! ``` -//! use minecraft_protocol::chat::{MessageBuilder, Color, Payload, Message}; +//! use minecraft_protocol::data::chat::{MessageBuilder, Payload, Message, Color}; //! //! let json = r#" //! { @@ -93,7 +93,7 @@ pub enum Color { /// # Examples /// /// ``` - /// use minecraft_protocol::chat::Color; + /// use minecraft_protocol::data::chat::Color; /// /// let color = Color::Hex("#f98aff".into()); /// ``` diff --git a/protocol/src/data/mod.rs b/protocol/src/data/mod.rs new file mode 100644 index 0000000..a9b9724 --- /dev/null +++ b/protocol/src/data/mod.rs @@ -0,0 +1,2 @@ +pub mod chat; +pub mod server_status; diff --git a/protocol/src/data/server_status.rs b/protocol/src/data/server_status.rs new file mode 100644 index 0000000..851c985 --- /dev/null +++ b/protocol/src/data/server_status.rs @@ -0,0 +1,32 @@ +use crate::data::chat::Message; +use crate::impl_json_encoder_decoder; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServerStatus { + pub version: ServerVersion, + pub players: OnlinePlayers, + pub description: Message, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServerVersion { + pub name: String, + pub protocol: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct OnlinePlayers { + pub max: u32, + pub online: u32, + pub sample: Vec<OnlinePlayer>, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct OnlinePlayer { + pub name: String, + pub id: Uuid, +} + +impl_json_encoder_decoder!(ServerStatus); diff --git a/protocol/src/decoder.rs b/protocol/src/decoder.rs new file mode 100644 index 0000000..825e478 --- /dev/null +++ b/protocol/src/decoder.rs @@ -0,0 +1,285 @@ +use crate::error::DecodeError; +use byteorder::{BigEndian, ReadBytesExt}; +use nbt::CompoundTag; +use num_traits::FromPrimitive; +use std::io::Read; +use uuid::Uuid; + +pub trait Decoder { + type Output; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>; +} + +/// Trait adds additional helper methods for `Read` to read protocol data. +pub trait DecoderReadExt { + fn read_bool(&mut self) -> Result<bool, DecodeError>; + + fn read_string(&mut self, max_length: u16) -> Result<String, DecodeError>; + + fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>; + + fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError>; + + fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError>; + + fn read_var_i32(&mut self) -> Result<i32, DecodeError>; + + fn read_var_i64(&mut self) -> Result<i64, DecodeError>; +} + +macro_rules! read_signed_var_int ( + ($type: ident, $name: ident, $max_bytes: expr) => ( + fn $name(&mut self) -> Result<$type, DecodeError> { + let mut bytes = 0; + let mut output = 0; + + loop { + let byte = self.read_u8()?; + let value = (byte & 0b01111111) as $type; + + output |= value << 7 * bytes; + bytes += 1; + + if bytes > $max_bytes { + return Err(DecodeError::VarIntTooLong { max_bytes: $max_bytes }) + } + + if (byte & 0b10000000) == 0 { + break; + } + } + + Ok(output) + } + ); +); + +impl<R: Read> DecoderReadExt for R { + fn read_bool(&mut self) -> Result<bool, DecodeError> { + match self.read_u8()? { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(DecodeError::NonBoolValue), + } + } + + fn read_string(&mut self, max_length: u16) -> Result<String, DecodeError> { + let length = self.read_var_i32()? as usize; + + if length as u16 > max_length { + return Err(DecodeError::StringTooLong { length, max_length }); + } + + let mut buf = vec![0; length as usize]; + self.read_exact(&mut buf)?; + + Ok(String::from_utf8(buf)?) + } + + fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError> { + let length = self.read_var_i32()?; + + let mut buf = vec![0; length as usize]; + self.read_exact(&mut buf)?; + + Ok(buf) + } + + fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError> { + let type_id = self.read_u8()?; + let result = FromPrimitive::from_u8(type_id); + + result.ok_or_else(|| DecodeError::UnknownEnumType { type_id }) + } + + fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError> { + Ok(nbt::decode::read_compound_tag(self)?) + } + + read_signed_var_int!(i32, read_var_i32, 5); + read_signed_var_int!(i64, read_var_i64, 10); +} + +impl Decoder for u8 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_u8()?) + } +} + +impl Decoder for i16 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_i16::<BigEndian>()?) + } +} + +impl Decoder for i32 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_i32::<BigEndian>()?) + } +} + +impl Decoder for u16 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_u16::<BigEndian>()?) + } +} + +impl Decoder for u32 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_u32::<BigEndian>()?) + } +} + +impl Decoder for i64 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_i64::<BigEndian>()?) + } +} + +impl Decoder for u64 { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_u64::<BigEndian>()?) + } +} + +impl Decoder for String { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_string(32_768)?) + } +} + +impl Decoder for bool { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_bool()?) + } +} + +impl Decoder for Vec<u8> { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_byte_array()?) + } +} + +impl Decoder for Uuid { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + let mut buf = [0; 16]; + reader.read_exact(&mut buf)?; + + Ok(Uuid::from_bytes(buf)) + } +} + +impl Decoder for CompoundTag { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + Ok(reader.read_compound_tag()?) + } +} + +impl Decoder for Vec<CompoundTag> { + type Output = Self; + + fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { + let length = reader.read_var_i32()? as usize; + let mut vec = Vec::with_capacity(length); + + for _ in 0..length { + let compound_tag = reader.read_compound_tag()?; + vec.push(compound_tag); + } + + Ok(vec) + } +} + +pub mod var_int { + use crate::decoder::DecoderReadExt; + use crate::error::DecodeError; + use std::io::Read; + + pub fn decode<R: Read>(reader: &mut R) -> Result<i32, DecodeError> { + Ok(reader.read_var_i32()?) + } +} + +pub mod var_long { + use crate::decoder::DecoderReadExt; + use crate::error::DecodeError; + use std::io::Read; + + pub fn decode<R: Read>(reader: &mut R) -> Result<i64, DecodeError> { + Ok(reader.read_var_i64()?) + } +} + +pub mod rest { + use crate::error::DecodeError; + use std::io::Read; + + pub fn decode<R: Read>(reader: &mut R) -> Result<Vec<u8>, DecodeError> { + let mut data = Vec::new(); + reader.read_to_end(data.as_mut())?; + + Ok(data) + } +} + +pub mod uuid_hyp_str { + use crate::decoder::DecoderReadExt; + use crate::error::DecodeError; + use std::io::Read; + use uuid::Uuid; + + pub fn decode<R: Read>(reader: &mut R) -> Result<Uuid, DecodeError> { + let uuid_hyphenated_string = reader.read_string(36)?; + let uuid = Uuid::parse_str(&uuid_hyphenated_string)?; + + Ok(uuid) + } +} + +#[cfg(test)] +mod tests { + use crate::decoder::DecoderReadExt; + use std::io::Cursor; + + #[test] + fn test_read_variable_i32_2_bytes_value() { + let mut cursor = Cursor::new(vec![0b10101100, 0b00000010]); + let value = cursor.read_var_i32().unwrap(); + + assert_eq!(value, 300); + } + + #[test] + fn test_read_variable_i32_5_bytes_value() { + let mut cursor = Cursor::new(vec![0xff, 0xff, 0xff, 0xff, 0x07]); + let value = cursor.read_var_i32().unwrap(); + + assert_eq!(value, 2147483647); + } +} diff --git a/protocol/src/encoder.rs b/protocol/src/encoder.rs new file mode 100644 index 0000000..6ea4b77 --- /dev/null +++ b/protocol/src/encoder.rs @@ -0,0 +1,253 @@ +use crate::error::EncodeError; +use byteorder::{BigEndian, WriteBytesExt}; +use nbt::CompoundTag; +use num_traits::ToPrimitive; +use std::io::Write; +use uuid::Uuid; + +pub trait Encoder { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError>; +} + +/// Trait adds additional helper methods for `Write` to write protocol data. +pub trait EncoderWriteExt { + fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>; + + fn write_string(&mut self, value: &str, max_length: u16) -> Result<(), EncodeError>; + + fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError>; + + fn write_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError>; + + fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError>; + + fn write_var_i32(&mut self, value: i32) -> Result<(), EncodeError>; + + fn write_var_i64(&mut self, value: i64) -> Result<(), EncodeError>; +} + +macro_rules! write_signed_var_int ( + ($type: ident, $name: ident) => ( + fn $name(&mut self, mut value: $type) -> Result<(), EncodeError> { + loop { + let mut byte = (value & 0b01111111) as u8; + value = value >> 7; + + if value != 0 { + byte |= 0b10000000; + } + + self.write_u8(byte)?; + + if value == 0 { + break; + } + } + + Ok(()) + } + ) +); + +impl<W: Write> EncoderWriteExt for W { + fn write_bool(&mut self, value: bool) -> Result<(), EncodeError> { + if value { + self.write_u8(1)?; + } else { + self.write_u8(0)?; + } + + Ok(()) + } + + fn write_string(&mut self, value: &str, max_length: u16) -> Result<(), EncodeError> { + let length = value.len(); + + if length > max_length as usize { + return Err(EncodeError::StringTooLong { length, max_length }); + } + + self.write_var_i32(value.len() as i32)?; + self.write_all(value.as_bytes())?; + + Ok(()) + } + + fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError> { + self.write_var_i32(value.len() as i32)?; + self.write_all(value)?; + + Ok(()) + } + + fn write_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError> { + let type_value = ToPrimitive::to_u8(value).unwrap(); + self.write_u8(type_value)?; + + Ok(()) + } + + fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError> { + nbt::encode::write_compound_tag(self, value.clone())?; + + Ok(()) + } + + write_signed_var_int!(i32, write_var_i32); + write_signed_var_int!(i64, write_var_i64); +} + +impl Encoder for u8 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u8(*self)?) + } +} + +impl Encoder for i16 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_i16::<BigEndian>(*self)?) + } +} + +impl Encoder for i32 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_i32::<BigEndian>(*self)?) + } +} + +impl Encoder for u16 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u16::<BigEndian>(*self)?) + } +} + +impl Encoder for u32 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u32::<BigEndian>(*self)?) + } +} + +impl Encoder for i64 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_i64::<BigEndian>(*self)?) + } +} + +impl Encoder for u64 { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u64::<BigEndian>(*self)?) + } +} + +impl Encoder for String { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_string(self, 32_768)?) + } +} + +impl Encoder for bool { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_bool(*self)?) + } +} + +impl Encoder for Vec<u8> { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_byte_array(self)?) + } +} + +impl Encoder for Uuid { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_all(self.as_bytes())?) + } +} + +impl Encoder for CompoundTag { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_compound_tag(self)?) + } +} + +impl Encoder for Vec<CompoundTag> { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + writer.write_var_i32(self.len() as i32)?; + + for compound_tag in self { + writer.write_compound_tag(&compound_tag)?; + } + + Ok(()) + } +} + +pub mod var_int { + use crate::encoder::EncoderWriteExt; + use crate::error::EncodeError; + use std::io::Write; + + pub fn encode<W: Write>(value: &i32, writer: &mut W) -> Result<(), EncodeError> { + writer.write_var_i32(*value)?; + + Ok(()) + } +} + +pub mod var_long { + use crate::encoder::EncoderWriteExt; + use crate::error::EncodeError; + use std::io::Write; + + pub fn encode<W: Write>(value: &i64, writer: &mut W) -> Result<(), EncodeError> { + writer.write_var_i64(*value)?; + + Ok(()) + } +} + +pub mod rest { + use crate::error::EncodeError; + use std::io::Write; + + pub fn encode<W: Write>(value: &[u8], writer: &mut W) -> Result<(), EncodeError> { + writer.write_all(value)?; + + Ok(()) + } +} + +pub mod uuid_hyp_str { + use crate::encoder::EncoderWriteExt; + use crate::error::EncodeError; + use std::io::Write; + use uuid::Uuid; + + pub fn encode<W: Write>(value: &Uuid, writer: &mut W) -> Result<(), EncodeError> { + let uuid_hyphenated_string = value.to_hyphenated().to_string(); + writer.write_string(&uuid_hyphenated_string, 36)?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::encoder::EncoderWriteExt; + use std::io::Cursor; + + #[test] + fn test_write_variable_i32_2_bytes_value() { + let mut cursor = Cursor::new(Vec::with_capacity(5)); + cursor.write_var_i32(300).unwrap(); + + assert_eq!(cursor.into_inner(), vec![0b10101100, 0b00000010]); + } + + #[test] + fn test_write_variable_i32_5_bytes_value() { + let mut cursor = Cursor::new(Vec::with_capacity(5)); + cursor.write_var_i32(2147483647).unwrap(); + + assert_eq!(cursor.into_inner(), vec![0xff, 0xff, 0xff, 0xff, 0x07]); + } +} diff --git a/protocol/src/error.rs b/protocol/src/error.rs new file mode 100644 index 0000000..0f80953 --- /dev/null +++ b/protocol/src/error.rs @@ -0,0 +1,106 @@ +use nbt::decode::TagDecodeError; +use serde_json::error::Error as JsonError; +use std::io::Error as IoError; +use std::string::FromUtf8Error; +use uuid::parser::ParseError as UuidParseError; + +/// Possible errors while encoding packet. +#[derive(Debug)] +pub enum EncodeError { + /// String length can't be more than provided value. + StringTooLong { + /// String length. + length: usize, + /// Max string length. + max_length: u16, + }, + IOError { + io_error: IoError, + }, + JsonError { + json_error: JsonError, + }, +} + +impl From<IoError> for EncodeError { + fn from(io_error: IoError) -> Self { + EncodeError::IOError { io_error } + } +} + +impl From<JsonError> for EncodeError { + fn from(json_error: JsonError) -> Self { + EncodeError::JsonError { json_error } + } +} + +/// Possible errors while decoding packet. +#[derive(Debug)] +pub enum DecodeError { + /// Packet was not recognized. Invalid data or wrong protocol version. + UnknownPacketType { + type_id: u8, + }, + /// String length can't be more than provided value. + StringTooLong { + /// String length. + length: usize, + /// Max string length. + max_length: u16, + }, + IOError { + io_error: IoError, + }, + JsonError { + json_error: JsonError, + }, + /// Byte array was not recognized as valid UTF-8 string. + Utf8Error { + utf8_error: FromUtf8Error, + }, + /// Boolean are parsed from byte. Valid byte value are 0 or 1. + NonBoolValue, + UuidParseError { + uuid_parse_error: UuidParseError, + }, + /// Type id was not parsed as valid enum value. + UnknownEnumType { + type_id: u8, + }, + TagDecodeError { + tag_decode_error: TagDecodeError, + }, + VarIntTooLong { + max_bytes: usize, + }, +} + +impl From<IoError> for DecodeError { + fn from(io_error: IoError) -> Self { + DecodeError::IOError { io_error } + } +} + +impl From<JsonError> for DecodeError { + fn from(json_error: JsonError) -> Self { + DecodeError::JsonError { json_error } + } +} + +impl From<FromUtf8Error> for DecodeError { + fn from(utf8_error: FromUtf8Error) -> Self { + DecodeError::Utf8Error { utf8_error } + } +} + +impl From<UuidParseError> for DecodeError { + fn from(uuid_parse_error: UuidParseError) -> Self { + DecodeError::UuidParseError { uuid_parse_error } + } +} + +impl From<TagDecodeError> for DecodeError { + fn from(tag_decode_error: TagDecodeError) -> Self { + DecodeError::TagDecodeError { tag_decode_error } + } +} diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index fa0aa78..aa92f71 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -1,521 +1,29 @@ //! This crate implements Minecraft protocol. //! //! Information about protocol can be found at https://wiki.vg/Protocol. -use io::Error as IoError; -use std::io; -use std::io::{Cursor, Read, Write}; -use std::string::FromUtf8Error; +pub mod data; +pub mod decoder; +pub mod encoder; +pub mod error; +pub mod version; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use serde_json::error::Error as JsonError; -use uuid::parser::ParseError as UuidParseError; - -use crate::chat::Message; -use nbt::decode::TagDecodeError; -use nbt::CompoundTag; -use num_traits::{FromPrimitive, ToPrimitive}; -use uuid::Uuid; - -pub mod chat; -pub mod game; -pub mod login; -pub mod status; - -/// Current supported protocol version. -pub const PROTOCOL_VERSION: u32 = 498; /// Protocol limits maximum string length. const STRING_MAX_LENGTH: u16 = 32_768; -const HYPHENATED_UUID_LENGTH: u16 = 36; - -/// Possible errors while encoding packet. -#[derive(Debug)] -pub enum EncodeError { - /// String length can't be more than provided value. - StringTooLong { - /// String length. - length: usize, - /// Max string length. - max_length: u16, - }, - IOError { - io_error: IoError, - }, - JsonError { - json_error: JsonError, - }, -} - -impl From<IoError> for EncodeError { - fn from(io_error: IoError) -> Self { - EncodeError::IOError { io_error } - } -} - -impl From<JsonError> for EncodeError { - fn from(json_error: JsonError) -> Self { - EncodeError::JsonError { json_error } - } -} - -/// Possible errors while decoding packet. -#[derive(Debug)] -pub enum DecodeError { - /// Packet was not recognized. Invalid data or wrong protocol version. - UnknownPacketType { - type_id: u8, - }, - /// String length can't be more than provided value. - StringTooLong { - /// String length. - length: usize, - /// Max string length. - max_length: u16, - }, - IOError { - io_error: IoError, - }, - JsonError { - json_error: JsonError, - }, - /// Byte array was not recognized as valid UTF-8 string. - Utf8Error { - utf8_error: FromUtf8Error, - }, - /// Boolean are parsed from byte. Valid byte value are 0 or 1. - NonBoolValue, - UuidParseError { - uuid_parse_error: UuidParseError, - }, - // Type id was not parsed as valid enum value. - UnknownEnumType { - type_id: u8, - }, - TagDecodeError { - tag_decode_error: TagDecodeError, - }, - VarIntTooLong { - max_bytes: usize, - }, -} - -impl From<IoError> for DecodeError { - fn from(io_error: IoError) -> Self { - DecodeError::IOError { io_error } - } -} - -impl From<JsonError> for DecodeError { - fn from(json_error: JsonError) -> Self { - DecodeError::JsonError { json_error } - } -} - -impl From<FromUtf8Error> for DecodeError { - fn from(utf8_error: FromUtf8Error) -> Self { - DecodeError::Utf8Error { utf8_error } - } -} - -impl From<UuidParseError> for DecodeError { - fn from(uuid_parse_error: UuidParseError) -> Self { - DecodeError::UuidParseError { uuid_parse_error } - } -} - -impl From<TagDecodeError> for DecodeError { - fn from(tag_decode_error: TagDecodeError) -> Self { - DecodeError::TagDecodeError { tag_decode_error } - } -} - -trait Encoder { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError>; -} - -trait Decoder { - type Output; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>; -} - -macro_rules! write_signed_var_int ( - ($type: ident, $name: ident) => ( - fn $name(&mut self, mut value: $type) -> Result<(), EncodeError> { - loop { - let mut byte = (value & 0b01111111) as u8; - value = value >> 7; - - if value != 0 { - byte |= 0b10000000; - } - - self.write_u8(byte)?; - - if value == 0 { - break; - } - } - - Ok(()) - } - ) -); - -macro_rules! read_signed_var_int ( - ($type: ident, $name: ident, $max_bytes: expr) => ( - fn $name(&mut self) -> Result<$type, DecodeError> { - let mut bytes = 0; - let mut output = 0; - - loop { - let byte = self.read_u8()?; - let value = (byte & 0b01111111) as $type; - - output |= value << 7 * bytes; - bytes += 1; - - if bytes > $max_bytes { - return Err(DecodeError::VarIntTooLong { max_bytes: $max_bytes }) - } - - if (byte & 0b10000000) == 0 { - break; - } - } - - Ok(output) - } - ); -); - -/// Trait adds additional helper methods for `Write` to write protocol data. -trait EncoderWriteExt { - fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>; - - fn write_string(&mut self, value: &str, max_length: u16) -> Result<(), EncodeError>; - - fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError>; - - fn write_chat_message(&mut self, value: &Message) -> Result<(), EncodeError>; - - fn write_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError>; - - fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError>; - - fn write_var_i32(&mut self, value: i32) -> Result<(), EncodeError>; - - fn write_var_i64(&mut self, value: i64) -> Result<(), EncodeError>; -} - -/// Trait adds additional helper methods for `Read` to read protocol data. -trait DecoderReadExt { - fn read_bool(&mut self) -> Result<bool, DecodeError>; - - fn read_string(&mut self, max_length: u16) -> Result<String, DecodeError>; - - fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>; - - fn read_chat_message(&mut self) -> Result<Message, DecodeError>; - - fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError>; - - fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError>; - - fn read_var_i32(&mut self) -> Result<i32, DecodeError>; - - fn read_var_i64(&mut self) -> Result<i64, DecodeError>; -} - -impl<W: Write> EncoderWriteExt for W { - fn write_bool(&mut self, value: bool) -> Result<(), EncodeError> { - if value { - self.write_u8(1)?; - } else { - self.write_u8(0)?; - } - - Ok(()) - } - - fn write_string(&mut self, value: &str, max_length: u16) -> Result<(), EncodeError> { - let length = value.len(); - - if length > max_length as usize { - return Err(EncodeError::StringTooLong { length, max_length }); - } - - self.write_var_i32(value.len() as i32)?; - self.write_all(value.as_bytes())?; - - Ok(()) - } - - fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError> { - self.write_var_i32(value.len() as i32)?; - self.write_all(value)?; - - Ok(()) - } - - fn write_chat_message(&mut self, value: &Message) -> Result<(), EncodeError> { - self.write_string(&value.to_json()?, STRING_MAX_LENGTH) - } - - fn write_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError> { - let type_value = ToPrimitive::to_u8(value).unwrap(); - self.write_u8(type_value)?; - - Ok(()) - } - - fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError> { - nbt::encode::write_compound_tag(self, value.clone())?; - - Ok(()) - } - - write_signed_var_int!(i32, write_var_i32); - write_signed_var_int!(i64, write_var_i64); -} - -impl<R: Read> DecoderReadExt for R { - fn read_bool(&mut self) -> Result<bool, DecodeError> { - match self.read_u8()? { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(DecodeError::NonBoolValue), - } - } - - fn read_string(&mut self, max_length: u16) -> Result<String, DecodeError> { - let length = self.read_var_i32()? as usize; - - if length as u16 > max_length { - return Err(DecodeError::StringTooLong { length, max_length }); - } - - let mut buf = vec![0; length as usize]; - self.read_exact(&mut buf)?; - - Ok(String::from_utf8(buf)?) - } - - fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError> { - let length = self.read_var_i32()?; - - let mut buf = vec![0; length as usize]; - self.read_exact(&mut buf)?; - - Ok(buf) - } - - fn read_chat_message(&mut self) -> Result<Message, DecodeError> { - let json = self.read_string(STRING_MAX_LENGTH)?; - let message = Message::from_json(&json)?; - - Ok(message) - } - - fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError> { - let type_id = self.read_u8()?; - let result = FromPrimitive::from_u8(type_id); - - result.ok_or_else(|| DecodeError::UnknownEnumType { type_id }) - } - - fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError> { - Ok(nbt::decode::read_compound_tag(self)?) - } - - read_signed_var_int!(i32, read_var_i32, 5); - read_signed_var_int!(i64, read_var_i64, 10); -} - -impl Encoder for u8 { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_u8(*self)?) - } -} - -impl Decoder for u8 { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_u8()?) - } -} - -impl Encoder for i32 { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_i32::<BigEndian>(*self)?) - } -} - -impl Decoder for i32 { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_i32::<BigEndian>()?) - } -} - -impl Encoder for u32 { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_u32::<BigEndian>(*self)?) - } -} - -impl Decoder for u32 { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_u32::<BigEndian>()?) - } -} - -impl Encoder for i64 { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_i64::<BigEndian>(*self)?) - } -} - -impl Decoder for i64 { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_i64::<BigEndian>()?) - } -} - -impl Encoder for u64 { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_u64::<BigEndian>(*self)?) - } -} - -impl Decoder for u64 { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_u64::<BigEndian>()?) - } -} - -impl Encoder for String { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_string(self, STRING_MAX_LENGTH)?) - } -} - -impl Decoder for String { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_string(STRING_MAX_LENGTH)?) - } -} - -impl Encoder for bool { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_bool(*self)?) - } -} - -impl Decoder for bool { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_bool()?) - } -} - -impl Encoder for Vec<u8> { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_byte_array(self)?) - } -} - -impl Decoder for Vec<u8> { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_byte_array()?) - } -} - -impl Encoder for Uuid { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_all(self.as_bytes())?) - } -} - -impl Decoder for Uuid { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - let mut buf = [0; 16]; - reader.read_exact(&mut buf)?; - - Ok(Uuid::from_bytes(buf)) - } -} - -impl Encoder for CompoundTag { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - Ok(writer.write_compound_tag(self)?) - } -} - -impl Decoder for CompoundTag { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - Ok(reader.read_compound_tag()?) - } -} - -impl Encoder for Vec<CompoundTag> { - fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i32(self.len() as i32)?; - - for compound_tag in self { - writer.write_compound_tag(&compound_tag)?; - } - - Ok(()) - } -} - -impl Decoder for Vec<CompoundTag> { - type Output = Self; - - fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { - let length = reader.read_var_i32()? as usize; - let mut vec = Vec::with_capacity(length); - - for _ in 0..length { - let compound_tag = reader.read_compound_tag()?; - vec.push(compound_tag); - } - - Ok(vec) - } -} #[macro_export] macro_rules! impl_enum_encoder_decoder ( ($ty: ident) => ( - impl crate::Encoder for $ty { - fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::EncodeError> { - Ok(crate::EncoderWriteExt::write_enum(writer, self)?) + impl crate::encoder::Encoder for $ty { + fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::error::EncodeError> { + Ok(crate::encoder::EncoderWriteExt::write_enum(writer, self)?) } } - impl crate::Decoder for $ty { + impl crate::decoder::Decoder for $ty { type Output = Self; - fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> { - Ok(crate::DecoderReadExt::read_enum(reader)?) + fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::error::DecodeError> { + Ok(crate::decoder::DecoderReadExt::read_enum(reader)?) } } ); @@ -524,127 +32,23 @@ macro_rules! impl_enum_encoder_decoder ( #[macro_export] macro_rules! impl_json_encoder_decoder ( ($ty: ident) => ( - impl crate::Encoder for $ty { - fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::EncodeError> { + impl crate::encoder::Encoder for $ty { + fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::error::EncodeError> { let json = serde_json::to_string(self)?; - crate::EncoderWriteExt::write_string(writer, &json, crate::STRING_MAX_LENGTH)?; + crate::encoder::EncoderWriteExt::write_string(writer, &json, crate::STRING_MAX_LENGTH)?; Ok(()) } } - impl crate::Decoder for $ty { + impl crate::decoder::Decoder for $ty { type Output = Self; - fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> { - let json = crate::DecoderReadExt::read_string(reader, crate::STRING_MAX_LENGTH)?; + fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::error::DecodeError> { + let json = crate::decoder::DecoderReadExt::read_string(reader, crate::STRING_MAX_LENGTH)?; Ok(serde_json::from_str(&json)?) } } ); ); - -mod var_int { - use crate::{DecodeError, EncodeError}; - use crate::{DecoderReadExt, EncoderWriteExt}; - use std::io::{Read, Write}; - - pub fn encode<W: Write>(value: &i32, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i32(*value)?; - - Ok(()) - } - - pub fn decode<R: Read>(reader: &mut R) -> Result<i32, DecodeError> { - Ok(reader.read_var_i32()?) - } -} - -mod var_long { - use crate::{DecodeError, EncodeError}; - use crate::{DecoderReadExt, EncoderWriteExt}; - use std::io::{Read, Write}; - - pub fn encode<W: Write>(value: &i64, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i64(*value)?; - - Ok(()) - } - - pub fn decode<R: Read>(reader: &mut R) -> Result<i64, DecodeError> { - Ok(reader.read_var_i64()?) - } -} - -mod rest { - use crate::{DecodeError, EncodeError}; - use std::io::{Read, Write}; - - pub fn encode<W: Write>(value: &[u8], writer: &mut W) -> Result<(), EncodeError> { - writer.write_all(value)?; - - Ok(()) - } - - pub fn decode<R: Read>(reader: &mut R) -> Result<Vec<u8>, DecodeError> { - let mut data = Vec::new(); - reader.read_to_end(data.as_mut())?; - - Ok(data) - } -} - -mod uuid_hyp_str { - use crate::{ - DecodeError, DecoderReadExt, EncodeError, EncoderWriteExt, HYPHENATED_UUID_LENGTH, - }; - use std::io::{Read, Write}; - use uuid::Uuid; - - pub fn encode<W: Write>(value: &Uuid, writer: &mut W) -> Result<(), EncodeError> { - let uuid_hyphenated_string = value.to_hyphenated().to_string(); - writer.write_string(&uuid_hyphenated_string, HYPHENATED_UUID_LENGTH)?; - - Ok(()) - } - - pub fn decode<R: Read>(reader: &mut R) -> Result<Uuid, DecodeError> { - let uuid_hyphenated_string = reader.read_string(HYPHENATED_UUID_LENGTH)?; - let uuid = Uuid::parse_str(&uuid_hyphenated_string)?; - - Ok(uuid) - } -} - -#[test] -fn test_read_variable_i32_2_bytes_value() { - let mut cursor = Cursor::new(vec![0b10101100, 0b00000010]); - let value = cursor.read_var_i32().unwrap(); - - assert_eq!(value, 300); -} - -#[test] -fn test_read_variable_i32_5_bytes_value() { - let mut cursor = Cursor::new(vec![0xff, 0xff, 0xff, 0xff, 0x07]); - let value = cursor.read_var_i32().unwrap(); - - assert_eq!(value, 2147483647); -} - -#[test] -fn test_write_variable_i32_2_bytes_value() { - let mut cursor = Cursor::new(Vec::with_capacity(5)); - cursor.write_var_i32(300).unwrap(); - - assert_eq!(cursor.into_inner(), vec![0b10101100, 0b00000010]); -} - -#[test] -fn test_write_variable_i32_5_bytes_value() { - let mut cursor = Cursor::new(Vec::with_capacity(5)); - cursor.write_var_i32(2147483647).unwrap(); - - assert_eq!(cursor.into_inner(), vec![0xff, 0xff, 0xff, 0xff, 0x07]); -} diff --git a/protocol/src/version/mod.rs b/protocol/src/version/mod.rs new file mode 100644 index 0000000..7cac6f3 --- /dev/null +++ b/protocol/src/version/mod.rs @@ -0,0 +1 @@ +pub mod v1_14_4; diff --git a/protocol/src/game.rs b/protocol/src/version/v1_14_4/game.rs similarity index 89% rename from protocol/src/game.rs rename to protocol/src/version/v1_14_4/game.rs index e5d32ca..952214a 100644 --- a/protocol/src/game.rs +++ b/protocol/src/version/v1_14_4/game.rs @@ -1,9 +1,9 @@ use num_derive::{FromPrimitive, ToPrimitive}; -use crate::chat::Message; +use crate::data::chat::Message; +use crate::decoder::Decoder; +use crate::error::DecodeError; use crate::impl_enum_encoder_decoder; -use crate::DecodeError; -use crate::Decoder; use minecraft_protocol_derive::Packet; use nbt::CompoundTag; use std::io::Read; @@ -252,10 +252,9 @@ impl GameDisconnect { #[cfg(test)] mod tests { use crate::chat::{Message, Payload}; - use crate::game::{ - ChunkData, ClientBoundChatMessage, ClientBoundKeepAlive, GameDisconnect, GameMode, - JoinGame, MessagePosition, ServerBoundChatMessage, ServerBoundKeepAlive, - }; + use crate::data::chat::Payload; + use crate::error::{DecodeError, EncodeError}; + use crate::version::v1_14_4::game::*; use crate::{DecodeError, Encoder, EncoderWriteExt, STRING_MAX_LENGTH}; use crate::{Decoder, EncodeError}; use nbt::CompoundTag; @@ -272,14 +271,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/server_bound_chat_message.dat").to_vec() + include_bytes!("../../../test/packet/game/server_bound_chat_message.dat").to_vec() ); } #[test] fn test_server_bound_chat_message_decode() { let mut cursor = Cursor::new( - include_bytes!("../test/packet/game/server_bound_chat_message.dat").to_vec(), + include_bytes!("../../../test/packet/game/server_bound_chat_message.dat").to_vec(), ); let chat_message = ServerBoundChatMessage::decode(&mut cursor).unwrap(); @@ -342,14 +341,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/client_bound_chat_message.dat").to_vec() + include_bytes!("../../../test/packet/game/client_bound_chat_message.dat").to_vec() ); } #[test] fn test_client_bound_chat_message_decode() { let mut cursor = Cursor::new( - include_bytes!("../test/packet/game/client_bound_chat_message.dat").to_vec(), + include_bytes!("../../../test/packet/game/client_bound_chat_message.dat").to_vec(), ); let chat_message = ClientBoundChatMessage::decode(&mut cursor).unwrap(); @@ -370,14 +369,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/server_bound_keep_alive.dat").to_vec() + include_bytes!("../../../test/packet/game/server_bound_keep_alive.dat").to_vec() ); } #[test] fn test_server_bound_keep_alive_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/game/server_bound_keep_alive.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/game/server_bound_keep_alive.dat").to_vec(), + ); let keep_alive = ServerBoundKeepAlive::decode(&mut cursor).unwrap(); assert_eq!(keep_alive.id, 31122019); @@ -392,14 +392,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/client_bound_keep_alive.dat").to_vec() + include_bytes!("../../../test/packet/game/client_bound_keep_alive.dat").to_vec() ); } #[test] fn test_client_bound_keep_alive_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/game/client_bound_keep_alive.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/game/client_bound_keep_alive.dat").to_vec(), + ); let keep_alive = ClientBoundKeepAlive::decode(&mut cursor).unwrap(); assert_eq!(keep_alive.id, 240714); @@ -422,13 +423,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/join_game.dat").to_vec() + include_bytes!("../../../test/packet/game/join_game.dat").to_vec() ); } #[test] fn test_join_game_decode() { - let mut cursor = Cursor::new(include_bytes!("../test/packet/game/join_game.dat").to_vec()); + let mut cursor = + Cursor::new(include_bytes!("../../../test/packet/game/join_game.dat").to_vec()); let join_game = JoinGame::decode(&mut cursor).unwrap(); assert_eq!(join_game.entity_id, 27); @@ -457,13 +459,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/chunk_data.dat").to_vec() + include_bytes!("../../../test/packet/game/chunk_data.dat").to_vec() ); } #[test] fn test_chunk_data_decode() { - let mut cursor = Cursor::new(include_bytes!("../test/packet/game/chunk_data.dat").to_vec()); + let mut cursor = + Cursor::new(include_bytes!("../../../test/packet/game/chunk_data.dat").to_vec()); let chunk_data = ChunkData::decode(&mut cursor).unwrap(); assert_eq!(chunk_data.x, -2); @@ -486,14 +489,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/game/game_disconnect.dat").to_vec() + include_bytes!("../../../test/packet/game/game_disconnect.dat").to_vec() ); } #[test] fn test_game_disconnect_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/game/game_disconnect.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/game/game_disconnect.dat").to_vec()); let game_disconnect = GameDisconnect::decode(&mut cursor).unwrap(); assert_eq!( diff --git a/protocol/src/login.rs b/protocol/src/version/v1_14_4/login.rs similarity index 86% rename from protocol/src/login.rs rename to protocol/src/version/v1_14_4/login.rs index d18331e..1674473 100644 --- a/protocol/src/login.rs +++ b/protocol/src/version/v1_14_4/login.rs @@ -1,9 +1,9 @@ -use crate::chat::Message; -use crate::DecodeError; -use crate::Decoder; use std::io::Read; use uuid::Uuid; +use crate::data::chat::Message; +use crate::decoder::Decoder; +use crate::error::DecodeError; use minecraft_protocol_derive::Packet; pub enum LoginServerBoundPacket { @@ -244,9 +244,8 @@ impl LoginPluginRequest { #[cfg(test)] mod tests { use crate::chat::{Message, Payload}; - use crate::login::{EncryptionRequest, LoginDisconnect, LoginPluginRequest, SetCompression}; - use crate::login::{EncryptionResponse, LoginPluginResponse}; - use crate::login::{LoginStart, LoginSuccess}; + use crate::data::chat::Payload; + use crate::version::v1_14_4::login::*; use crate::Decoder; use crate::Encoder; use std::io::Cursor; @@ -263,14 +262,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/login_start.dat").to_vec() + include_bytes!("../../../test/packet/login/login_start.dat").to_vec() ); } #[test] fn test_login_start_packet_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/login_start.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/login/login_start.dat").to_vec()); let login_start = LoginStart::decode(&mut cursor).unwrap(); assert_eq!(login_start.name, String::from("Username")); @@ -288,14 +287,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/encryption_response.dat").to_vec() + include_bytes!("../../../test/packet/login/encryption_response.dat").to_vec() ); } #[test] fn test_encryption_response_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/encryption_response.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/login/encryption_response.dat").to_vec(), + ); let encryption_response = EncryptionResponse::decode(&mut cursor).unwrap(); assert_eq!( @@ -318,14 +318,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/login_plugin_response.dat").to_vec() + include_bytes!("../../../test/packet/login/login_plugin_response.dat").to_vec() ); } #[test] fn test_login_plugin_response_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/login_plugin_response.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/login/login_plugin_response.dat").to_vec(), + ); let login_plugin_response = LoginPluginResponse::decode(&mut cursor).unwrap(); assert_eq!(login_plugin_response.message_id, 55); @@ -347,14 +348,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/login_disconnect.dat").to_vec() + include_bytes!("../../../test/packet/login/login_disconnect.dat").to_vec() ); } #[test] fn test_login_disconnect_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/login_disconnect.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/login/login_disconnect.dat").to_vec()); let login_disconnect = LoginDisconnect::decode(&mut cursor).unwrap(); assert_eq!( @@ -376,14 +377,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/encryption_request.dat").to_vec() + include_bytes!("../../../test/packet/login/encryption_request.dat").to_vec() ); } #[test] fn test_encryption_request_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/encryption_request.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/login/encryption_request.dat").to_vec(), + ); let encryption_request = EncryptionRequest::decode(&mut cursor).unwrap(); assert_eq!(encryption_request.server_id, String::from("ServerID")); @@ -406,14 +408,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/login_success.dat").to_vec() + include_bytes!("../../../test/packet/login/login_success.dat").to_vec() ); } #[test] fn test_login_success_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/login_success.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/login/login_success.dat").to_vec()); let login_success = LoginSuccess::decode(&mut cursor).unwrap(); assert_eq!(login_success.username, String::from("Username")); @@ -433,14 +435,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/login_set_compression.dat").to_vec() + include_bytes!("../../../test/packet/login/login_set_compression.dat").to_vec() ); } #[test] fn test_set_compression_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/login_set_compression.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/login/login_set_compression.dat").to_vec(), + ); let set_compression = SetCompression::decode(&mut cursor).unwrap(); assert_eq!(set_compression.threshold, 1); @@ -459,14 +462,15 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/login/login_plugin_request.dat").to_vec() + include_bytes!("../../../test/packet/login/login_plugin_request.dat").to_vec() ); } #[test] fn test_login_plugin_request_decode() { - let mut cursor = - Cursor::new(include_bytes!("../test/packet/login/login_plugin_request.dat").to_vec()); + let mut cursor = Cursor::new( + include_bytes!("../../../test/packet/login/login_plugin_request.dat").to_vec(), + ); let login_plugin_request = LoginPluginRequest::decode(&mut cursor).unwrap(); assert_eq!(login_plugin_request.message_id, 55); diff --git a/protocol/src/version/v1_14_4/mod.rs b/protocol/src/version/v1_14_4/mod.rs new file mode 100644 index 0000000..986f00e --- /dev/null +++ b/protocol/src/version/v1_14_4/mod.rs @@ -0,0 +1,3 @@ +pub mod game; +pub mod login; +pub mod status; diff --git a/protocol/src/status.rs b/protocol/src/version/v1_14_4/status.rs similarity index 77% rename from protocol/src/status.rs rename to protocol/src/version/v1_14_4/status.rs index 1d8f195..f71ef98 100644 --- a/protocol/src/status.rs +++ b/protocol/src/version/v1_14_4/status.rs @@ -1,10 +1,6 @@ -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -use crate::chat::Message; -use crate::impl_json_encoder_decoder; -use crate::DecodeError; -use crate::Decoder; +use crate::data::server_status::*; +use crate::decoder::Decoder; +use crate::error::DecodeError; use minecraft_protocol_derive::Packet; use std::io::Read; @@ -74,39 +70,11 @@ impl PingResponse { } } -#[derive(Serialize, Deserialize, Debug)] -pub struct ServerStatus { - pub version: ServerVersion, - pub players: OnlinePlayers, - pub description: Message, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ServerVersion { - pub name: String, - pub protocol: u32, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct OnlinePlayers { - pub max: u32, - pub online: u32, - pub sample: Vec<OnlinePlayer>, -} - -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -pub struct OnlinePlayer { - pub name: String, - pub id: Uuid, -} - #[derive(Packet, Debug)] pub struct StatusResponse { pub server_status: ServerStatus, } -impl_json_encoder_decoder!(ServerStatus); - impl StatusResponse { pub fn new(server_status: ServerStatus) -> StatusClientBoundPacket { let status_response = StatusResponse { server_status }; @@ -118,10 +86,8 @@ impl StatusResponse { #[cfg(test)] mod tests { use crate::chat::{Message, Payload}; - use crate::status::{ - OnlinePlayer, OnlinePlayers, PingRequest, PingResponse, ServerStatus, ServerVersion, - StatusResponse, - }; + use crate::data::chat::{Message, Payload}; + use crate::version::v1_14_4::status::*; use crate::Decoder; use crate::Encoder; use std::io::Cursor; @@ -138,14 +104,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/status/ping_request.dat").to_vec() + include_bytes!("../../../test/packet/status/ping_request.dat").to_vec() ); } #[test] fn test_status_ping_request_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/status/ping_request.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/status/ping_request.dat").to_vec()); let ping_request = PingRequest::decode(&mut cursor).unwrap(); assert_eq!(ping_request.time, 1577735845610); @@ -162,14 +128,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/status/ping_response.dat").to_vec() + include_bytes!("../../../test/packet/status/ping_response.dat").to_vec() ); } #[test] fn test_status_ping_response_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/status/ping_response.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/status/ping_response.dat").to_vec()); let ping_response = PingResponse::decode(&mut cursor).unwrap(); assert_eq!(ping_response.time, 1577735845610); @@ -206,14 +172,14 @@ mod tests { assert_eq!( vec, - include_bytes!("../test/packet/status/status_response.dat").to_vec() + include_bytes!("../../../test/packet/status/status_response.dat").to_vec() ); } #[test] fn test_status_response_decode() { let mut cursor = - Cursor::new(include_bytes!("../test/packet/status/status_response.dat").to_vec()); + Cursor::new(include_bytes!("../../../test/packet/status/status_response.dat").to_vec()); let status_response = StatusResponse::decode(&mut cursor).unwrap(); let server_status = status_response.server_status;