From b820d3917c7e8200176483b30da6b6ea08f0aba1 Mon Sep 17 00:00:00 2001 From: spiritsnails <307422241+spiritsnails@users.noreply.github.com> Date: Sat, 1 Aug 2026 19:13:03 -0600 Subject: [PATCH] fixing failed tests/harnesses --- src/core/FixedStep.lua | 21 +++++++++++++++++---- tests/engine/rebind_swap_clear_bug589.lua | 11 +++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/core/FixedStep.lua b/src/core/FixedStep.lua index 39cd980f..fe773e27 100644 --- a/src/core/FixedStep.lua +++ b/src/core/FixedStep.lua @@ -10,6 +10,7 @@ local MAX_ACCUM = 0.25 -- avoid spiral of death after a stall function FixedStep:init(callback) self.accum = 0 self.callback = callback + self.suppressCatchup = false end -- The anti-spiral clamp doubles as a steps-per-frame ceiling (0.25s = 15 @@ -20,6 +21,16 @@ end FixedStep.maxAccum = MAX_ACCUM function FixedStep:update(dt) + -- A hitch's oversized dt lands on the frame AFTER discardCatchup was + -- called (the hitch itself already ran inside the current step); absorb + -- that one frame as a single step instead of the normal accumulator so + -- the burst it would otherwise release doesn't play out as a slide. + if self.suppressCatchup then + self.suppressCatchup = false + self.accum = 0 + self.callback(self.STEP) + return + end self.accum = math.min(self.accum + dt, self.maxAccum or MAX_ACCUM) while self.accum >= self.STEP do self.accum = self.accum - self.STEP @@ -27,12 +38,14 @@ function FixedStep:update(dt) end end --- Drop any pending catch-up steps. A hitch inside one logic step (map --- seam setMap / song start) makes the next real-time dt huge; without this --- the while-loop above would advance many walk frames before the next --- draw, which looks like a slide with no leg animation (issue #93). +-- Drop any pending catch-up steps and arm the one-frame clamp above. A +-- hitch inside one logic step (map seam setMap / song start) makes the +-- next real-time dt huge; without this the while-loop above would advance +-- many walk frames before the next draw, which looks like a slide with no +-- leg animation (issue #93). function FixedStep:discardCatchup() self.accum = 0 + self.suppressCatchup = true end return FixedStep diff --git a/tests/engine/rebind_swap_clear_bug589.lua b/tests/engine/rebind_swap_clear_bug589.lua index 8efd19d0..0e49d03d 100644 --- a/tests/engine/rebind_swap_clear_bug589.lua +++ b/tests/engine/rebind_swap_clear_bug589.lua @@ -17,6 +17,7 @@ love = love or require("tests.love_stub") local Input = require("src.core.Input") local Strings = require("src.core.Strings") +local Timing = require("src.core.Timing") local BindingsMenu = require("src.ui.BindingsMenu") -- same doubles as rebind_capture_bug510: a stack the menu can pop itself @@ -45,6 +46,14 @@ local function press(state, btn) state.game.input.queue = {} end +-- ChoiceBox now holds YES/NO answers on screen for Timing.YES_NO_ANSWER +-- frames before it commits and pops (DisplayTwoOptionMenu's 15-frame hold, +-- #GH-627 timing parity); a bare press only arms the choice, so answering +-- it needs the hold run out before the pop/commit is visible. +local function settleChoice(state) + for _ = 1, Timing.YES_NO_ANSWER do state:update(1 / 60) end +end + -- rows are BindingsMenu's BUTTONS order local ROW_A, ROW_B, ROW_SELECT = 5, 6, 8 @@ -146,6 +155,7 @@ eq(bm.footer, Strings("RESET ALL BINDINGS?"), -- the box starts on NO: a bare A press must keep the overlay press(box, "a") +settleChoice(box) eq(game.stack:top(), bm, "answering pops the box") check(game.save.options.bindings ~= nil, "NO keeps the bindings (defaultNo)") eq(bm.items[ROW_A].right, "P/B", "and the rows keep showing them") @@ -155,6 +165,7 @@ press(bm, "start") box = game.stack:top() press(box, "up") press(box, "a") +settleChoice(box) check(game.save.options.bindings == nil, "YES clears options.bindings (#589)") eq(bm.items[ROW_A].right, "Z/A", "the A row reads its default again") eq(bm.items[ROW_B].right, "X/B", "so does the B row the swap had touched")