diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index 4e380b0..f6fe243 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -11,12 +11,11 @@ keywords = ["minecraft", "protocol", "packet", "io"] readme = "README.md" [dependencies] -minecraft-protocol-derive = { path = "../protocol-derive" } +minecraft-protocol-derive = { version = "0.0.0", path = "../protocol-derive" } byteorder = "1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "0.7", features = ["v4", "serde"] } -mc-varint = { git = "https://github.com/luojia65/mc-varint" } num-traits = "0.2" num-derive = "0.2" named-binary-tag = "0.2" diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index 5024b31..fa0aa78 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -3,11 +3,10 @@ //! 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::io::{Cursor, Read, Write}; use std::string::FromUtf8Error; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use mc_varint::{VarIntRead, VarIntWrite}; use serde_json::error::Error as JsonError; use uuid::parser::ParseError as UuidParseError; @@ -94,6 +93,9 @@ pub enum DecodeError { TagDecodeError { tag_decode_error: TagDecodeError, }, + VarIntTooLong { + max_bytes: usize, + }, } impl From<IoError> for DecodeError { @@ -136,6 +138,56 @@ trait Decoder { 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>; @@ -149,6 +201,10 @@ trait EncoderWriteExt { 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. @@ -164,6 +220,10 @@ trait DecoderReadExt { 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 { @@ -213,6 +273,9 @@ impl<W: Write> EncoderWriteExt for W { Ok(()) } + + write_signed_var_int!(i32, write_var_i32); + write_signed_var_int!(i64, write_var_i64); } impl<R: Read> DecoderReadExt for R { @@ -263,6 +326,9 @@ impl<R: Read> DecoderReadExt for R { 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 { @@ -481,7 +547,7 @@ macro_rules! impl_json_encoder_decoder ( mod var_int { use crate::{DecodeError, EncodeError}; - use mc_varint::{VarIntRead, VarIntWrite}; + use crate::{DecoderReadExt, EncoderWriteExt}; use std::io::{Read, Write}; pub fn encode<W: Write>(value: &i32, writer: &mut W) -> Result<(), EncodeError> { @@ -497,7 +563,7 @@ mod var_int { mod var_long { use crate::{DecodeError, EncodeError}; - use mc_varint::{VarIntRead, VarIntWrite}; + use crate::{DecoderReadExt, EncoderWriteExt}; use std::io::{Read, Write}; pub fn encode<W: Write>(value: &i64, writer: &mut W) -> Result<(), EncodeError> { @@ -550,3 +616,35 @@ mod uuid_hyp_str { 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]); +}