Split up BlockInfo type

By storing block types and depth values separately, the processed world
data can be compressed better, decreasing data size by ~10%.
This commit is contained in:
Matthias Schiffer 2023-05-06 00:44:00 +02:00
parent 0b392d7a3a
commit 31eb92864c
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
4 changed files with 45 additions and 43 deletions

View file

@ -1,14 +1,18 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use minedmap::{types::*, world}; use serde::{Deserialize, Serialize};
use minedmap::{types::*, world::layer};
pub type RegionCoords = (i32, i32); pub type RegionCoords = (i32, i32);
pub type ProcessedRegion = ChunkArray<
Option<( #[derive(Debug, Clone, Serialize, Deserialize)]
Box<world::layer::BlockInfoArray>, pub struct ProcessedChunk {
Box<world::layer::BiomeArray>, pub blocks: Box<layer::BlockArray>,
)>, pub biomes: Box<layer::BiomeArray>,
>; pub depths: Box<layer::DepthArray>,
}
pub type ProcessedRegion = ChunkArray<Option<ProcessedChunk>>;
pub struct Config { pub struct Config {
pub region_dir: PathBuf, pub region_dir: PathBuf,

View file

@ -6,7 +6,10 @@ use minedmap::{
io::storage, io::storage,
resource, resource,
types::*, types::*,
world::{self, layer::LayerData}, world::{
self,
layer::{self, LayerData},
},
}; };
use super::common::*; use super::common::*;
@ -104,15 +107,19 @@ impl<'a> RegionProcessor<'a> {
minedmap::io::region::from_file(path)?.foreach_chunk( minedmap::io::region::from_file(path)?.foreach_chunk(
|chunk_coords, data: world::de::Chunk| { |chunk_coords, data: world::de::Chunk| {
let Some(layer_data) = self let Some(layer::LayerData{ blocks, biomes, block_light, depths }) = self
.process_chunk(data) .process_chunk(data)
.with_context(|| format!("Failed to process chunk {:?}", chunk_coords))? .with_context(|| format!("Failed to process chunk {:?}", chunk_coords))?
else { else {
return Ok(()); return Ok(());
}; };
processed_region[chunk_coords] = Some((layer_data.blocks, layer_data.biomes)); processed_region[chunk_coords] = Some(ProcessedChunk {
blocks,
biomes,
depths,
});
let chunk_lightmap = Self::render_chunk_lightmap(layer_data.block_light); let chunk_lightmap = Self::render_chunk_lightmap(block_light);
overlay_chunk(&mut lightmap, &chunk_lightmap, chunk_coords); overlay_chunk(&mut lightmap, &chunk_lightmap, chunk_coords);
Ok(()) Ok(())

View file

@ -2,7 +2,7 @@ use std::fs;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use minedmap::{io::storage, resource::block_color, types::*, world}; use minedmap::{io::storage, resource::block_color, types::*};
use super::common::*; use super::common::*;
@ -20,12 +20,7 @@ impl<'a> TileRenderer<'a> {
storage::read(&processed_path).context("Failed to load processed region data") storage::read(&processed_path).context("Failed to load processed region data")
} }
fn render_chunk( fn render_chunk(image: &mut image::RgbaImage, coords: ChunkCoords, chunk: &ProcessedChunk) {
image: &mut image::RgbaImage,
coords: ChunkCoords,
blocks: &world::layer::BlockInfoArray,
biomes: &world::layer::BiomeArray,
) {
const N: u32 = BLOCKS_PER_CHUNK as u32; const N: u32 = BLOCKS_PER_CHUNK as u32;
let chunk_image = image::RgbaImage::from_fn(N, N, |x, z| { let chunk_image = image::RgbaImage::from_fn(N, N, |x, z| {
@ -33,28 +28,29 @@ impl<'a> TileRenderer<'a> {
x: BlockX(x as u8), x: BlockX(x as u8),
z: BlockZ(z as u8), z: BlockZ(z as u8),
}; };
image::Rgba(match (&blocks[coords], &biomes[coords]) { image::Rgba(
( match (
world::layer::BlockInfo { &chunk.blocks[coords],
block_type: Some(block_type), &chunk.biomes[coords],
depth: Some(depth), &chunk.depths[coords],
.. ) {
}, (Some(block), Some(biome), Some(depth)) => {
Some(biome), block_color(*block, biome, depth.0 as f32)
) => block_color(*block_type, biome, depth.0 as f32), }
_ => [0, 0, 0, 0], _ => [0, 0, 0, 0],
}) },
)
}); });
overlay_chunk(image, &chunk_image, coords); overlay_chunk(image, &chunk_image, coords);
} }
fn render_region(image: &mut image::RgbaImage, region: &ProcessedRegion) { fn render_region(image: &mut image::RgbaImage, region: &ProcessedRegion) {
for (coords, chunk) in region.iter() { for (coords, chunk) in region.iter() {
let Some((blocks, biomes)) = chunk else { let Some(chunk) = chunk else {
continue; continue;
}; };
Self::render_chunk(image, coords, blocks, biomes); Self::render_chunk(image, coords, chunk);
} }
} }

View file

@ -25,15 +25,10 @@ impl BlockHeight {
} }
} }
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)] pub type BlockArray = LayerBlockArray<Option<BlockType>>;
pub struct BlockInfo {
pub block_type: Option<BlockType>,
pub depth: Option<BlockHeight>,
}
pub type BlockInfoArray = LayerBlockArray<BlockInfo>;
pub type BiomeArray = LayerBlockArray<Option<Biome>>; pub type BiomeArray = LayerBlockArray<Option<Biome>>;
pub type BlockLightArray = LayerBlockArray<u8>; pub type BlockLightArray = LayerBlockArray<u8>;
pub type DepthArray = LayerBlockArray<Option<BlockHeight>>;
struct LayerEntry<'a> { struct LayerEntry<'a> {
block: &'a mut Option<BlockType>, block: &'a mut Option<BlockType>,
@ -80,19 +75,19 @@ impl<'a> LayerEntry<'a> {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct LayerData { pub struct LayerData {
pub blocks: Box<BlockInfoArray>, pub blocks: Box<BlockArray>,
pub biomes: Box<BiomeArray>, pub biomes: Box<BiomeArray>,
pub block_light: Box<BlockLightArray>, pub block_light: Box<BlockLightArray>,
pub depths: Box<DepthArray>,
} }
impl LayerData { impl LayerData {
fn entry(&mut self, coords: LayerBlockCoords) -> LayerEntry { fn entry(&mut self, coords: LayerBlockCoords) -> LayerEntry {
let block_info = &mut self.blocks[coords];
LayerEntry { LayerEntry {
block: &mut block_info.block_type, block: &mut self.blocks[coords],
biome: &mut self.biomes[coords], biome: &mut self.biomes[coords],
block_light: &mut self.block_light[coords], block_light: &mut self.block_light[coords],
depth: &mut block_info.depth, depth: &mut self.depths[coords],
} }
} }
} }
@ -116,7 +111,7 @@ pub fn top_layer(chunk: &Chunk) -> Result<Option<LayerData>> {
for section in chunk.sections().rev() { for section in chunk.sections().rev() {
for y in BlockY::iter().rev() { for y in BlockY::iter().rev() {
for xz in BlockInfoArray::keys() { for xz in LayerBlockArray::<()>::keys() {
let mut entry = ret.entry(xz); let mut entry = ret.entry(xz);
if entry.done() { if entry.done() {
continue; continue;