aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-07-20 19:43:14 +0200
committermetamuffin <metamuffin@disroot.org>2024-07-20 19:43:14 +0200
commitfebbc005cfac682257af0b74be5b307d4f23f91c (patch)
treea9884a873bd995b75c74583121e4bdd27c3fa5c2
parent1a45b0e0f5de785ddf268d7371f0cdaeafe9daa7 (diff)
downloadhurrycurry-febbc005cfac682257af0b74be5b307d4f23f91c.tar
hurrycurry-febbc005cfac682257af0b74be5b307d4f23f91c.tar.bz2
hurrycurry-febbc005cfac682257af0b74be5b307d4f23f91c.tar.zst
send score menu on game end
-rw-r--r--server/protocol/src/lib.rs2
-rw-r--r--server/src/entity/conveyor.rs12
-rw-r--r--server/src/entity/customers/mod.rs6
-rw-r--r--server/src/entity/mod.rs10
-rw-r--r--server/src/entity/portal.rs13
-rw-r--r--server/src/game.rs67
-rw-r--r--server/src/state.rs51
7 files changed, 100 insertions, 61 deletions
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index 61efd74f..fcccb107 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -209,7 +209,7 @@ pub enum PacketC {
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
-#[serde(rename_all = "snake_case", tag = "type", content = "data")]
+#[serde(rename_all = "snake_case", tag = "menu", content = "data")]
pub enum Menu {
Book,
Score(Score),
diff --git a/server/src/entity/conveyor.rs b/server/src/entity/conveyor.rs
index 38478db7..7f3d8688 100644
--- a/server/src/entity/conveyor.rs
+++ b/server/src/entity/conveyor.rs
@@ -1,3 +1,5 @@
+use std::collections::VecDeque;
+
/*
Hurry Curry! - a game about cooking
Copyright 2024 metamuffin
@@ -18,7 +20,7 @@
use super::EntityT;
use crate::game::{interact_effect, Game};
use anyhow::{anyhow, Result};
-use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation};
+use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation, PacketC};
#[derive(Debug, Clone)]
pub struct Conveyor {
@@ -31,7 +33,7 @@ pub struct Conveyor {
}
impl EntityT for Conveyor {
- fn tick(&mut self, game: &mut Game, dt: f32) -> Result<()> {
+ fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()> {
let from = game
.tiles
.get(&self.from)
@@ -44,7 +46,9 @@ impl EntityT for Conveyor {
.get(t)
.ok_or(anyhow!("conveyor filter missing"))?;
filter_tile.item.as_ref().map(|e| e.kind)
- } else { self.filter_item.as_ref().map(|i| *i) };
+ } else {
+ self.filter_item.as_ref().map(|i| *i)
+ };
if let Some(filter) = filter {
if from_item.kind != filter {
@@ -71,7 +75,7 @@ impl EntityT for Conveyor {
&mut from.item,
ItemLocation::Tile(self.from),
Some(to.kind),
- &mut game.packet_out,
+ packet_out,
&mut game.score,
true,
);
diff --git a/server/src/entity/customers/mod.rs b/server/src/entity/customers/mod.rs
index e8679dc9..974ae686 100644
--- a/server/src/entity/customers/mod.rs
+++ b/server/src/entity/customers/mod.rs
@@ -22,7 +22,7 @@ use super::EntityT;
use crate::{data::Demand, game::Game};
use anyhow::{anyhow, Result};
use fake::{faker, Fake};
-use hurrycurry_protocol::{glam::IVec2, DemandIndex, Message, PacketS, PlayerID};
+use hurrycurry_protocol::{glam::IVec2, DemandIndex, Message, PacketC, PacketS, PlayerID};
use log::{info, warn};
use pathfinding::{find_path, Path};
use rand::{random, thread_rng};
@@ -74,7 +74,7 @@ impl Customers {
}
impl EntityT for Customers {
- fn tick(&mut self, game: &mut Game, dt: f32) -> Result<()> {
+ fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()> {
self.spawn_cooldown -= dt;
self.spawn_cooldown = self.spawn_cooldown.max(0.);
if self.customers.len() < 5 && self.spawn_cooldown <= 0. {
@@ -253,7 +253,7 @@ impl EntityT for Customers {
self.customers.remove(&c).unwrap();
}
for (player, packet) in self.cpackets.drain(..) {
- if let Err(err) = game.packet_in(player, packet, &mut vec![]) {
+ if let Err(err) = game.packet_in(player, packet, &mut vec![], packet_out) {
warn!("demand packet {err}");
}
}
diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs
index c471a6d4..ec5ec744 100644
--- a/server/src/entity/mod.rs
+++ b/server/src/entity/mod.rs
@@ -18,18 +18,18 @@
pub mod conveyor;
pub mod customers;
pub mod portal;
-use std::collections::{HashMap, HashSet};
+use std::collections::{HashMap, HashSet, VecDeque};
use crate::{data::ItemTileRegistry, game::Game, interaction::Recipe};
use anyhow::{anyhow, Result};
use conveyor::Conveyor;
use customers::{demands::generate_demands, Customers};
-use hurrycurry_protocol::{glam::IVec2, ItemIndex, TileIndex};
+use hurrycurry_protocol::{glam::IVec2, ItemIndex, PacketC, TileIndex};
use portal::Portal;
use serde::{Deserialize, Serialize};
pub trait EntityT: Clone {
- fn tick(&mut self, game: &mut Game, dt: f32) -> Result<()>;
+ fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()>;
}
macro_rules! entities {
@@ -37,8 +37,8 @@ macro_rules! entities {
#[derive(Debug, Clone)]
pub enum Entity { $($e($e)),* }
impl EntityT for Entity {
- fn tick(&mut self, game: &mut Game, dt: f32) -> Result<()> {
- match self { $(Entity::$e(x) => x.tick(game, dt)),*, }
+ fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()> {
+ match self { $(Entity::$e(x) => x.tick(game, packet_out, dt)),*, }
}
}
};
diff --git a/server/src/entity/portal.rs b/server/src/entity/portal.rs
index 2d4a762b..e0ec353f 100644
--- a/server/src/entity/portal.rs
+++ b/server/src/entity/portal.rs
@@ -1,3 +1,5 @@
+use std::collections::VecDeque;
+
/*
Hurry Curry! - a game about cooking
Copyright 2024 metamuffin
@@ -18,7 +20,7 @@
use super::EntityT;
use crate::game::{interact_effect, Game};
use anyhow::{anyhow, Result};
-use hurrycurry_protocol::{glam::IVec2, ItemLocation};
+use hurrycurry_protocol::{glam::IVec2, ItemLocation, PacketC};
#[derive(Debug, Default, Clone)]
pub struct Portal {
@@ -27,7 +29,12 @@ pub struct Portal {
}
impl EntityT for Portal {
- fn tick(&mut self, game: &mut Game, _dt: f32) -> Result<()> {
+ fn tick(
+ &mut self,
+ game: &mut Game,
+ packet_out: &mut VecDeque<PacketC>,
+ _dt: f32,
+ ) -> Result<()> {
let [from, to] = game
.tiles
.get_many_mut([&self.from, &self.to])
@@ -42,7 +49,7 @@ impl EntityT for Portal {
&mut from.item,
ItemLocation::Tile(self.from),
Some(to.kind),
- &mut game.packet_out,
+ packet_out,
&mut game.score,
true,
);
diff --git a/server/src/game.rs b/server/src/game.rs
index 1f368b00..21bb5f33 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -72,7 +72,6 @@ pub struct Game {
pub walkable: HashSet<IVec2>,
pub players: HashMap<PlayerID, Player>,
players_spatial_index: SpatialIndex<PlayerID>,
- pub packet_out: VecDeque<PacketC>,
entities: Arc<RwLock<Vec<Entity>>>,
end: Option<Instant>,
pub lobby: bool,
@@ -92,7 +91,6 @@ impl Game {
Self {
lobby: false,
data: Gamedata::default().into(),
- packet_out: Default::default(),
players: HashMap::new(),
tiles: HashMap::new(),
walkable: HashSet::new(),
@@ -104,16 +102,16 @@ impl Game {
}
}
- fn unload(&mut self) {
- self.packet_out.push_back(PacketC::SetIngame {
+ fn unload(&mut self, packet_out: &mut VecDeque<PacketC>) {
+ packet_out.push_back(PacketC::SetIngame {
state: false,
lobby: false,
});
for (id, _) in self.players.drain() {
- self.packet_out.push_back(PacketC::RemovePlayer { id })
+ packet_out.push_back(PacketC::RemovePlayer { id })
}
for (pos, _) in self.tiles.drain() {
- self.packet_out.push_back(PacketC::UpdateMap {
+ packet_out.push_back(PacketC::UpdateMap {
tile: pos,
kind: None,
neighbors: [None, None, None, None],
@@ -121,7 +119,12 @@ impl Game {
}
self.walkable.clear();
}
- pub fn load(&mut self, gamedata: Gamedata, timer: Option<Duration>) {
+ pub fn load(
+ &mut self,
+ gamedata: Gamedata,
+ timer: Option<Duration>,
+ packet_out: &mut VecDeque<PacketC>,
+ ) {
let players = self
.players
.iter()
@@ -129,7 +132,7 @@ impl Game {
.map(|(id, p)| (*id, (p.name.to_owned(), p.character)))
.collect::<HashMap<_, _>>();
- self.unload();
+ self.unload(packet_out);
self.lobby = gamedata.map_name == "lobby";
self.data = gamedata.into();
@@ -180,7 +183,7 @@ impl Game {
);
}
- self.packet_out.extend(self.prime_client());
+ packet_out.extend(self.prime_client());
}
pub fn prime_client(&self) -> Vec<PacketC> {
@@ -261,6 +264,7 @@ impl Game {
player: PlayerID,
packet: PacketS,
replies: &mut Vec<PacketC>,
+ packet_out: &mut VecDeque<PacketC>,
) -> Result<()> {
match packet {
PacketS::Join { name, character } => {
@@ -297,7 +301,7 @@ impl Game {
name: name.clone(),
},
);
- self.packet_out.push_back(PacketC::AddPlayer {
+ packet_out.push_back(PacketC::AddPlayer {
id: player,
name,
position,
@@ -316,7 +320,7 @@ impl Game {
let pos = p.movement.position.floor().as_ivec2();
if let Some(tile) = self.tiles.get_mut(&pos) {
if tile.item.is_none() {
- self.packet_out.push_back(PacketC::SetItem {
+ packet_out.push_back(PacketC::SetItem {
location: ItemLocation::Tile(pos),
item: Some(item.kind),
});
@@ -324,8 +328,7 @@ impl Game {
}
}
}
- self.packet_out
- .push_back(PacketC::RemovePlayer { id: player })
+ packet_out.push_back(PacketC::RemovePlayer { id: player })
}
PacketS::Movement {
pos,
@@ -352,8 +355,7 @@ impl Game {
}
}
PacketS::Collide { player, force } => {
- self.packet_out
- .push_back(PacketC::Collide { player, force });
+ packet_out.push_back(PacketC::Collide { player, force });
}
PacketS::Interact { pos } => {
let pid = player;
@@ -410,7 +412,7 @@ impl Game {
&mut other.item,
ItemLocation::Player(pid),
None,
- &mut self.packet_out,
+ packet_out,
&mut self.score,
false,
)
@@ -428,7 +430,7 @@ impl Game {
&mut player.item,
ItemLocation::Player(pid),
Some(tile.kind),
- &mut self.packet_out,
+ packet_out,
&mut self.score,
false,
)
@@ -441,7 +443,7 @@ impl Game {
player.communicate_persist = message.clone()
}
}
- self.packet_out.push_back(PacketC::Communicate {
+ packet_out.push_back(PacketC::Communicate {
player,
message,
persist,
@@ -456,7 +458,7 @@ impl Game {
kind: i,
active: None,
});
- self.packet_out.push_back(PacketC::SetItem {
+ packet_out.push_back(PacketC::SetItem {
location: ItemLocation::Player(player),
item,
})
@@ -467,11 +469,10 @@ impl Game {
}
/// Returns true if the game should end
- pub fn tick(&mut self, dt: f32) -> bool {
+ pub fn tick(&mut self, dt: f32, packet_out: &mut VecDeque<PacketC>) -> bool {
if self.score_changed {
self.score_changed = false;
- self.packet_out
- .push_back(PacketC::Score(self.score.clone()));
+ packet_out.push_back(PacketC::Score(self.score.clone()));
}
for (&pos, tile) in &mut self.tiles {
@@ -483,7 +484,7 @@ impl Game {
&mut self.score,
) {
match effect {
- TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress {
+ TickEffect::Progress(warn) => packet_out.push_back(PacketC::SetProgress {
warn,
item: ItemLocation::Tile(pos),
progress: tile
@@ -495,7 +496,7 @@ impl Game {
.map(|i| i.progress),
}),
TickEffect::Produce => {
- self.packet_out.push_back(PacketC::SetItem {
+ packet_out.push_back(PacketC::SetItem {
location: ItemLocation::Tile(pos),
item: tile.item.as_ref().map(|i| i.kind),
});
@@ -522,7 +523,7 @@ impl Game {
});
for (&pid, player) in &mut self.players {
- self.packet_out.push_back(PacketC::Position {
+ packet_out.push_back(PacketC::Position {
player: pid,
pos: player.movement.position,
boosting: player.movement.boosting,
@@ -532,7 +533,7 @@ impl Game {
if let Some(effect) = tick_slot(dt, &self.data, None, &mut player.item, &mut self.score)
{
match effect {
- TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress {
+ TickEffect::Progress(warn) => packet_out.push_back(PacketC::SetProgress {
warn,
item: ItemLocation::Player(pid),
progress: player
@@ -544,7 +545,7 @@ impl Game {
.map(|i| i.progress),
}),
TickEffect::Produce => {
- self.packet_out.push_back(PacketC::SetItem {
+ packet_out.push_back(PacketC::SetItem {
location: ItemLocation::Player(pid),
item: player.item.as_ref().map(|i| i.kind),
});
@@ -568,11 +569,16 @@ impl Game {
}
}
for pid in players_auto_release.drain(..) {
- let _ = self.packet_in(pid, PacketS::Interact { pos: None }, &mut vec![]);
+ let _ = self.packet_in(
+ pid,
+ PacketS::Interact { pos: None },
+ &mut vec![],
+ packet_out,
+ );
}
for entity in self.entities.clone().write().unwrap().iter_mut() {
- if let Err(e) = entity.tick(self, dt) {
+ if let Err(e) = entity.tick(self, packet_out, dt) {
warn!("entity tick failed: {e}")
}
}
@@ -580,8 +586,7 @@ impl Game {
if let Some(end) = self.end {
self.score.time_remaining = (end - Instant::now()).as_secs_f64();
if end < Instant::now() {
- self.packet_out
- .push_back(PacketC::Menu(Menu::Score(self.score.clone())));
+ packet_out.push_back(PacketC::Menu(Menu::Score(self.score.clone())));
true
} else {
false
diff --git a/server/src/state.rs b/server/src/state.rs
index 3492e6e7..82540fd6 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -20,11 +20,12 @@ use anyhow::{anyhow, bail, Result};
use clap::{Parser, ValueEnum};
use hurrycurry_protocol::{Message, PacketC, PacketS, PlayerID};
use log::{debug, trace};
-use std::time::Duration;
+use std::{collections::VecDeque, time::Duration};
use tokio::sync::broadcast::Sender;
pub struct State {
index: DataIndex,
+ packet_out: VecDeque<PacketC>,
tx: Sender<PacketC>,
pub game: Game,
}
@@ -74,24 +75,37 @@ impl State {
let mut index = DataIndex::default();
index.reload()?;
+ let mut packet_out = VecDeque::new();
let mut game = Game::new();
- game.load(index.generate("lobby-none".to_string()).await?, None);
+ game.load(
+ index.generate("lobby-none".to_string()).await?,
+ None,
+ &mut packet_out,
+ );
- Ok(Self { game, index, tx })
+ Ok(Self {
+ game,
+ index,
+ tx,
+ packet_out,
+ })
}
pub async fn tick(&mut self, dt: f32) -> anyhow::Result<()> {
- if self.game.tick(dt) {
- self.game
- .load(self.index.generate("lobby-none".to_string()).await?, None);
+ if self.game.tick(dt, &mut self.packet_out) {
+ self.game.load(
+ self.index.generate("lobby-none".to_string()).await?,
+ None,
+ &mut self.packet_out,
+ );
}
- while let Some(p) = self.game.packet_out.pop_front() {
+ while let Some(p) = self.packet_out.pop_front() {
if matches!(p, PacketC::UpdateMap { .. } | PacketC::Position { .. }) {
trace!("-> {p:?}");
} else {
debug!("-> {p:?}");
}
- let _ = self.tx.send(p);
+ self.tx.send(p).unwrap();
}
Ok(())
}
@@ -113,15 +127,19 @@ impl State {
}
_ => (),
}
- self.game.packet_in(player, packet, &mut replies)?;
+ self.game
+ .packet_in(player, packet, &mut replies, &mut self.packet_out)?;
if self.game.players.is_empty() && !self.game.lobby {
self.tx
.send(PacketC::ServerMessage {
text: "Game was aborted automatically due to a lack of players".to_string(),
})
.ok();
- self.game
- .load(self.index.generate("lobby-none".to_string()).await?, None);
+ self.game.load(
+ self.index.generate("lobby-none".to_string()).await?,
+ None,
+ &mut self.packet_out,
+ );
}
Ok(replies)
}
@@ -143,7 +161,8 @@ impl State {
match command {
Command::Start { spec, timer } => {
let data = self.index.generate(spec).await?;
- self.game.load(data, Some(Duration::from_secs(timer)));
+ self.game
+ .load(data, Some(Duration::from_secs(timer)), &mut self.packet_out);
}
Command::End => {
self.tx
@@ -158,8 +177,11 @@ impl State {
),
})
.ok();
- self.game
- .load(self.index.generate("lobby-none".to_string()).await?, None);
+ self.game.load(
+ self.index.generate("lobby-none".to_string()).await?,
+ None,
+ &mut self.packet_out,
+ );
}
Command::Reload => {
if self.game.count_chefs() > 1 {
@@ -168,6 +190,7 @@ impl State {
self.game.load(
self.index.generate(self.game.data.spec.to_string()).await?,
None,
+ &mut self.packet_out,
);
}
Command::ReloadIndex => {