From b918ff61061d02e548b4f1e5631abef8f26fdfb4 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 12 Feb 2023 20:04:31 +0100 Subject: [PATCH] world/section: add method to get block ID at coordinate --- src/world/section.rs | 74 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/src/world/section.rs b/src/world/section.rs index 3aa5aca..8c849f9 100644 --- a/src/world/section.rs +++ b/src/world/section.rs @@ -1,6 +1,7 @@ use anyhow::{bail, Context, Result}; use super::de; +use crate::{resource, types::*}; fn palette_bits(len: usize, min: u8, max: u8) -> Option { let mut bits = min; @@ -15,7 +16,9 @@ fn palette_bits(len: usize, min: u8, max: u8) -> Option { Some(bits) } -pub trait Section {} +pub trait Section { + fn get_block_id(&self, coords: BlockCoords) -> Result<&str>; +} #[derive(Debug)] pub struct PaletteSectionBiomes<'a> { @@ -81,9 +84,48 @@ impl<'a> PaletteSection<'a> { aligned_blocks, }) } + + fn get_palette_index(&self, coords: BlockCoords) -> usize { + let Some(block_states) = self.block_states else { + return 0; + }; + + let bits = self.bits as usize; + let mask = (1 << bits) - 1; + + let offset = coords.offset(); + + let shifted = if self.aligned_blocks { + let blocks_per_word = 64 / bits; + let (word, shift) = offset.div_rem(blocks_per_word); + block_states[word] as u64 >> (shift * bits) + } else { + let bit_offset = offset * bits; + let (word, bit_shift) = bit_offset.div_rem(64); + + if bit_shift + bits <= 64 { + block_states[word] as u64 >> bit_shift + } else { + let tmp = (block_states[word + 1] as u64 as u128) << 64 + | block_states[word] as u64 as u128; + (tmp >> bit_shift) as u64 + } + }; + + (shifted & mask) as usize + } } -impl<'a> Section for PaletteSection<'a> {} +impl<'a> Section for PaletteSection<'a> { + fn get_block_id(&self, coords: BlockCoords) -> Result<&str> { + let index = self.get_palette_index(coords); + let entry = self + .palette + .get(index) + .context("Palette index out of bounds")?; + Ok(&entry.name) + } +} #[derive(Debug)] pub struct OldSection<'a> { @@ -93,9 +135,31 @@ pub struct OldSection<'a> { impl<'a> OldSection<'a> { pub fn new(blocks: &'a fastnbt::ByteArray, data: &'a fastnbt::ByteArray) -> Result { - // TODO: Check lengths - Ok(Self { blocks, data }) + const N: usize = BLOCKS_PER_CHUNK as usize; + if blocks.len() != N * N * N { + bail!("Invalid section block data"); + } + if data.len() != N * N * N / 2 { + bail!("Invalid section extra data"); + } + + Ok(OldSection { blocks, data }) } } -impl<'a> Section for OldSection<'a> {} +impl<'a> Section for OldSection<'a> { + fn get_block_id(&self, coords: BlockCoords) -> Result<&str> { + let offset = coords.offset(); + let block = self.blocks[offset] as u8; + + let (data_offset, data_nibble) = offset.div_rem(2); + let data_byte = self.data[data_offset] as u8; + let data = if data_nibble == 1 { + data_byte >> 4 + } else { + data_byte & 0xf + }; + + Ok(resource::LEGACY_BLOCK_TYPES[block as usize][data as usize]) + } +}