From 9dacd90abcfaa62ade1e4f130ed53da2c9facdbc Mon Sep 17 00:00:00 2001 From: mat Date: Sun, 1 May 2022 13:51:59 -0500 Subject: [PATCH] clientbound_add_entity_packet & clientbound_set_entity_data_packet --- azalea-client/README.md | 2 +- azalea-client/src/connect.rs | 5 +- azalea-core/src/block_pos.rs | 6 + azalea-core/src/direction.rs | 9 + azalea-core/src/lib.rs | 6 + azalea-protocol/packet-macros/src/lib.rs | 205 +++++---- azalea-protocol/src/mc_buf/read.rs | 57 ++- azalea-protocol/src/mc_buf/write.rs | 37 +- .../game/clientbound_add_entity_packet.rs | 22 + ...ientbound_level_chunk_with_light_packet.rs | 6 + .../clientbound_set_entity_data_packet.rs | 419 ++++++++++++++++++ azalea-protocol/src/packets/game/mod.rs | 4 + .../serverbound_status_request_packet.rs | 1 - bot/src/main.rs | 2 +- 14 files changed, 660 insertions(+), 121 deletions(-) create mode 100644 azalea-core/src/block_pos.rs create mode 100644 azalea-core/src/direction.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs create mode 100644 azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs diff --git a/azalea-client/README.md b/azalea-client/README.md index 9b51356e..296cab07 100755 --- a/azalea-client/README.md +++ b/azalea-client/README.md @@ -1,3 +1,3 @@ # Azalea Client -A library that can mimic everything a normal Minecraft client can do. If you want to make a bot with higher-level functions, you should use `azalea` instead. +A library that can mimic everything a normal Minecraft client can do. If you want to make a bot with higher-level functions, you should use the `azalea` crate instead. diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs index b6915fe8..c09d7d9e 100755 --- a/azalea-client/src/connect.rs +++ b/azalea-client/src/connect.rs @@ -200,7 +200,7 @@ impl Client { println!("Got update tags packet"); } GamePacket::ClientboundDisconnectPacket(p) => { - println!("Got login disconnect packet {:?}", p); + println!("Got disconnect packet {:?}", p); } GamePacket::ClientboundUpdateRecipesPacket(p) => { println!("Got update recipes packet"); @@ -230,6 +230,9 @@ impl Client { GamePacket::ClientboundAddMobPacket(p) => { println!("Got add mob packet {:?}", p); } + GamePacket::ClientboundAddEntityPacket(p) => { + println!("Got add entity packet {:?}", p); + } _ => panic!("Unexpected packet {:?}", packet), } println!(); diff --git a/azalea-core/src/block_pos.rs b/azalea-core/src/block_pos.rs new file mode 100644 index 00000000..96a234cb --- /dev/null +++ b/azalea-core/src/block_pos.rs @@ -0,0 +1,6 @@ +#[derive(Clone, Copy, Debug)] +pub struct BlockPos { + pub x: i32, + pub y: i32, + pub z: i32, +} diff --git a/azalea-core/src/direction.rs b/azalea-core/src/direction.rs new file mode 100644 index 00000000..721f21a0 --- /dev/null +++ b/azalea-core/src/direction.rs @@ -0,0 +1,9 @@ +#[derive(Clone, Copy, Debug)] +pub enum Direction { + Down = 0, + Up = 1, + North = 2, + South = 3, + West = 4, + East = 5, +} diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs index 6f52e7e9..c6b51cb1 100755 --- a/azalea-core/src/lib.rs +++ b/azalea-core/src/lib.rs @@ -7,3 +7,9 @@ pub mod serializable_uuid; mod slot; pub use slot::{Slot, SlotData}; + +mod block_pos; +pub use block_pos::BlockPos; + +mod direction; +pub use direction::Direction; diff --git a/azalea-protocol/packet-macros/src/lib.rs b/azalea-protocol/packet-macros/src/lib.rs index 0c98f4a3..6d1789a8 100755 --- a/azalea-protocol/packet-macros/src/lib.rs +++ b/azalea-protocol/packet-macros/src/lib.rs @@ -7,105 +7,146 @@ use syn::{ }; fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream { - let fields = match data { - syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, - _ => panic!("#[derive(*Packet)] can only be used on structs"), - }; - let FieldsNamed { named, .. } = match fields { - syn::Fields::Named(f) => f, - _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), - }; + match data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => { + let FieldsNamed { named, .. } = match fields { + syn::Fields::Named(f) => f, + _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), + }; - let read_fields = named - .iter() - .map(|f| { - let field_name = &f.ident; - let field_type = &f.ty; - // 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(_) => { - if f.attrs.iter().any(|a| a.path.is_ident("varint")) { - quote! { - let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?; - } - } else { - quote! { - let #field_name = crate::mc_buf::McBufReadable::read_into(buf).await?; + let read_fields = named + .iter() + .map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + // 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(_) => { + if f.attrs.iter().any(|a| a.path.is_ident("varint")) { + quote! { + let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?; + } + } else { + quote! { + let #field_name = crate::mc_buf::McBufReadable::read_into(buf).await?; + } } + } + _ => panic!( + "Error reading field {}: {}", + field_name.clone().unwrap(), + field_type.to_token_stream() + ), + } + }) + .collect::>(); + let read_field_names = named.iter().map(|f| &f.ident).collect::>(); + + quote! { + #[async_trait::async_trait] + impl crate::mc_buf::McBufReadable for #ident { + async fn read_into(buf: &mut R) -> Result + where + R: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send, + { + #(#read_fields)* + Ok(#ident { + #(#read_field_names: #read_field_names),* + }) + } + } + } + } + syn::Data::Enum(syn::DataEnum { variants, .. }) => { + let mut match_contents = quote!(); + for variant in variants { + let variant_name = &variant.ident; + let variant_discrim = &variant + .discriminant + .as_ref() + .expect("enum variant must have a discriminant") + .1; + match_contents.extend(quote! { + #variant_discrim => Ok(Self::#variant_name), + }); + } + + quote! { + #[async_trait::async_trait] + impl crate::mc_buf::McBufReadable for #ident { + async fn read_into(buf: &mut R) -> Result + where + R: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send, + { + let id = buf.read_varint().await?; + match id { + #match_contents + _ => Err(format!("Unknown enum variant {}", id)), } } - _ => panic!( - "Error reading field {}: {}", - field_name.clone().unwrap(), - field_type.to_token_stream() - ), } - }) - .collect::>(); - let read_field_names = named.iter().map(|f| &f.ident).collect::>(); - - quote! { - #[async_trait::async_trait] - impl crate::mc_buf::McBufReadable for #ident { - async fn read_into(buf: &mut R) -> Result - where - R: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send, - { - #(#read_fields)* - Ok(#ident { - #(#read_field_names: #read_field_names),* - }) + } } - } + _ => panic!("#[derive(*Packet)] can only be used on structs"), } } fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream { - let fields = match data { - syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, - _ => panic!("#[derive(*Packet)] can only be used on structs"), - }; - let FieldsNamed { named, .. } = match fields { - syn::Fields::Named(f) => f, - _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), - }; + match data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => { + let FieldsNamed { named, .. } = match fields { + syn::Fields::Named(f) => f, + _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), + }; - let write_fields = named - .iter() - .map(|f| { - let field_name = &f.ident; - let field_type = &f.ty; - // 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(_) => { - if f.attrs.iter().any(|attr| attr.path.is_ident("varint")) { - quote! { - crate::mc_buf::McBufVarintWritable::varint_write_into(&self.#field_name, buf)?; - } - } else { - quote! { - crate::mc_buf::McBufWritable::write_into(&self.#field_name, buf)?; + let write_fields = named + .iter() + .map(|f| { + let field_name = &f.ident; + let field_type = &f.ty; + // 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(_) => { + if f.attrs.iter().any(|attr| attr.path.is_ident("varint")) { + quote! { + crate::mc_buf::McBufVarintWritable::varint_write_into(&self.#field_name, buf)?; + } + } else { + quote! { + crate::mc_buf::McBufWritable::write_into(&self.#field_name, buf)?; + } } } + _ => panic!( + "Error writing field {}: {}", + field_name.clone().unwrap(), + field_type.to_token_stream() + ), } - _ => panic!( - "Error writing field {}: {}", - field_name.clone().unwrap(), - field_type.to_token_stream() - ), - } - }) - .collect::>(); + }) + .collect::>(); - quote! { - impl crate::mc_buf::McBufWritable for #ident { - fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - #(#write_fields)* - Ok(()) + quote! { + impl crate::mc_buf::McBufWritable for #ident { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + #(#write_fields)* + Ok(()) + } + } } } + syn::Data::Enum(syn::DataEnum { .. }) => { + quote! { + impl crate::mc_buf::McBufWritable for #ident { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + crate::mc_buf::Writable::write_varint(buf, *self as i32) + } + } + } + } + _ => panic!("#[derive(*Packet)] can only be used on structs"), } } diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-protocol/src/mc_buf/read.rs index b345aac9..53c137b3 100755 --- a/azalea-protocol/src/mc_buf/read.rs +++ b/azalea-protocol/src/mc_buf/read.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use azalea_chat::component::Component; use azalea_core::{ difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, - serializable_uuid::SerializableUuid, Slot, SlotData, + serializable_uuid::SerializableUuid, BlockPos, Direction, Slot, SlotData, }; use serde::Deserialize; use tokio::io::{AsyncRead, AsyncReadExt}; @@ -473,29 +473,14 @@ impl McBufReadable for Option { // Option #[async_trait] -impl McBufReadable for Option { - async fn read_into(buf: &mut R) -> Result +impl McBufReadable for Option { + default async fn read_into(buf: &mut R) -> Result where R: AsyncRead + std::marker::Unpin + std::marker::Send, { let present = buf.read_boolean().await?; Ok(if present { - Some(buf.read_utf().await?) - } else { - None - }) - } -} -// Option -#[async_trait] -impl McBufReadable for Option { - async fn read_into(buf: &mut R) -> Result - where - R: AsyncRead + std::marker::Unpin + std::marker::Send, - { - let present = buf.read_boolean().await?; - Ok(if present { - Some(Component::read_into(buf).await?) + Some(T::read_into(buf).await?) } else { None }) @@ -567,3 +552,37 @@ impl McBufReadable for Uuid { buf.read_uuid().await } } + +// BlockPos +#[async_trait] +impl McBufReadable for BlockPos { + async fn read_into(buf: &mut R) -> Result + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + let val = u64::read_into(buf).await?; + let x = (val >> 38) as i32; + let y = (val & 0xFFF) as i32; + let z = ((val >> 12) & 0x3FFFFFF) as i32; + Ok(BlockPos { x, y, z }) + } +} + +// Direction +#[async_trait] +impl McBufReadable for Direction { + async fn read_into(buf: &mut R) -> Result + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + match buf.read_varint().await? { + 0 => Ok(Self::Down), + 1 => Ok(Self::Up), + 2 => Ok(Self::North), + 3 => Ok(Self::South), + 4 => Ok(Self::West), + 5 => Ok(Self::East), + _ => Err("Invalid direction".to_string()), + } + } +} diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs index 4c7ac60c..e5437ae8 100755 --- a/azalea-protocol/src/mc_buf/write.rs +++ b/azalea-protocol/src/mc_buf/write.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use azalea_chat::component::Component; use azalea_core::{ difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, - serializable_uuid::SerializableUuid, Slot, + serializable_uuid::SerializableUuid, BlockPos, Direction, Slot, }; use byteorder::{BigEndian, WriteBytesExt}; use std::io::Write; @@ -336,21 +336,8 @@ impl McBufWritable for Option { } // Option -impl McBufWritable for Option { - fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - if let Some(s) = self { - buf.write_boolean(true)?; - buf.write_utf(s)?; - } else { - buf.write_boolean(false)?; - }; - Ok(()) - } -} - -// Option -impl McBufWritable for Option { - fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { +impl McBufWritable for Option { + default fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { if let Some(s) = self { buf.write_boolean(true)?; s.write_into(buf)?; @@ -418,3 +405,21 @@ impl McBufWritable for Uuid { Ok(()) } } + +// BlockPos +impl McBufWritable for BlockPos { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + buf.write_long( + (((self.x & 0x3FFFFFF) as i64) << 38) + | (((self.z & 0x3FFFFFF) as i64) << 12) + | ((self.y & 0xFFF) as i64), + ) + } +} + +// Direction +impl McBufWritable for Direction { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + buf.write_varint(*self as i32) + } +} diff --git a/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs new file mode 100644 index 00000000..f45e71c9 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs @@ -0,0 +1,22 @@ +use packet_macros::GamePacket; +use uuid::Uuid; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundAddEntityPacket { + #[varint] + pub id: i32, + pub uuid: Uuid, + // TODO: have an entity type struct + #[varint] + pub entity_type: i32, + pub x: f64, + pub y: f64, + pub z: f64, + pub x_rot: i8, + pub y_rot: i8, + // pub y_head_rot: i8, + pub data: i32, + pub x_vel: u16, + pub y_vel: u16, + pub z_vel: u16, +} diff --git a/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs index b916cb8e..1d017c2a 100644 --- a/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs @@ -26,3 +26,9 @@ pub struct BlockEntity { type_: i32, data: azalea_nbt::Tag, } + +pub struct ChunkSection {} + +impl ClientboundLevelChunkPacketData { + pub fn read(world_height: u32) {} +} 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 new file mode 100644 index 00000000..4cc456f3 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs @@ -0,0 +1,419 @@ +use crate::{ + mc_buf::{Readable, Writable}, + packets::{McBufReadable, McBufWritable}, +}; +use async_trait::async_trait; +use azalea_chat::component::Component; +use azalea_core::{BlockPos, Direction, Slot}; +use packet_macros::{GamePacket, McBufReadable, McBufWritable}; +use tokio::io::AsyncRead; +use uuid::Uuid; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundSetEntityDataPacket { + #[varint] + pub id: i32, + pub metadata: Vec, +} + +#[derive(Clone, Debug)] +pub struct EntityDataItem { + // we can't identify what the index is for here because we don't know the + // entity type + pub index: u8, + pub value: EntityDataValue, +} + +#[async_trait] +impl McBufReadable for Vec { + async fn read_into(buf: &mut R) -> Result + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + let mut metadata = Vec::new(); + loop { + let index = buf.read_byte().await?; + if index == 0xff { + break; + } + let value = EntityDataValue::read_into(buf).await?; + metadata.push(EntityDataItem { index, value }); + } + Ok(metadata) + } +} + +impl McBufWritable for Vec { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + for item in self { + buf.write_byte(item.index)?; + item.value.write_into(buf)?; + } + buf.write_byte(0xff)?; + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub enum EntityDataValue { + Byte(u8), + // varint + Int(i32), + Float(f32), + String(String), + Component(Component), + OptionalComponent(Option), + ItemStack(Slot), + Boolean(bool), + Rotations { x: f32, y: f32, z: f32 }, + BlockPos(BlockPos), + OptionalBlockPos(Option), + Direction(Direction), + OptionalUuid(Option), + // 0 for absent (implies air); otherwise, a block state ID as per the global palette + // this is a varint + OptionalBlockState(Option), + CompoundTag(azalea_nbt::Tag), + Particle(Particle), + VillagerData(VillagerData), + // 0 for absent; 1 + actual value otherwise. Used for entity IDs. + OptionalUnsignedInt(Option), + Pose(Pose), +} + +#[async_trait] +impl McBufReadable for EntityDataValue { + async fn read_into(buf: &mut R) -> Result + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + let type_ = buf.read_varint().await?; + Ok(match type_ { + 0 => EntityDataValue::Byte(buf.read_byte().await?), + 1 => EntityDataValue::Int(buf.read_varint().await?), + 2 => EntityDataValue::Float(buf.read_float().await?), + 3 => EntityDataValue::String(buf.read_utf().await?), + 4 => EntityDataValue::Component(Component::read_into(buf).await?), + 5 => EntityDataValue::OptionalComponent(Option::::read_into(buf).await?), + 6 => EntityDataValue::ItemStack(Slot::read_into(buf).await?), + 7 => EntityDataValue::Boolean(buf.read_boolean().await?), + 8 => EntityDataValue::Rotations { + x: buf.read_float().await?, + y: buf.read_float().await?, + z: buf.read_float().await?, + }, + 9 => EntityDataValue::BlockPos(BlockPos::read_into(buf).await?), + 10 => EntityDataValue::OptionalBlockPos(Option::::read_into(buf).await?), + 11 => EntityDataValue::Direction(Direction::read_into(buf).await?), + 12 => EntityDataValue::OptionalUuid(Option::::read_into(buf).await?), + 13 => EntityDataValue::OptionalBlockState({ + let val = i32::read_into(buf).await?; + if val == 0 { + None + } else { + Some(val) + } + }), + 14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_into(buf).await?), + 15 => EntityDataValue::Particle(Particle::read_into(buf).await?), + 16 => EntityDataValue::VillagerData(VillagerData::read_into(buf).await?), + 17 => EntityDataValue::OptionalUnsignedInt({ + let val = buf.read_varint().await?; + if val == 0 { + None + } else { + Some((val - 1) as u32) + } + }), + 18 => EntityDataValue::Pose(Pose::read_into(buf).await?), + _ => return Err(format!("Unknown entity data type: {}", type_)), + }) + } +} + +impl McBufWritable for EntityDataValue { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + todo!(); + } +} + +#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)] +pub enum Pose { + Standing = 0, + FallFlying = 1, + Sleeping = 2, + Swimming = 3, + SpinAttack = 4, + Sneaking = 5, + LongJumping = 6, + Dying = 7, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct VillagerData { + #[varint] + type_: u32, + #[varint] + profession: u32, + #[varint] + level: u32, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct Particle { + #[varint] + pub id: i32, + pub data: ParticleData, +} + +#[derive(Clone, Debug)] +pub enum ParticleData { + AmbientEntityEffect, + AngryVillager, + Block(BlockParticle), + BlockMarker(BlockParticle), + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + FallingLava, + LandingLava, + DrippingWater, + FallingWater, + Dust(DustParticle), + DustColorTransition(DustColorTransitionParticle), + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust(BlockParticle), + Firework, + Fishing, + Flame, + SoulFireFlame, + Soul, + Flash, + HappyVillager, + Composter, + Heart, + InstantEffect, + Item(ItemParticle), + Vibration(VibrationParticle), + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Sneeze, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BubblePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, + CampfireCozySmoke, + CampfireSignalSmoke, + DrippingHoney, + FallingHoney, + LandingHoney, + FallingNectar, + FallingSporeBlossom, + Ash, + CrimsonSpore, + WarpedSpore, + SporeBlossomAir, + DrippingObsidianTear, + FallingObsidianTear, + LandingObsidianTear, + ReversePortal, + WhiteAsh, + SmallFlame, + Snowflake, + DrippingDripstoneLava, + FallingDripstoneLava, + DrippingDripstoneWater, + FallingDripstoneWater, + GlowSquidInk, + Glow, + WaxOn, + WaxOff, + ElectricSpark, + Scrape, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct BlockParticle { + #[varint] + pub block_state: i32, +} +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct DustParticle { + /// Red value, 0-1 + pub red: f32, + /// Green value, 0-1 + pub green: f32, + /// Blue value, 0-1 + pub blue: f32, + /// The scale, will be clamped between 0.01 and 4. + pub scale: f32, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct DustColorTransitionParticle { + /// Red value, 0-1 + pub from_red: f32, + /// Green value, 0-1 + pub from_green: f32, + /// Blue value, 0-1 + pub from_blue: f32, + /// The scale, will be clamped between 0.01 and 4. + pub scale: f32, + /// Red value, 0-1 + pub to_red: f32, + /// Green value, 0-1 + pub to_green: f32, + /// Blue value, 0-1 + pub to_blue: f32, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct ItemParticle { + pub item: Slot, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct VibrationParticle { + pub origin: BlockPos, + pub position_type: String, + pub block_position: BlockPos, + #[varint] + pub entity_id: u32, + #[varint] + pub ticks: u32, +} + +#[async_trait] +impl McBufReadable for ParticleData { + async fn read_into(buf: &mut R) -> Result + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + let id = buf.read_varint().await?; + Ok(match id { + 0 => ParticleData::AmbientEntityEffect, + 1 => ParticleData::AngryVillager, + 2 => ParticleData::Block(BlockParticle::read_into(buf).await?), + 3 => ParticleData::BlockMarker(BlockParticle::read_into(buf).await?), + 4 => ParticleData::Bubble, + 5 => ParticleData::Cloud, + 6 => ParticleData::Crit, + 7 => ParticleData::DamageIndicator, + 8 => ParticleData::DragonBreath, + 9 => ParticleData::DrippingLava, + 10 => ParticleData::FallingLava, + 11 => ParticleData::LandingLava, + 12 => ParticleData::DrippingWater, + 13 => ParticleData::FallingWater, + 14 => ParticleData::Dust(DustParticle::read_into(buf).await?), + 15 => ParticleData::DustColorTransition( + DustColorTransitionParticle::read_into(buf).await?, + ), + 16 => ParticleData::Effect, + 17 => ParticleData::ElderGuardian, + 18 => ParticleData::EnchantedHit, + 19 => ParticleData::Enchant, + 20 => ParticleData::EndRod, + 21 => ParticleData::EntityEffect, + 22 => ParticleData::ExplosionEmitter, + 23 => ParticleData::Explosion, + 24 => ParticleData::FallingDust(BlockParticle::read_into(buf).await?), + 25 => ParticleData::Firework, + 26 => ParticleData::Fishing, + 27 => ParticleData::Flame, + 28 => ParticleData::SoulFireFlame, + 29 => ParticleData::Soul, + 30 => ParticleData::Flash, + 31 => ParticleData::HappyVillager, + 32 => ParticleData::Composter, + 33 => ParticleData::Heart, + 34 => ParticleData::InstantEffect, + 35 => ParticleData::Item(ItemParticle::read_into(buf).await?), + 36 => ParticleData::Vibration(VibrationParticle::read_into(buf).await?), + 37 => ParticleData::ItemSlime, + 38 => ParticleData::ItemSnowball, + 39 => ParticleData::LargeSmoke, + 40 => ParticleData::Lava, + 41 => ParticleData::Mycelium, + 42 => ParticleData::Note, + 43 => ParticleData::Poof, + 44 => ParticleData::Portal, + 45 => ParticleData::Rain, + 46 => ParticleData::Smoke, + 47 => ParticleData::Sneeze, + 48 => ParticleData::Spit, + 49 => ParticleData::SquidInk, + 50 => ParticleData::SweepAttack, + 51 => ParticleData::TotemOfUndying, + 52 => ParticleData::Underwater, + 53 => ParticleData::Splash, + 54 => ParticleData::Witch, + 55 => ParticleData::BubblePop, + 56 => ParticleData::CurrentDown, + 57 => ParticleData::BubbleColumnUp, + 58 => ParticleData::Nautilus, + 59 => ParticleData::Dolphin, + 60 => ParticleData::CampfireCozySmoke, + 61 => ParticleData::CampfireSignalSmoke, + 62 => ParticleData::DrippingHoney, + 63 => ParticleData::FallingHoney, + 64 => ParticleData::LandingHoney, + 65 => ParticleData::FallingNectar, + 66 => ParticleData::FallingSporeBlossom, + 67 => ParticleData::Ash, + 68 => ParticleData::CrimsonSpore, + 69 => ParticleData::WarpedSpore, + 70 => ParticleData::SporeBlossomAir, + 71 => ParticleData::DrippingObsidianTear, + 72 => ParticleData::FallingObsidianTear, + 73 => ParticleData::LandingObsidianTear, + 74 => ParticleData::ReversePortal, + 75 => ParticleData::WhiteAsh, + 76 => ParticleData::SmallFlame, + 77 => ParticleData::Snowflake, + 78 => ParticleData::DrippingDripstoneLava, + 79 => ParticleData::FallingDripstoneLava, + 80 => ParticleData::DrippingDripstoneWater, + 81 => ParticleData::FallingDripstoneWater, + 82 => ParticleData::GlowSquidInk, + 83 => ParticleData::Glow, + 84 => ParticleData::WaxOn, + 85 => ParticleData::WaxOff, + 86 => ParticleData::ElectricSpark, + 87 => ParticleData::Scrape, + _ => return Err(format!("Unknown particle id: {}", id)), + }) + } +} + +impl McBufWritable for ParticleData { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + todo!() + } +} diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs index aac1a9a0..e27255ac 100755 --- a/azalea-protocol/src/packets/game/mod.rs +++ b/azalea-protocol/src/packets/game/mod.rs @@ -1,3 +1,4 @@ +pub mod clientbound_add_entity_packet; pub mod clientbound_add_mob_packet; pub mod clientbound_change_difficulty_packet; pub mod clientbound_custom_payload_packet; @@ -13,6 +14,7 @@ pub mod clientbound_player_position_packet; pub mod clientbound_recipe_packet; pub mod clientbound_set_carried_item_packet; pub mod clientbound_set_chunk_cache_center; +pub mod clientbound_set_entity_data_packet; pub mod clientbound_update_recipes_packet; pub mod clientbound_update_tags_packet; pub mod clientbound_update_view_distance_packet; @@ -26,6 +28,7 @@ declare_state_packets!( 0x0a: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, }, Clientbound => { + 0x00: clientbound_add_entity_packet::ClientboundAddEntityPacket, 0x02: clientbound_add_mob_packet::ClientboundAddMobPacket, 0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket, 0x12: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket, @@ -42,6 +45,7 @@ declare_state_packets!( 0x48: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket, 0x49: clientbound_set_chunk_cache_center::ClientboundSetChunkCacheCenterPacket, 0x4a: clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket, + 0x4d: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket, 0x66: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket, 0x67: clientbound_update_tags_packet::ClientboundUpdateTagsPacket } diff --git a/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs b/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs index e77687ec..c15673d9 100755 --- a/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs +++ b/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs @@ -1,5 +1,4 @@ use packet_macros::StatusPacket; -use std::hash::Hash; #[derive(Clone, Debug, StatusPacket)] pub struct ServerboundStatusRequestPacket {} diff --git a/bot/src/main.rs b/bot/src/main.rs index 0b67cc44..8314eb5c 100644 --- a/bot/src/main.rs +++ b/bot/src/main.rs @@ -5,7 +5,7 @@ async fn main() { println!("Hello, world!"); // let address = "95.111.249.143:10000"; - let address = "172.23.192.1:51015"; + let address = "172.23.192.1:58024"; // let response = azalea_client::ping::ping_server(&address.try_into().unwrap()) // .await // .unwrap();