aboutsummaryrefslogtreecommitdiff
path: root/server/data
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-10-10 15:27:17 +0200
committermetamuffin <metamuffin@disroot.org>2025-10-10 15:27:17 +0200
commitd13b63d21a35318d6a756b70f6423750268a3831 (patch)
tree2e2cd5af6d8b9c826db1aaee87b5d95de83073f6 /server/data
parent7fde38f7eb4f3a1320080e8ce2a455deea8b24ef (diff)
downloadhurrycurry-d13b63d21a35318d6a756b70f6423750268a3831.tar
hurrycurry-d13b63d21a35318d6a756b70f6423750268a3831.tar.bz2
hurrycurry-d13b63d21a35318d6a756b70f6423750268a3831.tar.zst
Filter unused items and tiles from gamedata (close #449)
Diffstat (limited to 'server/data')
-rw-r--r--server/data/src/lib.rs103
-rw-r--r--server/data/src/registry.rs199
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")
+}