Back to Devlog
    v0.9.15
    EngineMay 20, 2026Release notes

    One Path For Single Player, Tests, And Matches

    The map command now spawns a real dedicated server, lobby dev-spawn is restricted to loopback, and a full manual pass documented from the code.

    map Stopped Faking It

    text
    map <name> [gametype]

    Now spawns a dedicated game server through the lobby and connects to it with autoJoin: true. Defaults to duel. Aliases: 1v1→duel, dm/deathmatch→ffa, team/teamdeathmatch→tdm. map reload restarts the pair, map unload disconnects and tears down, map current reports both. Marked developer-only.

    The manual local spawn branches in FPSController.attach() and JoinCommand were removed, so there is one gameplay path.

    Read the changelog's own summary of that decision:

    text
    single gameplay path shared by single-player, headless tests, and networked play

    Why Not The Easier Option

    The architecture note says the choice was lobby dev-spawn over an in-process ListenServerHost, specifically to exercise real WebSocket and BinaryProtocol end to end. The more convenient implementation was rejected because it would not have tested the real thing.

    Dev Spawn Is Loopback Only

    LobbyServer accepts dev:spawn_server only from loopback addresses and rejects cross-LAN requests. It tracks matchId → playerId and replies dev:server_spawned or failed. GameServerSpawner supports a public address override via SHAG_PUBLIC_GAME_PROTOCOL and SHAG_PUBLIC_GAME_HOST.

    A developer command that binds a game server on your machine is exactly the kind of thing that must be refused from the network, and it is.

    The Manual

    The FPS manual at src/games/fps/docs/manual/, written from the code with concrete numbers — movement.md from MovementProfile.ts, weapons.md covering 9 weapons with damage, fire rate, ammo and splash read out of shared/entities/definitions. Plus pickups-and-inventory.md and hud.md, and engine guides for the pickup system, map launching and service registries.

    BinaryProtocol narrowing: 10 TS18048 false positives fixed with (flags & FLAG) && value guards. tsc --noEmit clean. Tests 1027 → 1041.

    Known Issues: none stated.