Loading and saving time data
Co-authored-by: Luna <LuS404@users.noreply.github.com>
This commit is contained in:
parent
7f8b24e328
commit
583ece9c12
@ -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"
|
||||
|
||||
|
@ -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>>,
|
||||
|
@ -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
44
game/src/progress.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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
1
savegame.json
Normal file
@ -0,0 +1 @@
|
||||
{"level_best_times":{}}
|
Reference in New Issue
Block a user