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, +        } +    } +} | 
