diff --git a/Cargo.lock b/Cargo.lock index 270d61f7..19d15e25 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,7 @@ name = "azalea-block" version = "0.1.0" dependencies = [ "azalea-block-macros", + "azalea-buf", ] [[package]] @@ -235,6 +236,7 @@ dependencies = [ "async-compression", "async-recursion", "azalea-auth", + "azalea-block", "azalea-brigadier", "azalea-buf", "azalea-chat", @@ -242,6 +244,7 @@ dependencies = [ "azalea-crypto", "azalea-nbt", "azalea-protocol-macros", + "azalea-registry", "azalea-world", "byteorder", "bytes", @@ -268,6 +271,7 @@ dependencies = [ name = "azalea-registry" version = "0.1.0" dependencies = [ + "azalea-buf", "azalea-registry-macros", ] diff --git a/azalea-block/Cargo.toml b/azalea-block/Cargo.toml index e23eea4d..3dbc7735 100644 --- a/azalea-block/Cargo.toml +++ b/azalea-block/Cargo.toml @@ -11,3 +11,4 @@ version = "0.1.0" [dependencies] azalea-block-macros = {path = "./azalea-block-macros", version = "^0.1.0"} +azalea-buf = {path = "../azalea-buf", version = "^0.1.0"} diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs index 3eb86a90..fdcfe631 100644 --- a/azalea-block/src/lib.rs +++ b/azalea-block/src/lib.rs @@ -1,10 +1,13 @@ mod behavior; mod blocks; +use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable}; pub use behavior::BlockBehavior; pub use blocks::*; - -use std::mem; +use std::{ + io::{Read, Write}, + mem, +}; impl BlockState { /// Transmutes a u32 to a block state. @@ -35,6 +38,20 @@ impl TryFrom for BlockState { } } +impl McBufReadable for BlockState { + fn read_from(buf: &mut impl Read) -> Result { + let state_id = u32::var_read_from(buf)?; + Self::try_from(state_id).map_err(|_| BufReadError::UnexpectedEnumVariant { + id: state_id as i32, + }) + } +} +impl McBufWritable for BlockState { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + u32::var_write_into(&(*self as u32), buf) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/azalea-buf/azalea-buf-macros/src/lib.rs b/azalea-buf/azalea-buf-macros/src/lib.rs index 0d77488f..fce3b515 100644 --- a/azalea-buf/azalea-buf-macros/src/lib.rs +++ b/azalea-buf/azalea-buf-macros/src/lib.rs @@ -74,8 +74,22 @@ fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt variant_discrim += 1; } } + let reader = match variant.fields { + syn::Fields::Named(_) => { + panic!("writing named fields in enums is not supported") + } + syn::Fields::Unnamed(_) => quote! { + Ok(Self::#variant_name(azalea_buf::McBufReadable::read_from(buf)?)) + }, + syn::Fields::Unit => quote! { + Ok(Self::#variant_name) + }, + }; + match_contents.extend(quote! { - #variant_discrim => Ok(Self::#variant_name), + #variant_discrim => { + #reader + }, }); } @@ -141,11 +155,75 @@ fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt } } } - syn::Data::Enum(syn::DataEnum { .. }) => { - quote! { - impl azalea_buf::McBufWritable for #ident { - fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { - azalea_buf::McBufVarWritable::var_write_into(&(*self as u32), buf) + syn::Data::Enum(syn::DataEnum { variants, .. }) => { + // remember whether it's a data variant so we can do an optimization later + let mut is_data_enum = false; + let mut match_arms = quote!(); + let mut variant_discrim: u32 = 0; + for variant in variants { + // figure out the discriminant + if let Some(discriminant) = &variant.discriminant { + variant_discrim = match &discriminant.1 { + syn::Expr::Lit(e) => match &e.lit { + syn::Lit::Int(i) => i.base10_parse().unwrap(), + _ => panic!("Error parsing enum discriminant as int"), + }, + syn::Expr::Unary(_) => { + panic!("Negative enum discriminants are not supported") + } + _ => { + panic!( + "Error parsing enum discriminant as literal (is {:?})", + discriminant.1 + ) + } + }; + } else { + variant_discrim += 1; + } + + match &variant.fields { + syn::Fields::Named(_) => { + panic!("Enum variants with named fields are not supported yet"); + } + syn::Fields::Unit => { + let variant_name = &variant.ident; + match_arms.extend(quote! { + Self::#variant_name => { + azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?; + } + }); + } + syn::Fields::Unnamed(_) => { + is_data_enum = true; + let variant_name = &variant.ident; + match_arms.extend(quote! { + Self::#variant_name(data) => { + azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?; + azalea_buf::McBufWritable::write_into(data, buf)?; + } + }); + } + } + } + if is_data_enum { + quote! { + impl azalea_buf::McBufWritable for #ident { + fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { + match self { + #match_arms + } + Ok(()) + } + } + } + } else { + // optimization: if it doesn't have data we can just do `as u32` + quote! { + impl azalea_buf::McBufWritable for #ident { + fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> { + azalea_buf::McBufVarWritable::var_write_into(&(*self as u32), buf) + } } } } diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml index 6b7dc290..513e324c 100755 --- a/azalea-protocol/Cargo.toml +++ b/azalea-protocol/Cargo.toml @@ -11,6 +11,7 @@ version = "0.1.0" async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true} async-recursion = "1.0.0" azalea-auth = {path = "../azalea-auth", version = "^0.1.0"} +azalea-block = {path = "../azalea-block", default-features = false, version = "^0.1.0"} azalea-brigadier = {path = "../azalea-brigadier", version = "^0.1.0"} azalea-buf = {path = "../azalea-buf", version = "^0.1.0"} azalea-chat = {path = "../azalea-chat", version = "^0.1.1"} @@ -18,6 +19,7 @@ azalea-core = {path = "../azalea-core", optional = true, version = "^0.1.0"} azalea-crypto = {path = "../azalea-crypto", version = "^0.1.0"} azalea-nbt = {path = "../azalea-nbt", version = "^0.1.0"} azalea-protocol-macros = {path = "./azalea-protocol-macros", version = "^0.1.0"} +azalea-registry = {path = "../azalea-registry", version = "^0.1.0"} azalea-world = {path = "../azalea-world", version = "^0.1.0"} byteorder = "^1.4.3" bytes = "^1.1.0" diff --git a/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs index 403925f4..f74a8746 100644 --- a/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs @@ -10,9 +10,7 @@ pub struct ClientboundAddEntityPacket { #[var] pub id: u32, pub uuid: Uuid, - // TODO: have an entity type enum/struct - #[var] - pub entity_type: i32, + pub entity_type: azalea_registry::EntityType, pub x: f64, pub y: f64, pub z: f64, diff --git a/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs b/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs index 3629ed6f..2812987d 100644 --- a/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_award_stats_packet.rs @@ -9,10 +9,14 @@ pub struct ClientboundAwardStatsPacket { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, McBuf)] -pub struct Stat { - // TODO: make these good enums and stuff - #[var] - pub stat_type: u32, - #[var] - pub statistic_id: u32, +pub enum Stat { + Mined(azalea_registry::Block), + Crafted(azalea_registry::Item), + Used(azalea_registry::Item), + Broken(azalea_registry::Item), + PickedUp(azalea_registry::Item), + Dropped(azalea_registry::Item), + Killed(azalea_registry::EntityType), + KilledBy(azalea_registry::EntityType), + Custom(azalea_registry::CustomStat), } diff --git a/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs index dbf0ae65..faa3b1a9 100644 --- a/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs @@ -5,8 +5,6 @@ use azalea_protocol_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundBlockEntityDataPacket { pub pos: BlockPos, - // TODO: in vanilla this uses the block entity registry, we should have an enum in azalea-entity for this - #[var] - pub block_entity_type: u32, + pub block_entity_type: azalea_registry::BlockEntityType, pub tag: azalea_nbt::Tag, } diff --git a/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs index 124950f1..1a8a0c52 100644 --- a/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_block_event_packet.rs @@ -1,3 +1,4 @@ +use azalea_block::BlockState; use azalea_buf::McBuf; use azalea_core::BlockPos; use azalea_protocol_macros::ClientboundGamePacket; @@ -7,7 +8,5 @@ pub struct ClientboundBlockEventPacket { pub pos: BlockPos, pub b0: u8, pub b1: u8, - // TODO: this is a BlockState, see ClientboundBlockUpdatePacket for more info - #[var] - pub block: u32, + pub block: BlockState, } diff --git a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs index 44629c82..3034accc 100644 --- a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs @@ -1,3 +1,4 @@ +use azalea_block::BlockState; use azalea_buf::McBuf; use azalea_core::BlockPos; use azalea_protocol_macros::ClientboundGamePacket; @@ -5,8 +6,5 @@ use azalea_protocol_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundBlockUpdatePacket { pub pos: BlockPos, - // TODO: in vanilla this is a BlockState, but here we just have it as a number. - // perhaps we could make a crate that only handles block states? right now blockstates are handled in azalea-block - #[var] - pub block_state: u32, + pub block_state: BlockState, } diff --git a/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs b/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs index 36795575..41c8291a 100644 --- a/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_cooldown_packet.rs @@ -3,9 +3,7 @@ use azalea_protocol_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundCooldownPacket { - // TODO: make azalea-items or something and use that - #[var] - pub item: u32, + pub item: azalea_registry::Item, #[var] pub duration: u32, } diff --git a/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs b/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs index b526b210..521975af 100644 --- a/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_open_screen_packet.rs @@ -6,8 +6,6 @@ use azalea_protocol_macros::ClientboundGamePacket; pub struct ClientboundOpenScreenPacket { #[var] pub container_id: u32, - // TODO: have an enum of this - #[var] - pub menu_type: u32, + pub menu_type: azalea_registry::Menu, pub title: Component, } diff --git a/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs b/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs index 38265271..87bf81bd 100644 --- a/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_remove_mob_effect_packet.rs @@ -5,7 +5,5 @@ use azalea_protocol_macros::ClientboundGamePacket; pub struct ClientboundRemoveMobEffectPacket { #[var] pub entity_id: u32, - // TODO: have this use an enum - #[var] - pub effect: u32, + pub effect: azalea_registry::MobEffect, } diff --git a/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs index 9f8ab9e4..ad382fe0 100644 --- a/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_sound_entity_packet.rs @@ -4,9 +4,7 @@ use azalea_protocol_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundSoundEntityPacket { - // TODO: sound enum/registry - #[var] - pub sound: u32, + pub sound: azalea_registry::SoundEvent, pub source: SoundSource, #[var] pub id: u32, diff --git a/azalea-protocol/src/packets/game/clientbound_sound_packet.rs b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs index 5f67714d..54f35492 100644 --- a/azalea-protocol/src/packets/game/clientbound_sound_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs @@ -3,9 +3,7 @@ use azalea_protocol_macros::ClientboundGamePacket; #[derive(Clone, Debug, McBuf, ClientboundGamePacket)] pub struct ClientboundSoundPacket { - // TODO: sound enum/registry - #[var] - pub sound: u32, + pub sound: azalea_registry::SoundEvent, pub source: SoundSource, pub x: i32, pub y: i32, diff --git a/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs index aeaea223..d1d9f9cc 100644 --- a/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs @@ -5,9 +5,7 @@ use azalea_protocol_macros::ClientboundGamePacket; pub struct ClientboundUpdateMobEffectPacket { #[var] pub entity_id: u32, - // TODO: have an enum for this - #[var] - pub effect: u32, + pub effect: azalea_registry::MobEffect, pub effect_amplifier: u8, #[var] pub effect_duration_ticks: u32, 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 33e8e0fe..8d8ef32b 100644 --- a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs @@ -26,7 +26,6 @@ pub struct ShapelessRecipe { } #[derive(Clone, Debug)] pub struct ShapedRecipe { - // TODO: make own McBufReadable and McBufWritable for this width: usize, height: usize, group: String, diff --git a/azalea-registry/Cargo.toml b/azalea-registry/Cargo.toml index c9a4ed02..cb199611 100644 --- a/azalea-registry/Cargo.toml +++ b/azalea-registry/Cargo.toml @@ -8,4 +8,5 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +azalea-buf = {path = "../azalea-buf", version = "^0.1.0"} azalea-registry-macros = {path = "./azalea-registry-macros", version = "^0.1.0"} diff --git a/azalea-registry/azalea-registry-macros/src/lib.rs b/azalea-registry/azalea-registry-macros/src/lib.rs index fef698f5..16d8608e 100644 --- a/azalea-registry/azalea-registry-macros/src/lib.rs +++ b/azalea-registry/azalea-registry-macros/src/lib.rs @@ -67,7 +67,7 @@ pub fn registry(input: TokenStream) -> TokenStream { }); } generated.extend(quote! { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, azalea_buf::McBuf)] #[repr(u32)] pub enum #name { #enum_items @@ -75,12 +75,16 @@ pub fn registry(input: TokenStream) -> TokenStream { }); let max_id = input.items.len() as u32; + + let doc_0 = format!("Transmutes a u32 to a {}.", name); + let doc_1 = format!("The `id` should be at most {}.", max_id); + generated.extend(quote! { impl #name { - /// Transmutes a u32 to a #name. + #[doc = #doc_0] /// /// # Safety - /// The `id` should be at most #max_id. + #[doc = #doc_1] #[inline] pub unsafe fn from_u32_unchecked(id: u32) -> Self { std::mem::transmute::(id) @@ -93,11 +97,13 @@ pub fn registry(input: TokenStream) -> TokenStream { } }); + let doc_0 = format!("Safely transmutes a u32 to a {}.", name); + generated.extend(quote! { impl TryFrom for #name { type Error = (); - /// Safely converts a state id to a block state. + #[doc = #doc_0] fn try_from(id: u32) -> Result { if Self::is_valid_id(id) { Ok(unsafe { Self::from_u32_unchecked(id) })