Loading and saving time data

Co-authored-by: Luna <LuS404@users.noreply.github.com>
This commit is contained in:
Evan Pratten 2021-10-03 12:12:06 -04:00
parent 7f8b24e328
commit 583ece9c12
6 changed files with 75 additions and 5 deletions

View File

@ -14,7 +14,7 @@ tracing = { version = "0.1", features = ["log"] }
serde = { version = "1.0.126", features = ["derive"] }
serde_json = "1.0.64"
thiserror = "1.0"
chrono = "0.4"
chrono = { version = "0.4", features = ["serde"] }
rust-embed = "6.2.0"
raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", rev = "2ae949cb3488dd1bb052ece71d61021c8dd6e910", features = [
"serde"
@ -31,7 +31,7 @@ pkg-version = "1.0"
cfg-if = "1.0"
num-derive = "0.3"
num = "0.4"
tiled = { version ="0.9.5", default-features = false }
tiled = { version = "0.9.5", default-features = false }
async-trait = "0.1.51"
webbrowser = "0.5"

View File

@ -3,19 +3,21 @@ use std::{cell::RefCell, sync::mpsc::Sender};
use chrono::{DateTime, Utc};
use discord_sdk::activity::ActivityBuilder;
use crate::{utilities::non_ref_raylib::HackedRaylibHandle, GameConfig};
use crate::{progress::ProgressData, utilities::non_ref_raylib::HackedRaylibHandle, GameConfig};
#[derive(Debug)]
pub enum ControlFlag {
Quit,
SwitchLevel(usize),
UpdateLevelStart(DateTime<Utc>)
UpdateLevelStart(DateTime<Utc>),
SaveProgress
}
#[derive(Debug)]
pub struct GameContext {
pub renderer: RefCell<HackedRaylibHandle>,
pub config: GameConfig,
pub player_progress: ProgressData,
pub current_level: usize,
pub level_start_time: DateTime<Utc>,
pub discord_rpc_send: Sender<Option<ActivityBuilder>>,

View File

@ -81,6 +81,7 @@ use utilities::discord::DiscordConfig;
use crate::{
context::GameContext,
discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
progress::ProgressData,
scenes::{build_screen_state_machine, Scenes},
utilities::{
game_config::FinalShaderConfig,
@ -108,6 +109,7 @@ mod scenes;
mod utilities;
pub use utilities::{datastore::StaticGameData, game_config::GameConfig};
mod character;
mod progress;
/// The game entrypoint
pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std::error::Error>> {
@ -148,6 +150,9 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
// Build an MPSC for signaling the control thread
let (send_control_signal, recv_control_signal) = std::sync::mpsc::channel();
// Load the savefile
let mut save_file = ProgressData::load_from_file();
let mut context;
let raylib_thread;
{
@ -172,6 +177,7 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
renderer: RefCell::new(rl.into()),
config: game_config.clone(),
current_level: 0,
player_progress: save_file,
level_start_time: Utc::now(),
discord_rpc_send: send_discord_rpc,
flag_send: send_control_signal,
@ -320,9 +326,14 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
context::ControlFlag::Quit => break,
context::ControlFlag::SwitchLevel(level) => {
context.as_mut().current_level = level;
context.as_mut().player_progress.save();
}
context::ControlFlag::UpdateLevelStart(time) => {
context.as_mut().level_start_time = time;
context.as_mut().player_progress.save();
}
context::ControlFlag::SaveProgress => {
context.as_mut().player_progress.save();
}
}
}
@ -333,5 +344,6 @@ pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std:
}
}
}
context.as_mut().player_progress.save();
Ok(())
}

44
game/src/progress.rs Normal file
View File

@ -0,0 +1,44 @@
use std::collections::HashMap;
use chrono::Duration;
use tracing::info;
#[derive(Debug, Deserialize, Serialize, Default)]
pub struct ProgressData {
pub level_best_times: HashMap<usize, i64>,
}
impl ProgressData {
pub fn get_level_best_time(&self, level: usize) -> Option<Duration> {
let level_best_time = self.level_best_times.get(&level);
match level_best_time {
Some(time) => Some(Duration::seconds(*time)),
None => None,
}
}
pub fn maybe_write_new_time(&mut self, level: usize, time: &Duration) {
let time_in_seconds = time.num_seconds();
if let Some(best_time) = self.get_level_best_time(level) {
if best_time.num_seconds() > time_in_seconds {
self.level_best_times.insert(level, time_in_seconds);
}
} else {
self.level_best_times.insert(level, time_in_seconds);
}
}
pub fn load_from_file() -> Self {
info!("Loading progress data from file");
serde_json::from_str(
&std::fs::read_to_string("./savegame.json")
.unwrap_or("{\"level_best_times\":{}}".to_string()),
)
.unwrap_or(Self::default())
}
pub fn save(&self) {
info!("Saving progress data to file");
std::fs::write("./savegame.json", serde_json::to_string(self).unwrap()).unwrap()
}
}

View File

@ -104,7 +104,12 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
if self.current_level_idx != context.current_level {
self.current_level_idx = context.current_level;
self.level_switch_timestamp = Utc::now();
context.flag_send.send(Some(ControlFlag::UpdateLevelStart(self.level_switch_timestamp))).unwrap();
context
.flag_send
.send(Some(ControlFlag::UpdateLevelStart(
self.level_switch_timestamp,
)))
.unwrap();
}
// Grab exclusive access to the renderer
@ -131,6 +136,12 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
// Check if the player won
let cur_level = self.levels.get(context.current_level).unwrap();
if self.player.position.x > cur_level.zones.win.x {
// Save the progress
context
.flag_send
.send(Some(ControlFlag::SaveProgress))
.unwrap();
// If this is the last level, win the game
if self.current_level_idx >= self.levels.len() - 1 {
return Ok(ActionFlag::SwitchState(Scenes::WinScreen));

1
savegame.json Normal file
View File

@ -0,0 +1 @@
{"level_best_times":{}}