Save Data & Resume

Settings and three players' progress in savedata.txt, an interrupted mission in resume.txt, and the player's worlds and recordings beside them (as of 2026-11-10).

The player's folder

Since 2026-11-10 every file the player creates lives in one folder, chosen by the host at start (ChooseUserFolder() in src/GalaxyEggbertCNA/main.cpp) and handed to src/GalaxyEggbert/Game/UserFolder.hpp, which the save, resume, demo and editor code ask for paths.

Where the game runsFolder
Linux desktop$XDG_DATA_HOME/Galaxy Eggbert, else ~/.local/share/Galaxy Eggbert (CNA's StorageDevice root)
Windows desktop%LOCALAPPDATA%\Galaxy Eggbert (implemented; the Windows build is not verified)
Any desktop, chosen--user DIR on the command line, or the GALAXY_USER_DIR environment variable (the test scripts point it at their run folder)
Web/save, stored in the browser's IndexedDB
Androidthe app's internal storage, which is also its working folder

If no per-user folder can be found or created, the game says so on the console and keeps the files in the working folder. On the first start with an empty user folder, a savedata.txt, resume.txt, demos/ and customworlds/ left in the working folder by an earlier build are copied over (CopyOldUserFiles()); nothing is moved or overwritten.

<player's folder>/
├── savedata.txt                 settings and progress (SaveData)
├── resume.txt                   an interrupted mission (ResumeLog), only while there is one
├── demos/
│   ├── demo001.gdemo ...        the player's recordings for the ten demo positions
│   └── shared/                  exported recordings
└── customworlds/
    ├── gamer0/ gamer1/ gamer2/  each player's editor worlds
    │   ├── custom_001.vwr ... custom_010.vwr (+ .png thumbnails)
    │   ├── backups/
    │   └── galaxy/              the player's own galaxy (worldNNN.vwr, name.txt, backups/)
    ├── shared/                  exported worlds and .galaxy packs
    └── campaign-backups/, campaign-edits/, campaign-originals/   shipped worlds edited in play

savedata.txt

SaveData (src/GalaxyEggbert/Game/SaveData.hpp, .cpp) is engine-independent. The file is plain key=value lines, read once when the game is constructed; a missing file or an unknown key leaves the defaults. It is deliberately not the original's 640-byte binary GameData block, but it keeps the same contents: global settings plus three players. It is written when a setting changes, when a player is selected, and at the original's checkpoints (a mission lost or its exit reached), never during a resume replay or a demo. What SaveData::Write() produces:

soundEnabled=1
jumpRight=1
autoZoom=1
accelActive=0
effectsVolume=100
musicVolume=100
accelSensitivity=50
fullscreen=0
terrainRelief=0
effectsLevel=0
frameRate=60
textureScale=0
selectedGamer=0
gamer0.lives=3
gamer0.missionNumber=0
gamer0.lastWorld=1
gamer0.hasProgress=0
gamer0.doorsUnlocked=0000000000...   (200 characters, one per mission number)
gamer1.lives=3
...
gamer2.doorsUnlocked=0000000000...

Settings

KeyValues (default)Meaning
soundEnabled0/1 (1)sound on or off
jumpRight0/1 (1)the on-screen pad's Jump on the right
autoZoom0/1 (1)the original's automatic zoom while walking
accelActive, accelSensitivity0/1 (0); 0-100 (50)accelerometer steering
effectsVolume, musicVolume0-100 (100)Galaxy's two volume sliders
fullscreen0/1 (0)full screen (desktop); the first run is windowed
terrainRelief0/1 (0)the Setup's "3D terrain"
effectsLevel0-4 (0)3D effects Off, Low, Medium, High, Ultra (an old effects3d=1 reads as High)
frameRate60, 120, 144, 240 (60)frames drawn per second (Game Loop)
textureScale0 auto, 1, 2 (0)1x or 2x sprite sheets, at the next start
selectedGamer0-2 (0)the player selected in the menu

Environment variables can override some of these for one run; see Configuration.

Per-player progress

There are three players (SaveData::kGamerCount = 3), shown as A, B and C in the menu. Each has a GamerSlot:

FieldMeaning
liveslives at the last checkpoint (3 for a new player)
missionNumberthe mission of the last checkpoint, where Continue starts when there is no resume log
lastWorldthe world last played; the main hub places Blupi beside its sign
hasProgresswhether there is a checkpoint at all
doorsUnlocked200 flags indexed by mission number, as the original's door array: opened mission bars (0-179, the menu's "secondary gates") and the main hub's gold bars (180-199, "main gates"); HubDoors reads them

