summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorstale <redkugelblitzin@gmail.com>2022-07-03 05:34:07 -0300
committerstale <redkugelblitzin@gmail.com>2022-07-03 05:34:07 -0300
commit0c0491ad17a0adc1d63c183b934df683e5e98b3f (patch)
treefbd932249d9cc55e187e5045d68125e19da407b4 /src/main.rs
parentf8735f5b539b991f8da9ec1b3e64966566d77477 (diff)
hooray for untested code
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs69
1 files changed, 41 insertions, 28 deletions
diff --git a/src/main.rs b/src/main.rs
index e4ccc56..ce1cd45 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -214,46 +214,59 @@ async fn tokio_main(conf: Conf) -> Result<(), Box<dyn Error>> {
}
// If a move is made, broadcast new board, else just send current board
-async fn gameloop(mut move_rx: tokio::sync::mpsc::UnboundedReceiver<MetaMove>, players: Arc<RwLock<PlayerMap>>, bconf: minesweeper::BoardConf) {
+type MoveStreamHandles = (tokio::sync::mpsc::UnboundedSender<MetaMove>, tokio::sync::mpsc::UnboundedReceiver<MetaMove>);
+async fn gameloop(moves: MoveStreamHandles, players: Arc<RwLock<PlayerMap>>, bconf: minesweeper::BoardConf) {
// FIXME: push new board if and only if there aren't any remaining commands in the queue
use minesweeper::*;
use flate2::{ Compression, write::DeflateEncoder };
use std::io::Write;
+ let (move_tx, mut move_rx) = moves;
let mut game = Game::new(bconf);
- let mut latest_player_name = None;
+ let mut final_player_name = None;
+ let mut desynced = true;
while let Some(req) = move_rx.recv().await {
- let done = game.phase == Phase::Die || game.phase == Phase::Win;
+ let done = |p: &Phase| { *p == Phase::Die || *p == Phase::Win };
match req {
- MetaMove::Move(m, o) => if !done {
+ MetaMove::Move(m, o) => if !done(&game.phase) {
game = game.act(m);
- if game.phase == Phase::Win || game.phase == Phase::Die {
+ desynced = true;
+ if done(&game.phase) {
game.board = game.board.grade();
+ final_player_name = players.read().await.get(&o).map(|p| p.name.clone());
}
- latest_player_name = players.read().await.get(&o).map(|p| p.name.clone());
+ move_tx.send(MetaMove::StateSync).unwrap();
},
- MetaMove::Dump => (),
- MetaMove::Reset => { game = Game::new(bconf); },
- }
- use warp::ws::Message;
- let mut board_encoder = DeflateEncoder::new(Vec::new(), Compression::default());
- board_encoder.write_all(&game.board.render()).unwrap();
- let compressed_board = board_encoder.finish().unwrap();
- let mut reply = vec![Message::binary(compressed_board)];
- let lpname = latest_player_name.as_deref().unwrap_or("unknown player").replace(' ', "&nbsp");
- match game.phase {
- Phase::Win => { reply.push(Message::text(format!("win {lpname}"))); },
- Phase::Die => { reply.push(Message::text(format!("lose {lpname}"))); },
- _ => (),
- }
- {
- let peers = players.read().await;
- for (addr, p) in peers.iter() {
- for r in reply.iter() {
- if let Err(e) = p.conn.tx.send(r.clone()) {
- println!("couldn't send game update {r:?} to {addr}: {e}");
+ MetaMove::StateSync => { // a StateDump, but consecutive ones in the queue get merged
+ if desynced { move_tx.send(MetaMove::StateDump).unwrap(); desynced = false; }
+ },
+ MetaMove::StateDump => {
+ use warp::ws::Message;
+ let mut board_encoder = DeflateEncoder::new(Vec::new(), Compression::default());
+ board_encoder.write_all(&game.board.render()).unwrap();
+ let compressed_board = board_encoder.finish().unwrap();
+ let mut reply = vec![Message::binary(compressed_board)];
+ let lpname = final_player_name.as_deref().unwrap_or("unknown player").replace(' ', "&nbsp");
+ match game.phase {
+ Phase::Win => { reply.push(Message::text(format!("win {lpname}"))); },
+ Phase::Die => { reply.push(Message::text(format!("lose {lpname}"))); },
+ _ => (),
+ }
+ let peers = players.read().await;
+ for (addr, p) in peers.iter() {
+ for r in reply.iter() {
+ if let Err(e) = p.conn.tx.send(r.clone()) {
+ println!("couldn't send game update {r:?} to {addr}: {e}");
+ }
}
}
- }
+ desynced = false;
+ },
+ MetaMove::Reset => {
+ if done(&game.phase) {
+ game = Game::new(bconf);
+ move_tx.send(MetaMove::StateDump).unwrap();
+ }
+ },
}
}
}
@@ -318,7 +331,7 @@ fn room_from_form(uid: RoomId, rinfo: &HashMap<String,String>, conf: &Conf) -> R
let players = Arc::new(RwLock::new(PlayerMap::default()));
let (cmd_tx, cmd_rx) = tokio::sync::mpsc::unbounded_channel();
- let game_handle = tokio::spawn(gameloop(cmd_rx, players.clone(), board_conf));
+ let game_handle = tokio::spawn(gameloop((cmd_tx.clone(), cmd_rx), players.clone(), board_conf));
let (pos_tx, pos_rx) = tokio::sync::mpsc::unbounded_channel();
let livepos_handle = tokio::spawn(livepos::livepos(players.clone(), pos_rx));