1
2
Fork 0
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:
mat 2022-04-26 22:58:18 +00:00
parent 5736a790d3
commit dd24110019
4 changed files with 195 additions and 33 deletions

View file

@ -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);

View file

@ -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(())
}
}

View file

@ -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)
}
}

View file

@ -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