diff --git a/src/server.rs b/src/server.rs index a5e3fe9..e9fa501 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,4 +1,4 @@ -use crate::{tournaments::Tournament, types::*, *}; +use crate::{tournaments::*, types::*, *}; pub struct Server { pub clients: Clients, @@ -9,7 +9,8 @@ pub struct Server { pub admin_password: Arc, pub tournament: WrappedTournament, pub waiting_timeout: Arc>, - pub demo_mode: bool, + pub demo_mode: Arc>, + pub tournament_type: String, } impl Server { @@ -23,7 +24,8 @@ impl Server { admin_password: Arc::new(admin_password), tournament: Arc::new(RwLock::new(None)), waiting_timeout: Arc::new(RwLock::new(5000)), - demo_mode, + demo_mode: Arc::new(RwLock::new(demo_mode)), + tournament_type, } } @@ -67,7 +69,7 @@ impl Server { ))), ); - let _ = crate::send(&tx, "CONNECT:ACK"); + let _ = send(&tx, "CONNECT:ACK"); Ok(()) } @@ -117,20 +119,22 @@ impl Server { let mut client = clients_guard.get(&addr).unwrap().write().await; client.ready = true; - let _ = crate::send(&tx, "READY:ACK"); + let _ = send(&tx, "READY:ACK"); - if self.demo_mode { - let match_id: u32 = crate::gen_match_id(&self.matches).await; + let is_demo_mode = self.demo_mode.read().await.clone(); + if is_demo_mode { + let match_id: u32 = gen_match_id(&self.matches).await; let new_match = Arc::new(RwLock::new(Match::new( match_id, addr.to_string().parse()?, addr.to_string().parse()?, + is_demo_mode, ))); self.matches.write().await.insert(match_id, new_match.clone()); client.ready = false; client.current_match = Some(match_id); client.color = Color::Red; - let _ = crate::send(&tx, "GAME:START:1"); + let _ = send(&tx, "GAME:START:1"); } Ok(()) @@ -179,7 +183,7 @@ impl Server { || (current_match.ledger.last().is_some() && current_match.ledger.last().unwrap().0 == client.color) { - let _ = crate::send(&tx, "ERROR:INVALID:MOVE"); + let _ = send(&tx, "ERROR:INVALID:MOVE"); invalid = true; } @@ -192,18 +196,19 @@ impl Server { // Check if valid move if column >= 7 && !invalid { - let _ = crate::send(&tx, "ERROR:INVALID:MOVE"); + let _ = send(&tx, "ERROR:INVALID:MOVE"); invalid = true; } if current_match.board[column][5] != Color::None && !invalid { - let _ = crate::send(&tx, "ERROR:INVALID:MOVE"); + let _ = send(&tx, "ERROR:INVALID:MOVE"); invalid = true; } // Terminate games if a player makes an invalid move if invalid { let current_match_id = current_match.id; + let is_demo_mode = current_match.demo_mode; let viewers = current_match.viewers.clone(); drop(current_match); @@ -211,12 +216,12 @@ impl Server { drop(client); drop(clients_guard); - if self.demo_mode { + if is_demo_mode { self.terminate_match(current_match_id).await; tx.send(Message::Close(None))?; } else { - let _ = crate::send(&tx, "GAME:LOSS"); - let _ = crate::send(&opponent_connection, "GAME:WINS"); + let _ = send(&tx, "GAME:LOSS"); + let _ = send(&opponent_connection, "GAME:WINS"); self.broadcast_message(&viewers, &format!("GAME:WIN:{}", opponent_username)).await; let mut clients_guard = self.clients.write().await; @@ -252,9 +257,9 @@ impl Server { if winner != Color::None { if winner == client.color { - let _ = crate::send(&tx, "GAME:WINS"); - if !self.demo_mode { - let _ = crate::send(&opponent_connection, "GAME:LOSS"); + let _ = send(&tx, "GAME:WINS"); + if !current_match.demo_mode { + let _ = send(&opponent_connection, "GAME:LOSS"); } self.broadcast_message( ¤t_match.viewers, @@ -262,9 +267,9 @@ impl Server { ) .await; } else { - let _ = crate::send(&tx, "GAME:LOSS"); - if !self.demo_mode { - let _ = crate::send(&opponent_connection, "GAME:WINS"); + let _ = send(&tx, "GAME:LOSS"); + if !current_match.demo_mode { + let _ = send(&opponent_connection, "GAME:WINS"); } self.broadcast_message( ¤t_match.viewers, @@ -273,9 +278,9 @@ impl Server { .await; } } else if filled { - let _ = crate::send(&tx, "GAME:DRAW"); - if !self.demo_mode { - let _ = crate::send(&opponent_connection, "GAME:DRAW"); + let _ = send(&tx, "GAME:DRAW"); + if !current_match.demo_mode { + let _ = send(&opponent_connection, "GAME:DRAW"); } self.broadcast_message(¤t_match.viewers, "GAME:DRAW").await; } @@ -283,6 +288,7 @@ impl Server { // remove match from matchmaker if winner != Color::None || filled { let current_match_id = current_match.id; + let is_demo_mode = current_match.demo_mode; drop(client); drop(current_match); @@ -306,7 +312,7 @@ impl Server { drop(opponent); matches_guard.remove(¤t_match_id).unwrap(); - if !self.demo_mode && matches_guard.is_empty() { + if !is_demo_mode && matches_guard.is_empty() { drop(matches_guard); drop(clients_guard); @@ -321,17 +327,17 @@ impl Server { return Ok(()); } - let connection_to_send = if !self.demo_mode { + let connection_to_send = if !current_match.demo_mode { opponent_connection.clone() } else { tx.clone() }; - let column_to_use = if !self.demo_mode { + let column_to_use = if !current_match.demo_mode { column } else { - crate::random_move(¤t_match.board) + random_move(¤t_match.board) }; - if self.demo_mode { + if current_match.demo_mode { let move_to_dispatch = current_match.move_to_dispatch.clone(); current_match.ledger.push(move_to_dispatch); current_match.move_to_dispatch = (Color::Yellow, column_to_use); @@ -343,7 +349,7 @@ impl Server { let matches_move = self.matches.clone(); let observers_move = self.observers.clone(); let match_id_move = current_match.id; - let demo_mode_move = self.demo_mode; + let demo_mode_move = current_match.demo_mode; current_match.wait_thread = Some(tokio::spawn(async move { tokio::time::sleep(tokio::time::Duration::from_millis(waiting as u64)).await; @@ -354,7 +360,7 @@ impl Server { current_match.move_to_dispatch = (Color::None, 0); if demo_mode_move { - crate::broadcast_message( + broadcast_message( &observers_move, ¤t_match.viewers, &format!("GAME:MOVE:{}:{}", "demo", column_to_use), @@ -365,7 +371,7 @@ impl Server { drop(current_match); drop(matches_guard); - let _ = crate::send(&connection_to_send, &format!("OPPONENT:{}", column_to_use)); + let _ = send(&connection_to_send, &format!("OPPONENT:{}", column_to_use)); })); Ok(()) @@ -395,7 +401,7 @@ impl Server { to_send.remove(to_send.len() - 1); } - let _ = crate::send(&tx, to_send.as_str()); + let _ = send(&tx, to_send.as_str()); Ok(()) } @@ -426,7 +432,7 @@ impl Server { to_send.remove(to_send.len() - 1); } - let _ = crate::send(&tx, to_send.as_str()); + let _ = send(&tx, to_send.as_str()); Ok(()) } @@ -447,7 +453,7 @@ impl Server { let player1 = clients_guard.get(&the_match.player1).unwrap().read().await.username.clone(); let mut player2 = clients_guard.get(&the_match.player2).unwrap().read().await.username.clone(); - if self.demo_mode { + if the_match.demo_mode { player2 = "demo".to_string(); } let ledger = the_match.ledger.clone(); @@ -468,7 +474,7 @@ impl Server { message.pop(); - let _ = crate::send(&tx, &message); + let _ = send(&tx, &message); Ok(()) } @@ -488,7 +494,7 @@ impl Server { let mut admin_guard = self.admin.write().await; *admin_guard = Some(addr.to_string().parse()?); - let _ = crate::send(&tx, "ADMIN:AUTH:ACK"); + let _ = send(&tx, "ADMIN:AUTH:ACK"); Ok(()) } @@ -526,7 +532,7 @@ impl Server { self.terminate_match(match_id).await; - if !self.demo_mode && self.matches.read().await.is_empty() { + if self.tournament.read().await.is_some() && self.matches.read().await.is_empty() { let mut tournament_guard = self.tournament.write().await; let tourney = tournament_guard.as_mut().unwrap(); tourney.write().await.next(&self).await; @@ -547,7 +553,7 @@ impl Server { return Err(anyhow::anyhow!("ERROR:INVALID:AUTH")); } - if self.tournament.read().await.is_some() || self.demo_mode { + if self.tournament.read().await.is_some() { return Err(anyhow::anyhow!("ERROR:INVALID:TOURNAMENT")); } @@ -565,9 +571,9 @@ impl Server { drop(clients_guard); - let mut tourney = match tournament_type.as_str() { - "round_robin" => crate::tournaments::round_robin::RoundRobin::new(&ready_players), - &_ => crate::tournaments::round_robin::RoundRobin::new(&ready_players), + let mut tourney = match self.tournament_type.as_str() { + "RoundRobin" => RoundRobin::new(&ready_players), + &_ => RoundRobin::new(&ready_players), }; tourney.start(&self).await; @@ -589,7 +595,7 @@ impl Server { return Err(anyhow::anyhow!("ERROR:INVALID:AUTH")); } - if self.tournament.read().await.is_none() || self.demo_mode { + if self.tournament.read().await.is_none() { return Err(anyhow::anyhow!("ERROR:INVALID:TOURNAMENT")); } @@ -598,7 +604,7 @@ impl Server { tourney.write().await.cancel(&self).await; *tournament_guard = None; - let _ = crate::send(&tx, "TOURNAMENT:CANCEL:ACK"); + let _ = send(&tx, "TOURNAMENT:CANCEL:ACK"); Ok(()) } @@ -621,7 +627,7 @@ impl Server { ) -> Result<(), anyhow::Error> { let mut msg = "GET:MOVE_WAIT:".to_string(); msg += &(*self.waiting_timeout.read().await as f64 / 1000f64).to_string(); - let _ = crate::send(&tx, &msg); + let _ = send(&tx, &msg); Ok(()) } @@ -630,13 +636,43 @@ impl Server { tx: UnboundedSender, ) -> Result<(), anyhow::Error> { let status = self.tournament.read().await.is_some(); - if self.demo_mode { - let _ = crate::send(&tx, "GET:TOURNAMENT_STATUS:DEMO"); + let mut msg = "GET:TOURNAMENT_STATUS:".to_string(); + if status { + msg += self.tournament.read().await.as_ref().unwrap().read().await.get_type().as_str(); } else { - let mut msg = "GET:TOURNAMENT_STATUS:".to_string(); msg += status.to_string().as_str(); - let _ = crate::send(&tx, &msg); } + let _ = send(&tx, &msg); + Ok(()) + } + + pub async fn handle_get_demo_mode( + &self, + tx: UnboundedSender, + ) -> Result<(), anyhow::Error> { + let demo_mode = *self.demo_mode.read().await; + let mut msg = "GET:DEMO_MODE:".to_string(); + msg += demo_mode.to_string().as_str(); + let _ = send(&tx, &msg); + Ok(()) + } + + pub async fn handle_set_demo_mode( + &self, + tx: UnboundedSender, + addr: SocketAddr, + demo_mode: bool, + ) -> Result<(), anyhow::Error> { + if !self.auth_check(addr).await { + return Err(anyhow::anyhow!("ERROR:INVALID:AUTH")); + } + + if self.tournament.read().await.is_some() { + return Err(anyhow::anyhow!("ERROR:INVALID:TOURNAMENT")); + } + + *self.demo_mode.write().await = demo_mode; + let _ = send(&tx, "SET:DEMO_MODE:ACK"); Ok(()) } @@ -712,7 +748,7 @@ impl Server { player1.color = Color::None; drop(player1); - if !self.demo_mode { + if !the_match.demo_mode { let mut player2 = clients_guard.get(&the_match.player2).unwrap().write().await; let _ = send(&player2.connection, "GAME:TERMINATED"); player2.current_match = None; diff --git a/src/tournaments/mod.rs b/src/tournaments/mod.rs index 724f149..f956c0a 100644 --- a/src/tournaments/mod.rs +++ b/src/tournaments/mod.rs @@ -16,4 +16,5 @@ pub trait Tournament { async fn start(&mut self, server: &Server); async fn cancel(&mut self, server: &Server); fn is_completed(&self) -> bool; + fn get_type(&self) -> String; } diff --git a/src/tournaments/round_robin.rs b/src/tournaments/round_robin.rs index 5a2024c..5d3bff3 100644 --- a/src/tournaments/round_robin.rs +++ b/src/tournaments/round_robin.rs @@ -29,6 +29,7 @@ impl RoundRobin { match_id, *player1_addr, *player2_addr, + false, ))); let match_guard = new_match.read().await; @@ -185,4 +186,8 @@ impl Tournament for RoundRobin { fn is_completed(&self) -> bool { self.is_completed } + + fn get_type(&self) -> String { + "RoundRobin".to_string() + } } diff --git a/src/types.rs b/src/types.rs index 8a9686a..b6f33bd 100644 --- a/src/types.rs +++ b/src/types.rs @@ -40,6 +40,7 @@ impl Client { pub struct Match { pub id: u32, + pub demo_mode: bool, pub board: Vec>, pub viewers: Vec, pub ledger: Vec<(Color, usize)>, @@ -50,7 +51,7 @@ pub struct Match { } impl Match { - pub fn new(id: u32, player1: SocketAddr, player2: SocketAddr) -> Match { + pub fn new(id: u32, player1: SocketAddr, player2: SocketAddr, demo_mode: bool) -> Match { let first = if rand::rng().random_range(0..=1) == 0 { player1.to_string().parse().unwrap() } else { @@ -59,6 +60,7 @@ impl Match { Match { id, + demo_mode, board: vec![vec![Color::None; 6]; 7], viewers: Vec::new(), ledger: Vec::new(),