scroll.server/crates/game-service
WiseDev 82f00ac1bc hash at the client's tick, and clear the dormant king's combat bit
audit findings #1 and #2, the pair that makes the idle-board checksum
mean something again.

#1 the server hashed at its own free-running tick. sector_command calls
advance(client_tick) but advance_to is forward-only and the 50ms ticker
already ran the session past it, so it hashed at session.tick, not the
client's - and the tick is the first field in the checksum, so it could
never agree even on a bit-exact board. the session now records the
checksum of every tick it simulates and advance() returns the one for
the tick the client actually reported.

#2 the real idle divergence. the king is dormant at full health, and
LogicSummoner::updateCombatComponentState clears the combat bit of its
component mask every tick (13 -> 12) while field_256 <= KING_ACTIVATE
_TIME_MS; the mask is hashed for every object, so a server holding 13
disagreed on every tick and re-agreed only on the snapshot tick. the
sim now mirrors it: field_256 stays 0 while the king is unhurt and both
princess towers stand, ramps by 50/tick once it takes damage or loses a
tower, and the combat bit turns on only past KING_ACTIVATE_TIME_MS. the
king is also built with the bit already clear. princess towers are plain
characters and keep bit0 - verified against the client, which routes
them through the base updateCombatComponentState that sets it.

harness: dormant kings read mask 12, all four princess towers 13, and an
idle state hashes the same twice.
2026-08-24 09:32:44 +03:00
..
src hash at the client's tick, and clear the dormant king's combat bit 2026-08-24 09:32:44 +03:00
tests hash at the client's tick, and clear the dormant king's combat bit 2026-08-24 09:32:44 +03:00
Cargo.toml move players and accounts into postgres 2026-08-23 08:40:13 +03:00