//! 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::{Read, Write}; use std::string::FromUtf8Error; use byteorder::ReadBytesExt; use byteorder::WriteBytesExt; use mc_varint::{VarIntRead, VarIntWrite}; use serde_json::error::Error as JsonError; use uuid::parser::ParseError as UuidParseError; use crate::chat::Message; use num_traits::{FromPrimitive, ToPrimitive}; pub mod chat; pub mod game; pub mod login; pub mod status; /// Current supported protocol version. pub const PROTOCOL_VERSION: usize = 498; /// String maximum length. const STRING_MAX_LENGTH: u32 = 32_768; /// Possible errors while encoding packet. pub enum EncodeError { /// String length can't be more than provided value. StringTooLong { /// String length. length: usize, /// Max string length. max_length: u32, }, IOError { io_error: IoError, }, JsonError { json_error: JsonError, }, } impl From for EncodeError { fn from(io_error: IoError) -> Self { EncodeError::IOError { io_error } } } impl From for EncodeError { fn from(json_error: JsonError) -> Self { EncodeError::JsonError { json_error } } } /// Possible errors while decoding packet. 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: u32, /// Max string length. max_length: u32, }, 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, }, } impl From for DecodeError { fn from(io_error: IoError) -> Self { DecodeError::IOError { io_error } } } impl From for DecodeError { fn from(json_error: JsonError) -> Self { DecodeError::JsonError { json_error } } } impl From for DecodeError { fn from(utf8_error: FromUtf8Error) -> Self { DecodeError::Utf8Error { utf8_error } } } impl From for DecodeError { fn from(uuid_parse_error: UuidParseError) -> Self { DecodeError::UuidParseError { uuid_parse_error } } } trait Packet { type Output; fn encode(&self, writer: &mut W) -> Result<(), EncodeError>; fn decode(reader: &mut R) -> Result; } /// Trait adds additional helper methods for `Read` to read protocol data. trait PacketRead { fn read_bool(&mut self) -> Result; fn read_string(&mut self, max_length: u32) -> Result; fn read_byte_array(&mut self) -> Result, DecodeError>; fn read_chat_message(&mut self) -> Result; fn read_enum(&mut self) -> Result; } /// Trait adds additional helper methods for `Write` to write protocol data. trait PacketWrite { fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>; fn write_string(&mut self, value: &str, max_length: u32) -> 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(&mut self, value: &T) -> Result<(), EncodeError>; } impl PacketRead for R { fn read_bool(&mut self) -> Result { match self.read_u8()? { 0 => Ok(false), 1 => Ok(true), _ => Err(DecodeError::NonBoolValue), } } fn read_string(&mut self, max_length: u32) -> Result { let length = self.read_var_u32()?; if length > max_length as u32 { 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, DecodeError> { let length = self.read_var_u32()?; let mut buf = vec![0; length as usize]; self.read_exact(&mut buf)?; Ok(buf) } fn read_chat_message(&mut self) -> Result { let json = self.read_string(STRING_MAX_LENGTH)?; let message = Message::from_json(&json)?; Ok(message) } fn read_enum(&mut self) -> Result { let type_id = self.read_u8()?; let result = FromPrimitive::from_u8(type_id); result.ok_or_else(|| DecodeError::UnknownEnumType { type_id }) } } impl PacketWrite 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: u32) -> Result<(), EncodeError> { let length = value.len(); if length > max_length as usize { return Err(EncodeError::StringTooLong { length, max_length }); } self.write_var_u32(value.len() as u32)?; self.write_all(value.as_bytes())?; Ok(()) } fn write_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError> { self.write_var_u32(value.len() as u32)?; 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(&mut self, value: &T) -> Result<(), EncodeError> { let type_value = ToPrimitive::to_u8(value).unwrap(); self.write_u8(type_value)?; Ok(()) } }