mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-04-19 19:15:08 +02:00
treewide: add more documentation
This commit is contained in:
parent
5ee114ed0a
commit
493608ebc8
3 changed files with 53 additions and 0 deletions
12
src/types.rs
12
src/types.rs
|
@ -19,6 +19,7 @@ pub struct BlockY(pub u8);
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct BlockZ(pub u8);
|
pub struct BlockZ(pub u8);
|
||||||
|
|
||||||
|
/// X, Y and Z coordinates of a block in a chunk section
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct BlockCoords {
|
pub struct BlockCoords {
|
||||||
pub x: BlockX,
|
pub x: BlockX,
|
||||||
|
@ -27,6 +28,11 @@ pub struct BlockCoords {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockCoords {
|
impl BlockCoords {
|
||||||
|
/// Computes a block's offset in various data structures
|
||||||
|
///
|
||||||
|
/// Many chunk data structures store block and biome data in the same
|
||||||
|
/// order. [BlockCoords::offset] computes the offset at which the data
|
||||||
|
/// for the block at a given coordinate is stored.
|
||||||
pub fn offset(&self) -> usize {
|
pub fn offset(&self) -> usize {
|
||||||
use BLOCKS_PER_CHUNK as N;
|
use BLOCKS_PER_CHUNK as N;
|
||||||
let x = self.x.0 as usize;
|
let x = self.x.0 as usize;
|
||||||
|
@ -69,6 +75,9 @@ impl Debug for ChunkCoords {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generic array for data stored per chunk of a region
|
||||||
|
///
|
||||||
|
/// Includes various convenient iteration functions.
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct ChunkArray<T>(pub [[T; CHUNKS_PER_REGION]; CHUNKS_PER_REGION]);
|
pub struct ChunkArray<T>(pub [[T; CHUNKS_PER_REGION]; CHUNKS_PER_REGION]);
|
||||||
|
|
||||||
|
@ -105,11 +114,14 @@ impl<T> IndexMut<ChunkCoords> for ChunkArray<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate division and remainder at the same time
|
||||||
pub trait DivRem<Rhs>
|
pub trait DivRem<Rhs>
|
||||||
where
|
where
|
||||||
Self: Div<Rhs>,
|
Self: Div<Rhs>,
|
||||||
Self: Rem<Rhs>,
|
Self: Rem<Rhs>,
|
||||||
{
|
{
|
||||||
|
/// Returns the result of the division and remainder operations
|
||||||
|
/// with the same inputs
|
||||||
fn div_rem(self, rhs: Rhs) -> (<Self as Div<Rhs>>::Output, <Self as Rem<Rhs>>::Output);
|
fn div_rem(self, rhs: Rhs) -> (<Self as Div<Rhs>>::Output, <Self as Rem<Rhs>>::Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,41 +11,62 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
|
/// Chunk data structure wrapping a [de::Chunk] for convenient access to
|
||||||
|
/// block and biome data
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Chunk<'a> {
|
pub enum Chunk<'a> {
|
||||||
|
/// Minecraft v1.18+ chunk with biome data moved into sections
|
||||||
V1_18 {
|
V1_18 {
|
||||||
section_map: BTreeMap<SectionY, (PaletteSection<'a>, PaletteSectionBiomes<'a>)>,
|
section_map: BTreeMap<SectionY, (PaletteSection<'a>, PaletteSectionBiomes<'a>)>,
|
||||||
},
|
},
|
||||||
|
/// Minecraft v1.13+ chunk
|
||||||
|
///
|
||||||
|
/// Block data is stored in an indexed format with variable bit width
|
||||||
|
/// (depending on the total numer of distinct block types used in a
|
||||||
|
/// section), and a palette mapping these indices to namespaced
|
||||||
|
/// block IDs
|
||||||
V1_13 {
|
V1_13 {
|
||||||
section_map: BTreeMap<SectionY, PaletteSection<'a>>,
|
section_map: BTreeMap<SectionY, PaletteSection<'a>>,
|
||||||
biomes: &'a de::BiomesOld,
|
biomes: &'a de::BiomesOld,
|
||||||
},
|
},
|
||||||
|
/// Original pre-1.13 chunk
|
||||||
|
///
|
||||||
|
/// The original chunk format with fixed 8-bit numeric block IDs
|
||||||
Old {
|
Old {
|
||||||
section_map: BTreeMap<SectionY, OldSection<'a>>,
|
section_map: BTreeMap<SectionY, OldSection<'a>>,
|
||||||
biomes: &'a de::BiomesOld,
|
biomes: &'a de::BiomesOld,
|
||||||
},
|
},
|
||||||
|
/// Unpopulated chunk without any block data
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inner data structure of [SectionIter]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum SectionIterInner<'a> {
|
enum SectionIterInner<'a> {
|
||||||
|
/// Iterator over sections of [Chunk::V1_18]
|
||||||
V1_18 {
|
V1_18 {
|
||||||
iter: btree_map::Iter<'a, SectionY, (PaletteSection<'a>, PaletteSectionBiomes<'a>)>,
|
iter: btree_map::Iter<'a, SectionY, (PaletteSection<'a>, PaletteSectionBiomes<'a>)>,
|
||||||
},
|
},
|
||||||
|
/// Iterator over sections of [Chunk::V1_13]
|
||||||
V1_13 {
|
V1_13 {
|
||||||
iter: btree_map::Iter<'a, SectionY, PaletteSection<'a>>,
|
iter: btree_map::Iter<'a, SectionY, PaletteSection<'a>>,
|
||||||
},
|
},
|
||||||
|
/// Iterator over sections of [Chunk::Old]
|
||||||
Old {
|
Old {
|
||||||
iter: btree_map::Iter<'a, SectionY, OldSection<'a>>,
|
iter: btree_map::Iter<'a, SectionY, OldSection<'a>>,
|
||||||
},
|
},
|
||||||
|
/// Empty iterator over an unpopulated chunk ([Chunk::Empty])
|
||||||
Empty,
|
Empty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterator over the sections of a [Chunk]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SectionIter<'a> {
|
pub struct SectionIter<'a> {
|
||||||
inner: SectionIterInner<'a>,
|
inner: SectionIterInner<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Chunk<'a> {
|
impl<'a> Chunk<'a> {
|
||||||
|
/// Creates a new [Chunk] from a deserialized [de::Chunk]
|
||||||
pub fn new(data: &'a de::Chunk) -> Result<Self> {
|
pub fn new(data: &'a de::Chunk) -> Result<Self> {
|
||||||
let data_version = data.data_version.unwrap_or_default();
|
let data_version = data.data_version.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -55,6 +76,7 @@ impl<'a> Chunk<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [Chunk::new] implementation for Minecraft v1.18+ chunks
|
||||||
fn new_v1_18(data_version: u32, sections: &'a Vec<de::SectionV1_18>) -> Result<Self> {
|
fn new_v1_18(data_version: u32, sections: &'a Vec<de::SectionV1_18>) -> Result<Self> {
|
||||||
let mut section_map = BTreeMap::new();
|
let mut section_map = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -80,6 +102,7 @@ impl<'a> Chunk<'a> {
|
||||||
Ok(Chunk::V1_18 { section_map })
|
Ok(Chunk::V1_18 { section_map })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [Chunk::new] implementation for all pre-1.18 chunk variants
|
||||||
fn new_old(data_version: u32, level: &'a de::LevelOld) -> Result<Self> {
|
fn new_old(data_version: u32, level: &'a de::LevelOld) -> Result<Self> {
|
||||||
let mut section_map_v1_13 = BTreeMap::new();
|
let mut section_map_v1_13 = BTreeMap::new();
|
||||||
let mut section_map_old = BTreeMap::new();
|
let mut section_map_old = BTreeMap::new();
|
||||||
|
@ -131,6 +154,7 @@ impl<'a> Chunk<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an interator over the chunk's sections and their Y coordinates
|
||||||
pub fn sections(&self) -> SectionIter {
|
pub fn sections(&self) -> SectionIter {
|
||||||
use SectionIterInner::*;
|
use SectionIterInner::*;
|
||||||
SectionIter {
|
SectionIter {
|
||||||
|
|
|
@ -3,6 +3,11 @@ use anyhow::{bail, Context, Result};
|
||||||
use super::de;
|
use super::de;
|
||||||
use crate::{resource, types::*};
|
use crate::{resource, types::*};
|
||||||
|
|
||||||
|
/// Determine the number of bits required for indexing into a palette of a given length
|
||||||
|
///
|
||||||
|
/// This is basically a base-2 logarithm, with clamping to a minimum value and
|
||||||
|
/// check against a maximum value. If the result would be greater than the passed
|
||||||
|
/// `max` value, [None] is returned.
|
||||||
fn palette_bits(len: usize, min: u8, max: u8) -> Option<u8> {
|
fn palette_bits(len: usize, min: u8, max: u8) -> Option<u8> {
|
||||||
let mut bits = min;
|
let mut bits = min;
|
||||||
while (1 << bits) < len {
|
while (1 << bits) < len {
|
||||||
|
@ -16,10 +21,16 @@ fn palette_bits(len: usize, min: u8, max: u8) -> Option<u8> {
|
||||||
Some(bits)
|
Some(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for common functions of [PaletteSection] and [OldSection]
|
||||||
pub trait Section {
|
pub trait Section {
|
||||||
fn get_block_id(&self, coords: BlockCoords) -> Result<&str>;
|
fn get_block_id(&self, coords: BlockCoords) -> Result<&str>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Minecraft v1.18+ section biome data
|
||||||
|
///
|
||||||
|
/// The biome data is part of the section structure in Minecraft v1.18+, with
|
||||||
|
/// the biomes laid out as an array of indices into a palette, similar to the
|
||||||
|
/// v1.13+ block data.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PaletteSectionBiomes<'a> {
|
pub struct PaletteSectionBiomes<'a> {
|
||||||
_biomes: Option<&'a fastnbt::LongArray>,
|
_biomes: Option<&'a fastnbt::LongArray>,
|
||||||
|
@ -28,6 +39,7 @@ pub struct PaletteSectionBiomes<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PaletteSectionBiomes<'a> {
|
impl<'a> PaletteSectionBiomes<'a> {
|
||||||
|
/// Constructs a new [PaletteSectionBiomes] from deserialized data structures
|
||||||
pub fn new(biomes: Option<&'a fastnbt::LongArray>, palette: &'a Vec<String>) -> Result<Self> {
|
pub fn new(biomes: Option<&'a fastnbt::LongArray>, palette: &'a Vec<String>) -> Result<Self> {
|
||||||
let bits = palette_bits(palette.len(), 1, 6).context("Unsupported block palette size")?;
|
let bits = palette_bits(palette.len(), 1, 6).context("Unsupported block palette size")?;
|
||||||
|
|
||||||
|
@ -47,6 +59,7 @@ impl<'a> PaletteSectionBiomes<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Minecraft v1.13+ section block data
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PaletteSection<'a> {
|
pub struct PaletteSection<'a> {
|
||||||
block_states: Option<&'a fastnbt::LongArray>,
|
block_states: Option<&'a fastnbt::LongArray>,
|
||||||
|
@ -56,6 +69,7 @@ pub struct PaletteSection<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PaletteSection<'a> {
|
impl<'a> PaletteSection<'a> {
|
||||||
|
/// Constructs a new [PaletteSection] from deserialized data structures
|
||||||
pub fn new(
|
pub fn new(
|
||||||
data_version: u32,
|
data_version: u32,
|
||||||
block_states: Option<&'a fastnbt::LongArray>,
|
block_states: Option<&'a fastnbt::LongArray>,
|
||||||
|
@ -85,6 +99,7 @@ impl<'a> PaletteSection<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Looks up the block type palette index at the given coordinates
|
||||||
fn get_palette_index(&self, coords: BlockCoords) -> usize {
|
fn get_palette_index(&self, coords: BlockCoords) -> usize {
|
||||||
let Some(block_states) = self.block_states else {
|
let Some(block_states) = self.block_states else {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -127,6 +142,7 @@ impl<'a> Section for PaletteSection<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pre-1.13 section block data
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OldSection<'a> {
|
pub struct OldSection<'a> {
|
||||||
blocks: &'a fastnbt::ByteArray,
|
blocks: &'a fastnbt::ByteArray,
|
||||||
|
@ -134,6 +150,7 @@ pub struct OldSection<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> OldSection<'a> {
|
impl<'a> OldSection<'a> {
|
||||||
|
/// Constructs a new [OldSection] from deserialized data structures
|
||||||
pub fn new(blocks: &'a fastnbt::ByteArray, data: &'a fastnbt::ByteArray) -> Result<Self> {
|
pub fn new(blocks: &'a fastnbt::ByteArray, data: &'a fastnbt::ByteArray) -> Result<Self> {
|
||||||
use BLOCKS_PER_CHUNK as N;
|
use BLOCKS_PER_CHUNK as N;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue