From 0838c3688df147ceb057d29a2c0c724c073c790a Mon Sep 17 00:00:00 2001 From: vagola Date: Fri, 27 Dec 2019 01:08:17 +0300 Subject: [PATCH] Add join game packet --- src/game.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++++------ src/lib.rs | 19 ++++++++++ 2 files changed, 111 insertions(+), 10 deletions(-) diff --git a/src/game.rs b/src/game.rs index dbabd00..b73ed28 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,13 +1,14 @@ use std::io::{Read, Write}; -use byteorder::{ReadBytesExt, WriteBytesExt}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::{FromPrimitive, ToPrimitive}; use crate::chat::Message; use crate::{DecodeError, EncodeError, Packet, PacketRead, PacketWrite}; +use mc_varint::{VarIntRead, VarIntWrite}; const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256; +const LEVEL_TYPE_MAX_LENGTH: u32 = 16; pub enum GameServerBoundPacket { ServerBoundChatMessage(ServerBoundChatMessage), @@ -15,6 +16,7 @@ pub enum GameServerBoundPacket { pub enum GameClientBoundPacket { ClientBoundChatMessage(ClientBoundChatMessage), + JoinGame(JoinGame), } impl GameServerBoundPacket { @@ -40,6 +42,7 @@ impl GameClientBoundPacket { pub fn get_type_id(&self) -> u8 { match self { GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E, + GameClientBoundPacket::JoinGame(_) => 0x25, } } @@ -50,6 +53,11 @@ impl GameClientBoundPacket { Ok(GameClientBoundPacket::ClientBoundChatMessage(chat_message)) } + 0x25 => { + let join_game = JoinGame::decode(reader)?; + + Ok(GameClientBoundPacket::JoinGame(join_game)) + } _ => Err(DecodeError::UnknownPacketType { type_id }), } } @@ -106,23 +114,97 @@ impl Packet for ClientBoundChatMessage { fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { writer.write_chat_message(&self.message)?; - writer.write_u8(ToPrimitive::to_u8(&self.position).unwrap())?; + writer.write_enum(&self.position)?; Ok(()) } fn decode(reader: &mut R) -> Result { let message = reader.read_chat_message()?; - let position_type_id = reader.read_u8()?; - - let position = FromPrimitive::from_u8(position_type_id).ok_or_else(|| { - DecodeError::UnknownEnumType { - type_id: position_type_id, - } - })?; + let position = reader.read_enum()?; let chat_message = ClientBoundChatMessage { message, position }; Ok(chat_message) } } + +#[derive(Debug)] +pub struct JoinGame { + pub entity_id: u32, + pub game_mode: GameMode, + pub dimension: i32, + pub max_players: u8, + pub level_type: String, + pub view_distance: u8, + pub reduced_debug_info: bool, +} + +#[derive(Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)] +pub enum GameMode { + Survival = 0, + Creative = 1, + Adventure = 2, + Spectator = 3, + Hardcore = 8, +} + +impl JoinGame { + pub fn new( + entity_id: u32, + game_mode: GameMode, + dimension: i32, + max_players: u8, + level_type: String, + view_distance: u8, + reduced_debug_info: bool, + ) -> GameClientBoundPacket { + let join_game = JoinGame { + entity_id, + game_mode, + dimension, + max_players, + level_type, + view_distance, + reduced_debug_info, + }; + + GameClientBoundPacket::JoinGame(join_game) + } +} + +impl Packet for JoinGame { + type Output = Self; + + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + writer.write_u32::(self.entity_id)?; + writer.write_enum(&self.game_mode)?; + writer.write_i32::(self.dimension)?; + writer.write_u8(self.max_players)?; + writer.write_string(&self.level_type, LEVEL_TYPE_MAX_LENGTH)?; + writer.write_var_u32(self.view_distance as u32)?; + writer.write_bool(self.reduced_debug_info)?; + + Ok(()) + } + + fn decode(reader: &mut R) -> Result { + let entity_id = reader.read_u32::()?; + let game_mode = reader.read_enum()?; + let dimension = reader.read_i32::()?; + let max_players = reader.read_u8()?; + let level_type = reader.read_string(LEVEL_TYPE_MAX_LENGTH)?; + let view_distance = reader.read_var_u32()? as u8; + let reduced_debug_info = reader.read_bool()?; + + Ok(JoinGame { + entity_id, + game_mode, + dimension, + max_players, + level_type, + view_distance, + reduced_debug_info, + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 4cdf8af..e416457 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ 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; @@ -128,6 +129,8 @@ trait PacketRead { 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. @@ -139,6 +142,8 @@ trait PacketWrite { 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 { @@ -178,6 +183,13 @@ impl PacketRead for R { 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 { @@ -214,4 +226,11 @@ impl PacketWrite for W { 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(()) + } }