-
Notifications
You must be signed in to change notification settings - Fork 0
[Batch 2] Chunk serialization/deserialization #377
Copy link
Copy link
Open
Labels
batch-2Batch 2: GPU Culling + CompressionBatch 2: GPU Culling + CompressionbugSomething isn't workingSomething isn't workingdocumentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or requesthotfixworld/persistenceWorld save/load systemWorld save/load system
Description
Summary
Implement serialization and deserialization of chunk data (blocks, light, biomes) to a compact binary format. This is the data layer that sits between Chunk structs and the region file API from #372.
Depends on: #372 (region file format API)
Current State
Chunk data lives purely in memory:
Chunk.blocks:[CHUNK_SIZE_X][CHUNK_SIZE_Y][CHUNK_SIZE_Z]BlockType— 16×256×16 × 1 byte = 64KBChunk.sky_light/Chunk.block_light: packed light arraysBiomeIdper column (or per-block in some paths)- No serialization format exists
Serialization Format
[ChunkHeader: 8 bytes]
magic: u32 = 0x5A434B00 ("ZCK\0")
version: u8 = 1
flags: u8 = bitfield (has_block_light, has_biome_data, has_heightmap)
[BlockData: 4096 bytes]
16×16×16 block data per subchunk, NUM_SUBCHUNKS sections
BlockType stored as u8 (enum value)
Optional: RLE encoding for sparse subchunks (flag in header)
[LightData: variable]
If has_block_light:
Sky light: 16×16×16 packed nibbles per subchunk (2048 bytes total)
Block light: same format (RGB packed into 2 nibbles per block, or separate R/G/B)
[BiomeData: 256 bytes]
16×16 BiomeId (u8) per column
[HeightMap: 256 bytes] (optional)
16×16 u8 height values for quick surface lookup
Total uncompressed: ~64-70KB per chunk. With RLE on block data (many chunks are all-stone or all-air below/above surface), typical size: 2-20KB.
Implementation Plan
Step 1: Define wire format
- Create
src/world/persistence/chunk_serializer.zig - Define
ChunkHeader,ChunkDataVersionconstants - Version field allows future format changes without breaking old saves
Step 2: Serialize
pub fn serializeChunk(chunk: *const Chunk, allocator: Allocator) ![]u8- Write header with flags based on what data is present
- Write block data (subchunk by subchunk)
- Write light data if non-zero
- Write biome data
- Return owned slice (caller frees)
Step 3: Deserialize
pub fn deserializeChunk(data: []const u8, chunk: *Chunk) !void- Validate magic and version
- Read block data into chunk.blocks array
- Read light data if present (else default to full skylight)
- Read biome data if present
- Return error on corrupt/unknown version
Step 4: RLE optimization (optional, can be follow-up)
- For subchunks that are >80% single block type, use RLE:
[count, blockType]pairs - Flag in header indicates which subchunks use RLE
- Significant space savings for underground chunks
Files to Create
src/world/persistence/chunk_serializer.zig
Testing
- Round-trip: serialize chunk → deserialize → verify every block matches
- Round-trip: light data preserved correctly
- Round-trip: biome data preserved correctly
- Empty chunk (all air) serializes to minimal size
- Full chunk (all stone) serializes efficiently
- Corrupt data returns error, doesn't crash
- Unknown version returns error
- Integration: serialize → write to region file → read → deserialize → verify
Roadmap: docs/PERFORMANCE_ROADMAP.md — Batch 2, Issue 1B-2
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
batch-2Batch 2: GPU Culling + CompressionBatch 2: GPU Culling + CompressionbugSomething isn't workingSomething isn't workingdocumentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or requesthotfixworld/persistenceWorld save/load systemWorld save/load system