From 39751ce6043236394fb4b8762ffaf5975127f51d Mon Sep 17 00:00:00 2001 From: timvisee <tim@visee.me> Date: Fri, 12 Nov 2021 19:41:27 +0100 Subject: [PATCH] Add and update some v1.17.1 packets [WIP] --- protocol/src/encoder.rs | 40 ++++- protocol/src/version/mod.rs | 1 + protocol/src/version/v1_17_1/game.rs | 210 +++++++++++++++++++++++++++ protocol/src/version/v1_17_1/mod.rs | 1 + 4 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 protocol/src/version/v1_17_1/game.rs create mode 100644 protocol/src/version/v1_17_1/mod.rs diff --git a/protocol/src/encoder.rs b/protocol/src/encoder.rs index 8b80ee4..906f9c8 100644 --- a/protocol/src/encoder.rs +++ b/protocol/src/encoder.rs @@ -183,6 +183,32 @@ impl Encoder for Vec<CompoundTag> { } } +// TODO: identifier encoder, we might want a custom type +impl Encoder for Vec<String> { + fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { + writer.write_var_i32(self.len() as i32)?; + + for s in self { + writer.write_string(&s, 32767)?; + } + + Ok(()) + } +} + +// TODO: BitSet encoder, implement this +// TODO: impl Encoder for Vec<i64> { +// TODO: fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> { +// TODO: writer.write_var_i32(self.len() as i32)?; + +// TODO: for mask in self { +// TODO: writer.write_i64::<BigEndian>(*mask)? +// TODO: } + +// TODO: Ok(()) +// TODO: } +// TODO: } + pub mod var_int { use crate::encoder::EncoderWriteExt; use crate::error::EncodeError; @@ -222,11 +248,19 @@ pub mod uuid_hyp_str { use crate::encoder::EncoderWriteExt; use crate::error::EncodeError; use std::io::Write; - use uuid::Uuid; + use uuid::{Uuid, Version}; pub fn encode<W: Write>(value: &Uuid, writer: &mut W) -> Result<(), EncodeError> { - let uuid_hyphenated_string = value.to_hyphenated().to_string(); - writer.write_string(&uuid_hyphenated_string, 36)?; + // TODO: use custom encoder for this, rather than putting this in uuid_hyp_str + match value.get_version() { + Some(Version::Md5) => { + writer.write_all(value.as_bytes())?; + } + _ => { + let uuid_hyphenated_string = value.to_hyphenated().to_string(); + writer.write_string(&uuid_hyphenated_string, 36)?; + } + } Ok(()) } diff --git a/protocol/src/version/mod.rs b/protocol/src/version/mod.rs index 7cac6f3..68404a9 100644 --- a/protocol/src/version/mod.rs +++ b/protocol/src/version/mod.rs @@ -1 +1,2 @@ pub mod v1_14_4; +pub mod v1_17_1; diff --git a/protocol/src/version/v1_17_1/game.rs b/protocol/src/version/v1_17_1/game.rs new file mode 100644 index 0000000..b9b7b34 --- /dev/null +++ b/protocol/src/version/v1_17_1/game.rs @@ -0,0 +1,210 @@ +use crate::data::chat::Message; +use crate::decoder::Decoder; +use crate::error::DecodeError; +use minecraft_protocol_derive::Decoder; +use minecraft_protocol_derive::Encoder; +use nbt::CompoundTag; +use std::io::Read; + +// Re-export Minecraft 1.14.4 types +pub use super::super::v1_14_4::game::{ + BossBar, ChunkData, ClientBoundChatMessage, ClientBoundKeepAlive, EntityAction, GameDisconnect, + ServerBoundAbilities, ServerBoundChatMessage, ServerBoundKeepAlive, +}; + +pub enum GameServerBoundPacket { + ServerBoundChatMessage(ServerBoundChatMessage), + ServerBoundKeepAlive(ServerBoundKeepAlive), + ServerBoundAbilities(ServerBoundAbilities), +} + +pub enum GameClientBoundPacket { + ClientBoundChatMessage(ClientBoundChatMessage), + JoinGame(JoinGame), + ClientBoundKeepAlive(ClientBoundKeepAlive), + ChunkData(ChunkData), + GameDisconnect(GameDisconnect), + BossBar(BossBar), + EntityAction(EntityAction), + + PlayerPositionAndLook(PlayerPositionAndLook), + TimeUpdate(TimeUpdate), +} + +impl GameServerBoundPacket { + pub fn get_type_id(&self) -> u8 { + match self { + GameServerBoundPacket::ServerBoundChatMessage(_) => 0x03, + GameServerBoundPacket::ServerBoundKeepAlive(_) => 0x0F, + GameServerBoundPacket::ServerBoundAbilities(_) => 0x19, + } + } + + pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodeError> { + match type_id { + 0x03 => { + let chat_message = ServerBoundChatMessage::decode(reader)?; + + Ok(GameServerBoundPacket::ServerBoundChatMessage(chat_message)) + } + 0x0F => { + let keep_alive = ServerBoundKeepAlive::decode(reader)?; + + Ok(GameServerBoundPacket::ServerBoundKeepAlive(keep_alive)) + } + _ => Err(DecodeError::UnknownPacketType { type_id }), + } + } +} + +impl GameClientBoundPacket { + pub fn get_type_id(&self) -> u8 { + match self { + GameClientBoundPacket::ClientBoundChatMessage(_) => 0x0E, + GameClientBoundPacket::GameDisconnect(_) => 0x1A, + GameClientBoundPacket::ClientBoundKeepAlive(_) => 0x20, + GameClientBoundPacket::ChunkData(_) => 0x21, + GameClientBoundPacket::JoinGame(_) => 0x25, + GameClientBoundPacket::BossBar(_) => 0x0D, + GameClientBoundPacket::EntityAction(_) => 0x1B, + GameClientBoundPacket::PlayerPositionAndLook(_) => 0x38, + GameClientBoundPacket::TimeUpdate(_) => 0x58, + } + } + + pub fn decode<R: Read>(type_id: u8, reader: &mut R) -> Result<Self, DecodeError> { + match type_id { + 0x0E => { + let chat_message = ClientBoundChatMessage::decode(reader)?; + + Ok(GameClientBoundPacket::ClientBoundChatMessage(chat_message)) + } + 0x1A => { + let game_disconnect = GameDisconnect::decode(reader)?; + + Ok(GameClientBoundPacket::GameDisconnect(game_disconnect)) + } + 0x20 => { + let keep_alive = ClientBoundKeepAlive::decode(reader)?; + + Ok(GameClientBoundPacket::ClientBoundKeepAlive(keep_alive)) + } + 0x21 => { + let chunk_data = ChunkData::decode(reader)?; + + Ok(GameClientBoundPacket::ChunkData(chunk_data)) + } + // TODO: 0x25 => { + // TODO: let join_game = JoinGame::decode(reader)?; + + // TODO: Ok(GameClientBoundPacket::JoinGame(join_game)) + // TODO: } + // TODO: 0x38 => { + // TODO: let player_position = PlayerPositionAndLook::decode(reader)?; + + // TODO: Ok(GameClientBoundPacket::PlayerPositionAndLook( + // TODO: player_position, + // TODO: )) + // TODO: } + // TODO: 0x58 => { + // TODO: let time_update = TimeUpdate::decode(reader)?; + + // TODO: Ok(GameClientBoundPacket::TimeUpdate(time_update)) + // TODO: } + _ => Err(DecodeError::UnknownPacketType { type_id }), + } + } +} + +// TODO: implement decoder +// TODO: implement new() +#[derive(Encoder, Debug)] +pub struct JoinGame { + pub entity_id: u32, + pub hardcore: bool, + pub game_mode: u8, + pub previous_game_mode: u8, + pub world_names: Vec<String>, + pub dimension_codec: CompoundTag, + pub dimension: CompoundTag, + pub world_name: String, + pub hashed_seed: i64, + #[data_type(with = "var_int")] + pub max_players: i32, + #[data_type(with = "var_int")] + pub view_distance: i32, + pub reduced_debug_info: bool, + pub enable_respawn_screen: bool, + pub is_debug: bool, + pub is_flat: bool, +} + +// TODO: implement decoder +// TODO: implement new() +#[derive(Encoder, Debug)] +pub struct PlayerPositionAndLook { + pub x: f64, + pub y: f64, + pub z: f64, + pub yaw: f32, + pub pitch: f32, + pub flags: u8, + #[data_type(with = "var_int")] + pub teleport_id: i32, + pub dismount_vehicle: bool, +} + +// TODO: implement decoder +// TODO: implement new() +#[derive(Encoder, Debug)] +pub struct TimeUpdate { + pub world_age: i64, + pub time_of_day: i64, +} + +#[derive(Encoder, Decoder, Debug)] +pub struct SetTitleText { + pub text: Message, +} + +#[derive(Encoder, Decoder, Debug)] +pub struct SetTitleSubtitle { + pub text: Message, +} + +#[derive(Encoder, Decoder, Debug)] +pub struct SetTitleTimes { + pub fade_in: i32, + pub stay: i32, + pub fade_out: i32, +} + +#[derive(Encoder, Decoder, Debug)] +pub struct SpawnPosition { + pub position: u64, + pub angle: f32, +} + +// TODO: implement decoder +// TODO: implement new() +// #[derive(Encoder, Debug)] +// pub struct ChunkData { +// pub x: i32, +// pub z: i32, +// // TODO: should be BitSet type! +// pub primary_mask: Vec<i64>, +// pub heightmaps: CompoundTag, + +// #[data_type(with = "var_int_array")] +// pub biomes: Vec<i32>, + +// // TODO: extract this from block_entities with sized datatype +// #[data_type(with = "var_int")] +// pub data_size: i32, +// pub data: Vec<u8>, + +// // TODO: extract this from block_entities with sized datatype +// #[data_type(with = "var_int")] +// pub block_entities_size: i32, +// pub block_entities: Vec<u8>, +// } diff --git a/protocol/src/version/v1_17_1/mod.rs b/protocol/src/version/v1_17_1/mod.rs new file mode 100644 index 0000000..f7ee1cd --- /dev/null +++ b/protocol/src/version/v1_17_1/mod.rs @@ -0,0 +1 @@ +pub mod game;