Chunk

10×10×10 block sub-volume with palette-compressed bit-packing.

Overview

Chunk stores 1 000 block values in a compact palette + bit-packed index format. It is the storage unit inside World — each world holds 10³ = 1 000 chunks. Engine-agnostic; no Urho3D headers.

Header: include/GalaxyEggbert/Worlds/Chunk.hpp. Implementation: src/GalaxyEggbert/Worlds/Chunk.cpp.

Constants

static constexpr int Size   = 10;       // blocks per axis
static constexpr int Volume = 1000;     // Size³

Internal Storage Layout

private:
    std::vector<Block>    palette_;          // unique block values (≤256)
    std::vector<uint8_t>  packedIndices_;    // bit-packed palette indices
    std::vector<uint8_t>  extraMetadata_;    // reserved for future use
    uint8_t               bitsPerBlock_;     // ceil(log2(palette_.size()))
    bool                  dirty_;            // set by setBlock, cleared on serialise

When the palette has 1 entry (uniform chunk), packedIndices_ may be empty. bitsPerBlock_ is recomputed whenever the palette grows.

API

namespace GalaxyEggbert::Worlds {

class Chunk {
public:
    // Factory helpers
    static Chunk createUniform(Block fillBlock);
    static Chunk fromBlocks(const std::array<Block, Volume>& blocks);

    Block getBlock(uint8_t lx, uint8_t ly, uint8_t lz) const;
    void  setBlock(uint8_t lx, uint8_t ly, uint8_t lz, Block block);

    // Unpack all 1 000 blocks into a flat array (for terrain meshing)
    std::array<Block, Volume> unpackBlocks() const;

    bool isEmpty()   const;   // all blocks == Air
    bool isUniform() const;   // palette_.size() == 1
    bool isDirty()   const;   // modified since last write()

    // Serialisation (called by World::saveToFile / loadFromFile)
    void write(std::ostream& os) const;
    void read (std::istream& is);
};

Bit-packing Details

Block indices into the palette are stored consecutively in packedIndices_. Each index occupies exactly bitsPerBlock_ bits. Indices are packed little-endian within each byte.

Palette sizeBits per blockBytes for 1000 blocks
1 (uniform)00 (packedIndices_ empty)
21125
3–42250
5–83375
9–164500
17–325625
33–646750
65–1287875
129–25681000

Coordinate Mapping

Local indices lx, ly, lz ∈ [0, 9]. Flat index: lx + ly*10 + lz*100. World-to-local: lx = worldX % 10. Chunk coordinate: cx = worldX / 10.

Serialisation

write() emits the VCH1 chunk payload as described in VWR Format: palette count, palette entries, packed index data, and optional BMD1 metadata section.

Tests

Covered by tests/GalaxyEggbert/Worlds/ChunkTests.cpp: uniform create, palette growth, bit-pack round-trip, isEmpty/isUniform, dirty flag, write/read round-trip.