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,
|
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 {
|
fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use super::{UnsizedByteArray, MAX_STRING_LENGTH};
|
||||||
use async_trait::async_trait;
|
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, Slot,
|
||||||
};
|
};
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
@ -337,3 +337,19 @@ impl McBufWritable for Component {
|
||||||
todo!()
|
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 async_trait::async_trait;
|
||||||
use azalea_chat::component::Component;
|
use azalea_chat::component::Component;
|
||||||
use azalea_core::{resource_location::ResourceLocation, Slot};
|
use azalea_core::{resource_location::ResourceLocation, Slot};
|
||||||
use packet_macros::GamePacket;
|
use packet_macros::{GamePacket, McBufReadable, McBufWritable};
|
||||||
use tokio::io::AsyncRead;
|
use tokio::io::AsyncRead;
|
||||||
|
|
||||||
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
|
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
|
||||||
|
@ -17,19 +17,70 @@ pub struct Recipe {
|
||||||
pub data: RecipeData,
|
pub data: RecipeData,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, McBufReadable, McBufWritable)]
|
||||||
pub enum RecipeData {
|
pub struct ShapelessRecipe {
|
||||||
CraftingShapeless {
|
/// Used to group similar recipes together in the recipe book.
|
||||||
/// Used to group similar recipes together in the recipe book.
|
/// Tag is present in recipe JSON
|
||||||
/// Tag is present in recipe JSON
|
group: String,
|
||||||
group: String,
|
ingredients: Vec<Ingredient>,
|
||||||
// ingredients
|
result: Slot,
|
||||||
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)]
|
#[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 struct Ingredient {
|
||||||
pub allowed: Vec<Slot>,
|
pub allowed: Vec<Slot>,
|
||||||
}
|
}
|
||||||
|
@ -56,13 +107,13 @@ impl McBufReadable for Recipe {
|
||||||
let ingredients = Vec::<Ingredient>::read_into(buf).await?;
|
let ingredients = Vec::<Ingredient>::read_into(buf).await?;
|
||||||
let result = Slot::read_into(buf).await?;
|
let result = Slot::read_into(buf).await?;
|
||||||
|
|
||||||
RecipeData::CraftingShapeless {
|
RecipeData::CraftingShapeless(ShapelessRecipe {
|
||||||
group,
|
group,
|
||||||
ingredients,
|
ingredients,
|
||||||
result,
|
result,
|
||||||
}
|
})
|
||||||
} else {
|
} else {
|
||||||
panic!();
|
panic!("Unknown recipe type sent by server: {}", recipe_type);
|
||||||
};
|
};
|
||||||
|
|
||||||
let recipe = Recipe { identifier, data };
|
let recipe = Recipe { identifier, data };
|
||||||
|
@ -70,21 +121,3 @@ impl McBufReadable for Recipe {
|
||||||
Ok(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())
|
// let response = azalea_client::ping::ping_server(&address.try_into().unwrap())
|
||||||
// .await
|
// .await
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
// println!("{}", response.description.to_ansi(None));
|
// println!("{}", response.description.to_ansi(None));
|
||||||
let _response = azalea_client::connect::join_server(&address.try_into().unwrap())
|
let _response = azalea_client::connect::join_server(&address.try_into().unwrap())
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Add table
Reference in a new issue