Skip to content

Live events ​

"Double cash, Saturday 12:00 to Sunday 23:59 UTC": schedule a change of your game's live values on the explorer's Live events page, sign it once with the CLI, and every game server switches it on and off at those times by itself. Afterwards the page reports whether the event raised playtime, revenue and so on, or only moved them in time.

  • Game side: framework 0.7.1+ (kernel 0.3.8+ for the signed settings record). Signing: any CLI with typetorch settings set (0.8+).
  • Backend: main (unversioned). The page lives under Players & gameplay.

How it works ​

  • The backend never signs. Live values only reach servers through the signed settings record, and the prod keys stay on your machine. The backend keeps the schedule and prepares its JSON; you sign it like any other value.
  • The times are inside the signed record (game["tt.events"], unix seconds, UTC). Each server switches on its own clock: no message at the start or end, a server that starts mid-event has it from its first read, and an event ends on time even when the backend is down.
  • Cancelling is signing the schedule without the event. Until you sign, servers still run it.

Schedule one ​

On the Live events page (owners): a name, 1-8 game keys with JSON values, and a start and end. The page then shows the command to sign the whole schedule (a bash / zsh one, a PowerShell one that reads live-events.json, and the JSON file). Run it in the game's folder:

sh
typetorch settings set game.tt.events - <<'TT_EVENTS'
{"v":1,"events":[{"id":"ev_k3j9x0a1b2","name":"Double cash","start":1763812800,"end":1763942340,"set":{"cash.multiplier":2}}]}
TT_EVENTS

The CLI reads the record, verifies it, sets the one key, signs it with both prod keys and pings servers (Settings).

Checks (the backend refuses anything else):

RuleLimit
Name1-80 characters
Values per event1-8 game keys (the CLI's key rule; not tt.events itself)
A valueJSON, not null, at most 1 KB
StartISO with a zone, or unix ms, whole seconds. Up to 5 minutes in the past starts now; never backdated
Lengthat most 31 days
How far aheadat most 366 days
Overlapno two events on the same key at the same time (409)
Scheduled or live at onceat most 50
The scheduleat most 8 KB (the record's whole game field is 16 KB)

Servers read at most 64 events from a schedule. If two events set the same key at once, the later start wins.

Status: scheduled, live, ended (from the times) or cancelled. Creating and cancelling are in the audit log (live-events.create, live-events.cancel), refused ones too.

Do servers have it? ​

With OPENCLOUD_API_KEY (universe-datastores.objects:read) and TYPETORCH_UNIVERSE_ID, the backend reads the signed record back (at most once a minute; Check again, GET /v1/live-events?refresh=1, at most every 10 s), checks its signature with the game's public keys when it knows them, and shows per event:

StateMeaning
signedservers have this event as scheduled
outdatedservers have it with other times or values: sign again
unsignednot in the signed record: servers won't run it
cancel-unsignedcancelled here but still signed: servers will run it until you sign
doneended, or cancelled and gone from the signed record
unknownthe backend can't tell (no key, or signed by keys it doesn't know)

In game code ​

liveConfig already follows the schedule: while an event runs, its values replace the record's game[key], and get() and onChanged switch at the start and end. The game's parse still checks them. For UI ("Double cash ends in 3h"), TypeTorch.liveEvents() (server only):

ts
const multiplier = TypeTorch.liveConfig("cash.multiplier", { default: 1, parse: (raw) => (typeIs(raw, "number") ? raw : 1) });
multiplier.get(); // 2 while "Double cash" runs, else the record's value or 1

const events = TypeTorch.liveEvents();
events.active(); // [{ id, name, startsAt, endsAt, set }] running now
events.upcoming(); // not started yet, in start order
this.trove.add(events.onChanged((active) => this.showBanner(active)));

More in the Runtime API. A client throws; send what clients need through your own network.

The lift report ​

After an event (and while it runs, cut at now), the page compares it with normal weeks: GET /v1/live-events/<id>/lift?weeks=3&afterDays=3.

  • Windows: the event; the afterDays (default 3) after it, to see whether players only played earlier (pulled forward); and the baseline, the same weekdays and hours weeks weeks back (default 3, at most 8). A baseline week that overlaps another live event is skipped for an earlier one; a week with no players is dropped.
  • Metrics per window: players, playtime per player, sessions per player, Robux per player, payer conversion and new players (server-sent purchases only; Studio never counts).
  • Math: baseline = the mean of the baseline weeks; lift = event / baseline - 1. The range is how much a normal week moved (each baseline week against the mean of the others). Above the range is up, below is down, inside is no clear change; fewer than 2 weeks is "not enough baseline". A plain band you can check by hand, not a significance test.
  • Net: the event and after windows added up, for playtime, Robux, sessions and new players.

Example: "+20% playtime per player (baseline range -5% to +5%) ... Dip after: -7% playtime per player ... part of it was pulled forward; net over the event and the 1 day after: +2% playtime."

Each event's start and end are also dashed lines on every time chart in the explorer, next to the deploy markers. The raw numbers are the live-event-lift query.

Routes ​

RouteRoleWhat
GET /v1/live-eventsevery signed-in rolethe events with their sync state, the schedule and the signing command
POST /v1/live-eventsownerscreate one
POST /v1/live-events/<id>/cancelownerscancel one (then sign the new schedule)
GET /v1/live-events/<id>/liftevery signed-in rolethe lift report (weeks, afterDays)

Released under the MIT License.