feat(save): Speicherstand als Game-Baum

Autosave beim Betreten einer Etage und beim Beenden, ein Slot, bei Tod
geloescht. Der Save ist der Baum selbst — keine eigenen Save-Structs, die
man zweimal pflegt.

- Kacheln als ASCII-Zeilen wie ein Prefab, nicht 3200 Enum-Eintraege
- atomar geschrieben: tmp plus rename, der einzige Stand ueberlebt einen
  Abbruch
- fremdes Schema wird abgelehnt, die Datei bleibt liegen
- fehlende Mods verwerfen Eintraege, nie den Lauf
- Confirm-Screen vor dem Spiel, wenn der Save Eintraege verloren hat

Fuenf Befunde: die Ereigniswarteschlange gehoert nicht in den Save, die
Feldreihenfolge ist Teil des TOML-Formats, Serialize fuer Floor muss von
Hand, Confirm braucht on_no, und die Rueckfrage galt zuerst auch fuer
Mod-Ladewarnungen.
This commit is contained in:
2026-08-12 22:01:12 +02:00
parent 7fdd8bbb00
commit d09fef7069
15 changed files with 698 additions and 64 deletions

View File

@@ -60,8 +60,7 @@ struct Manifest {
id: String,
#[allow(dead_code)]
name: String,
/// Einziger Leser ist der Save-Header (Ticket 03/09).
#[allow(dead_code)]
/// Einziger Leser ist der Save-Kopf (Ticket 03/09).
version: String,
#[serde(default)]
depends: Vec<String>,
@@ -70,6 +69,9 @@ struct Manifest {
#[derive(Debug)]
struct ModInfo {
id: String,
/// Nur fuer den Save-Kopf (Ticket 09) — wird verglichen und protokolliert,
/// nie geprueft.
version: String,
depends: Vec<String>,
path: PathBuf,
}
@@ -133,7 +135,7 @@ fn discover(warnings: &mut Vec<String>) -> Vec<ModInfo> {
}
found.insert(
m.id.clone(),
ModInfo { id: m.id, depends: m.depends, path },
ModInfo { id: m.id, version: m.version, depends: m.depends, path },
);
}
Err(e) => warnings.push(format!("{}: {}", manifest_path.display(), e.message())),
@@ -531,6 +533,12 @@ pub fn load_mods() -> Result<(Registries, Vec<String>), LoadError> {
Err(e) => warnings.push(format!("[balance]: {} — Standardwerte gelten", e.message())),
}
reg.mods = order
.iter()
.filter_map(|id| found.iter().find(|m| &m.id == id))
.map(|m| super::save::ModStamp { id: m.id.clone(), version: m.version.clone() })
.collect();
// Phase 3 — Referenzen aufloesen
resolve(&mut reg, &mut warnings);