WorldEditor

One session of the in-game 3D world editor: browse a player's worlds, fly, place, undo, save and play-test.

Location

Headersrc/GalaxyEggbert/Editor/WorldEditor.hpp
Sourcessrc/GalaxyEggbert/Editor/WorldEditor.cpp (browser, session, drawing), src/GalaxyEggbert/Editor/WorldEditorUpdate.cpp (per-frame input, camera, aiming, placement, history)
NamespaceGalaxyEggbert::Editor
Engine dependencyUses CNA (XNA KeyboardState, MouseState, GraphicsDevice) and cna-engine (Camera, DebugDraw). It does not own a WorldRuntime: the host loads or creates the world and passes the World in every frame.

Purpose

WorldEditor is the in-game 3D world editor. One object lives inside the game host for the whole run and switches between two modes. While browsing (IsBrowsing()) it drives the world screen of the selected player (ten slots, older and shared worlds) or the galaxy screen (the player's own campaign). While editing it flies a free camera over the loaded world, aims a ray through the cursor, places and removes blocks, objects, BigDecor and Blupi starts from the palette, edits objects' routes and timing, keeps an undo history, copies and pastes boxes, and saves and play-tests the world.

The editor is the project's one approved exception to the faithful-remake rule: it may add content-authoring conveniences (a 3D camera, copy and paste, backups, thumbnails, sharing) but no gameplay mechanics. What it can place and how it validates follows the same registries the game uses (BlockDefinitionRegistry, ObjectDefinitionRegistry). It was called GEWorldEditor until the editor moved into the GalaxyEggbert::Editor namespace and lost its GE prefixes; the verifiers keep the old names (VerifyGEWorldEditor and so on).

Collaborators

The editor is split into small parts under src/GalaxyEggbert/Editor/; WorldEditor composes them.

PartHeaderRole
EditCommandStack, EditCommandEditCommandStack.hppUndo/redo. One tagged EditCommand per user action (BlockEdit, MoveObjectEdit, SkyRegionEdit, SpawnPointEdit, MusicEdit, BigDecorEdit, TurnEdit, MetadataEdit, Group); the last 200 are kept.
Clipboard, CopyBox, TurnedQuarter, MirroredX, PasteBoxClipboard.hppCopy a box with its blocks, turns, objects and BigDecor; turn it a quarter or mirror it on X; stamp it back as one Group command. Hint zones and the spawn point are not carried.
BoxRegion, NormalizeAndClampBoxRegion.hppAn inclusive cuboid from two corner cells, clamped to the world: box fill, copy and Shift-extended selections.
EditorPalette, EditorPaletteLayout, EditorPaletteInput, EditorPaletteRendererEditorPalette*.hppWhat is selected (block, object, Blupi start or BigDecor), the on-screen actions (Stop, play-test, X/Y/Z offsets, PLACE, delete), layout rectangles, hit-testing and drawing.
PaletteCategoriesPaletteCategories.hppTen groups in Eggbert 2's menu order (Scenery, Technical blocks, Rock and terrain, Buildings, Hazards, Moving mechanisms, Treasures, Keys and progression, Vehicles, Characters and goals) plus Galaxy's Background group (32 sky regions, then music: none and tracks 1-10).
RaycastVoxelRaycast.hppAmanatides-Woo voxel DDA in raw grid space to the first non-air cell. On an empty world the aim falls on y = 0.
AutoTile (namespace)AutoTile.hppThe original editor's auto-tiling (Decor::AdaptBorder) in 3D: a placed or emptied cell and its six neighbours are re-tiled (rock, girders, grass, bars, brick, slime, palace, pipes).
VariantFamilies, BigDecorVariantFamilies, VariantCyclerEditorVariants.hppThe original's variant families: a click on the block the previous click placed cycles it; Ctrl places without cycling.
EditorDeviceControlsEditorDeviceControls.hppKeyboard-free front end (touch, gamepad, a Tools menu). It turns those devices into the same keys, mouse and EditorNavigation the editor reads. Owned by the host.
EditorCommandKeysEditorCommandKeys.hppQueues short V, O, Delete and Backspace presses between ticks so each one is a separate edit. Owned by the host.
EditorHighlightRenderer, ObjectPathRendererEditorHighlightRenderer.hpp, ObjectPathRenderer.hppThe translucent cell, box and selection overlays; the numbered 1 and 2 cubes at a moving object's route ends (ObjectPathMarkers.hpp).
EditorBrowserScreen, GalaxyBrowserScreenEditorBrowserScreen.hpp, GalaxyBrowserScreen.hppThe world screen (slots, older and shared worlds, Backups, Export, Import, Galaxy) and the galaxy screen (main hub, bonus world, 14 worlds with 8 missions each, naming, export, import, delete).
Storage functionsCustomWorldStorage.hppSlot paths, backups, thumbnails, seeding, the galaxy's files: see CustomWorldStorage.

Uses also: World and MoveObjectRecord (the data it edits), GetObjectDefinition (exit and motion capabilities), WorldRuntime::kWorldCenterX/Z (raw grid to render space).

Used by: GalaxyEggbertGame (member worldEditor_) and the editor verifiers in tools/.

Key members

A selection of the public API of WorldEditor.hpp, as of 2026-11-10. XNA and cna-engine namespaces are left out of the signatures for space.

MemberSignatureWhat it does
EnterBrowservoid EnterBrowser(int gamerSlot)Starts browsing for player 0-2: seeds slot 1 from the showcase world and a free slot from the gallery world, rescans both screens.
ShowGalaxy, ShowSlotsvoid ShowGalaxy(), void ShowSlots() noexceptSwitch the browser between the galaxy screen and the slots.
IsBrowsingbool IsBrowsing() const noexceptBrowsing (no world loaded) versus editing.
UpdateBrowsingBrowserRequest UpdateBrowsing(const MouseState& mouse, int viewportWidth, int viewportHeight, bool backPressed = false)Drives the active screen. Returns a BrowserRequest: shouldOpen/openPath, shouldCreateNew/createPath, galaxyMission, galaxyImported, shouldReturnToMenu. The host does the loading.
ExitBrowser, EnterEditingvoid ExitBrowser() noexcept, void EnterEditing(float startX, float startY, float startZ) noexceptLeave browsing; reset the camera (render space) and the session state, including the undo history.
SetWorldPath, GetWorldPathvoid SetWorldPath(std::filesystem::path path) noexcept, const std::filesystem::path& GetWorldPath() const noexceptThe file that Enter saves and the dice play-tests.
Updatevoid Update(const KeyboardState& keyboard, const MouseState& mouse, float dt, int viewportWidth, int viewportHeight, CnaEngine::Graphics::Camera& camera, Worlds::World& world, const Navigation& navigation = {})One editing frame: camera, palette, aim, then the first handler that takes the input (extended selection, clipboard, placement, removal, save/undo/stop, box fill, background, music, turn, variant, object editing).
ConsumeNeedsPresentationRebuildbool ConsumeNeedsPresentationRebuild() noexceptTrue once after an edit changed the world; the host rebuilds the presentation.
ConsumePlayTestRequestedbool ConsumePlayTestRequested() noexceptTrue once after the dice saved the world, but only after the save's thumbnail was taken.
ConsumeThumbnailRequeststd::filesystem::path ConsumeThumbnailRequest() noexceptThe PNG the host writes the editor's view to after drawing this frame; empty when none.
BeginOutsideSession, EndOutsideSessionvoid BeginOutsideSession(std::filesystem::path backupDir, std::filesystem::path keepCopyIn = {}), void EndOutsideSession() noexceptA session on a world opened from play (the xnjttjpo cheat): backups go to backupDir, each save is also copied into keepCopyIn, no thumbnail.
ConsumeLeaveRequestedbool ConsumeLeaveRequested() noexceptStop in an outside session: the host returns to the mission.
CurrentEditTargetstd::optional<EditTarget> CurrentEditTarget(const Worlds::World& world) constWhat Turn, Delete and the red selection tint act on: a block, object, BigDecor or Blupi start (with its colour) at a cell.
CurrentClipboard, IsPastingconst Clipboard* CurrentClipboard() const noexcept, bool IsPasting() const noexceptThe copy made with C (kept across worlds of one run) and whether pasting is on.
DrawWorldOverlays, Drawvoid DrawWorldOverlays(GraphicsDevice&, const Camera&, const Worlds::World&), void Draw(GraphicsDevice&, const Camera&, int viewportWidth, int viewportHeight, const Worlds::World&)Depth-tested overlays drawn with the world (route cubes, aimed cell or box, selection); then the status lines, palette and axis names over the finished frame.
LiftPreset (free function)std::optional<LiftTiming> LiftPreset(Def::ObjectType type, int buttonIcon) noexceptA lift's advance, recede and rest ticks (20 Hz) by its palette entry, from the PC editor: slow 20/20/20, normal 10/10/10, fast 6/6/3, fast/slow 5/22/2.

How it is used

GalaxyEggbertGame enters the Editor game phase in three ways:

Each tick in the Editor phase the host either drives the browser and acts on its request, or runs an editing frame and acts on the editor's one-shot signals (from src/GalaxyEggbertCNA/GalaxyEggbertGameUpdate.cpp, shortened):

if (worldEditor_.IsBrowsing())
{
    const auto request = worldEditor_.UpdateBrowsing(
        mouse, viewport.getWidthProperty(), viewport.getHeightProperty(),
        phaseKeys.IsKeyDown(Keys::Escape));
    ...
    else if (request.shouldOpen)
    {
        LoadCustomWorldForEditing(request.openPath);
    }
    ...
}
else
{
    worldEditor_.Update(phaseKeys, mouse, dt,
                         viewport.getWidthProperty(), viewport.getHeightProperty(), camera_,
                         worldRuntime_.GetWorldMutable(), editorNavigation);
    ...
    if (worldEditor_.ConsumeNeedsPresentationRebuild())
    {
        RebuildWorldPresentation();
    }
    InteractionSystem::AdvanceEditorPlatforms(worldRuntime_, dt);
    if (worldEditor_.ConsumePlayTestRequested())
    {
        LoadCustomWorldForPlayTest(worldEditor_.GetWorldPath());
    }
    else if (worldEditor_.ConsumeLeaveRequested() && editorMission_ != 0)
    {
        LeaveMissionEditor();
    }
}

A new world is created by the host (CreateEditorStarterWorld(), or CreateGalaxyStarterWorld(mission) for a galaxy place), saved, then opened like any other. While editing, the world clock still runs, so lifts preview their patrol. A play-test loads the saved file with a fresh InteractionSystem and BlupiController; Pause's Menu or Back, or the return button on the Win/Lost screen, reopens the same world in the editor. Before an editing frame the keyboard, mouse, touches and gamepad pass through EditorDeviceControls and EditorCommandKeys.

Controls

DeviceBindings (from WorldEditorUpdate.cpp and EditorDeviceControls.cpp)
Keyboard and mouseW/A/S/D fly, Ctrl up, Z down (Shift alone also lowers); right button looks, wheel zooms. Left click or Space places at the preview; middle click or Backspace removes. NumPad 4/6, 8/2 and 7/9 move the preview on X, Z and Y, NumPad 5 resets it; Shift with them extends a 3D region that Place fills. Enter saves, U undo, R redo, F box fill (Escape cancels), C copy, P paste, Q turn the copy, X mirror it, Ctrl with a click places without cycling. Left/Right arrows step the background, M the music, O turns, V cycles the variant, H shows the keys. G, T, Tab, + and - pick an object, set its route end and adjust its ticks; Delete removes it. F10 or the Stop sign stops.
GamepadLeft stick flies, right stick looks, RT/LT change height, A places, X removes, B cancels, D-pad and shoulder buttons move the preview, Y switches to a menu cursor, Start saves, Back stops.
TouchOn-screen Move and Up/Down controls and a Tools menu (Save, Undo, Redo, Select 3D, Remove, Turn, Variant, Copy, Paste, Box fill, Music, Help, Stop and the object commands); dragging over the world turns the view, a tap aims and places.
Verification status As of 2026-11-10 the keyboard and mouse, an SDL virtual gamepad and synthetic touches were checked live under Xvfb. A physical gamepad and a real touch screen have not been tested.

Rules and invariants

Tests

Five verifiers drive the real editor without a window. They share one object library (GEEditorVerifySupport in CMakeLists.txt), are registered by ge_add_editor_verify and run in the build directory's verify-run/, because they write customworlds/ relative to their working directory.

TestCovers
VerifyGEWorldEditorPlacement, auto-tiling, variant cycling, turning, lift ends, copy/turn/mirror/paste, music, a mixed undo/redo history, outside (xnjttjpo) sessions, cursor aiming, the single-exit rule.
VerifyGEEditorDevicesEditorDeviceControls: gamepad and touch input mapped to navigation and keys.
VerifyGEEditorPaletteCategories in source order, layout, hit-testing, placeable blocks and objects, BigDecor mode.
VerifyGEEditorStorageSlots, seeding, backups, export and import, the browser screens, the galaxy (see CustomWorldStorage).
VerifyGEEditorObjectsObject placement, removal and timing edits.

For a look at the real thing, tools/qa_live.sh runs the step files in tools/qa_steps/editor_*.txt (play-test, copy and paste, lifts, backups, thumbnails, auto-tiling, cursor aiming). See Testing.

Related pages