Implement strike timeout on server side
This commit is contained in:
parent
ba1ed84b33
commit
42b0d84f9d
@ -130,31 +130,31 @@ impl GameRulesConfigurationScreen {
|
||||
KeyCode::Char(c) if ('0'..='9').contains(&c) => {
|
||||
let val = c.to_string().parse::<usize>().unwrap_or_default();
|
||||
|
||||
if self.curr_field == EditingField::MapWidth {
|
||||
if self.rules.map_width <= MAX_MAP_WIDTH {
|
||||
self.rules.map_width *= 10;
|
||||
self.rules.map_width += val;
|
||||
}
|
||||
if self.curr_field == EditingField::MapWidth
|
||||
&& self.rules.map_width <= MAX_MAP_WIDTH
|
||||
{
|
||||
self.rules.map_width *= 10;
|
||||
self.rules.map_width += val;
|
||||
}
|
||||
|
||||
if self.curr_field == EditingField::MapHeight {
|
||||
if self.rules.map_height <= MAX_MAP_HEIGHT {
|
||||
self.rules.map_height *= 10;
|
||||
self.rules.map_height += val;
|
||||
}
|
||||
if self.curr_field == EditingField::MapHeight
|
||||
&& self.rules.map_height <= MAX_MAP_HEIGHT
|
||||
{
|
||||
self.rules.map_height *= 10;
|
||||
self.rules.map_height += val;
|
||||
}
|
||||
|
||||
if self.curr_field == EditingField::BoatsList {
|
||||
if self.rules.boats_list().len() < MAX_BOATS_NUMBER {
|
||||
self.rules.add_boat(val);
|
||||
}
|
||||
if self.curr_field == EditingField::BoatsList
|
||||
&& self.rules.boats_list().len() < MAX_BOATS_NUMBER
|
||||
{
|
||||
self.rules.add_boat(val);
|
||||
}
|
||||
|
||||
if self.curr_field == EditingField::StrikeTimeout {
|
||||
let mut timeout = self.rules.strike_timeout.unwrap_or(0);
|
||||
if timeout <= MAX_STRIKE_TIMEOUT {
|
||||
timeout *= 10;
|
||||
timeout += val;
|
||||
timeout += val as u64;
|
||||
self.rules.strike_timeout = Some(timeout);
|
||||
}
|
||||
}
|
||||
|
@ -25,5 +25,5 @@ pub const INVITE_CODE_LENGTH: usize = 5;
|
||||
pub const MIN_PLAYER_NAME_LENGTH: usize = 1;
|
||||
pub const MAX_PLAYER_NAME_LENGTH: usize = 10;
|
||||
|
||||
pub const MIN_STRIKE_TIMEOUT: usize = 5;
|
||||
pub const MAX_STRIKE_TIMEOUT: usize = 90;
|
||||
pub const MIN_STRIKE_TIMEOUT: u64 = 5;
|
||||
pub const MAX_STRIKE_TIMEOUT: u64 = 90;
|
||||
|
@ -16,7 +16,7 @@ pub struct GameRules {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
pub player_continue_on_hit: bool,
|
||||
#[serde_as(as = "NoneAsEmptyString")]
|
||||
pub strike_timeout: Option<usize>,
|
||||
pub strike_timeout: Option<u64>,
|
||||
pub bot_type: BotType,
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,8 @@ pub struct PlayConfiguration {
|
||||
pub ordinate_alphabet: &'static str,
|
||||
pub min_player_name_len: usize,
|
||||
pub max_player_name_len: usize,
|
||||
pub min_strike_timeout: usize,
|
||||
pub max_strike_timeout: usize,
|
||||
pub min_strike_timeout: u64,
|
||||
pub max_strike_timeout: u64,
|
||||
}
|
||||
|
||||
impl Default for PlayConfiguration {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use actix::prelude::*;
|
||||
use actix::{Actor, Context, Handler};
|
||||
@ -6,6 +7,7 @@ use uuid::Uuid;
|
||||
|
||||
use crate::bot_player::BotPlayer;
|
||||
use crate::data::*;
|
||||
use crate::utils::time_utils::time;
|
||||
|
||||
pub trait Player {
|
||||
fn get_name(&self) -> &str;
|
||||
@ -51,6 +53,9 @@ pub trait Player {
|
||||
fn opponent_replaced_by_bot(&self);
|
||||
}
|
||||
|
||||
/// How often strike timeout controller is run
|
||||
const STRIKE_TIMEOUT_CONTROL: Duration = Duration::from_secs(1);
|
||||
|
||||
fn opponent(index: usize) -> usize {
|
||||
match index {
|
||||
0 => 1,
|
||||
@ -85,6 +90,7 @@ pub struct Game {
|
||||
map_0: Option<GameMap>,
|
||||
map_1: Option<GameMap>,
|
||||
turn: usize,
|
||||
curr_strike_request_started: u64,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
@ -96,6 +102,7 @@ impl Game {
|
||||
map_0: None,
|
||||
map_1: None,
|
||||
turn: 0,
|
||||
curr_strike_request_started: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,10 +137,14 @@ impl Game {
|
||||
self.turn
|
||||
);
|
||||
|
||||
self.request_fire();
|
||||
self.request_fire(true);
|
||||
}
|
||||
|
||||
fn request_fire(&self) {
|
||||
fn request_fire(&mut self, reset_counter: bool) {
|
||||
if reset_counter {
|
||||
self.curr_strike_request_started = time();
|
||||
}
|
||||
|
||||
self.players[self.turn].request_fire(self.get_game_status_for_player(self.turn));
|
||||
self.players[opponent(self.turn)]
|
||||
.opponent_must_fire(self.get_game_status_for_player(opponent(self.turn)));
|
||||
@ -148,6 +159,27 @@ impl Game {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Replace user for a fire in case of timeout
|
||||
fn force_fire_in_case_of_timeout(&mut self) {
|
||||
if self.status != GameStatus::Started || self.rules.strike_timeout.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let timeout = self.rules.strike_timeout.unwrap_or_default();
|
||||
|
||||
if time() <= self.curr_strike_request_started + timeout {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine target of fire
|
||||
let target = self
|
||||
.get_game_status_for_player(opponent(self.turn))
|
||||
.find_fire_coordinates_for_bot_type(self.rules.bot_type);
|
||||
|
||||
// Fire as player
|
||||
self.handle_fire(target);
|
||||
}
|
||||
|
||||
fn player_map_mut(&mut self, id: usize) -> &mut GameMap {
|
||||
match id {
|
||||
0 => self.map_0.as_mut(),
|
||||
@ -166,7 +198,7 @@ impl Game {
|
||||
// Easiest case : player missed his fire
|
||||
if result == FireResult::Missed {
|
||||
self.turn = opponent(self.turn);
|
||||
self.request_fire();
|
||||
self.request_fire(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -188,7 +220,9 @@ impl Game {
|
||||
self.turn = opponent(self.turn);
|
||||
}
|
||||
|
||||
self.request_fire();
|
||||
self.request_fire(
|
||||
result != FireResult::AlreadyTargetedPosition && result != FireResult::Rejected,
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_request_rematch(&mut self, player_id: Uuid) {
|
||||
@ -234,6 +268,14 @@ impl Game {
|
||||
|
||||
impl Actor for Game {
|
||||
type Context = Context<Self>;
|
||||
|
||||
fn started(&mut self, ctx: &mut Self::Context) {
|
||||
if self.rules.strike_timeout.is_some() {
|
||||
ctx.run_interval(STRIKE_TIMEOUT_CONTROL, |act, _ctx| {
|
||||
act.force_fire_in_case_of_timeout();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Message)]
|
||||
@ -387,7 +429,7 @@ impl Handler<PlayerLeftGame> for Game {
|
||||
|
||||
// Re-do current action
|
||||
if self.status == GameStatus::Started {
|
||||
self.request_fire();
|
||||
self.request_fire(true);
|
||||
} else if self.status == GameStatus::WaitingForBoatsDisposition {
|
||||
self.players[offline_player].query_boats_layout(&self.rules);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use std::io::ErrorKind;
|
||||
|
||||
pub mod network_utils;
|
||||
pub mod string_utils;
|
||||
pub mod time_utils;
|
||||
|
||||
pub type Res<E = ()> = Result<E, Box<dyn Error>>;
|
||||
|
||||
|
9
rust/sea_battle_backend/src/utils/time_utils.rs
Normal file
9
rust/sea_battle_backend/src/utils/time_utils.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// Get the current time since epoch
|
||||
pub fn time() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
}
|
Loading…
Reference in New Issue
Block a user