use brink_format::{DefinitionId, LoadReport, SAVE_FORMAT_VERSION, SaveState, VisitEntry};
use crate::StoryRng;
use crate::debug::NameResolver;
use crate::story::Story;
impl<R: StoryRng> Story<'_, R> {
#[must_use]
pub fn save_state(&self) -> SaveState {
let ctx = &self.default_context;
let resolver = NameResolver::new(self.program());
let globals = ctx
.globals
.iter()
.enumerate()
.filter_map(|(i, v)| {
self.program()
.global_slot_name(i)
.map(|name| (name.to_owned(), v.clone()))
})
.collect();
let to_entries = |map: &std::collections::HashMap<DefinitionId, u32>| {
let mut entries: Vec<VisitEntry> = map
.iter()
.map(|(&id, &count)| VisitEntry {
id,
path: resolver.def_path(id).map(str::to_owned),
count,
})
.collect();
entries.sort_by_key(|e| e.id.to_raw());
entries
};
SaveState {
version: SAVE_FORMAT_VERSION,
globals,
visits: to_entries(&ctx.visit_counts),
turns: to_entries(&ctx.turn_counts),
turn_index: ctx.turn_index,
rng_seed: ctx.rng_seed,
previous_random: ctx.previous_random,
}
}
pub fn load_state(&mut self, save: &SaveState) -> LoadReport {
let mut report = LoadReport::default();
for (name, value) in &save.globals {
match self.program().global_index(name) {
Some(idx) => self.default_context.set_global(idx, value.clone()),
None => report.unknown_globals.push(name.clone()),
}
}
let ctx = &mut self.default_context;
ctx.turn_index = save.turn_index;
ctx.rng_seed = save.rng_seed;
ctx.previous_random = save.previous_random;
for e in &save.visits {
ctx.visit_counts.insert(e.id, e.count);
}
for e in &save.turns {
ctx.turn_counts.insert(e.id, e.count);
}
report
}
}