import { Delegate, UpdateController } from "@24tools/playable_template"; export type ScheduledCall = { remaining: number; callback: () => void; cancelled: boolean; }; /** * Відкладені виклики, керовані ігровим тікером (delta з `UpdateController`), * а не `window.setTimeout`. Перевага: затримки можна скасувати на teardown і * вони не спрацюють після завершення playable. * * Прим.: коли дійде черга до уніфікації часу (план, п.2) — масштаб `TimeC.TimeScale` * додається саме тут, в одному місці. */ export class TickScheduler { private static updateDelegate: Delegate | null = null; private static calls = new Set(); /** `delaySeconds` — затримка в секундах ігрового часу. */ static schedule(delaySeconds: number, callback: () => void): ScheduledCall { this.ensureUpdate(); const call: ScheduledCall = { remaining: delaySeconds, callback, cancelled: false, }; this.calls.add(call); return call; } static cancel(call: ScheduledCall | null | undefined) { if (!call) return; call.cancelled = true; this.calls.delete(call); } private static ensureUpdate() { if (this.updateDelegate) return; this.updateDelegate = UpdateController.Instance.onUpdate.addDelegate((delta) => this.update(delta), ); } private static update(delta: number) { if (this.calls.size === 0) return; for (const call of [...this.calls]) { if (call.cancelled) { this.calls.delete(call); continue; } call.remaining -= delta; if (call.remaining <= 0) { this.calls.delete(call); call.callback(); } } } }