mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Implemented respawning for #32
This commit is contained in:
@@ -594,7 +594,7 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
|
|||||||
&rlnl::events::ingame::Kill { killee_player_id: remote_player, killer_player_id: killer_player },
|
&rlnl::events::ingame::Kill { killee_player_id: remote_player, killer_player_id: killer_player },
|
||||||
true,
|
true,
|
||||||
).await;
|
).await;
|
||||||
log::info!("Player {} was destroyed by {} ({}) in game {}", remote_player, killer_player, user_id, self.game_guid());
|
log::info!("Player {} was destroyed by player {} (user {}) in game {}", remote_player, killer_player, user_id, self.game_guid());
|
||||||
if self.custom_logic_handler.on_vehicle_destroyed(&self, killer_player, remote_player).await {
|
if self.custom_logic_handler.on_vehicle_destroyed(&self, killer_player, remote_player).await {
|
||||||
// the kill tracking is initiated separately by the client with kill bonus event
|
// the kill tracking is initiated separately by the client with kill bonus event
|
||||||
if let Some(killed) = self.users.read().await.get(&remote_player) {
|
if let Some(killed) = self.users.read().await.get(&remote_player) {
|
||||||
@@ -817,26 +817,6 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
|
|||||||
}, literustlib::packet::Property::Unreliable, &conn.connection.connection).await);
|
}, literustlib::packet::Property::Unreliable, &conn.connection.connection).await);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*if self.game_start.load(std::sync::atomic::Ordering::Relaxed) == -1 {
|
|
||||||
let mut all_users_loading_complete = true;
|
|
||||||
for conn in self.users.read().await.values() {
|
|
||||||
let mode = ConnectionMode::from_u8(conn.state.mode.load(std::sync::atomic::Ordering::Relaxed));
|
|
||||||
let is_in_sync = matches!(mode, ConnectionMode::Sync);
|
|
||||||
log::info!("Player {} is in mode {:?}", conn.descriptor.player_id, mode);
|
|
||||||
all_users_loading_complete &= is_in_sync && conn.state.progress.load(std::sync::atomic::Ordering::Relaxed) == 100;
|
|
||||||
}
|
|
||||||
if all_users_loading_complete {
|
|
||||||
for (id, conn) in self.users.read().await.iter() {
|
|
||||||
if let Err(e) = conn.connection.rlnl().send_empty(
|
|
||||||
rlnl::event_code::NetworkEvent::EndOfSync,
|
|
||||||
literustlib::packet::Property::ReliableOrdered,
|
|
||||||
&conn.connection.connection
|
|
||||||
).await {
|
|
||||||
log::error!("Failed to send EndOfSync event to user {}: {}", id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Received machine motion with unknown player id {} from user {}", motion.player_id, user_id);
|
log::warn!("Received machine motion with unknown player id {} from user {}", motion.player_id, user_id);
|
||||||
}
|
}
|
||||||
@@ -986,7 +966,6 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
|
|||||||
.await?;
|
.await?;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// fallback
|
// fallback
|
||||||
log::warn!("No spawn point found for player {} on team {}, using bad fallback", player.player_id, team);
|
log::warn!("No spawn point found for player {} on team {}, using bad fallback", player.player_id, team);
|
||||||
@@ -1063,7 +1042,12 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn game_done(&self) {
|
pub(super) fn game_done(&self) {
|
||||||
self.is_complete.store(true, std::sync::atomic::Ordering::SeqCst);
|
let old = self.is_complete.swap(true, std::sync::atomic::Ordering::SeqCst);
|
||||||
|
if old {
|
||||||
|
log::warn!("Game {} was marked as done again", self.game_guid());
|
||||||
|
} else {
|
||||||
|
log::debug!("Game {} is marked done (handler will exit once all players have disconnected)", self.game_guid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn is_game_done(&self) -> bool {
|
pub(super) fn is_game_done(&self) -> bool {
|
||||||
|
|||||||
@@ -597,6 +597,73 @@ impl BattleArenaLogic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn do_respawn_tasks(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, player_id: u8) {
|
||||||
|
log::info!("Handling respawn player {} in game {}", player_id, generic.game_guid());
|
||||||
|
let respawn_time = std::time::Duration::from_secs(self.config.respawn_time_seconds as u64);
|
||||||
|
let now = chrono::Utc::now();
|
||||||
|
let respawn_timestamp = now + respawn_time;
|
||||||
|
if let Some(player_respawn) = self.player_tracking.respawning.read().await.get(&player_id) {
|
||||||
|
player_respawn.store(respawn_timestamp.timestamp(), std::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
let respawn_payload = rlnl::events::ingame::RespawnTime {
|
||||||
|
owner: player_id,
|
||||||
|
waiting_time: self.config.respawn_time_seconds as i16,
|
||||||
|
};
|
||||||
|
generic.broadcast(
|
||||||
|
rlnl::event_code::NetworkEvent::SetRespawnWaitingTime,
|
||||||
|
literustlib::packet::Property::ReliableOrdered,
|
||||||
|
&respawn_payload,
|
||||||
|
true
|
||||||
|
).await;
|
||||||
|
if let Some(player_team) = self.player_tracking.team(player_id).await {
|
||||||
|
let spawn_point = if let Some(team_spawns) = generic.map_config.spawns.get(&player_team) {
|
||||||
|
if team_spawns.is_empty() {
|
||||||
|
oj_rc_core::persist::config::Point {
|
||||||
|
x: 10.0 * (player_id as f32),
|
||||||
|
y: 100.0,
|
||||||
|
z: 10.0 * (player_team as f32) + 10.0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let index = (player_id as usize) % team_spawns.len();
|
||||||
|
team_spawns[index].clone()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oj_rc_core::persist::config::Point {
|
||||||
|
x: 10.0 * (player_id as f32),
|
||||||
|
y: 100.0,
|
||||||
|
z: 10.0 * (player_team as f32) + 10.0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let connections = generic.users.read().await.values().map(|player_info| player_info.connection.clone()).collect();
|
||||||
|
tokio::task::spawn(Self::respawn_player_after(respawn_timestamp, connections, spawn_point, player_id));
|
||||||
|
} else {
|
||||||
|
log::error!("Player {} cannot respawn because they are not in a team!?", player_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
let sleep_dur = after.signed_duration_since(chrono::Utc::now()).to_std().expect("Respawn duration too long to sleep");
|
||||||
|
tokio::time::sleep(sleep_dur).await;
|
||||||
|
let spawn_payload = rlnl::events::sync::SpawnPoint {
|
||||||
|
pos: rlnl::types::PosQuatPair {
|
||||||
|
pos: rlnl::types::CompressedVec3::from((spawn.x, spawn.y, spawn.z)),
|
||||||
|
rot: rlnl::types::CompressedQuat { x: 0, y: 0, z: 0 },
|
||||||
|
},
|
||||||
|
owner: player_id,
|
||||||
|
};
|
||||||
|
log::debug!("Respawning player {} after {}ms", player_id, sleep_dur.as_millis());
|
||||||
|
for player in players {
|
||||||
|
if !player.connection.is_connected() { continue; }
|
||||||
|
crate::events::log_lnl_send_failure(player.rlnl().send_data(
|
||||||
|
&spawn_payload,
|
||||||
|
rlnl::event_code::NetworkEvent::FreeRespawnPoint,
|
||||||
|
literustlib::packet::Property::ReliableOrdered,
|
||||||
|
&player.connection,
|
||||||
|
).await);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@@ -619,13 +686,13 @@ impl CustomGameLogic for BattleArenaLogic {
|
|||||||
|
|
||||||
async fn on_vehicle_destroyed(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, _killer: u8, victim: u8) -> bool {
|
async fn on_vehicle_destroyed(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, _killer: u8, victim: u8) -> bool {
|
||||||
self.do_destruct_tasks(generic, victim).await;
|
self.do_destruct_tasks(generic, victim).await;
|
||||||
// TODO handle respawn
|
self.do_respawn_tasks(generic, victim).await;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_vehicle_self_destruct(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, user: u8, _is_classic: bool) -> bool {
|
async fn on_vehicle_self_destruct(&self, generic: &crate::matches::GenericGamemodeEngine<Self>, user: u8, _is_classic: bool) -> bool {
|
||||||
self.do_destruct_tasks(generic, user).await;
|
self.do_destruct_tasks(generic, user).await;
|
||||||
// TODO handle respawn
|
self.do_respawn_tasks(generic, user).await;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user