Add chunk data packet

This commit is contained in:
vagola 2019-12-28 02:28:02 +03:00
parent 8675361bef
commit 5c4721a2bc
3 changed files with 115 additions and 0 deletions

View File

@ -18,3 +18,4 @@ uuid = { version = "0.7", features = ["v4", "serde"] }
mc-varint = { git = "https://github.com/luojia65/mc-varint" } 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"

View File

@ -6,6 +6,7 @@ use num_derive::{FromPrimitive, ToPrimitive};
use crate::chat::Message; use crate::chat::Message;
use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite}; use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite};
use mc_varint::{VarIntRead, VarIntWrite}; use mc_varint::{VarIntRead, VarIntWrite};
use nbt::CompoundTag;
const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256; const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256;
const LEVEL_TYPE_MAX_LENGTH: u32 = 16; const LEVEL_TYPE_MAX_LENGTH: u32 = 16;
@ -19,6 +20,7 @@ pub enum GameClientBoundPacket {
ClientBoundChatMessage(ClientBoundChatMessage), ClientBoundChatMessage(ClientBoundChatMessage),
JoinGame(JoinGame), JoinGame(JoinGame),
ClientBoundKeepAlive(ClientBoundKeepAlive), ClientBoundKeepAlive(ClientBoundKeepAlive),
ChunkData(ChunkData),
} }
impl GameServerBoundPacket { impl GameServerBoundPacket {
@ -51,6 +53,7 @@ impl GameClientBoundPacket {
match self { match self {
GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E, GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E,
GameClientBoundPacket::ClientBoundKeepAlive(_) => 0x20, GameClientBoundPacket::ClientBoundKeepAlive(_) => 0x20,
GameClientBoundPacket::ChunkData(_) => 0x21,
GameClientBoundPacket::JoinGame(_) => 0x25, GameClientBoundPacket::JoinGame(_) => 0x25,
} }
} }
@ -67,6 +70,11 @@ impl GameClientBoundPacket {
Ok(GameClientBoundPacket::ClientBoundKeepAlive(keep_alive)) Ok(GameClientBoundPacket::ClientBoundKeepAlive(keep_alive))
} }
0x21 => {
let chunk_data = ChunkData::decode(reader)?;
Ok(GameClientBoundPacket::ChunkData(chunk_data))
}
0x25 => { 0x25 => {
let join_game = JoinGame::decode(reader)?; let join_game = JoinGame::decode(reader)?;
@ -278,3 +286,84 @@ impl Packet for ClientBoundKeepAlive {
Ok(ClientBoundKeepAlive { id }) Ok(ClientBoundKeepAlive { id })
} }
} }
pub struct ChunkData {
pub x: i32,
pub z: i32,
pub full: bool,
pub primary_mask: u32,
pub heights: CompoundTag,
pub data: Vec<u8>,
pub tiles: Vec<CompoundTag>,
}
impl ChunkData {
pub fn new(
x: i32,
z: i32,
full: bool,
primary_mask: u32,
heights: CompoundTag,
data: Vec<u8>,
tiles: Vec<CompoundTag>,
) -> GameClientBoundPacket {
let chunk_data = ChunkData {
x,
z,
full,
primary_mask,
heights,
data,
tiles,
};
GameClientBoundPacket::ChunkData(chunk_data)
}
}
impl Packet for ChunkData {
type Output = Self;
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_i32::<BigEndian>(self.x)?;
writer.write_i32::<BigEndian>(self.z)?;
writer.write_bool(self.full)?;
writer.write_var_u32(self.primary_mask)?;
writer.write_compound_tag(&self.heights)?;
writer.write_byte_array(&self.data)?;
writer.write_var_u32(self.tiles.len() as u32)?;
for tile_compound_tag in self.tiles.iter() {
writer.write_compound_tag(&tile_compound_tag)?;
}
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let x = reader.read_i32::<BigEndian>()?;
let z = reader.read_i32::<BigEndian>()?;
let full = reader.read_bool()?;
let primary_mask = reader.read_var_u32()?;
let heights = reader.read_compound_tag()?;
let data = reader.read_byte_array()?;
let tiles_length = reader.read_var_u32()?;
let mut tiles = Vec::new();
for _ in 0..tiles_length {
let tile_compound_tag = reader.read_compound_tag()?;
tiles.push(tile_compound_tag);
}
Ok(ChunkData {
x,
z,
full,
primary_mask,
heights,
data,
tiles,
})
}
}

View File

@ -13,6 +13,8 @@ use serde_json::error::Error as JsonError;
use uuid::parser::ParseError as UuidParseError; use uuid::parser::ParseError as UuidParseError;
use crate::chat::Message; use crate::chat::Message;
use nbt::decode::TagDecodeError;
use nbt::CompoundTag;
use num_traits::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive};
pub mod chat; pub mod chat;
@ -86,6 +88,9 @@ pub enum DecodeError {
UnknownEnumType { UnknownEnumType {
type_id: u8, type_id: u8,
}, },
TagDecodeError {
tag_decode_error: TagDecodeError,
},
} }
impl From<IoError> for DecodeError { impl From<IoError> for DecodeError {
@ -112,6 +117,12 @@ impl From<UuidParseError> for DecodeError {
} }
} }
impl From<TagDecodeError> for DecodeError {
fn from(tag_decode_error: TagDecodeError) -> Self {
DecodeError::TagDecodeError { tag_decode_error }
}
}
trait Packet { trait Packet {
type Output; type Output;
@ -131,6 +142,8 @@ trait PacketRead {
fn read_chat_message(&mut self) -> Result<Message, DecodeError>; fn read_chat_message(&mut self) -> Result<Message, DecodeError>;
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>;
} }
/// Trait adds additional helper methods for `Write` to write protocol data. /// Trait adds additional helper methods for `Write` to write protocol data.
@ -144,6 +157,8 @@ trait PacketWrite {
fn write_chat_message(&mut self, value: &Message) -> 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_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError>;
fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError>;
} }
impl<R: Read> PacketRead for R { impl<R: Read> PacketRead for R {
@ -190,6 +205,10 @@ impl<R: Read> PacketRead for R {
result.ok_or_else(|| DecodeError::UnknownEnumType { 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)?)
}
} }
impl<W: Write> PacketWrite for W { impl<W: Write> PacketWrite for W {
@ -233,4 +252,10 @@ impl<W: Write> PacketWrite for W {
Ok(()) Ok(())
} }
fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError> {
nbt::encode::write_compound_tag(self, value.clone())?;
Ok(())
}
} }