stamp the tick on the snapshot that carries it

the snapshot is built inside the tick loop but the clock was written
after it, so every pushed state went out carrying the tick from the
previous call. LogicGameMode::decode compares that number against the
last one it saw and ignores anything older, so a stale stamp is the
difference between a state being applied and being dropped on the floor.
the clock advances with the tick now.

the sector command log gains the summoner mana, how many snapshots have
gone out, and the type of the command that arrived, so the next run says
whether the push is happening at all rather than leaving it to inference.
This commit is contained in:
WiseDev 2026-08-23 13:58:48 +03:00
parent dbbd162bed
commit f51d76f780
2 changed files with 23 additions and 1 deletions

View file

@ -22,6 +22,7 @@ pub struct BattleSession {
next_bot_emote: i32,
next_snapshot: i32,
next_bot_play: i32,
pub pushed_snapshots: u32,
pending_bot_play: Option<(LogicDataRef, LogicVector2, i32)>,
}
impl BattleSession {
@ -39,6 +40,7 @@ impl BattleSession {
next_bot_emote,
next_snapshot: SNAPSHOT_INTERVAL_TICKS,
next_bot_play: 0,
pushed_snapshots: 0,
pending_bot_play: None,
}
}
@ -88,6 +90,18 @@ impl BattleSession {
pub fn pushes_snapshots(&self) -> bool {
self.mode.battle.battle_type == BATTLE_TYPE_PVP
}
pub fn mana(&self) -> Option<i32> {
self.mode.battle.objects.objects.iter().find_map(|entry| {
match &entry.body {
logic::battle::LogicObjectBody::Summoner(summoner)
if entry.owner_index() == 0 =>
{
Some(summoner.mana)
}
_ => None,
}
})
}
fn snapshot_message(&mut self) -> Option<WireMessage> {
let snapshot = self.mode.snapshot().ok()?;
let report = verify_snapshot(&snapshot);
@ -162,11 +176,13 @@ impl BattleSession {
pub fn advance_to(&mut self, tick: i32) {
while self.tick < tick {
self.tick += 1;
self.mode.time.tick = self.tick;
self.release_queued(self.tick);
self.mode.battle.tick(self.tick);
if self.pushes_snapshots() && self.tick >= self.next_snapshot {
self.next_snapshot = self.tick + SNAPSHOT_INTERVAL_TICKS;
if let Some(message) = self.snapshot_message() {
self.pushed_snapshots += 1;
self.outbound.push(message);
}
}
@ -187,7 +203,6 @@ impl BattleSession {
}
}
}
self.mode.time.tick = self.tick;
}
fn release_queued(&mut self, tick: i32) {
let mut due = Vec::new();
@ -323,6 +338,8 @@ impl BattleRegistry {
objects: session.object_count(),
towers: session.towers_standing(),
checksum: session.checksum(),
mana: session.mana(),
pushed: session.pushed_snapshots,
})
}
pub async fn play<F>(
@ -361,4 +378,6 @@ pub struct BattleProgress {
pub objects: usize,
pub towers: (usize, usize),
pub checksum: Option<i32>,
pub mana: Option<i32>,
pub pushed: u32,
}

View file

@ -512,9 +512,12 @@ impl GameApi for GameService {
server_checksum,
agrees = server_checksum == Some(sector.client_checksum),
objects = progress.map(|state| state.objects),
mana = progress.and_then(|state| state.mana),
pushed = progress.map(|state| state.pushed),
towers = ?progress.map(|state| state.towers),
stars = ?progress.map(|state| state.stars),
spawned,
command = sector.command.as_ref().map(|command| command.command_type()),
"sector command"
);
Ok(())