From 34967cd3b6530656ef0bf31810f9fd6dfb853765 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 4 Jun 2024 16:48:07 +0200 Subject: can vie games --- src/game/server.rs | 70 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 16 deletions(-) (limited to 'src/game/server.rs') 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) -> 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) -> Result<()> { bail!("accept failure") } +async fn game_loop(config: Config, state: Arc) { + 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, + alive: bool, +} + async fn handle_client(sock: TcpStream, state: Arc) -> 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) -> Result<()> { async fn handle_client_inner( sock: TcpStream, state: &Arc, - pid: &mut Option, + pid: &mut ClientState, ) -> anyhow::Result<()> { let (rx, tx) = sock.into_split(); let rx = BufReader::new(rx); @@ -79,19 +111,25 @@ impl SendPacketExt for T { async fn handle_tick( mut tx: impl AsyncWrite + Unpin, - pid: &mut Option, + cstate: &mut ClientState, state: &Arc, 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, + cstate: &mut ClientState, state: &Arc, 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); -- cgit v1.2.3-70-g09d2