mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-07-03 22:29:07 +02:00
Add documentation comments for all items
This commit is contained in:
parent
ba86dc8c06
commit
05a8056cbf
26 changed files with 576 additions and 42 deletions
|
@ -1,3 +1,8 @@
|
|||
//! Higher-level interfaces to chunk data
|
||||
//!
|
||||
//! The data types in this module attempt to provide interfaces abstracting
|
||||
//! over different data versions as much as possible.
|
||||
|
||||
use std::{
|
||||
collections::{btree_map, BTreeMap},
|
||||
iter::{self, FusedIterator},
|
||||
|
@ -17,6 +22,7 @@ use crate::{
|
|||
pub enum Chunk<'a> {
|
||||
/// Minecraft v1.18+ chunk with biome data moved into sections
|
||||
V1_18 {
|
||||
/// Section data
|
||||
section_map: BTreeMap<SectionY, (SectionV1_13<'a>, BiomesV1_18<'a>, BlockLight<'a>)>,
|
||||
},
|
||||
/// Minecraft v1.13+ chunk
|
||||
|
@ -26,14 +32,18 @@ pub enum Chunk<'a> {
|
|||
/// section), and a palette mapping these indices to namespaced
|
||||
/// block IDs
|
||||
V1_13 {
|
||||
/// Section data
|
||||
section_map: BTreeMap<SectionY, (SectionV1_13<'a>, BlockLight<'a>)>,
|
||||
/// Biome data
|
||||
biomes: BiomesV0<'a>,
|
||||
},
|
||||
/// Original pre-1.13 chunk
|
||||
///
|
||||
/// The original chunk format with fixed 8-bit numeric block IDs
|
||||
V0 {
|
||||
/// Section data
|
||||
section_map: BTreeMap<SectionY, (SectionV0<'a>, BlockLight<'a>)>,
|
||||
/// Biome data
|
||||
biomes: BiomesV0<'a>,
|
||||
},
|
||||
/// Unpopulated chunk without any block data
|
||||
|
@ -45,16 +55,21 @@ pub enum Chunk<'a> {
|
|||
enum SectionIterInner<'a> {
|
||||
/// Iterator over sections of [Chunk::V1_18]
|
||||
V1_18 {
|
||||
/// Inner iterator into section map
|
||||
iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BiomesV1_18<'a>, BlockLight<'a>)>,
|
||||
},
|
||||
/// Iterator over sections of [Chunk::V1_13]
|
||||
V1_13 {
|
||||
/// Inner iterator into section map
|
||||
iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BlockLight<'a>)>,
|
||||
/// Chunk biome data
|
||||
biomes: &'a BiomesV0<'a>,
|
||||
},
|
||||
/// Iterator over sections of [Chunk::V0]
|
||||
V0 {
|
||||
/// Inner iterator into section map
|
||||
iter: btree_map::Iter<'a, SectionY, (SectionV0<'a>, BlockLight<'a>)>,
|
||||
/// Chunk biome data
|
||||
biomes: &'a BiomesV0<'a>,
|
||||
},
|
||||
/// Empty iterator over an unpopulated chunk ([Chunk::Empty])
|
||||
|
@ -64,6 +79,7 @@ enum SectionIterInner<'a> {
|
|||
/// Iterator over the sections of a [Chunk]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SectionIter<'a> {
|
||||
/// Inner iterator enum
|
||||
inner: SectionIterInner<'a>,
|
||||
}
|
||||
|
||||
|
@ -193,6 +209,7 @@ impl<'a> Chunk<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Returns true if the chunk does not contain any sections
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
Chunk::V1_18 { section_map } => section_map.is_empty(),
|
||||
|
@ -230,14 +247,20 @@ impl<'a> Chunk<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Reference to block, biome and block light data of a section
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SectionIterItem<'a> {
|
||||
/// The Y coordinate of the section
|
||||
pub y: SectionY,
|
||||
/// Section block data
|
||||
pub section: &'a dyn Section,
|
||||
/// Section biome data
|
||||
pub biomes: &'a dyn Biomes,
|
||||
/// Section block light data
|
||||
pub block_light: BlockLight<'a>,
|
||||
}
|
||||
|
||||
/// Helper trait to specify section iterator trait bounds
|
||||
trait SectionIterTrait<'a>:
|
||||
Iterator<Item = SectionIterItem<'a>> + DoubleEndedIterator + ExactSizeIterator + FusedIterator
|
||||
{
|
||||
|
@ -252,6 +275,7 @@ impl<'a, T> SectionIterTrait<'a> for T where
|
|||
}
|
||||
|
||||
impl<'a> SectionIter<'a> {
|
||||
/// Helper to run a closure on the inner section iterator
|
||||
fn with_iter<F, T>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut dyn SectionIterTrait<'a>) -> T,
|
||||
|
|
|
@ -6,30 +6,39 @@ use serde::Deserialize;
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct BlockStatePaletteEntry {
|
||||
/// Block type ID
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// 1.18+ `block_states` element found in a [section](SectionV1_18)
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BlockStatesV1_18 {
|
||||
/// Palette of block types, indexed by block data
|
||||
pub palette: Vec<BlockStatePaletteEntry>,
|
||||
/// Block data
|
||||
pub data: Option<fastnbt::LongArray>,
|
||||
}
|
||||
|
||||
/// 1.18+ `biomes` element found in a [section](SectionV1_18)
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BiomesV1_18 {
|
||||
/// Palette of biome types, indexed by biome data
|
||||
pub palette: Vec<String>,
|
||||
/// Biome data
|
||||
pub data: Option<fastnbt::LongArray>,
|
||||
}
|
||||
|
||||
/// Element of the 1.18+ `sections` list found in a [Chunk]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SectionV1_18 {
|
||||
/// Y coordinate
|
||||
#[serde(rename = "Y")]
|
||||
pub y: i32,
|
||||
/// Block type data
|
||||
pub block_states: BlockStatesV1_18,
|
||||
/// Biome data
|
||||
pub biomes: BiomesV1_18,
|
||||
/// Block light data
|
||||
#[serde(rename = "BlockLight")]
|
||||
pub block_light: Option<fastnbt::ByteArray>,
|
||||
}
|
||||
|
@ -38,16 +47,23 @@ pub struct SectionV1_18 {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum SectionV0Variants {
|
||||
/// v1.13+ data
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
V1_13 {
|
||||
/// Block data
|
||||
block_states: fastnbt::LongArray,
|
||||
/// Block type palette, indexed by block data
|
||||
palette: Vec<BlockStatePaletteEntry>,
|
||||
},
|
||||
/// Pre-1.13 data
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
V0 {
|
||||
/// Block type data
|
||||
blocks: fastnbt::ByteArray,
|
||||
/// Block damage / subtype data
|
||||
data: fastnbt::ByteArray,
|
||||
},
|
||||
/// Empty section
|
||||
Empty {},
|
||||
}
|
||||
|
||||
|
@ -55,8 +71,11 @@ pub enum SectionV0Variants {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct SectionV0 {
|
||||
/// Y coordinate
|
||||
pub y: i8,
|
||||
/// Block light data
|
||||
pub block_light: Option<fastnbt::ByteArray>,
|
||||
/// Version-specific data
|
||||
#[serde(flatten)]
|
||||
pub section: SectionV0Variants,
|
||||
}
|
||||
|
@ -65,7 +84,9 @@ pub struct SectionV0 {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum BiomesV0 {
|
||||
/// Data for Minecraft versions storing biome data as an IntArray
|
||||
IntArray(fastnbt::IntArray),
|
||||
/// Data for Minecraft versions storing biome data as an ByteArray
|
||||
ByteArray(fastnbt::ByteArray),
|
||||
}
|
||||
|
||||
|
@ -73,8 +94,10 @@ pub enum BiomesV0 {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct LevelV0 {
|
||||
/// Section data
|
||||
#[serde(default)]
|
||||
pub sections: Vec<SectionV0>,
|
||||
/// Biome data
|
||||
pub biomes: Option<BiomesV0>,
|
||||
}
|
||||
|
||||
|
@ -82,11 +105,15 @@ pub struct LevelV0 {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ChunkVariants {
|
||||
/// 1.18+ chunk data
|
||||
V1_18 {
|
||||
/// List of chunk sections
|
||||
sections: Vec<SectionV1_18>,
|
||||
},
|
||||
/// Pre-1.18 chunk data
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
V0 {
|
||||
/// `Level` field of the chunk
|
||||
level: LevelV0,
|
||||
},
|
||||
}
|
||||
|
@ -95,16 +122,20 @@ pub enum ChunkVariants {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Chunk {
|
||||
/// The data version of the chunk
|
||||
pub data_version: Option<u32>,
|
||||
/// Version-specific chunk data
|
||||
#[serde(flatten)]
|
||||
pub chunk: ChunkVariants,
|
||||
}
|
||||
|
||||
/// "Data" compound element of level.dat
|
||||
/// `Data` compound element of level.dat
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct LevelDatData {
|
||||
/// X coordinate of spawn point for new players
|
||||
pub spawn_x: i32,
|
||||
/// Z coordinate of spawn point for new players
|
||||
pub spawn_z: i32,
|
||||
}
|
||||
|
||||
|
@ -112,5 +143,6 @@ pub struct LevelDatData {
|
|||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct LevelDat {
|
||||
/// The `Data` field
|
||||
pub data: LevelDatData,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Functions to search the "top" layer of a chunk
|
||||
|
||||
use std::num::NonZeroU16;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
@ -10,6 +12,7 @@ use crate::{
|
|||
types::*,
|
||||
};
|
||||
|
||||
/// Height (Y coordinate) of a block
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BlockHeight(pub i32);
|
||||
|
||||
|
@ -28,27 +31,52 @@ impl BlockHeight {
|
|||
}
|
||||
}
|
||||
|
||||
/// Array optionally storing a [BlockType] for each coordinate of a chunk
|
||||
pub type BlockArray = LayerBlockArray<Option<BlockType>>;
|
||||
|
||||
/// Array optionally storing a biome index for each coordinate of a chunk
|
||||
///
|
||||
/// The entries refer to a biome list generated with the top layer data.
|
||||
/// Indices are stored incremented by 1 to allow using a [NonZeroU16].
|
||||
pub type BiomeArray = LayerBlockArray<Option<NonZeroU16>>;
|
||||
|
||||
/// Array storing a block light value for each coordinate for a chunk
|
||||
pub type BlockLightArray = LayerBlockArray<u8>;
|
||||
|
||||
/// Array optionally storing a depth value for each coordinate for a chunk
|
||||
pub type DepthArray = LayerBlockArray<Option<BlockHeight>>;
|
||||
|
||||
/// References to LayerData entries for a single coordinate pair
|
||||
struct LayerEntry<'a> {
|
||||
/// The block type of the referenced entry
|
||||
block: &'a mut Option<BlockType>,
|
||||
/// The biome type of the referenced entry
|
||||
biome: &'a mut Option<NonZeroU16>,
|
||||
/// The block light of the referenced entry
|
||||
block_light: &'a mut u8,
|
||||
/// The depth value of the referenced entry
|
||||
depth: &'a mut Option<BlockHeight>,
|
||||
}
|
||||
|
||||
impl<'a> LayerEntry<'a> {
|
||||
/// Returns true if the entry has not been filled yet (no opaque block has been encountered)
|
||||
///
|
||||
/// The depth value is filled separately when a non-water block is encountered after the block type
|
||||
/// has already been filled.
|
||||
fn is_empty(&self) -> bool {
|
||||
self.block.is_none()
|
||||
}
|
||||
|
||||
/// Returns true if the entry has been filled including its depth (an opaque non-water block has been
|
||||
/// encountered)
|
||||
fn done(&self) -> bool {
|
||||
self.depth.is_some()
|
||||
}
|
||||
|
||||
/// Fills in the LayerEntry
|
||||
///
|
||||
/// Checks whether the passed coordinates point at an opaque or non-water block and
|
||||
/// fills in the entry accordingly. Returns true when the block has been filled including its depth.
|
||||
fn fill(
|
||||
&mut self,
|
||||
biome_list: &mut IndexSet<Biome>,
|
||||
|
@ -90,15 +118,24 @@ impl<'a> LayerEntry<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Top layer data
|
||||
///
|
||||
/// A LayerData stores block type, biome, block light and depth data for
|
||||
/// each coordinate of a chunk.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LayerData {
|
||||
/// Block type data
|
||||
pub blocks: Box<BlockArray>,
|
||||
/// Biome data
|
||||
pub biomes: Box<BiomeArray>,
|
||||
/// Block light data
|
||||
pub block_light: Box<BlockLightArray>,
|
||||
/// Depth data
|
||||
pub depths: Box<DepthArray>,
|
||||
}
|
||||
|
||||
impl LayerData {
|
||||
/// Builds a [LayerEntry] referencing the LayerData at a given coordinate pair
|
||||
fn entry(&mut self, coords: LayerBlockCoords) -> LayerEntry {
|
||||
LayerEntry {
|
||||
block: &mut self.blocks[coords],
|
||||
|
@ -109,13 +146,14 @@ impl LayerData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Fills in a [BlockInfoArray] with the information of the chunk's top
|
||||
/// Fills in a [LayerData] with the information of the chunk's top
|
||||
/// block layer
|
||||
///
|
||||
/// For each (X, Z) coordinate pair, the topmost opaque block is
|
||||
/// determined as the block that should be visible on the rendered
|
||||
/// map. For water blocks, the height of the first non-water block
|
||||
/// is additionally filled in as the water depth.
|
||||
/// is additionally filled in as the water depth (the block height is
|
||||
/// used as depth otherwise).
|
||||
pub fn top_layer(biome_list: &mut IndexSet<Biome>, chunk: &Chunk) -> Result<Option<LayerData>> {
|
||||
use BLOCKS_PER_CHUNK as N;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Data structures describing Minecraft save data
|
||||
|
||||
pub mod chunk;
|
||||
pub mod de;
|
||||
pub mod layer;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
//! Higher-level interfaces to section data
|
||||
//!
|
||||
//! The data types in this module attempt to provide interfaces abstracting
|
||||
//! over different data versions as much as possible.
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
@ -9,6 +14,14 @@ use crate::{
|
|||
types::*,
|
||||
};
|
||||
|
||||
use BLOCKS_PER_CHUNK as N;
|
||||
/// Maximum height of pre-1.18 levels
|
||||
const HEIGHT: usize = 256;
|
||||
/// Number of biome entries per chunk in each direction
|
||||
const BN: usize = N >> 2;
|
||||
/// Pre-1.18 height of level measured in 4-block spans (resolution of 1.15+ biome data)
|
||||
const BHEIGHT: usize = HEIGHT >> 2;
|
||||
|
||||
/// 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
|
||||
|
@ -29,20 +42,31 @@ fn palette_bits(len: usize, min: u8, max: u8) -> Option<u8> {
|
|||
|
||||
/// Trait for common functions of [SectionV1_13] and [SectionV0]
|
||||
pub trait Section: Debug {
|
||||
/// Returns the [BlockType] at a coordinate tuple inside the section
|
||||
fn block_at(&self, coords: SectionBlockCoords) -> Result<Option<BlockType>>;
|
||||
}
|
||||
|
||||
/// Minecraft v1.13+ section block data
|
||||
#[derive(Debug)]
|
||||
pub struct SectionV1_13<'a> {
|
||||
/// Packed block type data
|
||||
block_states: Option<&'a [i64]>,
|
||||
/// List of block types indexed by entries encoded in *block_states*
|
||||
palette: Vec<Option<BlockType>>,
|
||||
/// Number of bits per block in *block_states*
|
||||
bits: u8,
|
||||
/// Set to true if packed block entries in *block_states* are aligned to i64
|
||||
///
|
||||
/// In older data formats, entries are unaligned and a single block can span
|
||||
/// two i64 entries.
|
||||
aligned_blocks: bool,
|
||||
}
|
||||
|
||||
impl<'a> SectionV1_13<'a> {
|
||||
/// Constructs a new [SectionV1_13] from deserialized data structures
|
||||
///
|
||||
/// The block IDs in the section's palette are resolved to their [BlockType]s
|
||||
/// to allow for faster lookup later.
|
||||
pub fn new(
|
||||
data_version: u32,
|
||||
block_states: Option<&'a [i64]>,
|
||||
|
@ -127,16 +151,21 @@ impl<'a> Section for SectionV1_13<'a> {
|
|||
/// Pre-1.13 section block data
|
||||
#[derive(Debug)]
|
||||
pub struct SectionV0<'a> {
|
||||
/// Block type data
|
||||
///
|
||||
/// Each i8 entry corresponds to a block in the 16x16x16 section
|
||||
blocks: &'a [i8],
|
||||
/// Block damage/subtype data
|
||||
///
|
||||
/// Uses 4 bits for each block in the 16x16x16 section
|
||||
data: &'a [i8],
|
||||
/// Used to look up block type IDs
|
||||
block_types: &'a BlockTypes,
|
||||
}
|
||||
|
||||
impl<'a> SectionV0<'a> {
|
||||
/// Constructs a new [SectionV0] from deserialized data structures
|
||||
pub fn new(blocks: &'a [i8], data: &'a [i8], block_types: &'a BlockTypes) -> Result<Self> {
|
||||
use BLOCKS_PER_CHUNK as N;
|
||||
|
||||
if blocks.len() != N * N * N {
|
||||
bail!("Invalid section block data");
|
||||
}
|
||||
|
@ -171,6 +200,7 @@ impl<'a> Section for SectionV0<'a> {
|
|||
|
||||
/// Trait for common functions of [BiomesV1_18] and [BiomesV0]
|
||||
pub trait Biomes: Debug {
|
||||
/// Returns the [Biome] at a coordinate tuple inside the chunk
|
||||
fn biome_at(&self, section: SectionY, coords: SectionBlockCoords) -> Result<Option<&Biome>>;
|
||||
}
|
||||
|
||||
|
@ -181,13 +211,21 @@ pub trait Biomes: Debug {
|
|||
/// v1.13+ block data.
|
||||
#[derive(Debug)]
|
||||
pub struct BiomesV1_18<'a> {
|
||||
/// Packed biome data
|
||||
///
|
||||
/// Each entry specifies the biome of a 4x4x4 block area.
|
||||
///
|
||||
/// Unlike block type data in [SectionV1_13], biome data is always aligned
|
||||
/// to whole i64 values.
|
||||
biomes: Option<&'a [i64]>,
|
||||
/// Biome palette indexed by entries encoded in *biomes*
|
||||
palette: Vec<Option<&'a Biome>>,
|
||||
/// Number of bits used for each entry in *biomes*
|
||||
bits: u8,
|
||||
}
|
||||
|
||||
impl<'a> BiomesV1_18<'a> {
|
||||
/// Constructs a new [BiomesV18] from deserialized data structures
|
||||
/// Constructs a new [BiomesV1_18] from deserialized data structures
|
||||
pub fn new(
|
||||
biomes: Option<&'a [i64]>,
|
||||
palette: &'a [String],
|
||||
|
@ -223,9 +261,6 @@ impl<'a> BiomesV1_18<'a> {
|
|||
|
||||
/// Looks up the block type palette index at the given coordinates
|
||||
fn palette_index_at(&self, coords: SectionBlockCoords) -> usize {
|
||||
const N: usize = BLOCKS_PER_CHUNK;
|
||||
const BN: usize = N >> 2;
|
||||
|
||||
let Some(biomes) = self.biomes else {
|
||||
return 0;
|
||||
};
|
||||
|
@ -262,28 +297,31 @@ impl<'a> Biomes for BiomesV1_18<'a> {
|
|||
/// different pre-v1.18 Minecraft versions
|
||||
#[derive(Debug)]
|
||||
enum BiomesV0Data<'a> {
|
||||
/// Biome data stored as IntArray in 1.15+ format
|
||||
///
|
||||
/// Minecraft 1.15 switched to 3-dimensional biome information, but reduced
|
||||
/// the resolution to only use one entry for every 4x4x4 block area.
|
||||
IntArrayV15(&'a fastnbt::IntArray),
|
||||
/// Biome data stored as IntArray in some pre-1.15 versions
|
||||
IntArrayV0(&'a fastnbt::IntArray),
|
||||
/// Biome data stored as ByteArray in some pre-1.15 versions
|
||||
ByteArray(&'a fastnbt::ByteArray),
|
||||
}
|
||||
|
||||
/// Pre-v1.18 section biome data
|
||||
#[derive(Debug)]
|
||||
pub struct BiomesV0<'a> {
|
||||
/// Biome data from save data
|
||||
data: BiomesV0Data<'a>,
|
||||
/// Used to look up biome IDs
|
||||
biome_types: &'a BiomeTypes,
|
||||
}
|
||||
|
||||
impl<'a> BiomesV0<'a> {
|
||||
/// Constructs a new [BiomesV0] from deserialized data structures
|
||||
pub fn new(biomes: Option<&'a de::BiomesV0>, biome_types: &'a BiomeTypes) -> Result<Self> {
|
||||
const N: usize = BLOCKS_PER_CHUNK;
|
||||
const MAXY: usize = 256;
|
||||
const BN: usize = N >> 2;
|
||||
const BMAXY: usize = MAXY >> 2;
|
||||
|
||||
let data = match biomes {
|
||||
Some(de::BiomesV0::IntArray(data)) if data.len() == BN * BN * BMAXY => {
|
||||
Some(de::BiomesV0::IntArray(data)) if data.len() == BN * BN * BHEIGHT => {
|
||||
BiomesV0Data::IntArrayV15(data)
|
||||
}
|
||||
Some(de::BiomesV0::IntArray(data)) if data.len() == N * N => {
|
||||
|
@ -302,16 +340,12 @@ impl<'a> Biomes for BiomesV0<'a> {
|
|||
fn biome_at(&self, section: SectionY, coords: SectionBlockCoords) -> Result<Option<&Biome>> {
|
||||
let id = match self.data {
|
||||
BiomesV0Data::IntArrayV15(data) => {
|
||||
const N: usize = BLOCKS_PER_CHUNK;
|
||||
const MAXY: usize = 256;
|
||||
const BN: usize = N >> 2;
|
||||
|
||||
let LayerBlockCoords { x, z } = coords.xz;
|
||||
let y = section
|
||||
.0
|
||||
.checked_mul(BLOCKS_PER_CHUNK as i32)
|
||||
.and_then(|y| y.checked_add_unsigned(coords.y.0.into()))
|
||||
.filter(|&height| height >= 0 && (height as usize) < MAXY)
|
||||
.filter(|&height| height >= 0 && (height as usize) < HEIGHT)
|
||||
.context("Y coordinate out of range")? as usize;
|
||||
let offset = (y >> 2) * BN * BN + (z.0 >> 2) as usize * BN + (x.0 >> 2) as usize;
|
||||
let id = data[offset] as u32;
|
||||
|
@ -327,12 +361,13 @@ impl<'a> Biomes for BiomesV0<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Wrapper around chunk block light data array
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BlockLight<'a>(Option<&'a [i8]>);
|
||||
|
||||
impl<'a> BlockLight<'a> {
|
||||
/// Creates a new [BlockLight], checking validity
|
||||
pub fn new(block_light: Option<&'a [i8]>) -> Result<Self> {
|
||||
use BLOCKS_PER_CHUNK as N;
|
||||
if let Some(block_light) = block_light {
|
||||
if block_light.len() != N * N * N / 2 {
|
||||
bail!("Invalid section block light data");
|
||||
|
@ -341,6 +376,7 @@ impl<'a> BlockLight<'a> {
|
|||
Ok(BlockLight(block_light))
|
||||
}
|
||||
|
||||
/// Returns the block light value at the given coordinates
|
||||
pub fn block_light_at(&self, coords: SectionBlockCoords) -> u8 {
|
||||
let Some(block_light) = self.0 else {
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue