Scheduler
The Scheduler namespace provides save-resilient scheduling on the in-game clock.
A job is a due date, not a countdown, which is what makes it survive the things a countdown does not: quitting, loading another save, coming back a day later. Anything still due when the player returns fires as soon as its handler is registered.
No permission required.
Available since SDK v0.23.0
The Scheduler namespace requires @hotbunny/[email protected] or newer. Run npm install @hotbunny/hackhub-content-sdk@latest to update.
Import
import { Scheduler } from "@hotbunny/hackhub-content-sdk";Register handlers on every load
Jobs outlive the session that created them, so the handler has to exist before the job is due. Register at mod load, every load, above the content that schedules anything.
A job whose handler is missing is held, never dropped. Uninstalling a pack does not destroy the pending world state it created, and reinstalling picks it back up.
Prefix your kinds
The handler registry is shared between mods. Two packs that both register "triage" would silently answer each other's jobs, so prefix every kind with your pack id.
Methods
Scheduler.register<P>(kind, handler)
Handle jobs of one kind. The handler receives the job's payload and its ScheduledJobInfo, and may be async.
Scheduler.register<{ reportId: string }>("myPack.triage", ({ reportId }, job) => {
Mail.send({
from: "[email protected]",
subject: `Report ${reportId} triaged`,
content: "Reviewed and accepted.",
});
});Scheduler.unregister(kind)
Stop handling a kind. Jobs of that kind are held rather than dropped.
Scheduler.schedule<P>(kind, payload?, delay?, id?)
Schedule a job to fire after a delay. Pass id to make the call idempotent: scheduling the same id again replaces the pending job instead of adding a second one.
Returns: string (the job id)
Scheduler.schedule("myPack.triage", { reportId: "R-1" }, { days: 2 });
Scheduler.schedule("myPack.nudge", { step: 1 }, { realMs: 2500 });Scheduler.scheduleAt<P>(kind, payload, fireAt, id?)
Schedule a job for a specific in-game timestamp, as returned by Time.now().
Returns: string (the job id)
Scheduler.scheduleAt("myPack.deadline", { caseId }, Time.now() + Time.duration({ days: 7 }));Scheduler.cancel(id)
Cancel one pending job.
Scheduler.cancelKind(kind)
Cancel every pending job of one kind.
Scheduler.list(kind?)
Pending jobs, in the order they will fire. Pass a kind to filter.
Returns: ScheduledJobInfo[]
Scheduler.remaining(id)
In-game milliseconds until id fires, or null when there is no such job.
Returns: number | null
Types
ScheduleDelay
An in-game delay, expressed the way a designer thinks about it. Omit everything to fire on the next tick.
| Field | Type | Description |
|---|---|---|
minutes | number | In-game minutes |
hours | number | In-game hours |
days | number | In-game days |
ms | number | In-game milliseconds, if you would rather be explicit |
realMs | number | Real-world milliseconds, converted at the current clock scale |
Reach for realMs only when pacing a beat the player is watching, rather than saying anything about how much time passed in the fiction. An e-mail that should land "a couple of seconds after you click" is realMs. A two-day triage is not.
ScheduledJobInfo
| Field | Type | Description |
|---|---|---|
id | string | Job id |
fireAt | number | In-game timestamp at which the job is due |
kind | string | The registered kind |
payload | any | Whatever was scheduled with it |
createdAt | number | In-game timestamp the job was created |
Full example
import { Scheduler, Mail, Time } from "@hotbunny/hackhub-content-sdk";
// Top level of the pack entry file, so it runs on every load.
Scheduler.register<{ reportId: string }>("myPack.triage", ({ reportId }) => {
Mail.send({
from: "[email protected]",
subject: `Report ${reportId} triaged`,
content: "Reviewed and accepted. Bounty on its way.",
});
});
// Later, when the player submits a report:
Scheduler.schedule("myPack.triage", { reportId }, { days: 2 });A player who submits the report and quits for a week finds the reply waiting when they come back, because the job was a due date rather than a running timer.
