diff options
Diffstat (limited to 'azalea-physics/src')
| -rw-r--r-- | azalea-physics/src/clip.rs | 63 | ||||
| -rw-r--r-- | azalea-physics/src/collision/mod.rs | 60 | ||||
| -rwxr-xr-x | azalea-physics/src/collision/shape.rs | 2 |
3 files changed, 108 insertions, 17 deletions
diff --git a/azalea-physics/src/clip.rs b/azalea-physics/src/clip.rs index fd6bbf0b..4a374f58 100644 --- a/azalea-physics/src/clip.rs +++ b/azalea-physics/src/clip.rs @@ -20,12 +20,11 @@ pub struct ClipContext { // pub collision_context: EntityCollisionContext, } impl ClipContext { - // minecraft passes in the world and blockpos here... but it doesn't actually - // seem necessary? - /// Get the shape of given block, using the type of shape set in /// [`Self::block_shape_type`]. pub fn block_shape(&self, block_state: BlockState) -> &VoxelShape { + // minecraft passes in the world and blockpos to this function but it's not + // actually necessary. it is for fluid_shape though match self.block_shape_type { BlockShapeType::Collider => block_state.collision_shape(), BlockShapeType::Outline => block_state.outline_shape(), @@ -41,6 +40,19 @@ impl ClipContext { } } } + + pub fn fluid_shape( + &self, + fluid_state: FluidState, + world: &ChunkStorage, + pos: &BlockPos, + ) -> &VoxelShape { + if self.fluid_pick_type.can_pick(&fluid_state) { + crate::collision::fluid_shape(&fluid_state, world, pos) + } else { + &EMPTY_SHAPE + } + } } #[derive(Debug, Copy, Clone)] @@ -63,6 +75,17 @@ pub enum FluidPickType { Any, Water, } +impl FluidPickType { + pub fn can_pick(&self, fluid_state: &FluidState) -> bool { + match self { + Self::None => false, + Self::SourceOnly => fluid_state.amount == 8, + Self::Any => fluid_state.fluid != azalea_registry::Fluid::Empty, + Self::Water => fluid_state.fluid == azalea_registry::Fluid::Water, + } + } +} + #[derive(Debug, Clone)] pub struct EntityCollisionContext { pub descending: bool, @@ -81,15 +104,29 @@ pub fn clip(chunk_storage: &ChunkStorage, context: ClipContext) -> BlockHitResul let block_state = chunk_storage.get_block_state(block_pos).unwrap_or_default(); let fluid_state = FluidState::from(block_state); - // TODO: add fluid stuff to this (see getFluidState in vanilla source) let block_shape = ctx.block_shape(block_state); + let interaction_clip = clip_with_interaction_override( + &ctx.from, + &ctx.to, + block_pos, + block_shape, + &block_state, + ); + let fluid_shape = ctx.fluid_shape(fluid_state, chunk_storage, block_pos); + let fluid_clip = fluid_shape.clip(&ctx.from, &ctx.to, block_pos); - clip_with_interaction_override(&ctx.from, &ctx.to, block_pos, block_shape, &block_state) - // let block_distance = if let Some(block_hit_result) = - // block_hit_result { context.from.distance_squared_to(& - // block_hit_result.location) } else { - // f64::INFINITY - // }; + let distance_to_interaction = interaction_clip + .map(|hit| ctx.from.distance_squared_to(&hit.location)) + .unwrap_or(f64::MAX); + let distance_to_fluid = fluid_clip + .map(|hit| ctx.from.distance_squared_to(&hit.location)) + .unwrap_or(f64::MAX); + + if distance_to_interaction <= distance_to_fluid { + interaction_clip + } else { + fluid_clip + } }, |context| { let vec = context.from - context.to; @@ -107,9 +144,10 @@ fn clip_with_interaction_override( to: &Vec3, block_pos: &BlockPos, block_shape: &VoxelShape, - block_state: &BlockState, + _block_state: &BlockState, ) -> Option<BlockHitResult> { let block_hit_result = block_shape.clip(from, to, block_pos); + if let Some(block_hit_result) = block_hit_result { // TODO: minecraft calls .getInteractionShape here // getInteractionShape is empty for almost every shape except cauldons, @@ -123,9 +161,10 @@ fn clip_with_interaction_override( return Some(block_hit_result.with_direction(interaction_hit_result.direction)); } } + Some(block_hit_result) } else { - block_hit_result + None } } diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index 913cedac..bff9d6f8 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -4,14 +4,21 @@ mod mergers; mod shape; mod world_collisions; -use std::ops::Add; - -use azalea_core::{aabb::AABB, direction::Axis, math::EPSILON, position::Vec3}; -use azalea_world::{Instance, MoveEntityError}; +use std::{ops::Add, sync::LazyLock}; + +use azalea_block::FluidState; +use azalea_core::{ + aabb::AABB, + direction::Axis, + math::EPSILON, + position::{BlockPos, Vec3}, +}; +use azalea_world::{ChunkStorage, Instance, MoveEntityError}; use bevy_ecs::world::Mut; pub use blocks::BlockWithShape; pub use discrete_voxel_shape::*; pub use shape::*; +use tracing::warn; use self::world_collisions::get_block_collisions; @@ -333,3 +340,48 @@ fn collide_with_shapes( z: z_movement, } } + +/// Get the [`VoxelShape`] for the given fluid state. +/// +/// The instance and position are required so it can check if the block above is +/// also the same fluid type. +pub fn fluid_shape( + fluid: &FluidState, + world: &ChunkStorage, + pos: &BlockPos, +) -> &'static VoxelShape { + if fluid.amount == 9 { + let fluid_state_above = world.get_fluid_state(&pos.up(1)).unwrap_or_default(); + if fluid_state_above.fluid == fluid.fluid { + return &BLOCK_SHAPE; + } + } + + // pre-calculate these in a LazyLock so this function can return a + // reference instead + + static FLUID_SHAPES: LazyLock<[VoxelShape; 10]> = LazyLock::new(|| { + [ + calculate_shape_for_fluid(0), + calculate_shape_for_fluid(1), + calculate_shape_for_fluid(2), + calculate_shape_for_fluid(3), + calculate_shape_for_fluid(4), + calculate_shape_for_fluid(5), + calculate_shape_for_fluid(6), + calculate_shape_for_fluid(7), + calculate_shape_for_fluid(8), + calculate_shape_for_fluid(9), + ] + }); + + if fluid.amount > 9 { + warn!("Tried to calculate shape for fluid with height > 9: {fluid:?} at {pos}"); + return &EMPTY_SHAPE; + } + + &FLUID_SHAPES[fluid.amount as usize] +} +fn calculate_shape_for_fluid(amount: u8) -> VoxelShape { + box_shape(0.0, 0.0, 0.0, 1.0, (f32::from(amount) / 9.0) as f64, 1.0) +} diff --git a/azalea-physics/src/collision/shape.rs b/azalea-physics/src/collision/shape.rs index e7ac9c2e..fb733cae 100755 --- a/azalea-physics/src/collision/shape.rs +++ b/azalea-physics/src/collision/shape.rs @@ -413,7 +413,7 @@ impl VoxelShape { VoxelShape::Cube(s) => s.find_index(axis, coord), _ => { let upper_limit = (self.shape().size(axis) + 1) as i32; - binary_search(0, upper_limit, &|t| coord < self.get(axis, t as usize)) - 1 + binary_search(0, upper_limit, |t| coord < self.get(axis, t as usize)) - 1 } } } |
