mirror of
https://github.com/neocturne/MinedMap.git
synced 2025-03-05 17:44:52 +01:00
world: add types to wrap common parts of section data
This commit is contained in:
parent
b040a635ed
commit
2d782f25b1
3 changed files with 208 additions and 0 deletions
111
src/world/chunk.rs
Normal file
111
src/world/chunk.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
de,
|
||||||
|
section::{OldSection, PaletteSection, PaletteSectionBiomes},
|
||||||
|
};
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
pub enum Chunk<'a> {
|
||||||
|
V1_18 {
|
||||||
|
section_map: BTreeMap<SectionY, (PaletteSection<'a>, PaletteSectionBiomes<'a>)>,
|
||||||
|
},
|
||||||
|
V1_13 {
|
||||||
|
section_map: BTreeMap<SectionY, PaletteSection<'a>>,
|
||||||
|
biomes: &'a de::BiomesOld,
|
||||||
|
},
|
||||||
|
Old {
|
||||||
|
section_map: BTreeMap<SectionY, OldSection<'a>>,
|
||||||
|
biomes: &'a de::BiomesOld,
|
||||||
|
},
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Chunk<'a> {
|
||||||
|
pub fn new(data: &'a de::Chunk) -> Result<Self> {
|
||||||
|
let data_version = data.data_version.unwrap_or_default();
|
||||||
|
|
||||||
|
match &data.chunk {
|
||||||
|
de::ChunkVariants::V1_18 { sections } => Self::new_v1_18(data_version, sections),
|
||||||
|
de::ChunkVariants::Old { level } => Self::new_old(data_version, level),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_v1_18(data_version: u32, sections: &'a Vec<de::SectionV1_18>) -> Result<Self> {
|
||||||
|
let mut section_map = BTreeMap::new();
|
||||||
|
|
||||||
|
for section in sections {
|
||||||
|
section_map.insert(
|
||||||
|
SectionY(section.y),
|
||||||
|
(
|
||||||
|
PaletteSection::new(
|
||||||
|
data_version,
|
||||||
|
section.block_states.data.as_ref(),
|
||||||
|
§ion.block_states.palette,
|
||||||
|
)
|
||||||
|
.with_context(|| format!("Failed to load section at Y={}", section.y))?,
|
||||||
|
PaletteSectionBiomes::new(
|
||||||
|
section.biomes.data.as_ref(),
|
||||||
|
§ion.biomes.palette,
|
||||||
|
)
|
||||||
|
.with_context(|| format!("Failed to load section biomes at Y={}", section.y))?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Chunk::V1_18 { section_map })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_old(data_version: u32, level: &'a de::LevelOld) -> Result<Self> {
|
||||||
|
let mut section_map_v1_13 = BTreeMap::new();
|
||||||
|
let mut section_map_old = BTreeMap::new();
|
||||||
|
|
||||||
|
for section in &level.sections {
|
||||||
|
match §ion.section {
|
||||||
|
de::SectionOldVariants::V1_13 {
|
||||||
|
block_states,
|
||||||
|
palette,
|
||||||
|
} => {
|
||||||
|
section_map_v1_13.insert(
|
||||||
|
SectionY(section.y.into()),
|
||||||
|
PaletteSection::new(data_version, Some(block_states), palette)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("Failed to load section at Y={}", section.y)
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
de::SectionOldVariants::Old { blocks, data } => {
|
||||||
|
section_map_old.insert(
|
||||||
|
SectionY(section.y.into()),
|
||||||
|
OldSection::new(blocks, data).with_context(|| {
|
||||||
|
format!("Failed to load section at Y={}", section.y)
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
de::SectionOldVariants::Empty {} => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Check biomes length
|
||||||
|
let biomes = level.biomes.as_ref().context("Invalid biome data");
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
match (section_map_v1_13.is_empty(), section_map_old.is_empty()) {
|
||||||
|
(true, true) => Chunk::Empty,
|
||||||
|
(false, true) => Chunk::V1_13 {
|
||||||
|
section_map: section_map_v1_13,
|
||||||
|
biomes: biomes?,
|
||||||
|
},
|
||||||
|
(true, false) => Chunk::Old {
|
||||||
|
section_map: section_map_old,
|
||||||
|
biomes: biomes?,
|
||||||
|
},
|
||||||
|
(false, false) => {
|
||||||
|
bail!("Mixed section versions");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,3 @@
|
||||||
|
pub mod chunk;
|
||||||
pub mod de;
|
pub mod de;
|
||||||
|
pub mod section;
|
||||||
|
|
95
src/world/section.rs
Normal file
95
src/world/section.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
|
||||||
|
use super::de;
|
||||||
|
|
||||||
|
fn palette_bits(len: usize, min: u8, max: u8) -> Option<u8> {
|
||||||
|
let mut bits = min;
|
||||||
|
while (1 << bits) < len {
|
||||||
|
bits += 1;
|
||||||
|
|
||||||
|
if bits > max {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PaletteSectionBiomes<'a> {
|
||||||
|
biomes: Option<&'a fastnbt::LongArray>,
|
||||||
|
palette: &'a Vec<String>,
|
||||||
|
bits: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PaletteSectionBiomes<'a> {
|
||||||
|
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")?;
|
||||||
|
|
||||||
|
if let Some(biomes) = biomes {
|
||||||
|
let biomes_per_word = 64 / bits as usize;
|
||||||
|
let expected_length = (64 + biomes_per_word - 1) / biomes_per_word;
|
||||||
|
if biomes.len() != expected_length {
|
||||||
|
bail!("Invalid section biome data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PaletteSectionBiomes {
|
||||||
|
biomes,
|
||||||
|
palette,
|
||||||
|
bits,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PaletteSection<'a> {
|
||||||
|
block_states: Option<&'a fastnbt::LongArray>,
|
||||||
|
palette: &'a Vec<de::BlockStatePaletteEntry>,
|
||||||
|
bits: u8,
|
||||||
|
aligned_blocks: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PaletteSection<'a> {
|
||||||
|
pub fn new(
|
||||||
|
data_version: u32,
|
||||||
|
block_states: Option<&'a fastnbt::LongArray>,
|
||||||
|
palette: &'a Vec<de::BlockStatePaletteEntry>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let aligned_blocks = data_version >= 2529;
|
||||||
|
|
||||||
|
let bits = palette_bits(palette.len(), 4, 12).context("Unsupported block palette size")?;
|
||||||
|
|
||||||
|
if let Some(block_states) = block_states {
|
||||||
|
let expected_length = if aligned_blocks {
|
||||||
|
let blocks_per_word = 64 / bits as usize;
|
||||||
|
(4096 + blocks_per_word - 1) / blocks_per_word
|
||||||
|
} else {
|
||||||
|
64 * bits as usize
|
||||||
|
};
|
||||||
|
if block_states.len() != expected_length {
|
||||||
|
bail!("Invalid section block data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
block_states,
|
||||||
|
palette,
|
||||||
|
bits,
|
||||||
|
aligned_blocks,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OldSection<'a> {
|
||||||
|
blocks: &'a fastnbt::ByteArray,
|
||||||
|
data: &'a fastnbt::ByteArray,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> OldSection<'a> {
|
||||||
|
pub fn new(blocks: &'a fastnbt::ByteArray, data: &'a fastnbt::ByteArray) -> Result<Self> {
|
||||||
|
// TODO: Check lengths
|
||||||
|
Ok(Self { blocks, data })
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue