From 7709226a588791370a32a362f94e7eac54779019 Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Fri, 6 Nov 2026 07:54:36 +0100 Subject: [PATCH] Savegames hold only the game state: no settings, no camera (settings stay in local storage) Co-Authored-By: Claude Opus 5.5 --- src/fog.rs | 2 +- src/main.rs | 20 ++++++++++---------- src/save.rs | 36 ++++++++++++++++++------------------ src/scenes.rs | 2 +- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/fog.rs b/src/fog.rs index a8c3165..1c74c11 100644 --- a/src/fog.rs +++ b/src/fog.rs @@ -228,7 +228,7 @@ mod tests { assert!(g.map.shown(out), "own ground beyond the lifted start is known"); assert!(g.map.explored.iter().filter(|&&b| b).count() > explored); // savegame round trip - let json = crate::save::to_json(&g, &crate::render3d::Cam::new(0.0, 0.0), &crate::settings::Settings::default()); + let json = crate::save::to_json(&g); let l = crate::save::from_bytes(json.as_bytes()).unwrap(); assert_eq!(l.game.map.explored, g.map.explored); // the seer's eye opens a far area for a while diff --git a/src/main.rs b/src/main.rs index 39beb49..664d546 100644 --- a/src/main.rs +++ b/src/main.rs @@ -609,20 +609,20 @@ impl App { self.status = Some((text, now)); } - // Load a savegame (settings in the savegame are always applied) + // Load a savegame (only the game state; the settings stay as they are). The camera looks at + // the heart (screenshot scenes bring their own camera). fn load_bytes(&mut self, bytes: &[u8], ui: &mut Ui, menu: &mut Menu, r3d: &mut R3d, now: f64) { match save::from_bytes(bytes) { Ok(l) => { self.game = l.game; - if let Some(c) = l.camera { - self.cam = c; - self.cam.snap(); - } - if let Some(s) = l.settings { - self.settings = s; - apply_settings(&self.settings, r3d); - store_settings(&self.settings); + match l.camera { + Some(c) => self.cam = c, + None => { + let (cx, cy) = self.game.map.core; + self.cam = Cam::new(cx as f32 + 1.5, cy as f32 + 1.5); + } } + self.cam.snap(); apply_game_settings(&mut self.game, &self.settings); self.game.coop = false; self.coop = false; @@ -638,7 +638,7 @@ impl App { } fn autosave_json(&self) -> String { - save::to_json(&self.game, &self.cam, &self.settings) + save::to_json(&self.game) } fn connect_match(&mut self, cloud: &Cloud) -> bool { diff --git a/src/save.rs b/src/save.rs index 645d495..282c22f 100644 --- a/src/save.rs +++ b/src/save.rs @@ -1,9 +1,9 @@ -// Savegames: JSON with format tag and version, containing the game state, the camera -// and the player's settings (settings are always applied when a savegame is loaded). +// Savegames: JSON with format tag and version, containing the game state - nothing else. The +// player's settings live in the browser's local storage; settings in older savegames are +// ignored. Only the screenshot scenes (scenes.rs) also carry a camera. use crate::game::Game; use crate::render3d::Cam; -use crate::settings::Settings; use serde::{Deserialize, Serialize}; pub const FORMAT: &str = "dungeoncraft-save"; @@ -15,8 +15,8 @@ struct SaveOut<'a> { format: &'a str, version: u32, game: &'a Game, - camera: &'a Cam, - settings: &'a Settings, + #[serde(skip_serializing_if = "Option::is_none")] + camera: Option<&'a Cam>, } #[derive(Deserialize)] @@ -25,17 +25,21 @@ struct SaveIn { version: u32, game: Game, camera: Option, - settings: Option, } pub struct Loaded { pub game: Game, pub camera: Option, - pub settings: Option, } -pub fn to_json(game: &Game, camera: &Cam, settings: &Settings) -> String { - serde_json::to_string(&SaveOut { format: FORMAT, version: VERSION, game, camera, settings }).unwrap_or_default() +pub fn to_json(game: &Game) -> String { + serde_json::to_string(&SaveOut { format: FORMAT, version: VERSION, game, camera: None }).unwrap_or_default() +} + +// a screenshot scene: the game and where the camera looks +#[allow(dead_code)] // scenes.rs (tests) only +pub fn to_json_with_camera(game: &Game, camera: &Cam) -> String { + serde_json::to_string(&SaveOut { format: FORMAT, version: VERSION, game, camera: Some(camera) }).unwrap_or_default() } // Err contains a language key describing the problem @@ -50,7 +54,7 @@ pub fn from_bytes(data: &[u8]) -> Result { let mut game = s.game; game.map.activate(); game.recount(); - Ok(Loaded { game, camera: s.camera, settings: s.settings }) + Ok(Loaded { game, camera: s.camera }) } #[cfg(test)] @@ -65,18 +69,14 @@ mod tests { for _ in 0..3000 { g.update(0.05); } - let cam = Cam::new(10.0, 20.0); - let mut settings = Settings::default(); - settings.language = "de".into(); - let json = to_json(&g, &cam, &settings); + let json = to_json(&g); println!("savegame size: {} KB", json.len() / 1024); let l = from_bytes(json.as_bytes()).expect("load"); assert_eq!(l.game.time, g.time); assert_eq!(l.game.ents.len(), g.ents.len()); assert_eq!(l.game.gold, g.gold); assert!(l.game.map.t.iter().zip(g.map.t.iter()).all(|(a, b)| a.kind == b.kind && a.owner == b.owner && a.marked == b.marked)); - assert_eq!(l.settings.unwrap().language, "de"); - assert_eq!(l.camera.unwrap().tx, 10.0); + assert!(l.camera.is_none() && !json.contains("\"settings\"") && !json.contains("\"camera\""), "only the game state"); assert_eq!((l.game.map.w, l.game.map.h), (96, 128)); assert_eq!(l.game.map.portals.len(), g.map.portals.len()); assert!(l.game.map.t.iter().zip(g.map.t.iter()).all(|(a, b)| a.var == b.var && a.hp == b.hp && a.food == b.food && a.gold == b.gold)); @@ -107,7 +107,7 @@ mod tests { g.update(0.05); } let sim = t1.elapsed(); - let json = to_json(&g, &Cam::new(0.0, 0.0), &Settings::default()); + let json = to_json(&g); println!("256x256: generate {:?}, 2 min simulated in {:?}, savegame {} KB", gen, sim, json.len() / 1024); let l = from_bytes(json.as_bytes()).expect("load"); assert_eq!(l.game.map.t.len(), 256 * 256); @@ -132,7 +132,7 @@ mod tests { let (ex, ey) = (cx + 1, cy + 1); let mut cam = Cam::new(ex as f32 + 0.5, ey as f32 + 0.5); cam.zoom = 12.0; - std::fs::write(path, to_json(&g, &cam, &Settings { language: "en".into(), ..Settings::default() })).unwrap(); + std::fs::write(path, to_json_with_camera(&g, &cam)).unwrap(); } } diff --git a/src/scenes.rs b/src/scenes.rs index eb97140..a863c3f 100644 --- a/src/scenes.rs +++ b/src/scenes.rs @@ -55,7 +55,7 @@ fn save(name: &str, g: &mut Game, x: f32, z: f32, zoom: f32, yaw: f32, fog: bool let mut s = Settings::default(); s.language = "en".into(); s.hints = false; - std::fs::write(format!("/tmp/scenes/{}.json", name), crate::save::to_json(g, &cam, &s)).unwrap(); + std::fs::write(format!("/tmp/scenes/{}.json", name), crate::save::to_json_with_camera(g, &cam)).unwrap(); } fn run(g: &mut Game, secs: f32) {