diff --git a/src/utils/Timer.test.ts b/src/utils/Timer.test.ts index a60790d..6d71a9c 100644 --- a/src/utils/Timer.test.ts +++ b/src/utils/Timer.test.ts @@ -57,7 +57,7 @@ describe('Timer', () => { expect(timer.tick()).toBe(true); }); - it('does not lock when current tick rewinds', () => { + it('does not lock when current tick rewinds shallowly', () => { vi.spyOn(BTAPI.instance, 'getTicks').mockReturnValue(0); const timer = new Timer(5); @@ -66,6 +66,21 @@ describe('Timer', () => { expect(timer.remainingTicks(3)).toBe(5); expect(timer.tick(10)).toBe(true); }); + + it('resets baseline and does not lock after a hard tick rewind', () => { + vi.spyOn(BTAPI.instance, 'getTicks').mockReturnValue(0); + const timer = new Timer(5); + + // Advance well past the interval so lastFiredTick is 1000. + expect(timer.tick(1000)).toBe(true); + + // Hard rewind to 0 - without the guard the timer would lock until tick 1005. + expect(timer.tick(0)).toBe(false); // rewind detected, baseline reset to 0 + + // Should now fire exactly intervalTicks later. + expect(timer.tick(4)).toBe(false); + expect(timer.tick(5)).toBe(true); + }); }); describe('reset and helpers', () => { diff --git a/src/utils/Timer.ts b/src/utils/Timer.ts index a0c081f..e55a8ee 100644 --- a/src/utils/Timer.ts +++ b/src/utils/Timer.ts @@ -34,6 +34,11 @@ export class Timer { * @returns True when at least `intervalTicks` have elapsed since the last fire/reset. */ public tick(currentTick: number = BTAPI.instance.getTicks()): boolean { + if (currentTick < this.lastFiredTick) { + this.lastFiredTick = currentTick; + return false; + } + if (this.elapsedTicks(currentTick) < this.intervalTicks) { return false; }