use bit_field::BitField;
use fastnbt::LongArray;
use serde::Deserialize;
use std::fmt::Debug;
#[derive(Deserialize, Debug)]
#[serde(transparent)]
pub struct BlockData<T: Debug> {
inner: DataInner<T>,
}
#[derive(Deserialize, Debug)]
#[serde(transparent)]
pub struct BiomeData<T: Debug> {
inner: DataInner<T>,
}
impl<T: Debug> BlockData<T> {
pub fn at(&self, x: usize, sec_y: usize, z: usize) -> Option<&T> {
let state_index = (sec_y * 16 * 16) + z * 16 + x;
self.inner.at(
state_index,
blockstates_bits_per_block(self.inner.palette.len()),
)
}
pub fn try_iter_indices(&self) -> Option<StatesIter> {
if let Some(data) = &self.inner.data {
let bits = blockstates_bits_per_block(self.inner.palette.len());
Some(StatesIter::new(bits, 16 * 16 * 16, data))
} else {
None
}
}
pub fn palette(&self) -> &[T] {
self.inner.palette.as_slice()
}
}
impl<T: Debug> BiomeData<T> {
pub fn at(&self, x: usize, sec_y: usize, z: usize) -> Option<&T> {
let x = x / 4;
let y = sec_y / 4;
let z = z / 4;
let state_index = (y * 4 * 4) + z * 4 + x;
self.inner
.at(state_index, biomes_bits_per_block(self.inner.palette.len()))
}
pub fn try_iter_indices(&self) -> Option<StatesIter> {
if let Some(data) = &self.inner.data {
let bits = biomes_bits_per_block(self.inner.palette.len());
Some(StatesIter::new(bits, 4 * 4 * 4, data))
} else {
None
}
}
pub fn palette(&self) -> &[T] {
self.inner.palette.as_slice()
}
}
#[derive(Deserialize, Debug)]
struct DataInner<T: Debug> {
data: Option<LongArray>,
palette: Vec<T>,
}
impl<T: Debug> DataInner<T> {
pub fn at(&self, index: usize, bits_per_item: usize) -> Option<&T> {
if self.data.is_none() && self.palette.len() == 1 {
return self.palette.get(0);
}
let data = self.data.as_ref()?;
let values_per_64bits = 64 / bits_per_item;
let long_index = index / values_per_64bits;
let inter_index = index % values_per_64bits;
let range = inter_index * bits_per_item..(inter_index + 1) * bits_per_item;
let long = data[long_index] as u64;
let palette_index = long.get_bits(range);
self.palette.get(palette_index as usize)
}
}
impl<T: Debug> Default for DataInner<T> {
fn default() -> Self {
Self {
data: Default::default(),
palette: Default::default(),
}
}
}
impl<T: Debug> Default for BlockData<T> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T: Debug> Default for BiomeData<T> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
fn blockstates_bits_per_block(palette_len: usize) -> usize {
std::cmp::max(4, min_bits_for_n_states(palette_len))
}
fn biomes_bits_per_block(palette_len: usize) -> usize {
std::cmp::max(1, min_bits_for_n_states(palette_len))
}
pub(crate) fn min_bits_for_n_states(palette_len: usize) -> usize {
(usize::BITS - (palette_len - 1).leading_zeros()) as usize
}
pub struct StatesIter<'a> {
inner: &'a [i64], stride: usize, pos: usize, remaining: usize,
}
impl<'a> StatesIter<'a> {
pub(crate) fn new(stride: usize, len: usize, inner: &'a [i64]) -> Self {
Self {
inner,
stride,
remaining: len,
pos: 0,
}
}
}
impl<'a> Iterator for StatesIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let start = self.pos;
self.pos += self.stride;
let end = self.pos;
let datum = *(self.inner.first()?) as u64;
let value = datum.get_bits(start..end) as usize;
self.remaining -= 1;
if self.pos + self.stride > 64 {
self.pos = 0;
self.inner = &self.inner[1..];
}
Some(value)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<'a> ExactSizeIterator for StatesIter<'a> {}