summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-17 23:41:25 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-23 19:20:50 +0200
commita99aa006599827ea999a5684e40635175c8d790a (patch)
tree1b36a73833d3a87384e7bbfb379c4adceb72cd27
parent6f0424b9b4cddc0495eb673d314c570e27e61e83 (diff)
downloadhurrycurry-a99aa006599827ea999a5684e40635175c8d790a.tar
hurrycurry-a99aa006599827ea999a5684e40635175c8d790a.tar.bz2
hurrycurry-a99aa006599827ea999a5684e40635175c8d790a.tar.zst
a
-rw-r--r--data/recipes.yaml8
-rw-r--r--server/src/game.rs98
-rw-r--r--server/src/interaction.rs64
-rw-r--r--server/src/protocol.rs4
-rw-r--r--server/src/recipes.rs6
-rw-r--r--test-client/main.ts4
6 files changed, 134 insertions, 50 deletions
diff --git a/data/recipes.yaml b/data/recipes.yaml
index de8de444..46ac8b15 100644
--- a/data/recipes.yaml
+++ b/data/recipes.yaml
@@ -1,10 +1,16 @@
- tile: floor
action: !never # tomato pipeline
+
- tile: meat-spawn
action: !instant
- outputs: [raw-meat]
+ outputs: [raw-steak]
+
+- tile: trash
+ action: !instant
+ inputs: [raw-steak]
+- { tile: table, inputs: [raw-steak, void] }
- tile: table
inputs: [tomato]
diff --git a/server/src/game.rs b/server/src/game.rs
index a7a07881..3b16cc05 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -1,20 +1,27 @@
use crate::{
- protocol::{ItemID, ItemIndex, PacketC, PacketS, PlayerID, TileIndex},
+ interaction::{interact, Out},
+ protocol::{ItemID, ItemIndex, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex},
recipes::Gamedata,
};
use anyhow::{anyhow, Result};
use glam::IVec2;
+use log::info;
use std::{
collections::{HashMap, VecDeque},
ops::Deref,
sync::Arc,
};
+pub struct ActiveRecipe {
+ pub recipe: RecipeIndex,
+ pub progress: f32,
+ pub working: usize,
+}
+
pub struct Tile {
kind: TileIndex,
items: Vec<ItemID>,
- active: bool,
- progress: f32,
+ active: Option<ActiveRecipe>,
}
struct Player {
@@ -69,17 +76,13 @@ impl Game {
}
g.tiles.extend(
- [([-5, 1], "pan"), ([-5, 2], "pan"), ([4, 3], "meat-spawn")].map(|(k, v)| {
- (
- IVec2::from_array(k),
- Tile {
- active: false,
- items: vec![],
- kind: gamedata.get_tile(v).unwrap().into(),
- progress: 0.,
- },
- )
- }),
+ [
+ ([-5, 1], "pan"),
+ ([-5, 2], "pan"),
+ ([4, 3], "meat-spawn"),
+ ([4, 1], "trash"),
+ ]
+ .map(|(k, v)| (IVec2::from_array(k), gamedata.get_tile(v).unwrap().into())),
);
g
@@ -150,19 +153,59 @@ impl Game {
.push_back(PacketC::Position { player, pos, rot });
}
PacketS::Interact { pos, edge } => {
+ let pid = player;
+ let player = self
+ .players
+ .get_mut(&player)
+ .ok_or(anyhow!("player does not exist"))?;
+ let tile = self
+ .tiles
+ .get_mut(&pos)
+ .ok_or(anyhow!("tile does not exist"))?;
+
+ let items = tile.items.iter().map(|e| self.items[e]).collect::<Vec<_>>();
+ let tilekind = tile.kind;
+ let hand = player.hand.map(|e| self.items[&e]);
- // if let Some(item) = player_data.hand.take() {
- // info!("put {item}");
- // tile.items.push(item);
- // self.packet_out.push_back(PacketC::PutItem { item, pos })
- // } else {
- // if let Some(item) = tile.items.pop() {
- // info!("take {item}");
- // player_data.hand = Some(item);
- // self.packet_out
- // .push_back(PacketC::TakeItem { item, player })
- // }
- // }
+ interact(
+ &self.data,
+ edge,
+ tilekind,
+ &mut tile.active,
+ items,
+ hand,
+ |out| match out {
+ Out::Take(index) => {
+ info!("take");
+ let item = tile.items.remove(index);
+ player.hand = Some(item);
+ self.packet_out
+ .push_back(PacketC::TakeItem { item, player: pid })
+ }
+ Out::Put => {
+ info!("put");
+ let hand = player.hand.take().unwrap();
+ tile.items.push(hand);
+ self.packet_out
+ .push_back(PacketC::PutItem { item: hand, pos })
+ }
+ Out::Produce(kind) => {
+ info!("produce");
+ let id = self.item_id_counter;
+ self.item_id_counter += 1;
+ self.items.insert(id, kind);
+ tile.items.push(id);
+ self.packet_out
+ .push_back(PacketC::ProduceItem { id, pos, kind });
+ }
+ Out::Consume(index) => {
+ info!("consume");
+ let id = tile.items.remove(index);
+ info!("left {:?}", tile.items);
+ self.packet_out.push_back(PacketC::ConsumeItem { id, pos });
+ }
+ },
+ );
}
}
Ok(())
@@ -173,9 +216,8 @@ impl From<TileIndex> for Tile {
fn from(kind: TileIndex) -> Self {
Self {
kind,
- progress: 0.,
- active: false,
items: vec![],
+ active: None,
}
}
}
diff --git a/server/src/interaction.rs b/server/src/interaction.rs
index 5f8b0097..7ef4a9b4 100644
--- a/server/src/interaction.rs
+++ b/server/src/interaction.rs
@@ -1,8 +1,11 @@
use crate::{
+ game::ActiveRecipe,
protocol::{ItemIndex, TileIndex},
recipes::{Action, Gamedata},
};
+use log::{debug, info};
use std::collections::BTreeSet;
+use Out::*;
pub enum Out {
Take(usize),
@@ -10,14 +13,14 @@ pub enum Out {
Produce(ItemIndex),
Consume(usize),
}
-use Out::*;
pub fn interact(
data: &Gamedata,
edge: bool,
tile: TileIndex,
- items: &[ItemIndex],
- hand: &Option<ItemIndex>,
+ active: &mut Option<ActiveRecipe>,
+ mut items: Vec<ItemIndex>,
+ mut hand: Option<ItemIndex>,
mut out: impl FnMut(Out),
) {
let mut allowed = BTreeSet::new();
@@ -27,28 +30,52 @@ pub fn interact(
}
}
if !edge {
+ if let Some(ac) = active {
+ if matches!(data.recipes[ac.recipe].action, Action::Active(_)) {
+ ac.working -= 1;
+ }
+ }
return;
}
- let mut put_item = None;
- if let Some(hand) = hand {
- if allowed.contains(hand) {
+ if let Some(hi) = hand {
+ if allowed.contains(&hi) {
out(Put);
- put_item = Some(*hand);
+ items.push(hi);
+ hand = None;
}
}
- for r in &data.recipes {
- let ok = r
- .inputs
- .iter()
- .all(|e| items.contains(e) || put_item == Some(*e))
- && r.inputs.len() == items.len();
- if ok {
+ if hand.is_none() {
+ 'rloop: for (ri, r) in data.recipes.iter().enumerate() {
+ if tile != r.tile {
+ continue;
+ }
+ let mut inputs = r.inputs.clone();
+ for i in &items {
+ debug!("take {i:?} {inputs:?}");
+ let Some(pos) = inputs.iter().position(|e| e == i) else {
+ continue 'rloop;
+ };
+ inputs.remove(pos);
+ }
+ debug!("end {inputs:?}");
+ if !inputs.is_empty() {
+ continue;
+ }
+
match r.action {
- Action::Passive(_) => todo!(),
- Action::Active(_) => todo!(),
+ Action::Passive(_) => {
+ *active = Some(ActiveRecipe {
+ recipe: ri,
+ progress: 0.,
+ working: 0,
+ });
+ break 'rloop;
+ }
+ Action::Active(_) => {}
Action::Instant => {
+ info!("use recipe {r:?}");
for i in 0..items.len() {
out(Consume(i))
}
@@ -58,9 +85,14 @@ pub fn interact(
if !r.outputs.is_empty() {
out(Take(r.outputs.len() - 1));
}
+ break 'rloop;
}
Action::Never => (),
}
}
}
+
+ if !items.is_empty() && hand.is_none() {
+ out(Take(items.len() - 1));
+ }
}
diff --git a/server/src/protocol.rs b/server/src/protocol.rs
index ae87ffb4..fa34954b 100644
--- a/server/src/protocol.rs
+++ b/server/src/protocol.rs
@@ -1,12 +1,12 @@
+use crate::recipes::Gamedata;
use glam::{IVec2, Vec2};
use serde::{Deserialize, Serialize};
-use crate::recipes::Gamedata;
-
pub type PlayerID = usize;
pub type ItemID = usize;
pub type ItemIndex = usize;
pub type TileIndex = usize;
+pub type RecipeIndex = usize;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
diff --git a/server/src/recipes.rs b/server/src/recipes.rs
index 25a4be98..11c455ba 100644
--- a/server/src/recipes.rs
+++ b/server/src/recipes.rs
@@ -1,13 +1,14 @@
use crate::protocol::{ItemIndex, TileIndex};
use serde::{Deserialize, Serialize};
-#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
+#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default)]
#[serde(rename_all = "snake_case")]
pub enum Action {
+ #[default]
+ Never,
Passive(f32),
Active(f32),
Instant,
- Never,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
@@ -17,6 +18,7 @@ pub struct Recipe<T = TileIndex, I = ItemIndex> {
pub inputs: Vec<I>,
#[serde(default)]
pub outputs: Vec<I>,
+ #[serde(default)]
pub action: Action,
}
diff --git a/test-client/main.ts b/test-client/main.ts
index 5f4475f2..6622d37f 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -75,7 +75,9 @@ function packet(p: PacketC) {
items.set(p.produce_item.id, { kind: p.produce_item.kind, x: p.produce_item.pos[0] + 0.5, y: p.produce_item.pos[1] + 0.5, tracking_player: false, tile: { x: p.produce_item.pos[0], y: p.produce_item.pos[1] } })
tiles.get(p.produce_item.pos.toString())!.items.push(p.produce_item.id)
} else if ("consume_item" in p) {
- // TODO
+ const t = tiles.get(p.consume_item.pos.toString())!
+ t.items.splice(t.items.indexOf(p.consume_item.id))
+ items.delete(p.consume_item.id)
} else if ("set_active" in p) {
// TODO
} else if ("update_map" in p) {