use std::sync::Arc; use serde::{Deserialize, Serialize}; use serenity::prelude::{Mutex, TypeMapKey}; use std::fs::File; use std::io::{Read, Write}; use crate::config::BotConfig; use crate::error::{Result, WoxlfError}; use crate::game::game_state::GameState; use crate::game::Phase; use crate::imgur::{get_album_images, Image}; use chrono::Duration; use rand::prelude::SliceRandom; use serenity::utils::MessageBuilder; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct GlobalData { pub cfg: BotConfig, pub game_state: Option, } impl GlobalData { pub fn new(cfg: BotConfig) -> Self { Self { cfg, game_state: None, } } pub fn start_game(&mut self, starting_phase: Phase, starting_phase_duration: Duration) { self.game_state = Some(GameState::new(starting_phase, starting_phase_duration)) } 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)?); 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 clear_game_state(&mut self) -> Result<()> { self.game_state = None; if self.game_state_exists() { std::fs::remove_file(self.cfg.get_game_state_path())?; } Ok(()) } pub fn print_game_status(&self) -> String { if let Some(game_state) = &self.game_state { MessageBuilder::new() .push_line(format!( "CURRENT EXPERIMENT PHASE: {} {}", game_state.current_phase, game_state.phase_number )) .push_line(format!( "PHASE END TIME: {}", game_state.get_phase_end_time() )) .push_line(format!("PHASE ENDING {}", game_state.get_phase_countdown())) .build() } else { "Game not in progress.".to_string() } } pub async fn get_profile_pic_url(&self) -> Result { let images: Vec = get_album_images( &self.cfg.imgur_client_id, &self.cfg.game_config.profile_album_hash, ) .await?; Ok(images.choose(&mut rand::thread_rng()).unwrap().link.clone()) } } impl TypeMapKey for GlobalData { type Value = Arc>; }