/* Hurry Curry! - a game about cooking Copyright 2024 metamuffin This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ pub mod spatial_index; use hurrycurry_protocol::{ glam::IVec2, movement::MovementBase, ClientGamedata, ItemIndex, ItemLocation, Message, PacketC, PlayerID, Score, TileIndex, }; use spatial_index::SpatialIndex; use std::{ collections::{HashMap, HashSet}, sync::Arc, time::Instant, }; #[derive(Debug, PartialEq)] pub struct Item { pub kind: ItemIndex, pub progress: Option<(f32, bool)>, } pub struct Tile { pub kind: TileIndex, pub item: Option, } pub struct Player { pub name: String, pub character: i32, pub interacting: Option, pub item: Option, pub communicate_persist: Option, pub movement: MovementBase, } pub struct Game { pub data: Arc, pub tiles: HashMap, pub walkable: HashSet, pub players: HashMap, pub players_spatial_index: SpatialIndex, pub end: Option, pub lobby: bool, pub environment_effects: HashSet, pub score: Score, } impl Game { pub fn apply_packet(&mut self, packet: PacketC) { match packet { PacketC::Data { data } => { self.data = Arc::new(data); } PacketC::AddPlayer { id, position, character, name, } => { self.players.insert( id, Player { name, character, interacting: None, item: None, communicate_persist: None, movement: MovementBase::new(position), }, ); } PacketC::RemovePlayer { id } => { self.players.remove(&id); } PacketC::Position { player, pos, rot, boosting, } => { if let Some(p) = self.players.get_mut(&player) { p.movement.position = pos; p.movement.rotation = rot; p.movement.boosting = boosting; } } PacketC::MoveItem { from, to } => { *self.get_item(to) = self.get_item(from).take(); } PacketC::SetItem { location, item } => { *self.get_item(location) = item.map(|kind| Item { kind, progress: None, }); } PacketC::SetProgress { item, progress, warn, } => { self.get_item(item).as_mut().unwrap().progress = progress.map(|s| (s, warn)); } PacketC::UpdateMap { tile, kind, neighbors: _, } => { if let Some(kind) = kind { self.tiles.insert(tile, Tile { kind, item: None }); if self.data.tile_collide[kind.0] { self.walkable.remove(&tile); } else { self.walkable.insert(tile); } } else { self.tiles.remove(&tile); self.walkable.remove(&tile); } } PacketC::Communicate { player, message, persist, } => { if persist { if let Some(player) = self.players.get_mut(&player) { player.communicate_persist = message; } } } PacketC::Score(score) => { self.score = score; } PacketC::SetIngame { state: _, lobby } => { self.lobby = lobby; } PacketC::Environment { effects } => { self.environment_effects = effects; } _ => (), } } pub fn get_item(&mut self, location: ItemLocation) -> &mut Option { match location { ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item, ItemLocation::Player(pid) => &mut self.players.get_mut(&pid).unwrap().item, } } }