Maintain state records for connected players
This commit is contained in:
parent
750cfe1630
commit
43babbbfab
1 changed files with 60 additions and 14 deletions
|
@ -5,10 +5,13 @@ use serde_json::json;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use stream::iter;
|
use stream::iter;
|
||||||
|
|
||||||
pub async fn greet<T>(sink: &mut T) -> Result<()>
|
/// There is a point at which a client falls far enough behind
|
||||||
where
|
/// that it's probably not worth trying to catch them up; for now,
|
||||||
T: Sink<ServerMessage, Error = Error> + Unpin,
|
/// 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<ServerMessage>) -> Result<()> {
|
||||||
let mut greeting = iter(vec![
|
let mut greeting = iter(vec![
|
||||||
ServerMessage::Meta {
|
ServerMessage::Meta {
|
||||||
m: Meta {
|
m: Meta {
|
||||||
|
@ -16,7 +19,10 @@ where
|
||||||
helo: Some("Dedicated base2020 server".into()),
|
helo: Some("Dedicated base2020 server".into()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ServerMessage::SetState { u: Some(0), s: json!({}) },
|
ServerMessage::SetState {
|
||||||
|
u: Some(0),
|
||||||
|
s: json!({}),
|
||||||
|
},
|
||||||
])
|
])
|
||||||
.map(Ok);
|
.map(Ok);
|
||||||
|
|
||||||
|
@ -25,7 +31,12 @@ where
|
||||||
.context("Greeting client")
|
.context("Greeting client")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PlayerState {
|
||||||
|
sender: Sender<ServerMessage>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
|
players: Vec<Option<PlayerState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -37,6 +48,7 @@ impl Server {
|
||||||
pub fn create() -> Handle {
|
pub fn create() -> Handle {
|
||||||
Handle {
|
Handle {
|
||||||
server: Arc::new(Mutex::new(Server {
|
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) {
|
pub fn process_message(&mut self, player: usize, msg: ClientMessage) {
|
||||||
debug!("Client#{} message: {:?}", player, &msg);
|
debug!("Client#{} message: {:?}", player, &msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn add_player(&mut self, mut sender: Sender<ServerMessage>) -> Result<PlayerId> {
|
||||||
|
// 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(
|
pub async fn run_client(
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
source: &mut (impl Stream<Item = Result<ClientMessage, Error>> + Send + Unpin),
|
source: &mut (impl Stream<Item = Result<ClientMessage, Error>> + Send + Unpin),
|
||||||
mut sink: &mut (impl Sink<ServerMessage, Error = Error> + Send + Unpin),
|
sink: &mut (impl Sink<ServerMessage, Error = Error> + Send + Unpin),
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let output_task = async {
|
let (sender, receiver) = channel(CHANNEL_BUFFER);
|
||||||
greet(&mut sink).await?;
|
|
||||||
Ok::<(), Error>(())
|
// 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 {
|
let input_task = async {
|
||||||
loop {
|
loop {
|
||||||
match source.next().await {
|
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),
|
Some(Err(error)) => return Err(error),
|
||||||
None => break Ok(()),
|
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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue