fix(client): space proof moves past the stance cooldown — test_proof_corner_reveal flake (T-1037)
test_proof_corner_reveal drove moves back-to-back. The Gauntlet player is Walk stance (ticks_per_move=2, server stance.rs), so a move arriving within the cooldown window is silently throttled (movement.rs::apply_move -> PlayerMoveCooldown::try_move). _send_and_receive returned the instant a move landed, so the next send raced the cooldown and an occasional move was dropped — leaving the player one tile short, which (via the test's cumulative expectations) cascaded into the corner-reveal perception assert. A different move dropped each run = flaky; exposed by the heavier post-cascade tick timing. Test-side fix only — game behaviour is correct and the Gauntlet world is immutable: after a move lands, wait for the server clock to advance COOLDOWN_TICKS past the landing tick before the next send. Full client suite 2538/2538 green; the proof suite drops from ~28s (timeouts) to ~4s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,12 @@ extends GdUnitTestSuite
|
||||
|
||||
const CONNECT_TIMEOUT: float = 3.0
|
||||
const RESPONSE_TIMEOUT: float = 5.0
|
||||
# Server move cooldown: the Gauntlet player is Walk stance (ticks_per_move = 2,
|
||||
# server stance.rs). A move input arriving within that window is silently
|
||||
# throttled away (movement.rs::apply_move -> PlayerMoveCooldown::try_move).
|
||||
# Space consecutive sends past it (2 ticks + 1 margin for apply/snapshot lag)
|
||||
# so back-to-back moves can never race the cooldown.
|
||||
const COOLDOWN_TICKS: int = 3
|
||||
const MAX_PORT_ATTEMPTS: int = 5
|
||||
|
||||
var _server_pid: int = -1
|
||||
@@ -128,6 +134,27 @@ func _send_and_receive(
|
||||
assert_that(actual.is_equal_approx(expect_position)).override_failure_message(
|
||||
"player must reach %s after '%s' — last seen %s" % [expect_position, action_name, actual]
|
||||
).is_true()
|
||||
# Space the next move past the per-stance cooldown. The server silently
|
||||
# drops a move that arrives within ticks_per_move ticks of the previous
|
||||
# one; without this wait, back-to-back sends race the cooldown and an
|
||||
# occasional move is throttled, leaving the player one tile short (flaky).
|
||||
# Wait for the server clock to advance COOLDOWN_TICKS past the landing
|
||||
# tick so the next send can never be throttled. The player is stationary
|
||||
# meanwhile, so the fresher snapshot is still valid for the caller.
|
||||
var landed_tick: int = int(snapshot.tick)
|
||||
var spacing_elapsed := 0.0
|
||||
while spacing_elapsed < RESPONSE_TIMEOUT:
|
||||
_bridge.poll()
|
||||
var m := _bridge.poll_message()
|
||||
if m.size() > 0:
|
||||
var d: Variant = Protocol.decode_snapshot(m)
|
||||
if d != null:
|
||||
snapshot = d
|
||||
if int(d.tick) >= landed_tick + COOLDOWN_TICKS:
|
||||
break
|
||||
continue
|
||||
await get_tree().create_timer(0.05).timeout
|
||||
spacing_elapsed += 0.05
|
||||
return snapshot
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user