diff options
Diffstat (limited to 'server/src/data')
-rw-r--r-- | server/src/data/mod.rs | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/server/src/data/mod.rs b/server/src/data/mod.rs index 17ebd5bf..1fab912a 100644 --- a/server/src/data/mod.rs +++ b/server/src/data/mod.rs @@ -19,6 +19,7 @@ pub mod demands; use crate::entity::{construct_entity, Entities, EntityDecl}; use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use demands::generate_demands; use hurrycurry_bot::algos::ALGO_CONSTRUCTORS; use hurrycurry_protocol::{ @@ -28,7 +29,7 @@ use hurrycurry_protocol::{ }; use serde::{Deserialize, Serialize}; use std::{ - collections::{BTreeMap, HashMap, HashSet}, + collections::{BTreeMap, BTreeSet, HashMap, HashSet}, fs::{read_to_string, File}, path::PathBuf, str::FromStr, @@ -63,22 +64,35 @@ pub struct RecipeDecl { #[rustfmt::skip] #[derive(Debug, Clone, Deserialize)] pub struct MapDecl { - #[serde(default)] recipes: Option<String>, map: Vec<String>, tiles: HashMap<char, String>, - #[serde(default)] items: HashMap<char, String>, - collider: Vec<String>, - walkable: Vec<String>, - chef_spawn: char, - customer_spawn: char, + #[serde(default)] recipes: Option<String>, #[serde(default)] hand_count: Option<usize>, #[serde(default)] entities: Vec<EntityDecl>, - #[serde(default)] tile_entities: HashMap<char, EntityDecl>, #[serde(default)] score_baseline: i64, #[serde(default)] default_timer: Option<u64>, #[serde(default)] flags: ServerdataFlags, } +#[derive(Parser)] +struct TileArgs { + tile_name: String, + #[clap(short = 'c', long)] + collider: bool, + #[clap(short = 'x', long)] + exclusive: bool, + #[clap(short = 'w', long)] + walkable: bool, + #[clap(long)] + book: bool, + #[clap(long)] + chef_spawn: bool, + #[clap(long)] + customer_spawn: bool, + #[clap(short = 'i', long)] + item: Option<String>, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DemandDecl { from: String, @@ -92,7 +106,7 @@ pub struct DemandDecl { pub struct Serverdata { pub initial_map: HashMap<IVec2, (TileIndex, Option<ItemIndex>)>, pub chef_spawn: Vec2, - pub customer_spawn: Vec2, + pub customer_spawn: Option<Vec2>, pub score_baseline: i64, pub default_timer: Option<Duration>, pub book: Book, @@ -240,48 +254,53 @@ pub fn build_data( assert_eq!(r.points, None, "points specified where not possible") } - let mut chef_spawn = Vec2::new(0., 0.); - let mut customer_spawn = Vec2::new(0., 0.); + let mut chef_spawn = None; + let mut customer_spawn = None; let mut initial_map = HashMap::new(); let mut tiles_used = HashSet::new(); let mut items_used = HashSet::new(); + let mut tile_walkable = HashSet::new(); + let mut exclusive_tiles = BTreeSet::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 + + let tile_spec = map_in .tiles .get(&tile) .ok_or(anyhow!("tile {tile} is undefined"))? .clone(); + let mut toks = shlex::split(&tile_spec).ok_or(anyhow!("tile spec quoting invalid"))?; + toks.insert(0, "tile-spec".to_string()); // exe name + let tile_spec = TileArgs::try_parse_from(toks)?; - let itemname = map_in.items.get(&tile).cloned(); - let tile = reg.register_tile(tilename); - let item = itemname.map(|i| reg.register_item(i)); + let tile = reg.register_tile(tile_spec.tile_name); tiles_used.insert(tile); - if let Some(i) = item { - items_used.insert(i); - }; + let item = tile_spec.item.map(|i| reg.register_item(i)); + items_used.extend(item); 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, ®)?); + if tile_spec.chef_spawn { + chef_spawn = Some(pos.as_vec2() + Vec2::splat(0.5)); + } + if tile_spec.customer_spawn { + customer_spawn = Some(pos.as_vec2() + Vec2::splat(0.5)); + } + if tile_spec.book { + entities.push(construct_entity(Some(pos), &EntityDecl::Book, ®)?); + } + if tile_spec.walkable { + tile_walkable.insert(tile); + } + if tile_spec.walkable || tile_spec.collider || tile_spec.exclusive { + exclusive_tiles.insert(tile); } } } + let chef_spawn = chef_spawn.ok_or(anyhow!("map has no chef spawn"))?; entities.extend( map_in @@ -308,8 +327,7 @@ pub fn build_data( let mut tile_placeable_items = BTreeMap::new(); let mut tile_interactable_empty = HashSet::new(); - for tile_name in map_in.collider.iter().chain(map_in.walkable.iter()) { - let tile = reg.register_tile(tile_name.to_string()); + for tile in exclusive_tiles { let whitelist = recipes .iter() .filter(|r| r.tile() == Some(tile)) @@ -323,11 +341,6 @@ pub fn build_data( tile_interactable_empty.insert(tile); } } - let tile_walkable = map_in - .walkable - .into_iter() - .map(|name| reg.register_tile(name)) - .collect(); let item_names = reg.items.into_inner().unwrap(); let tile_names = reg.tiles.into_inner().unwrap(); |