WorldRuntime
The world as it is being played: the voxel grid, the live object list, BigDecor, spawn point and the animation clock.
Location
| Header | src/GalaxyEggbert/Game/WorldRuntime.hpp |
|---|---|
| Sources | src/GalaxyEggbert/Game/WorldRuntime.cpp |
| Namespace | GalaxyEggbert::Game |
| Engine dependency | None. Plain C++ over the engine-independent world model; it is linked into command-line verifiers. |
Older pages called this class GEWorldRuntime; the GE prefixes were dropped when the game code moved to
src/GalaxyEggbert/Game/.
Purpose
WorldRuntime turns a world file into the state the game plays on. It owns a World (the
100 × 100 × 100 voxel grid) and derives from it everything that changes during play or that other
systems look up every tick: the list of moving objects (MobileObjSpec), the BigDecor scenery and its solid boxes, the
training-hint zones, the spawn point, the sky region and the mission number. It also keeps the world's animation clock, which
advances at the original game's 20 Hz reference rate, and offers a few pure helpers that encode the original's timing and
mission arithmetic.
Collaborators
Uses
- World and its records: MoveObjectRecord,
BigDecorRecord,HintZoneRecord,PlayerStart. - ObjectDefinitionRegistry to skip unsupported or null-placement object types.
LegacySawFloors.hpp(upgrades old saw cells on load),FanGeometry.hpp,SolidBox.hpp; the body constants of BlupiController for fan contact.
Used by
- GalaxyEggbertGame:
LoadMission, the title scene, editor play-tests, demo and resume validation. - InteractionSystem: moves, collects and spawns objects in the mutable object list.
- TerrainRenderer and the scene builder: animation phase, objects, BigDecor.
- WorldEditor through the host: edits the mutable
World, thenResyncFromWorld(). - Verifiers:
VerifyShippedWorlds,VerifyInteractionSystem,VerifyMoveObjectTypesCna.
Key members
A selection of the public API of WorldRuntime.hpp (verified 2026-11-10):
| Member | Signature | What it does |
|---|---|---|
kWorldCenterX, kWorldCenterZ | static constexpr int = 50 | Offset between raw grid cells and centred world coordinates (see below). |
LoadFromVwrFile | bool LoadFromVwrFile(const std::string& path) | Loads a .vwr world. On failure returns false. |
LoadFromVwrStream | bool LoadFromVwrStream(std::istream& in) | The same from bytes already in memory, so mission loading and resume/demo validation read one identical snapshot. Resets the animation clock, then calls ResyncFromWorld(). |
LoadFromMobileEggbertFile | bool LoadFromMobileEggbertFile(const std::string& path) | Reads an original 2D .txt world; kept as a reference path for verifiers, not used by the game. |
ResyncFromWorld | void ResyncFromWorld() | Re-derives sky region, mission number, spawn, hint zones, BigDecor cells and the object list from the current World, without disk I/O. Used after editor changes. |
Update | void Update(float dt) | Advances the 20 Hz animation tick and every object's phase. |
GetWorld, GetWorldMutable | const Worlds::World& GetWorld() constWorlds::World& GetWorldMutable() | The voxel grid; mutable access for tile reactions, the editor and tests. |
GetMobileObjects, GetMobileObjectsMutable | const std::vector<MobileObjSpec>& GetMobileObjects() const | The live objects (lifts, enemies, pickups, crates, effects). |
GetAnimPhase | int GetAnimPhase() const | The raw 20 Hz tick count; renderers divide it by each tile's own divisor. |
GetSpawnTileX/Y/Z, GetSpawnRenderX/Y/Z, GetSpawnYaw, HasExplicitSpawnPoint | int / float / bool getters | Spawn in raw cells and in centred coordinates; the yaw of the yellow player start. |
GetSkyRegion, GetMissionNumber, OverrideMissionNumber | int ...() const, void OverrideMissionNumber(int) noexcept | Header fields of the world; a galaxy world is played as the mission of its place in the galaxy. |
GetBigDecorCells, SolidBigDecorBoxes, SetBigDecorShapes | const std::vector<BigDecorSpec>& ..., std::vector<SolidBox> ... const | Sparse BigDecor scenery and, for the solid models, collision boxes for Blupi and crates (shapes measured by the host from the models). |
GetHintZones | const std::vector<HintZoneRecord>& GetHintZones() const | Training-hint zones in record order. |
TryActivateSwitch | std::optional<bool> TryActivateSwitch(float, float, float, bool blupiOnGround) | Toggles the switch under Blupi and every saw within X ±20 on the same row; returns the new state so the caller plays the sound. |
TryConsumeFan, LastConsumedFan | std::optional<std::uint16_t> TryConsumeFan(float, float, float) | Touching a fan's rotor removes the fan and its wind column; the caller applies death or immunity. |
FindTeleportDestination | bool FindTeleportDestination(std::uint16_t icon, float, float, float, float&, float&, float&) const | The other teleporter with the same icon (330-333); Blupi lands one cell below it. |
IsBlitzActiveAtPhase, IsCrusherActiveAtPhase, IsTempPassableAtPhase | static bool ...(int animPhase) noexcept | The original's hazard cycles as pure functions of the phase. |
ComputeWorldSelectTarget, ComputeMissionBack, ComputeWinExitTarget | static int ...(int currentMission, ...) noexcept | Mission arithmetic of signs, Back and the exit (see below). |
MobileObjSpec
One moving or interactive object, in plain floats. The fields that matter most:
| Field | Meaning |
|---|---|
type, visualIcon | Def::ObjectType; an optional tile override (0 keeps the type's own icon). |
posStartX/Y/Z, posEndX/Y/Z | The path's two ends (centred X/Z; Y is the centre of the occupied cell, so an object on a floor at Y=0 has Y=1). |
currentX/Y/Z, active | Live position (what is drawn) and whether the object still exists (false once collected). |
phase | Per-object animation tick at 20 Hz, read by GetObjIcon. |
stepAdvanceTicks, stepRecedeTicks, timeStopStartTicks, timeStopEndTicks, patrolStep, patrolTime | The original's patrol state machine in 20 Hz ticks: dwell at start, advance, dwell at end, recede. Lifts follow it too; speed no longer moves anything. |
firedByBlupi | A glue ball Blupi fired himself never hits him. |
Coordinates and the world centre
Files, editor and tools use raw grid cells 0-99. The simulation and the renderer use centred
coordinates: X and Z minus kWorldCenterX/kWorldCenterZ (50), Y unchanged, so the world sits around the
origin. ResyncFromWorld() applies the shift when it builds MobileObjSpecs and BigDecor cells, and the spawn
is offered both ways (GetSpawnTileX raw, GetSpawnRenderX centred). Blupi's position in
BlupiController is centred too; crate cells and solid boxes handed to it are raw.
Animation phase
Update(dt) accumulates time and advances animPhase_ once per 1/20 s, the original's reference tick;
each object's phase advances by dt × 20. Animated tiles divide this tick by their own divisor (from
BlockDefinitionRegistry) before choosing a frame. The hazard helpers read the same tick:
bool WorldRuntime::IsBlitzActiveAtPhase(int animPhase) noexcept
{
const int cycle = ((animPhase % 100) + 100) % 100; // defensive: handle a negative phase
return cycle % 2 == 0 && cycle < 50;
}
Lightning is lethal on even ticks of the first half of a 100-tick cycle; a crusher when (phase/3)%10 <= 2; a vanishing
(Temp) tile is passable when (phase/4)%20 >= 18. The host passes the Temp result to BlupiController::Step as a
plain bool.
How it is used
The host loads each mission from bytes it has already read, then re-applies the galaxy mission number when needed:
std::istringstream world(bytes ? *bytes : std::string{}, std::ios::in | std::ios::binary);
if (!bytes || !worldRuntime_.LoadFromVwrStream(world))
{
...
return;
}
loadedMissionPath_ = path;
loadedMissionHash_ = ResumeLog::HashBytes(*bytes);
if (galaxyGamer_ >= 0) worldRuntime_.OverrideMissionNumber(missionNumber); // its place in the galaxy
Every Play tick starts with worldRuntime_.Update(simDt); InteractionSystem::Update then works on
GetMobileObjectsMutable().
Mission arithmetic: from the main hub (mission 1) sign N leads to world N×10 (sign 13 to the showcase, world 999, except in
a player's galaxy); inside a world hub sign N leads to mission hub+N and sign 199 back to the main hub.
ComputeMissionBack returns to the mission's hub, or from a hub to the main hub. ComputeWinExitTarget(1) is 199
(the bonus world) and ComputeWinExitTarget(199) is 1.
Rules and invariants
- Engine-independent: no CNA or cna-engine include, so the verifiers can load worlds without a window.
- Object timing is the original's: the loader forces the big creature (type 54) to rest 152 ticks at each end, whatever the file says.
ResyncFromWorld()deliberately leaves the animation clock alone;LoadFromVwrStream()resets it, so a newly loaded world starts at phase 0.- Old worlds with implicit saw floors are upgraded in memory on load (
UpgradeLegacySawFloors).
Tests
VerifyShippedWorlds: everyworlds3d/*.vwrloads throughLoadFromVwrFile, carries the mission number of its file name, yields its objects, and survives load, save, load unchanged.VerifyInteractionSystem: loadsworld999and checks, among much else, the Blitz, crusher and Temp cycles and patrol timing.VerifyMoveObjectTypesCna:LoadFromMobileEggbertFileon original world files (needs the sibling reference checkout).