use std::sync::Arc; use chrono::Duration; use serenity::prelude::{Mutex, TypeMapKey}; use std::fs::File; use std::io::{Read, Write}; use crate::config::{BotConfig, GameConfig}; use crate::error::{Result, WoxlfError}; use crate::game::game_state::GameState; use crate::game::Phase; use crate::imgur::{get_album_images, Image}; use crate::messages::MessageTemplates; #[derive(Debug, Clone)] pub struct GlobalData { pub cfg: BotConfig, pub game_cfg: Option, pub templates: Option, pub game_state: Option, } impl GlobalData { pub fn new(cfg: BotConfig) -> Self { Self { cfg, game_cfg: None, templates: None, game_state: None, } } pub fn start_game( &mut self, game_name: &str, starting_phase: Phase, starting_phase_duration: Duration, ) -> Result<()> { let game_config = self .cfg .get_game_config(game_name) .ok_or(WoxlfError::ConfigNotfound)?; self.templates = Some(MessageTemplates::try_from(game_config.messages.clone())?); self.game_cfg = Some(game_config); self.game_state = Some(GameState::new( starting_phase, starting_phase_duration, game_name, )); Ok(()) } pub fn save_game_state(&mut self) -> Result<()> { if let Some(game_state) = &mut self.game_state { let s = toml::to_string_pretty(game_state)?; let mut file = File::create(self.cfg.get_game_state_path())?; file.write_all(s.as_bytes())?; Ok(()) } else { Err(WoxlfError::GameNotInProgress) } } pub fn game_state_exists(&self) -> bool { self.cfg.get_game_state_path().exists() } pub fn load_game_state(&mut self) -> Result<()> { let mut file = File::open(self.cfg.get_game_state_path())?; let mut data = String::new(); file.read_to_string(&mut data)?; self.game_state = Some(toml::from_str(&data)?); let game_config = self .cfg .get_game_config(&self.game_state.as_ref().unwrap().game_name) .unwrap(); self.templates = Some(MessageTemplates::try_from(game_config.messages.clone())?); self.game_cfg = Some(game_config); Ok(()) } pub fn game_state_mut(&mut self) -> Result<&mut GameState> { match &mut self.game_state { None => Err(WoxlfError::GameNotInProgress), Some(game_state) => Ok(game_state), } } pub fn game_state(&self) -> Result<&GameState> { match &self.game_state { None => Err(WoxlfError::GameNotInProgress), Some(game_state) => Ok(game_state), } } pub fn templates(&self) -> Result<&MessageTemplates> { match &self.templates { None => Err(WoxlfError::GameNotInProgress), Some(templates) => Ok(templates), } } pub fn game_cfg(&self) -> Result<&GameConfig> { match &self.game_cfg { None => Err(WoxlfError::GameNotInProgress), Some(game_config) => Ok(game_config), } } pub fn clear_game_state(&mut self) -> Result<()> { self.game_state = None; self.game_cfg = None; self.templates = None; if self.game_state_exists() { std::fs::remove_file(self.cfg.get_game_state_path())?; } Ok(()) } pub async fn get_profile_pic_album(&self) -> Result> { Ok(get_album_images( &self.cfg.imgur_client_id, &self.game_cfg()?.profile_album_hash, ) .await?) } pub fn get_phase_name(&self) -> Result { let game_cfg = self.game_cfg()?; let state = self.game_state()?; Ok(if state.current_phase == Phase::Day { game_cfg.vote_phase_name.clone() } else { game_cfg.enemy_phase_name.clone() }) } } impl TypeMapKey for GlobalData { type Value = Arc>; }