flutter3d_net library

Networking over flutter3d_sim: the one transport, the one rollback, the relay's transports, finding a party, and rollback over the engine's loop.

One transport and one rollback. Every transport is a PeerWire — WebSocketTransport through the relay, flutter3d_net_webrtc's data channel, PeerWire.party over a relay's party room (joinParty, findParty) — and the rollback is RollbackSession, for two machines or a party, which EngineRollback runs over an EngineLoop's snapshots and steps. PeerRoom is two machines meeting, with the hello (WireHello) that refuses another protocol or another simulation. LoopbackWire and LoopbackParty stand in for a network in a test, late and lossy as it asks.

Observing an authoritative simulation, for twins and laboratories: ObserverFeed on the machine that runs it sends each observer (SimulationObserver, over the relay's observer path, observeParty) the tape to replay, telemetry and all, when its profile is bit-exact and the observer runs the same simulation, and the published state (poses, probe readings) otherwise, each filtered by what the observer asked for.

On the 1.0 line. These were flame_multiplayer's before 1.0; the network core a 1.0 game depends on lives here, and flame_multiplayer (turns, a ghost's feed, a spectator's tape) is built on it.

Flat Dart. Nothing here needs the Flutter SDK; a relay and a test run under plain dart test.

Classes

EngineRollback
An EngineLoop kept in step on two machines or a party of them over a PeerWire: RollbackSession with the loop's snapshots as its state and the loop's steps as its step.
InputStatus
Where a slot's frame for a step came from: heard from its machine, guessed from the last one heard, or from a machine gone.
LoopbackPair
The two ends LoopbackWire.pair joins: first in slot nought, second in slot one. Taken apart as final LoopbackPair(:first, :second) = ….
LoopbackParty
size machines on one wire in one process, as late and as lossy as a test asks, the same losses for the same seed — the party's LoopbackWire.
LoopbackWire
Two PeerWires joined to each other in one process, as late and as lossy as a test asks, and repeatable from its seed.
ObserverFeed
The machine that runs the authoritative simulation, sending it to whoever observes: a twin's server to its dashboards, a laboratory's bench to a class, a match to its spectators.
ObserverFilter
What one observer wants sent: which probes' readings, by id. Null for every probe.
ObserverMessages
The engine's observer messages: under PeerWire.engineKey, so a game's own messages on the same wire never collide with them.
ObserverMode
What a SimulationObserver is sent, step by step: the run's tape, to replay into a simulation of its own, or the published state, to draw.
ObserverRestore
What SimulationObserver.restore is handed: the feed's state to start the tape from, and the step it was taken after.
ObserverSnapshot
Whether a snapshot an observer is sent is the whole state or the change since the last one it was sent.
PartySeat
A machine's place in a relay's party: its wire, the slot the relay gave it, the party's code — the one to send a friend — and full, which completes once every player's slot is taken.
PeerBytes
Bytes as a PeerWire.listenBytes listener hears them, for the reason PeerMessage gives.
PeerBytesDelivery
What PeerWire.deliverBytes is handed, for the reason PeerSend gives.
PeerDelivery
What PeerWire.deliver is handed by an adapter, for each message the connection brings, for the reason PeerSend gives.
PeerMessage
A message as a PeerWire.listenFrom listener hears it: what arrived, and who sent it.
PeerRoom
The room two machines meet in, over the one PeerWire a relay gives them.
PeerSend
What PeerWire.send is handed: a message and how it must travel.
PeerSendBytes
What PeerWire.sendBytes is handed, for the reason PeerSend gives.
PeerWire
Whatever carries messages between machines: a relay's WebSocket, a WebRTC data channel, a game networking library's connection, a party room's fan-out.
RollbackSession<S>
A fixed-step game kept in step on players machines over a PeerWire, each sending its own player's hands: the one rollback, for two machines and for a party alike.
RollbackStats
What a RollbackSession has done, read at one moment: how many steps it ran, how many it ran again and what each of those took, and the corrections it could not make.
RollbackStep
What RollbackSession.applyAndStep is handed for one step: its number, every slot's frame, where each came from, and whether it is a step run again.
SettledStep<S>
What RollbackSession.onSettled is told of a step as it leaves the window: its number, the state it ended in and the frames it ran on.
SimulationObserver
A machine watching an authoritative simulation an ObserverFeed sends.
SnapshotDivergence
Where two runs claiming to be the same actually differ, once DigestTrace has already said they do.
WebSocketTransport
A PeerWire over a plain WebSocket, through net-02's relay — doc/tooling-plan.md's named fallback for whatever a WebRTC data channel could not reach: a platform it has not been wired into yet, or a network whose NAT neither side's ICE candidates got through.
WireHello
The versions a machine names in its hello, and the rule two hellos are held to.
WireState
Whether a PeerWire carries messages.

Functions

diffRuns({required DigestTrace a, required DigestTrace b, required Map<String, Object?> snapshotAtA(int step), required Map<String, Object?> snapshotAtB(int step)}) → SnapshotDivergence?
net-04's whole shape: DigestTrace.divergenceFromHex already finds the step cheaply, from nothing but the eight-digit hex numbers a .f3drun already carries; this asks for the one thing a digest cannot answer — what, at that step, differed — and only there, rather than at every checkpoint either side ever recorded.
findParty(Uri relay, {required String game, int size = 4, String terms = '', SimulationVersion? simulation, void left(int slot)?, Duration timeout = const Duration(seconds: 10)}) → Future<PartySeat>
Finds a party of size for game on the relay at relay — one still filling with strangers who asked for the same, or a new one — and answers with this machine's seat in it. The seat's code is the party's, for a friend to join by; its full completes when the last player arrives, which is when a game should start.
joinParty(Uri relay, String code, {int size = 4, bool watching = false, String? owner, String terms = '', SimulationVersion? simulation, void left(int slot)?, Duration timeout = const Duration(seconds: 10)}) → Future<PartySeat>
Joins the party code on the relay at relay — ws://host:port/ — as a player, or with watching as a spectator, and answers once the relay has said which slot is this machine's; a party of size when this machine is the first to ask for code.
observeParty(Uri relay, String code, {required String owner, SimulationVersion? simulation, void left(int slot)?, Duration timeout = const Duration(seconds: 10)}) → Future<PartySeat>
Joins the party code on the relay at relay as an observer of the authoritative simulation its slot 0 runs: the relay's observer path, let in by the owner's token as a watcher is, whatever simulation it names. What it sends reaches the authority alone, and the authority's messages addressed to its slot reach it alone; a SimulationObserver on the seat's wire does the rest.
relayRoom(Uri relay, String code, {String terms = '', SimulationVersion? simulation}) → Uri
The address of the two-player room code on the relay at relay — ws://host:port/ — for WebSocketTransport.connect, asking with terms, this build's protocol and the game's simulation, as joinParty does: a machine on another simulation is closed with the relay's reason, which WebSocketTransport.closed answers.

Typedefs

LoopState = ({Snapshot state, int step})
A state an EngineRollback keeps of its loop: the step count and every part of the state the loop's snapshots hold.