From 5c4721a2bc300952a27ab31682044ecf14711ef3 Mon Sep 17 00:00:00 2001 From: vagola Date: Sat, 28 Dec 2019 02:28:02 +0300 Subject: [PATCH] Add chunk data packet --- Cargo.toml | 1 + src/game.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 25 +++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 23f5766..c327452 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,4 @@ 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/src/game.rs b/src/game.rs index af9ee3a..e14a6ae 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,6 +6,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use crate::chat::Message; use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite}; use mc_varint::{VarIntRead, VarIntWrite}; +use nbt::CompoundTag; const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256; const LEVEL_TYPE_MAX_LENGTH: u32 = 16; @@ -19,6 +20,7 @@ pub enum GameClientBoundPacket { ClientBoundChatMessage(ClientBoundChatMessage), JoinGame(JoinGame), ClientBoundKeepAlive(ClientBoundKeepAlive), + ChunkData(ChunkData), } impl GameServerBoundPacket { @@ -51,6 +53,7 @@ impl GameClientBoundPacket { match self { GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E, GameClientBoundPacket::ClientBoundKeepAlive(_) => 0x20, + GameClientBoundPacket::ChunkData(_) => 0x21, GameClientBoundPacket::JoinGame(_) => 0x25, } } @@ -67,6 +70,11 @@ impl GameClientBoundPacket { Ok(GameClientBoundPacket::ClientBoundKeepAlive(keep_alive)) } + 0x21 => { + let chunk_data = ChunkData::decode(reader)?; + + Ok(GameClientBoundPacket::ChunkData(chunk_data)) + } 0x25 => { let join_game = JoinGame::decode(reader)?; @@ -278,3 +286,84 @@ impl Packet for ClientBoundKeepAlive { 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, + pub tiles: Vec, +} + +impl ChunkData { + pub fn new( + x: i32, + z: i32, + full: bool, + primary_mask: u32, + heights: CompoundTag, + data: Vec, + tiles: Vec, + ) -> 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(&self, writer: &mut W) -> Result<(), EncodeError> { + writer.write_i32::(self.x)?; + writer.write_i32::(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(reader: &mut R) -> Result { + let x = reader.read_i32::()?; + let z = reader.read_i32::()?; + 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, + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index e416457..a8bb427 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,8 @@ 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}; pub mod chat; @@ -86,6 +88,9 @@ pub enum DecodeError { UnknownEnumType { type_id: u8, }, + TagDecodeError { + tag_decode_error: TagDecodeError, + }, } impl From for DecodeError { @@ -112,6 +117,12 @@ impl From for DecodeError { } } +impl From for DecodeError { + fn from(tag_decode_error: TagDecodeError) -> Self { + DecodeError::TagDecodeError { tag_decode_error } + } +} + trait Packet { type Output; @@ -131,6 +142,8 @@ trait PacketRead { fn read_chat_message(&mut self) -> Result; fn read_enum(&mut self) -> Result; + + fn read_compound_tag(&mut self) -> Result; } /// 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_enum(&mut self, value: &T) -> Result<(), EncodeError>; + + fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError>; } impl PacketRead for R { @@ -190,6 +205,10 @@ impl PacketRead for R { result.ok_or_else(|| DecodeError::UnknownEnumType { type_id }) } + + fn read_compound_tag(&mut self) -> Result { + Ok(nbt::decode::read_compound_tag(self)?) + } } impl PacketWrite for W { @@ -233,4 +252,10 @@ impl PacketWrite for W { Ok(()) } + + fn write_compound_tag(&mut self, value: &CompoundTag) -> Result<(), EncodeError> { + nbt::encode::write_compound_tag(self, value.clone())?; + + Ok(()) + } }