diff options
| -rw-r--r-- | data/recipes.yaml | 8 | ||||
| -rw-r--r-- | server/src/game.rs | 98 | ||||
| -rw-r--r-- | server/src/interaction.rs | 64 | ||||
| -rw-r--r-- | server/src/protocol.rs | 4 | ||||
| -rw-r--r-- | server/src/recipes.rs | 6 | ||||
| -rw-r--r-- | test-client/main.ts | 4 | 
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) { |