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-physics/src/collision | |
| 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-physics/src/collision')
| -rwxr-xr-x | azalea-physics/src/collision/discrete_voxel_shape.rs | 36 | ||||
| -rw-r--r-- | azalea-physics/src/collision/mod.rs | 44 | ||||
| -rwxr-xr-x | azalea-physics/src/collision/shape.rs | 67 | ||||
| -rw-r--r-- | azalea-physics/src/collision/world_collisions.rs | 29 |
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); |
