feat: max timeout for move
This commit is contained in:
@@ -11,6 +11,7 @@ pub struct Server {
|
||||
pub admin_password: Arc<String>,
|
||||
pub tournament: WrappedTournament,
|
||||
pub waiting_timeout: Arc<RwLock<u64>>,
|
||||
pub max_timeout: Arc<RwLock<u64>>,
|
||||
pub demo_mode: Arc<RwLock<bool>>,
|
||||
}
|
||||
|
||||
@@ -25,6 +26,7 @@ impl Server {
|
||||
admin_password: Arc::new(admin_password),
|
||||
tournament: Arc::new(RwLock::new(None)),
|
||||
waiting_timeout: Arc::new(RwLock::new(5000)),
|
||||
max_timeout: Arc::new(RwLock::new(30000)),
|
||||
demo_mode: Arc::new(RwLock::new(demo_mode)),
|
||||
}
|
||||
}
|
||||
@@ -125,7 +127,7 @@ impl Server {
|
||||
}
|
||||
|
||||
if clients_guard.get(&addr).unwrap().read().await.ready {
|
||||
return Err(anyhow::anyhow!("ERROR:INVALID"));
|
||||
return Err(anyhow::anyhow!("ERROR:INVALID:READY"));
|
||||
}
|
||||
|
||||
let mut client = clients_guard.get(&addr).unwrap().write().await;
|
||||
@@ -263,8 +265,12 @@ impl Server {
|
||||
self.matches.write().await.remove(¤t_match_id).unwrap();
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
}
|
||||
|
||||
current_match.place_token(client.color.clone(), column);
|
||||
|
||||
if let Some(timeout_thread) = ¤t_match.timeout_thread {
|
||||
timeout_thread.abort();
|
||||
}
|
||||
|
||||
let mut viewer_messages = Vec::new();
|
||||
@@ -357,19 +363,21 @@ impl Server {
|
||||
let demo_move = random_move(¤t_match.board);
|
||||
let no_winner = winner == Color::None && !filled;
|
||||
let observers = self.observers.clone();
|
||||
|
||||
let opp_connection_move = opponent_connection.clone();
|
||||
let client_tx = tx.clone();
|
||||
if current_match.demo_mode {
|
||||
current_match.ledger.push((!client.color, demo_move, Instant::now()));
|
||||
current_match.place_token(!client.color, demo_move);
|
||||
}
|
||||
|
||||
let opp_connection_move = opponent_connection.clone();
|
||||
|
||||
current_match.wait_thread = Some(tokio::spawn(async move {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(adjusted_waiting as u64)).await;
|
||||
|
||||
if !demo_mode && no_winner {
|
||||
let _ = send(&opp_connection_move.as_ref().unwrap(), &format!("OPPONENT:{}", column));
|
||||
let _ = send(
|
||||
&opp_connection_move.as_ref().unwrap(),
|
||||
&format!("OPPONENT:{}", column),
|
||||
);
|
||||
}
|
||||
|
||||
for msg in viewer_messages {
|
||||
@@ -378,7 +386,7 @@ impl Server {
|
||||
|
||||
if demo_mode && no_winner {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(default_waiting_time)).await;
|
||||
let _ = send(&tx, &format!("OPPONENT:{}", demo_move));
|
||||
let _ = send(&client_tx, &format!("OPPONENT:{}", demo_move));
|
||||
broadcast_message(
|
||||
&observers,
|
||||
&viewers,
|
||||
@@ -388,6 +396,60 @@ impl Server {
|
||||
}
|
||||
}));
|
||||
|
||||
let max_timeout = *self.max_timeout.read().await;
|
||||
let matches = self.matches.clone();
|
||||
let tournament = self.tournament.clone();
|
||||
let clients = self.clients.clone();
|
||||
let match_id = current_match.id;
|
||||
let ledger_size = current_match.ledger.len();
|
||||
let client_username = client.username.clone();
|
||||
let client_tx = tx.clone();
|
||||
let client_addr = addr.clone();
|
||||
let observers = self.observers.clone();
|
||||
let viewers = current_match.viewers.clone();
|
||||
current_match.timeout_thread = Some(tokio::spawn(async move {
|
||||
if demo_mode {
|
||||
return;
|
||||
}
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(adjusted_waiting as u64)).await;
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(max_timeout as u64)).await;
|
||||
|
||||
let matches_guard = matches.read().await;
|
||||
let the_match = matches_guard.get(&match_id);
|
||||
if let Some(the_match) = the_match {
|
||||
let the_match = the_match.read().await;
|
||||
if the_match.ledger.len() == ledger_size {
|
||||
// forfeit the match
|
||||
let _ = send(&client_tx, "GAME:WINS");
|
||||
let _ = send(&opponent_connection.unwrap(), "GAME:LOSS");
|
||||
broadcast_message(
|
||||
&observers,
|
||||
&viewers,
|
||||
&format!("GAME:WIN:{}", client_username),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut clients_guard = clients.write().await;
|
||||
let mut client = clients_guard.get_mut(&client_addr).unwrap().write().await;
|
||||
client.current_match = None;
|
||||
client.color = Color::None;
|
||||
drop(client);
|
||||
|
||||
let mut opponent = clients_guard.get_mut(&opponent_addr).unwrap().write().await;
|
||||
opponent.current_match = None;
|
||||
opponent.color = Color::None;
|
||||
drop(opponent);
|
||||
|
||||
let mut tournament_guard = tournament.write().await;
|
||||
let tourney = tournament_guard.as_mut().unwrap();
|
||||
tourney.write().await.inform_winnder(client_addr, false);
|
||||
drop(tournament_guard);
|
||||
|
||||
matches.write().await.remove(&match_id).unwrap();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -650,6 +712,10 @@ impl Server {
|
||||
let demo_mode = *self.demo_mode.read().await;
|
||||
msg += demo_mode.to_string().as_str();
|
||||
}
|
||||
"MAX_TIMEOUT" => {
|
||||
let max_time = *self.max_timeout.read().await as f64 / 1000f64;
|
||||
msg += max_time.to_string().as_str();
|
||||
}
|
||||
&_ => return Err(anyhow::anyhow!("ERROR:INVALID:GET")),
|
||||
}
|
||||
|
||||
@@ -683,6 +749,13 @@ impl Server {
|
||||
}
|
||||
*self.waiting_timeout.write().await = (wait_time.unwrap() * 1000.0) as u64;
|
||||
}
|
||||
"MAX_TIMEOUT" => {
|
||||
let max_time = data_value.parse::<f64>();
|
||||
if max_time.is_err() {
|
||||
return Err(anyhow::anyhow!("ERROR:INVALID:SET"));
|
||||
}
|
||||
*self.max_timeout.write().await = (max_time.unwrap() * 1000.0) as u64;
|
||||
}
|
||||
&_ => return Err(anyhow::anyhow!("ERROR:INVALID:SET")),
|
||||
}
|
||||
|
||||
@@ -749,8 +822,12 @@ impl Server {
|
||||
}
|
||||
let the_match = the_match.unwrap().read().await;
|
||||
|
||||
if the_match.wait_thread.is_some() {
|
||||
the_match.wait_thread.as_ref().unwrap().abort();
|
||||
if let Some(wait_thread) = &the_match.wait_thread {
|
||||
wait_thread.abort();
|
||||
}
|
||||
|
||||
if let Some(timeout_thread) = &the_match.timeout_thread {
|
||||
timeout_thread.abort();
|
||||
}
|
||||
|
||||
self.broadcast_message(&the_match.viewers, "GAME:TERMINATED").await;
|
||||
|
||||
@@ -155,7 +155,7 @@ impl Tournament for RoundRobin {
|
||||
// Send scores
|
||||
let clients_guard = server.clients.read().await;
|
||||
for (_, player_addr) in self.players.iter() {
|
||||
let mut player = clients_guard.get(&player_addr.0).unwrap().write().await;
|
||||
let player = clients_guard.get(&player_addr.0).unwrap().read().await;
|
||||
let _ = send(&player.connection.clone(), "TOURNAMENT:END");
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -54,6 +54,7 @@ pub struct Match {
|
||||
pub viewers: Vec<SocketAddr>,
|
||||
pub ledger: Vec<(Color, usize, Instant)>,
|
||||
pub wait_thread: Option<tokio::task::JoinHandle<()>>,
|
||||
pub timeout_thread: Option<tokio::task::JoinHandle<()>>,
|
||||
pub player1: SocketAddr,
|
||||
pub player2: SocketAddr,
|
||||
}
|
||||
@@ -73,6 +74,7 @@ impl Match {
|
||||
viewers: Vec::new(),
|
||||
ledger: Vec::new(),
|
||||
wait_thread: None,
|
||||
timeout_thread: None,
|
||||
player1: if player1 == first { player1 } else { player2 },
|
||||
player2: if player1 == first { player2 } else { player1 },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user