diff --git a/crates/shared/src/world.rs b/crates/shared/src/world.rs index f734410..f5d561f 100644 --- a/crates/shared/src/world.rs +++ b/crates/shared/src/world.rs @@ -86,4 +86,42 @@ impl ChunkPos { pub fn new(x: i32, y: i32, z: i32) -> Self { Self { x, y, z } } + + /// Initializes a new chunk position from a world-space position measured in blocks. + #[must_use] + #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] + pub fn from_world(x: f64, y: f64, z: f64) -> Self { + ChunkPos { + x: (x.floor() as i32).div_euclid(CHUNK_SIZE as i32), + y: (y.floor() as i32).div_euclid(CHUNK_SIZE as i32), + z: (z.floor() as i32).div_euclid(CHUNK_SIZE as i32), + } + } +} + +#[cfg(test)] +mod tests { + use super::ChunkPos; + + #[test] + fn from_world_maps_positive_positions() { + // A block at 40 falls in chunk 1 (chunk 1 spans blocks 32..=63). + assert_eq!(ChunkPos::from_world(40.0, 0.0, 0.0).x, 1); + // The last block of chunk 0 (block 31) stays in chunk 0. + assert_eq!(ChunkPos::from_world(31.0, 0.0, 0.0).x, 0); + } + + #[test] + fn from_world_floors_negative_positions() { + // Block -1 belongs to chunk -1, not chunk 0: this is the div_euclid contract. + assert_eq!(ChunkPos::from_world(-1.0, 0.0, 0.0).x, -1); + // Block -33 belongs to chunk -2 (chunk -2 spans blocks -64..=-33). + assert_eq!(ChunkPos::from_world(-33.0, 0.0, 0.0).x, -2); + } + + #[test] + fn from_world_floors_fractional_positions() { + // A position of -0.5 lies inside block -1, which is in chunk -1. + assert_eq!(ChunkPos::from_world(-0.5, 0.0, 0.0).x, -1); + } }