/*
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 .
*/
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>,
items: RwLock>,
}
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>, 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, Vec) {
(
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")
}