use std::collections::{BTreeMap, HashMap};
use std::io::Read;
use std::ops::Range;
use std::sync::Arc;
use fastnbt::Value;
use crate::{BlockEntity, Entity};
use crate::biome::Biome;
use crate::block::Block;
use crate::error::Error;
use crate::raid::RaidList;
use crate::region::{Light, PendingTick};
pub mod mca;
mod files_reader;
mod chunk;
mod dimension;
mod sub_chunk;
mod chunk_ref;
mod world;
#[derive(Debug, Eq, Hash, PartialEq)]
pub struct XZCoordinate<T = i32> {
pub x: T,
pub z: T,
}
#[derive(Debug, Clone)]
pub struct SubChunk {
pub palette: Vec<Block>,
block_id_array: [u16; 4096],
pub sky_block_light_array: [Light; 4096],
pub biome_array: [Biome; 64],
}
#[derive(Debug, Clone)]
pub struct Chunk {
pub time_stamp: u32,
pub status: ChunkStatus,
pub last_update: i64,
pub inhabited_time: i64,
pub is_light_on: bool,
sub_chunks: BTreeMap<i8, SubChunk>,
pub entities: Vec<Entity>,
pub block_entities: HashMap<[i32; 3], BlockEntity>,
pub pending_ticks: HashMap<[i32; 3], Vec<PendingTick>>,
pub file_region: String,
pub file_entities: String,
}
#[derive(Debug, Eq, Hash, PartialEq, Copy, Clone)]
pub struct ChunkPos {
global_x: i32,
global_z: i32,
}
pub struct ChunkRefRelativePos<'chunk> {
chunk: &'chunk Chunk,
chunk_pos: ChunkPos,
}
pub struct ChunkRefAbsolutePos<'chunk> {
chunk: &'chunk Chunk,
chunk_pos: ChunkPos,
}
pub enum RefOrObject<'a, T: Sized> {
Ref(&'a T),
Object(T),
}
#[derive(Debug, Clone)]
pub struct ArcSlice {
data_owner: Arc<Vec<u8>>,
range: Range<usize>,
}
pub struct NBTWithSource<'a> {
pub nbt: HashMap<String, Value>,
pub source: &'a str,
}
#[derive(Debug, Clone)]
pub struct MCARawData {
pub time_stamp: u32,
pub compress_method: u8,
pub data: ArcSlice,
pub source_file: String,
}
#[derive(Debug, Clone)]
pub struct UnparsedChunkData {
pub region_data: MCARawData,
pub entity_data: Option<MCARawData>,
}
#[derive(Debug, Clone)]
pub enum ChunkVariant {
Parsed(Chunk),
Unparsed(UnparsedChunkData),
}
#[derive(Debug, Clone)]
pub struct Dimension {
pub chunks: HashMap<ChunkPos, ChunkVariant>,
y_range: Range<i32>,
#[allow(dead_code)]
raids: RaidList,
}
#[derive(Debug, Clone)]
pub struct World {
pub dimensions: BTreeMap<i32, Dimension>,
}
#[derive(Debug, Clone)]
pub struct WorldLoadOption {
parse_directly: bool,
}
#[derive(Debug, Clone)]
pub struct FileInfo {
pub name: String,
pub full_name: String,
pub size: u64,
}
#[derive(Clone)]
pub struct SubDirectory<'a> {
root: &'a dyn FilesRead,
dirname_with_slash: String,
}
pub trait FilesRead {
fn sub_directory(&self, dir: &str) -> SubDirectory;
fn path(&self) -> String;
fn files(&self) -> Vec<FileInfo>;
fn open_file(&self, filename: &str) -> Result<Box<dyn Read + '_>, Error>;
fn read_file(&self, filename: &str, dest: &mut Vec<u8>) -> Result<(), Error> {
let mut src = self.open_file(filename)?;
dest.clear();
return match src.read_to_end(dest) {
Ok(_) => { Ok(()) }
Err(e) => { Err(Error::IOReadError(e)) }
};
}
fn read_file_as_bytes(&self, filename: &str) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
self.read_file(filename, &mut result)?;
return Ok(result);
}
fn read_file_nocopy(&self, filename: &str) -> Result<Option<ArcSlice>, Error> {
let _ = self.open_file(filename)?;
return Ok(None);
}
fn read_file_as_arc_slice(&self, filename: &str) -> Result<ArcSlice, Error> {
if let Some(arc_slice) = self.read_file_nocopy(filename)? {
return Ok(arc_slice);
}
let vec = self.read_file_as_bytes(filename)?;
return Ok(ArcSlice::from(Arc::new(vec)));
}
}
#[derive(Debug, Clone)]
pub struct FolderOnDisk {
path: String,
}
#[derive(Debug, Clone)]
pub struct FilesInMemory {
files: HashMap<String, Arc<Vec<u8>>>,
pub source: String,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum ChunkStatus {
Empty,
StructureStarts,
StructureReferences,
Biomes,
Noise,
Surface,
Carvers,
Features,
InitializeLight,
Light,
Spawn,
Full,
}
pub trait AbsolutePosIndexed<'this, 'dim: 'this> {
fn shape(&self) -> [i32; 3] {
let r = self.pos_range();
return [r[0].len() as i32, r[1].len() as i32, r[2].len() as i32];
}
fn volume(&self) -> u64 {
return self.shape()[0] as u64 * self.shape()[1] as u64 * self.shape()[2] as u64;
}
fn pos_range(&self) -> [Range<i32>; 3];
fn contains_coord(&self, a_pos: [i32; 3]) -> bool {
let r = self.pos_range();
for dim in 0..3 {
if !r[dim].contains(&a_pos[dim]) {
return false;
}
}
return true;
}
fn total_blocks(&self, include_air: bool) -> u64;
fn block_info_at(&'this self, a_pos: [i32; 3]) -> Option<(u16, &'dim Block, Option<&'dim BlockEntity>, &'dim [PendingTick])> {
return Some((self.block_index_at(a_pos)?,
self.block_at(a_pos)?,
self.block_entity_at(a_pos),
self.pending_tick_at(a_pos),
));
}
fn block_index_at(&self, a_pos: [i32; 3]) -> Option<u16>;
fn block_at(&'this self, a_pos: [i32; 3]) -> Option<&'dim Block>;
fn block_entity_at(&'this self, a_pos: [i32; 3]) -> Option<&'dim BlockEntity>;
fn pending_tick_at(&'this self, a_pos: [i32; 3]) -> &'dim [PendingTick];
}