← All Workshops
MudEngine Part 7: Save & Load
Step 10 / 10
Congratulations!
You just added persistent game state to the MUD engine!
What we achieved:
- Data-driven world — the full 9-room grid is defined in
game.toml, editable without recompiling - Server-side persistence — player positions are saved to disk on every join, move, and leave
- Client-server synchronisation — room data is sent from the server to the client in the initial
Statemessage, eliminating the hardcoded statics - Save/load architecture —
load_game_state()at startup,save_game_state()after every mutation,can_move()for movement validation from loaded data - Cleanup — the old
ROOM_NAMES,ROOM_DESCS, andEXITSstatics are gone; the game is fully data-driven
Architecture recap
game.toml ──read──▶ LazyLock ──▶ GameState { rooms, players }
│
┌────────────┼────────────┐
▼ ▼ ▼
Player join Player move Player leave
│ │ │
└────────────┼────────────┘
▼
save_game_state()
│
▼
game.toml (updated)
What's next?
The dungeon keeps growing! Future parts could explore:
- SQLite database — replace
game.tomlwithsqlx+ SQLite for concurrent read/write access - Room state — locked doors, dark rooms that need a torch, writable signs
- Inventory — items the player can pick up, carry between rooms, and drop
- Chat — add a chat panel where players can send messages to each other
- Monsters & combat — NPCs roaming the world, attack commands, health bars
- Editor UI — an admin panel to edit room data from the browser
The MUD persists! 🏰💾
📚 What we learned
| Concept | How we used it |
|---|---|
serde + toml | Deserialize game.toml into TomlGame, serialize GameState back |
LazyLock<Mutex<T>> | Thread-safe, lazily-initialised global game state |
load_game_state() | Reads TOML, converts to runtime types, panics on missing file |
save_game_state() | Converts runtime state back to TOML types, writes to disk |
RoomInfo | Shared type sent from server to client in initial State message |
| Data-driven design | World definition lives in a data file, not in source code |
| Persistence on mutation | Every player join/move/leave triggers an immediate disk write |
can_move() | Movement validation using room-ID-based lookup instead of index-based slices |
Step 10 / 10