basic save for game server
This commit is contained in:
parent
2a36485b1b
commit
98ee910ce1
3 changed files with 38 additions and 3 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
/data
|
33
src/lib.rs
33
src/lib.rs
|
@ -7,17 +7,24 @@ use game::{
|
||||||
entry::{ActionDefinition, DiceRoll},
|
entry::{ActionDefinition, DiceRoll},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::sync::{broadcast, mpsc};
|
use tokio::{
|
||||||
|
sync::{broadcast, mpsc},
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod pathfinder2r_impl;
|
pub mod pathfinder2r_impl;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
|
pub const GAME_SAVE_FILE: &str = "data/game.json";
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GameServer {
|
pub struct GameServer {
|
||||||
game: Game<pathfinder2r_impl::Pathfinder2rCharacterSheet, pathfinder2r_impl::entry::Entry>,
|
game: Game<pathfinder2r_impl::Pathfinder2rCharacterSheet, pathfinder2r_impl::entry::Entry>,
|
||||||
chat: Vec<(String, ChatMessage)>,
|
chat: Vec<(String, ChatMessage)>,
|
||||||
|
#[serde(skip, default = "default_last_save_time")]
|
||||||
|
last_save_time: Instant,
|
||||||
// we dont want to save the logged users as it will always be empty when the server restarts
|
// we dont want to save the logged users as it will always be empty when the server restarts
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
/// Logged in users, bool value used to know if the user is an admin or not
|
/// Logged in users, bool value used to know if the user is an admin or not
|
||||||
|
@ -25,6 +32,10 @@ pub struct GameServer {
|
||||||
// TODO: JEESH REPLACE THIS WITH A DATABASE AND PROPER SECURITY ONCE ITS DONE PLEASE GOD
|
// TODO: JEESH REPLACE THIS WITH A DATABASE AND PROPER SECURITY ONCE ITS DONE PLEASE GOD
|
||||||
creds: HashMap<String, String>,
|
creds: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
/// This is needed for the default value in GameServer.last_save_time
|
||||||
|
fn default_last_save_time() -> Instant {
|
||||||
|
Instant::now()
|
||||||
|
}
|
||||||
impl GameServer {
|
impl GameServer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut creds = HashMap::new();
|
let mut creds = HashMap::new();
|
||||||
|
@ -51,11 +62,19 @@ impl GameServer {
|
||||||
)))
|
)))
|
||||||
.with_action(ActionDefinition::new("Attack -1".to_string())),
|
.with_action(ActionDefinition::new("Attack -1".to_string())),
|
||||||
)],
|
)],
|
||||||
|
last_save_time: Instant::now(),
|
||||||
users: HashMap::new(),
|
users: HashMap::new(),
|
||||||
creds,
|
creds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn save(&self) {
|
||||||
|
let _ = tokio::fs::create_dir("data").await;
|
||||||
|
if let Ok(json) = serde_json::to_string(self) {
|
||||||
|
let _ = tokio::fs::write(GAME_SAVE_FILE, json.as_bytes()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn server_loop(
|
pub async fn server_loop(
|
||||||
mut self,
|
mut self,
|
||||||
mut msgs: mpsc::Receiver<(String, api::Request)>,
|
mut msgs: mpsc::Receiver<(String, api::Request)>,
|
||||||
|
@ -206,7 +225,11 @@ impl GameServer {
|
||||||
}
|
}
|
||||||
_ = broadcast.send((Some(id), api::Response::Shutdown));
|
_ = broadcast.send((Some(id), api::Response::Shutdown));
|
||||||
}
|
}
|
||||||
api::Request::Shutdown => break,
|
api::Request::Shutdown => {
|
||||||
|
if *self.users.get(&id).unwrap_or(&false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
api::Request::CharacterDisplay { id: _ } => {}
|
api::Request::CharacterDisplay { id: _ } => {}
|
||||||
api::Request::CharacterInputs { id: _ } => todo!(),
|
api::Request::CharacterInputs { id: _ } => todo!(),
|
||||||
api::Request::CharacterGetField { id: _, field: _ } => todo!(),
|
api::Request::CharacterGetField { id: _, field: _ } => todo!(),
|
||||||
|
@ -217,8 +240,14 @@ impl GameServer {
|
||||||
} => todo!(),
|
} => todo!(),
|
||||||
api::Request::CharacterAssign { id: _, user: _ } => todo!(),
|
api::Request::CharacterAssign { id: _, user: _ } => todo!(),
|
||||||
}
|
}
|
||||||
|
// Auto save every 5 minutes, once a request is received
|
||||||
|
// TODO: Export the auto save time
|
||||||
|
if self.last_save_time.elapsed().as_secs() > 5 * 60 {
|
||||||
|
self.save().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ = broadcast.send((None, api::Response::Shutdown));
|
_ = broadcast.send((None, api::Response::Shutdown));
|
||||||
|
self.save().await; // Save the game one last time :)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_scene_list(&self, id: &str) -> api::Response {
|
fn get_scene_list(&self, id: &str) -> api::Response {
|
||||||
|
|
|
@ -30,7 +30,12 @@ async fn main() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap();
|
||||||
let game = open_tavern::GameServer::new();
|
let game = tokio::fs::read_to_string(open_tavern::GAME_SAVE_FILE)
|
||||||
|
.await
|
||||||
|
.map(|s| serde_json::from_str(&s).ok())
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or(open_tavern::GameServer::new());
|
||||||
tokio::spawn(game.server_loop(mrecv, bsend));
|
tokio::spawn(game.server_loop(mrecv, bsend));
|
||||||
|
|
||||||
println!("Server is running at http://localhost:3001");
|
println!("Server is running at http://localhost:3001");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue