use crate::protocol::{Item, PacketC, PacketS, Tile, ID}; use anyhow::{anyhow, Result}; use glam::IVec2; use log::info; use std::collections::{HashMap, VecDeque}; struct TileData { kind: Tile, items: Vec, active: bool, progress: f32, } struct Player { name: String, hand: Option, } #[derive(Default)] pub struct Game { item_id_counter: ID, tiles: HashMap, items: HashMap, players: HashMap, packet_out: VecDeque, } impl Game { pub fn new() -> Self { let mut g = Self::default(); for x in -5..5 { for y in -5..5 { g.tiles .insert(IVec2 { x, y }, Tile("floor".to_string()).into()); } } for x in -5..5 { g.tiles .insert(IVec2 { x, y: -5 }, Tile("table".to_string()).into()); g.tiles .insert(IVec2 { x, y: 4 }, Tile("table".to_string()).into()); } for y in -5..5 { g.tiles .insert(IVec2 { x: -5, y }, Tile("table".to_string()).into()); g.tiles .insert(IVec2 { x: 4, y }, Tile("table".to_string()).into()); } g.tiles.extend( [([-5, 1], "pan"), ([-5, 2], "pan"), ([4, 3], "flour_bag")].map(|(k, v)| { ( IVec2::from_array(k), TileData { active: false, items: vec![], kind: Tile(v.to_string()).into(), progress: 0., }, ) }), ); g } pub fn packet_out(&mut self) -> Option { self.packet_out.pop_front() } pub fn prime_client(&self, id: ID) -> Vec { let mut out = Vec::new(); for (&id, player) in &self.players { out.push(PacketC::AddPlayer { id, name: player.name.clone(), hand: player.hand.map(|i| (i, self.items[&i].clone())), }) } for (&pos, tdata) in &self.tiles { out.push(PacketC::UpdateMap { pos, tile: tdata.kind.clone(), }); for &id in &tdata.items { out.push(PacketC::ProduceItem { id, pos, kind: self.items[&id].clone(), }) } } out.push(PacketC::Joined { id }); out } pub fn packet_in(&mut self, player: ID, packet: PacketS) -> Result<()> { match packet { PacketS::Join { name } => { self.players.insert( player, Player { hand: None, name: name.clone(), }, ); self.packet_out.push_back(PacketC::AddPlayer { id: player, name, hand: None, }); } PacketS::Leave => { let p = self .players .remove(&player) .ok_or(anyhow!("player does not exist"))?; if let Some(id) = p.hand { self.items.remove(&id).expect("hand item lost"); } self.packet_out .push_back(PacketC::RemovePlayer { id: player }) } PacketS::Position { pos, rot } => { self.packet_out .push_back(PacketC::Position { player, pos, rot }); } PacketS::Interact { pos, edge } => { if !edge { return Ok(()); } let tile = self .tiles .get_mut(&pos) .ok_or(anyhow!("interacting with empty tile"))?; let player_data = self .players .get_mut(&player) .ok_or(anyhow!("player does not exist"))?; if tile.kind.0 == "flour_bag" { info!("new flour"); let item = Item("flour".to_string()); self.items.insert(self.item_id_counter, item.clone()); tile.items.push(self.item_id_counter); self.packet_out.push_back(PacketC::ProduceItem { id: self.item_id_counter, pos, kind: item, }); self.item_id_counter += 1; } 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 }) } } } } Ok(()) } } impl From for TileData { fn from(kind: Tile) -> Self { Self { kind, progress: 0., active: false, items: vec![], } } }