gate the heartbeat off; it was resyncing the client every turn

the live log showed the client requesting a full sector state every
500ms - one per turn, in lockstep with the heartbeat. the heartbeat
verifies the client's predicted checksum against ours, and the sim is
not yet bit-exact, so most turns mismatch, flip the client out of sync,
and it re-downloads the whole state. that resync storm is the "86%,
70%..." loading flicker at battle start and it hard-resets the battle
scene every turn, so nothing on screen can settle.

the heartbeat now stays off unless SCROLL_HEARTBEAT=1. this returns the
client to the snapshot-only path (a hard reset every 4 ticks, but no
per-turn off-sync request). turn it back on once checksums reliably
agree.
This commit is contained in:
WiseDev 2026-08-24 20:13:16 +03:00
parent 447cc091bc
commit c18ce37a42
2 changed files with 9 additions and 1 deletions

View file

@ -1,6 +1,9 @@
use std::collections::HashMap;
use std::sync::Arc;
pub const SNAPSHOT_INTERVAL_TICKS: i32 = 4;
pub fn heartbeats_enabled() -> bool {
std::env::var("SCROLL_HEARTBEAT").map(|v| v == "1").unwrap_or(false)
}
pub fn snapshot_interval_ticks() -> i32 {
std::env::var("SCROLL_SNAPSHOT_INTERVAL_TICKS")
.ok()
@ -265,7 +268,10 @@ impl BattleSession {
}
self.recent_checksums.push_back((self.tick, checksum));
}
if self.pushes_snapshots() && self.tick % TICKS_PER_TURN == 0 {
if heartbeats_enabled()
&& self.pushes_snapshots()
&& self.tick % TICKS_PER_TURN == 0
{
if let Some(checksum) = this_checksum {
let turn = self.tick / TICKS_PER_TURN;
if let Ok(message) =

View file

@ -495,9 +495,11 @@ fn the_session_emits_a_heartbeat_every_turn() {
1,
)
.expect("battle");
std::env::set_var("SCROLL_HEARTBEAT", "1");
let mut session = game_service::battle_session::BattleSession::new(mode, Vec::new());
session.advance_to(25);
let out = session.take_outbound();
std::env::remove_var("SCROLL_HEARTBEAT");
let heartbeats: Vec<&service_rpc::WireMessage> = out
.iter()
.filter(|m| m.message_type == 21902)