aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2022-08-20 15:17:07 -0500
committerGitHub <noreply@github.com>2022-08-20 15:17:07 -0500
commitdbb2092ac002790c07ad21cf7d12aabb477a2e74 (patch)
tree5d5bb1e6dbca8250292a9e0b1edc7325699bbbaf
parentac4d675d44a93a6625f508263c650206a7ff1f98 (diff)
downloadazalea-drasl-dbb2092ac002790c07ad21cf7d12aabb477a2e74.tar.xz
Implement ALL packets (#16)
* 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
-rw-r--r--azalea-buf/buf-macros/src/lib.rs4
-rw-r--r--azalea-buf/src/read.rs39
-rw-r--r--azalea-buf/src/write.rs34
-rwxr-xr-xazalea-chat/src/component.rs2
-rwxr-xr-xazalea-chat/src/style.rs297
-rwxr-xr-xazalea-chat/src/text_component.rs18
-rwxr-xr-xazalea-chat/tests/integration_test.rs2
-rw-r--r--azalea-client/src/client.rs6
-rw-r--r--azalea-client/src/movement.rs2
-rwxr-xr-xazalea-client/src/ping.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_add_experience_orb_packet.rs12
-rw-r--r--azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs18
-rw-r--r--azalea-protocol/src/packets/game/clientbound_block_destruction_packet.rs13
-rw-r--r--azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs12
-rw-r--r--azalea-protocol/src/packets/game/clientbound_block_event_packet.rs13
-rw-r--r--azalea-protocol/src/packets/game/clientbound_block_update_packet.rs3
-rw-r--r--azalea-protocol/src/packets/game/clientbound_boss_event_packet.rs143
-rw-r--r--azalea-protocol/src/packets/game/clientbound_command_suggestions_packet.rs32
-rw-r--r--[-rwxr-xr-x]azalea-protocol/src/packets/game/clientbound_commands_packet.rs (renamed from azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs)2
-rw-r--r--azalea-protocol/src/packets/game/clientbound_container_set_data_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_container_set_slot_packet.rs12
-rw-r--r--azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_custom_chat_completions_packet.rs2
-rw-r--r--azalea-protocol/src/packets/game/clientbound_custom_sound_packet.rs20
-rw-r--r--azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs1
-rw-r--r--azalea-protocol/src/packets/game/clientbound_explode_packet.rs118
-rw-r--r--azalea-protocol/src/packets/game/clientbound_forget_level_chunk_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_horse_screen_open_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/clientbound_level_event_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_light_update_packet.rs2
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_login_packet.rs4
-rw-r--r--azalea-protocol/src/packets/game/clientbound_map_item_data_packet.rs119
-rw-r--r--azalea-protocol/src/packets/game/clientbound_merchant_offers_packet.rs30
-rw-r--r--azalea-protocol/src/packets/game/clientbound_move_entity_pos_rot_packet.rs (renamed from azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs)2
-rw-r--r--azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs2
-rw-r--r--azalea-protocol/src/packets/game/clientbound_move_vehicle_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_open_book_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs13
-rw-r--r--azalea-protocol/src/packets/game/clientbound_open_sign_editor_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_ping_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/clientbound_place_ghost_recipe_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_combat_end_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_combat_enter_packet.rs5
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_combat_kill_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_player_look_at_packet.rs24
-rw-r--r--azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_resource_pack_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_respawn_packet.rs16
-rw-r--r--azalea-protocol/src/packets/game/clientbound_select_advancements_tab_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_action_bar_text_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_border_center_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_border_lerp_size_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_border_size_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_border_warning_delay_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_border_warning_distance_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_camera_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_chunk_cache_radius_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_display_objective_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs2
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_entity_motion_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_objective_packet.rs59
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_passengers_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_player_team_packet.rs80
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_score_packet.rs61
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_simulation_distance_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_subtitle_text_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_title_text_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/clientbound_set_titles_animation_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs16
-rw-r--r--azalea-protocol/src/packets/game/clientbound_sound_packet.rs5
-rw-r--r--azalea-protocol/src/packets/game/clientbound_stop_sound_packet.rs51
-rw-r--r--azalea-protocol/src/packets/game/clientbound_tab_list_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/clientbound_take_item_entity_packet.rs12
-rwxr-xr-xazalea-protocol/src/packets/game/mod.rs210
-rw-r--r--azalea-protocol/src/packets/game/serverbound_block_entity_tag_query.rs10
-rw-r--r--azalea-protocol/src/packets/game/serverbound_change_difficulty_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_client_command_packet.rs13
-rw-r--r--azalea-protocol/src/packets/game/serverbound_client_information_packet.rs27
-rw-r--r--azalea-protocol/src/packets/game/serverbound_command_suggestion_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/serverbound_container_button_click_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_container_click_packet.rs26
-rw-r--r--azalea-protocol/src/packets/game/serverbound_container_close_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/serverbound_edit_book_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/serverbound_entity_tag_query.rs10
-rw-r--r--azalea-protocol/src/packets/game/serverbound_interact_packet.rs85
-rw-r--r--azalea-protocol/src/packets/game/serverbound_jigsaw_generate_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/serverbound_lock_difficulty_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/serverbound_move_player_pos_packet.rs (renamed from azalea-protocol/src/packets/game/serverbound_move_player_packet_pos.rs)0
-rw-r--r--azalea-protocol/src/packets/game/serverbound_move_player_pos_rot_packet.rs (renamed from azalea-protocol/src/packets/game/serverbound_move_player_packet_pos_rot.rs)0
-rw-r--r--azalea-protocol/src/packets/game/serverbound_move_player_rot_packet.rs (renamed from azalea-protocol/src/packets/game/serverbound_move_player_packet_rot.rs)0
-rw-r--r--azalea-protocol/src/packets/game/serverbound_move_player_status_only_packet.rs (renamed from azalea-protocol/src/packets/game/serverbound_move_player_packet_status_only.rs)0
-rw-r--r--azalea-protocol/src/packets/game/serverbound_move_vehicle_packet.rs11
-rw-r--r--azalea-protocol/src/packets/game/serverbound_paddle_boat_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_pick_item_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_place_recipe_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/serverbound_player_abilities_packet.rs28
-rw-r--r--azalea-protocol/src/packets/game/serverbound_player_action_packet.rs24
-rw-r--r--azalea-protocol/src/packets/game/serverbound_player_command_packet.rs24
-rw-r--r--azalea-protocol/src/packets/game/serverbound_player_input_packet.rs43
-rw-r--r--azalea-protocol/src/packets/game/serverbound_pong_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/serverbound_recipe_book_change_settings_packet.rs17
-rw-r--r--azalea-protocol/src/packets/game/serverbound_recipe_book_seen_recipe_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_rename_item_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/serverbound_resource_pack_packet.rs15
-rw-r--r--azalea-protocol/src/packets/game/serverbound_seen_advancements_packet.rs38
-rw-r--r--azalea-protocol/src/packets/game/serverbound_select_trade_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_beacon_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_carried_item_packet.rs7
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_command_block_packet.rs64
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_command_minecart_packet.rs10
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_creative_mode_slot_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_jigsaw_block_packet.rs44
-rw-r--r--azalea-protocol/src/packets/game/serverbound_set_structure_block_packet.rs96
-rw-r--r--azalea-protocol/src/packets/game/serverbound_sign_update_packet.rs9
-rw-r--r--azalea-protocol/src/packets/game/serverbound_swing_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_teleport_to_entity_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/serverbound_use_item_on_packet.rs54
-rw-r--r--azalea-protocol/src/packets/game/serverbound_use_item_packet.rs10
-rwxr-xr-xazalea-protocol/src/packets/login/mod.rs5
-rw-r--r--azalea-protocol/src/packets/login/serverbound_custom_query_packet.rs9
-rw-r--r--azalea-protocol/src/packets/status/clientbound_pong_response_packet.rs7
-rwxr-xr-xazalea-protocol/src/packets/status/mod.rs4
-rw-r--r--azalea-protocol/src/packets/status/serverbound_ping_request_packet.rs7
-rw-r--r--azalea-world/src/entity.rs7
-rw-r--r--codegen/lib/code/packet.py189
-rw-r--r--codegen/lib/code/utils.py102
-rw-r--r--codegen/lib/extract.py31
-rw-r--r--codegen/lib/mappings.py39
129 files changed, 2800 insertions, 223 deletions
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<K: McBufReadable + Send + Eq + Hash, V: McBufReadable + Send> McBufReadable
}
}
+impl<K: McBufReadable + Send + Eq + Hash, V: McBufVarReadable + Send> McBufVarReadable
+ for HashMap<K, V>
+{
+ default fn var_read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ 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<u8> {
fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
buf.read_byte_array()
@@ -386,3 +401,27 @@ impl<T: McBufReadable> McBufReadable for Option<T> {
})
}
}
+
+impl<T: McBufVarReadable> McBufVarReadable for Option<T> {
+ default fn var_read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ let present = buf.read_boolean()?;
+ Ok(if present {
+ Some(T::var_read_from(buf)?)
+ } else {
+ None
+ })
+ }
+}
+
+// [String; 4]
+impl<T: McBufReadable, const N: usize> McBufReadable for [T; N] {
+ default fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ 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<K: McBufWritable, V: McBufWritable> McBufWritable for HashMap<K, V> {
}
}
+impl<K: McBufWritable, V: McBufVarWritable> McBufVarWritable for HashMap<K, V> {
+ 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<u8> {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
buf.write_byte_array(self)
@@ -284,3 +296,25 @@ impl<T: McBufWritable> McBufWritable for Option<T> {
Ok(())
}
}
+
+impl<T: McBufVarWritable> McBufVarWritable for Option<T> {
+ 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<T: McBufWritable, const N: usize> 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<u32>,
-}
-
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);
-
- 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,
+#[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,
+}
+
+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<u32>,
- ) -> 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<ChatFormatting> {
+ 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<u32> {
+ 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<ChatFormatting<'_>> for TextColor {
+impl TryFrom<ChatFormatting> for TextColor {
type Error = String;
- fn try_from(formatter: ChatFormatting<'_>) -> Result<Self, Self::Error> {
- if formatter.is_format {
- return Err(format!("{} is not a color", formatter.name));
+ fn try_from(formatter: ChatFormatting) -> Result<Self, Self::Error> {
+ 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<Stat, i32>,
+}
+
+#[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<Self, BufReadError> {
+ 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<Self, BufReadError> {
+ 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<Self, BufReadError> {
+ // 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
index 622b9ec7..f3ae4ab9 100755..100644
--- 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<BrigadierNodeStub>,
#[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<String>,
}
-#[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<BlockPos>,
+ pub knockback_x: f32,
+ pub knockback_y: f32,
+ pub knockback_z: f32,
+}
+
+impl McBufReadable for ClientboundExplodePacket {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ 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<MapDecoration>,
+ pub color_patch: Option<MapPatch>,
+}
+
+impl McBufReadable for ClientboundMapItemDataPacket {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ let map_id = u32::var_read_from(buf)?;
+ let scale = u8::read_from(buf)?;
+ let locked = bool::read_from(buf)?;
+ let decorations = Vec::<MapDecoration>::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::<u8>::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<Component>,
+}
+
+#[derive(Debug, Clone)]
+pub struct MapPatch {
+ pub start_x: u8,
+ pub start_y: u8,
+ pub width: u8,
+ pub height: u8,
+ pub map_colors: Vec<u8>,
+}
+
+#[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<MerchantOffer>,
+ #[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
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<AtEntity>,
+}
+
+#[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<Component>,
+}
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<GlobalPos>,
+}
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<ResourceLocation>,
+}
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<Self, BufReadError> {
+ 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<u32>,
+}
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<Self, BufReadError> {
+ 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<String>;
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<String>,
+}
+
+impl McBufReadable for ClientboundSetScorePacket {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ 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<SoundSource>,
+ pub name: Option<ResourceLocation>,
+}
+
+impl McBufReadable for ClientboundStopSoundPacket {
+ fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
+ 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<u16, Slot>,
+}
+
+#[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<String>,
+ pub title: Option<String>,
+}
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<Self, BufReadError> {
+ 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
index 9e70eec6..9e70eec6 100644
--- a/azalea-protocol/src/packets/game/serverbound_move_player_packet_pos.rs
+++ b/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
index 6933a724..6933a724 100644
--- 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
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
index 493c5eab..493c5eab 100644
--- a/azalea-protocol/src/packets/game/serverbound_move_player_packet_rot.rs
+++ b/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
index 8b08154b..8b08154b 100644
--- 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
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<Self, BufReadError> {
+ 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<Self, BufReadError> {
+ 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<ResourceLocation>,
+}
+
+#[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<Self, BufReadError> {
+ 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<u32>,
+ #[var]
+ pub secondary: Option<u32>,
+}
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<Self, BufReadError> {
+ 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<Self, BufReadError> {
+ 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<Self, BufReadError> {
+ 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<Self, BufReadError> {
+ 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<UnsizedByteArray>,
+}
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<F>(&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)
-
- 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)
+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<T>
+ 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)
+
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<u8>':
+ 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 @@
+from typing import Optional
+
+
class Mappings:
- __slots__ = ('classes', 'fields', 'methods')
+ __slots__ = ('classes', 'fields', 'methods', 'field_types', 'method_types')
- def __init__(self, classes, fields, methods):
+ 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