1
0
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:
NG (Graham)
2026-01-25 18:17:34 -05:00
parent a5ebe4284b
commit a346299de8
17 changed files with 391 additions and 52 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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");

View File

@@ -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

View File

@@ -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;

View File

@@ -3,3 +3,6 @@ pub use surrender::{SurrenderGameTracker, SurrenderVoteResult};
mod ticker;
pub use ticker::TickTracker;
mod timeout;
pub use timeout::Timeout;

View 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))
}
}