aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-26 22:58:18 +0000
committermat <github@matdoes.dev>2022-04-26 22:58:18 +0000
commitdd24110019c0ded21e064b2273acc326173c84f5 (patch)
tree5d958ce932379a8b2548e01ccd09d08accce5450
parent5736a790d34cb55202521fcfe807bea6eb5f07c7 (diff)
downloadazalea-drasl-dd24110019c0ded21e064b2273acc326173c84f5.tar.xz
add derive mcbufreadable/writable
-rwxr-xr-xazalea-protocol/packet-macros/src/lib.rs112
-rwxr-xr-xazalea-protocol/src/mc_buf/write.rs18
-rw-r--r--azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs95
-rw-r--r--bot/src/main.rs1
4 files changed, 194 insertions, 32 deletions
diff --git a/azalea-protocol/packet-macros/src/lib.rs b/azalea-protocol/packet-macros/src/lib.rs
index 45df7e81..089d1594 100755
--- a/azalea-protocol/packet-macros/src/lib.rs
+++ b/azalea-protocol/packet-macros/src/lib.rs
@@ -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);
diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs
index e8845f25..2c46157b 100755
--- a/azalea-protocol/src/mc_buf/write.rs
+++ b/azalea-protocol/src/mc_buf/write.rs
@@ -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(())
+ }
+}
diff --git a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
index 2e8532df..d9e6b262 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
@@ -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, McBufReadable, McBufWritable)]
+pub struct ShapelessRecipe {
+ /// Used to group similar recipes together in the recipe book.
+ /// Tag is present in recipe JSON
+ group: String,
+ 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 {
- /// Used to group similar recipes together in the recipe book.
- /// Tag is present in recipe JSON
- group: String,
- // ingredients
- ingredients: Vec<Ingredient>,
- result: Slot,
- },
+ 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)]
+#[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)
- }
-}
diff --git a/bot/src/main.rs b/bot/src/main.rs
index 7d129478..71e325c6 100644
--- a/bot/src/main.rs
+++ b/bot/src/main.rs
@@ -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