mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
clientbound_add_entity_packet & clientbound_set_entity_data_packet
This commit is contained in:
parent
4b1cfd1cf8
commit
9dacd90abc
14 changed files with 660 additions and 121 deletions
|
@ -1,3 +1,3 @@
|
||||||
# Azalea Client
|
# 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.
|
||||||
|
|
|
@ -200,7 +200,7 @@ impl Client {
|
||||||
println!("Got update tags packet");
|
println!("Got update tags packet");
|
||||||
}
|
}
|
||||||
GamePacket::ClientboundDisconnectPacket(p) => {
|
GamePacket::ClientboundDisconnectPacket(p) => {
|
||||||
println!("Got login disconnect packet {:?}", p);
|
println!("Got disconnect packet {:?}", p);
|
||||||
}
|
}
|
||||||
GamePacket::ClientboundUpdateRecipesPacket(p) => {
|
GamePacket::ClientboundUpdateRecipesPacket(p) => {
|
||||||
println!("Got update recipes packet");
|
println!("Got update recipes packet");
|
||||||
|
@ -230,6 +230,9 @@ impl Client {
|
||||||
GamePacket::ClientboundAddMobPacket(p) => {
|
GamePacket::ClientboundAddMobPacket(p) => {
|
||||||
println!("Got add mob packet {:?}", p);
|
println!("Got add mob packet {:?}", p);
|
||||||
}
|
}
|
||||||
|
GamePacket::ClientboundAddEntityPacket(p) => {
|
||||||
|
println!("Got add entity packet {:?}", p);
|
||||||
|
}
|
||||||
_ => panic!("Unexpected packet {:?}", packet),
|
_ => panic!("Unexpected packet {:?}", packet),
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|
6
azalea-core/src/block_pos.rs
Normal file
6
azalea-core/src/block_pos.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct BlockPos {
|
||||||
|
pub x: i32,
|
||||||
|
pub y: i32,
|
||||||
|
pub z: i32,
|
||||||
|
}
|
9
azalea-core/src/direction.rs
Normal file
9
azalea-core/src/direction.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Direction {
|
||||||
|
Down = 0,
|
||||||
|
Up = 1,
|
||||||
|
North = 2,
|
||||||
|
South = 3,
|
||||||
|
West = 4,
|
||||||
|
East = 5,
|
||||||
|
}
|
|
@ -7,3 +7,9 @@ pub mod serializable_uuid;
|
||||||
|
|
||||||
mod slot;
|
mod slot;
|
||||||
pub use slot::{Slot, SlotData};
|
pub use slot::{Slot, SlotData};
|
||||||
|
|
||||||
|
mod block_pos;
|
||||||
|
pub use block_pos::BlockPos;
|
||||||
|
|
||||||
|
mod direction;
|
||||||
|
pub use direction::Direction;
|
||||||
|
|
|
@ -7,105 +7,146 @@ use syn::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
|
fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
|
||||||
let fields = match data {
|
match data {
|
||||||
syn::Data::Struct(syn::DataStruct { fields, .. }) => fields,
|
syn::Data::Struct(syn::DataStruct { fields, .. }) => {
|
||||||
_ => panic!("#[derive(*Packet)] can only be used on structs"),
|
let FieldsNamed { named, .. } = match fields {
|
||||||
};
|
syn::Fields::Named(f) => f,
|
||||||
let FieldsNamed { named, .. } = match fields {
|
_ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
|
||||||
syn::Fields::Named(f) => f,
|
};
|
||||||
_ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let read_fields = named
|
let read_fields = named
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
let field_name = &f.ident;
|
let field_name = &f.ident;
|
||||||
let field_type = &f.ty;
|
let field_type = &f.ty;
|
||||||
// do a different buf.write_* for each field depending on the type
|
// do a different buf.write_* for each field depending on the type
|
||||||
// if it's a string, use buf.write_string
|
// if it's a string, use buf.write_string
|
||||||
match field_type {
|
match field_type {
|
||||||
syn::Type::Path(_) => {
|
syn::Type::Path(_) => {
|
||||||
if f.attrs.iter().any(|a| a.path.is_ident("varint")) {
|
if f.attrs.iter().any(|a| a.path.is_ident("varint")) {
|
||||||
quote! {
|
quote! {
|
||||||
let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?;
|
let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
let #field_name = crate::mc_buf::McBufReadable::read_into(buf).await?;
|
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::<Vec<_>>();
|
||||||
|
let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl crate::mc_buf::McBufReadable for #ident {
|
||||||
|
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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::<Vec<_>>();
|
|
||||||
let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl crate::mc_buf::McBufReadable for #ident {
|
|
||||||
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
|
||||||
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 {
|
fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
|
||||||
let fields = match data {
|
match data {
|
||||||
syn::Data::Struct(syn::DataStruct { fields, .. }) => fields,
|
syn::Data::Struct(syn::DataStruct { fields, .. }) => {
|
||||||
_ => panic!("#[derive(*Packet)] can only be used on structs"),
|
let FieldsNamed { named, .. } = match fields {
|
||||||
};
|
syn::Fields::Named(f) => f,
|
||||||
let FieldsNamed { named, .. } = match fields {
|
_ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
|
||||||
syn::Fields::Named(f) => f,
|
};
|
||||||
_ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let write_fields = named
|
let write_fields = named
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
let field_name = &f.ident;
|
let field_name = &f.ident;
|
||||||
let field_type = &f.ty;
|
let field_type = &f.ty;
|
||||||
// do a different buf.write_* for each field depending on the type
|
// do a different buf.write_* for each field depending on the type
|
||||||
// if it's a string, use buf.write_string
|
// if it's a string, use buf.write_string
|
||||||
match field_type {
|
match field_type {
|
||||||
syn::Type::Path(_) => {
|
syn::Type::Path(_) => {
|
||||||
if f.attrs.iter().any(|attr| attr.path.is_ident("varint")) {
|
if f.attrs.iter().any(|attr| attr.path.is_ident("varint")) {
|
||||||
quote! {
|
quote! {
|
||||||
crate::mc_buf::McBufVarintWritable::varint_write_into(&self.#field_name, buf)?;
|
crate::mc_buf::McBufVarintWritable::varint_write_into(&self.#field_name, buf)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
crate::mc_buf::McBufWritable::write_into(&self.#field_name, buf)?;
|
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 {}: {}",
|
.collect::<Vec<_>>();
|
||||||
field_name.clone().unwrap(),
|
|
||||||
field_type.to_token_stream()
|
|
||||||
),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl crate::mc_buf::McBufWritable for #ident {
|
impl crate::mc_buf::McBufWritable for #ident {
|
||||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
#(#write_fields)*
|
#(#write_fields)*
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
syn::Data::Enum(syn::DataEnum { .. }) => {
|
||||||
|
quote! {
|
||||||
|
impl crate::mc_buf::McBufWritable for #ident {
|
||||||
|
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
|
crate::mc_buf::Writable::write_varint(buf, *self as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("#[derive(*Packet)] can only be used on structs"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use async_trait::async_trait;
|
||||||
use azalea_chat::component::Component;
|
use azalea_chat::component::Component;
|
||||||
use azalea_core::{
|
use azalea_core::{
|
||||||
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
|
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
|
||||||
serializable_uuid::SerializableUuid, Slot, SlotData,
|
serializable_uuid::SerializableUuid, BlockPos, Direction, Slot, SlotData,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
|
@ -473,29 +473,14 @@ impl McBufReadable for Option<GameType> {
|
||||||
|
|
||||||
// Option<String>
|
// Option<String>
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl McBufReadable for Option<String> {
|
impl<T: McBufReadable> McBufReadable for Option<T> {
|
||||||
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
default async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||||
where
|
where
|
||||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||||
{
|
{
|
||||||
let present = buf.read_boolean().await?;
|
let present = buf.read_boolean().await?;
|
||||||
Ok(if present {
|
Ok(if present {
|
||||||
Some(buf.read_utf().await?)
|
Some(T::read_into(buf).await?)
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Option<Component>
|
|
||||||
#[async_trait]
|
|
||||||
impl McBufReadable for Option<Component> {
|
|
||||||
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
|
||||||
where
|
|
||||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
|
||||||
{
|
|
||||||
let present = buf.read_boolean().await?;
|
|
||||||
Ok(if present {
|
|
||||||
Some(Component::read_into(buf).await?)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
|
@ -567,3 +552,37 @@ impl McBufReadable for Uuid {
|
||||||
buf.read_uuid().await
|
buf.read_uuid().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockPos
|
||||||
|
#[async_trait]
|
||||||
|
impl McBufReadable for BlockPos {
|
||||||
|
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use async_trait::async_trait;
|
||||||
use azalea_chat::component::Component;
|
use azalea_chat::component::Component;
|
||||||
use azalea_core::{
|
use azalea_core::{
|
||||||
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
|
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
|
||||||
serializable_uuid::SerializableUuid, Slot,
|
serializable_uuid::SerializableUuid, BlockPos, Direction, Slot,
|
||||||
};
|
};
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
@ -336,21 +336,8 @@ impl McBufWritable for Option<GameType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option<String>
|
// Option<String>
|
||||||
impl McBufWritable for Option<String> {
|
impl<T: McBufWritable> McBufWritable for Option<T> {
|
||||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
default fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||||
if let Some(s) = self {
|
|
||||||
buf.write_boolean(true)?;
|
|
||||||
buf.write_utf(s)?;
|
|
||||||
} else {
|
|
||||||
buf.write_boolean(false)?;
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option<Component>
|
|
||||||
impl McBufWritable for Option<Component> {
|
|
||||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
|
||||||
if let Some(s) = self {
|
if let Some(s) = self {
|
||||||
buf.write_boolean(true)?;
|
buf.write_boolean(true)?;
|
||||||
s.write_into(buf)?;
|
s.write_into(buf)?;
|
||||||
|
@ -418,3 +405,21 @@ impl McBufWritable for Uuid {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockPos
|
||||||
|
impl McBufWritable for BlockPos {
|
||||||
|
fn write_into(&self, buf: &mut Vec<u8>) -> 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<u8>) -> Result<(), std::io::Error> {
|
||||||
|
buf.write_varint(*self as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
|
@ -26,3 +26,9 @@ pub struct BlockEntity {
|
||||||
type_: i32,
|
type_: i32,
|
||||||
data: azalea_nbt::Tag,
|
data: azalea_nbt::Tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ChunkSection {}
|
||||||
|
|
||||||
|
impl ClientboundLevelChunkPacketData {
|
||||||
|
pub fn read(world_height: u32) {}
|
||||||
|
}
|
||||||
|
|
|
@ -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<EntityDataItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<EntityDataItem> {
|
||||||
|
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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<EntityDataItem> {
|
||||||
|
fn write_into(&self, buf: &mut Vec<u8>) -> 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<Component>),
|
||||||
|
ItemStack(Slot),
|
||||||
|
Boolean(bool),
|
||||||
|
Rotations { x: f32, y: f32, z: f32 },
|
||||||
|
BlockPos(BlockPos),
|
||||||
|
OptionalBlockPos(Option<BlockPos>),
|
||||||
|
Direction(Direction),
|
||||||
|
OptionalUuid(Option<Uuid>),
|
||||||
|
// 0 for absent (implies air); otherwise, a block state ID as per the global palette
|
||||||
|
// this is a varint
|
||||||
|
OptionalBlockState(Option<i32>),
|
||||||
|
CompoundTag(azalea_nbt::Tag),
|
||||||
|
Particle(Particle),
|
||||||
|
VillagerData(VillagerData),
|
||||||
|
// 0 for absent; 1 + actual value otherwise. Used for entity IDs.
|
||||||
|
OptionalUnsignedInt(Option<u32>),
|
||||||
|
Pose(Pose),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl McBufReadable for EntityDataValue {
|
||||||
|
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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::<Component>::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::<BlockPos>::read_into(buf).await?),
|
||||||
|
11 => EntityDataValue::Direction(Direction::read_into(buf).await?),
|
||||||
|
12 => EntityDataValue::OptionalUuid(Option::<Uuid>::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<u8>) -> 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<R>(buf: &mut R) -> Result<Self, String>
|
||||||
|
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<u8>) -> Result<(), std::io::Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod clientbound_add_entity_packet;
|
||||||
pub mod clientbound_add_mob_packet;
|
pub mod clientbound_add_mob_packet;
|
||||||
pub mod clientbound_change_difficulty_packet;
|
pub mod clientbound_change_difficulty_packet;
|
||||||
pub mod clientbound_custom_payload_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_recipe_packet;
|
||||||
pub mod clientbound_set_carried_item_packet;
|
pub mod clientbound_set_carried_item_packet;
|
||||||
pub mod clientbound_set_chunk_cache_center;
|
pub mod clientbound_set_chunk_cache_center;
|
||||||
|
pub mod clientbound_set_entity_data_packet;
|
||||||
pub mod clientbound_update_recipes_packet;
|
pub mod clientbound_update_recipes_packet;
|
||||||
pub mod clientbound_update_tags_packet;
|
pub mod clientbound_update_tags_packet;
|
||||||
pub mod clientbound_update_view_distance_packet;
|
pub mod clientbound_update_view_distance_packet;
|
||||||
|
@ -26,6 +28,7 @@ declare_state_packets!(
|
||||||
0x0a: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
0x0a: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||||
},
|
},
|
||||||
Clientbound => {
|
Clientbound => {
|
||||||
|
0x00: clientbound_add_entity_packet::ClientboundAddEntityPacket,
|
||||||
0x02: clientbound_add_mob_packet::ClientboundAddMobPacket,
|
0x02: clientbound_add_mob_packet::ClientboundAddMobPacket,
|
||||||
0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
|
0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
|
||||||
0x12: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket,
|
0x12: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket,
|
||||||
|
@ -42,6 +45,7 @@ declare_state_packets!(
|
||||||
0x48: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket,
|
0x48: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket,
|
||||||
0x49: clientbound_set_chunk_cache_center::ClientboundSetChunkCacheCenterPacket,
|
0x49: clientbound_set_chunk_cache_center::ClientboundSetChunkCacheCenterPacket,
|
||||||
0x4a: clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket,
|
0x4a: clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket,
|
||||||
|
0x4d: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket,
|
||||||
0x66: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket,
|
0x66: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket,
|
||||||
0x67: clientbound_update_tags_packet::ClientboundUpdateTagsPacket
|
0x67: clientbound_update_tags_packet::ClientboundUpdateTagsPacket
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use packet_macros::StatusPacket;
|
use packet_macros::StatusPacket;
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, StatusPacket)]
|
#[derive(Clone, Debug, StatusPacket)]
|
||||||
pub struct ServerboundStatusRequestPacket {}
|
pub struct ServerboundStatusRequestPacket {}
|
||||||
|
|
|
@ -5,7 +5,7 @@ async fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
||||||
// let address = "95.111.249.143:10000";
|
// 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())
|
// let response = azalea_client::ping::ping_server(&address.try_into().unwrap())
|
||||||
// .await
|
// .await
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
|
|
Loading…
Add table
Reference in a new issue