aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xazalea-core/src/lib.rs2
-rw-r--r--azalea-core/src/position.rs43
-rw-r--r--azalea-world/src/bit_storage.rs16
-rw-r--r--azalea-world/src/lib.rs43
-rw-r--r--azalea-world/src/palette.rs30
-rw-r--r--bot/src/main.rs8
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);
}
}
}