Add own varint/varlong support
This commit is contained in:
parent
3e86e216c9
commit
e6a4cc6679
@ -11,12 +11,11 @@ keywords = ["minecraft", "protocol", "packet", "io"]
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
minecraft-protocol-derive = { path = "../protocol-derive" }
|
minecraft-protocol-derive = { version = "0.0.0", path = "../protocol-derive" }
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
uuid = { version = "0.7", features = ["v4", "serde"] }
|
uuid = { version = "0.7", features = ["v4", "serde"] }
|
||||||
mc-varint = { git = "https://github.com/luojia65/mc-varint" }
|
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-derive = "0.2"
|
num-derive = "0.2"
|
||||||
named-binary-tag = "0.2"
|
named-binary-tag = "0.2"
|
||||||
|
@ -3,11 +3,10 @@
|
|||||||
//! Information about protocol can be found at https://wiki.vg/Protocol.
|
//! Information about protocol can be found at https://wiki.vg/Protocol.
|
||||||
use io::Error as IoError;
|
use io::Error as IoError;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Cursor, Read, Write};
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
|
||||||
use serde_json::error::Error as JsonError;
|
use serde_json::error::Error as JsonError;
|
||||||
use uuid::parser::ParseError as UuidParseError;
|
use uuid::parser::ParseError as UuidParseError;
|
||||||
|
|
||||||
@ -94,6 +93,9 @@ pub enum DecodeError {
|
|||||||
TagDecodeError {
|
TagDecodeError {
|
||||||
tag_decode_error: TagDecodeError,
|
tag_decode_error: TagDecodeError,
|
||||||
},
|
},
|
||||||
|
VarIntTooLong {
|
||||||
|
max_bytes: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IoError> for DecodeError {
|
impl From<IoError> for DecodeError {
|
||||||
@ -136,6 +138,56 @@ trait Decoder {
|
|||||||
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>;
|
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 adds additional helper methods for `Write` to write protocol data.
|
||||||
trait EncoderWriteExt {
|
trait EncoderWriteExt {
|
||||||
fn write_bool(&mut self, value: bool) -> Result<(), EncodeError>;
|
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_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError>;
|
||||||
|
|
||||||
fn write_compound_tag(&mut self, value: &CompoundTag) -> 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 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_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError>;
|
||||||
|
|
||||||
fn read_compound_tag(&mut self) -> Result<CompoundTag, 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 {
|
impl<W: Write> EncoderWriteExt for W {
|
||||||
@ -213,6 +273,9 @@ impl<W: Write> EncoderWriteExt for W {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_signed_var_int!(i32, write_var_i32);
|
||||||
|
write_signed_var_int!(i64, write_var_i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> DecoderReadExt for R {
|
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> {
|
fn read_compound_tag(&mut self) -> Result<CompoundTag, DecodeError> {
|
||||||
Ok(nbt::decode::read_compound_tag(self)?)
|
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 {
|
impl Encoder for u8 {
|
||||||
@ -481,7 +547,7 @@ macro_rules! impl_json_encoder_decoder (
|
|||||||
|
|
||||||
mod var_int {
|
mod var_int {
|
||||||
use crate::{DecodeError, EncodeError};
|
use crate::{DecodeError, EncodeError};
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
use crate::{DecoderReadExt, EncoderWriteExt};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
pub fn encode<W: Write>(value: &i32, writer: &mut W) -> Result<(), EncodeError> {
|
pub fn encode<W: Write>(value: &i32, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
@ -497,7 +563,7 @@ mod var_int {
|
|||||||
|
|
||||||
mod var_long {
|
mod var_long {
|
||||||
use crate::{DecodeError, EncodeError};
|
use crate::{DecodeError, EncodeError};
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
use crate::{DecoderReadExt, EncoderWriteExt};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
pub fn encode<W: Write>(value: &i64, writer: &mut W) -> Result<(), EncodeError> {
|
pub fn encode<W: Write>(value: &i64, writer: &mut W) -> Result<(), EncodeError> {
|
||||||
@ -550,3 +616,35 @@ mod uuid_hyp_str {
|
|||||||
Ok(uuid)
|
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]);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user