aboutsummaryrefslogtreecommitdiff
path: root/server/src/data.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-08-13 12:48:31 +0200
committermetamuffin <metamuffin@disroot.org>2024-08-13 16:03:38 +0200
commit16ff78180669411326d42ea32d4a9260c018236c (patch)
treed7c6a7ab498bb1b4f9a3b3db99d54e8781216e05 /server/src/data.rs
parent11ff74f034aeec58c06dbe15a3f1ee650ef18c9f (diff)
downloadhurrycurry-16ff78180669411326d42ea32d4a9260c018236c.tar
hurrycurry-16ff78180669411326d42ea32d4a9260c018236c.tar.bz2
hurrycurry-16ff78180669411326d42ea32d4a9260c018236c.tar.zst
refactor server to use client-lib data model (breaks customers)
Diffstat (limited to 'server/src/data.rs')
-rw-r--r--server/src/data.rs363
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,
- &reg,
- &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,
+ &reg,
+ &tiles_used,
+ &items_used,
+ &raw_demands,
+ &recipes,
+ &initial_map,
+ )?);
}
}
+ }
- entities.extend(
- map_in
- .entities
- .iter()
- .map(|decl| {
- construct_entity(
- None,
- decl,
- &reg,
- &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,
+ &reg,
+ &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/>.
-
-*/