mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
add derive mcbufreadable/writable
This commit is contained in:
parent
5736a790d3
commit
dd24110019
4 changed files with 195 additions and 33 deletions
|
@ -6,6 +6,118 @@ use syn::{
|
|||
parse_macro_input, DeriveInput, FieldsNamed, Ident, LitInt, Token,
|
||||
};
|
||||
|
||||
#[proc_macro_derive(McBufReadable, attributes(varint))]
|
||||
pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream {
|
||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||
|
||||
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"),
|
||||
};
|
||||
|
||||
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::<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: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||
{
|
||||
#(#read_fields)*
|
||||
Ok(#ident {
|
||||
#(#read_field_names: #read_field_names),*
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(McBufWritable, attributes(varint))]
|
||||
pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream {
|
||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||
|
||||
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"),
|
||||
};
|
||||
|
||||
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()
|
||||
),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
impl crate::mc_buf::McBufWritable for #ident {
|
||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||
#(#write_fields)*
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream {
|
||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::{UnsizedByteArray, MAX_STRING_LENGTH};
|
|||
use async_trait::async_trait;
|
||||
use azalea_chat::component::Component;
|
||||
use azalea_core::{
|
||||
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
|
||||
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, Slot,
|
||||
};
|
||||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
use std::io::Write;
|
||||
|
@ -337,3 +337,19 @@ impl McBufWritable for Component {
|
|||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// Slot
|
||||
impl McBufWritable for Slot {
|
||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||
match self {
|
||||
Slot::Empty => buf.write_byte(0)?,
|
||||
Slot::Present(i) => {
|
||||
buf.write_varint(i.id)?;
|
||||
buf.write_byte(i.count)?;
|
||||
buf.write_nbt(&i.nbt)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use async_trait::async_trait;
|
||||
use azalea_chat::component::Component;
|
||||
use azalea_core::{resource_location::ResourceLocation, Slot};
|
||||
use packet_macros::GamePacket;
|
||||
use packet_macros::{GamePacket, McBufReadable, McBufWritable};
|
||||
use tokio::io::AsyncRead;
|
||||
|
||||
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
|
||||
|
@ -17,19 +17,70 @@ pub struct Recipe {
|
|||
pub data: RecipeData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RecipeData {
|
||||
CraftingShapeless {
|
||||
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||
pub struct ShapelessRecipe {
|
||||
/// Used to group similar recipes together in the recipe book.
|
||||
/// Tag is present in recipe JSON
|
||||
group: String,
|
||||
// ingredients
|
||||
ingredients: Vec<Ingredient>,
|
||||
result: Slot,
|
||||
},
|
||||
}
|
||||
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||
pub struct ShapedRecipe {
|
||||
width: u32,
|
||||
height: u32,
|
||||
group: String,
|
||||
ingredients: Vec<Ingredient>,
|
||||
result: Slot,
|
||||
}
|
||||
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||
pub struct CookingRecipe {
|
||||
group: String,
|
||||
ingredient: Ingredient,
|
||||
result: Slot,
|
||||
experience: f32,
|
||||
#[varint]
|
||||
cooking_time: u32,
|
||||
}
|
||||
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||
pub struct StoneCuttingRecipe {
|
||||
group: String,
|
||||
ingredient: Ingredient,
|
||||
result: Slot,
|
||||
}
|
||||
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||
pub struct SmithingRecipe {
|
||||
base: Ingredient,
|
||||
addition: Ingredient,
|
||||
result: Slot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RecipeData {
|
||||
CraftingShapeless(ShapelessRecipe),
|
||||
CraftingShaped(ShapedRecipe),
|
||||
CraftingSpecialArmorDye,
|
||||
CraftingSpecialBookCloning,
|
||||
CraftingSpecialMapCloning,
|
||||
CraftingSpecialMapExtending,
|
||||
CraftingSpecialFireworkRocket,
|
||||
CraftingSpecialFireworkStar,
|
||||
CraftingSpecialFireworkStarFade,
|
||||
CraftingSpecialRepairItem,
|
||||
CraftingSpecialTippedArrow,
|
||||
CraftingSpecialBannerDuplicate,
|
||||
CraftingSpecialBannerAddPattern,
|
||||
CraftingSpecialShieldDecoration,
|
||||
CraftingSpecialShulkerBoxColoring,
|
||||
CraftingSpecialSuspiciousStew,
|
||||
Smelting(CookingRecipe),
|
||||
Blasting(CookingRecipe),
|
||||
Smoking(CookingRecipe),
|
||||
CampfireCooking(CookingRecipe),
|
||||
Stonecutting(StoneCuttingRecipe),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||
pub struct Ingredient {
|
||||
pub allowed: Vec<Slot>,
|
||||
}
|
||||
|
@ -56,13 +107,13 @@ impl McBufReadable for Recipe {
|
|||
let ingredients = Vec::<Ingredient>::read_into(buf).await?;
|
||||
let result = Slot::read_into(buf).await?;
|
||||
|
||||
RecipeData::CraftingShapeless {
|
||||
RecipeData::CraftingShapeless(ShapelessRecipe {
|
||||
group,
|
||||
ingredients,
|
||||
result,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
panic!();
|
||||
panic!("Unknown recipe type sent by server: {}", recipe_type);
|
||||
};
|
||||
|
||||
let recipe = Recipe { identifier, data };
|
||||
|
@ -70,21 +121,3 @@ impl McBufReadable for Recipe {
|
|||
Ok(recipe)
|
||||
}
|
||||
}
|
||||
|
||||
impl McBufWritable for Ingredient {
|
||||
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
#[async_trait]
|
||||
impl McBufReadable for Ingredient {
|
||||
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
|
||||
where
|
||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
||||
{
|
||||
let ingredient = Ingredient {
|
||||
allowed: Vec::<Slot>::read_into(buf).await?,
|
||||
};
|
||||
Ok(ingredient)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ async fn main() {
|
|||
// let response = azalea_client::ping::ping_server(&address.try_into().unwrap())
|
||||
// .await
|
||||
// .unwrap();
|
||||
|
||||
// println!("{}", response.description.to_ansi(None));
|
||||
let _response = azalea_client::connect::join_server(&address.try_into().unwrap())
|
||||
.await
|
||||
|
|
Loading…
Add table
Reference in a new issue