use chashmap::{CHashMap, ReadGuard, WriteGuard}; use fastanvil::{Block, Chunk, CurrentJavaChunk, Region, RegionFileLoader, RegionLoader}; use log::{debug, info}; use std::{fs::File, path::PathBuf}; pub struct Dimension { loader: RegionFileLoader, regions: CHashMap<(isize, isize), Option>>, chunks: CHashMap<(isize, isize), Option>, } impl Dimension { pub fn new(path: PathBuf) -> Self { let loader = fastanvil::RegionFileLoader::new(path); Self { loader, regions: Default::default(), chunks: Default::default(), } } pub fn region( &self, rx: isize, rz: isize, ) -> WriteGuard<'_, (isize, isize), Option>> { if self.regions.contains_key(&(rx, rz)) { self.regions.get_mut(&(rx, rz)).unwrap() } else { info!("loading region {:?}", (rx, rz)); self.regions.insert( (rx, rz), self.loader .region(fastanvil::RCoord(rx), fastanvil::RCoord(rz)), ); self.region(rx, rz) } } pub fn chunk( &self, cx: isize, cz: isize, ) -> ReadGuard<'_, (isize, isize), Option> { if self.chunks.contains_key(&(cx, cz)) { self.chunks.get(&(cx, cz)).unwrap() } else { let mut guard = self.region(cx / 32, cz / 32); debug!("loading chunk {:?}", (cx, cz)); let chunk: Option = guard .as_mut() .map(|c| { c.read_chunk(cx.rem_euclid(32) as usize, cz.rem_euclid(32) as usize) .ok() }) .flatten() .flatten() .map(|chunk| fastnbt::from_bytes(&chunk).ok()) .flatten(); self.chunks.insert((cx, cz), chunk); self.chunk(cx, cz) } } pub fn block(&self, x: isize, y: isize, z: isize) -> Option { self.chunk(x / 16, z / 16) .as_ref()? .block((x % 16).abs() as usize, y, (z % 16).abs() as usize) .map(|e| e.to_owned()) } }