Session
One player's data, live on this server.
You get one from Store:Get, Store:Expect or Store:WaitForLoaded. Sessions only exist on player
keyed stores.
Fields
LogSize
Session.LogSize: numberHow many ops are in the stored log. Read only.
LogBytes
Session.LogBytes: numberRoughly how many bytes the stored ops plus the queued ones take. Read only.
Reading
Get
Session:Get() -> SLive state. Every table in it is frozen, at every depth, so a mutation throws on the line that did it:
local State = Session:Get()
State.Gold = 99 --> attempt to modify a readonly table
State.Bag.Items[1] = "sword" --> attempt to modify a readonly tableObserve
Session:Observe() -> Observer<S>Fires on every change that goes through, including ones from another server that turned up when a transfer or transaction settled. Doesn't fire for a refused op.
Session:Observe():Subscribe(function(State)
UpdateHud(Player, State)
end)This is the session's own stream, not a copy, so Session:Observe() == Session:Observe(). Destroy
on it removes Ledger's own subscribers too, so don't call it. See
Observer for the chain methods and cleanup.
DidApply
Session:DidApply(Id: string) -> booleanWhether a Once name ever applied on this key. Reads live state, so it
doesn't yield.
Live state includes the ops that wait for the next save. Apply puts a name in that queue, so
DidApply gives true before the op is written. It tells you that the name applied. It does not
tell you that the name is saved. To be sure that it is saved, use Commit, or use Apply and
then Flush.
Writing
Apply
Session:Apply(Kind: string, Fields: { [any]: any }?) -> (boolean, Reason?)Instant and local. Runs the reducer, updates state, tells observers, queues the op for the next save. Never touches the datastore.
Use it for gameplay. See Apply and Commit.
Commit
Session:Commit(Kind: string, Fields: { [any]: any }?) -> Future<boolean, Reason?>Pushes everything queued, appends the op, waits for the datastore, refolds, then answers. true
means it's durable and every server will agree.
Use it for anything you can't take back.
CommitOp
Session:CommitOp(Op: Op) -> Future<boolean, Reason?>Same as Commit but you build the op. Needs a string Id and a string Kind. A Once field, if
you give one, has to be a non empty string.
Session:CommitOp({
Id = HttpService:GenerateGUID(false),
Kind = "ProductGrant",
ProductId = 123456,
Once = `receipt:{Receipt.PurchaseId}`,
}):Wait()Id, Kind and OnceAt belong to Ledger. Passing them in Fields through Apply or Commit
warns and gets overwritten.
Saving
Flush
Session:Flush() -> Future<boolean, Reason?>Pushes queued ops without adding one. What autosave calls. false comes with a
reason and the ops stay queued for next time.
Compact
Session:Compact() -> Future<boolean, Reason?>Folds the log down into a fresh snapshot and drops the ops it absorbed. Autosave does this when the log gets long, so you rarely need it.
Release
Session:Release() -> Future<boolean, Reason?>Marks the session closed and pushes what's left. Apply, Commit and CommitOp then answer
Closed. Flush still works, it adds no op.
Use Store:Unload instead. Release closes the session and tells the store nothing, so IsLoaded
stays true, Get still hands back the closed session, and the autosave timer keeps running.
Unload does both halves.