diff --git a/azalea-core/src/direction.rs b/azalea-core/src/direction.rs index d3083922..521040f1 100644 --- a/azalea-core/src/direction.rs +++ b/azalea-core/src/direction.rs @@ -1,5 +1,7 @@ use azalea_buf::McBuf; +use crate::floor_mod; + #[derive(Clone, Copy, Debug, McBuf)] pub enum Direction { Down = 0, @@ -9,3 +11,29 @@ pub enum Direction { West = 4, East = 5, } + +pub enum Axis { + X, + Y, + Z, +} + +pub enum AxisCycle { + None, + Forward, + Backward, +} + +impl AxisCycle { + pub fn from_ordinal(ordinal: u32) -> Self { + match ordinal { + 0 => Self::None, + 1 => Self::Forward, + 2 => Self::Backward, + _ => panic!("invalid ordinal"), + } + } + pub fn between(axis0: Axis, axis1: Axis) -> Self { + Self::from_ordinal(floor_mod(axis1 as i32 - axis0 as i32, 3)) + } +} diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs index 7bb48650..cea97458 100755 --- a/azalea-core/src/lib.rs +++ b/azalea-core/src/lib.rs @@ -12,13 +12,13 @@ mod game_type; pub use game_type::*; mod slot; -pub use slot::{Slot, SlotData}; +pub use slot::*; mod position; pub use position::*; mod direction; -pub use direction::Direction; +pub use direction::*; mod delta; pub use delta::*; @@ -31,3 +31,13 @@ pub use cursor3d::*; mod bitset; pub use bitset::*; + +// java moment +// TODO: add tests and optimize/simplify this +pub fn floor_mod(x: i32, y: u32) -> u32 { + if x < 0 { + y - ((-x) as u32 % y) + } else { + x as u32 % y + } +} diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 04a8ea5a..5de85fea 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -100,7 +100,46 @@ impl HasPhysics for Entity { entity_box: &AABB, collision_boxes: &Vec>, ) -> Vec3 { - // TODO - *movement + if collision_boxes.is_empty() { + return *movement; + } + + let mut x_movement = movement.x; + let mut y_movement = movement.y; + let mut z_movement = movement.z; + if y_movement != 0. { + y_movement = Shapes::collide_y(entity_box, collision_boxes, y_movement); + if y_movement != 0. { + *entity_box = entity_box.move_relative(0., y_movement, 0.); + } + } + + // whether the player is moving more in the z axis than x + // this is done to fix a movement bug, minecraft does this too + let more_z_movement = x_movement.abs() < z_movement.abs(); + + if more_z_movement && z_movement != 0. { + z_movement = Shapes::collide_z(entity_box, collision_boxes, z_movement); + if z_movement != 0. { + *entity_box = entity_box.move_relative(0., 0., z_movement); + } + } + + if x_movement != 0. { + x_movement = Shapes::collide_x(entity_box, collision_boxes, x_movement); + if x_movement != 0. { + *entity_box = entity_box.move_relative(x_movement, 0., 0.); + } + } + + if !more_z_movement && z_movement != 0. { + z_movement = Shapes::collide_z(entity_box, collision_boxes, z_movement); + } + + Vec3 { + x: x_movement, + y: y_movement, + z: z_movement, + } } } diff --git a/azalea-physics/src/shape.rs b/azalea-physics/src/shape.rs index 52f29d32..e3caa818 100644 --- a/azalea-physics/src/shape.rs +++ b/azalea-physics/src/shape.rs @@ -1,4 +1,6 @@ -use crate::{BitSetDiscreteVoxelShape, DiscreteVoxelShape}; +use azalea_core::Axis; + +use crate::{BitSetDiscreteVoxelShape, DiscreteVoxelShape, AABB, EPSILON}; use std::ops::Add; pub struct Shapes {} @@ -17,6 +19,23 @@ pub fn empty_shape() -> Box { )) } +impl Shapes { + pub fn collide_x( + entity_box: &AABB, + collision_boxes: &Vec>, + movement: f64, + ) -> f64 { + let mut shape: Box; + for shape in collision_boxes { + if movement.abs() < EPSILON { + return 0.; + } + movement = shape.collide_x(entity_box, movement); + } + movement + } +} + pub trait VoxelShape { fn shape(&self) -> Box; @@ -37,6 +56,10 @@ pub trait VoxelShape { self.get_z_coords().iter().map(|c| c + z).collect(), )) } + + fn collide(axis: &Axis, entity_box: &AABB, movement: f64) { + self.collide_x() + } } pub struct ArrayVoxelShape { diff --git a/azalea-world/src/chunk.rs b/azalea-world/src/chunk.rs index e4893ace..67c2c425 100644 --- a/azalea-world/src/chunk.rs +++ b/azalea-world/src/chunk.rs @@ -3,6 +3,7 @@ use crate::palette::PalettedContainerType; use crate::Dimension; use azalea_block::BlockState; use azalea_buf::{McBufReadable, McBufWritable}; +use azalea_core::floor_mod; use azalea_core::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos}; use std::fmt::Debug; use std::{ @@ -23,16 +24,6 @@ pub struct ChunkStorage { chunks: Vec>>>, } -// java moment -// it might be possible to replace this with just a modulo, but i copied java's floorMod just in case -fn floor_mod(x: i32, y: u32) -> u32 { - if x < 0 { - y - ((-x) as u32 % y) - } else { - x as u32 % y - } -} - impl ChunkStorage { pub fn new(chunk_radius: u32, height: u32, min_y: i32) -> Self { let view_range = chunk_radius * 2 + 1;