Previously maxLimit was passed directly to setTimeout/setInterval (ms), so a JSON value of 10 meant 10ms instead of the intended 10 seconds. Now timeLimit in JSON represents seconds, engine multiplies by 1000.
74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import type { Choice } from '../types'
|
|
|
|
export interface ChoiceTimerState {
|
|
total: number
|
|
remaining: number
|
|
}
|
|
|
|
type TimerUpdateCallback = (state: ChoiceTimerState) => void
|
|
type TimeoutCallback = (choice: Choice) => void
|
|
|
|
export class ChoiceSystem {
|
|
private timerId: ReturnType<typeof setInterval> | null = null
|
|
private timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
private timeLimit = 0
|
|
private elapsed = 0
|
|
private tickMs = 100
|
|
private onUpdate: TimerUpdateCallback | null = null
|
|
private onTimeout: TimeoutCallback | null = null
|
|
|
|
start(choices: Choice[], onUpdate: TimerUpdateCallback, onTimeout: TimeoutCallback) {
|
|
this.clear()
|
|
|
|
const timed = choices.filter((c) => c.timeLimit && c.timeLimit > 0)
|
|
if (timed.length === 0) return
|
|
|
|
const maxLimitSec = Math.max(...timed.map((c) => c.timeLimit!))
|
|
const maxLimitMs = maxLimitSec * 1000
|
|
|
|
this.timeLimit = maxLimitMs
|
|
this.elapsed = 0
|
|
this.onUpdate = onUpdate
|
|
this.onTimeout = onTimeout
|
|
|
|
this.onUpdate({ total: maxLimitSec, remaining: maxLimitSec })
|
|
|
|
this.timerId = setInterval(() => {
|
|
this.elapsed += this.tickMs
|
|
const remainingSec = Math.max(0, maxLimitMs - this.elapsed) / 1000
|
|
this.onUpdate?.({
|
|
total: maxLimitSec,
|
|
remaining: Math.ceil(remainingSec * 10) / 10,
|
|
})
|
|
}, this.tickMs)
|
|
|
|
this.timeoutId = setTimeout(() => {
|
|
this.clear()
|
|
if (choices.length > 0) {
|
|
this.onTimeout?.(choices[0])
|
|
}
|
|
}, maxLimitMs)
|
|
}
|
|
|
|
stop() {
|
|
this.clear()
|
|
}
|
|
|
|
private clear() {
|
|
if (this.timerId !== null) {
|
|
clearInterval(this.timerId)
|
|
this.timerId = null
|
|
}
|
|
if (this.timeoutId !== null) {
|
|
clearTimeout(this.timeoutId)
|
|
this.timeoutId = null
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
this.clear()
|
|
this.onUpdate = null
|
|
this.onTimeout = null
|
|
}
|
|
}
|