summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/menu/ingame.gd2
-rw-r--r--client/multiplayer.gd6
-rw-r--r--locale/en.ini3
-rw-r--r--server/protocol/src/lib.rs3
-rw-r--r--server/src/server.rs6
-rw-r--r--server/src/state.rs40
6 files changed, 48 insertions, 12 deletions
diff --git a/client/menu/ingame.gd b/client/menu/ingame.gd
index 33aa5fc1..85c03ad4 100644
--- a/client/menu/ingame.gd
+++ b/client/menu/ingame.gd
@@ -44,7 +44,9 @@ func anim_setup(): pass
func _menu_open():
anim.play("activate")
await anim.animation_finished
+ game.mp.send_idle(true)
func _menu_exit():
+ game.mp.send_idle(false)
anim.play_backwards("activate")
await anim.animation_finished
diff --git a/client/multiplayer.gd b/client/multiplayer.gd
index 5a9406ab..084622c3 100644
--- a/client/multiplayer.gd
+++ b/client/multiplayer.gd
@@ -135,6 +135,12 @@ func send_replay_tick(dt: float):
"dt": dt
})
+func send_idle(paused: bool):
+ send_packet({
+ "type": "idle",
+ "paused": paused,
+ })
+
func send_leave(player):
send_packet({
"type": "leave",
diff --git a/locale/en.ini b/locale/en.ini
index 7b201183..71df1707 100644
--- a/locale/en.ini
+++ b/locale/en.ini
@@ -2,7 +2,6 @@
c.chat.write_message=Write message
c.credits.contributors=with contributions from
c.credits.developed_by=developed by
-c.legal.using_godot=This game uses Godot Engine, available under the following license:
c.credits.models=Models
c.credits.sounds=Sounds
c.credits.thanks=Thank You For Playing
@@ -27,6 +26,7 @@ c.hint.reset_camera=Press {0} to reset the camera view
c.hint.rotate=Use {0} to rotate the camera view
c.hint.username_tags=Username tags can be enabled/disabled in the settings
c.hint.zoom_camera=Use {0} to zoom in/out
+c.legal.using_godot=This game uses Godot Engine, available under the following license:
c.map.difficulty.0=Easy
c.map.difficulty.1=Hard
c.map.difficulty.2=Moderate
@@ -254,6 +254,7 @@ s.replay.cannot_join=Replays cannot be joined.
s.state.abort_no_players=Game was aborted due to a lack of players.
s.state.game_aborted=Game was aborted by {0}.
s.state.overflow_resubscribe=Lagging behind. Some clientbound packets were dropped.
+s.state.paused=Game paused
s.tutorial.accept_order=Approach the customer take their order
s.tutorial.active_cuttingboard=Cut the item to slices here
s.tutorial.active=Interact here for {0}s
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index 552c4eed..24e547f6 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -142,6 +142,9 @@ pub enum PacketS {
pin: Option<bool>,
},
+ Idle {
+ paused: bool,
+ },
/// For use in replay sessions only
ReplayTick {
dt: f64,
diff --git a/server/src/server.rs b/server/src/server.rs
index 3da95a43..a06f4f36 100644
--- a/server/src/server.rs
+++ b/server/src/server.rs
@@ -42,7 +42,8 @@ use tokio::sync::broadcast::Sender;
pub struct Server {
pub tx: Sender<PacketC>,
- pub connections: HashMap<ConnectionID, HashSet<PlayerID>>,
+ pub connections: HashMap<ConnectionID, (HashSet<PlayerID>, bool)>,
+ pub paused: bool,
pub game: Game,
@@ -328,9 +329,11 @@ impl Server {
.await
.context("Failed to load scoreboards")?,
editor_address: None,
+ paused: false,
})
}
}
+
impl Server {
pub fn load(
&mut self,
@@ -629,6 +632,7 @@ impl Server {
self.score_changed = true;
}
PacketS::ReplayTick { .. } => return Err(tre!("s.error.packet_not_supported")),
+ PacketS::Idle { .. } => (),
}
Ok(())
}
diff --git a/server/src/state.rs b/server/src/state.rs
index 20e2bf80..53ca3b42 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -18,14 +18,32 @@
use crate::{message::TrError, server::Server, tre, trm, ConnectionID};
use anyhow::Result;
use hurrycurry_protocol::{Message, PacketC, PacketS, PlayerID};
-use log::{debug, trace};
+use log::{debug, info, trace};
impl Server {
pub async fn tick_outer(&mut self, dt: f32) -> anyhow::Result<()> {
- let r = self.tick(dt);
- if let Some((name, timer)) = r {
- self.scoreboard.save().await?;
- self.load(self.index.generate(&name).await?, timer);
+ let should_pause = self.connections.iter().all(|c| c.1 .1);
+ if should_pause != self.paused {
+ info!("Game paused: {}", should_pause);
+ self.paused = should_pause;
+ for p in self.game.players.keys() {
+ self.packet_out.push_back(PacketC::ServerHint {
+ position: None,
+ message: if self.paused {
+ Some(trm!("s.state.paused"))
+ } else {
+ None
+ },
+ player: *p,
+ });
+ }
+ }
+ if !self.paused {
+ let r = self.tick(dt);
+ if let Some((name, timer)) = r {
+ self.scoreboard.save().await?;
+ self.load(self.index.generate(&name).await?, timer);
+ }
}
while let Some(p) = self.packet_out.pop_front() {
if matches!(p, PacketC::UpdateMap { .. } | PacketC::Movement { .. }) {
@@ -43,7 +61,7 @@ impl Server {
packet: PacketS,
) -> Result<Vec<PacketC>, TrError> {
if let Some(p) = get_packet_player(&packet) {
- if !self.connections.entry(conn).or_default().contains(&p) {
+ if !self.connections.entry(conn).or_default().0.contains(&p) {
return Err(tre!("s.error.packet_sender_invalid"));
}
}
@@ -65,11 +83,12 @@ impl Server {
}
}
}
+ PacketS::Idle { paused } => self.connections.entry(conn).or_default().1 = *paused,
PacketS::Leave { player } => {
- self.connections.entry(conn).or_default().remove(player);
+ self.connections.entry(conn).or_default().0.remove(player);
}
PacketS::Join { .. } => {
- if self.connections.entry(conn).or_default().len() > 8 {
+ if self.connections.entry(conn).or_default().0.len() > 8 {
return Err(tre!("s.error.conn_too_many_players"));
}
}
@@ -79,7 +98,7 @@ impl Server {
for p in &replies {
if let PacketC::Joined { id } = p {
- self.connections.entry(conn).or_default().insert(*id);
+ self.connections.entry(conn).or_default().0.insert(*id);
}
}
@@ -102,7 +121,7 @@ impl Server {
}
pub async fn disconnect(&mut self, conn: ConnectionID) {
- if let Some(players) = self.connections.get(&conn) {
+ if let Some((players, _)) = self.connections.get(&conn) {
for player in players.clone() {
let _ = self.packet_in_outer(conn, PacketS::Leave { player }).await;
}
@@ -114,6 +133,7 @@ impl Server {
fn get_packet_player(packet: &PacketS) -> Option<PlayerID> {
match packet {
PacketS::Join { .. } => None,
+ PacketS::Idle { .. } => None,
PacketS::Leave { player } => Some(*player),
PacketS::Movement { player, .. } => Some(*player),
PacketS::Interact { player, .. } => Some(*player),