aboutsummaryrefslogtreecommitdiff
path: root/azalea-physics/src/collision
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-01-10 16:45:27 -0600
committerGitHub <noreply@github.com>2025-01-10 16:45:27 -0600
commit0d16f01571ec8315f3979eae46981e559ade1cf9 (patch)
treeea43c32a57b0e6a67579d75a134dfbc009d09781 /azalea-physics/src/collision
parent615d8f9d2ac56b3244d328587243301da253eafd (diff)
downloadazalea-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-physics/src/collision')
-rwxr-xr-xazalea-physics/src/collision/discrete_voxel_shape.rs36
-rw-r--r--azalea-physics/src/collision/mod.rs44
-rwxr-xr-xazalea-physics/src/collision/shape.rs67
-rw-r--r--azalea-physics/src/collision/world_collisions.rs29
4 files changed, 85 insertions, 91 deletions
diff --git a/azalea-physics/src/collision/discrete_voxel_shape.rs b/azalea-physics/src/collision/discrete_voxel_shape.rs
index 211e6303..cacbc987 100755
--- a/azalea-physics/src/collision/discrete_voxel_shape.rs
+++ b/azalea-physics/src/collision/discrete_voxel_shape.rs
@@ -238,39 +238,33 @@ impl BitSetDiscreteVoxelShape {
var2: bool,
) {
let mut var3 = BitSetDiscreteVoxelShape::from(var0);
- for var4 in 0..var3.y_size {
- for var5 in 0..var3.x_size {
+ for y in 0..var3.y_size {
+ for x in 0..var3.x_size {
let mut var6 = None;
- for var7 in 0..=var3.z_size {
- if var3.is_full_wide(var5, var4, var7) {
+ for z in 0..=var3.z_size {
+ if var3.is_full_wide(x, y, z) {
if var2 {
if var6.is_none() {
- var6 = Some(var7);
+ var6 = Some(z);
}
} else {
- consumer(var5, var4, var7, var5 + 1, var4 + 1, var7 + 1);
+ consumer(x, y, z, x + 1, y + 1, z + 1);
}
} else if var6.is_some() {
- let mut var8 = var5;
- let mut var9 = var4;
- var3.clear_z_strip(var6.unwrap(), var7, var5, var4);
- while var3.is_z_strip_full(var6.unwrap(), var7, var8 + 1, var4) {
- var3.clear_z_strip(var6.unwrap(), var7, var8 + 1, var4);
+ let mut var8 = x;
+ let mut var9 = y;
+ var3.clear_z_strip(var6.unwrap(), z, x, y);
+ while var3.is_z_strip_full(var6.unwrap(), z, var8 + 1, y) {
+ var3.clear_z_strip(var6.unwrap(), z, var8 + 1, y);
var8 += 1;
}
- while var3.is_xz_rectangle_full(
- var5,
- var8 + 1,
- var6.unwrap(),
- var7,
- var9 + 1,
- ) {
- for var10 in var5..=var8 {
- var3.clear_z_strip(var6.unwrap(), var7, var10, var9 + 1);
+ while var3.is_xz_rectangle_full(x, var8 + 1, var6.unwrap(), z, var9 + 1) {
+ for var10 in x..=var8 {
+ var3.clear_z_strip(var6.unwrap(), z, var10, var9 + 1);
}
var9 += 1;
}
- consumer(var5, var4, var6.unwrap(), var8 + 1, var9 + 1, var7);
+ consumer(x, y, var6.unwrap(), var8 + 1, var9 + 1, z);
var6 = None;
}
}
diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs
index 39fc43f8..530aa47f 100644
--- a/azalea-physics/src/collision/mod.rs
+++ b/azalea-physics/src/collision/mod.rs
@@ -6,7 +6,7 @@ mod world_collisions;
use std::{ops::Add, sync::LazyLock};
-use azalea_block::FluidState;
+use azalea_block::{fluid_state::FluidState, BlockState};
use azalea_core::{
aabb::AABB,
direction::Axis,
@@ -22,6 +22,7 @@ use tracing::warn;
use self::world_collisions::get_block_collisions;
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MoverType {
Own,
Player,
@@ -111,7 +112,7 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
y: 0.,
z: movement.z,
},
- &entity_bounding_box.move_relative(&directly_up_delta),
+ &entity_bounding_box.move_relative(directly_up_delta),
world,
entity_collisions.clone(),
)
@@ -132,7 +133,7 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
y: -step_to_delta.y + movement.y,
z: 0.,
},
- &entity_bounding_box.move_relative(&step_to_delta),
+ &entity_bounding_box.move_relative(step_to_delta),
world,
entity_collisions.clone(),
));
@@ -143,8 +144,10 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
}
/// Move an entity by a given delta, checking for collisions.
+///
+/// In Mojmap, this is `Entity.move`.
pub fn move_colliding(
- _mover_type: &MoverType,
+ _mover_type: MoverType,
movement: &Vec3,
world: &Instance,
position: &mut Mut<azalea_entity::Position>,
@@ -296,7 +299,7 @@ fn collide_with_shapes(
if y_movement != 0. {
y_movement = Shapes::collide(&Axis::Y, &entity_box, collision_boxes, y_movement);
if y_movement != 0. {
- entity_box = entity_box.move_relative(&Vec3 {
+ entity_box = entity_box.move_relative(Vec3 {
x: 0.,
y: y_movement,
z: 0.,
@@ -311,7 +314,7 @@ fn collide_with_shapes(
if more_z_movement && z_movement != 0. {
z_movement = Shapes::collide(&Axis::Z, &entity_box, collision_boxes, z_movement);
if z_movement != 0. {
- entity_box = entity_box.move_relative(&Vec3 {
+ entity_box = entity_box.move_relative(Vec3 {
x: 0.,
y: 0.,
z: z_movement,
@@ -322,7 +325,7 @@ fn collide_with_shapes(
if x_movement != 0. {
x_movement = Shapes::collide(&Axis::X, &entity_box, collision_boxes, x_movement);
if x_movement != 0. {
- entity_box = entity_box.move_relative(&Vec3 {
+ entity_box = entity_box.move_relative(Vec3 {
x: x_movement,
y: 0.,
z: 0.,
@@ -352,7 +355,7 @@ pub fn fluid_shape(
) -> &'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 {
+ if fluid_state_above.kind == fluid.kind {
return &BLOCK_SHAPE;
}
}
@@ -384,3 +387,28 @@ pub fn fluid_shape(
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)
}
+
+/// Whether the block is treated as "motion blocking".
+///
+/// This is marked as deprecated in Minecraft.
+pub fn legacy_blocks_motion(block: BlockState) -> bool {
+ let registry_block = azalea_registry::Block::from(block);
+ legacy_calculate_solid(block)
+ && registry_block != azalea_registry::Block::Cobweb
+ && registry_block != azalea_registry::Block::BambooSapling
+}
+
+pub fn legacy_calculate_solid(block: BlockState) -> bool {
+ // force_solid has to be checked before anything else
+ let block_trait = Box::<dyn azalea_block::Block>::from(block);
+ if let Some(solid) = block_trait.behavior().force_solid {
+ return solid;
+ }
+
+ let shape = block.collision_shape();
+ if shape.is_empty() {
+ return false;
+ }
+ let bounds = shape.bounds();
+ bounds.size() >= 0.7291666666666666 || bounds.get_size(Axis::Y) >= 1.0
+}
diff --git a/azalea-physics/src/collision/shape.rs b/azalea-physics/src/collision/shape.rs
index fb733cae..9d870498 100755
--- a/azalea-physics/src/collision/shape.rs
+++ b/azalea-physics/src/collision/shape.rs
@@ -381,16 +381,25 @@ impl VoxelShape {
}
#[must_use]
- pub fn move_relative(&self, x: f64, y: f64, z: f64) -> VoxelShape {
+ pub fn move_relative(&self, delta: Vec3) -> VoxelShape {
if self.shape().is_empty() {
return EMPTY_SHAPE.clone();
}
VoxelShape::Array(ArrayVoxelShape::new(
self.shape().to_owned(),
- self.get_coords(Axis::X).iter().map(|c| c + x).collect(),
- self.get_coords(Axis::Y).iter().map(|c| c + y).collect(),
- self.get_coords(Axis::Z).iter().map(|c| c + z).collect(),
+ self.get_coords(Axis::X)
+ .iter()
+ .map(|c| c + delta.x)
+ .collect(),
+ self.get_coords(Axis::Y)
+ .iter()
+ .map(|c| c + delta.y)
+ .collect(),
+ self.get_coords(Axis::Z)
+ .iter()
+ .map(|c| c + delta.z)
+ .collect(),
))
}
@@ -526,13 +535,6 @@ impl VoxelShape {
movement
}
- // public VoxelShape optimize() {
- // VoxelShape[] var1 = new VoxelShape[]{Shapes.empty()};
- // this.forAllBoxes((var1x, var3, var5, var7, var9, var11) -> {
- // var1[0] = Shapes.joinUnoptimized(var1[0], Shapes.box(var1x, var3,
- // var5, var7, var9, var11), BooleanOp.OR); });
- // return var1[0];
- // }
fn optimize(&self) -> VoxelShape {
let mut shape = EMPTY_SHAPE.clone();
self.for_all_boxes(|var1x, var3, var5, var7, var9, var11| {
@@ -545,35 +547,10 @@ impl VoxelShape {
shape
}
- // public void forAllBoxes(Shapes.DoubleLineConsumer var1) {
- // DoubleList var2 = this.getCoords(Direction.Axis.X);
- // DoubleList var3 = this.getCoords(Direction.Axis.Y);
- // DoubleList var4 = this.getCoords(Direction.Axis.Z);
- // this.shape.forAllBoxes((var4x, var5, var6, var7, var8, var9) -> {
- // var1.consume(var2.getDouble(var4x), var3.getDouble(var5),
- // var4.getDouble(var6), var2.getDouble(var7), var3.getDouble(var8),
- // var4.getDouble(var9)); }, true);
- // }
pub fn for_all_boxes(&self, mut consumer: impl FnMut(f64, f64, f64, f64, f64, f64))
where
Self: Sized,
{
- // let x_coords = self.get_coords(Axis::X);
- // let y_coords = self.get_coords(Axis::Y);
- // let z_coords = self.get_coords(Axis::Z);
- // self.shape().for_all_boxes(
- // |var4x, var5, var6, var7, var8, var9| {
- // consumer(
- // x_coords[var4x as usize],
- // y_coords[var5 as usize],
- // z_coords[var6 as usize],
- // x_coords[var7 as usize],
- // y_coords[var8 as usize],
- // z_coords[var9 as usize],
- // )
- // },
- // true,
- // );
let x_coords = self.get_coords(Axis::X);
let y_coords = self.get_coords(Axis::Y);
let z_coords = self.get_coords(Axis::Z);
@@ -596,22 +573,26 @@ impl VoxelShape {
let mut aabbs = Vec::new();
self.for_all_boxes(|min_x, min_y, min_z, max_x, max_y, max_z| {
aabbs.push(AABB {
- min_x,
- min_y,
- min_z,
- max_x,
- max_y,
- max_z,
+ min: Vec3::new(min_x, min_y, min_z),
+ max: Vec3::new(max_x, max_y, max_z),
});
});
aabbs
}
+
+ pub fn bounds(&self) -> AABB {
+ assert!(!self.is_empty(), "Can't get bounds for empty shape");
+ AABB {
+ min: Vec3::new(self.min(Axis::X), self.min(Axis::Y), self.min(Axis::Z)),
+ max: Vec3::new(self.max(Axis::X), self.max(Axis::Y), self.max(Axis::Z)),
+ }
+ }
}
impl From<AABB> for VoxelShape {
fn from(aabb: AABB) -> Self {
box_shape_unchecked(
- aabb.min_x, aabb.min_y, aabb.min_z, aabb.max_x, aabb.max_y, aabb.max_z,
+ aabb.min.x, aabb.min.y, aabb.min.z, aabb.max.x, aabb.max.y, aabb.max.z,
)
}
}
diff --git a/azalea-physics/src/collision/world_collisions.rs b/azalea-physics/src/collision/world_collisions.rs
index 36488777..f0b41986 100644
--- a/azalea-physics/src/collision/world_collisions.rs
+++ b/azalea-physics/src/collision/world_collisions.rs
@@ -49,28 +49,19 @@ pub fn get_block_collisions(world: &Instance, aabb: AABB) -> Vec<VoxelShape> {
// if it's a full block do a faster collision check
if block_state.is_collision_shape_full() {
if !state.aabb.intersects_aabb(&AABB {
- min_x: item.pos.x as f64,
- min_y: item.pos.y as f64,
- min_z: item.pos.z as f64,
- max_x: (item.pos.x + 1) as f64,
- max_y: (item.pos.y + 1) as f64,
- max_z: (item.pos.z + 1) as f64,
+ min: item.pos.to_vec3_floored(),
+ max: (item.pos + 1).to_vec3_floored(),
}) {
continue;
}
- block_collisions.push(BLOCK_SHAPE.move_relative(
- item.pos.x as f64,
- item.pos.y as f64,
- item.pos.z as f64,
- ));
+ block_collisions.push(BLOCK_SHAPE.move_relative(item.pos.to_vec3_floored()));
continue;
}
let block_shape = state.get_block_shape(block_state);
- let block_shape =
- block_shape.move_relative(item.pos.x as f64, item.pos.y as f64, item.pos.z as f64);
+ let block_shape = block_shape.move_relative(item.pos.to_vec3_floored());
// if the entity shape and block shape don't collide, continue
if !Shapes::matches_anywhere(&block_shape, &state.entity_shape, |a, b| a && b) {
continue;
@@ -95,15 +86,15 @@ pub struct BlockCollisionsState<'a> {
impl<'a> BlockCollisionsState<'a> {
pub fn new(world: &'a Instance, aabb: AABB) -> Self {
let origin = BlockPos {
- x: (aabb.min_x - EPSILON).floor() as i32 - 1,
- y: (aabb.min_y - EPSILON).floor() as i32 - 1,
- z: (aabb.min_z - EPSILON).floor() as i32 - 1,
+ x: (aabb.min.x - EPSILON).floor() as i32 - 1,
+ y: (aabb.min.y - EPSILON).floor() as i32 - 1,
+ z: (aabb.min.z - EPSILON).floor() as i32 - 1,
};
let end = BlockPos {
- x: (aabb.max_x + EPSILON).floor() as i32 + 1,
- y: (aabb.max_y + EPSILON).floor() as i32 + 1,
- z: (aabb.max_z + EPSILON).floor() as i32 + 1,
+ x: (aabb.max.x + EPSILON).floor() as i32 + 1,
+ y: (aabb.max.y + EPSILON).floor() as i32 + 1,
+ z: (aabb.max.z + EPSILON).floor() as i32 + 1,
};
let cursor = Cursor3d::new(origin, end);