diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-01-10 16:45:27 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-10 16:45:27 -0600 |
| commit | 0d16f01571ec8315f3979eae46981e559ade1cf9 (patch) | |
| tree | ea43c32a57b0e6a67579d75a134dfbc009d09781 /azalea-block/src/lib.rs | |
| parent | 615d8f9d2ac56b3244d328587243301da253eafd (diff) | |
| download | azalea-drasl-0d16f01571ec8315f3979eae46981e559ade1cf9.tar.xz | |
Fluid physics (#199)
* start implementing fluid physics
* Initial implementation of fluid pushing
* different travel function in water
* bubble columns
* jumping in water
* cleanup
* change ultrawarm to be required
* fix for clippy
Diffstat (limited to 'azalea-block/src/lib.rs')
| -rwxr-xr-x | azalea-block/src/lib.rs | 241 |
1 files changed, 5 insertions, 236 deletions
diff --git a/azalea-block/src/lib.rs b/azalea-block/src/lib.rs index 4719ef42..bbf3ece7 100755 --- a/azalea-block/src/lib.rs +++ b/azalea-block/src/lib.rs @@ -2,18 +2,17 @@ #![feature(trait_upcasting)] mod behavior; +pub mod block_state; +pub mod fluid_state; mod generated; mod range; use core::fmt::Debug; -use std::{ - any::Any, - fmt, - io::{self, Cursor, Write}, -}; +use std::any::Any; -use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError}; pub use behavior::BlockBehavior; +// re-exported for convenience +pub use block_state::BlockState; pub use generated::{blocks, properties}; pub use range::BlockStates; @@ -40,233 +39,3 @@ pub trait Property { fn try_from_block_state(state: BlockState) -> Option<Self::Value>; } - -/// 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: BlockStateIntegerRepr, -} - -impl BlockState { - pub const AIR: BlockState = BlockState { id: 0 }; - - #[inline] - pub fn is_valid_state(state_id: BlockStateIntegerRepr) -> bool { - state_id <= Self::MAX_STATE - } - - /// Returns true if the block is air. This only checks for normal air, not - /// other types like cave air. - #[inline] - pub fn is_air(&self) -> bool { - self == &Self::AIR - } -} - -impl TryFrom<u32> for BlockState { - type Error = (); - - /// Safely converts a u32 state id to a block state. - fn try_from(state_id: u32) -> Result<Self, Self::Error> { - let state_id = state_id as BlockStateIntegerRepr; - if Self::is_valid_state(state_id) { - Ok(BlockState { id: state_id }) - } else { - Err(()) - } - } -} -impl TryFrom<u16> for BlockState { - type Error = (); - - /// Safely converts a u16 state id to a block state. - fn try_from(state_id: u16) -> Result<Self, Self::Error> { - let state_id = state_id as BlockStateIntegerRepr; - if Self::is_valid_state(state_id) { - Ok(BlockState { id: state_id }) - } else { - Err(()) - } - } -} - -impl AzaleaRead for BlockState { - fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { - let state_id = u32::azalea_read_var(buf)?; - Self::try_from(state_id).map_err(|_| BufReadError::UnexpectedEnumVariant { - id: state_id as i32, - }) - } -} -impl AzaleaWrite for BlockState { - fn azalea_write(&self, buf: &mut impl Write) -> Result<(), io::Error> { - u32::azalea_write_var(&(self.id as u32), buf) - } -} - -impl Debug for BlockState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "BlockState(id: {}, {:?})", - self.id, - Box::<dyn Block>::from(*self) - ) - } -} - -#[derive(Clone, Debug)] -pub struct FluidState { - pub fluid: azalea_registry::Fluid, - /// 0 = empty, 8 = full, 9 = max. - /// - /// 9 is meant to be used when there's another fluid block of the same type - /// above it, but it's usually unused by this struct. - pub amount: u8, -} -impl FluidState { - /// A floating point number in between 0 and 1 representing the height (as a - /// percentage of a full block) of the fluid. - pub fn height(&self) -> f32 { - self.amount as f32 / 9. - } -} - -impl Default for FluidState { - fn default() -> Self { - Self { - fluid: azalea_registry::Fluid::Empty, - amount: 0, - } - } -} - -impl From<BlockState> for FluidState { - fn from(state: BlockState) -> Self { - // note that 8 here might be treated as 9 in some cases if there's another fluid - // block of the same type above it - - if state - .property::<crate::properties::Waterlogged>() - .unwrap_or_default() - { - Self { - fluid: azalea_registry::Fluid::Water, - amount: 8, - } - } else { - let block = Box::<dyn Block>::from(state); - if let Some(water) = block.downcast_ref::<crate::blocks::Water>() { - Self { - fluid: azalea_registry::Fluid::Water, - amount: to_or_from_legacy_fluid_level(water.level as u8), - } - } else if let Some(lava) = block.downcast_ref::<crate::blocks::Lava>() { - Self { - fluid: azalea_registry::Fluid::Lava, - amount: to_or_from_legacy_fluid_level(lava.level as u8), - } - } else { - Self { - fluid: azalea_registry::Fluid::Empty, - amount: 0, - } - } - } - } -} - -// see FlowingFluid.getLegacyLevel -fn to_or_from_legacy_fluid_level(level: u8) -> u8 { - 8_u8.saturating_sub(level) -} - -impl From<FluidState> for BlockState { - fn from(state: FluidState) -> Self { - match state.fluid { - 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.amount as BlockStateIntegerRepr, - ), - }) - } - azalea_registry::Fluid::Lava | azalea_registry::Fluid::FlowingLava => { - BlockState::from(crate::blocks::Lava { - level: crate::properties::LavaLevel::from( - state.amount as BlockStateIntegerRepr, - ), - }) - } - } - } -} - -impl From<BlockState> for azalea_registry::Block { - fn from(value: BlockState) -> Self { - Box::<dyn Block>::from(value).as_registry_block() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_from_u32() { - 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()); - } - - #[test] - fn test_from_blockstate() { - let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::AIR); - assert_eq!(block.id(), "air"); - - let block: Box<dyn Block> = - Box::<dyn Block>::from(BlockState::from(azalea_registry::Block::FloweringAzalea)); - assert_eq!(block.id(), "flowering_azalea"); - } - - #[test] - fn test_debug_blockstate() { - let formatted = format!( - "{:?}", - BlockState::from(azalea_registry::Block::FloweringAzalea) - ); - assert!(formatted.ends_with(", FloweringAzalea)"), "{}", formatted); - - let formatted = format!( - "{:?}", - BlockState::from(azalea_registry::Block::BigDripleafStem) - ); - assert!( - formatted.ends_with(", BigDripleafStem { facing: North, waterlogged: false })"), - "{}", - formatted - ); - } -} |
