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 = { version = "1.0.126", features = ["derive"] }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.64"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
chrono = "0.4"
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
rust-embed = "6.2.0"
|
rust-embed = "6.2.0"
|
||||||
raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", rev = "2ae949cb3488dd1bb052ece71d61021c8dd6e910", features = [
|
raylib = { version = "3.5", git = "https://github.com/ewpratten/raylib-rs", rev = "2ae949cb3488dd1bb052ece71d61021c8dd6e910", features = [
|
||||||
"serde"
|
"serde"
|
||||||
@ -31,7 +31,7 @@ pkg-version = "1.0"
|
|||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
num-derive = "0.3"
|
num-derive = "0.3"
|
||||||
num = "0.4"
|
num = "0.4"
|
||||||
tiled = { version ="0.9.5", default-features = false }
|
tiled = { version = "0.9.5", default-features = false }
|
||||||
async-trait = "0.1.51"
|
async-trait = "0.1.51"
|
||||||
webbrowser = "0.5"
|
webbrowser = "0.5"
|
||||||
|
|
||||||
|
@ -3,19 +3,21 @@ use std::{cell::RefCell, sync::mpsc::Sender};
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use discord_sdk::activity::ActivityBuilder;
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum ControlFlag {
|
pub enum ControlFlag {
|
||||||
Quit,
|
Quit,
|
||||||
SwitchLevel(usize),
|
SwitchLevel(usize),
|
||||||
UpdateLevelStart(DateTime<Utc>)
|
UpdateLevelStart(DateTime<Utc>),
|
||||||
|
SaveProgress
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GameContext {
|
pub struct GameContext {
|
||||||
pub renderer: RefCell<HackedRaylibHandle>,
|
pub renderer: RefCell<HackedRaylibHandle>,
|
||||||
pub config: GameConfig,
|
pub config: GameConfig,
|
||||||
|
pub player_progress: ProgressData,
|
||||||
pub current_level: usize,
|
pub current_level: usize,
|
||||||
pub level_start_time: DateTime<Utc>,
|
pub level_start_time: DateTime<Utc>,
|
||||||
pub discord_rpc_send: Sender<Option<ActivityBuilder>>,
|
pub discord_rpc_send: Sender<Option<ActivityBuilder>>,
|
||||||
|
@ -81,6 +81,7 @@ use utilities::discord::DiscordConfig;
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::GameContext,
|
context::GameContext,
|
||||||
discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
|
discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
|
||||||
|
progress::ProgressData,
|
||||||
scenes::{build_screen_state_machine, Scenes},
|
scenes::{build_screen_state_machine, Scenes},
|
||||||
utilities::{
|
utilities::{
|
||||||
game_config::FinalShaderConfig,
|
game_config::FinalShaderConfig,
|
||||||
@ -108,6 +109,7 @@ mod scenes;
|
|||||||
mod utilities;
|
mod utilities;
|
||||||
pub use utilities::{datastore::StaticGameData, game_config::GameConfig};
|
pub use utilities::{datastore::StaticGameData, game_config::GameConfig};
|
||||||
mod character;
|
mod character;
|
||||||
|
mod progress;
|
||||||
|
|
||||||
/// The game entrypoint
|
/// The game entrypoint
|
||||||
pub async fn game_begin(game_config: &mut GameConfig) -> Result<(), Box<dyn std::error::Error>> {
|
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
|
// Build an MPSC for signaling the control thread
|
||||||
let (send_control_signal, recv_control_signal) = std::sync::mpsc::channel();
|
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 mut context;
|
||||||
let raylib_thread;
|
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()),
|
renderer: RefCell::new(rl.into()),
|
||||||
config: game_config.clone(),
|
config: game_config.clone(),
|
||||||
current_level: 0,
|
current_level: 0,
|
||||||
|
player_progress: save_file,
|
||||||
level_start_time: Utc::now(),
|
level_start_time: Utc::now(),
|
||||||
discord_rpc_send: send_discord_rpc,
|
discord_rpc_send: send_discord_rpc,
|
||||||
flag_send: send_control_signal,
|
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::Quit => break,
|
||||||
context::ControlFlag::SwitchLevel(level) => {
|
context::ControlFlag::SwitchLevel(level) => {
|
||||||
context.as_mut().current_level = level;
|
context.as_mut().current_level = level;
|
||||||
|
context.as_mut().player_progress.save();
|
||||||
}
|
}
|
||||||
context::ControlFlag::UpdateLevelStart(time) => {
|
context::ControlFlag::UpdateLevelStart(time) => {
|
||||||
context.as_mut().level_start_time = 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(())
|
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 {
|
if self.current_level_idx != context.current_level {
|
||||||
self.current_level_idx = context.current_level;
|
self.current_level_idx = context.current_level;
|
||||||
self.level_switch_timestamp = Utc::now();
|
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
|
// Grab exclusive access to the renderer
|
||||||
@ -131,6 +136,12 @@ impl Action<Scenes, ScreenError, GameContext> for InGameScreen {
|
|||||||
// Check if the player won
|
// Check if the player won
|
||||||
let cur_level = self.levels.get(context.current_level).unwrap();
|
let cur_level = self.levels.get(context.current_level).unwrap();
|
||||||
if self.player.position.x > cur_level.zones.win.x {
|
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 this is the last level, win the game
|
||||||
if self.current_level_idx >= self.levels.len() - 1 {
|
if self.current_level_idx >= self.levels.len() - 1 {
|
||||||
return Ok(ActionFlag::SwitchState(Scenes::WinScreen));
|
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