use std::{
fs::File,
io::{self, Read, Write},
};
use crate::application::{Application, CompressedInputHistory, GameSave};
#[derive(
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Clone,
Copy,
Debug,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub enum SavefileGranularity {
#[default]
NoSavefile,
RememberSettings,
RememberSettingsScores,
RememberSettingsScoresReplays,
}
impl<T: Write> Application<T> {
pub fn load_from_savefile(&mut self) -> io::Result<()> {
let mut file = File::open(self.temp_data.savefile_path.clone())?;
let mut save_str = String::new();
file.read_to_string(&mut save_str)?;
let compressed_game_saves: (usize, Vec<GameSave<CompressedInputHistory>>);
(
self.temp_data.save_on_exit,
self.settings,
self.scores_and_replays,
self.statistics,
compressed_game_saves,
) = serde_json::from_str(&save_str)?;
self.game_saves = (
compressed_game_saves.0,
compressed_game_saves
.1
.into_iter()
.map(|save| save.map(|input_history| input_history.decompress()))
.collect::<Vec<_>>(),
);
Ok(())
}
pub fn store_to_savefile(&mut self) -> io::Result<()> {
if self.temp_data.save_on_exit < SavefileGranularity::RememberSettingsScores {
self.scores_and_replays.entries.clear();
} else if self.temp_data.save_on_exit < SavefileGranularity::RememberSettingsScoresReplays {
for (_entry, restoration_data) in &mut self.scores_and_replays.entries {
restoration_data.take();
}
}
let compressed_game_saves = (
self.game_saves.0,
self.game_saves
.1
.iter()
.cloned()
.map(|save| save.map(|input_history| CompressedInputHistory::new(&input_history)))
.collect::<Vec<_>>(),
);
let save_str = serde_json::to_string(&(
self.temp_data.save_on_exit,
&self.settings,
&self.scores_and_replays,
&self.statistics,
compressed_game_saves,
))?;
let mut file = File::create(self.temp_data.savefile_path.clone())?;
let n_written = file.write(save_str.as_bytes())?;
if n_written < save_str.len() {
Err(std::io::Error::other(
"attempt to write to file consumed `n < save_str.len()` bytes",
))
} else {
Ok(())
}
}
}