From 43babbbfabbca7c114894dd56581778219aa9c98 Mon Sep 17 00:00:00 2001 From: Tangent Wantwight Date: Sat, 30 May 2020 16:10:55 -0400 Subject: [PATCH] Maintain state records for connected players --- src/net/server.rs | 74 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/src/net/server.rs b/src/net/server.rs index b74a16d..b050737 100644 --- a/src/net/server.rs +++ b/src/net/server.rs @@ -5,10 +5,13 @@ use serde_json::json; use std::sync::Arc; use stream::iter; -pub async fn greet(sink: &mut T) -> Result<()> -where - T: Sink + Unpin, -{ +/// There is a point at which a client falls far enough behind +/// that it's probably not worth trying to catch them up; for now, +/// implement this as a buffer size limit and disconnect a client if +/// the cap is reached. More elegant solutions may be reached in the future. +const CHANNEL_BUFFER: usize = 200; + +pub async fn greet(sink: &mut Sender) -> Result<()> { let mut greeting = iter(vec![ ServerMessage::Meta { m: Meta { @@ -16,7 +19,10 @@ where helo: Some("Dedicated base2020 server".into()), }, }, - ServerMessage::SetState { u: Some(0), s: json!({}) }, + ServerMessage::SetState { + u: Some(0), + s: json!({}), + }, ]) .map(Ok); @@ -25,7 +31,12 @@ where .context("Greeting client") } +pub struct PlayerState { + sender: Sender, +} + pub struct Server { + players: Vec>, } #[derive(Clone)] @@ -37,6 +48,7 @@ impl Server { pub fn create() -> Handle { Handle { server: Arc::new(Mutex::new(Server { + players: Vec::new(), })), } } @@ -44,28 +56,62 @@ impl Server { pub fn process_message(&mut self, player: usize, msg: ClientMessage) { debug!("Client#{} message: {:?}", player, &msg); } + + pub async fn add_player(&mut self, mut sender: Sender) -> Result { + // TODO: limit total number of players + + // allot player ID + let player_id = self + .players + .iter() + .position(|slot| slot.is_none()) + .unwrap_or_else(|| { + self.players.push(None); + self.players.len() - 1 + }); + + // connect player + greet(&mut sender).await?; + self.players[player_id] = Some(PlayerState { sender }); + info!("Client#{} connected", player_id); + Ok(player_id) + } + + pub fn remove_player(&mut self, player_id: PlayerId) { + if player_id < self.players.len() && self.players[player_id].is_some() { + self.players[player_id] = None; + info!("Client#{} disconnected", player_id); + } else { + error!("Tried to disconnect Client#{} but there was no record for them", player_id); + } + } } -where -{ pub async fn run_client( handle: Handle, source: &mut (impl Stream> + Send + Unpin), - mut sink: &mut (impl Sink + Send + Unpin), + sink: &mut (impl Sink + Send + Unpin), ) -> Result<()> { - let output_task = async { - greet(&mut sink).await?; - Ok::<(), Error>(()) - }; + let (sender, receiver) = channel(CHANNEL_BUFFER); + + // register player + let player_id = handle.server.lock().await.add_player(sender).await?; + + let output_task = receiver.map(Ok).forward(sink); let input_task = async { loop { match source.next().await { - Some(Ok(msg)) => handle.server.lock().await.process_message(0, msg), + Some(Ok(msg)) => handle.server.lock().await.process_message(player_id, msg), Some(Err(error)) => return Err(error), None => break Ok(()), } } }; - try_join(output_task, input_task).await.map(|((), ())| ()) + let result = try_join(output_task, input_task).await.map(|_| ()); + + // deregister player, whether normally or via error + handle.server.lock().await.remove_player(player_id); + + result }