aboutsummaryrefslogtreecommitdiff
path: root/azalea-physics/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-physics/src')
-rw-r--r--azalea-physics/src/clip.rs63
-rw-r--r--azalea-physics/src/collision/mod.rs60
-rwxr-xr-xazalea-physics/src/collision/shape.rs2
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
}
}
}