MudEngine Part 9: The Twin Guardians
Update load_game_state and save_game_state
Both functions need to handle the new quest config. The quest config is loaded once from TOML and never changes during the session — it's read-only at runtime. We only need to serialize the standard game data back.
The vault room (id 9) gets loaded into the rooms list like any other room. Its empty exits list is intentional — movement validation will never match it through can_move, so the only way in is through the dynamic quest exit.
fn load_game_state(path: &str) -> GameState { let content = std::fs::read_to_string(path) .unwrap_or_else(|e| panic!("Failed to read {}: {}", path, e)); let toml_game: TomlGame = toml::from_str(&content) .unwrap_or_else(|e| panic!("Failed to parse {}: {}", path, e)); let rooms: Vec<RoomData> = toml_game .rooms .iter() .map(|r| RoomData { id: r.id, name: r.name.clone(), description: r.description.clone(), exits: r .exits .iter() .map(|e| (e.direction.clone(), e.destination)) .collect(), items: r.items.clone(), }) .collect(); let players: HashMap<String, PlayerInfo> = toml_game .players .iter() .map(|p| { let pi = PlayerInfo { id: p.id.clone(), name: p.name.clone(), room: p.room, items: p.items.clone(), }; (p.id.clone(), pi) }) .collect(); let quest = toml_game.quest.map(|config| QuestStatus { config, previously_active: false, completed: false, }); GameState { rooms, players, quest } }
pub fn save_game_state(state: &GameState) { let toml_game = TomlGame { rooms: state .rooms .iter() .map(|r| TomlRoom { id: r.id, name: r.name.clone(), description: r.description.clone(), exits: r .exits .iter() .map(|(d, dest)| TomlExit { direction: d.clone(), destination: *dest, }) .collect(), items: r.items.clone(), }) .collect(), players: state .players .values() .map(|p| TomlPlayer { id: p.id.clone(), name: p.name.clone(), room: p.room, items: p.items.clone(), }) .collect(), quest: None, // quest config is read-only, not serialized back }; let toml_str = toml::to_string_pretty(&toml_game).unwrap(); std::fs::write("game.toml", toml_str).unwrap(); }
The quest config in game.toml is read-only — it defines the static quest structure (which rooms are guardians, where the reward door goes). We never need to write it back.
Setting quest: None in the serialized TOML means the [quest] section is simply omitted from the saved file. The section you manually wrote in game.toml stays intact because toml::to_string_pretty only outputs fields that are Some(...) for Option<T>.
However, there's a subtlety: toml::to_string_pretty will overwrite the entire file, including the [quest] section that was there before. To preserve it, we'd need to either:
- Read the original TOML, modify only the
[[players]]section, and write back — complex and error-prone - Use a separate file for quest config — over-engineered for a demo
- Accept that
[quest]is dropped on save and the server must be restarted to re-load it — which is fine because quest config doesn't change at runtime
For a production MUD you'd likely store quest scripts in a separate file or database. For a workshop, the simplicity of quest: None on write is the right trade-off.