From a599b5614e6acf65e552940fff99a9252a600472 Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 24 Dec 2024 09:40:29 +0000 Subject: make BlockState a u16 and add a BlockStateIntegerRepr type --- azalea-block/src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++++------- azalea-block/src/range.rs | 6 +++--- 2 files changed, 43 insertions(+), 10 deletions(-) (limited to 'azalea-block/src') diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs index 3de0aa5a..65dd581e 100755 --- a/azalea-block/src/lib.rs +++ b/azalea-block/src/lib.rs @@ -40,22 +40,34 @@ pub trait Property { fn try_from_block_state(state: BlockState) -> Option; } +/// The type that's used internally to represent a block state ID. +/// +/// This should be either `u16` or `u32`. If you choose to modify it, you must +/// also change it in `azalea-block-macros/src/lib.rs`. +/// +/// This does not affect protocol serialization, it just allows you to make the +/// internal type smaller if you want. +pub type BlockStateIntegerRepr = u16; + /// A representation of a state a block can be in. /// /// For example, a stone block only has one state but each possible stair /// rotation is a different state. +/// +/// Note that this type is internally either a `u16` or `u32`, depending on +/// [`BlockStateIntegerRepr`]. #[derive(Copy, Clone, PartialEq, Eq, Default, Hash)] pub struct BlockState { /// The protocol ID for the block state. IDs may change every /// version, so you shouldn't hard-code them or store them in databases. - pub id: u32, + pub id: BlockStateIntegerRepr, } impl BlockState { pub const AIR: BlockState = BlockState { id: 0 }; #[inline] - pub fn is_valid_state(state_id: u32) -> bool { + pub fn is_valid_state(state_id: BlockStateIntegerRepr) -> bool { state_id <= Self::MAX_STATE } @@ -70,8 +82,22 @@ impl BlockState { impl TryFrom for BlockState { type Error = (); - /// Safely converts a state id to a block state. + /// Safely converts a u32 state id to a block state. fn try_from(state_id: u32) -> Result { + let state_id = state_id as BlockStateIntegerRepr; + if Self::is_valid_state(state_id) { + Ok(BlockState { id: state_id }) + } else { + Err(()) + } + } +} +impl TryFrom for BlockState { + type Error = (); + + /// Safely converts a u16 state id to a block state. + fn try_from(state_id: u16) -> Result { + let state_id = state_id as BlockStateIntegerRepr; if Self::is_valid_state(state_id) { Ok(BlockState { id: state_id }) } else { @@ -90,7 +116,7 @@ impl AzaleaRead for BlockState { } impl AzaleaWrite for BlockState { fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { - u32::azalea_write_var(&self.id, buf) + u32::azalea_write_var(&(self.id as u32), buf) } } @@ -158,12 +184,16 @@ impl From for BlockState { azalea_registry::Fluid::Empty => BlockState::AIR, azalea_registry::Fluid::Water | azalea_registry::Fluid::FlowingWater => { BlockState::from(crate::blocks::Water { - level: crate::properties::WaterLevel::from(state.height as u32), + level: crate::properties::WaterLevel::from( + state.height as BlockStateIntegerRepr, + ), }) } azalea_registry::Fluid::Lava | azalea_registry::Fluid::FlowingLava => { BlockState::from(crate::blocks::Lava { - level: crate::properties::LavaLevel::from(state.height as u32), + level: crate::properties::LavaLevel::from( + state.height as BlockStateIntegerRepr, + ), }) } } @@ -182,7 +212,10 @@ mod tests { #[test] fn test_from_u32() { - assert_eq!(BlockState::try_from(0).unwrap(), BlockState::AIR); + assert_eq!( + BlockState::try_from(0 as BlockStateIntegerRepr).unwrap(), + BlockState::AIR + ); assert!(BlockState::try_from(BlockState::MAX_STATE).is_ok()); assert!(BlockState::try_from(BlockState::MAX_STATE + 1).is_err()); diff --git a/azalea-block/src/range.rs b/azalea-block/src/range.rs index 9b520d49..779d805d 100644 --- a/azalea-block/src/range.rs +++ b/azalea-block/src/range.rs @@ -3,15 +3,15 @@ use std::{ ops::{Add, RangeInclusive}, }; -use crate::BlockState; +use crate::{BlockState, BlockStateIntegerRepr}; #[derive(Debug, Clone)] pub struct BlockStates { pub set: HashSet, } -impl From> for BlockStates { - fn from(range: RangeInclusive) -> Self { +impl From> for BlockStates { + fn from(range: RangeInclusive) -> Self { let mut set = HashSet::with_capacity((range.end() - range.start() + 1) as usize); for id in range { set.insert(BlockState { id }); -- cgit v1.2.3