← All Workshops
MudEngine Part 7: Save & Load
Step 5 / 10
Define Save Data Models
We need three layers of types:
- TOML types — mirror the structure of
game.toml, annotated with serde derives - Runtime types — the in-memory representation used by the game logic (
RoomData,GameState) - RoomInfo — sent to clients so they can render room names without hardcoded statics
Add these types at the top of src/main.rs, after the existing shared types (PlayerInfo, ClientMessage, ServerMessage):
mud-engine/src/main.rs
// ── Room info sent to clients ── #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] struct RoomInfo { id: usize, name: String, description: String, } // ── TOML save data models ── #[derive(Serialize, Deserialize)] struct TomlExit { direction: String, destination: usize, } #[derive(Serialize, Deserialize)] struct TomlRoom { id: usize, name: String, description: String, exits: Vec<TomlExit>, } #[derive(Serialize, Deserialize)] struct TomlPlayer { id: String, name: String, room: usize, } #[derive(Serialize, Deserialize)] struct TomlGame { rooms: Vec<TomlRoom>, players: Vec<TomlPlayer>, } // ── Runtime game state (server only) ── #[cfg(feature = "server")] struct RoomData { id: usize, name: String, description: String, exits: Vec<(String, usize)>, } #[cfg(feature = "server")] struct GameState { rooms: Vec<RoomData>, players: HashMap<String, PlayerInfo>, }
🔍 Why separate TOML and runtime types?
The TOML types (TomlRoom, TomlExit, etc.) are designed to mirror the exact structure of game.toml — serde maps them field-by-field. The runtime types (RoomData, GameState) are designed for efficient game logic:
TomlRoom.exitsusesVec<TomlExit>because TOML serialises arrays of inline tables cleanlyRoomData.exitsusesVec<(String, usize)>— a tuple is simpler to pattern-match in the movement validation code
The conversion between the two happens in load_game_state() and save_game_state().
RoomInfo lives outside the server-only module because it needs to be shared with the client through the ServerMessage::State payload. It only carries what the client needs (id, name, description — no exits).
Step 5 / 10