use crate::{ data::Gamedata, interaction::interact, protocol::{ItemIndex, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex}, }; use anyhow::{anyhow, bail, Result}; use glam::{IVec2, Vec2}; use log::info; use std::{ collections::{HashMap, VecDeque}, ops::Deref, sync::Arc, }; pub struct Involvement { pub recipe: RecipeIndex, pub progress: f32, pub working: usize, } pub struct Item { pub kind: ItemIndex, pub active: Option, } pub struct Tile { pub kind: TileIndex, pub item: Option, } pub struct Player { pub name: String, pub position: Vec2, pub interacting: bool, pub item: Option, } pub struct Game { data: Arc, tiles: HashMap, players: HashMap, packet_out: VecDeque, } impl Game { pub fn new(gamedata: Arc) -> Self { let mut g = Self { data: gamedata.clone(), packet_out: Default::default(), players: Default::default(), tiles: Default::default(), }; for (&p, &t) in &gamedata.initial_map { g.tiles.insert(p, t.into()); } g } pub fn packet_out(&mut self) -> Option { self.packet_out.pop_front() } pub fn prime_client(&self, id: PlayerID) -> Vec { let mut out = Vec::new(); out.push(PacketC::Init { id, data: self.data.deref().to_owned(), }); for (&id, player) in &self.players { out.push(PacketC::AddPlayer { id, name: player.name.clone(), hand: player.item.as_ref().map(|i| i.kind), }) } for (&tile, tdata) in &self.tiles { out.push(PacketC::UpdateMap { pos: tile, tile: tdata.kind.clone(), }); if let Some(item) = &tdata.item { out.push(PacketC::ProduceItem { item: item.kind, tile, }) } } out } pub fn packet_in(&mut self, player: PlayerID, packet: PacketS) -> Result<()> { match packet { PacketS::Join { name } => { self.players.insert( player, Player { item: None, position: self.data.spawn, interacting: false, 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.item { // TODO place on ground } 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 } => { info!("interact {pos:?} edge={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"))?; if edge == player.interacting { bail!("already (not) interacting") } let tile_had_item = tile.item.is_some(); 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::>(); // 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 for Tile { fn from(kind: TileIndex) -> Self { Self { kind, item: None } } }