diff options
| -rwxr-xr-x | azalea-core/src/lib.rs | 2 | ||||
| -rw-r--r-- | azalea-core/src/position.rs | 43 | ||||
| -rw-r--r-- | azalea-world/src/bit_storage.rs | 16 | ||||
| -rw-r--r-- | azalea-world/src/lib.rs | 43 | ||||
| -rw-r--r-- | azalea-world/src/palette.rs | 30 | ||||
| -rw-r--r-- | bot/src/main.rs | 8 |
6 files changed, 127 insertions, 15 deletions
diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs index 0053dc9b..2b12db53 100755 --- a/azalea-core/src/lib.rs +++ b/azalea-core/src/lib.rs @@ -9,7 +9,7 @@ mod slot; pub use slot::{Slot, SlotData}; mod position; -pub use position::{BlockPos, ChunkPos, ChunkSectionPos}; +pub use position::{BlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos}; mod direction; pub use direction::Direction; diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs index a2292651..1dd200ab 100644 --- a/azalea-core/src/position.rs +++ b/azalea-core/src/position.rs @@ -1,3 +1,5 @@ +use std::ops::Rem; + #[derive(Clone, Copy, Debug, Default)] pub struct BlockPos { pub x: i32, @@ -11,6 +13,18 @@ impl BlockPos { } } +impl Rem<i32> for BlockPos { + type Output = Self; + + fn rem(self, rhs: i32) -> Self { + BlockPos { + x: self.x % rhs, + y: self.y % rhs, + z: self.z % rhs, + } + } +} + #[derive(Clone, Copy, Debug, Default)] pub struct ChunkPos { pub x: i32, @@ -23,8 +37,8 @@ impl ChunkPos { } } -impl From<BlockPos> for ChunkPos { - fn from(pos: BlockPos) -> Self { +impl From<&BlockPos> for ChunkPos { + fn from(pos: &BlockPos) -> Self { ChunkPos { x: pos.x / 16, z: pos.z / 16, @@ -32,6 +46,7 @@ impl From<BlockPos> for ChunkPos { } } +/// The coordinates of a chunk section in the world. #[derive(Clone, Copy, Debug, Default)] pub struct ChunkSectionPos { pub x: i32, @@ -60,3 +75,27 @@ impl From<ChunkSectionPos> for ChunkPos { ChunkPos { x: pos.x, z: pos.z } } } + +/// The coordinates of a block inside a chunk section. +#[derive(Clone, Copy, Debug, Default)] +pub struct ChunkSectionBlockPos { + pub x: u8, + pub y: u8, + pub z: u8, +} + +impl ChunkSectionBlockPos { + pub fn new(x: u8, y: u8, z: u8) -> Self { + ChunkSectionBlockPos { x, y, z } + } +} + +impl From<&BlockPos> for ChunkSectionBlockPos { + fn from(pos: &BlockPos) -> Self { + ChunkSectionBlockPos { + x: pos.x.rem(16).abs() as u8, + y: pos.y.rem(16).abs() as u8, + z: pos.z.rem(16).abs() as u8, + } + } +} diff --git a/azalea-world/src/bit_storage.rs b/azalea-world/src/bit_storage.rs index 3f810f40..f24a0514 100644 --- a/azalea-world/src/bit_storage.rs +++ b/azalea-world/src/bit_storage.rs @@ -103,6 +103,9 @@ impl BitStorage { /// Create a new BitStorage with the given number of bits per entry. /// `size` is the number of entries in the BitStorage. pub fn new(bits: usize, size: usize, data: Option<Vec<u64>>) -> Result<Self, BitStorageError> { + // vanilla has this assert but it's not always true for some reason?? + // assert!(bits >= 1 && bits <= 32); + if let Some(data) = &data { if data.len() == 0 { // TODO: make 0 bit storage actually work @@ -142,10 +145,12 @@ impl BitStorage { } pub fn cell_index(&self, index: u64) -> usize { - let first = self.divide_mul as u64; + // 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) + (((index * first) + second) >> 32 >> self.divide_shift) .try_into() .unwrap() } @@ -157,7 +162,12 @@ impl BitStorage { // int var5 = (var1 - var2 * this.valuesPerLong) * this.bits; // return (int)(var3 >> var5 & this.mask); - assert!(index <= self.size - 1); + assert!( + index <= self.size - 1, + "Index {} out of bounds (max is {})", + index, + self.size - 1 + ); let cell_index = self.cell_index(index as u64); let cell = &self.data[cell_index as usize]; let bit_index = (index - cell_index * self.values_per_long as usize) * self.bits; diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs index 4da2fb0f..aa99a470 100644 --- a/azalea-world/src/lib.rs +++ b/azalea-world/src/lib.rs @@ -1,7 +1,8 @@ mod bit_storage; mod palette; -use azalea_core::ChunkPos; +use crate::palette::PalettedContainerType; +use azalea_core::{BlockPos, ChunkPos, ChunkSectionBlockPos}; use azalea_protocol::mc_buf::{McBufReadable, McBufWritable}; pub use bit_storage::BitStorage; use palette::PalettedContainer; @@ -11,8 +12,6 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::palette::PalettedContainerType; - #[cfg(test)] mod tests { #[test] @@ -54,6 +53,10 @@ impl World { pub fn update_view_center(&mut self, pos: &ChunkPos) { self.storage.view_center = *pos; } + + pub fn get_block_state(&self, pos: &BlockPos) -> Option<u32> { + self.storage.get_block_state(pos) + } } impl Index<&ChunkPos> for World { type Output = Option<Arc<Mutex<Chunk>>>; @@ -115,6 +118,15 @@ impl ChunkStorage { (chunk_pos.x - self.view_center.x).unsigned_abs() <= self.chunk_radius && (chunk_pos.z - self.view_center.z).unsigned_abs() <= self.chunk_radius } + + pub fn get_block_state(&self, pos: &BlockPos) -> Option<u32> { + let chunk_pos = ChunkPos::from(pos); + let chunk = &self[&chunk_pos]; + match chunk { + Some(chunk) => Some(chunk.lock().unwrap().get(pos)), + None => None, + } + } } impl Index<&ChunkPos> for ChunkStorage { @@ -150,6 +162,23 @@ impl Chunk { } Ok(Chunk { sections }) } + + pub fn section_index(&self, 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 + } + + pub fn get(&self, pos: &BlockPos) -> u32 { + let section_index = self.section_index(pos.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); + let block_state = section.get(chunk_section_pos); + block_state + } } impl McBufWritable for Chunk { @@ -194,3 +223,11 @@ impl McBufWritable for Section { Ok(()) } } + +impl Section { + // TODO: return a BlockState instead of a u32 + fn get(&self, pos: ChunkSectionBlockPos) -> u32 { + self.states + .get(pos.x as usize, pos.y as usize, pos.z as usize) + } +} diff --git a/azalea-world/src/palette.rs b/azalea-world/src/palette.rs index 55a33bde..6dc5e183 100644 --- a/azalea-world/src/palette.rs +++ b/azalea-world/src/palette.rs @@ -15,6 +15,7 @@ pub struct PalettedContainer { pub palette: Palette, /// Compacted list of indices pointing to entry IDs in the Palette. pub storage: BitStorage, + pub container_type: PalettedContainerType, } impl PalettedContainer { @@ -47,9 +48,29 @@ impl PalettedContainer { bits_per_entry, palette, storage, + container_type: *type_, }) } + + pub fn get_index(&self, x: usize, y: usize, z: usize) -> usize { + let size_bits = match self.container_type { + PalettedContainerType::BlockStates => 4, + PalettedContainerType::Biomes => 2, + }; + + (((y << size_bits) | z) << size_bits) | x + } + + 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)); + self.palette.value_for(paletted_value as usize) + } } + impl McBufWritable for PalettedContainer { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { buf.write_byte(self.bits_per_entry)?; @@ -91,6 +112,15 @@ impl Palette { _ => Palette::Global, }) } + + pub fn value_for(&self, value: usize) -> u32 { + match self { + Palette::SingleValue(v) => *v, + Palette::Linear(v) => v[value], + Palette::Hashmap(v) => v[value], + Palette::Global => value as u32, + } + } } impl McBufWritable for Palette { diff --git a/bot/src/main.rs b/bot/src/main.rs index 2f9fb9e6..93d83be9 100644 --- a/bot/src/main.rs +++ b/bot/src/main.rs @@ -25,12 +25,8 @@ async fn main() { if p.message.to_ansi(None) == "<py5> ok" { let state = client.state.lock().await; let world = state.world.as_ref().unwrap(); - // let c = world[&BlockPos::new(5, 78, -2)] - // .as_ref() - // .unwrap() - // .lock() - // .unwrap(); - // println!("{:?}", c); + let c = world.get_block_state(&BlockPos::new(5, 78, -2)).unwrap(); + println!("{:?}", c); } } } |
