aboutsummaryrefslogtreecommitdiff
path: root/server/tools/src/recipe_diagram.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-10-06 23:03:32 +0200
committermetamuffin <metamuffin@disroot.org>2025-10-06 23:03:40 +0200
commit176e6bc6c4c29bea3be2aceca99743b997c76c97 (patch)
tree1161e7a966843324756340da4b6452492902fa07 /server/tools/src/recipe_diagram.rs
parentea86b11b682500160f37b35ea8f06b081cd05036 (diff)
downloadhurrycurry-176e6bc6c4c29bea3be2aceca99743b997c76c97.tar
hurrycurry-176e6bc6c4c29bea3be2aceca99743b997c76c97.tar.bz2
hurrycurry-176e6bc6c4c29bea3be2aceca99743b997c76c97.tar.zst
Move data code to own crate + general data refactor
Diffstat (limited to 'server/tools/src/recipe_diagram.rs')
-rw-r--r--server/tools/src/recipe_diagram.rs239
1 files changed, 0 insertions, 239 deletions
diff --git a/server/tools/src/recipe_diagram.rs b/server/tools/src/recipe_diagram.rs
deleted file mode 100644
index 0be75433..00000000
--- a/server/tools/src/recipe_diagram.rs
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- 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 anyhow::Result;
-use hurrycurry_protocol::{
- Gamedata, ItemIndex, Message, Recipe, RecipeIndex,
- book::{Diagram, DiagramEdge, DiagramNode, NodeStyle},
- glam::Vec2,
-};
-use hurrycurry_server::data::Serverdata;
-use std::{
- cmp::Reverse,
- collections::{BTreeMap, BTreeSet, HashSet},
-};
-
-pub(crate) fn recipe_diagram(
- data: &Gamedata,
- serverdata: &Serverdata,
- target_items: &[&str],
-) -> Result<Diagram> {
- let ambient_items = serverdata
- .initial_map
- .iter()
- .flat_map(|(_, (_, item))| item)
- .copied()
- .collect::<HashSet<_>>();
-
- let mut need = BTreeSet::from_iter(
- target_items
- .iter()
- .map(|name| data.get_item_by_name(name).unwrap()),
- );
- let mut have = BTreeSet::<ItemIndex>::new();
- let mut recipes = BTreeSet::new();
-
- #[derive(PartialEq, PartialOrd, Eq, Ord)]
- struct GraphRecipe {
- index: RecipeIndex,
- inputs: Vec<ItemIndex>,
- outputs: Vec<ItemIndex>,
- }
-
- while let Some(item) = need.pop_last() {
- for (ri, r) in data.recipes() {
- if r.outputs().contains(&item) {
- let gr = GraphRecipe {
- inputs: r
- .inputs()
- .iter()
- .filter(|i| !ambient_items.contains(i))
- .copied()
- .collect(),
- outputs: r
- .outputs()
- .iter()
- .filter(|i| !ambient_items.contains(i))
- .copied()
- .collect(),
- index: ri,
- };
- need.extend(gr.inputs.iter().filter(|i| !have.contains(&i)));
- have.extend(&gr.outputs);
- recipes.insert(gr);
- }
- }
- }
-
- let mut diag = Diagram::default();
- let mut item_index = BTreeMap::new();
- for i in have {
- item_index.insert(i, diag.nodes.len());
- diag.nodes.push(DiagramNode {
- label: Message::Item(i),
- position: Vec2::ZERO,
- style: if target_items.contains(&data.item_name(i)) {
- NodeStyle::FinalProduct
- } else {
- NodeStyle::IntermediateProduct
- },
- });
- }
- for r in recipes {
- let index = diag.nodes.len();
- let recipe = data.recipe(r.index);
-
- if matches!(recipe, Recipe::Instant { .. }) && r.inputs.len() >= 1 && r.outputs.len() >= 1 {
- for i in r.inputs {
- diag.edges.push(DiagramEdge {
- src: item_index[&i],
- dst: item_index[&r.outputs[0]],
- label: None,
- });
- }
- continue;
- }
- if matches!(recipe, Recipe::Passive { tile: None, .. })
- && r.inputs.len() == 1
- && r.outputs.len() == 1
- {
- diag.nodes[item_index[&r.inputs[0]]].style = NodeStyle::ProcessPassive;
- diag.edges.push(DiagramEdge {
- src: item_index[&r.inputs[0]],
- dst: item_index[&r.outputs[0]],
- label: None,
- });
- continue;
- }
-
- let (kind, style) = match recipe {
- Recipe::Passive { .. } => ("Passive", NodeStyle::ProcessPassive),
- Recipe::Active { .. } => ("Active", NodeStyle::ProcessActive),
- Recipe::Instant { .. } => ("Instant", NodeStyle::ProcessInstant),
- };
- diag.nodes.push(DiagramNode {
- position: Vec2::ZERO,
- label: if let Some(tile) = recipe.tile() {
- Message::Tile(tile)
- } else {
- Message::Text(kind.to_string())
- },
- style,
- });
-
- for i in r.inputs {
- diag.edges.push(DiagramEdge {
- src: item_index[&i],
- dst: index,
- label: None,
- });
- }
- for o in r.outputs {
- diag.edges.push(DiagramEdge {
- src: index,
- dst: item_index[&o],
- label: None,
- });
- }
- }
-
- merge_combine_clusters(&mut diag);
- remove_orphan_nodes(&mut diag);
-
- Ok(diag)
-}
-
-fn merge_combine_clusters(diag: &mut Diagram) {
- let instant_nodes = diag
- .nodes
- .iter()
- .enumerate()
- .filter(|(_, n)| matches!(n.style, NodeStyle::IntermediateProduct))
- .map(|(i, _)| i)
- .collect::<Vec<_>>();
-
- for ni in instant_nodes {
- let inputs = diag
- .edges
- .iter()
- .enumerate()
- .filter(|(_, e)| e.dst == ni)
- .map(|(i, e)| (i, e.src))
- .collect::<Vec<_>>();
- let outputs = diag
- .edges
- .iter()
- .enumerate()
- .filter(|(_, e)| e.src == ni)
- .map(|(i, e)| (i, e.dst))
- .collect::<Vec<_>>();
-
- if outputs
- .iter()
- .all(|&(_, ni)| diag.nodes[ni].style.is_procuct())
- && inputs
- .iter()
- .all(|&(_, ni)| diag.nodes[ni].style.is_procuct())
- {
- let mut to_remove = inputs
- .iter()
- .map(|&(i, _)| i)
- .chain(outputs.iter().map(|&(i, _)| i))
- .collect::<Vec<_>>();
- to_remove.sort_by_key(|x| Reverse(*x));
- for i in to_remove {
- diag.edges.remove(i);
- }
-
- for &input in &inputs {
- for &output in &outputs {
- if !diag
- .edges
- .iter()
- .any(|e| e.src == input.1 && e.dst == output.1)
- {
- diag.edges.push(DiagramEdge {
- src: input.1,
- dst: output.1,
- label: None,
- });
- }
- }
- }
- }
- }
-}
-
-fn remove_orphan_nodes(diag: &mut Diagram) {
- let mut to_remove = diag
- .nodes
- .iter()
- .enumerate()
- .filter(|&(i, _)| !diag.edges.iter().any(|e| e.src == i || e.dst == i))
- .map(|(i, _)| i)
- .collect::<Vec<_>>();
- to_remove.sort_by_key(|x| Reverse(*x));
-
- for e in &mut diag.edges {
- e.src -= to_remove.iter().filter(|&&i| i < e.src).count();
- e.dst -= to_remove.iter().filter(|&&i| i < e.dst).count();
- }
- for i in to_remove {
- diag.nodes.remove(i);
- }
-}