Ledger v3 · C# · Godot 4.7 Get started
The author's guide

The visibility checklist

For a game where a side doesn't see everything: fog, a hidden hand, a secret. The world holds everything and answers whoever asks it, so every leak below is the game's, made safe by a filter the game puts between the world and what it tells a player. Go down the list for each new thing the game shows, sends or saves.

WhatWhat it tellsWhere the filter stands
Actor numbersA number counts every actor made before it, the other side's too: a gap says the other side made somethingNever show or send a number; name each actor by the viewer's own label, made in the order the viewer saw it
Journal rowsA row names its subject, source, credit and target, seen or not; a row's number counts every rowPass on only rows whose subject the viewer sees; say an unseen source, credit or target as "unseen"; drop the row's number
Previews and forecastsA plain preview runs every rule, the unseen side's too: a damage forecast against a unit with an unseen medic tells that the medic is thereAsk as the viewer sees the world: CheckAs, PriceAs, PreviewAs, ForecastAs, ChoicesAs, with the actors it sees (WorldHost.Sees)
The draw streamOne stream's state tells every next draw; a hidden draw moves itGive each side its own stream where a side draws in secret; never send a stream's state or the seed
Saves and recordingsA save, a capture and a recording hold the whole world, its streams and the seedNever send one to a player who mustn't see all of it; a peer's sync is the state hash, not the save
Refusal words"needs 50 Ore, has 20" says the other side's bank, where the order named the other side's actorWord a refusal for the viewer: its own order's need and have; another side's only as "not now"
A side's view (SideView.Read)Each actor sees names, whole: its archetype, every pool's amount and maximum, every hold with its source, its links, what it runs, its place; the side's own made actors' ties, which count their caster's activationsPass the game's sight, the public actors among it; Withhold each pool or effect told of the side's own actors alone (a magazine, a charge, a reload, a cooldown); never send a number, only the view's labels (host.md, "A predicting client")
An order's answer (SideView.Answer)The tag, given or refused and why, the activation's count, the actor it made by label where seenWhat the game sends beside it, what an order met, it names by LabelOf, 0 where the side didn't see it; never the outcome's words or numbers
An auto's candidatesAn auto picks among bodies in reach, the unseen among them: who it fired at says who stood thereAnswer a fact the auto's target query asks (requires fact(Seen, holder, target) > 0), so the world refuses an unseen target

Also: a tick told while another side acts (a turn-based game's AI planning) says how long it thought; an open choice's answers are shown only to the side it waits on.

What the shared world rules out

One world, run the same on every peer, is what makes a replay and a hash agree. It also rules out these, so choose with them in mind:

  • Lockstep keeps no secret. Under lockstep every peer holds the whole world, so fog or a hidden hand there is a courtesy, not privacy: a player who reads their own memory sees all of it. A game that hides anything runs with server authority, the server holding the world and sending each player what it sees.
  • A world rolled back in place hashes as its frame; one restored from text hashes apart. A world rolled back by its snapshots (S.RollBack, host.md, "A rollback host") hashes as the frame it came from, so rollback peers compare one number. A world restored from a text save lays its rows out anew and hashes apart from its source though the two saves agree: a peer that resyncs from a save can't compare hashes with one that didn't, unless both restore the same save.
  • A game whose engine owns the physics replays from its recording, not by simulating again, so it can't be a lockstep peer: the engine's steps aren't the world's, and two machines' differ.
  • What a game keeps outside the seat (a field of its own, an engine's places, input buffers) is in no world save, hash or view: a host that rolls back or resyncs puts it back itself. What it keeps in the seat is the world's, saved, restored, hashed, recorded and rolled back with it, a side's part told to that side alone (state.md).
  • The per-frame snapshot is the session's, not the text save. At the action RPG's wave of 1,226 actors one save takes 9 to 10 ms, against a median frame of about 1.3 ms (the kernel's .scratch\15\hashcost-run.txt). A rollback host takes S.Take() each frame and rolls back with S.RollBack(tick) in place (host.md, "A rollback host"); the text save is for a quicksave or a resync, taken seldom.

design\24-previews.md, "Who may see what", says what the world itself guarantees a view, and what it leaves to the game.

From ledger-v3's guide/ledger-author/visibility.md, last changed 2026-10-31.