use crate::{State, TILES}; use anyhow::{Result, anyhow}; use hurrycurry_protocol::{ TileIndex, glam::{IVec2, ivec2}, }; use serde::{Deserialize, Serialize}; use std::{ collections::{HashMap, HashSet}, hash::RandomState, }; #[rustfmt::skip] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MapDecl { map: Vec, tiles: HashMap, items: HashMap, collider: Vec, walkable: Vec, chef_spawn: char, customer_spawn: char, score_baseline: i64, } pub fn export_state(state: &State) -> String { let mut cmin = IVec2::MAX; let mut cmax = IVec2::MIN; for pos in state.tiles.keys().copied() { cmin = cmin.min(pos); cmax = cmax.max(pos); } let mut map = Vec::new(); let mut tiles = HashMap::new(); let mut collider = HashSet::new(); let mut walkable = HashSet::new(); for y in cmin.y..=cmax.y { let mut line = String::new(); for x in cmin.x..=cmax.x { let p = ivec2(x, y); line.push(if let Some(t) = state.tiles.get(&p) { let c = if p == state.chef_spawn { '~' } else if p == state.customer_spawn { '!' } else { TILES[t.0].1 }; if TILES[t.0].2 == 2 { collider.insert(TILES[t.0].0.to_string()); } if TILES[t.0].2 == 1 { walkable.insert(TILES[t.0].0.to_string()); } tiles.insert(c, TILES[t.0].0.to_string()); c } else { ' ' }) } map.push(line); } let decl: MapDecl = MapDecl { map, tiles, items: HashMap::new(), collider: collider.into_iter().collect(), walkable: walkable.into_iter().collect(), chef_spawn: '~', customer_spawn: '!', score_baseline: 200, }; serde_yml::to_string(&decl).unwrap() } pub fn import_state(state: &mut State, s: &str) -> Result<()> { let decl: MapDecl = serde_yml::from_str(s)?; let name_to_tile = HashMap::<_, _, RandomState>::from_iter( TILES .iter() .enumerate() .map(|(i, (name, _, _))| ((*name).to_owned(), i)), ); for (y, line) in decl.map.iter().enumerate() { for (x, char) in line.chars().enumerate() { let pos = ivec2(x as i32, y as i32); if char == ' ' { continue; } if char == decl.customer_spawn { state.customer_spawn = pos; } if char == decl.chef_spawn { state.chef_spawn = pos; } let tile = decl .tiles .get(&char) .ok_or(anyhow!("char undefined {char:?}"))?; let tile = name_to_tile .get(tile) .ok_or(anyhow!("unknown tile {tile:?}"))?; state.set_tile(pos, TileIndex(*tile)); } } Ok(()) }