use std::ops::Range;
use std::sync::RwLock;
use serde::Deserialize;
use crate::{biome::Biome, Block, Chunk, HeightMode};
use crate::{expand_heightmap, Heightmaps, Section, SectionTower};
use super::AIR;
impl Chunk for CurrentJavaChunk {
fn status(&self) -> String {
self.status.clone()
}
fn surface_height(&self, x: usize, z: usize, mode: HeightMode) -> isize {
let mut heightmap = self.lazy_heightmap.read().unwrap();
if heightmap.is_none() {
drop(heightmap);
self.recalculate_heightmap(mode);
heightmap = self.lazy_heightmap.read().unwrap();
}
heightmap.unwrap()[z * 16 + x] as isize
}
fn biome(&self, x: usize, y: isize, z: usize) -> Option<Biome> {
let sections = self.sections.as_ref()?;
let sec = sections.get_section_for_y(y)?;
let sec_y = (y - sec.y as isize * 16) as usize;
sec.biomes.at(x, sec_y, z).cloned()
}
fn block(&self, x: usize, y: isize, z: usize) -> Option<&Block> {
let sections = self.sections.as_ref()?;
let sec = sections.get_section_for_y(y)?;
let sec_y = (y - sec.y as isize * 16) as usize;
Some(sec.block_states.at(x, sec_y, z).unwrap_or(&AIR))
}
fn y_range(&self) -> Range<isize> {
match &self.sections {
Some(sections) => Range {
start: sections.y_min(),
end: sections.y_max(),
},
None => Range { start: 0, end: 0 },
}
}
}
#[derive(Deserialize, Debug)]
pub struct CurrentJavaChunk {
#[serde(rename = "DataVersion")]
pub data_version: i32,
pub sections: Option<SectionTower<Section>>,
#[serde(rename = "Heightmaps")]
pub heightmaps: Option<Heightmaps>,
#[serde(rename = "Status")]
pub status: String,
#[serde(skip)]
pub(crate) lazy_heightmap: RwLock<Option<[i16; 256]>>,
}
impl CurrentJavaChunk {
pub fn recalculate_heightmap(&self, mode: HeightMode) {
let mut map = [0; 256];
match mode {
HeightMode::Trust => {
let updated = self
.heightmaps
.as_ref()
.and_then(|hm| hm.motion_blocking.as_ref())
.map(|hm| {
let y_min = self.sections.as_ref().unwrap().y_min();
expand_heightmap(hm, y_min, self.data_version)
})
.map(|hm| map.copy_from_slice(hm.as_slice()))
.is_some();
if updated {
*self.lazy_heightmap.write().unwrap() = Some(map);
return;
}
}
HeightMode::Calculate => {} }
let y_range = self.y_range();
let y_end = y_range.end;
for z in 0..16 {
for x in 0..16 {
for i in y_range.clone() {
let y = y_end - i;
let block = self.block(x, y - 1, z);
if block.is_none() {
continue;
}
if !["minecraft:air", "minecraft:cave_air"]
.as_ref()
.contains(&block.unwrap().name())
{
map[z * 16 + x] = y as i16;
break;
}
}
}
}
*self.lazy_heightmap.write().unwrap() = Some(map);
}
}