Each player's own galaxy has a second slot with the same fields, saved as galaxy0.lives= ... and written only once that player has galaxy progress, so a file from before galaxies existed stays as it was. While a galaxy is played, the progress accessors read and write that slot; the mode itself is not saved.

Mission resume: resume.txt

An interrupted mission continues from the exact moment it stopped. The original saved the moment's state; Galaxy saves the mission's start plus every tick's input and replays it (ResumeLog, src/GalaxyEggbert/Game/ResumeLog.hpp; host code in src/GalaxyEggbertCNA/GalaxyEggbertGameDemo.cpp). This works because the simulation is deterministic (Game Loop).

  1. Mission start. When a mission begins in Play, StartResumeLog() records the start: the build identity, the world's path and the FNV-1a hash of its exact bytes, mission number, lives, game speed, the random seed, Blupi's position and heading, the cheat state (quick, opendoors, showsecret, compass, debug, the fairplay/honest lock), the camera mode, and the whole savedata.txt text as it was.
  2. Every tick. The tick's input record (Input) is appended; identical consecutive records are stored once with a count.
  3. Losing focus. When the window or app is deactivated during Play, the log is written to resume.txt.tmp and renamed to resume.txt.
  4. Deleted on a clean exit, when the mission's exit is reached, and when the file is refused. Demos never write or delete it; editor play-tests do not record one.
  5. Next start. After the loading screen the game parses resume.txt. If it is valid, or if the player has a checkpoint, the Resume screen asks Continue or menu.
  6. Continue. BeginResume() reads the world file again and checks its path and hash, restores the recorded settings, cheats and seed, loads the mission, places Blupi, and ReplayBatch() replays up to 600 ticks per update with drawing off and sound muted until the recorded moment is reached. A mission of the player's galaxy continues inside that galaxy.
  7. Fallback. If the file is missing, damaged, of another format version or another build, or the world changed, the game starts the checkpoint mission instead, with the saved lives.

Format version 7

Text, classic locale, floats written with enough digits to read back exactly. Field by field, as Serialize() and WriteBody() write it:

GALAXY_RESUME 7
"<build identity>"
"<world path>" <world hash>
<mission> <lives> <speed> <seed> <x> <y> <z> <yaw> <quick> <openDoors> <showSecret> <compass> <cheatsLocked> <debug> <cameraMode>
"<savedata.txt at the start>"
<run count> <tick count>
<count> <key count> <keys...> <mouseX> <mouseY> <wheel> <buttons> <viewportW> <viewportH> <touch count> <id x y state>... <touchControls> <accelValid> <accelReset> <accelY> <cheatLetter>
...                                    (one line per run)
END <FNV-1a 64 of everything above>
Checking replay equality. GALAXY_RESUME_SELFTEST=N makes the game, after N recorded ticks, rebuild the mission from its own log and compare Blupi, counters, objects and world state with the live game, printing RESUME SELFTEST equal or the parts that differ. The autoplay checks use it.

Galaxies

Each player's galaxy is a set of world files in customworlds/gamerN/galaxy/ (world001.vwr for its main hub, world010.vwr ... for world hubs, their missions, and world199.vwr), with name.txt and a backups/ folder for deleted places. Its progress is the galaxyN.* slot in savedata.txt. Importing another galaxy resets that progress. An export is a single .galaxy pack in customworlds/shared/ (a download on the web). See Your Own Galaxy.

Demos and recordings

See Demos & Recordings and DemoReplay.

Custom worlds

CustomWorldStorage gives each player ten slots, customworlds/gamerN/custom_001.vwr to custom_010.vwr, each with a .png thumbnail. The first save after opening a world keeps up to three earlier versions in backups/ (custom_003.1.vwr the newest), and a deleted slot goes there too. Other .vwr files found in the folder are listed and never deleted.

A shipped world edited in play with the xnjttjpo cheat is handled per platform: the desktop rewrites the file in worlds3d/ and keeps earlier versions in customworlds/campaign-backups/ and the shipped one in customworlds/campaign-originals/; the web keeps the edit in /save/customworlds/campaign-edits/ and lays it over the packed worlds at every start. Pause's Original button restores the shipped world. See 3D World Editor.

Web and Android

Tests

Related: SaveData, ResumeLog, Configuration.