World

The voxel world: a cubic grid of palette-compressed chunks, sparse per-block metadata, a block change journal, and the .vwr file reader and writer.

Location

Headerinclude/GalaxyEggbert/Worlds/World.hpp
Sourcesrc/GalaxyEggbert/Worlds/World.cpp
NamespaceGalaxyEggbert::Worlds
Depends onChunk, Block, VoxelConfig, BinaryIO.hpp (little-endian helpers)

Purpose

World is the single data model of a Galaxy Eggbert level. It has no CNA or cna-engine dependency: the game, the in-game editor, the renderers, the command-line verifiers and the unit tests all use the same class. Every campaign world in worlds3d/, every player's custom world and every galaxy world is one World saved as a .vwr file.

Coordinates are always raw grid cells, 0 to blocksPerAxis() - 1. The game's render space is shifted by 50 on X and Z (WorldRuntime::kWorldCenterX/Z); World never applies that shift.

Public API

All members verified in World.hpp as of 2026-11-10.

MemberDescription
explicit World(std::uint8_t chunksPerAxis = VoxelConfig::WorldChunksPerAxis)An all-air cubic world. Throws std::out_of_range for 0.
chunksPerAxis(), blocksPerAxis(), chunkCount()Grid dimensions (10, 100 and 1000 by default).
getBlock(x, y, z) / setBlock(x, y, z, Block)Read or write one cell. Both throw std::out_of_range outside the world. setBlock bumps the revision and journals the change only when the raw value actually changes.
chunk(cx, cy, cz) (const and mutable)Direct access to one Chunk by chunk-grid coordinates.
skyRegion() / setSkyRegion(r)Background id 0-31: selects Content/backgrounds/decorNNN.png.
musicTrack() / setMusicTrack(t), kMusicTrackCount = 100 = no music, 1-10 = the original tracks Content/music/music000-009.ogg. Out-of-range values are stored as 0.
missionNumber() / setMissionNumber(n)The mission this file is (1 the main hub; 10, 20, ... 120 the world hubs; 11, 12, ... their missions; 199; 998/999 the showcase worlds; 0 = none).
hasSpawnPoint(), spawnX/Y/Z(), setSpawnPoint(x, y, z), clearSpawnPoint()The optional explicit start cell (the yellow player start). setSpawnPoint throws outside the world.
hasLegacySawFloors() / setLegacySawFloors(bool)True for files whose header flag bit 0 is clear: saws there were drawn with an implied floor. WorldRuntime upgrades such worlds in memory (see World Loading).
blockRevision()Counts setBlock() calls that changed a block, plus metadata additions/removals.
struct BlockChange { x, y, z, oldRaw, newRaw }One journaled change.
struct BlockChanges { bool known; std::vector<BlockChange> cells; }Result of blockChangesSince; known == false means "history lost, rebuild everything".
BlockChangeCapacity = 256Journal length; the oldest entries drop off.
blockChangesSince(revision)Non-destructive: every consumer keeps its own last-seen revision. Returns known = false when more changes happened than the journal holds, or after any extra-metadata edit (which clears the journal). The journal is never saved.
struct BlockExtraMetadataRecord { x, y, z, metadataType, payload }A sparse record resolved to world coordinates.
setBlockExtraMetadata(x, y, z, type, payload)Adds or replaces the record of that type at that cell (one per cell and type). Payload must fit in 65 535 bytes.
removeBlockExtraMetadata(x, y, z, type)Returns true if a record was removed.
findBlockExtraMetadata(x, y, z, type)Pointer to the payload bytes, or nullptr. Used for per-cell lookups such as a turned fan.
collectExtraMetadata(type)Every record of one type in the whole world, chunk by chunk.
saveToFile(path)Writes the .vwr file; throws std::runtime_error on failure. Empty chunks (all air and no metadata) are written as table entries only.
static loadFromFile(path)Reads and validates a .vwr file; throws std::runtime_error on any mismatch.
static loadFromStream(std::istream&)The same validation from a seekable stream starting at byte 0. The game uses it to decode the exact byte snapshot it hashed for the resume log.

How it is used

Loading and saving

The minimal round trip (from World Format.md):

#include "GalaxyEggbert/Worlds/World.hpp"
using namespace GalaxyEggbert::Worlds;

World world;
const Block grass = Block::make(1, 0);
world.setBlock(10, 5, 10, grass);
world.saveToFile("level.vwr");

World loaded = World::loadFromFile("level.vwr");
return loaded.getBlock(10, 5, 10) == grass ? 0 : 1;

In the game, WorldRuntime::LoadFromVwrStream() (src/GalaxyEggbert/Game/WorldRuntime.cpp) wraps the loaded world in a std::unique_ptr, runs the legacy saw-floor upgrade and then derives objects, BigDecor and hint zones from the sparse metadata. See WorldRuntime.

Patching the terrain from the change journal

When a door opens, a bridge crumbles or a switch flips the saws, the game changes blocks through setBlock(). Each frame GalaxyEggbertGame::RefreshTerrainMeshIfChanged() (src/GalaxyEggbertCNA/GalaxyEggbertGameLoad.cpp) compares revisions and asks for the changes since its last build:

if (terrainRenderer_ && (worldRuntime_.GetWorld().blockRevision() != terrainRevision_ || ...))
{
    const auto& world = worldRuntime_.GetWorld();
    const auto changes = world.blockChangesSince(terrainRevision_);
    if (... && terrainRenderer_->PatchModelCells(world, changes, StillModelIcons(), ...))
    {
        terrainRevision_ = world.blockRevision();
        return;            // only the changed model cells were redrawn
    }
    ...                    // otherwise: full TerrainRenderer rebuild
}

Who uses it

Behaviour worth knowing

Tests

Related pages