diff --git a/Cargo.lock b/Cargo.lock index c77a753d..5f817777 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,7 @@ version = "0.1.0" dependencies = [ "azalea-core", "azalea-entity", + "azalea-world", ] [[package]] diff --git a/azalea-core/src/cursor3d.rs b/azalea-core/src/cursor3d.rs new file mode 100644 index 00000000..9083e7a7 --- /dev/null +++ b/azalea-core/src/cursor3d.rs @@ -0,0 +1,108 @@ +pub struct Cursor3d { + index: usize, + + origin_x: i32, + origin_y: i32, + origin_z: i32, + + width: usize, + height: usize, + depth: usize, + + end: usize, +} + +impl Iterator for Cursor3d { + type Item = CursorIteration; + + fn next(&mut self) -> Option { + if self.index == self.end { + return None; + } + let x = self.index % self.width; + let r = self.index / self.width; + let y = r % self.height; + let z = r / self.height; + self.index += 1; + + let mut iteration_type = 0; + if x == 0 || x == self.width - 1 { + iteration_type += 1; + } + if y == 0 || y == self.height - 1 { + iteration_type += 1; + } + if z == 0 || z == self.depth - 1 { + iteration_type += 1; + } + + Some(CursorIteration { + x: self.origin_x + x as i32, + y: self.origin_y + y as i32, + z: self.origin_z + z as i32, + iteration_type: iteration_type.into(), + }) + } +} + +#[repr(u8)] +pub enum CursorIterationType { + Inside = 0, + Face = 1, + Edge = 2, + Corner = 3, +} + +pub struct CursorIteration { + pub x: i32, + pub y: i32, + pub z: i32, + pub iteration_type: CursorIterationType, +} + +impl Cursor3d { + pub fn new( + origin_x: i32, + origin_y: i32, + origin_z: i32, + end_x: i32, + end_y: i32, + end_z: i32, + ) -> Self { + let width = (end_x - origin_x + 1) + .try_into() + .expect("Impossible width."); + let height = (end_y - origin_y + 1) + .try_into() + .expect("Impossible height."); + let depth = (end_z - origin_z + 1) + .try_into() + .expect("Impossible depth."); + + Self { + index: 0, + + origin_x, + origin_y, + origin_z, + + width, + height, + depth, + + end: width * height * depth, + } + } +} + +impl From for CursorIterationType { + fn from(value: u8) -> Self { + match value { + 0 => CursorIterationType::Inside, + 1 => CursorIterationType::Face, + 2 => CursorIterationType::Edge, + 3 => CursorIterationType::Corner, + _ => panic!("Invalid iteration type"), + } + } +} diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs index a1fa1fca..0b3e18bd 100755 --- a/azalea-core/src/lib.rs +++ b/azalea-core/src/lib.rs @@ -25,3 +25,6 @@ pub use delta::*; mod particle; pub use particle::*; + +mod cursor3d; +pub use cursor3d::*; diff --git a/azalea-physics/Cargo.toml b/azalea-physics/Cargo.toml index fc007e18..910167d4 100644 --- a/azalea-physics/Cargo.toml +++ b/azalea-physics/Cargo.toml @@ -8,3 +8,4 @@ version = "0.1.0" [dependencies] azalea-core = {path = "../azalea-core"} azalea-entity = {path = "../azalea-entity"} +azalea-world = {path = "../azalea-world"} diff --git a/azalea-physics/src/aabb.rs b/azalea-physics/src/aabb.rs index 46e93317..741daa05 100644 --- a/azalea-physics/src/aabb.rs +++ b/azalea-physics/src/aabb.rs @@ -53,7 +53,7 @@ impl AABB { } } - pub fn expand_towards(&mut self, x: f64, y: f64, z: f64) -> AABB { + pub fn expand_towards(&mut self, other: &Vec3) -> AABB { let mut min_x = self.min_x; let mut min_y = self.min_y; let mut min_z = self.min_z; @@ -62,22 +62,22 @@ impl AABB { let mut max_y = self.max_y; let mut max_z = self.max_z; - if x < 0.0 { - min_x += x; - } else if x > 0.0 { - max_x += x; + if other.x < 0.0 { + min_x += other.x; + } else if other.x > 0.0 { + max_x += other.x; } - if y < 0.0 { - min_y += y; - } else if y > 0.0 { - max_y += y; + if other.y < 0.0 { + min_y += other.y; + } else if other.y > 0.0 { + max_y += other.y; } - if z < 0.0 { - min_z += z; - } else if z > 0.0 { - max_z += z; + if other.z < 0.0 { + min_z += other.z; + } else if other.z > 0.0 { + max_z += other.z; } AABB { diff --git a/azalea-physics/src/dimension_collisions.rs b/azalea-physics/src/dimension_collisions.rs new file mode 100644 index 00000000..bbac09de --- /dev/null +++ b/azalea-physics/src/dimension_collisions.rs @@ -0,0 +1,48 @@ +use azalea_entity::Entity; +use azalea_world::Dimension; + +use crate::AABB; + +trait CollisionGetter { + fn get_block_collisions<'a>( + &'a self, + entity: Option<&Entity>, + aabb: AABB, + ) -> BlockCollisions<'a>; +} + +impl CollisionGetter for Dimension { + fn get_block_collisions<'a>( + &'a self, + entity: Option<&Entity>, + aabb: AABB, + ) -> BlockCollisions<'a> { + BlockCollisions::new(self, entity, aabb) + } +} + +pub struct BlockCollisions<'a> { + dimension: &'a Dimension, + // context: CollisionContext, + aabb: AABB, +} + +impl<'a> BlockCollisions<'a> { + pub fn new(dimension: &'a Dimension, entity: Option<&Entity>, aabb: AABB) -> Self { + Self { dimension, aabb } + } +} + +impl Iterator for BlockCollisions<'a> { + type Item = VoxelShape; + + fn next(&mut self) -> Option { + loop { + if !self.cursor.advance() { + return None; + } + } + } +} + +pub struct VoxelShape {} diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 45ac0186..1f50473c 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -1,9 +1,11 @@ mod aabb; mod block_hit_result; +mod dimension_collisions; pub use aabb::AABB; use azalea_core::{PositionDelta, PositionXYZ, Vec3}; use azalea_entity::Entity; +use azalea_world::Dimension; pub use block_hit_result::BlockHitResult; pub enum MoverType { @@ -16,6 +18,13 @@ pub enum MoverType { trait HasPhysics { fn move_entity(&mut self, mover_type: &MoverType, movement: &PositionDelta); + fn collide_bounding_box( + entity: Option<&Self>, + movement: &Vec3, + entity_bounding_box: &AABB, + dimension: &Dimension, + // entity_collisions: Vec + ) -> Vec3; } impl HasPhysics for Entity { @@ -55,5 +64,22 @@ impl HasPhysics for Entity { // } // } - // fn collide_bounding_box(self: ) + fn collide_bounding_box( + entity: Option<&Self>, + movement: &Vec3, + entity_bounding_box: &AABB, + dimension: &Dimension, + // entity_collisions: Vec + ) -> Vec3 { + let mut collision_boxes = Vec::with_capacity(1); // entity_collisions.len() + 1 + + // if !entity_collisions.is_empty() { add to collision_boxes } + + // TODO: world border + + let block_collisions = + dimension.get_block_collisions(entity, entity_bounding_box.expand_towards(movement)); + collision_boxes.extend(block_collisions); + Self::collide_with_shapes(movement, &entity_bounding_box, &collision_boxes) + } } diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs index 5c5d316e..207b3781 100644 --- a/azalea-world/src/lib.rs +++ b/azalea-world/src/lib.rs @@ -28,6 +28,8 @@ mod tests { } /// A dimension is a collection of chunks and entities. +/// Minecraft calls these "Levels", Fabric calls them "Worlds", Minestom calls them "Instances". +/// Yeah. #[derive(Debug)] pub struct Dimension { chunk_storage: ChunkStorage,