diff --git a/crates/game-service/src/battle_session.rs b/crates/game-service/src/battle_session.rs index 788144b..6ed0570 100644 --- a/crates/game-service/src/battle_session.rs +++ b/crates/game-service/src/battle_session.rs @@ -4,7 +4,8 @@ pub const SNAPSHOT_INTERVAL_TICKS: i32 = 4; pub const MAX_CATCH_UP_TICKS: i32 = 40; use std::time::Instant; use logic::battle::{ - LogicGameMode, LogicGameObjectEntry, LogicVector2, BATTLE_TICKS_PER_SECOND, BATTLE_TYPE_PVP, + LogicGameMode, LogicGameObjectEntry, LogicGameObjectRef, LogicVector2, + BATTLE_TICKS_PER_SECOND, BATTLE_TYPE_PVP, CHARACTER_OBJECT_TYPE, }; use logic::battle::{verify_snapshot, LogicBattleEvent}; use logic::SectorStateMessage; @@ -25,6 +26,7 @@ pub struct BattleSession { next_bot_play: i32, pub pushed_snapshots: u32, next_instance: i32, + announced: bool, pending_bot_play: Option<(LogicDataRef, LogicVector2, i32)>, } impl BattleSession { @@ -53,9 +55,43 @@ impl BattleSession { next_bot_play: crate::bot::BOT_OPENING_DELAY_SECONDS * BATTLE_TICKS_PER_SECOND, pushed_snapshots: 0, next_instance: first_instance, + announced: false, pending_bot_play: None, } } + pub fn reannounce(&mut self) { + let mut remap: Vec<(LogicGameObjectRef, LogicGameObjectRef)> = Vec::new(); + for entry in self.mode.battle.objects.objects.iter_mut() { + let fresh = LogicGameObjectRef::of(CHARACTER_OBJECT_TYPE + 1, self.next_instance); + self.next_instance += 1; + remap.push((entry.global_id, fresh)); + entry.global_id = fresh; + } + let translate = |old: &LogicGameObjectRef| -> Option { + remap + .iter() + .find(|(was, _)| was == old) + .map(|(_, now)| *now) + }; + for leader in self.mode.battle.leaders.iter_mut() { + if let Some(now) = translate(leader) { + *leader = now; + } + } + for towers in self.mode.battle.leader_towers.iter_mut() { + for tower in towers.iter_mut() { + if let Some(now) = translate(tower) { + *tower = now; + } + } + } + self.mode + .battle + .objects + .objects + .sort_by_key(|entry| entry.global_id.0.map(|id| (id.class_id, id.instance_id))); + self.next_snapshot = self.tick; + } pub fn take_bot_play(&mut self) -> Option<(LogicDataRef, LogicVector2, i32)> { self.pending_bot_play.take() } @@ -347,8 +383,21 @@ impl BattleRegistry { pub async fn resend(&self, account: AccountRef) -> Option { let handle = self.session(account).await?; let mut session = handle.lock().await; + session.reannounce(); session.snapshot_message() } + pub async fn announce_once(&self, account: AccountRef) -> bool { + let Some(handle) = self.session(account).await else { + return false; + }; + let mut session = handle.lock().await; + if session.announced { + return false; + } + session.announced = true; + session.reannounce(); + true + } pub async fn send(&self, account: AccountRef, message: WireMessage) { if let Some(handle) = self.session(account).await { handle.lock().await.push_outbound(message); diff --git a/crates/game-service/src/service.rs b/crates/game-service/src/service.rs index 4f98fd0..7773d1d 100644 --- a/crates/game-service/src/service.rs +++ b/crates/game-service/src/service.rs @@ -488,6 +488,9 @@ impl GameApi for GameService { let Ok(sector) = SectorCommandMessage::from_bytes(&payload) else { return Ok(()); }; + if self.running_battles.announce_once(account).await { + tracing::info!(%account, "client is live, announcing the objects again"); + } let progress = self .running_battles .advance(account, sector.client_tick)