diff options
author | metamuffin <metamuffin@disroot.org> | 2024-06-18 19:36:36 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-06-23 19:21:22 +0200 |
commit | 48934ff63ee14d4759eda36512af87361dd915dd (patch) | |
tree | f7a80115eacfee7b6871040a87f5fb0087098ea8 /server/src | |
parent | 6ec47d729509db83eaeb6a9d855ce2483d70f227 (diff) | |
download | hurrycurry-48934ff63ee14d4759eda36512af87361dd915dd.tar hurrycurry-48934ff63ee14d4759eda36512af87361dd915dd.tar.bz2 hurrycurry-48934ff63ee14d4759eda36512af87361dd915dd.tar.zst |
remodel game.
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/data.rs | 127 | ||||
-rw-r--r-- | server/src/game.rs | 224 | ||||
-rw-r--r-- | server/src/interaction.rs | 302 | ||||
-rw-r--r-- | server/src/lib.rs | 2 | ||||
-rw-r--r-- | server/src/main.rs | 2 | ||||
-rw-r--r-- | server/src/protocol.rs | 24 | ||||
-rw-r--r-- | server/src/recipes.rs | 104 |
7 files changed, 427 insertions, 358 deletions
diff --git a/server/src/data.rs b/server/src/data.rs new file mode 100644 index 00000000..6affccb5 --- /dev/null +++ b/server/src/data.rs @@ -0,0 +1,127 @@ +use crate::{interaction::Recipe, protocol::TileIndex}; +use glam::{IVec2, Vec2}; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, sync::RwLock}; + +#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default)] +#[serde(rename_all = "snake_case")] +pub enum Action { + #[default] + Never, + Passive(f32), + Active(f32), + Instant, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RecipeDecl { + #[serde(default)] + pub tile: Option<String>, + #[serde(default)] + pub inputs: Vec<String>, + #[serde(default)] + pub outputs: Vec<String>, + #[serde(default)] + pub action: Action, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct InitialMap { + map: Vec<String>, + tiles: HashMap<String, String>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Gamedata { + pub recipes: Vec<Recipe>, + pub item_names: Vec<String>, + pub tile_names: Vec<String>, + #[serde(skip)] + pub initial_map: HashMap<IVec2, TileIndex>, + pub spawn: Vec2, +} + +pub fn build_gamedata(recipes_in: Vec<RecipeDecl>, map_in: InitialMap) -> Gamedata { + let item_names = RwLock::new(Vec::new()); + let tile_names = RwLock::new(Vec::new()); + let mut recipes = Vec::new(); + + for r in recipes_in { + let r2 = r.clone(); + let mut inputs = r.inputs.into_iter().map(|i| register(&item_names, i)); + let mut outputs = r.outputs.into_iter().map(|o| register(&item_names, o)); + let tile = r.tile.map(|t| register(&tile_names, t)); + match r.action { + Action::Never => {} + Action::Passive(duration) => recipes.push(Recipe::Passive { + duration, + tile, + input: inputs.next().expect("passive recipe without input"), + output: outputs.next(), + }), + Action::Active(duration) => recipes.push(Recipe::Active { + duration, + tile, + input: inputs.next().expect("active recipe without input"), + outputs: [outputs.next(), outputs.next()], + }), + Action::Instant => { + recipes.push(Recipe::Instant { + tile, + inputs: [inputs.next(), inputs.next()], + outputs: [outputs.next(), outputs.next()], + }); + } + } + assert_eq!(inputs.next(), None, "{r2:?}"); + assert_eq!(outputs.next(), None, "{r2:?}"); + } + + let mut spawn = Vec2::new(0., 0.); + let mut initial_map = HashMap::new(); + for (y, line) in map_in.map.iter().enumerate() { + for (x, tile) in line.trim().char_indices() { + let pos = IVec2::new(x as i32, y as i32); + let mut tilename = map_in.tiles[&tile.to_string()].clone(); + if tilename == "spawn" { + spawn = pos.as_vec2(); + tilename = "floor".to_owned(); + } + let tile = register(&tile_names, tilename); + initial_map.insert(pos, tile); + } + } + + Gamedata { + recipes, + initial_map, + item_names: item_names.into_inner().unwrap(), + tile_names: tile_names.into_inner().unwrap(), + spawn, + } +} + +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 + } +} + +impl Gamedata { + pub fn get_tile(&self, name: &str) -> Option<TileIndex> { + self.tile_names.iter().position(|t| t == name) + } +} +impl Action { + pub fn duration(&self) -> f32 { + match self { + Action::Instant | Action::Never => 0., + Action::Passive(x) | Action::Active(x) => *x, + } + } +} diff --git a/server/src/game.rs b/server/src/game.rs index 5cb155f1..d481dc4f 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -1,10 +1,10 @@ use crate::{ - interaction::{interact, tick_tile, Out}, - protocol::{ItemID, ItemIndex, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex}, - recipes::Gamedata, + data::Gamedata, + interaction::interact, + protocol::{ItemIndex, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex}, }; use anyhow::{anyhow, bail, Result}; -use glam::IVec2; +use glam::{IVec2, Vec2}; use log::info; use std::{ collections::{HashMap, VecDeque}, @@ -12,29 +12,32 @@ use std::{ sync::Arc, }; -pub struct ActiveRecipe { +pub struct Involvement { pub recipe: RecipeIndex, pub progress: f32, pub working: usize, } +pub struct Item { + pub kind: ItemIndex, + pub active: Option<Involvement>, +} + pub struct Tile { - kind: TileIndex, - items: Vec<ItemID>, - active: Option<ActiveRecipe>, + pub kind: TileIndex, + pub item: Option<Item>, } -struct Player { - name: String, - interacting: bool, - hand: Option<ItemID>, +pub struct Player { + pub name: String, + pub position: Vec2, + pub interacting: bool, + pub item: Option<Item>, } pub struct Game { data: Arc<Gamedata>, - item_id_counter: ItemID, tiles: HashMap<IVec2, Tile>, - items: HashMap<ItemID, ItemIndex>, players: HashMap<PlayerID, Player>, packet_out: VecDeque<PacketC>, } @@ -43,8 +46,6 @@ impl Game { pub fn new(gamedata: Arc<Gamedata>) -> Self { let mut g = Self { data: gamedata.clone(), - item_id_counter: 0, - items: Default::default(), packet_out: Default::default(), players: Default::default(), tiles: Default::default(), @@ -69,19 +70,18 @@ impl Game { out.push(PacketC::AddPlayer { id, name: player.name.clone(), - hand: player.hand.map(|i| (i, self.items[&i].clone())), + hand: player.item.as_ref().map(|i| i.kind), }) } - for (&pos, tdata) in &self.tiles { + for (&tile, tdata) in &self.tiles { out.push(PacketC::UpdateMap { - pos, + pos: tile, tile: tdata.kind.clone(), }); - for &id in &tdata.items { + if let Some(item) = &tdata.item { out.push(PacketC::ProduceItem { - id, - pos, - kind: self.items[&id].clone(), + item: item.kind, + tile, }) } } @@ -94,7 +94,8 @@ impl Game { self.players.insert( player, Player { - hand: None, + item: None, + position: self.data.spawn, interacting: false, name: name.clone(), }, @@ -110,8 +111,8 @@ impl Game { .players .remove(&player) .ok_or(anyhow!("player does not exist"))?; - if let Some(id) = p.hand { - self.items.remove(&id).expect("hand item lost"); + if let Some(id) = p.item { + // TODO place on ground } self.packet_out .push_back(PacketC::RemovePlayer { id: player }) @@ -137,108 +138,105 @@ impl Game { bail!("already (not) interacting") } - 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]); + let tile_had_item = tile.item.is_some(); - 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 }); - } - Out::SetActive(progress) => { - self.packet_out.push_back(PacketC::SetActive { - tile: pos, - progress, - }); - } - }, - ); + interact(&self.data, edge, tile, player); + + // interact( + // &self.data, + // edge, + // tilekind, + // &mut tile.active, + // item, + // 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 }); + // } + // Out::SetActive(progress) => { + // self.packet_out.push_back(PacketC::SetActive { + // tile: pos, + // progress, + // }); + // } + // }, + // ); player.interacting = edge; } + PacketS::Collide { player, force } => {} } Ok(()) } pub fn tick(&mut self, dt: f32) { for (&pos, tile) in &mut self.tiles { - let items = tile.items.iter().map(|e| self.items[e]).collect::<Vec<_>>(); - tick_tile( - dt, - &self.data, - tile.kind, - &mut tile.active, - items, - |out| match out { - Out::Take(_) | Out::Put => { - unreachable!() - } - 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 }); - } - Out::SetActive(progress) => { - self.packet_out.push_back(PacketC::SetActive { - tile: pos, - progress, - }); - } - }, - ); + // let items = tile.items.iter().map(|e| self.items[e]).collect::<Vec<_>>(); + // tick_tile( + // dt, + // &self.data, + // tile.kind, + // &mut tile.active, + // items, + // |out| match out { + // Out::Take(_) | Out::Put => { + // unreachable!() + // } + // 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 }); + // } + // Out::SetActive(progress) => { + // self.packet_out.push_back(PacketC::SetActive { + // tile: pos, + // progress, + // }); + // } + // }, + // ); } } } impl From<TileIndex> for Tile { fn from(kind: TileIndex) -> Self { - Self { - kind, - items: vec![], - active: None, - } + Self { kind, item: None } } } diff --git a/server/src/interaction.rs b/server/src/interaction.rs index 11409b10..aa216410 100644 --- a/server/src/interaction.rs +++ b/server/src/interaction.rs @@ -1,150 +1,196 @@ use crate::{ - game::ActiveRecipe, + data::{Action, Gamedata}, + game::{Involvement, Item, Player, Tile}, protocol::{ItemIndex, TileIndex}, - recipes::{Action, Gamedata}, }; use log::{debug, info}; +use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; -use Out::*; -pub enum Out { - Take(usize), - Put, - Produce(ItemIndex), - Consume(usize), - SetActive(Option<f32>), +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Recipe { + Passive { + duration: f32, + tile: Option<TileIndex>, + input: ItemIndex, + output: Option<ItemIndex>, + }, + Active { + duration: f32, + tile: Option<TileIndex>, + input: ItemIndex, + outputs: [Option<ItemIndex>; 2], + }, + Instant { + tile: Option<TileIndex>, + inputs: [Option<ItemIndex>; 2], + outputs: [Option<ItemIndex>; 2], + }, } -pub fn interact( - data: &Gamedata, - edge: bool, - tile: TileIndex, - active: &mut Option<ActiveRecipe>, - mut items: Vec<ItemIndex>, - mut hand: Option<ItemIndex>, - mut out: impl FnMut(Out), -) { - let mut allowed = BTreeSet::new(); - for r in &data.recipes { - if r.tile == tile { - allowed.extend(r.inputs.clone()) - } - } - if !edge { - debug!("falling edge"); - if let Some(ac) = active { - if matches!(data.recipes[ac.recipe].action, Action::Active(_)) { - debug!("workers--"); - ac.working -= 1; - } - } - return; - } - - if hand.is_none() { - debug!("rising edge"); - if let Some(active) = active { - if matches!(data.recipes[active.recipe].action, Action::Active(_)) { - debug!("workers++"); - active.working += 1; - } +impl Recipe { + pub fn tile(&self) -> Option<TileIndex> { + match self { + Recipe::Passive { tile, .. } => *tile, + Recipe::Active { tile, .. } => *tile, + Recipe::Instant { tile, .. } => *tile, } } +} - if active.is_none() && !items.is_empty() && hand.is_none() { - out(Take(items.len() - 1)); +pub fn interact(data: &Gamedata, edge: bool, tile: &mut Tile, player: &mut Player) { + if !edge { return; } - if active.is_none() { - if let Some(hi) = hand { - if allowed.contains(&hi) { - out(Put); - items.push(hi); - hand = None; - } - } - } - - if hand.is_none() && active.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() { + for recipe in &data.recipes { + if let Some(tile_constraint) = recipe.tile() { + if tile.kind != tile_constraint { continue; } - - match r.action { - Action::Passive(_) => { - info!("use passive recipe {ri}"); - *active = Some(ActiveRecipe { - recipe: ri, - progress: 0., - working: 1, - }); - break 'rloop; - } - Action::Active(_) => { - info!("use active recipe {ri}"); - *active = Some(ActiveRecipe { - recipe: ri, - progress: 0., - working: 1, - }); - break 'rloop; - } - Action::Instant => { - info!("use instant recipe {ri}"); - for _ in 0..items.len() { - out(Consume(0)) - } - for i in &r.outputs { - out(Produce(*i)); - } - if !r.outputs.is_empty() { - out(Take(r.outputs.len() - 1)); - } - items.clear(); - break 'rloop; + } + match recipe { + Recipe::Passive { + duration, + input, + output, + .. + } => todo!(), + Recipe::Active { + duration, + input: inputs, + outputs, + .. + } => todo!(), + Recipe::Instant { + inputs, outputs, .. + } => { + let on_tile = tile.item.as_ref().map(|i| i.kind); + let in_hand = player.item.as_ref().map(|i| i.kind); + let ok = (inputs[0] == on_tile && inputs[1] == in_hand) + || (inputs[1] == on_tile && inputs[0] == in_hand); + if ok { + player.item = outputs[0].map(|kind| Item { kind, active: None }); + tile.item = outputs[1].map(|kind| Item { kind, active: None }); } - Action::Never => (), } } } } +// if !edge { +// debug!("falling edge"); +// if let Some(ac) = active { +// if matches!(data.recipes[ac.recipe].action, Action::Active(_)) { +// debug!("workers--"); +// ac.working -= 1; +// } +// } +// return; +// } -pub fn tick_tile( - dt: f32, - data: &Gamedata, - _tile: TileIndex, - active: &mut Option<ActiveRecipe>, - items: Vec<ItemIndex>, - mut out: impl FnMut(Out), -) { - if let Some(a) = active { - let r = &data.recipes[a.recipe]; - a.progress += a.working as f32 * dt / r.action.duration(); - if a.progress >= 1. { - for _ in 0..items.len() { - out(Consume(0)) - } - for i in &r.outputs { - out(Produce(*i)); - } - out(SetActive(None)); - active.take(); - } else { - out(SetActive(Some(a.progress))); - } - } -} +// if hand.is_none() { +// debug!("rising edge"); +// if let Some(active) = active { +// if matches!(data.recipes[active.recipe].action, Action::Active(_)) { +// debug!("workers++"); +// active.working += 1; +// } +// } +// } + +// if active.is_none() && !items.is_empty() && hand.is_none() { +// out(Take(items.len() - 1)); +// return; +// } + +// if active.is_none() { +// if let Some(hi) = hand { +// if allowed.contains(&hi) { +// out(Put); +// items.push(hi); +// hand = None; +// } +// } +// } + +// if hand.is_none() && active.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(_) => { +// info!("use passive recipe {ri}"); +// *active = Some(Involvement { +// recipe: ri, +// progress: 0., +// working: 1, +// }); +// break 'rloop; +// } +// Action::Active(_) => { +// info!("use active recipe {ri}"); +// *active = Some(Involvement { +// recipe: ri, +// progress: 0., +// working: 1, +// }); +// break 'rloop; +// } +// Action::Instant => { +// info!("use instant recipe {ri}"); +// for _ in 0..items.len() { +// out(Consume(0)) +// } +// for i in &r.outputs { +// out(Produce(*i)); +// } +// if !r.outputs.is_empty() { +// out(Take(r.outputs.len() - 1)); +// } +// items.clear(); +// break 'rloop; +// } +// Action::Never => (), +// } +// } +// } + +// pub fn tick_tile( +// dt: f32, +// data: &Gamedata, +// _tile: TileIndex, +// active: &mut Option<Involvement>, +// items: Vec<ItemIndex>, +// mut out: impl FnMut(Out), +// ) { +// if let Some(a) = active { +// let r = &data.recipes[a.recipe]; +// a.progress += a.working as f32 * dt / r.action.duration(); +// if a.progress >= 1. { +// for _ in 0..items.len() { +// out(Consume(0)) +// } +// for i in &r.outputs { +// out(Produce(*i)); +// } +// out(SetActive(None)); +// active.take(); +// } else { +// out(SetActive(Some(a.progress))); +// } +// } +// } diff --git a/server/src/lib.rs b/server/src/lib.rs index 5bb09e41..b40bcdd8 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -1,4 +1,4 @@ pub mod game; pub mod protocol; -pub mod recipes; +pub mod data; pub mod interaction; diff --git a/server/src/main.rs b/server/src/main.rs index 5414e9fd..6cb65141 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -13,7 +13,7 @@ use tokio_tungstenite::tungstenite::Message; use undercooked::{ game::Game, protocol::{PacketC, PacketS}, - recipes::build_gamedata, + data::build_gamedata, }; #[tokio::main] diff --git a/server/src/protocol.rs b/server/src/protocol.rs index 9e6717a3..4f04793f 100644 --- a/server/src/protocol.rs +++ b/server/src/protocol.rs @@ -1,9 +1,8 @@ -use crate::recipes::Gamedata; +use crate::data::Gamedata; use glam::{IVec2, Vec2}; use serde::{Deserialize, Serialize}; pub type PlayerID = usize; -pub type ItemID = usize; pub type ItemIndex = usize; pub type TileIndex = usize; pub type RecipeIndex = usize; @@ -15,6 +14,7 @@ pub enum PacketS { Leave, Position { pos: Vec2, rot: f32 }, Interact { pos: IVec2, edge: bool }, + Collide { player: PlayerID, force: Vec2 }, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -27,7 +27,7 @@ pub enum PacketC { AddPlayer { id: PlayerID, name: String, - hand: Option<(ItemID, ItemIndex)>, + hand: Option<ItemIndex>, }, RemovePlayer { id: PlayerID, @@ -38,21 +38,19 @@ pub enum PacketC { rot: f32, }, TakeItem { - item: ItemID, + tile: IVec2, player: PlayerID, }, PutItem { - item: ItemID, - pos: IVec2, + player: PlayerID, + tile: IVec2, }, ProduceItem { - id: ItemID, - pos: IVec2, - kind: ItemIndex, + tile: IVec2, + item: ItemIndex, }, ConsumeItem { - id: ItemID, - pos: IVec2, + tile: IVec2, }, SetActive { tile: IVec2, @@ -62,4 +60,8 @@ pub enum PacketC { pos: IVec2, tile: TileIndex, }, + Collide { + player: PlayerID, + force: Vec2, + }, } diff --git a/server/src/recipes.rs b/server/src/recipes.rs deleted file mode 100644 index 2dcb215c..00000000 --- a/server/src/recipes.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::protocol::{ItemIndex, TileIndex}; -use glam::IVec2; -use log::debug; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; - -#[derive(Debug, Deserialize, Serialize, Clone, Copy, Default)] -#[serde(rename_all = "snake_case")] -pub enum Action { - #[default] - Never, - Passive(f32), - Active(f32), - Instant, -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Recipe<T = TileIndex, I = ItemIndex> { - pub tile: T, - #[serde(default)] - pub inputs: Vec<I>, - #[serde(default)] - pub outputs: Vec<I>, - #[serde(default)] - pub action: Action, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct InitialMap { - map: Vec<String>, - tiles: HashMap<String, String>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Gamedata { - pub recipes: Vec<Recipe>, - pub item_names: Vec<String>, - pub tile_names: Vec<String>, - #[serde(skip)] - pub initial_map: HashMap<IVec2, TileIndex>, -} -pub fn build_gamedata(recipes_in: Vec<Recipe<String, String>>, map_in: InitialMap) -> Gamedata { - let mut item_names = Vec::new(); - let mut tile_names = Vec::new(); - let mut recipes = Vec::new(); - - for r in recipes_in { - recipes.push(Recipe { - action: r.action, - tile: register(&mut tile_names, r.tile.clone()), - inputs: r - .inputs - .clone() - .into_iter() - .map(|e| register(&mut item_names, e)) - .collect(), - outputs: r - .outputs - .clone() - .into_iter() - .map(|e| register(&mut item_names, e)) - .collect(), - }) - } - - let mut initial_map = HashMap::new(); - for (y, line) in map_in.map.iter().enumerate() { - for (x, tile) in line.trim().char_indices() { - debug!("{tile:?}"); - let tile = register(&mut tile_names, map_in.tiles[&tile.to_string()].clone()); - initial_map.insert(IVec2::new(x as i32, y as i32), tile); - } - } - - Gamedata { - recipes, - initial_map, - item_names, - tile_names, - } -} -fn register(db: &mut Vec<String>, name: String) -> usize { - if let Some(index) = db.iter().position(|e| e == &name) { - index - } else { - let index = db.len(); - db.push(name); - index - } -} - -impl Gamedata { - pub fn get_tile(&self, name: &str) -> Option<TileIndex> { - self.tile_names.iter().position(|t| t == name) - } -} -impl Action { - pub fn duration(&self) -> f32 { - match self { - Action::Instant | Action::Never => 0., - Action::Passive(x) | Action::Active(x) => *x, - } - } -} |