diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/src/commands.rs | 21 | ||||
-rw-r--r-- | server/src/main.rs | 18 | ||||
-rw-r--r-- | server/src/server.rs | 6 | ||||
-rw-r--r-- | server/src/state.rs | 100 |
4 files changed, 102 insertions, 43 deletions
diff --git a/server/src/commands.rs b/server/src/commands.rs index 8e3d926a..1ffe4cd1 100644 --- a/server/src/commands.rs +++ b/server/src/commands.rs @@ -78,6 +78,13 @@ enum Command { Tile { name: String }, /// Show all possible demands for this map Demands, + /// Ready yourself + Ready { + #[arg(short, long)] + force: bool, + #[arg(short, long)] + unready: bool, + }, /// Reload the resource index ReloadIndex, #[clap(alias = "summon", alias = "bot")] @@ -167,9 +174,10 @@ impl Server { .map_err(|e| TrError::Plain(e.to_string()))?; self.load(data, timer.map(Duration::from_secs)); if !skip_announce { - self.start_pause_timer = 3.5; + self.announce_timer = 3.5; self.packet_out .push_back(PacketC::Menu(Menu::AnnounceStart)); + self.update_paused(); } } Command::End => { @@ -206,6 +214,17 @@ impl Server { None, ); } + Command::Ready { force, unready } => { + for c in self.connections.values_mut() { + if c.players.contains(&player) || force { + c.ready = true; + } + if unready && c.players.contains(&player) { + c.ready = false; + } + } + self.update_paused(); + } Command::ReloadIndex => { self.index .reload() diff --git a/server/src/main.rs b/server/src/main.rs index c6b0d59f..2c47db7d 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -18,12 +18,8 @@ use anyhow::{bail, Result}; use clap::Parser; use futures_util::{SinkExt, StreamExt}; -use hurrycurry_protocol::{PacketC, PacketS, VERSION}; -use hurrycurry_server::{ - data::DATA_DIR, - server::{GameServerExt, Server}, - trm, ConnectionID, -}; +use hurrycurry_protocol::{PacketC, PacketS}; +use hurrycurry_server::{data::DATA_DIR, server::Server, trm, ConnectionID}; use log::{debug, info, trace, warn, LevelFilter}; use std::{ env::var, net::SocketAddr, path::PathBuf, process::exit, str::FromStr, sync::Arc, @@ -209,15 +205,7 @@ async fn run(args: Args) -> anyhow::Result<()> { let mut rx = rx.resubscribe(); let (error_tx, mut error_rx) = channel::<PacketC>(8); - let mut init = state.write().await.game.prime_client(); - init.insert( - 0, - PacketC::Version { - major: VERSION.0, - minor: VERSION.1, - supports_bincode: true, - }, - ); + let init = state.write().await.connect(id).await; // let supports_binary = Arc::new(AtomicBool::new(false)); // let supports_binary2 = supports_binary.clone(); diff --git a/server/src/server.rs b/server/src/server.rs index a1a849c4..22ad5d23 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -51,7 +51,7 @@ pub struct Server { pub tx: Sender<PacketC>, pub connections: HashMap<ConnectionID, ConnectionData>, pub paused: bool, - pub start_pause_timer: f32, + pub announce_timer: f32, pub game: Game, @@ -326,7 +326,7 @@ impl Server { game: Game::default(), index: DataIndex::load().context("Failed to load data index")?, tx, - start_pause_timer: 0., + announce_timer: 0., packet_out: VecDeque::new(), connections: HashMap::new(), data: Serverdata::default().into(), @@ -385,6 +385,8 @@ impl Server { dt: 0., }); } + self.connections.values_mut().for_each(|c| c.ready = false); + self.update_paused(); } pub fn packet_in( diff --git a/server/src/state.rs b/server/src/state.rs index b4a8ce1f..1d2af247 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -15,33 +15,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use crate::{message::TrError, server::Server, tre, trm, ConnectionID}; +use crate::{ + message::TrError, + server::{ConnectionData, GameServerExt, Server}, + tre, trm, ConnectionID, +}; use anyhow::Result; -use hurrycurry_protocol::{Message, PacketC, PacketS, PlayerID}; +use hurrycurry_protocol::{Message, PacketC, PacketS, PlayerID, VERSION}; use log::{debug, info, trace}; impl Server { pub fn tick_outer(&mut self, dt: f32) -> anyhow::Result<()> { - if self.start_pause_timer > 0. { - self.start_pause_timer -= dt - } - let should_pause = self.start_pause_timer > 0. || self.connections.values().all(|c| c.idle); + let should_pause = self.announce_timer > 0.; 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::Pause { state: self.paused }); - self.packet_out.push_back(PacketC::ServerHint { - position: None, - message: if self.paused && self.start_pause_timer <= 0. { - Some(trm!("s.state.paused")) - } else { - None - }, - player: *p, - }); - } } if !self.paused { let r = self.tick(dt); @@ -49,7 +36,13 @@ impl Server { self.scoreboard.save()?; self.load(self.index.generate_with_book(&name)?, timer); } + } else if self.announce_timer > 0. { + self.announce_timer -= dt; + if self.announce_timer <= 0. { + self.update_paused(); + } } + while let Some(p) = self.packet_out.pop_front() { if matches!(p, PacketC::UpdateMap { .. } | PacketC::Movement { .. }) { trace!("-> {p:?}"); @@ -60,6 +53,32 @@ impl Server { } Ok(()) } + + pub async fn connect(&mut self, id: ConnectionID) -> Vec<PacketC> { + let mut init = self.game.prime_client(); + init.insert( + 0, + PacketC::Version { + major: VERSION.0, + minor: VERSION.1, + supports_bincode: true, + }, + ); + self.connections.insert(id, ConnectionData::default()); + self.update_paused(); + init + } + + pub async fn disconnect(&mut self, conn: ConnectionID) { + if let Some(cd) = self.connections.get(&conn) { + for player in cd.players.clone() { + let _ = self.packet_in_outer(conn, PacketS::Leave { player }).await; + } + } + self.connections.remove(&conn); + self.update_paused(); + } + pub async fn packet_in_outer( &mut self, conn: ConnectionID, @@ -96,9 +115,11 @@ impl Server { } PacketS::Ready => { self.connections.entry(conn).or_default().ready = true; + self.update_paused(); } PacketS::Idle { paused } => { self.connections.entry(conn).or_default().idle = *paused; + self.update_paused(); } PacketS::Leave { player } => { self.connections @@ -143,13 +164,42 @@ impl Server { Ok(replies) } - pub async fn disconnect(&mut self, conn: ConnectionID) { - if let Some(cd) = self.connections.get(&conn) { - for player in cd.players.clone() { - let _ = self.packet_in_outer(conn, PacketS::Leave { player }).await; + pub fn update_paused(&mut self) { + let all_idle = self.connections.values().all(|c| c.idle); + let not_ready = self.connections.values().filter(|c| !c.ready).count(); + let announcing = self.announce_timer > 0.; + + let should_pause = all_idle || not_ready > 0 || announcing; + + let reason = if not_ready > 0 { + info!("Game paused: {not_ready} player are not ready"); + Some(trm!( + "s.state.paused.any_not_ready", + s = not_ready.to_string() + )) + } else if all_idle { + info!("Game paused: All players idle"); + Some(trm!("s.state.paused.all_idle")) + } else if announcing { + info!("Game paused: Waiting for announcement"); + None + } else { + if self.paused { + info!("Game unpaused"); } + None + }; + self.paused = should_pause; + + for p in self.game.players.keys() { + self.packet_out + .push_back(PacketC::Pause { state: self.paused }); + self.packet_out.push_back(PacketC::ServerHint { + position: None, + message: reason.clone(), + player: *p, + }); } - self.connections.remove(&conn); } } |