Add join game packet

This commit is contained in:
vagola 2019-12-27 01:08:17 +03:00
parent 61d3c950b3
commit 0838c3688d
2 changed files with 111 additions and 10 deletions

View File

@ -1,13 +1,14 @@
use std::io::{Read, Write}; use std::io::{Read, Write};
use byteorder::{ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{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};
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;
pub enum GameServerBoundPacket { pub enum GameServerBoundPacket {
ServerBoundChatMessage(ServerBoundChatMessage), ServerBoundChatMessage(ServerBoundChatMessage),
@ -15,6 +16,7 @@ pub enum GameServerBoundPacket {
pub enum GameClientBoundPacket { pub enum GameClientBoundPacket {
ClientBoundChatMessage(ClientBoundChatMessage), ClientBoundChatMessage(ClientBoundChatMessage),
JoinGame(JoinGame),
} }
impl GameServerBoundPacket { impl GameServerBoundPacket {
@ -40,6 +42,7 @@ impl GameClientBoundPacket {
pub fn get_type_id(&self) -> u8 { pub fn get_type_id(&self) -> u8 {
match self { match self {
GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E, GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E,
GameClientBoundPacket::JoinGame(_) => 0x25,
} }
} }
@ -50,6 +53,11 @@ impl GameClientBoundPacket {
Ok(GameClientBoundPacket::ClientBoundChatMessage(chat_message)) Ok(GameClientBoundPacket::ClientBoundChatMessage(chat_message))
} }
0x25 => {
let join_game = JoinGame::decode(reader)?;
Ok(GameClientBoundPacket::JoinGame(join_game))
}
_ => Err(DecodeError::UnknownPacketType { type_id }), _ => Err(DecodeError::UnknownPacketType { type_id }),
} }
} }
@ -106,23 +114,97 @@ impl Packet for ClientBoundChatMessage {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_chat_message(&self.message)?; writer.write_chat_message(&self.message)?;
writer.write_u8(ToPrimitive::to_u8(&self.position).unwrap())?; writer.write_enum(&self.position)?;
Ok(()) Ok(())
} }
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> { fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let message = reader.read_chat_message()?; let message = reader.read_chat_message()?;
let position_type_id = reader.read_u8()?; let position = reader.read_enum()?;
let position = FromPrimitive::from_u8(position_type_id).ok_or_else(|| {
DecodeError::UnknownEnumType {
type_id: position_type_id,
}
})?;
let chat_message = ClientBoundChatMessage { message, position }; let chat_message = ClientBoundChatMessage { message, position };
Ok(chat_message) 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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u32::<BigEndian>(self.entity_id)?;
writer.write_enum(&self.game_mode)?;
writer.write_i32::<BigEndian>(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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let entity_id = reader.read_u32::<BigEndian>()?;
let game_mode = reader.read_enum()?;
let dimension = reader.read_i32::<BigEndian>()?;
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,
})
}
}

View File

@ -13,6 +13,7 @@ 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 num_traits::{FromPrimitive, ToPrimitive};
pub mod chat; pub mod chat;
pub mod game; pub mod game;
@ -128,6 +129,8 @@ trait PacketRead {
fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>; fn read_byte_array(&mut self) -> Result<Vec<u8>, DecodeError>;
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>;
} }
/// Trait adds additional helper methods for `Write` to write protocol data. /// 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_byte_array(&mut self, value: &[u8]) -> Result<(), EncodeError>;
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>;
} }
impl<R: Read> PacketRead for R { impl<R: Read> PacketRead for R {
@ -178,6 +183,13 @@ impl<R: Read> PacketRead for R {
Ok(message) Ok(message)
} }
fn read_enum<T: FromPrimitive>(&mut self) -> Result<T, DecodeError> {
let type_id = self.read_u8()?;
let result = FromPrimitive::from_u8(type_id);
result.ok_or_else(|| DecodeError::UnknownEnumType { type_id })
}
} }
impl<W: Write> PacketWrite for W { impl<W: Write> PacketWrite for W {
@ -214,4 +226,11 @@ impl<W: Write> PacketWrite for W {
fn write_chat_message(&mut self, value: &Message) -> Result<(), EncodeError> { fn write_chat_message(&mut self, value: &Message) -> Result<(), EncodeError> {
self.write_string(&value.to_json()?, STRING_MAX_LENGTH) self.write_string(&value.to_json()?, STRING_MAX_LENGTH)
} }
fn write_enum<T: ToPrimitive>(&mut self, value: &T) -> Result<(), EncodeError> {
let type_value = ToPrimitive::to_u8(value).unwrap();
self.write_u8(type_value)?;
Ok(())
}
} }