diff --git a/src/world/chunk.rs b/src/world/chunk.rs index 10efc6a..a9a5c6b 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -24,14 +24,14 @@ pub enum Chunk<'a> { /// block IDs V1_13 { section_map: BTreeMap, BlockLight<'a>)>, - biomes: &'a de::BiomesV0, + biomes: BiomesV0<'a>, }, /// Original pre-1.13 chunk /// /// The original chunk format with fixed 8-bit numeric block IDs V0 { section_map: BTreeMap, BlockLight<'a>)>, - biomes: &'a de::BiomesV0, + biomes: BiomesV0<'a>, }, /// Unpopulated chunk without any block data Empty, @@ -158,8 +158,7 @@ impl<'a> Chunk<'a> { } } - // TODO Check biomes length - let biomes = level.biomes.as_ref().context("Invalid biome data"); + let biomes = BiomesV0::new(level.biomes.as_ref()); Ok( match (section_map_v1_13.is_empty(), section_map_v0.is_empty()) { diff --git a/src/world/section.rs b/src/world/section.rs index d3c590a..1aa8b7f 100644 --- a/src/world/section.rs +++ b/src/world/section.rs @@ -202,6 +202,36 @@ impl<'a> BiomesV18<'a> { } } +/// Pre-v1.18 section biome data +/// +/// There are a 3 formats for biome data that were used in +/// different pre-v1.18 Minecraft versions +#[derive(Debug)] +pub enum BiomesV0<'a> { + IntArrayV15(&'a fastnbt::IntArray), + IntArrayV0(&'a fastnbt::IntArray), + ByteArray(&'a fastnbt::ByteArray), +} + +impl<'a> BiomesV0<'a> { + /// Constructs a new [BiomesV0] from deserialized data structures + pub fn new(biomes: Option<&'a de::BiomesV0>) -> Result { + const N: usize = BLOCKS_PER_CHUNK; + const MAXY: usize = 256; + const BN: usize = N >> 2; + const BMAXY: usize = MAXY >> 2; + + Ok(match biomes { + Some(de::BiomesV0::IntArray(data)) if data.len() == BN * BN * BMAXY => { + BiomesV0::IntArrayV15(data) + } + Some(de::BiomesV0::IntArray(data)) if data.len() == N * N => BiomesV0::IntArrayV0(data), + Some(de::BiomesV0::ByteArray(data)) if data.len() == N * N => BiomesV0::ByteArray(data), + _ => bail!("Invalid biome data"), + }) + } +} + #[derive(Debug, Clone, Copy)] pub struct BlockLight<'a>(Option<&'a [i8]>);