aboutsummaryrefslogtreecommitdiff
path: root/src/game/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/server.rs')
-rw-r--r--src/game/server.rs70
1 files changed, 54 insertions, 16 deletions
diff --git a/src/game/server.rs b/src/game/server.rs
index a4472a8..f1d10d2 100644
--- a/src/game/server.rs
+++ b/src/game/server.rs
@@ -1,15 +1,18 @@
-use super::{protocol::Packet, Config};
+use super::{protocol::Packet, Config, Game};
use crate::State;
use anyhow::{anyhow, bail, Result};
use log::{debug, error, info};
-use std::sync::Arc;
+use std::{ops::ControlFlow, sync::Arc, time::Duration};
use tokio::{
io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
net::{TcpListener, TcpStream},
spawn,
+ time::sleep,
};
pub async fn game_server(config: Config, state: Arc<State>) -> Result<()> {
+ spawn(game_loop(config.clone(), state.clone()));
+
let listener = TcpListener::bind(config.bind).await?;
info!("listening on {}", listener.local_addr()?);
while let Ok((sock, addr)) = listener.accept().await {
@@ -25,10 +28,39 @@ pub async fn game_server(config: Config, state: Arc<State>) -> Result<()> {
bail!("accept failure")
}
+async fn game_loop(config: Config, state: Arc<State>) {
+ loop {
+ sleep(Duration::from_secs_f32(1. / config.tickrate)).await;
+
+ let mut g = state.game.write().await;
+ let res = g.tick();
+ match res {
+ ControlFlow::Continue(()) => {
+ let _ = state.tick.send(false);
+ }
+ ControlFlow::Break(winner) => {
+ info!("winner: {winner:?}");
+ let p = state.players.read().await;
+ *g = Game::new(p.clone().into_iter().collect());
+ let _ = state.tick.send(true);
+ }
+ }
+ drop(g);
+ }
+}
+
+struct ClientState {
+ pid: Option<u32>,
+ alive: bool,
+}
+
async fn handle_client(sock: TcpStream, state: Arc<State>) -> Result<()> {
- let mut pid = None;
- let res = handle_client_inner(sock, &state, &mut pid).await;
- if let Some(pid) = pid {
+ let mut cstate = ClientState {
+ pid: None,
+ alive: false,
+ };
+ let res = handle_client_inner(sock, &state, &mut cstate).await;
+ if let Some(pid) = cstate.pid {
state.players.write().await.remove(&pid);
}
res
@@ -37,7 +69,7 @@ async fn handle_client(sock: TcpStream, state: Arc<State>) -> Result<()> {
async fn handle_client_inner(
sock: TcpStream,
state: &Arc<State>,
- pid: &mut Option<u32>,
+ pid: &mut ClientState,
) -> anyhow::Result<()> {
let (rx, tx) = sock.into_split();
let rx = BufReader::new(rx);
@@ -79,19 +111,25 @@ impl<T: AsyncWrite + Unpin> SendPacketExt for T {
async fn handle_tick(
mut tx: impl AsyncWrite + Unpin,
- pid: &mut Option<u32>,
+ cstate: &mut ClientState,
state: &Arc<State>,
new_game: bool,
) -> anyhow::Result<()> {
- let Some(pid) = pid else { return Ok(()) };
+ let Some(pid) = cstate.pid else { return Ok(()) };
let mut events = Vec::new();
+ if new_game {
+ if cstate.alive {
+ tx.send_packet(Packet::Win(0, 0)).await?;
+ }
+ cstate.alive = true;
+ }
{
let g = state.game.read().await;
if new_game {
events.push(Packet::Game {
my_id: 0,
- width: g.size.x as usize,
- height: g.size.y as usize,
+ width: g.map.size.x as usize,
+ height: g.map.size.y as usize,
});
for (player, (_, _, name)) in &g.heads {
events.push(Packet::Player {
@@ -110,7 +148,7 @@ async fn handle_tick(
if !g.dead.is_empty() {
events.push(Packet::Die(g.dead.clone()));
}
- if g.dead.contains(pid) {
+ if g.dead.contains(&pid) {
events.push(Packet::Lose(0, 0)); // TODO implement stats
}
events.push(Packet::Tick);
@@ -123,7 +161,7 @@ async fn handle_tick(
async fn handle_packet(
mut tx: impl AsyncWrite + Unpin,
- pid: &mut Option<u32>,
+ cstate: &mut ClientState,
state: &Arc<State>,
line: String,
) -> anyhow::Result<()> {
@@ -141,7 +179,7 @@ async fn handle_packet(
username,
password: _,
} => {
- if pid.is_some() {
+ if cstate.pid.is_some() {
tx.send_packet(Packet::Error("already joined".to_string()))
.await?
} else {
@@ -151,13 +189,13 @@ async fn handle_packet(
id += 1;
}
g.insert(id, username);
- *pid = Some(id);
+ cstate.pid = Some(id);
}
}
Packet::Move(dir) => {
- if let Some(pid) = pid {
+ if let Some(pid) = cstate.pid {
let mut g = state.game.write().await;
- if let Some((head_dir, _, _)) = g.heads.get_mut(pid) {
+ if let Some((head_dir, _, _)) = g.heads.get_mut(&pid) {
*head_dir = dir
} else {
drop(g);