mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Make match loading forcefully advanced after a time
This commit is contained in:
@@ -1322,6 +1322,11 @@ impl CustomGameLogic for BattleArenaLogic {
|
||||
if generic.is_game_done() {
|
||||
return true;
|
||||
}
|
||||
let game_start = generic.game_start.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if game_start == i64::MIN || game_start > chrono::Utc::now().timestamp() {
|
||||
// game has not started yet, player probably timed out while loading (which we can ignore)
|
||||
return true;
|
||||
}
|
||||
let player_id = player.descriptor.player_id;
|
||||
self.do_destruct_tasks(generic, player_id).await;
|
||||
self.player_tracking.disconnect_player(player_id).await;
|
||||
@@ -1620,12 +1625,18 @@ impl CustomGameLogic for BattleArenaLogic {
|
||||
}
|
||||
if generic.is_game_done() {
|
||||
self.abort_timer_sync().await;
|
||||
#[cfg(debug_assertions)]
|
||||
log::debug!("Game {} is already complete", generic.game_guid());
|
||||
return true;
|
||||
}
|
||||
if self.check_if_match_time_is_done(generic).await {
|
||||
#[cfg(debug_assertions)]
|
||||
log::debug!("Out of time for game {}", generic.game_guid());
|
||||
return true;
|
||||
}
|
||||
if generic.map_config.capture_points.is_empty() {
|
||||
#[cfg(debug_assertions)]
|
||||
log::debug!("No capture points for game {}", generic.game_guid());
|
||||
return true; // don't bother trying to track whether players are in capture points since there are none
|
||||
}
|
||||
if let Some(player_team) = self.player_tracking.team(motion.player_id).await {
|
||||
@@ -1646,6 +1657,8 @@ impl CustomGameLogic for BattleArenaLogic {
|
||||
self.capture_tracking.on_exit(generic, was_in_point, motion.player_id, player_team as i8, self.config.num_segments as f32).await;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("Unknown team for player {} in game {}", motion.player_id, generic.game_guid());
|
||||
}
|
||||
if let Some(tick_info) = self.capture_tracking.tick(generic, self.config.num_segments as f32).await {
|
||||
// handle shield (de)activation
|
||||
|
||||
@@ -418,6 +418,11 @@ impl CustomGameLogic for EliminationLogic {
|
||||
if generic.is_game_done() {
|
||||
return true;
|
||||
}
|
||||
let game_start = generic.game_start.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if game_start == i64::MIN || game_start > chrono::Utc::now().timestamp() {
|
||||
// game has not started yet, player probably timed out while loading (which we can ignore)
|
||||
return true;
|
||||
}
|
||||
if chrono::Utc::now().timestamp() >= generic.game_end() {
|
||||
generic.game_done();
|
||||
self.abort_timer_sync().await;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub use pit::PitLogic;
|
||||
mod team_death_match;
|
||||
pub use team_death_match::TeamDeathMatchLogic;
|
||||
|
||||
mod trackers;
|
||||
pub(super) mod trackers;
|
||||
|
||||
async fn respawn_player_after(after: chrono::DateTime<chrono::Utc>, players: Vec<crate::matches::generic::UserSender>, spawn: oj_rc_core::persist::config::Point, player_id: u8, alive_flag: std::sync::Arc<std::sync::atomic::AtomicBool>) {
|
||||
let sleep_dur = after.signed_duration_since(chrono::Utc::now()).to_std().expect("Respawn duration too long to sleep");
|
||||
|
||||
@@ -353,6 +353,11 @@ impl CustomGameLogic for PitLogic {
|
||||
if generic.is_game_done() {
|
||||
return true;
|
||||
}
|
||||
let game_start = generic.game_start.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if game_start == i64::MIN || game_start > chrono::Utc::now().timestamp() {
|
||||
// game has not started yet, player probably timed out while loading (which we can ignore)
|
||||
return true;
|
||||
}
|
||||
let read_lock = generic.users.read().await;
|
||||
if read_lock.len() == 1 {
|
||||
// nobody to play against, automatically end the game
|
||||
|
||||
@@ -325,6 +325,11 @@ impl CustomGameLogic for TeamDeathMatchLogic {
|
||||
if generic.is_game_done() {
|
||||
return true;
|
||||
}
|
||||
let game_start = generic.game_start.load(std::sync::atomic::Ordering::Relaxed);
|
||||
if game_start == i64::MIN || game_start > chrono::Utc::now().timestamp() {
|
||||
// game has not started yet, player probably timed out while loading (which we can ignore)
|
||||
return true;
|
||||
}
|
||||
if let Some(winning_team) = PlayerTracker::single_remaining_team(generic).await {
|
||||
log::info!("All players except those on team {} have disconnected, ending game {} early", winning_team, generic.game_guid());
|
||||
self.do_win(WinReason::OutOfPlayers, generic, winning_team).await;
|
||||
|
||||
@@ -3,3 +3,6 @@ pub use surrender::{SurrenderGameTracker, SurrenderVoteResult};
|
||||
|
||||
mod ticker;
|
||||
pub use ticker::TickTracker;
|
||||
|
||||
mod timeout;
|
||||
pub use timeout::Timeout;
|
||||
|
||||
84
rc_multiplayer/src/matches/modes/trackers/timeout.rs
Normal file
84
rc_multiplayer/src/matches/modes/trackers/timeout.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
const TIMEOUT_GRANULARITY: std::time::Duration = std::time::Duration::from_millis(100);
|
||||
|
||||
pub struct WithTimeoutAction<TA: (Fn() -> bool) + Send + 'static> {
|
||||
on_timeout: TA,
|
||||
}
|
||||
|
||||
pub struct WithTimeoutAndCancelAction<TA: (Fn() -> bool) + Send + Sync + 'static, CA: (FnMut() -> bool) + Send + 'static> {
|
||||
// returns true if successful (return false to continuously re-run it)
|
||||
on_timeout: std::sync::Arc<TA>,
|
||||
// returns true if cancelled
|
||||
is_cancelled: CA,
|
||||
}
|
||||
|
||||
|
||||
pub struct Timeout<T> {
|
||||
inner: T,
|
||||
duration: std::time::Duration,
|
||||
}
|
||||
|
||||
impl Timeout<()> {
|
||||
#[must_use]
|
||||
pub fn new(duration: std::time::Duration) -> Self {
|
||||
Self {
|
||||
inner: (),
|
||||
duration,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn on_timeout<TA: (Fn() -> bool) + Send + 'static>(self, action: TA) -> Timeout<WithTimeoutAction<TA>> {
|
||||
Timeout {
|
||||
inner: WithTimeoutAction { on_timeout: action },
|
||||
duration: self.duration,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <TA: (Fn() -> bool) + Send + Sync + 'static> Timeout<WithTimeoutAction<TA>> {
|
||||
#[must_use]
|
||||
pub fn with_cancel_check<CA: (FnMut() -> bool) + Send + 'static>(self, action: CA) -> Timeout<WithTimeoutAndCancelAction<TA, CA>> {
|
||||
Timeout {
|
||||
inner: WithTimeoutAndCancelAction {
|
||||
on_timeout: std::sync::Arc::new(self.inner.on_timeout),
|
||||
is_cancelled: action,
|
||||
},
|
||||
duration: self.duration,
|
||||
}
|
||||
}
|
||||
|
||||
/*async fn main_task(mut self2: Self) {
|
||||
tokio::time::sleep(self2.duration).await;
|
||||
while !(self2.inner.on_timeout)() {
|
||||
tokio::time::sleep(TIMEOUT_GRANULARITY).await;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn start(self) -> tokio::task::JoinHandle<()> {
|
||||
tokio::task::spawn(Self::main_task(self))
|
||||
}*/
|
||||
}
|
||||
|
||||
impl <TA: (Fn() -> bool) + Send + Sync + 'static, CA: (FnMut() -> bool) + Send + 'static> Timeout<WithTimeoutAndCancelAction<TA, CA>> {
|
||||
async fn main_task(mut self, deadline: chrono::DateTime<chrono::Utc>) {
|
||||
loop {
|
||||
if (self.inner.is_cancelled)() { return; }
|
||||
let now = chrono::Utc::now();
|
||||
if now >= deadline {
|
||||
let on_timeout_clone = self.inner.on_timeout.clone();
|
||||
if tokio::task::spawn_blocking(move || on_timeout_clone() ).await.unwrap_or(true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
tokio::time::sleep(TIMEOUT_GRANULARITY).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(self) -> tokio::task::JoinHandle<()> {
|
||||
let deadline = chrono::Utc::now() + self.duration;
|
||||
tokio::task::spawn(self.main_task(deadline))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user