diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-10-10 15:27:17 +0200 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-10-10 15:27:17 +0200 |
| commit | d13b63d21a35318d6a756b70f6423750268a3831 (patch) | |
| tree | 2e2cd5af6d8b9c826db1aaee87b5d95de83073f6 /server/data/src | |
| parent | 7fde38f7eb4f3a1320080e8ce2a455deea8b24ef (diff) | |
| download | hurrycurry-d13b63d21a35318d6a756b70f6423750268a3831.tar hurrycurry-d13b63d21a35318d6a756b70f6423750268a3831.tar.bz2 hurrycurry-d13b63d21a35318d6a756b70f6423750268a3831.tar.zst | |
Filter unused items and tiles from gamedata (close #449)
Diffstat (limited to 'server/data/src')
| -rw-r--r-- | server/data/src/lib.rs | 103 | ||||
| -rw-r--r-- | server/data/src/registry.rs | 199 |
2 files changed, 237 insertions, 65 deletions
diff --git a/server/data/src/lib.rs b/server/data/src/lib.rs index d316d0b7..a5e8ac68 100644 --- a/server/data/src/lib.rs +++ b/server/data/src/lib.rs @@ -20,6 +20,7 @@ pub mod book; pub mod entities; pub mod filter_demands; pub mod index; +pub mod registry; use anyhow::{Result, anyhow, bail}; use clap::Parser; @@ -33,11 +34,13 @@ use log::debug; use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeMap, BTreeSet, HashMap, HashSet}, - sync::RwLock, time::Duration, }; -use crate::entities::EntityDecl; +use crate::{ + entities::EntityDecl, + registry::{ItemTileRegistry, filter_unused_tiles_and_items}, +}; #[derive(Debug, Deserialize, Serialize, Clone, Copy, Default)] #[serde(rename_all = "snake_case")] @@ -241,13 +244,7 @@ fn build_data( } } - let item_names = reg.items.into_inner().unwrap(); - let tile_names = reg.tiles.into_inner().unwrap(); - debug!( - "{} items and {} tiles registered", - item_names.len(), - tile_names.len() - ); + let (item_names, tile_names) = reg.finish(); let default_timer = if map_name.ends_with("lobby") { None @@ -255,37 +252,38 @@ fn build_data( Some(Duration::from_secs(map_in.default_timer.unwrap_or(420))) }; - Ok(( - Gamedata { - current_map: map_name, - maps, - tile_walkable, - tile_placeable_items, - tile_interactable_empty, - recipes, - item_names, - demands, - tile_names, - bot_algos: vec![ - "waiter".to_string(), - "simple".to_string(), - "dishwasher".to_string(), - "frank".to_string(), - ], - hand_count: map_in.hand_count.unwrap_or(1), - }, - Serverdata { - initial_map, - chef_spawn, - flags: map_in.flags, - customer_spawn, - default_timer, - book: Book::default(), - score_baseline: map_in.score_baseline, - entity_decls: entities, - recipe_groups, - }, - )) + let mut data = Gamedata { + current_map: map_name, + maps, + tile_walkable, + tile_placeable_items, + tile_interactable_empty, + recipes, + item_names, + demands, + tile_names, + bot_algos: vec![ + "waiter".to_string(), + "simple".to_string(), + "dishwasher".to_string(), + "frank".to_string(), + ], + hand_count: map_in.hand_count.unwrap_or(1), + }; + let mut serverdata = Serverdata { + initial_map, + chef_spawn, + flags: map_in.flags, + customer_spawn, + default_timer, + book: Book::default(), + score_baseline: map_in.score_baseline, + entity_decls: entities, + recipe_groups, + }; + filter_unused_tiles_and_items(&mut data, &mut serverdata); + + Ok((data, serverdata)) } fn load_recipes( @@ -362,28 +360,3 @@ fn load_recipes( Ok((recipes, demands, recipe_groups)) } - -#[derive(Default)] -pub(crate) struct ItemTileRegistry { - tiles: RwLock<Vec<String>>, - items: RwLock<Vec<String>>, -} - -impl ItemTileRegistry { - pub fn register_tile(&self, name: String) -> TileIndex { - TileIndex(Self::register(&self.tiles, name)) - } - pub fn register_item(&self, name: String) -> ItemIndex { - ItemIndex(Self::register(&self.items, name)) - } - 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 - } - } -} diff --git a/server/data/src/registry.rs b/server/data/src/registry.rs new file mode 100644 index 00000000..7d56567d --- /dev/null +++ b/server/data/src/registry.rs @@ -0,0 +1,199 @@ +/* + Hurry Curry! - a game about cooking + Copyright (C) 2025 Hurry Curry! Contributors + + 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/>. + +*/ + +use hurrycurry_protocol::{Gamedata, ItemIndex, Recipe, TileIndex}; +use log::debug; +use std::{ + collections::{BTreeSet, HashMap}, + sync::RwLock, +}; + +use crate::Serverdata; + +#[derive(Default)] +pub(crate) struct ItemTileRegistry { + tiles: RwLock<Vec<String>>, + items: RwLock<Vec<String>>, +} + +impl ItemTileRegistry { + pub fn register_tile(&self, name: String) -> TileIndex { + TileIndex(Self::register(&self.tiles, name)) + } + pub fn register_item(&self, name: String) -> ItemIndex { + ItemIndex(Self::register(&self.items, name)) + } + fn register(db: &RwLock<Vec<String>>, name: String) -> usize { + let mut db = db.write().unwrap(); + // TODO maybe btreemap for better time complexity + if let Some(index) = db.iter().position(|e| e == &name) { + index + } else { + let index = db.len(); + db.push(name); + index + } + } + pub fn finish(self) -> (Vec<String>, Vec<String>) { + ( + self.items.into_inner().unwrap(), + self.tiles.into_inner().unwrap(), + ) + } +} + +pub(crate) fn filter_unused_tiles_and_items(data: &mut Gamedata, serverdata: &mut Serverdata) { + debug!("running unused item/tile filter"); + let mut used_items = BTreeSet::new(); + let mut used_tiles = BTreeSet::new(); + + for recipe in &data.recipes { + used_items.extend(recipe.inputs()); + used_items.extend(recipe.outputs()); + used_tiles.extend(recipe.tile()); + } + for demand in &data.demands { + used_items.insert(demand.input); + used_items.extend(demand.output); + } + for rg in serverdata.recipe_groups.values() { + used_items.extend(rg); + } + for &(tile, item) in serverdata.initial_map.values() { + used_tiles.insert(tile); + used_items.extend(item); + } + + let mut item_names = Vec::new(); + let mut item_map = HashMap::new(); + for item in used_items { + item_map.insert(item, ItemIndex(item_names.len())); + item_names.push(data.item_name(item).to_string()); + } + + let mut tile_names = Vec::new(); + let mut tile_map = HashMap::new(); + for tile in used_tiles { + tile_map.insert(tile, TileIndex(tile_names.len())); + tile_names.push(data.tile_name(tile).to_string()); + } + + debug!( + "removing {} items and {} tiles from registry", + data.item_names.len() - item_names.len(), + data.tile_names.len() - tile_names.len() + ); + + data.item_names = item_names; + data.tile_names = tile_names; + + for recipe in &mut data.recipes { + match recipe { + Recipe::Passive { + tile, + input, + output, + .. + } => { + if let Some(tile) = tile { + *tile = tile_map[tile] + } + *input = item_map[input]; + if let Some(output) = output { + *output = item_map[output]; + } + } + Recipe::Active { + tile, + input, + outputs, + .. + } => { + if let Some(tile) = tile { + *tile = tile_map[tile] + } + *input = item_map[input]; + for output in outputs { + if let Some(output) = output { + *output = item_map[output]; + } + } + } + Recipe::Instant { + tile, + inputs, + outputs, + .. + } => { + if let Some(tile) = tile { + *tile = tile_map[tile] + } + for input in inputs { + if let Some(input) = input { + *input = item_map[input]; + } + } + for output in outputs { + if let Some(output) = output { + *output = item_map[output]; + } + } + } + } + } + for demand in &mut data.demands { + demand.input = item_map[&demand.input]; + if let Some(output) = &mut demand.output { + *output = item_map[output]; + } + } + for rg in serverdata.recipe_groups.values_mut() { + *rg = rg.clone().into_iter().map(|e| item_map[&e]).collect(); + } + for (tile, item) in serverdata.initial_map.values_mut() { + *tile = tile_map[tile]; + if let Some(item) = item { + *item = item_map[item] + } + } + data.tile_walkable = data + .tile_walkable + .clone() + .into_iter() + .map(|e| tile_map[&e]) + .collect(); + data.tile_interactable_empty = data + .tile_interactable_empty + .clone() + .into_iter() + .map(|e| tile_map[&e]) + .collect(); + data.tile_placeable_items = data + .tile_placeable_items + .clone() + .into_iter() + .map(|(tile, items)| { + ( + tile_map[&tile], + items.into_iter().map(|i| item_map[&i]).collect(), + ) + }) + .collect(); + + debug!("done") +} |