From dbb2092ac002790c07ad21cf7d12aabb477a2e74 Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Sat, 20 Aug 2022 15:17:07 -0500 Subject: [PATCH] Implement ALL packets (#16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add a couple more packets and improve codegen * enums in packet codegen * fix enums and MORE PACKETS * make unsigned numbers the default * codegen can make hashmaps * UnsizedByteArray in codegen * Vec and Option * enum codgen works in more situations * ServerboundInteractPacket * Fix error with new error system * More packets * more packets * more packets * guess what was added * yeah it's more packets * add more packets * packets * start adding ClientboundBossEventPacket * finish boss event packet * improve codegen for linux * start on command suggestions packet * rename declare_commands to commands * más paquetes * fix generating custom payload packet * more packets * mehr Pakete * improve codegen for movement packets * rename move packets to have "packet" at the end * fix some unused variable warns * addere plus facis * pli da pakoj * plus de paquets * più pacchetti * make ChatFormatting a macro in azalea-chat * change a match to matches! macro * update SetPlayerTeam to use ChatFormatting * ClientboundSetScorePacket & fix clippy warnings * finish game state :tada: * add remaining packets for other states * fix error in ping.rs --- azalea-buf/buf-macros/src/lib.rs | 4 +- azalea-buf/src/read.rs | 39 +++ azalea-buf/src/write.rs | 34 ++ azalea-chat/src/component.rs | 2 +- azalea-chat/src/style.rs | 295 +++++++++++------- azalea-chat/src/text_component.rs | 18 +- azalea-chat/tests/integration_test.rs | 2 +- azalea-client/src/client.rs | 6 +- azalea-client/src/movement.rs | 2 +- azalea-client/src/ping.rs | 9 +- .../clientbound_add_experience_orb_packet.rs | 12 + .../game/clientbound_award_stats_packet.rs | 18 ++ .../clientbound_block_destruction_packet.rs | 13 + .../clientbound_block_entity_data_packet.rs | 12 + .../game/clientbound_block_event_packet.rs | 13 + .../game/clientbound_block_update_packet.rs | 3 +- .../game/clientbound_boss_event_packet.rs | 143 +++++++++ .../clientbound_command_suggestions_packet.rs | 32 ++ ...cket.rs => clientbound_commands_packet.rs} | 2 +- .../clientbound_container_set_data_packet.rs | 9 + .../clientbound_container_set_slot_packet.rs | 12 + .../game/clientbound_cooldown_packet.rs | 11 + ...entbound_custom_chat_completions_packet.rs | 2 +- .../game/clientbound_custom_sound_packet.rs | 20 ++ .../game/clientbound_entity_event_packet.rs | 1 - .../game/clientbound_explode_packet.rs | 118 +++++++ .../clientbound_forget_level_chunk_packet.rs | 8 + .../clientbound_horse_screen_open_packet.rs | 10 + .../game/clientbound_level_event_packet.rs | 4 +- .../game/clientbound_light_update_packet.rs | 2 + .../packets/game/clientbound_login_packet.rs | 4 +- .../game/clientbound_map_item_data_packet.rs | 119 +++++++ .../clientbound_merchant_offers_packet.rs | 30 ++ ...clientbound_move_entity_pos_rot_packet.rs} | 2 +- .../clientbound_move_entity_rot_packet.rs | 2 +- .../game/clientbound_move_vehicle_packet.rs | 11 + .../game/clientbound_open_book_packet.rs | 8 + .../game/clientbound_open_screen_packet.rs | 13 + .../clientbound_open_sign_editor_packet.rs | 8 + .../packets/game/clientbound_ping_packet.rs | 7 + .../clientbound_place_ghost_recipe_packet.rs | 9 + .../clientbound_player_combat_end_packet.rs | 9 + .../clientbound_player_combat_enter_packet.rs | 5 + .../clientbound_player_combat_kill_packet.rs | 11 + .../game/clientbound_player_look_at_packet.rs | 24 ++ .../clientbound_remove_mob_effect_packet.rs | 11 + .../game/clientbound_resource_pack_packet.rs | 11 + .../game/clientbound_respawn_packet.rs | 16 + ...entbound_select_advancements_tab_packet.rs | 8 + .../clientbound_set_action_bar_text_packet.rs | 8 + .../clientbound_set_border_center_packet.rs | 8 + ...clientbound_set_border_lerp_size_packet.rs | 10 + .../clientbound_set_border_size_packet.rs | 7 + ...ntbound_set_border_warning_delay_packet.rs | 8 + ...ound_set_border_warning_distance_packet.rs | 8 + .../game/clientbound_set_camera_packet.rs | 8 + ...ientbound_set_chunk_cache_radius_packet.rs | 8 + ...lientbound_set_display_objective_packet.rs | 8 + .../clientbound_set_entity_data_packet.rs | 2 +- .../clientbound_set_entity_motion_packet.rs | 11 + .../game/clientbound_set_objective_packet.rs | 59 ++++ .../game/clientbound_set_passengers_packet.rs | 10 + .../clientbound_set_player_team_packet.rs | 80 +++++ .../game/clientbound_set_score_packet.rs | 61 ++++ ...entbound_set_simulation_distance_packet.rs | 8 + .../clientbound_set_subtitle_text_packet.rs | 8 + .../game/clientbound_set_title_text_packet.rs | 8 + ...clientbound_set_titles_animation_packet.rs | 9 + .../game/clientbound_sound_entity_packet.rs | 16 + .../packets/game/clientbound_sound_packet.rs | 5 +- .../game/clientbound_stop_sound_packet.rs | 51 +++ .../game/clientbound_tab_list_packet.rs | 9 + .../game/clientbound_tag_query_packet.rs | 9 + .../clientbound_take_item_entity_packet.rs | 12 + azalea-protocol/src/packets/game/mod.rs | 210 ++++++++++++- .../serverbound_block_entity_tag_query.rs | 10 + .../serverbound_change_difficulty_packet.rs | 8 + .../game/serverbound_client_command_packet.rs | 13 + .../serverbound_client_information_packet.rs | 27 ++ .../serverbound_command_suggestion_packet.rs | 9 + ...rverbound_container_button_click_packet.rs | 8 + .../serverbound_container_click_packet.rs | 26 ++ .../serverbound_container_close_packet.rs | 7 + .../game/serverbound_edit_book_packet.rs | 10 + .../game/serverbound_entity_tag_query.rs | 10 + .../game/serverbound_interact_packet.rs | 85 +++++ .../serverbound_jigsaw_generate_packet.rs | 11 + .../serverbound_lock_difficulty_packet.rs | 7 + ... => serverbound_move_player_pos_packet.rs} | 0 ...serverbound_move_player_pos_rot_packet.rs} | 0 ... => serverbound_move_player_rot_packet.rs} | 0 ...erbound_move_player_status_only_packet.rs} | 0 .../game/serverbound_move_vehicle_packet.rs | 11 + .../game/serverbound_paddle_boat_packet.rs | 8 + .../game/serverbound_pick_item_packet.rs | 8 + .../game/serverbound_place_recipe_packet.rs | 10 + .../serverbound_player_abilities_packet.rs | 28 ++ .../game/serverbound_player_action_packet.rs | 24 ++ .../game/serverbound_player_command_packet.rs | 24 ++ .../game/serverbound_player_input_packet.rs | 43 +++ .../packets/game/serverbound_pong_packet.rs | 7 + ...ound_recipe_book_change_settings_packet.rs | 17 + ...verbound_recipe_book_seen_recipe_packet.rs | 8 + .../game/serverbound_rename_item_packet.rs | 7 + .../game/serverbound_resource_pack_packet.rs | 15 + .../serverbound_seen_advancements_packet.rs | 38 +++ .../game/serverbound_select_trade_packet.rs | 8 + .../game/serverbound_set_beacon_packet.rs | 10 + .../serverbound_set_carried_item_packet.rs | 7 + .../serverbound_set_command_block_packet.rs | 64 ++++ ...serverbound_set_command_minecart_packet.rs | 10 + ...rverbound_set_creative_mode_slot_packet.rs | 9 + .../serverbound_set_jigsaw_block_packet.rs | 44 +++ .../serverbound_set_structure_block_packet.rs | 96 ++++++ .../game/serverbound_sign_update_packet.rs | 9 + .../packets/game/serverbound_swing_packet.rs | 8 + .../serverbound_teleport_to_entity_packet.rs | 8 + .../game/serverbound_use_item_on_packet.rs | 54 ++++ .../game/serverbound_use_item_packet.rs | 10 + azalea-protocol/src/packets/login/mod.rs | 5 +- .../login/serverbound_custom_query_packet.rs | 9 + .../clientbound_pong_response_packet.rs | 7 + azalea-protocol/src/packets/status/mod.rs | 4 + .../status/serverbound_ping_request_packet.rs | 7 + azalea-world/src/entity.rs | 7 +- codegen/lib/code/packet.py | 187 +++++++++-- codegen/lib/code/utils.py | 102 +++++- codegen/lib/extract.py | 31 +- codegen/lib/mappings.py | 41 ++- 129 files changed, 2799 insertions(+), 222 deletions(-) create mode 100644 azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_block_event_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs rename azalea-protocol/src/packets/game/{clientbound_declare_commands_packet.rs => clientbound_commands_packet.rs} (99%) mode change 100755 => 100644 create mode 100644 azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_explode_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_forget_level_chunk_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_horse_screen_open_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_map_item_data_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_merchant_offers_packet.rs rename azalea-protocol/src/packets/game/{clientbound_move_entity_posrot_packet.rs => clientbound_move_entity_pos_rot_packet.rs} (88%) create mode 100644 azalea-protocol/src/packets/game/clientbound_move_vehicle_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_open_book_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_open_sign_editor_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_ping_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_place_ghost_recipe_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_player_combat_end_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_player_combat_enter_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_player_combat_kill_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_player_look_at_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_resource_pack_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_respawn_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_select_advancements_tab_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_action_bar_text_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_border_center_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_border_lerp_size_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_border_size_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_border_warning_delay_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_border_warning_distance_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_camera_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_chunk_cache_radius_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_display_objective_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_entity_motion_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_objective_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_passengers_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_player_team_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_score_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_simulation_distance_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_subtitle_text_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_title_text_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_titles_animation_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_stop_sound_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_tab_list_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_take_item_entity_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_block_entity_tag_query.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_change_difficulty_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_client_command_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_client_information_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_command_suggestion_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_container_button_click_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_container_click_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_container_close_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_edit_book_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_entity_tag_query.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_interact_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_jigsaw_generate_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_lock_difficulty_packet.rs rename azalea-protocol/src/packets/game/{serverbound_move_player_packet_pos.rs => serverbound_move_player_pos_packet.rs} (100%) rename azalea-protocol/src/packets/game/{serverbound_move_player_packet_pos_rot.rs => serverbound_move_player_pos_rot_packet.rs} (100%) rename azalea-protocol/src/packets/game/{serverbound_move_player_packet_rot.rs => serverbound_move_player_rot_packet.rs} (100%) rename azalea-protocol/src/packets/game/{serverbound_move_player_packet_status_only.rs => serverbound_move_player_status_only_packet.rs} (100%) create mode 100644 azalea-protocol/src/packets/game/serverbound_move_vehicle_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_paddle_boat_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_pick_item_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_place_recipe_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_player_abilities_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_player_action_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_player_command_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_player_input_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_pong_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_recipe_book_change_settings_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_recipe_book_seen_recipe_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_rename_item_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_resource_pack_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_seen_advancements_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_select_trade_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_beacon_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_carried_item_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_command_block_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_command_minecart_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_creative_mode_slot_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_jigsaw_block_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_set_structure_block_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_sign_update_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_swing_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_teleport_to_entity_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_use_item_on_packet.rs create mode 100644 azalea-protocol/src/packets/game/serverbound_use_item_packet.rs create mode 100644 azalea-protocol/src/packets/login/serverbound_custom_query_packet.rs create mode 100644 azalea-protocol/src/packets/status/clientbound_pong_response_packet.rs create mode 100644 azalea-protocol/src/packets/status/serverbound_ping_request_packet.rs diff --git a/azalea-buf/buf-macros/src/lib.rs b/azalea-buf/buf-macros/src/lib.rs index 25bceef0..43e60e6e 100644 --- a/azalea-buf/buf-macros/src/lib.rs +++ b/azalea-buf/buf-macros/src/lib.rs @@ -18,7 +18,7 @@ fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt // do a different buf.write_* for each field depending on the type // if it's a string, use buf.write_string match field_type { - syn::Type::Path(_) => { + syn::Type::Path(_) | syn::Type::Array(_) => { if f.attrs.iter().any(|a| a.path.is_ident("var")) { quote! { let #field_name = azalea_buf::McBufVarReadable::var_read_from(buf)?; @@ -112,7 +112,7 @@ fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt // do a different buf.write_* for each field depending on the type // if it's a string, use buf.write_string match field_type { - syn::Type::Path(_) => { + syn::Type::Path(_) | syn::Type::Array(_) => { if f.attrs.iter().any(|attr| attr.path.is_ident("var")) { quote! { azalea_buf::McBufVarWritable::var_write_into(&self.#field_name, buf)?; diff --git a/azalea-buf/src/read.rs b/azalea-buf/src/read.rs index 8518d637..7372018e 100644 --- a/azalea-buf/src/read.rs +++ b/azalea-buf/src/read.rs @@ -24,6 +24,8 @@ pub enum BufReadError { InvalidUtf8, #[error("Unexpected enum variant {id}")] UnexpectedEnumVariant { id: i32 }, + #[error("Unexpected enum variant {id}")] + UnexpectedStringEnumVariant { id: String }, #[error("{0}")] Custom(String), #[cfg(feature = "serde_json")] @@ -281,6 +283,19 @@ impl McBufReadable } } +impl McBufVarReadable + for HashMap +{ + default fn var_read_from(buf: &mut impl Read) -> Result { + let length = buf.read_varint()? as usize; + let mut contents = HashMap::with_capacity(length); + for _ in 0..length { + contents.insert(K::read_from(buf)?, V::var_read_from(buf)?); + } + Ok(contents) + } +} + impl McBufReadable for Vec { fn read_from(buf: &mut impl Read) -> Result { buf.read_byte_array() @@ -386,3 +401,27 @@ impl McBufReadable for Option { }) } } + +impl McBufVarReadable for Option { + default fn var_read_from(buf: &mut impl Read) -> Result { + let present = buf.read_boolean()?; + Ok(if present { + Some(T::var_read_from(buf)?) + } else { + None + }) + } +} + +// [String; 4] +impl McBufReadable for [T; N] { + default fn read_from(buf: &mut impl Read) -> Result { + let mut contents = Vec::with_capacity(N); + for _ in 0..N { + contents.push(T::read_from(buf)?); + } + contents.try_into().map_err(|_| { + panic!("Panic is not possible since the Vec is the same size as the array") + }) + } +} diff --git a/azalea-buf/src/write.rs b/azalea-buf/src/write.rs index df7f56e0..8def52b3 100644 --- a/azalea-buf/src/write.rs +++ b/azalea-buf/src/write.rs @@ -155,6 +155,18 @@ impl McBufWritable for HashMap { } } +impl McBufVarWritable for HashMap { + default fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + u32::var_write_into(&(self.len() as u32), buf)?; + for (key, value) in self { + key.write_into(buf)?; + value.var_write_into(buf)?; + } + + Ok(()) + } +} + impl McBufWritable for Vec { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { buf.write_byte_array(self) @@ -284,3 +296,25 @@ impl McBufWritable for Option { Ok(()) } } + +impl McBufVarWritable for Option { + default fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + if let Some(s) = self { + buf.write_boolean(true)?; + s.var_write_into(buf)?; + } else { + buf.write_boolean(false)?; + }; + Ok(()) + } +} + +// [T; N] +impl McBufWritable for [T; N] { + default fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + for i in self { + i.write_into(buf)?; + } + Ok(()) + } +} diff --git a/azalea-chat/src/component.rs b/azalea-chat/src/component.rs index 8a038bf0..291baa16 100755 --- a/azalea-chat/src/component.rs +++ b/azalea-chat/src/component.rs @@ -18,7 +18,7 @@ pub enum Component { lazy_static! { pub static ref DEFAULT_STYLE: Style = Style { - color: Some(ChatFormatting::WHITE.try_into().unwrap()), + color: Some(ChatFormatting::White.try_into().unwrap()), ..Style::default() }; } diff --git a/azalea-chat/src/style.rs b/azalea-chat/src/style.rs index 3a667776..6edcdc2d 100755 --- a/azalea-chat/src/style.rs +++ b/azalea-chat/src/style.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, fmt}; +use azalea_buf::McBuf; use serde_json::Value; #[derive(Clone, PartialEq, Eq, Debug)] @@ -28,15 +29,15 @@ impl TextColor { } lazy_static! { - static ref LEGACY_FORMAT_TO_COLOR: HashMap<&'static ChatFormatting<'static>, TextColor> = { + static ref LEGACY_FORMAT_TO_COLOR: HashMap<&'static ChatFormatting, TextColor> = { let mut legacy_format_to_color = HashMap::new(); for formatter in &ChatFormatting::FORMATTERS { - if !formatter.is_format && *formatter != ChatFormatting::RESET { + if !formatter.is_format() && *formatter != ChatFormatting::Reset { legacy_format_to_color.insert( formatter, TextColor { - value: formatter.color.unwrap(), - name: Some(formatter.name.to_string()), + value: formatter.color().unwrap(), + name: Some(formatter.name().to_string()), }, ); } @@ -52,15 +53,6 @@ lazy_static! { }; } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct ChatFormatting<'a> { - pub name: &'a str, - pub code: char, - pub is_format: bool, - pub id: i32, - pub color: Option, -} - pub struct Ansi {} impl Ansi { pub const BOLD: &'static str = "\u{1b}[1m"; @@ -80,91 +72,172 @@ impl Ansi { } } -impl<'a> ChatFormatting<'a> { - pub const BLACK: ChatFormatting<'a> = ChatFormatting::new("BLACK", '0', false, 0, Some(0)); - pub const DARK_BLUE: ChatFormatting<'a> = - ChatFormatting::new("DARK_BLUE", '1', false, 1, Some(170)); - pub const DARK_GREEN: ChatFormatting<'a> = - ChatFormatting::new("DARK_GREEN", '2', false, 2, Some(43520)); - pub const DARK_AQUA: ChatFormatting<'a> = - ChatFormatting::new("DARK_AQUA", '3', false, 3, Some(43690)); - pub const DARK_RED: ChatFormatting<'a> = - ChatFormatting::new("DARK_RED", '4', false, 4, Some(1114112)); - pub const DARK_PURPLE: ChatFormatting<'a> = - ChatFormatting::new("DARK_PURPLE", '5', false, 5, Some(11141290)); - pub const GOLD: ChatFormatting<'a> = ChatFormatting::new("GOLD", '6', false, 6, Some(16755200)); - pub const GRAY: ChatFormatting<'a> = ChatFormatting::new("GRAY", '7', false, 7, Some(11184810)); - pub const DARK_GRAY: ChatFormatting<'a> = - ChatFormatting::new("DARK_GRAY", '8', false, 8, Some(5592405)); - pub const BLUE: ChatFormatting<'a> = ChatFormatting::new("BLUE", '9', false, 9, Some(5592575)); - pub const GREEN: ChatFormatting<'a> = - ChatFormatting::new("GREEN", 'a', false, 10, Some(5635925)); - pub const AQUA: ChatFormatting<'a> = ChatFormatting::new("AQUA", 'b', false, 11, Some(5636095)); - pub const RED: ChatFormatting<'a> = ChatFormatting::new("RED", 'c', false, 12, Some(16733525)); - pub const LIGHT_PURPLE: ChatFormatting<'a> = - ChatFormatting::new("LIGHT_PURPLE", 'd', false, 13, Some(16733695)); - pub const YELLOW: ChatFormatting<'a> = - ChatFormatting::new("YELLOW", 'e', false, 14, Some(16777045)); - pub const WHITE: ChatFormatting<'a> = - ChatFormatting::new("WHITE", 'f', false, 15, Some(16777215)); - pub const OBFUSCATED: ChatFormatting<'a> = - ChatFormatting::new("OBFUSCATED", 'k', true, -1, None); - pub const STRIKETHROUGH: ChatFormatting<'a> = - ChatFormatting::new("STRIKETHROUGH", 'm', true, -1, None); - pub const BOLD: ChatFormatting<'a> = ChatFormatting::new("BOLD", 'l', true, -1, None); - pub const UNDERLINE: ChatFormatting<'a> = ChatFormatting::new("UNDERLINE", 'n', true, -1, None); - pub const ITALIC: ChatFormatting<'a> = ChatFormatting::new("ITALIC", 'o', true, -1, None); - pub const RESET: ChatFormatting<'a> = ChatFormatting::new("RESET", 'r', true, -1, None); +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, McBuf)] +pub enum ChatFormatting { + Black, + DarkBlue, + DarkGreen, + DarkAqua, + DarkRed, + DarkPurple, + Gold, + Gray, + DarkGray, + Blue, + Green, + Aqua, + Red, + LightPurple, + Yellow, + White, + Obfuscated, + Strikethrough, + Bold, + Underline, + Italic, + Reset, +} - pub const FORMATTERS: [ChatFormatting<'a>; 22] = [ - ChatFormatting::BLACK, - ChatFormatting::DARK_BLUE, - ChatFormatting::DARK_GREEN, - ChatFormatting::DARK_AQUA, - ChatFormatting::DARK_RED, - ChatFormatting::DARK_PURPLE, - ChatFormatting::GOLD, - ChatFormatting::GRAY, - ChatFormatting::DARK_GRAY, - ChatFormatting::BLUE, - ChatFormatting::GREEN, - ChatFormatting::AQUA, - ChatFormatting::RED, - ChatFormatting::LIGHT_PURPLE, - ChatFormatting::YELLOW, - ChatFormatting::WHITE, - ChatFormatting::OBFUSCATED, - ChatFormatting::STRIKETHROUGH, - ChatFormatting::BOLD, - ChatFormatting::UNDERLINE, - ChatFormatting::ITALIC, - ChatFormatting::RESET, +impl ChatFormatting { + pub const FORMATTERS: [ChatFormatting; 22] = [ + ChatFormatting::Black, + ChatFormatting::DarkBlue, + ChatFormatting::DarkGreen, + ChatFormatting::DarkAqua, + ChatFormatting::DarkRed, + ChatFormatting::DarkPurple, + ChatFormatting::Gold, + ChatFormatting::Gray, + ChatFormatting::DarkGray, + ChatFormatting::Blue, + ChatFormatting::Green, + ChatFormatting::Aqua, + ChatFormatting::Red, + ChatFormatting::LightPurple, + ChatFormatting::Yellow, + ChatFormatting::White, + ChatFormatting::Obfuscated, + ChatFormatting::Strikethrough, + ChatFormatting::Bold, + ChatFormatting::Underline, + ChatFormatting::Italic, + ChatFormatting::Reset, ]; - const fn new( - name: &str, - code: char, - is_format: bool, - id: i32, - color: Option, - ) -> ChatFormatting { - ChatFormatting { - name, - code, - is_format, - id, - color, + pub fn name(&self) -> &'static str { + match self { + ChatFormatting::Black => "BLACK", + ChatFormatting::DarkBlue => "DARK_BLUE", + ChatFormatting::DarkGreen => "DARK_GREEN", + ChatFormatting::DarkAqua => "DARK_AQUA", + ChatFormatting::DarkRed => "DARK_RED", + ChatFormatting::DarkPurple => "DARK_PURPLE", + ChatFormatting::Gold => "GOLD", + ChatFormatting::Gray => "GRAY", + ChatFormatting::DarkGray => "DARK_GRAY", + ChatFormatting::Blue => "BLUE", + ChatFormatting::Green => "GREEN", + ChatFormatting::Aqua => "AQUA", + ChatFormatting::Red => "RED", + ChatFormatting::LightPurple => "LIGHT_PURPLE", + ChatFormatting::Yellow => "YELLOW", + ChatFormatting::White => "WHITE", + ChatFormatting::Obfuscated => "OBFUSCATED", + ChatFormatting::Strikethrough => "STRIKETHROUGH", + ChatFormatting::Bold => "BOLD", + ChatFormatting::Underline => "UNDERLINE", + ChatFormatting::Italic => "ITALIC", + ChatFormatting::Reset => "RESET", } } - pub fn from_code(code: char) -> Option<&'static ChatFormatting<'static>> { - for formatter in &ChatFormatting::FORMATTERS { - if formatter.code == code { - return Some(formatter); - } + pub fn code(&self) -> char { + match self { + ChatFormatting::Black => '0', + ChatFormatting::DarkBlue => '1', + ChatFormatting::DarkGreen => '2', + ChatFormatting::DarkAqua => '3', + ChatFormatting::DarkRed => '4', + ChatFormatting::DarkPurple => '5', + ChatFormatting::Gold => '6', + ChatFormatting::Gray => '7', + ChatFormatting::DarkGray => '8', + ChatFormatting::Blue => '9', + ChatFormatting::Green => 'a', + ChatFormatting::Aqua => 'b', + ChatFormatting::Red => 'c', + ChatFormatting::LightPurple => 'd', + ChatFormatting::Yellow => 'e', + ChatFormatting::White => 'f', + ChatFormatting::Obfuscated => 'k', + ChatFormatting::Strikethrough => 'm', + ChatFormatting::Bold => 'l', + ChatFormatting::Underline => 'n', + ChatFormatting::Italic => 'o', + ChatFormatting::Reset => 'r', } + } - None + pub fn from_code(code: char) -> Option { + match code { + '0' => Some(ChatFormatting::Black), + '1' => Some(ChatFormatting::DarkBlue), + '2' => Some(ChatFormatting::DarkGreen), + '3' => Some(ChatFormatting::DarkAqua), + '4' => Some(ChatFormatting::DarkRed), + '5' => Some(ChatFormatting::DarkPurple), + '6' => Some(ChatFormatting::Gold), + '7' => Some(ChatFormatting::Gray), + '8' => Some(ChatFormatting::DarkGray), + '9' => Some(ChatFormatting::Blue), + 'a' => Some(ChatFormatting::Green), + 'b' => Some(ChatFormatting::Aqua), + 'c' => Some(ChatFormatting::Red), + 'd' => Some(ChatFormatting::LightPurple), + 'e' => Some(ChatFormatting::Yellow), + 'f' => Some(ChatFormatting::White), + 'k' => Some(ChatFormatting::Obfuscated), + 'm' => Some(ChatFormatting::Strikethrough), + 'l' => Some(ChatFormatting::Bold), + 'n' => Some(ChatFormatting::Underline), + 'o' => Some(ChatFormatting::Italic), + 'r' => Some(ChatFormatting::Reset), + _ => None, + } + } + + pub fn is_format(&self) -> bool { + matches!( + self, + ChatFormatting::Obfuscated + | ChatFormatting::Strikethrough + | ChatFormatting::Bold + | ChatFormatting::Underline + | ChatFormatting::Italic + | ChatFormatting::Reset + ) + } + + pub fn color(&self) -> Option { + match self { + ChatFormatting::Black => Some(0), + ChatFormatting::DarkBlue => Some(170), + ChatFormatting::DarkGreen => Some(43520), + ChatFormatting::DarkAqua => Some(43690), + ChatFormatting::DarkRed => Some(1114112), + ChatFormatting::DarkPurple => Some(11141290), + ChatFormatting::Gold => Some(16755200), + ChatFormatting::Gray => Some(11184810), + ChatFormatting::DarkGray => Some(5592405), + ChatFormatting::Blue => Some(5592575), + ChatFormatting::Green => Some(5635925), + ChatFormatting::Aqua => Some(5636095), + ChatFormatting::Red => Some(16733525), + ChatFormatting::LightPurple => Some(16733695), + ChatFormatting::Yellow => Some(16777045), + ChatFormatting::White => Some(16777215), + _ => None, + } } } @@ -189,15 +262,15 @@ impl fmt::Display for TextColor { } // from ChatFormatting to TextColor -impl TryFrom> for TextColor { +impl TryFrom for TextColor { type Error = String; - fn try_from(formatter: ChatFormatting<'_>) -> Result { - if formatter.is_format { - return Err(format!("{} is not a color", formatter.name)); + fn try_from(formatter: ChatFormatting) -> Result { + if formatter.is_format() { + return Err(format!("{} is not a color", formatter.name())); } - let color = formatter.color.unwrap_or(0); - Ok(Self::new(color, Some(formatter.name.to_string()))) + let color = formatter.color().unwrap_or(0); + Ok(Self::new(color, Some(formatter.name().to_string()))) } } @@ -363,21 +436,15 @@ impl Style { /// Apply a ChatFormatting to this style pub fn apply_formatting(&mut self, formatting: &ChatFormatting) { match *formatting { - ChatFormatting::BOLD => self.bold = Some(true), - ChatFormatting::ITALIC => self.italic = Some(true), - ChatFormatting::UNDERLINE => self.underlined = Some(true), - ChatFormatting::STRIKETHROUGH => self.strikethrough = Some(true), - ChatFormatting::OBFUSCATED => self.obfuscated = Some(true), - ChatFormatting::RESET => self.reset = true, - ChatFormatting { - name: _, - code: _, - is_format: _, - id: _, - color, - } => { + ChatFormatting::Bold => self.bold = Some(true), + ChatFormatting::Italic => self.italic = Some(true), + ChatFormatting::Underline => self.underlined = Some(true), + ChatFormatting::Strikethrough => self.strikethrough = Some(true), + ChatFormatting::Obfuscated => self.obfuscated = Some(true), + ChatFormatting::Reset => self.reset = true, + formatter => { // if it's a color, set it - if let Some(color) = color { + if let Some(color) = formatter.color() { self.color = Some(TextColor::from_rgb(color)); } } @@ -455,7 +522,7 @@ mod tests { format!( "{reset}{italic}{white}", reset = Ansi::RESET, - white = Ansi::rgb(ChatFormatting::WHITE.color.unwrap()), + white = Ansi::rgb(ChatFormatting::White.color().unwrap()), italic = Ansi::ITALIC ) ) @@ -465,15 +532,15 @@ mod tests { fn test_from_code() { assert_eq!( ChatFormatting::from_code('a').unwrap(), - &ChatFormatting::GREEN + ChatFormatting::Green ); } #[test] fn test_apply_formatting() { let mut style = Style::default(); - style.apply_formatting(&ChatFormatting::BOLD); - style.apply_formatting(&ChatFormatting::RED); + style.apply_formatting(&ChatFormatting::Bold); + style.apply_formatting(&ChatFormatting::Red); assert_eq!(style.color, Some(TextColor::from_rgb(16733525))); } } diff --git a/azalea-chat/src/text_component.rs b/azalea-chat/src/text_component.rs index a3eb0e4b..564511fc 100755 --- a/azalea-chat/src/text_component.rs +++ b/azalea-chat/src/text_component.rs @@ -29,7 +29,7 @@ pub fn legacy_color_code_to_text_component(legacy_color_code: &str) -> TextCompo let style = &mut components.last_mut().unwrap().base.style; // if the formatter is a reset, then we need to reset the style to the default - style.apply_formatting(formatter); + style.apply_formatting(&formatter); } i += 1; } else { @@ -93,9 +93,9 @@ mod tests { component.to_ansi(None), format!( "{GREEN}Hypixel Network {RED}[1.8-1.18]\n{BOLD}{AQUA}HAPPY HOLIDAYS{RESET}", - GREEN = Ansi::rgb(ChatFormatting::GREEN.color.unwrap()), - RED = Ansi::rgb(ChatFormatting::RED.color.unwrap()), - AQUA = Ansi::rgb(ChatFormatting::AQUA.color.unwrap()), + GREEN = Ansi::rgb(ChatFormatting::Green.color().unwrap()), + RED = Ansi::rgb(ChatFormatting::Red.color().unwrap()), + AQUA = Ansi::rgb(ChatFormatting::Aqua.color().unwrap()), BOLD = Ansi::BOLD, RESET = Ansi::RESET ) @@ -111,11 +111,11 @@ mod tests { "{BOLD}Hello {RESET}{DARK_BLUE}w{DARK_GREEN}o{DARK_AQUA}r{DARK_RED}l{DARK_PURPLE}d{RESET}", BOLD = Ansi::BOLD, RESET = Ansi::RESET, - DARK_BLUE = Ansi::rgb(ChatFormatting::DARK_BLUE.color.unwrap()), - DARK_GREEN = Ansi::rgb(ChatFormatting::DARK_GREEN.color.unwrap()), - DARK_AQUA = Ansi::rgb(ChatFormatting::DARK_AQUA.color.unwrap()), - DARK_RED = Ansi::rgb(ChatFormatting::DARK_RED.color.unwrap()), - DARK_PURPLE = Ansi::rgb(ChatFormatting::DARK_PURPLE.color.unwrap()) + DARK_BLUE = Ansi::rgb(ChatFormatting::DarkBlue.color().unwrap()), + DARK_GREEN = Ansi::rgb(ChatFormatting::DarkGreen.color().unwrap()), + DARK_AQUA = Ansi::rgb(ChatFormatting::DarkAqua.color().unwrap()), + DARK_RED = Ansi::rgb(ChatFormatting::DarkRed.color().unwrap()), + DARK_PURPLE = Ansi::rgb(ChatFormatting::DarkPurple.color().unwrap()) ) ); } diff --git a/azalea-chat/tests/integration_test.rs b/azalea-chat/tests/integration_test.rs index 1278adfa..c2be960e 100755 --- a/azalea-chat/tests/integration_test.rs +++ b/azalea-chat/tests/integration_test.rs @@ -59,7 +59,7 @@ fn complex_ansi_test() { bold = Ansi::BOLD, italic = Ansi::ITALIC, underlined = Ansi::UNDERLINED, - red = Ansi::rgb(ChatFormatting::RED.color.unwrap()), + red = Ansi::rgb(ChatFormatting::Red.color().unwrap()), reset = Ansi::RESET, strikethrough = Ansi::STRIKETHROUGH, abcdef = Ansi::rgb(TextColor::parse("#abcdef".to_string()).unwrap().value), diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index 38e36b63..fcb624b4 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -11,7 +11,7 @@ use azalea_protocol::{ serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket, serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, serverbound_keep_alive_packet::ServerboundKeepAlivePacket, - serverbound_move_player_packet_pos_rot::ServerboundMovePlayerPacketPosRot, + serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPacketPosRot, ClientboundGamePacket, ServerboundGamePacket, }, handshake::client_intention_packet::ClientIntentionPacket, @@ -339,7 +339,7 @@ impl Client { ClientboundGamePacket::ClientboundChangeDifficultyPacket(p) => { println!("Got difficulty packet {:?}", p); } - ClientboundGamePacket::ClientboundDeclareCommandsPacket(_p) => { + ClientboundGamePacket::ClientboundCommandsPacket(_p) => { println!("Got declare commands packet"); } ClientboundGamePacket::ClientboundPlayerAbilitiesPacket(p) => { @@ -562,7 +562,7 @@ impl Client { .move_entity_with_delta(p.entity_id, &p.delta) .map_err(|e| HandleError::Other(e.into()))?; } - ClientboundGamePacket::ClientboundMoveEntityPosrotPacket(p) => { + ClientboundGamePacket::ClientboundMoveEntityPosRotPacket(p) => { let mut dimension_lock = client.dimension.lock()?; let dimension = dimension_lock.as_mut().unwrap(); diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs index bc48e1b2..5f9533be 100644 --- a/azalea-client/src/movement.rs +++ b/azalea-client/src/movement.rs @@ -1,6 +1,6 @@ use crate::Client; use azalea_core::EntityPos; -use azalea_protocol::packets::game::serverbound_move_player_packet_pos_rot::ServerboundMovePlayerPacketPosRot; +use azalea_protocol::packets::game::serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPacketPosRot; use azalea_world::MoveEntityError; use thiserror::Error; diff --git a/azalea-client/src/ping.rs b/azalea-client/src/ping.rs index 303fae74..e4872881 100755 --- a/azalea-client/src/ping.rs +++ b/azalea-client/src/ping.rs @@ -52,7 +52,12 @@ pub async fn ping_server( let packet = conn.read().await?; - match packet { - ClientboundStatusPacket::ClientboundStatusResponsePacket(p) => Ok(p), + loop { + match packet { + ClientboundStatusPacket::ClientboundStatusResponsePacket(p) => return Ok(p), + ClientboundStatusPacket::ClientboundPongResponsePacket(_) => { + // we should never get this packet since we didn't send a ping + } + } } } diff --git a/azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs new file mode 100644 index 00000000..e5e89561 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs @@ -0,0 +1,12 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundAddExperienceOrbPacket { + #[var] + pub id: u32, + pub x: f64, + pub y: f64, + pub z: f64, + pub value: u16, +} diff --git a/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs b/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs new file mode 100644 index 00000000..fbfba57e --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs @@ -0,0 +1,18 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; +use std::collections::HashMap; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundAwardStatsPacket { + #[var] + pub stats: HashMap, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, McBuf)] +pub struct Stat { + // TODO: make these good enums and stuff + #[var] + pub stat_type: u32, + #[var] + pub statistic_id: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs new file mode 100644 index 00000000..15d16a9d --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs @@ -0,0 +1,13 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundBlockDestructionPacket { + /// The ID of the entity breaking the block. + #[var] + pub id: u32, + pub pos: BlockPos, + /// 0–9 to set it, any other value to remove it. + pub progress: u8, +} diff --git a/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs new file mode 100644 index 00000000..e0991e89 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs @@ -0,0 +1,12 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundBlockEntityDataPacket { + pub pos: BlockPos, + // TODO: in vanilla this uses the block entity registry, we should have an enum in azalea-entity for this + #[var] + pub block_entity_type: u32, + pub tag: azalea_nbt::Tag, +} diff --git a/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs new file mode 100644 index 00000000..7175da7a --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs @@ -0,0 +1,13 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundBlockEventPacket { + pub pos: BlockPos, + pub b0: u8, + pub b1: u8, + // TODO: this is a BlockState, see ClientboundBlockUpdatePacket for more info + #[var] + pub block: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs index f3082dc8..dedcc5db 100644 --- a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs @@ -6,8 +6,7 @@ use packet_macros::ClientboundGamePacket; pub struct ClientboundBlockUpdatePacket { pub pos: BlockPos, // TODO: in vanilla this is a BlockState, but here we just have it as a number. - // however, we can't add azalea-world as a dependency because it depends on us. - // we could have a crate that contains encoding/decoding and the definitions? + // perhaps we could make a crate that only handles block states? right now blockstates are handled in azalea-block #[var] pub block_state: u32, } diff --git a/azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs new file mode 100644 index 00000000..396513b7 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs @@ -0,0 +1,143 @@ +use std::io::{Read, Write}; + +use azalea_buf::{ + BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable, +}; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; +use uuid::Uuid; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundBossEventPacket { + pub id: Uuid, + pub operation: Operation, +} + +#[derive(Clone, Debug)] +pub enum Operation { + Add(AddOperation), + Remove, + UpdateProgress(f32), + UpdateName(Component), + UpdateStyle(Style), + UpdateProperties(Properties), +} + +impl McBufReadable for Operation { + fn read_from(buf: &mut impl Read) -> Result { + let operation_id = u32::var_read_from(buf)?; + Ok(match operation_id { + 0 => Operation::Add(AddOperation::read_from(buf)?), + 1 => Operation::Remove, + 2 => Operation::UpdateProgress(f32::read_from(buf)?), + 3 => Operation::UpdateName(Component::read_from(buf)?), + 4 => Operation::UpdateStyle(Style::read_from(buf)?), + 5 => Operation::UpdateProperties(Properties::read_from(buf)?), + _ => { + return Err(BufReadError::UnexpectedEnumVariant { + id: operation_id as i32, + }) + } + }) + } +} + +impl McBufWritable for Operation { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + match self { + Operation::Add(add) => { + 0u32.var_write_into(buf)?; + add.write_into(buf)?; + } + Operation::Remove => { + 1u32.var_write_into(buf)?; + } + Operation::UpdateProgress(progress) => { + 2u32.var_write_into(buf)?; + progress.write_into(buf)?; + } + Operation::UpdateName(name) => { + 3u32.var_write_into(buf)?; + name.write_into(buf)?; + } + Operation::UpdateStyle(style) => { + 4u32.var_write_into(buf)?; + style.write_into(buf)?; + } + Operation::UpdateProperties(properties) => { + 5u32.var_write_into(buf)?; + properties.write_into(buf)?; + } + } + Ok(()) + } +} + +#[derive(Clone, Debug, McBuf)] +pub struct AddOperation { + name: Component, + progress: f32, + style: Style, + properties: Properties, +} + +#[derive(Clone, Debug, McBuf)] +pub struct Style { + color: BossBarColor, + overlay: BossBarOverlay, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum BossBarColor { + Pink = 0, + Blue = 1, + Red = 2, + Green = 3, + Yellow = 4, + Purple = 5, + White = 6, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum BossBarOverlay { + Progress = 0, + Notched6 = 1, + Notched10 = 2, + Notched12 = 3, + Notched20 = 4, +} + +#[derive(Clone, Debug)] +pub struct Properties { + pub darken_screen: bool, + pub play_music: bool, + pub create_world_fog: bool, +} + +impl McBufReadable for Properties { + fn read_from(buf: &mut impl Read) -> Result { + let byte = u8::read_from(buf)?; + Ok(Self { + darken_screen: byte & 1 != 0, + play_music: byte & 2 != 0, + create_world_fog: byte & 4 != 0, + }) + } +} + +impl McBufWritable for Properties { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + let mut byte = 0; + if self.darken_screen { + byte |= 1; + } + if self.play_music { + byte |= 2; + } + if self.create_world_fog { + byte |= 4; + } + u8::write_into(&byte, buf)?; + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs b/azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs new file mode 100644 index 00000000..fc5cfc23 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs @@ -0,0 +1,32 @@ +// use azalea_brigadier::context::StringRange; +use azalea_buf::{ + // BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable, + BufReadError, + McBufReadable, + McBufWritable, +}; +use packet_macros::ClientboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, ClientboundGamePacket)] +pub struct ClientboundCommandSuggestionsPacket { + #[var] + pub id: u32, + // pub suggestions: Suggestions, +} + +impl McBufReadable for ClientboundCommandSuggestionsPacket { + fn read_from(_buf: &mut impl Read) -> Result { + // let id = u32::var_read_from(buf)?; + // let start = u32::var_read_from(buf)? as usize; + // let length = u32::var_read_from(buf)? as usize; + // let stringrange = StringRange::between(start, start + length); + todo!("Suggestions aren't implemented in azalea-brigadier yet") + } +} + +impl McBufWritable for ClientboundCommandSuggestionsPacket { + fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> { + todo!() + } +} diff --git a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs b/azalea-protocol/src/packets/game/clientbound_commands_packet.rs old mode 100755 new mode 100644 similarity index 99% rename from azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs rename to azalea-protocol/src/packets/game/clientbound_commands_packet.rs index 622b9ec7..f3ae4ab9 --- a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_commands_packet.rs @@ -10,7 +10,7 @@ use std::{ }; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] -pub struct ClientboundDeclareCommandsPacket { +pub struct ClientboundCommandsPacket { pub entries: Vec, #[var] pub root_index: i32, diff --git a/azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs new file mode 100644 index 00000000..de4941ca --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundContainerSetDataPacket { + pub container_id: u8, + pub id: u16, + pub value: u16, +} diff --git a/azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs b/azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs new file mode 100644 index 00000000..f74470e7 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs @@ -0,0 +1,12 @@ +use azalea_buf::McBuf; +use azalea_core::Slot; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundContainerSetSlotPacket { + pub container_id: u8, + #[var] + pub state_id: u32, + pub slot: u16, + pub item_stack: Slot, +} diff --git a/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs b/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs new file mode 100644 index 00000000..b13cdde3 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundCooldownPacket { + // TODO: make azalea-items or something and use that + #[var] + pub item: u32, + #[var] + pub duration: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs b/azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs index 1f6d49dd..b257c8f8 100644 --- a/azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs @@ -7,7 +7,7 @@ pub struct ClientboundCustomChatCompletionsPacket { pub entries: Vec, } -#[derive(Clone, Debug, McBuf, Copy)] +#[derive(McBuf, Clone, Copy, Debug)] pub enum Action { Add = 0, Remove = 1, diff --git a/azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs b/azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs new file mode 100644 index 00000000..2d6286a3 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs @@ -0,0 +1,20 @@ +use azalea_buf::McBuf; +use azalea_core::ResourceLocation; +use packet_macros::ClientboundGamePacket; + +use super::clientbound_sound_packet::SoundSource; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundCustomSoundPacket { + pub name: ResourceLocation, + pub source: SoundSource, + /// x position multiplied by 8 + pub x: i32, + /// y position multiplied by 8 + pub y: i32, + /// z position multiplied by 8 + pub z: i32, + pub volume: f32, + pub pitch: f32, + pub seed: u64, +} diff --git a/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs index a5ff2c52..93bed1d4 100644 --- a/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs @@ -1,7 +1,6 @@ use azalea_buf::McBuf; use packet_macros::ClientboundGamePacket; -// we can't identify the status in azalea-protocol since they vary depending on the entity #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundEntityEventPacket { pub entity_id: u32, diff --git a/azalea-protocol/src/packets/game/clientbound_explode_packet.rs b/azalea-protocol/src/packets/game/clientbound_explode_packet.rs new file mode 100644 index 00000000..25731bcf --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_explode_packet.rs @@ -0,0 +1,118 @@ +use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable}; +use azalea_core::BlockPos; +use packet_macros::ClientboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, PartialEq, ClientboundGamePacket)] +pub struct ClientboundExplodePacket { + pub x: f32, + pub y: f32, + pub z: f32, + pub power: f32, + pub to_blow: Vec, + pub knockback_x: f32, + pub knockback_y: f32, + pub knockback_z: f32, +} + +impl McBufReadable for ClientboundExplodePacket { + fn read_from(buf: &mut impl Read) -> Result { + let x = f32::read_from(buf)?; + let y = f32::read_from(buf)?; + let z = f32::read_from(buf)?; + let power = f32::read_from(buf)?; + + let x_floor = x.floor() as i32; + let y_floor = y.floor() as i32; + let z_floor = z.floor() as i32; + + let to_blow_len = u32::var_read_from(buf)?; + let mut to_blow = Vec::with_capacity(to_blow_len as usize); + for _ in 0..to_blow_len { + // the bytes are offsets from the main x y z + let x = x_floor + i8::read_from(buf)? as i32; + let y = y_floor + i8::read_from(buf)? as i32; + let z = z_floor + i8::read_from(buf)? as i32; + to_blow.push(BlockPos { x, y, z }); + } + + let knockback_x = f32::read_from(buf)?; + let knockback_y = f32::read_from(buf)?; + let knockback_z = f32::read_from(buf)?; + + Ok(Self { + x, + y, + z, + power, + to_blow, + knockback_x, + knockback_y, + knockback_z, + }) + } +} + +impl McBufWritable for ClientboundExplodePacket { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + self.x.write_into(buf)?; + self.y.write_into(buf)?; + self.z.write_into(buf)?; + self.power.write_into(buf)?; + + let to_blow_len = self.to_blow.len() as u32; + to_blow_len.var_write_into(buf)?; + + let x_floor = self.x.floor() as i32; + let y_floor = self.y.floor() as i32; + let z_floor = self.z.floor() as i32; + + for pos in &self.to_blow { + let x = (pos.x - x_floor) as i8; + let y = (pos.y - y_floor) as i8; + let z = (pos.z - z_floor) as i8; + x.write_into(buf)?; + y.write_into(buf)?; + z.write_into(buf)?; + } + + self.knockback_x.write_into(buf)?; + self.knockback_y.write_into(buf)?; + self.knockback_z.write_into(buf)?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_read_write() { + let packet = ClientboundExplodePacket { + x: 123_456.0, + y: 789_012.0, + z: 345_678.0, + power: 1_000.0, + to_blow: vec![ + BlockPos { + x: 123_456 + 1, + y: 789_012 + 2, + z: 345_678 - 127, + }, + BlockPos { + x: 123_456 + 4, + y: 789_012 - 5, + z: 345_678 + 6, + }, + ], + knockback_x: 1_000.0, + knockback_y: 2_000.0, + knockback_z: 3_000.0, + }; + let mut buf = Vec::new(); + packet.write_into(&mut buf).unwrap(); + let packet2 = ClientboundExplodePacket::read_from(&mut buf.as_slice()).unwrap(); + assert_eq!(packet, packet2); + } +} diff --git a/azalea-protocol/src/packets/game/clientbound_forget_level_chunk_packet.rs b/azalea-protocol/src/packets/game/clientbound_forget_level_chunk_packet.rs new file mode 100644 index 00000000..c8bf6042 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_forget_level_chunk_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundForgetLevelChunkPacket { + pub x: i32, + pub z: i32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_horse_screen_open_packet.rs b/azalea-protocol/src/packets/game/clientbound_horse_screen_open_packet.rs new file mode 100644 index 00000000..f5b8c463 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_horse_screen_open_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundHorseScreenOpenPacket { + pub container_id: u8, + #[var] + pub size: u32, + pub entity_id: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs index b31cccf0..23e98c6b 100644 --- a/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs @@ -4,8 +4,8 @@ use packet_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundLevelEventPacket { - pub type_: i32, + pub event_type: u32, pub pos: BlockPos, - pub data: i32, + pub data: u32, pub global_event: bool, } diff --git a/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs index 8c731863..038e6202 100644 --- a/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs @@ -3,7 +3,9 @@ use packet_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundLightUpdatePacket { + #[var] pub x: i32, + #[var] pub z: i32, pub light_data: ClientboundLightUpdatePacketData, } diff --git a/azalea-protocol/src/packets/game/clientbound_login_packet.rs b/azalea-protocol/src/packets/game/clientbound_login_packet.rs index df53f678..2c895b88 100755 --- a/azalea-protocol/src/packets/game/clientbound_login_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_login_packet.rs @@ -16,9 +16,9 @@ pub struct ClientboundLoginPacket { #[var] pub max_players: i32, #[var] - pub chunk_radius: i32, + pub chunk_radius: u32, #[var] - pub simulation_distance: i32, + pub simulation_distance: u32, pub reduced_debug_info: bool, pub show_death_screen: bool, pub is_debug: bool, diff --git a/azalea-protocol/src/packets/game/clientbound_map_item_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_map_item_data_packet.rs new file mode 100644 index 00000000..e79e056e --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_map_item_data_packet.rs @@ -0,0 +1,119 @@ +use std::io::{Read, Write}; + +use azalea_buf::{BufReadError, McBuf}; +use azalea_buf::{McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable}; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, ClientboundGamePacket)] +pub struct ClientboundMapItemDataPacket { + // #[var] + pub map_id: u32, + pub scale: u8, + pub locked: bool, + pub decorations: Vec, + pub color_patch: Option, +} + +impl McBufReadable for ClientboundMapItemDataPacket { + fn read_from(buf: &mut impl Read) -> Result { + let map_id = u32::var_read_from(buf)?; + let scale = u8::read_from(buf)?; + let locked = bool::read_from(buf)?; + let decorations = Vec::::read_from(buf)?; + + let width = u8::read_from(buf)?; + let color_patch = if width == 0 { + None + } else { + let height = u8::read_from(buf)?; + let start_x = u8::read_from(buf)?; + let start_y = u8::read_from(buf)?; + let map_colors = Vec::::read_from(buf)?; + Some(MapPatch { + width, + height, + start_x, + start_y, + map_colors, + }) + }; + + Ok(Self { + map_id, + scale, + locked, + decorations, + color_patch, + }) + } +} + +impl McBufWritable for ClientboundMapItemDataPacket { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + self.map_id.var_write_into(buf)?; + self.scale.write_into(buf)?; + self.locked.write_into(buf)?; + self.decorations.write_into(buf)?; + if let Some(color_patch) = &self.color_patch { + color_patch.width.write_into(buf)?; + color_patch.height.write_into(buf)?; + color_patch.start_x.write_into(buf)?; + color_patch.start_y.write_into(buf)?; + color_patch.map_colors.write_into(buf)?; + } else { + 0u8.write_into(buf)?; + } + Ok(()) + } +} + +#[derive(Clone, Debug, McBuf)] +pub struct MapDecoration { + pub decoration_type: DecorationType, + pub x: i8, + pub y: i8, + /// Minecraft does & 15 on this value, azalea-protocol doesn't. I don't think it matters. + pub rot: i8, + pub name: Option, +} + +#[derive(Debug, Clone)] +pub struct MapPatch { + pub start_x: u8, + pub start_y: u8, + pub width: u8, + pub height: u8, + pub map_colors: Vec, +} + +#[derive(Clone, Copy, Debug, McBuf)] +pub enum DecorationType { + Player, + Frame, + RedMarker, + BlueMarker, + TargetX, + TargetPoint, + PlayerOffMap, + PlayerOffLimits, + Mansion, + Monument, + BannerWhite, + BannerOrange, + BannerMagenta, + BannerLightBlue, + BannerYellow, + BannerLime, + BannerPink, + BannerGray, + BannerLightGray, + BannerCyan, + BannerPurple, + BannerBlue, + BannerBrown, + BannerGreen, + BannerRed, + BannerBlack, + RedX, +} diff --git a/azalea-protocol/src/packets/game/clientbound_merchant_offers_packet.rs b/azalea-protocol/src/packets/game/clientbound_merchant_offers_packet.rs new file mode 100644 index 00000000..0c35f81d --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_merchant_offers_packet.rs @@ -0,0 +1,30 @@ +use azalea_buf::McBuf; +use azalea_core::Slot; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundMerchantOffersPacket { + #[var] + pub container_id: u32, + pub offers: Vec, + #[var] + pub villager_level: u32, + #[var] + pub villager_xp: u32, + pub show_progress: bool, + pub can_restock: bool, +} + +#[derive(Clone, Debug, McBuf)] +pub struct MerchantOffer { + pub base_cost_a: Slot, + pub result: Slot, + pub cost_b: Slot, + pub out_of_stock: bool, + pub uses: u32, + pub max_uses: u32, + pub xp: u32, + pub special_price_diff: i32, + pub price_multiplier: f32, + pub demand: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs b/azalea-protocol/src/packets/game/clientbound_move_entity_pos_rot_packet.rs similarity index 88% rename from azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs rename to azalea-protocol/src/packets/game/clientbound_move_entity_pos_rot_packet.rs index 47086337..3f7da4b0 100644 --- a/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_move_entity_pos_rot_packet.rs @@ -4,7 +4,7 @@ use packet_macros::ClientboundGamePacket; /// This packet is sent by the server when an entity moves less then 8 blocks. #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] -pub struct ClientboundMoveEntityPosrotPacket { +pub struct ClientboundMoveEntityPosRotPacket { #[var] pub entity_id: u32, pub delta: PositionDelta8, diff --git a/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs b/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs index c68e37c6..08124e53 100644 --- a/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs @@ -4,7 +4,7 @@ use packet_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundMoveEntityRotPacket { #[var] - pub entity_id: i32, + pub entity_id: u32, pub y_rot: i8, pub x_rot: i8, pub on_ground: bool, diff --git a/azalea-protocol/src/packets/game/clientbound_move_vehicle_packet.rs b/azalea-protocol/src/packets/game/clientbound_move_vehicle_packet.rs new file mode 100644 index 00000000..93b65e19 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_move_vehicle_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundMoveVehiclePacket { + pub x: f64, + pub y: f64, + pub z: f64, + pub y_rot: f32, + pub x_rot: f32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_open_book_packet.rs b/azalea-protocol/src/packets/game/clientbound_open_book_packet.rs new file mode 100644 index 00000000..98d512d1 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_open_book_packet.rs @@ -0,0 +1,8 @@ +use super::serverbound_interact_packet::InteractionHand; +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundOpenBookPacket { + pub hand: InteractionHand, +} diff --git a/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs b/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs new file mode 100644 index 00000000..43ab7716 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs @@ -0,0 +1,13 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundOpenScreenPacket { + #[var] + pub container_id: u32, + // TODO: have an enum of this + #[var] + pub menu_type: u32, + pub title: Component, +} diff --git a/azalea-protocol/src/packets/game/clientbound_open_sign_editor_packet.rs b/azalea-protocol/src/packets/game/clientbound_open_sign_editor_packet.rs new file mode 100644 index 00000000..477b8f6b --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_open_sign_editor_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundOpenSignEditorPacket { + pub pos: BlockPos, +} diff --git a/azalea-protocol/src/packets/game/clientbound_ping_packet.rs b/azalea-protocol/src/packets/game/clientbound_ping_packet.rs new file mode 100644 index 00000000..01e32a11 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_ping_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundPingPacket { + pub id: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_place_ghost_recipe_packet.rs b/azalea-protocol/src/packets/game/clientbound_place_ghost_recipe_packet.rs new file mode 100644 index 00000000..accaeb8c --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_place_ghost_recipe_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use azalea_core::ResourceLocation; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundPlaceGhostRecipePacket { + pub container_id: u8, + pub recipe: ResourceLocation, +} diff --git a/azalea-protocol/src/packets/game/clientbound_player_combat_end_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_combat_end_packet.rs new file mode 100644 index 00000000..3839716c --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_player_combat_end_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundPlayerCombatEndPacket { + #[var] + pub duration: u32, + pub killer_id: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_player_combat_enter_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_combat_enter_packet.rs new file mode 100644 index 00000000..80269e78 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_player_combat_enter_packet.rs @@ -0,0 +1,5 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundPlayerCombatEnterPacket {} diff --git a/azalea-protocol/src/packets/game/clientbound_player_combat_kill_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_combat_kill_packet.rs new file mode 100644 index 00000000..eae2a711 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_player_combat_kill_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundPlayerCombatKillPacket { + #[var] + pub player_id: u32, + pub killer_id: u32, + pub message: Component, +} diff --git a/azalea-protocol/src/packets/game/clientbound_player_look_at_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_look_at_packet.rs new file mode 100644 index 00000000..59567da6 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_player_look_at_packet.rs @@ -0,0 +1,24 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundPlayerLookAtPacket { + pub from_anchor: Anchor, + pub x: f64, + pub y: f64, + pub z: f64, + pub entity: Option, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Anchor { + Feet = 0, + Eyes = 1, +} + +#[derive(McBuf, Clone, Debug)] +pub struct AtEntity { + #[var] + pub entity: u32, + pub to_anchor: Anchor, +} diff --git a/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs b/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs new file mode 100644 index 00000000..98224bff --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundRemoveMobEffectPacket { + #[var] + pub entity_id: u32, + // TODO: have this use an enum + #[var] + pub effect: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_resource_pack_packet.rs b/azalea-protocol/src/packets/game/clientbound_resource_pack_packet.rs new file mode 100644 index 00000000..4d82e187 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_resource_pack_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundResourcePackPacket { + pub url: String, + pub hash: String, + pub required: bool, + pub prompt: Option, +} diff --git a/azalea-protocol/src/packets/game/clientbound_respawn_packet.rs b/azalea-protocol/src/packets/game/clientbound_respawn_packet.rs new file mode 100644 index 00000000..d5da4392 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_respawn_packet.rs @@ -0,0 +1,16 @@ +use azalea_buf::McBuf; +use azalea_core::{GameType, GlobalPos, OptionalGameType, ResourceLocation}; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundRespawnPacket { + pub dimension_type: ResourceLocation, + pub dimension: ResourceLocation, + pub seed: u64, + pub player_game_type: GameType, + pub previous_player_game_type: OptionalGameType, + pub is_debug: bool, + pub is_flat: bool, + pub keep_all_player_data: bool, + pub last_death_location: Option, +} diff --git a/azalea-protocol/src/packets/game/clientbound_select_advancements_tab_packet.rs b/azalea-protocol/src/packets/game/clientbound_select_advancements_tab_packet.rs new file mode 100644 index 00000000..7eddbf95 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_select_advancements_tab_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_core::ResourceLocation; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSelectAdvancementsTabPacket { + pub tab: Option, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_action_bar_text_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_action_bar_text_packet.rs new file mode 100644 index 00000000..f5e6915f --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_action_bar_text_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetActionBarTextPacket { + pub text: Component, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_border_center_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_border_center_packet.rs new file mode 100644 index 00000000..2b01ea9f --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_border_center_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetBorderCenterPacket { + pub new_center_x: f64, + pub new_center_z: f64, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_border_lerp_size_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_border_lerp_size_packet.rs new file mode 100644 index 00000000..b0a415c1 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_border_lerp_size_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetBorderLerpSizePacket { + pub old_size: f64, + pub new_size: f64, + #[var] + pub lerp_time: u64, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_border_size_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_border_size_packet.rs new file mode 100644 index 00000000..87b66622 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_border_size_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetBorderSizePacket { + pub size: f64, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_border_warning_delay_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_border_warning_delay_packet.rs new file mode 100644 index 00000000..46f5be8c --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_border_warning_delay_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetBorderWarningDelayPacket { + #[var] + pub warning_delay: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_border_warning_distance_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_border_warning_distance_packet.rs new file mode 100644 index 00000000..70069bf9 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_border_warning_distance_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetBorderWarningDistancePacket { + #[var] + pub warning_blocks: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_camera_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_camera_packet.rs new file mode 100644 index 00000000..45e62c4b --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_camera_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetCameraPacket { + #[var] + pub camera_id: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_radius_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_radius_packet.rs new file mode 100644 index 00000000..df545ace --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_radius_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetChunkCacheRadiusPacket { + #[var] + pub radius: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_display_objective_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_display_objective_packet.rs new file mode 100644 index 00000000..7dabff72 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_display_objective_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetDisplayObjectivePacket { + pub slot: u8, + pub objective_name: String, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs index 5edc2acc..7468fc91 100644 --- a/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs @@ -6,5 +6,5 @@ use packet_macros::ClientboundGamePacket; pub struct ClientboundSetEntityDataPacket { #[var] pub id: u32, - pub metadata: EntityMetadata, + pub packed_items: EntityMetadata, } diff --git a/azalea-protocol/src/packets/game/clientbound_set_entity_motion_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_entity_motion_packet.rs new file mode 100644 index 00000000..50301982 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_entity_motion_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetEntityMotionPacket { + #[var] + pub id: u32, + pub xa: i16, + pub ya: i16, + pub za: i16, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_objective_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_objective_packet.rs new file mode 100644 index 00000000..4165e03c --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_objective_packet.rs @@ -0,0 +1,59 @@ +use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetObjectivePacket { + pub objective_name: String, + pub method: Method, +} + +#[derive(Clone, Debug)] +pub enum Method { + Add(DisplayInfo), + Remove, + Change(DisplayInfo), +} + +impl McBufReadable for Method { + fn read_from(buf: &mut impl Read) -> Result { + Ok(match u8::read_from(buf)? { + 0 => Method::Add(DisplayInfo::read_from(buf)?), + 1 => Method::Remove, + 2 => Method::Change(DisplayInfo::read_from(buf)?), + id => return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 }), + }) + } +} + +impl McBufWritable for Method { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + match self { + Method::Add(info) => { + 0u8.write_into(buf)?; + info.write_into(buf)?; + } + Method::Remove => { + 1u8.write_into(buf)?; + } + Method::Change(info) => { + 2u8.write_into(buf)?; + info.write_into(buf)?; + } + } + Ok(()) + } +} + +#[derive(McBuf, Clone, Debug)] +pub struct DisplayInfo { + pub display_name: Component, + pub render_type: RenderType, +} + +#[derive(McBuf, Copy, Clone, Debug)] +pub enum RenderType { + Integer, + Hearts, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_passengers_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_passengers_packet.rs new file mode 100644 index 00000000..39d8e3be --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_passengers_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetPassengersPacket { + #[var] + pub vehicle: u32, + #[var] + pub passengers: Vec, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_player_team_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_player_team_packet.rs new file mode 100644 index 00000000..7db043ff --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_player_team_packet.rs @@ -0,0 +1,80 @@ +use std::io::{Read, Write}; + +use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; +use azalea_chat::{component::Component, style::ChatFormatting}; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetPlayerTeamPacket { + pub name: String, + pub method: Method, +} + +#[derive(Clone, Debug)] +pub enum Method { + Add((Parameters, PlayerList)), + Remove, + Change(Parameters), + Join(PlayerList), + Leave(PlayerList), +} + +impl McBufReadable for Method { + fn read_from(buf: &mut impl Read) -> Result { + Ok(match u8::read_from(buf)? { + 0 => Method::Add((Parameters::read_from(buf)?, PlayerList::read_from(buf)?)), + 1 => Method::Remove, + 2 => Method::Change(Parameters::read_from(buf)?), + 3 => Method::Join(PlayerList::read_from(buf)?), + 4 => Method::Leave(PlayerList::read_from(buf)?), + id => return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 }), + }) + } +} + +impl McBufWritable for Method { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + match self { + Method::Add((parameters, playerlist)) => { + 0u8.write_into(buf)?; + parameters.write_into(buf)?; + playerlist.write_into(buf)?; + } + Method::Remove => { + 1u8.write_into(buf)?; + } + Method::Change(parameters) => { + 2u8.write_into(buf)?; + parameters.write_into(buf)?; + } + Method::Join(playerlist) => { + 3u8.write_into(buf)?; + playerlist.write_into(buf)?; + } + Method::Leave(playerlist) => { + 4u8.write_into(buf)?; + playerlist.write_into(buf)?; + } + } + Ok(()) + } +} + +#[derive(McBuf, Clone, Debug)] +pub struct Parameters { + pub display_name: Component, + pub options: u8, + pub nametag_visibility: String, + pub collision_rule: String, + pub color: ChatFormatting, + pub player_prefix: Component, + pub player_suffix: Component, +} + +#[derive(McBuf, Copy, Clone, Debug)] +pub enum RenderType { + Integer, + Hearts, +} + +type PlayerList = Vec; diff --git a/azalea-protocol/src/packets/game/clientbound_set_score_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_score_packet.rs new file mode 100644 index 00000000..d1482828 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_score_packet.rs @@ -0,0 +1,61 @@ +use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable}; +use packet_macros::ClientboundGamePacket; +use std::{ + io::{Read, Write}, + ops::Not, +}; + +#[derive(Clone, Debug, ClientboundGamePacket)] +pub struct ClientboundSetScorePacket { + pub owner: String, + pub method: Method, + pub objective_name: Option, +} + +impl McBufReadable for ClientboundSetScorePacket { + fn read_from(buf: &mut impl Read) -> Result { + let owner = String::read_from(buf)?; + let method_id = u32::var_read_from(buf)?; + let objective_name = String::read_from(buf)?; + let objective_name = objective_name.is_empty().not().then_some(objective_name); + // if it's change, read the score + let method = match method_id { + 0 => Method::Change { + score: u32::var_read_from(buf)?, + }, + 1 => Method::Remove, + id => return Err(BufReadError::UnexpectedEnumVariant { id: id as i32 }), + }; + Ok(ClientboundSetScorePacket { + owner, + method, + objective_name, + }) + } +} + +impl McBufWritable for ClientboundSetScorePacket { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + self.owner.write_into(buf)?; + match self.method { + Method::Change { .. } => 0u32, + Method::Remove => 1u32, + } + .var_write_into(buf)?; + // convert None to an empty string + self.objective_name + .as_ref() + .unwrap_or(&"".to_string()) + .write_into(buf)?; + if let Method::Change { score } = self.method { + score.var_write_into(buf)?; + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug)] +pub enum Method { + Change { score: u32 }, + Remove, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_simulation_distance_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_simulation_distance_packet.rs new file mode 100644 index 00000000..9a938e86 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_simulation_distance_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetSimulationDistancePacket { + #[var] + pub simulation_distance: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_subtitle_text_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_subtitle_text_packet.rs new file mode 100644 index 00000000..1312b78f --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_subtitle_text_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetSubtitleTextPacket { + pub text: Component, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_title_text_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_title_text_packet.rs new file mode 100644 index 00000000..28d06a55 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_title_text_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetTitleTextPacket { + pub text: Component, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_titles_animation_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_titles_animation_packet.rs new file mode 100644 index 00000000..a4e4f353 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_titles_animation_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSetTitlesAnimationPacket { + pub fade_in: u32, + pub stay: u32, + pub fade_out: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs new file mode 100644 index 00000000..40648311 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs @@ -0,0 +1,16 @@ +use super::clientbound_sound_packet::SoundSource; +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundSoundEntityPacket { + // TODO: sound enum/registry + #[var] + pub sound: u32, + pub source: SoundSource, + #[var] + pub id: u32, + pub volume: f32, + pub pitch: f32, + pub seed: u64, +} diff --git a/azalea-protocol/src/packets/game/clientbound_sound_packet.rs b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs index a4d1d713..99d70482 100644 --- a/azalea-protocol/src/packets/game/clientbound_sound_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs @@ -3,8 +3,8 @@ use packet_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundSoundPacket { + // TODO: sound enum/registry #[var] - // TODO: use the sound registry instead of just being a u32 pub sound: u32, pub source: SoundSource, pub x: i32, @@ -12,11 +12,10 @@ pub struct ClientboundSoundPacket { pub z: i32, pub volume: f32, pub pitch: f32, - /// Seed used to pick sound varient. pub seed: u64, } -#[derive(Clone, Debug, Copy, McBuf)] +#[derive(McBuf, Clone, Copy, Debug)] pub enum SoundSource { Master = 0, Music = 1, diff --git a/azalea-protocol/src/packets/game/clientbound_stop_sound_packet.rs b/azalea-protocol/src/packets/game/clientbound_stop_sound_packet.rs new file mode 100644 index 00000000..cdf7cd47 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_stop_sound_packet.rs @@ -0,0 +1,51 @@ +use std::io::{Read, Write}; + +use azalea_buf::{BufReadError, McBufReadable, McBufWritable}; +use azalea_core::ResourceLocation; +use packet_macros::ClientboundGamePacket; + +use super::clientbound_sound_packet::SoundSource; + +#[derive(Clone, Debug, ClientboundGamePacket)] +pub struct ClientboundStopSoundPacket { + pub source: Option, + pub name: Option, +} + +impl McBufReadable for ClientboundStopSoundPacket { + fn read_from(buf: &mut impl Read) -> Result { + let byte = u8::read_from(buf)?; + let source = if byte & 1 != 0 { + Some(SoundSource::read_from(buf)?) + } else { + None + }; + let name = if byte & 2 != 0 { + Some(ResourceLocation::read_from(buf)?) + } else { + None + }; + + Ok(Self { source, name }) + } +} + +impl McBufWritable for ClientboundStopSoundPacket { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + let mut byte = 0u8; + if self.source.is_some() { + byte |= 1; + } + if self.name.is_some() { + byte |= 2; + } + byte.write_into(buf)?; + if let Some(source) = &self.source { + source.write_into(buf)?; + } + if let Some(name) = &self.name { + name.write_into(buf)?; + } + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/clientbound_tab_list_packet.rs b/azalea-protocol/src/packets/game/clientbound_tab_list_packet.rs new file mode 100644 index 00000000..b12cb124 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_tab_list_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use azalea_chat::component::Component; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundTabListPacket { + pub header: Component, + pub footer: Component, +} diff --git a/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs b/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs new file mode 100644 index 00000000..62da50e2 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundTagQueryPacket { + #[var] + pub transaction_id: u32, + pub tag: azalea_nbt::Tag, +} diff --git a/azalea-protocol/src/packets/game/clientbound_take_item_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_take_item_entity_packet.rs new file mode 100644 index 00000000..f1e1ef33 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_take_item_entity_packet.rs @@ -0,0 +1,12 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundGamePacket; + +#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] +pub struct ClientboundTakeItemEntityPacket { + #[var] + pub item_id: u32, + #[var] + pub player_id: u32, + #[var] + pub amount: u32, +} diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs index 0b5c4d3e..194c7680 100755 --- a/azalea-protocol/src/packets/game/mod.rs +++ b/azalea-protocol/src/packets/game/mod.rs @@ -1,19 +1,33 @@ pub mod clientbound_add_entity_packet; +pub mod clientbound_add_experience_orb_packet; pub mod clientbound_add_player_packet; pub mod clientbound_animate_packet; +pub mod clientbound_award_stats_packet; pub mod clientbound_block_changed_ack_packet; +pub mod clientbound_block_destruction_packet; +pub mod clientbound_block_entity_data_packet; +pub mod clientbound_block_event_packet; pub mod clientbound_block_update_packet; +pub mod clientbound_boss_event_packet; pub mod clientbound_change_difficulty_packet; pub mod clientbound_chat_preview_packet; +pub mod clientbound_command_suggestions_packet; +pub mod clientbound_commands_packet; pub mod clientbound_container_set_content_packet; +pub mod clientbound_container_set_data_packet; +pub mod clientbound_container_set_slot_packet; +pub mod clientbound_cooldown_packet; pub mod clientbound_custom_chat_completions_packet; pub mod clientbound_custom_payload_packet; -pub mod clientbound_declare_commands_packet; +pub mod clientbound_custom_sound_packet; pub mod clientbound_delete_chat_packet; pub mod clientbound_disconnect_packet; pub mod clientbound_entity_event_packet; pub mod clientbound_entity_velocity_packet; +pub mod clientbound_explode_packet; +pub mod clientbound_forget_level_chunk_packet; pub mod clientbound_game_event_packet; +pub mod clientbound_horse_screen_open_packet; pub mod clientbound_initialize_border_packet; pub mod clientbound_keep_alive_packet; pub mod clientbound_level_chunk_with_light_packet; @@ -21,31 +35,70 @@ pub mod clientbound_level_event_packet; pub mod clientbound_level_particles_packet; pub mod clientbound_light_update_packet; pub mod clientbound_login_packet; +pub mod clientbound_map_item_data_packet; +pub mod clientbound_merchant_offers_packet; pub mod clientbound_move_entity_pos_packet; -pub mod clientbound_move_entity_posrot_packet; +pub mod clientbound_move_entity_pos_rot_packet; pub mod clientbound_move_entity_rot_packet; +pub mod clientbound_move_vehicle_packet; +pub mod clientbound_open_book_packet; +pub mod clientbound_open_screen_packet; +pub mod clientbound_open_sign_editor_packet; +pub mod clientbound_ping_packet; +pub mod clientbound_place_ghost_recipe_packet; pub mod clientbound_player_abilities_packet; pub mod clientbound_player_chat_header_packet; pub mod clientbound_player_chat_packet; +pub mod clientbound_player_combat_end_packet; +pub mod clientbound_player_combat_enter_packet; +pub mod clientbound_player_combat_kill_packet; pub mod clientbound_player_info_packet; +pub mod clientbound_player_look_at_packet; pub mod clientbound_player_position_packet; pub mod clientbound_recipe_packet; pub mod clientbound_remove_entities_packet; +pub mod clientbound_remove_mob_effect_packet; +pub mod clientbound_resource_pack_packet; +pub mod clientbound_respawn_packet; pub mod clientbound_rotate_head_packet; pub mod clientbound_section_blocks_update_packet; +pub mod clientbound_select_advancements_tab_packet; pub mod clientbound_server_data_packet; +pub mod clientbound_set_action_bar_text_packet; +pub mod clientbound_set_border_center_packet; +pub mod clientbound_set_border_lerp_size_packet; +pub mod clientbound_set_border_size_packet; +pub mod clientbound_set_border_warning_delay_packet; +pub mod clientbound_set_border_warning_distance_packet; +pub mod clientbound_set_camera_packet; pub mod clientbound_set_carried_item_packet; pub mod clientbound_set_chunk_cache_center_packet; +pub mod clientbound_set_chunk_cache_radius_packet; pub mod clientbound_set_default_spawn_position_packet; pub mod clientbound_set_display_chat_preview_packet; +pub mod clientbound_set_display_objective_packet; pub mod clientbound_set_entity_data_packet; pub mod clientbound_set_entity_link_packet; +pub mod clientbound_set_entity_motion_packet; pub mod clientbound_set_equipment_packet; pub mod clientbound_set_experience_packet; pub mod clientbound_set_health_packet; +pub mod clientbound_set_objective_packet; +pub mod clientbound_set_passengers_packet; +pub mod clientbound_set_player_team_packet; +pub mod clientbound_set_score_packet; +pub mod clientbound_set_simulation_distance_packet; +pub mod clientbound_set_subtitle_text_packet; pub mod clientbound_set_time_packet; +pub mod clientbound_set_title_text_packet; +pub mod clientbound_set_titles_animation_packet; +pub mod clientbound_sound_entity_packet; pub mod clientbound_sound_packet; +pub mod clientbound_stop_sound_packet; pub mod clientbound_system_chat_packet; +pub mod clientbound_tab_list_packet; +pub mod clientbound_tag_query_packet; +pub mod clientbound_take_item_entity_packet; pub mod clientbound_teleport_entity_packet; pub mod clientbound_update_advancements_packet; pub mod clientbound_update_attributes_packet; @@ -54,16 +107,56 @@ pub mod clientbound_update_recipes_packet; pub mod clientbound_update_tags_packet; pub mod clientbound_update_view_distance_packet; pub mod serverbound_accept_teleportation_packet; +pub mod serverbound_block_entity_tag_query; +pub mod serverbound_change_difficulty_packet; pub mod serverbound_chat_ack_packet; pub mod serverbound_chat_command_packet; pub mod serverbound_chat_packet; pub mod serverbound_chat_preview_packet; +pub mod serverbound_client_command_packet; +pub mod serverbound_client_information_packet; +pub mod serverbound_command_suggestion_packet; +pub mod serverbound_container_button_click_packet; +pub mod serverbound_container_click_packet; +pub mod serverbound_container_close_packet; pub mod serverbound_custom_payload_packet; +pub mod serverbound_edit_book_packet; +pub mod serverbound_entity_tag_query; +pub mod serverbound_interact_packet; +pub mod serverbound_jigsaw_generate_packet; pub mod serverbound_keep_alive_packet; -pub mod serverbound_move_player_packet_pos; -pub mod serverbound_move_player_packet_pos_rot; -pub mod serverbound_move_player_packet_rot; -pub mod serverbound_move_player_packet_status_only; +pub mod serverbound_lock_difficulty_packet; +pub mod serverbound_move_player_pos_packet; +pub mod serverbound_move_player_pos_rot_packet; +pub mod serverbound_move_player_rot_packet; +pub mod serverbound_move_player_status_only_packet; +pub mod serverbound_move_vehicle_packet; +pub mod serverbound_paddle_boat_packet; +pub mod serverbound_pick_item_packet; +pub mod serverbound_place_recipe_packet; +pub mod serverbound_player_abilities_packet; +pub mod serverbound_player_action_packet; +pub mod serverbound_player_command_packet; +pub mod serverbound_player_input_packet; +pub mod serverbound_pong_packet; +pub mod serverbound_recipe_book_change_settings_packet; +pub mod serverbound_recipe_book_seen_recipe_packet; +pub mod serverbound_rename_item_packet; +pub mod serverbound_resource_pack_packet; +pub mod serverbound_seen_advancements_packet; +pub mod serverbound_select_trade_packet; +pub mod serverbound_set_beacon_packet; +pub mod serverbound_set_carried_item_packet; +pub mod serverbound_set_command_block_packet; +pub mod serverbound_set_command_minecart_packet; +pub mod serverbound_set_creative_mode_slot_packet; +pub mod serverbound_set_jigsaw_block_packet; +pub mod serverbound_set_structure_block_packet; +pub mod serverbound_sign_update_packet; +pub mod serverbound_swing_packet; +pub mod serverbound_teleport_to_entity_packet; +pub mod serverbound_use_item_on_packet; +pub mod serverbound_use_item_packet; use packet_macros::declare_state_packets; @@ -71,33 +164,87 @@ declare_state_packets!( GamePacket, Serverbound => { 0x00: serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket, + 0x01: serverbound_block_entity_tag_query::ServerboundBlockEntityTagQuery, + 0x02: serverbound_change_difficulty_packet::ServerboundChangeDifficultyPacket, 0x03: serverbound_chat_ack_packet::ServerboundChatAckPacket, 0x04: serverbound_chat_command_packet::ServerboundChatCommandPacket, 0x05: serverbound_chat_packet::ServerboundChatPacket, 0x06: serverbound_chat_preview_packet::ServerboundChatPreviewPacket, + 0x07: serverbound_client_command_packet::ServerboundClientCommandPacket, + 0x08: serverbound_client_information_packet::ServerboundClientInformationPacket, + 0x09: serverbound_command_suggestion_packet::ServerboundCommandSuggestionPacket, + 0x0a: serverbound_container_button_click_packet::ServerboundContainerButtonClickPacket, + 0x0b: serverbound_container_click_packet::ServerboundContainerClickPacket, + 0x0c: serverbound_container_close_packet::ServerboundContainerClosePacket, 0x0d: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, + 0x0e: serverbound_edit_book_packet::ServerboundEditBookPacket, + 0x0f: serverbound_entity_tag_query::ServerboundEntityTagQuery, + 0x10: serverbound_interact_packet::ServerboundInteractPacket, + 0x11: serverbound_jigsaw_generate_packet::ServerboundJigsawGeneratePacket, 0x12: serverbound_keep_alive_packet::ServerboundKeepAlivePacket, - 0x14: serverbound_move_player_packet_pos::ServerboundMovePlayerPacketPos, - 0x15: serverbound_move_player_packet_pos_rot::ServerboundMovePlayerPacketPosRot, - 0x16: serverbound_move_player_packet_rot::ServerboundMovePlayerPacketRot, - 0x17: serverbound_move_player_packet_status_only::ServerboundMovePlayerPacketStatusOnly, + 0x13: serverbound_lock_difficulty_packet::ServerboundLockDifficultyPacket, + 0x14: serverbound_move_player_pos_packet::ServerboundMovePlayerPacketPos, + 0x15: serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPacketPosRot, + 0x16: serverbound_move_player_rot_packet::ServerboundMovePlayerPacketRot, + 0x17: serverbound_move_player_status_only_packet::ServerboundMovePlayerPacketStatusOnly, + 0x18: serverbound_move_vehicle_packet::ServerboundMoveVehiclePacket, + 0x19: serverbound_paddle_boat_packet::ServerboundPaddleBoatPacket, + 0x1a: serverbound_pick_item_packet::ServerboundPickItemPacket, + 0x1b: serverbound_place_recipe_packet::ServerboundPlaceRecipePacket, + 0x1c: serverbound_player_abilities_packet::ServerboundPlayerAbilitiesPacket, + 0x1d: serverbound_player_action_packet::ServerboundPlayerActionPacket, + 0x1e: serverbound_player_command_packet::ServerboundPlayerCommandPacket, + 0x1f: serverbound_player_input_packet::ServerboundPlayerInputPacket, + 0x20: serverbound_pong_packet::ServerboundPongPacket, + 0x21: serverbound_recipe_book_change_settings_packet::ServerboundRecipeBookChangeSettingsPacket, + 0x22: serverbound_recipe_book_seen_recipe_packet::ServerboundRecipeBookSeenRecipePacket, + 0x23: serverbound_rename_item_packet::ServerboundRenameItemPacket, + 0x24: serverbound_resource_pack_packet::ServerboundResourcePackPacket, + 0x25: serverbound_seen_advancements_packet::ServerboundSeenAdvancementsPacket, + 0x26: serverbound_select_trade_packet::ServerboundSelectTradePacket, + 0x27: serverbound_set_beacon_packet::ServerboundSetBeaconPacket, + 0x28: serverbound_set_carried_item_packet::ServerboundSetCarriedItemPacket, + 0x29: serverbound_set_command_block_packet::ServerboundSetCommandBlockPacket, + 0x2a: serverbound_set_command_minecart_packet::ServerboundSetCommandMinecartPacket, + 0x2b: serverbound_set_creative_mode_slot_packet::ServerboundSetCreativeModeSlotPacket, + 0x2c: serverbound_set_jigsaw_block_packet::ServerboundSetJigsawBlockPacket, + 0x2d: serverbound_set_structure_block_packet::ServerboundSetStructureBlockPacket, + 0x2e: serverbound_sign_update_packet::ServerboundSignUpdatePacket, + 0x2f: serverbound_swing_packet::ServerboundSwingPacket, + 0x30: serverbound_teleport_to_entity_packet::ServerboundTeleportToEntityPacket, + 0x31: serverbound_use_item_on_packet::ServerboundUseItemOnPacket, + 0x32: serverbound_use_item_packet::ServerboundUseItemPacket, }, Clientbound => { 0x00: clientbound_add_entity_packet::ClientboundAddEntityPacket, + 0x01: clientbound_add_experience_orb_packet::ClientboundAddExperienceOrbPacket, 0x02: clientbound_add_player_packet::ClientboundAddPlayerPacket, 0x03: clientbound_animate_packet::ClientboundAnimatePacket, + 0x04: clientbound_award_stats_packet::ClientboundAwardStatsPacket, 0x05: clientbound_block_changed_ack_packet::ClientboundBlockChangedAckPacket, + 0x06: clientbound_block_destruction_packet::ClientboundBlockDestructionPacket, + 0x07: clientbound_block_entity_data_packet::ClientboundBlockEntityDataPacket, + 0x08: clientbound_block_event_packet::ClientboundBlockEventPacket, 0x09: clientbound_block_update_packet::ClientboundBlockUpdatePacket, + 0x0a: clientbound_boss_event_packet::ClientboundBossEventPacket, 0x0b: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket, 0x0c: clientbound_chat_preview_packet::ClientboundChatPreviewPacket, - 0x0f: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket, + 0x0e: clientbound_command_suggestions_packet::ClientboundCommandSuggestionsPacket, + 0x0f: clientbound_commands_packet::ClientboundCommandsPacket, 0x11: clientbound_container_set_content_packet::ClientboundContainerSetContentPacket, + 0x12: clientbound_container_set_data_packet::ClientboundContainerSetDataPacket, + 0x13: clientbound_container_set_slot_packet::ClientboundContainerSetSlotPacket, + 0x14: clientbound_cooldown_packet::ClientboundCooldownPacket, 0x15: clientbound_custom_chat_completions_packet::ClientboundCustomChatCompletionsPacket, 0x16: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket, + 0x17: clientbound_custom_sound_packet::ClientboundCustomSoundPacket, 0x18: clientbound_delete_chat_packet::ClientboundDeleteChatPacket, 0x19: clientbound_disconnect_packet::ClientboundDisconnectPacket, 0x1a: clientbound_entity_event_packet::ClientboundEntityEventPacket, + 0x1b: clientbound_explode_packet::ClientboundExplodePacket, + 0x1c: clientbound_forget_level_chunk_packet::ClientboundForgetLevelChunkPacket, 0x1d: clientbound_game_event_packet::ClientboundGameEventPacket, + 0x1e: clientbound_horse_screen_open_packet::ClientboundHorseScreenOpenPacket, 0x1f: clientbound_initialize_border_packet::ClientboundInitializeBorderPacket, 0x20: clientbound_keep_alive_packet::ClientboundKeepAlivePacket, 0x21: clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket, @@ -105,33 +252,72 @@ declare_state_packets!( 0x23: clientbound_level_particles_packet::ClientboundLevelParticlesPacket, 0x24: clientbound_light_update_packet::ClientboundLightUpdatePacket, 0x25: clientbound_login_packet::ClientboundLoginPacket, + 0x26: clientbound_map_item_data_packet::ClientboundMapItemDataPacket, + 0x27: clientbound_merchant_offers_packet::ClientboundMerchantOffersPacket, 0x28: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket, - 0x29: clientbound_move_entity_posrot_packet::ClientboundMoveEntityPosrotPacket, + 0x29: clientbound_move_entity_pos_rot_packet::ClientboundMoveEntityPosRotPacket, 0x2a: clientbound_move_entity_rot_packet::ClientboundMoveEntityRotPacket, + 0x2b: clientbound_move_vehicle_packet::ClientboundMoveVehiclePacket, + 0x2c: clientbound_open_book_packet::ClientboundOpenBookPacket, + 0x2d: clientbound_open_screen_packet::ClientboundOpenScreenPacket, + 0x2e: clientbound_open_sign_editor_packet::ClientboundOpenSignEditorPacket, + 0x2f: clientbound_ping_packet::ClientboundPingPacket, + 0x30: clientbound_place_ghost_recipe_packet::ClientboundPlaceGhostRecipePacket, 0x31: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket, 0x32: clientbound_player_chat_header_packet::ClientboundPlayerChatHeaderPacket, 0x33: clientbound_player_chat_packet::ClientboundPlayerChatPacket, + 0x34: clientbound_player_combat_end_packet::ClientboundPlayerCombatEndPacket, + 0x35: clientbound_player_combat_enter_packet::ClientboundPlayerCombatEnterPacket, + 0x36: clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket, 0x37: clientbound_player_info_packet::ClientboundPlayerInfoPacket, + 0x38: clientbound_player_look_at_packet::ClientboundPlayerLookAtPacket, 0x39: clientbound_player_position_packet::ClientboundPlayerPositionPacket, 0x3a: clientbound_recipe_packet::ClientboundRecipePacket, 0x3b: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket, + 0x3c: clientbound_remove_mob_effect_packet::ClientboundRemoveMobEffectPacket, + 0x3d: clientbound_resource_pack_packet::ClientboundResourcePackPacket, + 0x3e: clientbound_respawn_packet::ClientboundRespawnPacket, 0x3f: clientbound_rotate_head_packet::ClientboundRotateHeadPacket, 0x40: clientbound_section_blocks_update_packet::ClientboundSectionBlocksUpdatePacket, + 0x41: clientbound_select_advancements_tab_packet::ClientboundSelectAdvancementsTabPacket, 0x42: clientbound_server_data_packet::ClientboundServerDataPacket, + 0x43: clientbound_set_action_bar_text_packet::ClientboundSetActionBarTextPacket, + 0x44: clientbound_set_border_center_packet::ClientboundSetBorderCenterPacket, + 0x45: clientbound_set_border_lerp_size_packet::ClientboundSetBorderLerpSizePacket, + 0x46: clientbound_set_border_size_packet::ClientboundSetBorderSizePacket, + 0x47: clientbound_set_border_warning_delay_packet::ClientboundSetBorderWarningDelayPacket, + 0x48: clientbound_set_border_warning_distance_packet::ClientboundSetBorderWarningDistancePacket, + 0x49: clientbound_set_camera_packet::ClientboundSetCameraPacket, 0x4a: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket, 0x4b: clientbound_set_chunk_cache_center_packet::ClientboundSetChunkCacheCenterPacket, 0x4c: clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket, + 0x4c: clientbound_set_chunk_cache_radius_packet::ClientboundSetChunkCacheRadiusPacket, 0x4d: clientbound_set_default_spawn_position_packet::ClientboundSetDefaultSpawnPositionPacket, 0x4e: clientbound_set_display_chat_preview_packet::ClientboundSetDisplayChatPreviewPacket, + 0x4f: clientbound_set_display_objective_packet::ClientboundSetDisplayObjectivePacket, 0x50: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket, 0x51: clientbound_set_entity_link_packet::ClientboundSetEntityLinkPacket, 0x52: clientbound_entity_velocity_packet::ClientboundEntityVelocityPacket, + 0x52: clientbound_set_entity_motion_packet::ClientboundSetEntityMotionPacket, 0x53: clientbound_set_equipment_packet::ClientboundSetEquipmentPacket, 0x54: clientbound_set_experience_packet::ClientboundSetExperiencePacket, 0x55: clientbound_set_health_packet::ClientboundSetHealthPacket, + 0x56: clientbound_set_objective_packet::ClientboundSetObjectivePacket, + 0x57: clientbound_set_passengers_packet::ClientboundSetPassengersPacket, + 0x58: clientbound_set_player_team_packet::ClientboundSetPlayerTeamPacket, + 0x59: clientbound_set_score_packet::ClientboundSetScorePacket, + 0x5a: clientbound_set_simulation_distance_packet::ClientboundSetSimulationDistancePacket, + 0x5b: clientbound_set_subtitle_text_packet::ClientboundSetSubtitleTextPacket, 0x5c: clientbound_set_time_packet::ClientboundSetTimePacket, + 0x5d: clientbound_set_title_text_packet::ClientboundSetTitleTextPacket, + 0x5e: clientbound_set_titles_animation_packet::ClientboundSetTitlesAnimationPacket, + 0x5f: clientbound_sound_entity_packet::ClientboundSoundEntityPacket, 0x60: clientbound_sound_packet::ClientboundSoundPacket, + 0x61: clientbound_stop_sound_packet::ClientboundStopSoundPacket, 0x62: clientbound_system_chat_packet::ClientboundSystemChatPacket, + 0x63: clientbound_tab_list_packet::ClientboundTabListPacket, + 0x64: clientbound_tag_query_packet::ClientboundTagQueryPacket, + 0x65: clientbound_take_item_entity_packet::ClientboundTakeItemEntityPacket, 0x66: clientbound_teleport_entity_packet::ClientboundTeleportEntityPacket, 0x67: clientbound_update_advancements_packet::ClientboundUpdateAdvancementsPacket, 0x68: clientbound_update_attributes_packet::ClientboundUpdateAttributesPacket, diff --git a/azalea-protocol/src/packets/game/serverbound_block_entity_tag_query.rs b/azalea-protocol/src/packets/game/serverbound_block_entity_tag_query.rs new file mode 100644 index 00000000..176df75e --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_block_entity_tag_query.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundBlockEntityTagQuery { + #[var] + pub transaction_id: i32, + pub pos: BlockPos, +} diff --git a/azalea-protocol/src/packets/game/serverbound_change_difficulty_packet.rs b/azalea-protocol/src/packets/game/serverbound_change_difficulty_packet.rs new file mode 100644 index 00000000..0414af46 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_change_difficulty_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_core::Difficulty; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundChangeDifficultyPacket { + pub difficulty: Difficulty, +} diff --git a/azalea-protocol/src/packets/game/serverbound_client_command_packet.rs b/azalea-protocol/src/packets/game/serverbound_client_command_packet.rs new file mode 100644 index 00000000..c1324256 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_client_command_packet.rs @@ -0,0 +1,13 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundClientCommandPacket { + pub action: Action, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Action { + PerformRespawn = 0, + RequestStats = 1, +} diff --git a/azalea-protocol/src/packets/game/serverbound_client_information_packet.rs b/azalea-protocol/src/packets/game/serverbound_client_information_packet.rs new file mode 100644 index 00000000..1da0b917 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_client_information_packet.rs @@ -0,0 +1,27 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundClientInformationPacket { + pub language: String, + pub view_distance: u8, + pub chat_visibility: ChatVisiblity, + pub chat_colors: bool, + pub model_customisation: u8, + pub main_hand: HumanoidArm, + pub text_filtering_enabled: bool, + pub allows_listing: bool, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum ChatVisiblity { + Full = 0, + System = 1, + Hidden = 2, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum HumanoidArm { + Left = 0, + Right = 1, +} diff --git a/azalea-protocol/src/packets/game/serverbound_command_suggestion_packet.rs b/azalea-protocol/src/packets/game/serverbound_command_suggestion_packet.rs new file mode 100644 index 00000000..b0d7d8e3 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_command_suggestion_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundCommandSuggestionPacket { + #[var] + pub id: u32, + pub command: String, +} diff --git a/azalea-protocol/src/packets/game/serverbound_container_button_click_packet.rs b/azalea-protocol/src/packets/game/serverbound_container_button_click_packet.rs new file mode 100644 index 00000000..08013ec5 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_container_button_click_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundContainerButtonClickPacket { + pub container_id: u8, + pub button_id: u8, +} diff --git a/azalea-protocol/src/packets/game/serverbound_container_click_packet.rs b/azalea-protocol/src/packets/game/serverbound_container_click_packet.rs new file mode 100644 index 00000000..5c18b8cd --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_container_click_packet.rs @@ -0,0 +1,26 @@ +use azalea_buf::McBuf; +use azalea_core::Slot; +use packet_macros::ServerboundGamePacket; +use std::collections::HashMap; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundContainerClickPacket { + pub container_id: u8, + #[var] + pub state_id: u32, + pub slot_num: u16, + pub button_num: u8, + pub click_type: ClickType, + pub changed_slots: HashMap, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum ClickType { + Pickup = 0, + QuickMove = 1, + Swap = 2, + Clone = 3, + Throw = 4, + QuickCraft = 5, + PickupAll = 6, +} diff --git a/azalea-protocol/src/packets/game/serverbound_container_close_packet.rs b/azalea-protocol/src/packets/game/serverbound_container_close_packet.rs new file mode 100644 index 00000000..c9894144 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_container_close_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundContainerClosePacket { + pub container_id: u8, +} diff --git a/azalea-protocol/src/packets/game/serverbound_edit_book_packet.rs b/azalea-protocol/src/packets/game/serverbound_edit_book_packet.rs new file mode 100644 index 00000000..b562cbaf --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_edit_book_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundEditBookPacket { + #[var] + pub slot: u32, + pub pages: Vec, + pub title: Option, +} diff --git a/azalea-protocol/src/packets/game/serverbound_entity_tag_query.rs b/azalea-protocol/src/packets/game/serverbound_entity_tag_query.rs new file mode 100644 index 00000000..b3e4014e --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_entity_tag_query.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundEntityTagQuery { + #[var] + pub transaction_id: u32, + #[var] + pub entity_id: u32, +} diff --git a/azalea-protocol/src/packets/game/serverbound_interact_packet.rs b/azalea-protocol/src/packets/game/serverbound_interact_packet.rs new file mode 100644 index 00000000..47843d47 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_interact_packet.rs @@ -0,0 +1,85 @@ +use crate::packets::BufReadError; +use azalea_buf::McBufVarReadable; +use azalea_buf::{McBuf, McBufReadable, McBufVarWritable, McBufWritable}; +use azalea_core::EntityPos; +use packet_macros::ServerboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundInteractPacket { + #[var] + pub entity_id: u32, + pub action: ActionType, + /// Whether the player is sneaking + pub using_secondary_action: bool, +} + +#[derive(Clone, Copy, Debug)] +pub enum ActionType { + Interact { + hand: InteractionHand, + }, + Attack, + InteractAt { + location: EntityPos, + hand: InteractionHand, + }, +} + +impl McBufWritable for ActionType { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + match self { + ActionType::Interact { hand } => { + 0u32.var_write_into(buf)?; + hand.write_into(buf)?; + } + ActionType::Attack => { + 1u32.var_write_into(buf)?; + } + ActionType::InteractAt { location, hand } => { + 2u32.var_write_into(buf)?; + (location.x as f32).write_into(buf)?; + (location.y as f32).write_into(buf)?; + (location.z as f32).write_into(buf)?; + hand.write_into(buf)?; + } + } + Ok(()) + } +} + +impl McBufReadable for ActionType { + fn read_from(buf: &mut impl Read) -> Result { + let action_type = u32::var_read_from(buf)?; + match action_type { + 0 => { + let hand = InteractionHand::read_from(buf)?; + Ok(ActionType::Interact { hand }) + } + 1 => Ok(ActionType::Attack), + 2 => { + let x = f32::read_from(buf)?; + let y = f32::read_from(buf)?; + let z = f32::read_from(buf)?; + let hand = InteractionHand::read_from(buf)?; + Ok(ActionType::InteractAt { + location: EntityPos { + x: x as f64, + y: y as f64, + z: z as f64, + }, + hand, + }) + } + _ => Err(BufReadError::UnexpectedEnumVariant { + id: action_type as i32, + }), + } + } +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum InteractionHand { + MainHand = 0, + OffHand = 1, +} diff --git a/azalea-protocol/src/packets/game/serverbound_jigsaw_generate_packet.rs b/azalea-protocol/src/packets/game/serverbound_jigsaw_generate_packet.rs new file mode 100644 index 00000000..e0dba5fc --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_jigsaw_generate_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundJigsawGeneratePacket { + pub pos: BlockPos, + #[var] + pub levels: u32, + pub keep_jigsaws: bool, +} diff --git a/azalea-protocol/src/packets/game/serverbound_lock_difficulty_packet.rs b/azalea-protocol/src/packets/game/serverbound_lock_difficulty_packet.rs new file mode 100644 index 00000000..bbfd7891 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_lock_difficulty_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundLockDifficultyPacket { + pub locked: bool, +} diff --git a/azalea-protocol/src/packets/game/serverbound_move_player_packet_pos.rs b/azalea-protocol/src/packets/game/serverbound_move_player_pos_packet.rs similarity index 100% rename from azalea-protocol/src/packets/game/serverbound_move_player_packet_pos.rs rename to azalea-protocol/src/packets/game/serverbound_move_player_pos_packet.rs diff --git a/azalea-protocol/src/packets/game/serverbound_move_player_packet_pos_rot.rs b/azalea-protocol/src/packets/game/serverbound_move_player_pos_rot_packet.rs similarity index 100% rename from azalea-protocol/src/packets/game/serverbound_move_player_packet_pos_rot.rs rename to azalea-protocol/src/packets/game/serverbound_move_player_pos_rot_packet.rs diff --git a/azalea-protocol/src/packets/game/serverbound_move_player_packet_rot.rs b/azalea-protocol/src/packets/game/serverbound_move_player_rot_packet.rs similarity index 100% rename from azalea-protocol/src/packets/game/serverbound_move_player_packet_rot.rs rename to azalea-protocol/src/packets/game/serverbound_move_player_rot_packet.rs diff --git a/azalea-protocol/src/packets/game/serverbound_move_player_packet_status_only.rs b/azalea-protocol/src/packets/game/serverbound_move_player_status_only_packet.rs similarity index 100% rename from azalea-protocol/src/packets/game/serverbound_move_player_packet_status_only.rs rename to azalea-protocol/src/packets/game/serverbound_move_player_status_only_packet.rs diff --git a/azalea-protocol/src/packets/game/serverbound_move_vehicle_packet.rs b/azalea-protocol/src/packets/game/serverbound_move_vehicle_packet.rs new file mode 100644 index 00000000..31b2647e --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_move_vehicle_packet.rs @@ -0,0 +1,11 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundMoveVehiclePacket { + pub x: f64, + pub y: f64, + pub z: f64, + pub y_rot: f32, + pub x_rot: f32, +} diff --git a/azalea-protocol/src/packets/game/serverbound_paddle_boat_packet.rs b/azalea-protocol/src/packets/game/serverbound_paddle_boat_packet.rs new file mode 100644 index 00000000..812895bc --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_paddle_boat_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundPaddleBoatPacket { + pub left: bool, + pub right: bool, +} diff --git a/azalea-protocol/src/packets/game/serverbound_pick_item_packet.rs b/azalea-protocol/src/packets/game/serverbound_pick_item_packet.rs new file mode 100644 index 00000000..5db8e00b --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_pick_item_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundPickItemPacket { + #[var] + pub slot: u32, +} diff --git a/azalea-protocol/src/packets/game/serverbound_place_recipe_packet.rs b/azalea-protocol/src/packets/game/serverbound_place_recipe_packet.rs new file mode 100644 index 00000000..82576791 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_place_recipe_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use azalea_core::ResourceLocation; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundPlaceRecipePacket { + pub container_id: u8, + pub recipe: ResourceLocation, + pub shift_down: bool, +} diff --git a/azalea-protocol/src/packets/game/serverbound_player_abilities_packet.rs b/azalea-protocol/src/packets/game/serverbound_player_abilities_packet.rs new file mode 100644 index 00000000..7ea43e88 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_player_abilities_packet.rs @@ -0,0 +1,28 @@ +use crate::packets::BufReadError; +use azalea_buf::{McBufReadable, McBufWritable}; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, ServerboundGamePacket)] +pub struct ServerboundPlayerAbilitiesPacket { + is_flying: bool, +} + +impl McBufReadable for ServerboundPlayerAbilitiesPacket { + fn read_from(buf: &mut impl std::io::Read) -> Result { + let byte = u8::read_from(buf)?; + Ok(Self { + is_flying: byte & 2 != 0, + }) + } +} + +impl McBufWritable for ServerboundPlayerAbilitiesPacket { + fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { + let mut byte = 0; + if self.is_flying { + byte |= 2; + } + byte.write_into(buf)?; + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_player_action_packet.rs b/azalea-protocol/src/packets/game/serverbound_player_action_packet.rs new file mode 100644 index 00000000..ac2910b1 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_player_action_packet.rs @@ -0,0 +1,24 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use azalea_core::Direction; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundPlayerActionPacket { + pub action: Action, + pub pos: BlockPos, + pub direction: Direction, + #[var] + pub sequence: u32, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Action { + StartDestroyBlock = 0, + AbortDestroyBlock = 1, + StopDestroyBlock = 2, + DropAllItems = 3, + DropItem = 4, + ReleaseUseItem = 5, + SwapItemWithOffhand = 6, +} diff --git a/azalea-protocol/src/packets/game/serverbound_player_command_packet.rs b/azalea-protocol/src/packets/game/serverbound_player_command_packet.rs new file mode 100644 index 00000000..20f80b4c --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_player_command_packet.rs @@ -0,0 +1,24 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundPlayerCommandPacket { + #[var] + pub id: u32, + pub action: Action, + #[var] + pub data: u32, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Action { + PressShiftKey = 0, + ReleaseShiftKey = 1, + StopSleeping = 2, + StartSprinting = 3, + StopSprinting = 4, + StartRidingJump = 5, + StopRidingJump = 6, + OpenInventory = 7, + StartFallFlying = 8, +} diff --git a/azalea-protocol/src/packets/game/serverbound_player_input_packet.rs b/azalea-protocol/src/packets/game/serverbound_player_input_packet.rs new file mode 100644 index 00000000..b0906691 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_player_input_packet.rs @@ -0,0 +1,43 @@ +use azalea_buf::BufReadError; +use azalea_buf::{McBufReadable, McBufWritable}; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, ServerboundGamePacket)] +pub struct ServerboundPlayerInputPacket { + pub xxa: f32, + pub zza: f32, + pub is_jumping: bool, + pub is_shift_key_down: bool, +} + +impl McBufReadable for ServerboundPlayerInputPacket { + fn read_from(buf: &mut impl std::io::Read) -> Result { + let xxa = f32::read_from(buf)?; + let zza = f32::read_from(buf)?; + let byte = u8::read_from(buf)?; + let is_jumping = byte & 1 != 0; + let is_shift_key_down = byte & 2 != 0; + Ok(Self { + xxa, + zza, + is_jumping, + is_shift_key_down, + }) + } +} + +impl McBufWritable for ServerboundPlayerInputPacket { + fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { + self.xxa.write_into(buf)?; + self.zza.write_into(buf)?; + let mut byte = 0; + if self.is_jumping { + byte |= 1; + } + if self.is_shift_key_down { + byte |= 2; + } + byte.write_into(buf)?; + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_pong_packet.rs b/azalea-protocol/src/packets/game/serverbound_pong_packet.rs new file mode 100644 index 00000000..a2a4b32d --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_pong_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundPongPacket { + pub id: u32, +} diff --git a/azalea-protocol/src/packets/game/serverbound_recipe_book_change_settings_packet.rs b/azalea-protocol/src/packets/game/serverbound_recipe_book_change_settings_packet.rs new file mode 100644 index 00000000..9fd8eca5 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_recipe_book_change_settings_packet.rs @@ -0,0 +1,17 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundRecipeBookChangeSettingsPacket { + pub book_type: RecipeBookType, + pub is_open: bool, + pub is_filtering: bool, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum RecipeBookType { + Crafting = 0, + Furnace = 1, + BlastFurnace = 2, + Smoker = 3, +} diff --git a/azalea-protocol/src/packets/game/serverbound_recipe_book_seen_recipe_packet.rs b/azalea-protocol/src/packets/game/serverbound_recipe_book_seen_recipe_packet.rs new file mode 100644 index 00000000..d70e80bb --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_recipe_book_seen_recipe_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use azalea_core::ResourceLocation; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundRecipeBookSeenRecipePacket { + pub recipe: ResourceLocation, +} diff --git a/azalea-protocol/src/packets/game/serverbound_rename_item_packet.rs b/azalea-protocol/src/packets/game/serverbound_rename_item_packet.rs new file mode 100644 index 00000000..85792895 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_rename_item_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundRenameItemPacket { + pub name: String, +} diff --git a/azalea-protocol/src/packets/game/serverbound_resource_pack_packet.rs b/azalea-protocol/src/packets/game/serverbound_resource_pack_packet.rs new file mode 100644 index 00000000..98a1d3f7 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_resource_pack_packet.rs @@ -0,0 +1,15 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundResourcePackPacket { + pub action: Action, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Action { + SuccessfullyLoaded = 0, + Declined = 1, + FailedDownload = 2, + Accepted = 3, +} diff --git a/azalea-protocol/src/packets/game/serverbound_seen_advancements_packet.rs b/azalea-protocol/src/packets/game/serverbound_seen_advancements_packet.rs new file mode 100644 index 00000000..199568f7 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_seen_advancements_packet.rs @@ -0,0 +1,38 @@ +use crate::packets::BufReadError; +use azalea_buf::{McBuf, McBufReadable, McBufWritable}; +use azalea_core::ResourceLocation; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, ServerboundGamePacket)] +pub struct ServerboundSeenAdvancementsPacket { + pub action: Action, + pub tab: Option, +} + +#[derive(McBuf, Clone, Copy, Debug, Eq, PartialEq)] +pub enum Action { + OpenedTab = 0, + ClosedScreen = 1, +} + +impl McBufReadable for ServerboundSeenAdvancementsPacket { + fn read_from(buf: &mut impl std::io::Read) -> Result { + let action = Action::read_from(buf)?; + let tab = if action == Action::OpenedTab { + Some(ResourceLocation::read_from(buf)?) + } else { + None + }; + Ok(Self { action, tab }) + } +} + +impl McBufWritable for ServerboundSeenAdvancementsPacket { + fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { + self.action.write_into(buf)?; + if let Some(tab) = &self.tab { + tab.write_into(buf)?; + } + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_select_trade_packet.rs b/azalea-protocol/src/packets/game/serverbound_select_trade_packet.rs new file mode 100644 index 00000000..78e68bc0 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_select_trade_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSelectTradePacket { + #[var] + pub item: u32, +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_beacon_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_beacon_packet.rs new file mode 100644 index 00000000..b286204c --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_beacon_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSetBeaconPacket { + #[var] + pub primary: Option, + #[var] + pub secondary: Option, +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_carried_item_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_carried_item_packet.rs new file mode 100644 index 00000000..7a857794 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_carried_item_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSetCarriedItemPacket { + pub slot: u16, +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_command_block_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_command_block_packet.rs new file mode 100644 index 00000000..4569eb64 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_command_block_packet.rs @@ -0,0 +1,64 @@ +use crate::packets::McBufWritable; +use azalea_buf::{BufReadError, McBuf, McBufReadable}; +use azalea_core::BlockPos; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, ServerboundGamePacket)] +pub struct ServerboundSetCommandBlockPacket { + pub pos: BlockPos, + pub command: String, + pub mode: Mode, + + pub track_output: bool, + pub conditional: bool, + pub automatic: bool, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Mode { + Sequence = 0, + Auto = 1, + Redstone = 2, +} + +impl McBufReadable for ServerboundSetCommandBlockPacket { + fn read_from(buf: &mut impl std::io::Read) -> Result { + let pos = BlockPos::read_from(buf)?; + let command = String::read_from(buf)?; + let mode = Mode::read_from(buf)?; + + let byte = u8::read_from(buf)?; + let track_output = byte & 1 != 0; + let conditional = byte & 2 != 0; + let automatic = byte & 4 != 0; + Ok(Self { + pos, + command, + mode, + track_output, + conditional, + automatic, + }) + } +} + +impl McBufWritable for ServerboundSetCommandBlockPacket { + fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { + self.pos.write_into(buf)?; + self.command.write_into(buf)?; + self.mode.write_into(buf)?; + + let mut byte: u8 = 0; + if self.track_output { + byte |= 1; + } + if self.conditional { + byte |= 2; + } + if self.automatic { + byte |= 4; + } + byte.write_into(buf)?; + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_command_minecart_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_command_minecart_packet.rs new file mode 100644 index 00000000..5d81b2b4 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_command_minecart_packet.rs @@ -0,0 +1,10 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSetCommandMinecartPacket { + #[var] + pub entity: u32, + pub command: String, + pub track_output: bool, +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_creative_mode_slot_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_creative_mode_slot_packet.rs new file mode 100644 index 00000000..1e04a29e --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_creative_mode_slot_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use azalea_core::Slot; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSetCreativeModeSlotPacket { + pub slot_num: u16, + pub item_stack: Slot, +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_jigsaw_block_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_jigsaw_block_packet.rs new file mode 100644 index 00000000..d098aa86 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_jigsaw_block_packet.rs @@ -0,0 +1,44 @@ +use crate::packets::BufReadError; +use crate::packets::McBufWritable; +use azalea_buf::McBuf; +use azalea_buf::McBufReadable; +use azalea_core::BlockPos; +use azalea_core::ResourceLocation; +use packet_macros::ServerboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSetJigsawBlockPacket { + pub pos: BlockPos, + pub name: ResourceLocation, + pub target: ResourceLocation, + pub pool: ResourceLocation, + pub final_state: String, + pub joint: String, // TODO: Does JigsawBlockEntity$JointType::getSerializedName, may not be implemented +} + +pub enum JointType { + Rollable, + Aligned, +} + +impl McBufReadable for JointType { + fn read_from(buf: &mut impl Read) -> Result { + let name = String::read_from(buf)?; + match name.as_str() { + "rollable" => Ok(JointType::Rollable), + "aligned" => Ok(JointType::Aligned), + _ => Err(BufReadError::UnexpectedStringEnumVariant { id: name }), + } + } +} + +impl McBufWritable for JointType { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + match self { + JointType::Rollable => "rollable".to_string().write_into(buf)?, + JointType::Aligned => "aligned".to_string().write_into(buf)?, + }; + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_set_structure_block_packet.rs b/azalea-protocol/src/packets/game/serverbound_set_structure_block_packet.rs new file mode 100644 index 00000000..33fbb951 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_set_structure_block_packet.rs @@ -0,0 +1,96 @@ +use crate::packets::BufReadError; +use azalea_buf::McBuf; +use azalea_buf::{McBufReadable, McBufWritable}; +use azalea_core::BlockPos; +use packet_macros::ServerboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSetStructureBlockPacket { + pub pos: BlockPos, + pub update_type: UpdateType, + pub mode: StructureMode, + pub name: String, + pub offset: BytePosition, + pub size: BytePosition, + pub mirror: Mirror, + pub rotation: Rotation, + pub data: String, + pub integrity: f32, + #[var] + pub seed: u64, + pub flags: Flags, +} + +#[derive(Clone, Debug, McBuf)] +pub struct BytePosition { + pub x: u8, + pub y: u8, + pub z: u8, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum UpdateType { + UpdateData = 0, + SaveArea = 1, + LoadArea = 2, + ScanArea = 3, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum StructureMode { + Save = 0, + Load = 1, + Corner = 2, + Data = 3, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Mirror { + None = 0, + LeftRight = 1, + FrontBack = 2, +} + +#[derive(McBuf, Clone, Copy, Debug)] +pub enum Rotation { + None = 0, + Clockwise90 = 1, + Clockwise180 = 2, + Counterclockwise90 = 3, +} + +#[derive(Debug, Clone)] +pub struct Flags { + pub ignore_entities: bool, + pub show_air: bool, + pub show_bounding_box: bool, +} + +impl McBufReadable for Flags { + fn read_from(buf: &mut impl Read) -> Result { + let byte = u8::read_from(buf)?; + Ok(Self { + ignore_entities: byte & 1 != 0, + show_air: byte & 2 != 0, + show_bounding_box: byte & 4 != 0, + }) + } +} + +impl McBufWritable for Flags { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + let mut byte = 0; + if self.ignore_entities { + byte |= 1; + } + if self.show_air { + byte |= 2; + } + if self.show_bounding_box { + byte |= 4; + } + u8::write_into(&byte, buf)?; + Ok(()) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_sign_update_packet.rs b/azalea-protocol/src/packets/game/serverbound_sign_update_packet.rs new file mode 100644 index 00000000..b90ef487 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_sign_update_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::McBuf; +use azalea_core::BlockPos; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSignUpdatePacket { + pub pos: BlockPos, + pub lines: [String; 4], +} diff --git a/azalea-protocol/src/packets/game/serverbound_swing_packet.rs b/azalea-protocol/src/packets/game/serverbound_swing_packet.rs new file mode 100644 index 00000000..b22375d9 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_swing_packet.rs @@ -0,0 +1,8 @@ +use crate::packets::game::serverbound_interact_packet::InteractionHand; +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundSwingPacket { + pub hand: InteractionHand, +} diff --git a/azalea-protocol/src/packets/game/serverbound_teleport_to_entity_packet.rs b/azalea-protocol/src/packets/game/serverbound_teleport_to_entity_packet.rs new file mode 100644 index 00000000..920b8cac --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_teleport_to_entity_packet.rs @@ -0,0 +1,8 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; +use uuid::Uuid; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundTeleportToEntityPacket { + pub uuid: Uuid, +} diff --git a/azalea-protocol/src/packets/game/serverbound_use_item_on_packet.rs b/azalea-protocol/src/packets/game/serverbound_use_item_on_packet.rs new file mode 100644 index 00000000..f2fb1b2a --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_use_item_on_packet.rs @@ -0,0 +1,54 @@ +use crate::packets::game::serverbound_interact_packet::InteractionHand; +use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable}; +use azalea_core::{BlockPos, Direction, EntityPos}; +use packet_macros::ServerboundGamePacket; +use std::io::{Read, Write}; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundUseItemOnPacket { + pub hand: InteractionHand, + pub block_hit: BlockHitResult, + #[var] + pub sequence: u32, +} + +#[derive(Clone, Debug)] +pub struct BlockHitResult { + pub block_pos: BlockPos, + pub direction: Direction, + pub location: EntityPos, + pub inside: bool, +} + +impl McBufWritable for BlockHitResult { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + self.block_pos.write_into(buf)?; + self.direction.write_into(buf)?; + f32::write_into(&((self.location.x - (self.block_pos.x as f64)) as f32), buf)?; + f32::write_into(&((self.location.y - (self.block_pos.y as f64)) as f32), buf)?; + f32::write_into(&((self.location.z - (self.block_pos.z as f64)) as f32), buf)?; + self.inside.write_into(buf)?; + Ok(()) + } +} + +impl McBufReadable for BlockHitResult { + fn read_from(buf: &mut impl Read) -> Result { + let block_pos = BlockPos::read_from(buf)?; + let direction = Direction::read_from(buf)?; + let cursor_x = f32::read_from(buf)?; + let cursor_y = f32::read_from(buf)?; + let cursor_z = f32::read_from(buf)?; + let inside = bool::read_from(buf)?; + Ok(Self { + block_pos, + direction, + location: EntityPos { + x: block_pos.x as f64 + cursor_x as f64, + y: block_pos.y as f64 + cursor_y as f64, + z: block_pos.z as f64 + cursor_z as f64, + }, + inside, + }) + } +} diff --git a/azalea-protocol/src/packets/game/serverbound_use_item_packet.rs b/azalea-protocol/src/packets/game/serverbound_use_item_packet.rs new file mode 100644 index 00000000..4fb9d34d --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_use_item_packet.rs @@ -0,0 +1,10 @@ +use crate::packets::game::serverbound_interact_packet::InteractionHand; +use azalea_buf::McBuf; +use packet_macros::ServerboundGamePacket; + +#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] +pub struct ServerboundUseItemPacket { + pub hand: InteractionHand, + #[var] + pub sequence: u32, +} diff --git a/azalea-protocol/src/packets/login/mod.rs b/azalea-protocol/src/packets/login/mod.rs index b160a28c..17976e48 100755 --- a/azalea-protocol/src/packets/login/mod.rs +++ b/azalea-protocol/src/packets/login/mod.rs @@ -3,6 +3,7 @@ pub mod clientbound_game_profile_packet; pub mod clientbound_hello_packet; pub mod clientbound_login_compression_packet; pub mod clientbound_login_disconnect_packet; +pub mod serverbound_custom_query_packet; pub mod serverbound_hello_packet; pub mod serverbound_key_packet; @@ -13,12 +14,10 @@ declare_state_packets!( Serverbound => { 0x00: serverbound_hello_packet::ServerboundHelloPacket, 0x01: serverbound_key_packet::ServerboundKeyPacket, + 0x02: serverbound_custom_query_packet::ServerboundCustomQueryPacket, }, Clientbound => { 0x00: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, - // sometimes this is used for some reason? - // 0x1a: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, - 0x01: clientbound_hello_packet::ClientboundHelloPacket, 0x02: clientbound_game_profile_packet::ClientboundGameProfilePacket, 0x03: clientbound_login_compression_packet::ClientboundLoginCompressionPacket, diff --git a/azalea-protocol/src/packets/login/serverbound_custom_query_packet.rs b/azalea-protocol/src/packets/login/serverbound_custom_query_packet.rs new file mode 100644 index 00000000..cc9a5dc9 --- /dev/null +++ b/azalea-protocol/src/packets/login/serverbound_custom_query_packet.rs @@ -0,0 +1,9 @@ +use azalea_buf::{McBuf, UnsizedByteArray}; +use packet_macros::ServerboundLoginPacket; + +#[derive(Clone, Debug, McBuf, ServerboundLoginPacket)] +pub struct ServerboundCustomQueryPacket { + #[var] + pub transaction_id: u32, + pub data: Option, +} diff --git a/azalea-protocol/src/packets/status/clientbound_pong_response_packet.rs b/azalea-protocol/src/packets/status/clientbound_pong_response_packet.rs new file mode 100644 index 00000000..08a086c5 --- /dev/null +++ b/azalea-protocol/src/packets/status/clientbound_pong_response_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ClientboundStatusPacket; + +#[derive(Clone, Debug, McBuf, ClientboundStatusPacket)] +pub struct ClientboundPongResponsePacket { + pub time: u64, +} diff --git a/azalea-protocol/src/packets/status/mod.rs b/azalea-protocol/src/packets/status/mod.rs index 56aa577e..37c5af88 100755 --- a/azalea-protocol/src/packets/status/mod.rs +++ b/azalea-protocol/src/packets/status/mod.rs @@ -1,4 +1,6 @@ +pub mod clientbound_pong_response_packet; pub mod clientbound_status_response_packet; +pub mod serverbound_ping_request_packet; pub mod serverbound_status_request_packet; use packet_macros::declare_state_packets; @@ -7,8 +9,10 @@ declare_state_packets!( StatusPacket, Serverbound => { 0x00: serverbound_status_request_packet::ServerboundStatusRequestPacket, + 0x01: serverbound_ping_request_packet::ServerboundPingRequestPacket, }, Clientbound => { 0x00: clientbound_status_response_packet::ClientboundStatusResponsePacket, + 0x01: clientbound_pong_response_packet::ClientboundPongResponsePacket, } ); diff --git a/azalea-protocol/src/packets/status/serverbound_ping_request_packet.rs b/azalea-protocol/src/packets/status/serverbound_ping_request_packet.rs new file mode 100644 index 00000000..93f49644 --- /dev/null +++ b/azalea-protocol/src/packets/status/serverbound_ping_request_packet.rs @@ -0,0 +1,7 @@ +use azalea_buf::McBuf; +use packet_macros::ServerboundStatusPacket; + +#[derive(Clone, Debug, McBuf, ServerboundStatusPacket)] +pub struct ServerboundPingRequestPacket { + pub time: u64, +} diff --git a/azalea-world/src/entity.rs b/azalea-world/src/entity.rs index 5219e410..69529294 100644 --- a/azalea-world/src/entity.rs +++ b/azalea-world/src/entity.rs @@ -113,12 +113,7 @@ impl EntityStorage { where F: FnMut(&Entity) -> bool, { - for entity in self.entities() { - if f(entity) { - return Some(entity); - } - } - None + self.entities().find(|&entity| f(entity)) } pub fn find_one_entity_in_chunk(&self, chunk: &ChunkPos, mut f: F) -> Option<&Entity> diff --git a/codegen/lib/code/packet.py b/codegen/lib/code/packet.py index ffa7841c..692a449e 100644 --- a/codegen/lib/code/packet.py +++ b/codegen/lib/code/packet.py @@ -27,27 +27,40 @@ def generate_packet(burger_packets, mappings: Mappings, target_packet_id, target generated_packet_code = [] uses = set() + extra_code = [] + + packet_derive_name = f'{to_camel_case(direction)}{to_camel_case(state)}Packet' + generated_packet_code.append( - f'#[derive(Clone, Debug, McBuf, {to_camel_case(state)}Packet)]') - uses.add(f'packet_macros::{to_camel_case(state)}Packet') + f'#[derive(Clone, Debug, McBuf, {packet_derive_name})]') + uses.add(f'packet_macros::{packet_derive_name}') uses.add(f'azalea_buf::McBuf') obfuscated_class_name = packet['class'].split('.')[0] class_name = mappings.get_class( obfuscated_class_name).split('.')[-1] if '$' in class_name: - class_name = class_name.replace('$', '') + class_name, extra_part = class_name.split('$') + if class_name.endswith('Packet'): + class_name = class_name[:- + len('Packet')] + extra_part + 'Packet' generated_packet_code.append( f'pub struct {to_camel_case(class_name)} {{') - for instruction in packet.get('instructions', []): - if instruction['operation'] == 'write': - burger_instruction_to_code( - instruction, generated_packet_code, mappings, obfuscated_class_name, uses) + # call burger_instruction_to_code for each instruction + i = -1 + instructions = packet.get('instructions', []) + while (i + 1) < len(instructions): + i += 1 + + if instructions[i]['operation'] == 'write': + skip = burger_instruction_to_code( + instructions, i, generated_packet_code, mappings, obfuscated_class_name, uses, extra_code) + if skip: + i += skip else: - generated_packet_code.append(f'// TODO: {instruction}') - continue + generated_packet_code.append(f'// TODO: {instructions[i]}') generated_packet_code.append('}') @@ -56,6 +69,8 @@ def generate_packet(burger_packets, mappings: Mappings, target_packet_id, target generated_packet_code.insert(0, '') for use in uses: generated_packet_code.insert(0, f'use {use};') + for line in extra_code: + generated_packet_code.append(line) print(generated_packet_code) write_packet_file(state, to_snake_case(class_name), @@ -204,21 +219,108 @@ def get_packets(direction: str, state: str): return packet_ids, packet_class_names -def burger_instruction_to_code(instruction: dict, generated_packet_code: list[str], mappings: Mappings, obfuscated_class_name: str, uses: set): - field_type = instruction['type'] - field_type_rs, is_var, instruction_uses = burger_type_to_rust_type( - field_type) +def burger_instruction_to_code(instructions: list[dict], index: int, generated_packet_code: list[str], mappings: Mappings, obfuscated_class_name: str, uses: set, extra_code: list[str]) -> Optional[int]: + ''' + Generate a field for an instruction, returns the number of instructions to skip (if any). + ''' + instruction = instructions[index] + next_instruction = instructions[index + + 1] if index + 1 < len(instructions) else None + next_next_instruction = instructions[index + + 2] if index + 2 < len(instructions) else None + + is_var = False + skip = 0 + field_type_rs = None + field_comment = None + + # iterators + if instruction['operation'] == 'write' and instruction['field'].endswith('.size()') and next_instruction and next_instruction['type'] == 'Iterator' and next_next_instruction and next_next_instruction['operation'] == 'loop': + field_obfuscated_name = instruction['field'].split('.')[ + 0] + field_name = mappings.get_field( + obfuscated_class_name, field_obfuscated_name) + + # figure out what kind of iterator it is + loop_instructions = next_next_instruction['instructions'] + if len(loop_instructions) == 2: + entry_type_rs, is_var, uses, extra_code = burger_type_to_rust_type( + loop_instructions[1]['type'], None, loop_instructions[1], mappings, obfuscated_class_name) + field_type_rs = f'Vec<{entry_type_rs}>' + elif len(loop_instructions) == 3: + is_map = loop_instructions[0]['type'].startswith( + 'Map.Entry<') + if is_map: + assert loop_instructions[1]['field'].endswith( + '.getKey()') + assert loop_instructions[2]['field'].endswith( + '.getValue()') + + # generate the type for the key + key_type_rs, is_key_var, key_uses, key_extra_code = burger_type_to_rust_type( + loop_instructions[1]['type'], None, loop_instructions[1], mappings, obfuscated_class_name) + uses.update(key_uses) + extra_code.extend(key_extra_code) + + # generate the type for the value + value_type_rs, is_value_var, value_uses, value_extra_code = burger_type_to_rust_type( + loop_instructions[2]['type'], None, loop_instructions[2], mappings, obfuscated_class_name) + uses.update(value_uses) + extra_code.extend(value_extra_code) + + field_type_rs = f'HashMap<{key_type_rs}, {value_type_rs}>' + uses.add('std::collections::HashMap') + + # only the key is var since the value can be made var in other ways + is_var = is_key_var + + skip = 2 # skip the next 2 instructions + + # Option + elif instruction['operation'] == 'write' and (instruction['field'].endswith('.isPresent()') or instruction['field'].endswith(' != null')) and next_instruction and (next_instruction.get('condition', '').endswith('.isPresent()') or next_instruction.get('condition', '').endswith(' != null')): + field_obfuscated_name = instruction['field'].split('.')[ + 0].split(' ')[0] + field_name = mappings.get_field( + obfuscated_class_name, field_obfuscated_name) + condition_instructions = next_instruction['instructions'] + + condition_types_rs = [] + for condition_instruction in condition_instructions: + condition_type_rs, is_var, this_uses, this_extra_code = burger_type_to_rust_type( + condition_instruction['type'], None, condition_instruction, mappings, obfuscated_class_name) + condition_types_rs.append(condition_type_rs) + uses.update(this_uses) + extra_code.extend(this_extra_code) + field_type_rs = f'Option<({", ".join(condition_types_rs)})>' if len( + condition_types_rs) != 1 else f'Option<{condition_types_rs[0]}>' + skip = 1 + else: + field_type = instruction['type'] + obfuscated_field_name = instruction['field'] + + if obfuscated_field_name.startswith('(float)'): + obfuscated_field_name = obfuscated_field_name[len('(float)'):] + + field_name = mappings.get_field( + obfuscated_class_name, obfuscated_field_name) or mappings.get_field( + obfuscated_class_name.split('$')[0], obfuscated_field_name) + + field_type_rs, is_var, instruction_uses, instruction_extra_code = burger_type_to_rust_type( + field_type, field_name, instruction, mappings, obfuscated_class_name) + + if '.' in obfuscated_field_name or ' ' in obfuscated_field_name or '(' in obfuscated_field_name: + field_type_rs2, obfuscated_field_name, field_comment = burger_field_to_type( + obfuscated_field_name, mappings, obfuscated_class_name) + if not field_type_rs2: + generated_packet_code.append(f'// TODO: {instruction}') + return + # try to get the field name again with the new stuff we know + field_name = mappings.get_field( + obfuscated_class_name, obfuscated_field_name) or mappings.get_field( + obfuscated_class_name.split('$')[0], obfuscated_field_name) + uses.update(instruction_uses) + extra_code.extend(instruction_extra_code) - obfuscated_field_name = instruction['field'] - if '.' in obfuscated_field_name or ' ' in obfuscated_field_name or '(' in obfuscated_field_name: - field_type_rs, obfuscated_field_name = burger_field_to_type( - obfuscated_field_name) - if not field_type_rs: - generated_packet_code.append(f'// TODO: {instruction}') - return - field_name = mappings.get_field( - obfuscated_class_name, obfuscated_field_name) or mappings.get_field( - obfuscated_class_name.split('$')[0], obfuscated_field_name) if not field_name: generated_packet_code.append( f'// TODO: unknown field {instruction}') @@ -226,17 +328,44 @@ def burger_instruction_to_code(instruction: dict, generated_packet_code: list[st if is_var: generated_packet_code.append('#[var]') - generated_packet_code.append( - f'pub {to_snake_case(field_name)}: {field_type_rs},') - uses.update(instruction_uses) + line = f'pub {to_snake_case(field_name)}: {field_type_rs or "todo!()"},' + if field_comment: + line += f' // {field_comment}' + generated_packet_code.append(line) + + return skip -def burger_field_to_type(field) -> tuple[Optional[str], str]: +def burger_field_to_type(field, mappings: Mappings, obfuscated_class_name: str) -> tuple[Optional[str], str, Optional[str]]: + ''' + Returns field_type_rs, obfuscated_field_name, field_comment + ''' # match `(x) ? 1 : 0` match = re.match(r'\((.*)\) \? 1 : 0', field) if match: - return ('bool', match.group(1)) - return None, field + return ('bool', match.group(1), None) + match = re.match(r'^\w+\.\w+\(\)$', field) + if match: + print('field', field) + obfuscated_first = field.split('.')[0] + obfuscated_second = field.split('.')[1].split('(')[0] + first = mappings.get_field(obfuscated_class_name, obfuscated_first) + first_type = mappings.get_field_type( + obfuscated_class_name, obfuscated_first) + first_obfuscated_class_name: Optional[str] = mappings.get_class_from_deobfuscated_name( + first_type) + if first_obfuscated_class_name: + try: + second = mappings.get_method( + first_obfuscated_class_name, obfuscated_second, '') + except: + # if this happens then the field is probably from a super class + second = obfuscated_second + else: + second = obfuscated_second + first_type_short = first_type.split('.')[-1] + return (first_type_short, obfuscated_first, f'TODO: Does {first_type_short}::{second}, may not be implemented') + return None, field, None def change_packet_ids(id_map: dict[int, int], direction: str, state: str): diff --git a/codegen/lib/code/utils.py b/codegen/lib/code/utils.py index 0c22d7ba..e4671488 100644 --- a/codegen/lib/code/utils.py +++ b/codegen/lib/code/utils.py @@ -1,22 +1,31 @@ -from lib.utils import get_dir_location +from lib.utils import to_camel_case, to_snake_case, get_dir_location +from lib.mappings import Mappings +from typing import Optional import os # utilities specifically for codegen -def burger_type_to_rust_type(burger_type): +def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, instruction=None, mappings: Optional[Mappings] = None, obfuscated_class_name: Optional[str] = None): is_var = False uses = set() + # extra code, like enum definitions + extra_code = [] + + should_be_signed = False + if field_name and any(map(lambda w: w in {'x', 'y', 'z', 'xa', 'ya', 'za'}, to_snake_case(field_name).split('_'))): + # coordinates are signed + should_be_signed = True if burger_type == 'byte': - field_type_rs = 'i8' + field_type_rs = 'i8' if should_be_signed else 'u8' elif burger_type == 'short': - field_type_rs = 'i16' + field_type_rs = 'i16' if should_be_signed else 'u16' elif burger_type == 'int': - field_type_rs = 'i32' + field_type_rs = 'i32' if should_be_signed else 'u32' elif burger_type == 'long': - field_type_rs = 'i64' + field_type_rs = 'i64' if should_be_signed else 'u64' elif burger_type == 'float': field_type_rs = 'f32' elif burger_type == 'double': @@ -24,10 +33,10 @@ def burger_type_to_rust_type(burger_type): elif burger_type == 'varint': is_var = True - field_type_rs = 'i32' + field_type_rs = 'i32' if should_be_signed else 'u32' elif burger_type == 'varlong': is_var = True - field_type_rs = 'i64' + field_type_rs = 'i64' if should_be_signed else 'u64' elif burger_type == 'boolean': field_type_rs = 'bool' @@ -39,7 +48,7 @@ def burger_type_to_rust_type(burger_type): uses.add('azalea_chat::component::Component') elif burger_type == 'identifier': field_type_rs = 'ResourceLocation' - uses.add('azalea_core::resource_location::ResourceLocation') + uses.add('azalea_core::ResourceLocation') elif burger_type == 'uuid': field_type_rs = 'Uuid' uses.add('uuid::Uuid') @@ -53,17 +62,82 @@ def burger_type_to_rust_type(burger_type): uses.add('azalea_core::Slot') elif burger_type == 'metadata': field_type_rs = 'EntityMetadata' - uses.add('crate::mc_buf::EntityMetadata') - elif burger_type == 'enum': - # enums are too complicated, leave those to the user + uses.add('azalea_entity::EntityMetadata') + elif burger_type == 'abstract': field_type_rs = 'todo!()' + elif burger_type == 'enum': + if not instruction or not mappings or not obfuscated_class_name: + field_type_rs = 'todo!("enum")' + else: + # generate the whole enum :) + print(instruction) + enum_field = instruction['field'] + # enums with a.b() as the field + if '.' in enum_field: + enum_first_part_name = mappings.get_field_type( + obfuscated_class_name, enum_field.split('.')[0]) + enum_first_part_obfuscated_name = mappings.get_class_from_deobfuscated_name( + enum_first_part_name) + print('enum_first_part_obfuscated_name', + enum_first_part_obfuscated_name) + enum_name = mappings.get_method_type( + enum_first_part_obfuscated_name, enum_field.split('.')[1].split('(')[0], '') + + print('hm', enum_name) + else: + enum_name = mappings.get_field_type( + obfuscated_class_name, enum_field) + print('enum_name', enum_name) + enum_obfuscated_name = mappings.get_class_from_deobfuscated_name( + enum_name) + print('enum_obfuscated_name', enum_obfuscated_name) + enum_variants = [] + for obfuscated_field_name in mappings.fields[enum_obfuscated_name]: + field_name = mappings.get_field( + enum_obfuscated_name, obfuscated_field_name) + + # get the type just to make sure it's actually a variant and not something else + field_type = mappings.get_field_type( + enum_obfuscated_name, obfuscated_field_name) + if field_type != enum_name: + continue + + enum_variants.append(field_name) + + field_type_rs = to_camel_case( + enum_name.split('.')[-1].split('$')[-1]) + extra_code.append('') + extra_code.append(f'#[derive(McBuf, Clone, Copy, Debug)]') + extra_code.append(f'pub enum {field_type_rs} {{') + for index, variant in enumerate(enum_variants): + extra_code.append( + f' {to_camel_case(variant.lower())}={index},') + extra_code.append('}') + elif burger_type.endswith('[]'): - field_type_rs, is_var, uses = burger_type_to_rust_type( + field_type_rs, is_var, uses, extra_code = burger_type_to_rust_type( burger_type[:-2]) field_type_rs = f'Vec<{field_type_rs}>' + + # sometimes burger gives us a slightly incorrect type + if mappings and instruction: + if field_type_rs == 'Vec': + field = instruction['field'] + if field.endswith('.copy()'): + field = field[:-7] + try: + array_type = mappings.get_field_type( + obfuscated_class_name, field) + except KeyError: + print('Error getting array type', field) + return field_type_rs, is_var, uses, extra_code + if array_type == 'net.minecraft.network.FriendlyByteBuf': + field_type_rs = 'UnsizedByteArray' + uses.add('azalea_buf::UnsizedByteArray') + else: raise Exception(f'Unknown field type: {burger_type}') - return field_type_rs, is_var, uses + return field_type_rs, is_var, uses, extra_code def write_packet_file(state, packet_name_snake_case, code): diff --git a/codegen/lib/extract.py b/codegen/lib/extract.py index 4c2d2399..7c27d1ae 100644 --- a/codegen/lib/extract.py +++ b/codegen/lib/extract.py @@ -2,7 +2,9 @@ from lib.download import get_server_jar, get_burger, get_client_jar, get_generator_mod, get_yarn_data, get_fabric_api_versions from lib.utils import get_dir_location +import subprocess import json +import re import os @@ -31,15 +33,38 @@ def get_ordered_blocks_burger(version_id: str): burger_data = get_burger_data_for_version(version_id) return burger_data[0]['blocks']['ordered_blocks'] +python_command = None +def determine_python_command(): + global python_command + if python_command: + return python_command + + def try_python_command(version): + return os.system(f'{version} --version') == 0 + + for version in ('python3.9', 'python3.8', 'python3', 'python'): + if try_python_command(version): + python_command = version + return version + raise Exception('Couldn\'t determine python command to use to run burger with!') def get_burger_data_for_version(version_id: str): if not os.path.exists(get_dir_location(f'downloads/burger-{version_id}.json')): get_burger() get_client_jar(version_id) - os.system( - f'cd {get_dir_location("downloads/Burger")} && python munch.py ../client-{version_id}.jar --output ../burger-{version_id}.json' - ) + for _ in range(10): + r = subprocess.run( + f'cd {get_dir_location("downloads/Burger")} && {determine_python_command()} munch.py ../client-{version_id}.jar --output ../burger-{version_id}.json', + capture_output=True, + shell=True + ) + regex_match = re.search(r'ModuleNotFoundError: No module named \'(\w+?)\'', r.stderr.decode()) + if not regex_match: + break + missing_lib = regex_match.group(1) + print('Missing required lib for Burger:', missing_lib) + os.system(f'{determine_python_command()} -m pip install {missing_lib}') with open(get_dir_location(f'downloads/burger-{version_id}.json'), 'r') as f: return json.load(f) diff --git a/codegen/lib/mappings.py b/codegen/lib/mappings.py index fb3e8bda..6cf6273f 100644 --- a/codegen/lib/mappings.py +++ b/codegen/lib/mappings.py @@ -1,16 +1,23 @@ -class Mappings: - __slots__ = ('classes', 'fields', 'methods') +from typing import Optional - def __init__(self, classes, fields, methods): + +class Mappings: + __slots__ = ('classes', 'fields', 'methods', 'field_types', 'method_types') + + def __init__(self, classes, fields, methods, field_types, method_types): self.classes = classes self.fields = fields self.methods = methods + self.field_types = field_types + self.method_types = method_types @staticmethod def parse(mappings_txt): classes = {} fields = {} methods = {} + field_types = {} + method_types = {} current_obfuscated_class_name = None @@ -26,21 +33,28 @@ class Mappings: real_name_with_parameters = real_name_with_parameters_and_line.split( ':')[-1] - real_name = real_name_with_parameters.split('(')[0] - parameters = real_name_with_parameters.split('(')[1] + real_type, real_name = real_name_with_parameters.split('(')[ + 0].split(' ') + parameters = real_name_with_parameters.split('(')[1].split(')')[ + 0] if current_obfuscated_class_name not in methods: methods[current_obfuscated_class_name] = {} + method_types[current_obfuscated_class_name] = {} methods[current_obfuscated_class_name][ f'{obfuscated_name}({parameters})'] = real_name + method_types[current_obfuscated_class_name][ + f'{obfuscated_name}({parameters})'] = real_type else: # otherwise, it's a field real_name_with_type, obfuscated_name = line.strip().split(' -> ') - real_name = real_name_with_type.split(' ')[1] + real_type, real_name = real_name_with_type.split(' ') if current_obfuscated_class_name not in fields: fields[current_obfuscated_class_name] = {} + field_types[current_obfuscated_class_name] = {} fields[current_obfuscated_class_name][obfuscated_name] = real_name + field_types[current_obfuscated_class_name][obfuscated_name] = real_type else: # otherwise it's a class real_name, obfuscated_name = line.strip(':').split(' -> ') @@ -48,7 +62,7 @@ class Mappings: classes[obfuscated_name] = real_name - return Mappings(classes, fields, methods) + return Mappings(classes, fields, methods, field_types, method_types) def get_field(self, obfuscated_class_name, obfuscated_field_name): return self.fields.get(obfuscated_class_name, {}).get(obfuscated_field_name) @@ -57,4 +71,17 @@ class Mappings: return self.classes[obfuscated_class_name] def get_method(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature): + print(obfuscated_class_name, self.methods[obfuscated_class_name]) return self.methods[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})'] + + def get_field_type(self, obfuscated_class_name, obfuscated_field_name) -> str: + return self.field_types[obfuscated_class_name][obfuscated_field_name] + + def get_method_type(self, obfuscated_class_name, obfuscated_method_name, obfuscated_signature) -> str: + return self.method_types[obfuscated_class_name][f'{obfuscated_method_name}({obfuscated_signature})'] + + def get_class_from_deobfuscated_name(self, deobfuscated_name) -> Optional[str]: + for obfuscated_name, real_name in self.classes.items(): + if real_name == deobfuscated_name: + return obfuscated_name + return None