Startup Sequence

From main() to the main menu, step by step, as of 2026-11-10.

The files involved are src/GalaxyEggbertCNA/main.cpp (entry point and flags), GalaxyEggbertGame.cpp (constructor), GalaxyEggbertGameLoad.cpp (LoadContent()), GalaxyEggbertGameUpdate.cpp (the first updates) and GalaxyEggbertGameMissions.cpp (title scene, missions). The host class is GalaxyEggbertGame, a Microsoft::Xna::Framework::Game from CNA.

1. main()

main() only calls RunGame() inside a try. An escaping exception is printed (GalaxyEggbertCNA: fatal exception: ...) and rethrown, because in the browser it would otherwise arrive as a bare pointer with no text. On Android CNA's Entrypoint.hpp renames main() so the Java side can start it.

RunGame() first does the platform-specific preparation:

2. The player's folder: ChooseUserFolder()

On desktop builds the folder for savedata.txt, resume.txt, demos/ and customworlds/ is chosen before the game object exists:

  1. --user DIR on the command line, else
  2. the environment variable GALAXY_USER_DIR (the test scripts use their run folder), else
  3. CNA's StorageDevice root for the application name "Galaxy Eggbert" (~/.local/share/Galaxy Eggbert or $XDG_DATA_HOME on Linux, %LOCALAPPDATA%\Galaxy Eggbert on Windows).

In the default case the files an earlier build kept in the working folder are copied over once (Game::CopyOldUserFiles(), only if the new folder has no savedata.txt; nothing is moved or overwritten). Game::SetUserFolder() records the choice (UserFolder.hpp). If no folder can be created the game keeps the working folder. The web build keeps /save and Android its private storage; this step is skipped there.

3. Constructing GalaxyEggbertGame

The constructor (GalaxyEggbertGame.cpp):

Members such as Sound, Hud, InputPad, WorldRuntime, InteractionSystem and WorldEditor are plain value members, constructed with the game.

4. Command-line flags

RunGame() then scans argv and switches modes on the game object. All flags as of 2026-11-10:

FlagEffect
--user DIRThe player's folder (step 2).
--mission NSkip the menus and start mission N in Play (EnableStartMission).
--spawn x,y,z[,yawDeg]With --mission: place Blupi at that raw-grid position and yaw.
--galaxyWith --mission: play the selected player's own galaxy, with its progress.
--autoplay SCRIPTPlay the mission by an autoplay script (Autoplay); the process exits with 2 if the script cannot be loaded, otherwise with the autoplay result.
--record-demo FILE, --demo-ticks N, --demo-title TEXTRecord a main-menu demo (used by tools/record_demo.sh).
--verify-demo FILEReplay a demo and compare its end (tools/verify_demos.sh).
--golden-captureDeterministic screenshots of world 999 for tests/golden/.
--golden-capture-traceDeterministic movement trace for tests/golden/golden_trace.txt.

See Running the Game and Configuration for the environment variables.

5. Run() and LoadContent()

game->Run() enters CNA's loop. As in XNA, CNA's Game::DoInitialize() creates the graphics device, then calls Initialize(), which calls LoadContent(). GalaxyEggbertGame does not override Initialize(); everything happens in LoadContent() (GalaxyEggbertGameLoad.cpp), synchronously, in this order:

  1. A first world. worldRuntime_.LoadFromVwrFile("worlds3d/world001.vwr"), the main hub. If it is missing the function prints a hint ("run the binary from its own build directory") and returns: the game needs its data next to the executable.
  2. Texture scale. 1x or 2x for this run, decided once: the Setup's "Textures" setting, GALAXY_TEXTURES, or Auto (2x with Ultra effects on a display at least 1000 px tall). Web and Android always use 1x.
  3. The terrain sheet. Content/icons/object-m.png (or icons2x/): tile coverage is classified from its alpha (TileCoverage.hpp), brick edges and clear texels of opaque tiles are filled, and a padded, mipmapped copy is built for the TileAtlas. Average tile colours and water tints for the 3D effects are taken from it.
  4. The world's presentation. RebuildWorldPresentation(): background picture, TerrainRenderer meshes, block models (see World Loading). Then the terrain and grass effects (textures3d/grass_top.png).
  5. 2D layers. hud_.LoadContent() and inputPad_.LoadContent() load their own sheets (text.png, pad.png, menu backgrounds).
  6. Object sheets for billboards: element.png, explo.png, blupi.png, blupi1.png.
  7. 3D models. Blupi from avatars3d/blupi/avatar.skinnedmodel.json with its clips.txt and face textures, or the fox placeholder in avatars3d/blupi_placeholder/ if the real model is absent (without any model the camera stays first-person). Then the object model library: avatars3d/objects/index.txt, and per model its icons.txt (into the ObjectModelTable), materials.txt, measured BigDecor shapes, spark textures and sign decals.
  8. Blupi's start. PlaceBlupi() at the world's spawn cell, or (0, 1, 0).
  9. Sound. sound_.LoadContent() loads whichever of Content/sounds/sound000.wav to sound092.wav exist (Sound); sound on/off, effects volume and the jump-button side are restored from SaveData.

The WorldEditor has no loading step; it builds what it needs when it is opened.

6. The first frames: Wait, title scene, menu

The game starts in the Wait phase (GamePhase, include/GalaxyEggbert/Def/GamePhase.hpp). Each Update() runs a fixed 1/60 s step:

7. The --mission shortcut

With --mission N the menus never appear. On the first Update() (GalaxyEggbertGameUpdate.cpp):

if (startMission_ != 0)
{
    SetPhase(GalaxyEggbert::Def::GamePhase::Play, /*bypassFade=*/true);
    if (startGalaxy_) { galaxyGamer_ = saveData_.GetSelectedGamer(); saveData_.SetGalaxyMode(true); ... }
    LoadMission(startMission_);
    startMission_ = 0;
    if (startSpawnSet_)
    {
        PlaceBlupi(startSpawnX_ - WorldRuntime::kWorldCenterX, startSpawnY_,
                   startSpawnZ_ - WorldRuntime::kWorldCenterZ);
        blupi_.SetYaw(startYawDegrees_ * 3.14159265f / 180.0f);
        ...
    }
}

The golden-capture modes do the same with the fixed showcase world, LoadMission(999). Once in Play with the mission loaded, StartResumeLog() records the mission's start (build, world path and hash, seed, Blupi's position, settings) and input recording begins; an armed demo recording starts at the same moment.

Related pages