diff options
Diffstat (limited to 'server/src/data.rs')
-rw-r--r-- | server/src/data.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/server/src/data.rs b/server/src/data.rs new file mode 100644 index 00000000..6affccb5 --- /dev/null +++ b/server/src/data.rs @@ -0,0 +1,127 @@ +use crate::{interaction::Recipe, protocol::TileIndex}; +use glam::{IVec2, Vec2}; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, sync::RwLock}; + +#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default)] +#[serde(rename_all = "snake_case")] +pub enum Action { + #[default] + Never, + Passive(f32), + Active(f32), + Instant, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RecipeDecl { + #[serde(default)] + pub tile: Option<String>, + #[serde(default)] + pub inputs: Vec<String>, + #[serde(default)] + pub outputs: Vec<String>, + #[serde(default)] + pub action: Action, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct InitialMap { + map: Vec<String>, + tiles: HashMap<String, String>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Gamedata { + pub recipes: Vec<Recipe>, + pub item_names: Vec<String>, + pub tile_names: Vec<String>, + #[serde(skip)] + pub initial_map: HashMap<IVec2, TileIndex>, + pub spawn: Vec2, +} + +pub fn build_gamedata(recipes_in: Vec<RecipeDecl>, map_in: InitialMap) -> Gamedata { + let item_names = RwLock::new(Vec::new()); + let tile_names = RwLock::new(Vec::new()); + let mut recipes = Vec::new(); + + for r in recipes_in { + let r2 = r.clone(); + let mut inputs = r.inputs.into_iter().map(|i| register(&item_names, i)); + let mut outputs = r.outputs.into_iter().map(|o| register(&item_names, o)); + let tile = r.tile.map(|t| register(&tile_names, t)); + match r.action { + Action::Never => {} + Action::Passive(duration) => recipes.push(Recipe::Passive { + duration, + tile, + input: inputs.next().expect("passive recipe without input"), + output: outputs.next(), + }), + Action::Active(duration) => recipes.push(Recipe::Active { + duration, + tile, + input: inputs.next().expect("active recipe without input"), + outputs: [outputs.next(), outputs.next()], + }), + Action::Instant => { + recipes.push(Recipe::Instant { + tile, + inputs: [inputs.next(), inputs.next()], + outputs: [outputs.next(), outputs.next()], + }); + } + } + assert_eq!(inputs.next(), None, "{r2:?}"); + assert_eq!(outputs.next(), None, "{r2:?}"); + } + + let mut spawn = Vec2::new(0., 0.); + let mut initial_map = HashMap::new(); + for (y, line) in map_in.map.iter().enumerate() { + for (x, tile) in line.trim().char_indices() { + let pos = IVec2::new(x as i32, y as i32); + let mut tilename = map_in.tiles[&tile.to_string()].clone(); + if tilename == "spawn" { + spawn = pos.as_vec2(); + tilename = "floor".to_owned(); + } + let tile = register(&tile_names, tilename); + initial_map.insert(pos, tile); + } + } + + Gamedata { + recipes, + initial_map, + item_names: item_names.into_inner().unwrap(), + tile_names: tile_names.into_inner().unwrap(), + spawn, + } +} + +fn register(db: &RwLock<Vec<String>>, name: String) -> usize { + let mut db = db.write().unwrap(); + if let Some(index) = db.iter().position(|e| e == &name) { + index + } else { + let index = db.len(); + db.push(name); + index + } +} + +impl Gamedata { + pub fn get_tile(&self, name: &str) -> Option<TileIndex> { + self.tile_names.iter().position(|t| t == name) + } +} +impl Action { + pub fn duration(&self) -> f32 { + match self { + Action::Instant | Action::Never => 0., + Action::Passive(x) | Action::Active(x) => *x, + } + } +} |