diff --git a/azalea-core/src/direction.rs b/azalea-core/src/direction.rs index 521040f1..ffb517f4 100644 --- a/azalea-core/src/direction.rs +++ b/azalea-core/src/direction.rs @@ -12,18 +12,32 @@ pub enum Direction { East = 5, } +#[derive(Clone, Copy, Debug)] pub enum Axis { X, Y, Z, } +#[derive(Clone, Copy, Debug)] pub enum AxisCycle { None, Forward, Backward, } +impl Axis { + /// Pick x, y, or z from the arguments depending on the axis. + #[inline] + pub fn choose(&self, x: T, y: T, z: T) -> T { + match self { + Axis::X => x, + Axis::Y => y, + Axis::Z => z, + } + } +} + impl AxisCycle { pub fn from_ordinal(ordinal: u32) -> Self { match ordinal { @@ -36,4 +50,18 @@ impl AxisCycle { pub fn between(axis0: Axis, axis1: Axis) -> Self { Self::from_ordinal(floor_mod(axis1 as i32 - axis0 as i32, 3)) } + pub fn inverse(self) -> Self { + match self { + Self::None => Self::None, + Self::Forward => Self::Backward, + Self::Backward => Self::Forward, + } + } + pub fn cycle(self, axis: Axis) -> Self { + match self { + Self::None => Self::None, + Self::Forward => Self::from_ordinal(floor_mod(axis as i32 + 1, 3)), + Self::Backward => Self::from_ordinal(floor_mod(axis as i32 - 1, 3)), + } + } } diff --git a/azalea-physics/src/aabb.rs b/azalea-physics/src/aabb.rs index 020221dc..a6c0f5e4 100644 --- a/azalea-physics/src/aabb.rs +++ b/azalea-physics/src/aabb.rs @@ -1,5 +1,5 @@ use crate::BlockHitResult; -use azalea_core::{BlockPos, Direction, PositionXYZ, Vec3}; +use azalea_core::{Axis, BlockPos, Direction, PositionXYZ, Vec3}; pub const EPSILON: f64 = 1.0E-7; @@ -193,20 +193,18 @@ impl AABB { } pub fn size(&self) -> f64 { - let x = self.get_xsize(); - let y = self.get_ysize(); - let z = self.get_zsize(); + let x = self.get_size(Axis::X); + let y = self.get_size(Axis::Y); + let z = self.get_size(Axis::Z); (x + y + z) / 3.0 } - pub fn get_xsize(&self) -> f64 { - self.max_x - self.min_x - } - pub fn get_ysize(&self) -> f64 { - self.max_y - self.min_y - } - pub fn get_zsize(&self) -> f64 { - self.max_z - self.min_z + pub fn get_size(&self, axis: Axis) -> f64 { + axis.choose( + self.max_x - self.min_x, + self.max_y - self.min_y, + self.max_z - self.min_z, + ) } pub fn deflate(&mut self, x: f64, y: f64, z: f64) -> AABB { @@ -437,4 +435,11 @@ impl AABB { max_z: center.z + dz / 2.0, } } + + pub fn max(&self, axis: &Axis) -> f64 { + axis.choose(self.max_x, self.max_y, self.max_z) + } + pub fn min(&self, axis: &Axis) -> f64 { + axis.choose(self.min_x, self.min_y, self.min_z) + } } diff --git a/azalea-physics/src/shape.rs b/azalea-physics/src/shape.rs index e3caa818..a9f0eb7e 100644 --- a/azalea-physics/src/shape.rs +++ b/azalea-physics/src/shape.rs @@ -1,4 +1,4 @@ -use azalea_core::Axis; +use azalea_core::{Axis, AxisCycle}; use crate::{BitSetDiscreteVoxelShape, DiscreteVoxelShape, AABB, EPSILON}; use std::ops::Add; @@ -20,7 +20,8 @@ pub fn empty_shape() -> Box { } impl Shapes { - pub fn collide_x( + pub fn collide( + axis: &Axis, entity_box: &AABB, collision_boxes: &Vec>, movement: f64, @@ -30,7 +31,7 @@ impl Shapes { if movement.abs() < EPSILON { return 0.; } - movement = shape.collide_x(entity_box, movement); + movement = shape.collide(axis, entity_box, movement); } movement } @@ -57,8 +58,82 @@ pub trait VoxelShape { )) } - fn collide(axis: &Axis, entity_box: &AABB, movement: f64) { - self.collide_x() + fn collide(&self, axis: &Axis, entity_box: &AABB, movement: f64) -> f64 { + self.collide_x(AxisCycle::between(*axis, Axis::X), entity_box, movement) + } + fn collide_x(&self, axis_cycle: AxisCycle, entity_box: &AABB, movement: f64) -> f64 { + if self.shape().is_empty() { + return movement; + } + if movement.abs() < EPSILON { + return 0.; + } + + let inverse_axis_cycle = axis_cycle.inverse(); + + // probably not good names but idk what this does + let x_axis = inverse_axis_cycle.cycle(Axis::X); + let y_axis = inverse_axis_cycle.cycle(Axis::Y); + let z_axis = inverse_axis_cycle.cycle(Axis::Z); + + // i gave up on names at this point (these are the obfuscated names from fernflower) + let var9 = entity_box.max(x_axis); + let var11 = entity_box.min(x_axis); + + let var13 = self.find_index(x_axis, var11 + EPSILON); + let var14 = self.find_index(x_axis, var9 - EPSILON); + + let var15 = cmp::max(0, self.find_index(y_axis, entity_box.min(y_axis) + EPSILON)); + let var16 = cmp::min( + self.shape().get_size(y_axis), + self.find_index(y_axis, entity_box.max(y_axis) - EPSILON) + 1, + ); + + let var17 = cmp::max(0, self.find_index(z_axis, entity_box.min(z_axis) + EPSILON)); + let var18 = cmp::min( + self.shape().get_size(z_axis), + self.find_index(z_axis, entity_box.max(z_axis) - EPSILON) + 1, + ); + + let var19 = self.shape().get_size(x_axis); + + if movement > 0. { + for var20 in var14 + 1..var19 { + for var21 in var15..var16 { + for var22 in var17..var18 { + if self + .shape() + .is_full_wide(inverse_axis_cycle, var20, var21, var22) + { + let var23 = self.get(x_axis, var20) - var9; + if var23 >= -EPSILON { + movement = cmp::min(movement, var23); + } + return movement; + } + } + } + } + } else if movement < 0. { + for var20 in (var13 - 1)..=0 { + for var21 in var15..var16 { + for var22 in var17..var18 { + if self + .shape() + .is_full_wide(inverse_axis_cycle, var20, var21, var22) + { + let var23 = self.get(x_axis, var20 + 1) - var11; + if var23 <= EPSILON { + movement = cmp::max(movement, var23); + } + return movement; + } + } + } + } + } + + return movement; } }