use rhai::{ serde::{from_dynamic, to_dynamic}, Dynamic, Func, AST, }; use uuid::Uuid; use std::collections::HashMap; use super::config::{Config, Pile}; mod engine; use engine::setup_engine; mod functions; use functions::Functions; mod types; pub use types::{CardId, CardIdx, PileKind}; use types::{Data, Player, RhaiResult}; pub struct RunningGame { #[allow(unused)] // TODO Remove name: String, pub piles: HashMap, pub player_piles: Vec>, functions: Functions, current_player: Player, data: HashMap, pub players: HashMap, } // TODO add errors impl RunningGame { fn get_fns(ast: &AST) -> Vec { ast.iter_functions() .map(|(_, _, name, _, _)| name.to_string()) .collect() } pub fn compile(path: std::path::PathBuf) -> RhaiResult<(AST, Vec)> { let e = setup_engine(); let ast = e.compile_file(path)?; let fns = Self::get_fns(&ast); Ok((ast, fns)) } pub fn new( name: String, ast: AST, fns: &[String], conf: &Config, current_players: &[Uuid], ) -> Self { // log::info!("Fns: {:?}", fns); let functions = Functions::new(fns, ast.clone(), &name); let engine = setup_engine(); let setup = Func::<(Dynamic,), Dynamic>::create_from_ast(engine, ast, "setup"); let piles = conf.piles.clone(); let player_piles = vec![conf.player_piles.clone(); current_players.len()]; let Data { piles, player_piles, players: _, other, } = from_dynamic( &setup( to_dynamic(Data::new(piles, player_piles, current_players.len() as u32)).unwrap(), ) .unwrap(), ) .unwrap(); let mut players = HashMap::new(); for (i, player) in current_players.iter().enumerate() { players.insert(player.clone(), i as u32); } log::info!("Players in game {}: {:?}", name, players); Self { name, piles, player_piles, functions, current_player: Player::new(0, current_players.len() as u32), data: other, players, } // Self {setup: Box::new(Func::<(Vec, Vec>), ()>::create_from_ast(engine, ast, "setup"))} } pub fn get_player_for_uuid(&self, user: &Uuid) -> Option { self.players.get(user).copied() } pub fn get_current_player(&self) -> u32 { self.current_player.num } fn data_as_dynamic(&self) -> RhaiResult { to_dynamic(Data { piles: self.piles.clone(), player_piles: self.player_piles.clone(), players: self.current_player.max, other: self.data.clone(), }) } fn save_data(&mut self, d: &Dynamic) -> RhaiResult<()> { let d: Data = from_dynamic(d)?; self.data = d.other; self.piles = d.piles; self.player_piles = d.player_piles; Ok(()) } pub fn on_click(&mut self, card: CardId, player: u32) { let action_author = Player::new(player, self.current_player.max); let data = self.data_as_dynamic().unwrap(); let arr = self .functions .on_click(data, card, action_author, self.current_player) .unwrap(); self.save_data(&arr[0]).unwrap(); let turn_end: bool = arr[1].clone().cast(); if turn_end { self.turn_end() } } fn turn_end(&mut self) { let data = self.data_as_dynamic().unwrap(); let mut arr = self.functions.turn_end(data, self.current_player).unwrap(); self.save_data(&arr[0]).unwrap(); self.current_player = arr.remove(1).cast(); self.turn_start(); } fn turn_start(&mut self) { let data = self.data_as_dynamic().unwrap(); let data = self .functions .turn_start(data, self.current_player) .transpose() .unwrap(); if let Some(data) = data { self.save_data(&data).unwrap(); } } }