diff options
Diffstat (limited to 'server/src/data.rs')
-rw-r--r-- | server/src/data.rs | 363 |
1 files changed, 155 insertions, 208 deletions
diff --git a/server/src/data.rs b/server/src/data.rs index 99cbaf9f..f0a85cca 100644 --- a/server/src/data.rs +++ b/server/src/data.rs @@ -20,7 +20,7 @@ use crate::entity::{construct_entity, Entity, EntityDecl}; use anyhow::{anyhow, bail, Result}; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, - ItemIndex, MapMetadata, Recipe, RecipeIndex, TileIndex, + Gamedata, ItemIndex, MapMetadata, Recipe, TileIndex, }; use serde::{Deserialize, Serialize}; use std::{ @@ -99,15 +99,8 @@ pub struct Demand { #[derive(Debug, Clone, Default)] #[rustfmt::skip] -pub struct Gamedata { +pub struct Serverdata { pub spec: String, - pub map_name: String, - pub item_names: Vec<String>, - pub tile_names: Vec<String>, - pub tile_collide: Vec<bool>, - pub tile_interact: Vec<bool>, - pub map: HashMap<String, MapMetadata>, - pub recipes: Vec<Recipe>, pub initial_map: HashMap<IVec2, (TileIndex, Option<ItemIndex>)>, pub chef_spawn: Vec2, pub customer_spawn: Vec2, @@ -151,182 +144,189 @@ impl DataIndex { Ok(read_to_string(path).await?) } - pub async fn generate(&self, spec: String) -> Result<Gamedata> { + pub async fn generate(&self, spec: String) -> Result<(Gamedata, Serverdata)> { let (map, recipes) = spec.split_once("-").unwrap_or((spec.as_str(), "default")); let map_in = serde_yml::from_str(&self.read_map(map).await?)?; let recipes_in = serde_yml::from_str(&self.read_recipes(recipes).await?)?; - let mut gd = Gamedata::build(spec.clone(), map.to_string(), map_in, recipes_in)?; - gd.map = self.maps.clone(); - Ok(gd) + Ok(build_data( + self.maps.clone(), + spec.clone(), + map.to_string(), + map_in, + recipes_in, + )?) } } -impl Gamedata { - pub fn build( - spec: String, - map_name: String, - map_in: InitialMap, - recipes_in: Vec<RecipeDecl>, - ) -> Result<Self> { - let reg = ItemTileRegistry::default(); - let mut recipes = Vec::new(); - let mut entities = Vec::new(); - let mut raw_demands = Vec::new(); +pub fn build_data( + maps: HashMap<String, MapMetadata>, + spec: String, + map_name: String, + map_in: InitialMap, + recipes_in: Vec<RecipeDecl>, +) -> Result<(Gamedata, Serverdata)> { + let reg = ItemTileRegistry::default(); + let mut recipes = Vec::new(); + let mut entities = Vec::new(); + let mut raw_demands = Vec::new(); - for mut r in recipes_in { - let r2 = r.clone(); - let mut inputs = r.inputs.into_iter().map(|i| reg.register_item(i)); - let mut outputs = r.outputs.into_iter().map(|o| reg.register_item(o)); - let tile = r.tile.map(|t| reg.register_tile(t)); - match r.action { - Action::Never => {} - Action::Passive => recipes.push(Recipe::Passive { - duration: r.duration.ok_or(anyhow!("duration for passive missing"))?, - warn: r.warn, + for mut r in recipes_in { + let r2 = r.clone(); + let mut inputs = r.inputs.into_iter().map(|i| reg.register_item(i)); + let mut outputs = r.outputs.into_iter().map(|o| reg.register_item(o)); + let tile = r.tile.map(|t| reg.register_tile(t)); + match r.action { + Action::Never => {} + Action::Passive => recipes.push(Recipe::Passive { + duration: r.duration.ok_or(anyhow!("duration for passive missing"))?, + warn: r.warn, + tile, + revert_duration: r.revert_duration, + input: inputs + .next() + .ok_or(anyhow!("passive recipe without input"))?, + output: outputs.next(), + }), + Action::Active => recipes.push(Recipe::Active { + duration: r.duration.ok_or(anyhow!("duration for active missing"))?, + tile, + input: inputs + .next() + .ok_or(anyhow!("active recipe without input"))?, + outputs: [outputs.next(), outputs.next()], + }), + Action::Instant => { + recipes.push(Recipe::Instant { + points: r.points.take().unwrap_or(0), tile, - revert_duration: r.revert_duration, - input: inputs - .next() - .ok_or(anyhow!("passive recipe without input"))?, - output: outputs.next(), - }), - Action::Active => recipes.push(Recipe::Active { - duration: r.duration.ok_or(anyhow!("duration for active missing"))?, - tile, - input: inputs - .next() - .ok_or(anyhow!("active recipe without input"))?, + inputs: [inputs.next(), inputs.next()], outputs: [outputs.next(), outputs.next()], - }), - Action::Instant => { - recipes.push(Recipe::Instant { - points: r.points.take().unwrap_or(0), - tile, - inputs: [inputs.next(), inputs.next()], - outputs: [outputs.next(), outputs.next()], - }); - } - Action::Demand => raw_demands.push(( - inputs.next().ok_or(anyhow!("demand needs inputs"))?, - outputs.next(), - r.duration.unwrap_or(10.), - )), + }); } - assert_eq!(inputs.next(), None, "{r2:?} inputs left over"); - assert_eq!(outputs.next(), None, "{r2:?} outputs left over"); - assert_eq!(r.points, None, "points specified where not possible") + Action::Demand => raw_demands.push(( + inputs.next().ok_or(anyhow!("demand needs inputs"))?, + outputs.next(), + r.duration.unwrap_or(10.), + )), } + assert_eq!(inputs.next(), None, "{r2:?} inputs left over"); + assert_eq!(outputs.next(), None, "{r2:?} outputs left over"); + assert_eq!(r.points, None, "points specified where not possible") + } - // TODO - // for d in demands_in { - // demands.push(Demand { - // from: reg.register_item(d.from), - // to: d.to.map(|to| reg.register_item(to)), - // duration: d.duration, - // points: d.points, - // }) - // } - - let mut chef_spawn = Vec2::new(0., 0.); - let mut customer_spawn = Vec2::new(0., 0.); - let mut initial_map = HashMap::new(); - let mut tiles_used = HashSet::new(); - let mut items_used = HashSet::new(); - for (y, line) in map_in.map.iter().enumerate() { - for (x, tile) in line.chars().enumerate() { - if tile == ' ' { - continue; // space is empty space - } - let pos = IVec2::new(x as i32, y as i32); - if tile == map_in.chef_spawn { - chef_spawn = pos.as_vec2() + Vec2::splat(0.5); - } - if tile == map_in.customer_spawn { - customer_spawn = pos.as_vec2() + Vec2::splat(0.5); - } - let tilename = map_in - .tiles - .get(&tile) - .ok_or(anyhow!("tile {tile} is undefined"))? - .clone(); + // TODO + // for d in demands_in { + // demands.push(Demand { + // from: reg.register_item(d.from), + // to: d.to.map(|to| reg.register_item(to)), + // duration: d.duration, + // points: d.points, + // }) + // } - let itemname = map_in.items.get(&tile).cloned(); - let tile = reg.register_tile(tilename); - let item = itemname.map(|i| reg.register_item(i)); - tiles_used.insert(tile); - if let Some(i) = item { - items_used.insert(i); - }; - initial_map.insert(pos, (tile, item)); + let mut chef_spawn = Vec2::new(0., 0.); + let mut customer_spawn = Vec2::new(0., 0.); + let mut initial_map = HashMap::new(); + let mut tiles_used = HashSet::new(); + let mut items_used = HashSet::new(); + for (y, line) in map_in.map.iter().enumerate() { + for (x, tile) in line.chars().enumerate() { + if tile == ' ' { + continue; // space is empty space + } + let pos = IVec2::new(x as i32, y as i32); + if tile == map_in.chef_spawn { + chef_spawn = pos.as_vec2() + Vec2::splat(0.5); } + if tile == map_in.customer_spawn { + customer_spawn = pos.as_vec2() + Vec2::splat(0.5); + } + let tilename = map_in + .tiles + .get(&tile) + .ok_or(anyhow!("tile {tile} is undefined"))? + .clone(); + + let itemname = map_in.items.get(&tile).cloned(); + let tile = reg.register_tile(tilename); + let item = itemname.map(|i| reg.register_item(i)); + tiles_used.insert(tile); + if let Some(i) = item { + items_used.insert(i); + }; + initial_map.insert(pos, (tile, item)); } + } - for (y, line) in map_in.map.iter().enumerate() { - for (x, tile) in line.trim().chars().enumerate() { - let pos = IVec2::new(x as i32, y as i32); - if let Some(ent) = map_in.tile_entities.get(&tile) { - entities.push(construct_entity( - Some(pos), - ent, - ®, - &tiles_used, - &items_used, - &raw_demands, - &recipes, - &initial_map, - )?); - } + for (y, line) in map_in.map.iter().enumerate() { + for (x, tile) in line.trim().chars().enumerate() { + let pos = IVec2::new(x as i32, y as i32); + if let Some(ent) = map_in.tile_entities.get(&tile) { + entities.push(construct_entity( + Some(pos), + ent, + ®, + &tiles_used, + &items_used, + &raw_demands, + &recipes, + &initial_map, + )?); } } + } - entities.extend( - map_in - .entities - .iter() - .map(|decl| { - construct_entity( - None, - decl, - ®, - &tiles_used, - &items_used, - &raw_demands, - &recipes, - &initial_map, - ) - }) - .try_collect::<Vec<_>>()?, - ); - - let item_names = reg.items.into_inner().unwrap(); - let tile_names = reg.tiles.into_inner().unwrap(); - let tile_collide = tile_names - .iter() - .map(|i| !map_in.walkable.contains(i)) - .collect(); - let tile_interact = tile_names + entities.extend( + map_in + .entities .iter() - .map(|i| !map_in.collider.contains(i) && !map_in.walkable.contains(i)) - .collect(); + .map(|decl| { + construct_entity( + None, + decl, + ®, + &tiles_used, + &items_used, + &raw_demands, + &recipes, + &initial_map, + ) + }) + .try_collect::<Vec<_>>()?, + ); - Ok(Gamedata { - spec, + let item_names = reg.items.into_inner().unwrap(); + let tile_names = reg.tiles.into_inner().unwrap(); + let tile_collide = tile_names + .iter() + .map(|i| !map_in.walkable.contains(i)) + .collect(); + let tile_interact = tile_names + .iter() + .map(|i| !map_in.collider.contains(i) && !map_in.walkable.contains(i)) + .collect(); + + Ok(( + Gamedata { + current_map: map_name, + maps, tile_collide, - map_name, tile_interact, recipes, - score_baseline: map_in.score_baseline, - map: HashMap::new(), - initial_map, item_names, - entities, tile_names, + }, + Serverdata { + spec, + initial_map, chef_spawn, customer_spawn, - }) - } + score_baseline: map_in.score_baseline, + entities, + }, + )) } #[derive(Default)] @@ -353,56 +353,3 @@ impl ItemTileRegistry { } } } - -impl Gamedata { - pub fn tile_name(&self, index: TileIndex) -> &String { - &self.tile_names[index.0] - } - pub fn is_tile_colliding(&self, index: TileIndex) -> bool { - self.tile_collide[index.0] - } - pub fn is_tile_interactable(&self, index: TileIndex) -> bool { - self.tile_interact[index.0] - } - pub fn item_name(&self, index: ItemIndex) -> &String { - &self.item_names[index.0] - } - pub fn recipe(&self, index: RecipeIndex) -> &Recipe { - &self.recipes[index.0] - } - pub fn get_tile_by_name(&self, name: &str) -> Option<TileIndex> { - self.tile_names - .iter() - .position(|t| t == name) - .map(TileIndex) - } - pub fn get_item_by_name(&self, name: &str) -> Option<ItemIndex> { - self.item_names - .iter() - .position(|t| t == name) - .map(ItemIndex) - } - pub fn recipes(&self) -> impl Iterator<Item = (RecipeIndex, &Recipe)> { - self.recipes - .iter() - .enumerate() - .map(|(i, e)| (RecipeIndex(i), e)) - } -} -/* - Hurry Curry! - a game about cooking - Copyright 2024 metamuffin - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, version 3 of the License only. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. - -*/ |