107 lines
2.8 KiB
Rust
107 lines
2.8 KiB
Rust
use crate::prelude::*;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Resource, Clone, Debug)]
|
|
pub struct SavegamePath(pub PathBuf);
|
|
|
|
#[derive(Debug)]
|
|
pub struct SavegameInfo {
|
|
pub path: SavegamePath,
|
|
pub index: u32,
|
|
pub total_berries: u32,
|
|
pub completed_focus: u32,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct PartialSaveData {
|
|
session_tracker: PartialSessionTracker,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct PartialSessionTracker {
|
|
completed_focus_phases: u32,
|
|
}
|
|
|
|
impl SavegamePath {
|
|
pub fn new(index: u32) -> Self {
|
|
let base_path = get_internal_path().unwrap_or_else(|| {
|
|
println!(
|
|
"Could not determine platform-specific save directory. Falling back to `./saves/"
|
|
);
|
|
PathBuf::from("./saves/")
|
|
});
|
|
|
|
if let Err(e) = std::fs::create_dir_all(&base_path) {
|
|
panic!("Failed to create save directory at {:?}: {}", base_path, e);
|
|
}
|
|
|
|
Self(base_path.join(format!("savegame-{}.json", index)))
|
|
}
|
|
|
|
pub fn list() -> Vec<SavegameInfo> {
|
|
let mut savegames = Vec::new();
|
|
|
|
let Some(base_path) = get_internal_path() else {
|
|
return Vec::new();
|
|
};
|
|
if !base_path.exists() {
|
|
return Vec::new();
|
|
}
|
|
let Ok(entries) = fs::read_dir(base_path) else {
|
|
return Vec::new();
|
|
};
|
|
|
|
for entry in entries.flatten() {
|
|
let path = entry.path();
|
|
|
|
if path.extension().and_then(|s| s.to_str()) != Some("json") {
|
|
continue;
|
|
}
|
|
let Some(file_name) = path.file_stem().and_then(|s| s.to_str()) else {
|
|
continue;
|
|
};
|
|
if !file_name.starts_with("savegame-") {
|
|
continue;
|
|
}
|
|
let Ok(index) = file_name.trim_start_matches("savegame-").parse::<u32>() else {
|
|
continue;
|
|
};
|
|
let Ok(content) = fs::read_to_string(&path) else {
|
|
continue;
|
|
};
|
|
let Ok(data) = serde_json::from_str::<PartialSaveData>(&content) else {
|
|
continue;
|
|
};
|
|
|
|
savegames.push(SavegameInfo {
|
|
path: SavegamePath(path),
|
|
index,
|
|
total_berries: 0, // TODO: add total_berries
|
|
completed_focus: data.session_tracker.completed_focus_phases,
|
|
});
|
|
}
|
|
|
|
savegames.sort_by_key(|s| s.index);
|
|
savegames
|
|
}
|
|
|
|
pub fn next() -> Self {
|
|
let savegames = Self::list();
|
|
let next_index = savegames.last().map(|s| s.index + 1).unwrap_or(0);
|
|
Self::new(next_index)
|
|
}
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub enum RootMarker {
|
|
PopupSavegameLoad,
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub enum ButtonType {
|
|
SavegameLoad { savegame_path: SavegamePath },
|
|
SavegameDelete { savegame_path: SavegamePath },
|
|
PopupClose,
|
|
}
|