diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs index 522d7d48..8d2e9dc1 100755 --- a/azalea-client/src/connect.rs +++ b/azalea-client/src/connect.rs @@ -195,9 +195,17 @@ impl Client { .expect("height tag is not int")) .try_into() .expect("height is not a u32"); + let min_y = (*dimension_type + .get("min_y") + .expect("No min_y tag") + .as_int() + .expect("min_y tag is not int")) + .try_into() + .expect("min_y is not an i32"); state.world = Some(World { height, + min_y, storage: ChunkStorage::new(16), }); diff --git a/azalea-core/src/difficulty.rs b/azalea-core/src/difficulty.rs index 21e980ba..5d869325 100755 --- a/azalea-core/src/difficulty.rs +++ b/azalea-core/src/difficulty.rs @@ -83,7 +83,6 @@ mod tests { assert_eq!(1, Difficulty::EASY.id()); assert_eq!(2, Difficulty::NORMAL.id()); assert_eq!(3, Difficulty::HARD.id()); - assert_eq!(4, Difficulty::PEACEFUL.id()); } #[test] diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs index 2b12db53..d2a2d558 100755 --- a/azalea-core/src/lib.rs +++ b/azalea-core/src/lib.rs @@ -1,5 +1,7 @@ //! Random miscellaneous things like UUIDs that don't deserve their own crate. +#![feature(int_roundings)] + pub mod difficulty; pub mod game_type; pub mod resource_location; @@ -9,7 +11,7 @@ mod slot; pub use slot::{Slot, SlotData}; mod position; -pub use position::{BlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos}; +pub use position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos}; mod direction; pub use direction::Direction; diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs index 1dd200ab..9c7cd132 100644 --- a/azalea-core/src/position.rs +++ b/azalea-core/src/position.rs @@ -25,7 +25,7 @@ impl Rem for BlockPos { } } -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct ChunkPos { pub x: i32, pub z: i32, @@ -40,8 +40,8 @@ impl ChunkPos { impl From<&BlockPos> for ChunkPos { fn from(pos: &BlockPos) -> Self { ChunkPos { - x: pos.x / 16, - z: pos.z / 16, + x: pos.x.div_floor(16), + z: pos.z.div_floor(16), } } } @@ -63,9 +63,9 @@ impl ChunkSectionPos { impl From for ChunkSectionPos { fn from(pos: BlockPos) -> Self { ChunkSectionPos { - x: pos.x / 16, - y: pos.y / 16, - z: pos.z / 16, + x: pos.x.div_floor(16), + y: pos.y.div_floor(16), + z: pos.z.div_floor(16), } } } @@ -76,11 +76,38 @@ impl From for ChunkPos { } } +/// The coordinates of a block inside a chunk. +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct ChunkBlockPos { + pub x: u8, + pub y: i32, + pub z: u8, +} + +impl ChunkBlockPos { + pub fn new(x: u8, y: i32, z: u8) -> Self { + ChunkBlockPos { x, y, z } + } +} + +impl From<&BlockPos> for ChunkBlockPos { + fn from(pos: &BlockPos) -> Self { + ChunkBlockPos { + x: pos.x.rem_euclid(16).abs() as u8, + y: pos.y, + z: pos.z.rem_euclid(16).abs() as u8, + } + } +} + /// The coordinates of a block inside a chunk section. #[derive(Clone, Copy, Debug, Default)] pub struct ChunkSectionBlockPos { + /// A number between 0 and 16. pub x: u8, + /// A number between 0 and 16. pub y: u8, + /// A number between 0 and 16. pub z: u8, } @@ -99,3 +126,32 @@ impl From<&BlockPos> for ChunkSectionBlockPos { } } } + +impl From<&ChunkBlockPos> for ChunkSectionBlockPos { + fn from(pos: &ChunkBlockPos) -> Self { + ChunkSectionBlockPos { + x: pos.x, + y: pos.y.rem(16).abs() as u8, + z: pos.z, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_from_block_pos_to_chunk_pos() { + let block_pos = BlockPos::new(5, 78, -2); + let chunk_pos = ChunkPos::from(&block_pos); + assert_eq!(chunk_pos, ChunkPos::new(0, -1)); + } + + #[test] + fn test_from_block_pos_to_chunk_block_pos() { + let block_pos = BlockPos::new(5, 78, -2); + let chunk_block_pos = ChunkBlockPos::from(&block_pos); + assert_eq!(chunk_block_pos, ChunkBlockPos::new(5, 78, 14)); + } +} diff --git a/azalea-world/src/bit_storage.rs b/azalea-world/src/bit_storage.rs index f24a0514..aba52aef 100644 --- a/azalea-world/src/bit_storage.rs +++ b/azalea-world/src/bit_storage.rs @@ -148,7 +148,6 @@ impl BitStorage { // as unsigned wrap let first = self.divide_mul as u32 as u64; let second = self.divide_add as u64; - dbg!(first, second, index); (((index * first) + second) >> 32 >> self.divide_shift) .try_into() diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs index aa99a470..4641729c 100644 --- a/azalea-world/src/lib.rs +++ b/azalea-world/src/lib.rs @@ -1,8 +1,10 @@ +#![feature(int_roundings)] + mod bit_storage; mod palette; use crate::palette::PalettedContainerType; -use azalea_core::{BlockPos, ChunkPos, ChunkSectionBlockPos}; +use azalea_core::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos}; use azalea_protocol::mc_buf::{McBufReadable, McBufWritable}; pub use bit_storage::BitStorage; use palette::PalettedContainer; @@ -26,6 +28,7 @@ const SECTION_HEIGHT: u32 = 16; pub struct World { pub storage: ChunkStorage, pub height: u32, + pub min_y: i32, } impl World { @@ -55,7 +58,7 @@ impl World { } pub fn get_block_state(&self, pos: &BlockPos) -> Option { - self.storage.get_block_state(pos) + self.storage.get_block_state(pos, self.min_y) } } impl Index<&ChunkPos> for World { @@ -119,11 +122,12 @@ impl ChunkStorage { && (chunk_pos.z - self.view_center.z).unsigned_abs() <= self.chunk_radius } - pub fn get_block_state(&self, pos: &BlockPos) -> Option { + pub fn get_block_state(&self, pos: &BlockPos, min_y: i32) -> Option { let chunk_pos = ChunkPos::from(pos); + println!("chunk_pos {:?} block_pos {:?}", chunk_pos, pos); let chunk = &self[&chunk_pos]; match chunk { - Some(chunk) => Some(chunk.lock().unwrap().get(pos)), + Some(chunk) => Some(chunk.lock().unwrap().get(&ChunkBlockPos::from(pos), min_y)), None => None, } } @@ -156,26 +160,28 @@ impl Chunk { pub fn read_with_world_height(buf: &mut impl Read, world_height: u32) -> Result { let section_count = world_height / SECTION_HEIGHT; let mut sections = Vec::with_capacity(section_count as usize); - for i in 0..section_count { + for _ in 0..section_count { let section = Section::read_into(buf)?; sections.push(section); } Ok(Chunk { sections }) } - pub fn section_index(&self, y: i32) -> u32 { + pub fn section_index(&self, y: i32, min_y: i32) -> u32 { // TODO: check the build height and stuff, this code will be broken if the min build height is 0 // (LevelHeightAccessor.getMinSection in vanilla code) assert!(y >= 0); - (y as u32) / 16 + let min_section_index = min_y.div_floor(16); + (y.div_floor(16) - min_section_index) as u32 } - pub fn get(&self, pos: &BlockPos) -> u32 { - let section_index = self.section_index(pos.y); + pub fn get(&self, pos: &ChunkBlockPos, min_y: i32) -> u32 { + let section_index = self.section_index(pos.y, min_y); println!("section index: {}", section_index); // TODO: make sure the section exists let section = &self.sections[section_index as usize]; let chunk_section_pos = ChunkSectionBlockPos::from(pos); + println!("chunk section pos: {:?}", chunk_section_pos); let block_state = section.get(chunk_section_pos); block_state } diff --git a/azalea-world/src/palette.rs b/azalea-world/src/palette.rs index 6dc5e183..be6f022c 100644 --- a/azalea-world/src/palette.rs +++ b/azalea-world/src/palette.rs @@ -62,11 +62,8 @@ impl PalettedContainer { } pub fn get(&self, x: usize, y: usize, z: usize) -> u32 { - println!( - "get: {} {} {}, bits per entry: {}", - x, y, z, self.bits_per_entry - ); let paletted_value = self.storage.get(self.get_index(x, y, z)); + println!("palette: {:?}", self.palette); self.palette.value_for(paletted_value as usize) } } diff --git a/bot/src/main.rs b/bot/src/main.rs index 93d83be9..1f2cb6e1 100644 --- a/bot/src/main.rs +++ b/bot/src/main.rs @@ -26,7 +26,7 @@ async fn main() { let state = client.state.lock().await; let world = state.world.as_ref().unwrap(); let c = world.get_block_state(&BlockPos::new(5, 78, -2)).unwrap(); - println!("{:?}", c); + println!("block state: {:?}", c); } } }