Skip to content

Multiplayer

orblit-net replicates component columns, not objects.

That follows from the core. The store already holds every Transform contiguously, so a column is the natural unit to send, and sending one is a memcpy rather than a walk over a graph serialising each node in turn.

Deltas against an acknowledged baseline, rather than against the last thing sent. Each peer knows which tick the other confirmed and sends the difference from that, so a dropped message costs you one larger snapshot instead of a world that quietly drifts apart.

Which components replicate is declared where they are:

import 'package:orblit_codegen/orblit_codegen.dart';
@OrblitComponent(replicated: true, ownerWritable: true)
class Health {
int value = 100;
}

ownerWritable is the authority rule. A component’s owner may change it and have the change accepted, and anyone else’s write is dropped rather than merged.

It’s the boring, correct answer to a class of bug that’s very hard to find any other way. Without an ownership rule, two peers writing the same column give you a value that depends on packet arrival order, and it will be right in testing and wrong out in the world.

Updates arrive at whatever rate the network manages, and a frame needs a value for now, between two of them.

This is the third place sampling pays for itself. The received values are two moments, and what gets drawn is the moment in between. Nothing in the renderer knows the network exists at all.

Transport is a deliberately narrow seam: a stream of framed messages in, a send out, and a close. Everything above it turns a world into bytes, and everything below it gets bytes to another machine.

Two come with it.

LoopbackLink wires two transports to each other in the same process, with optional latency. That’s useful well beyond testing. A single-player build and a listen server both run the real replication path over it, so the networked code path is the only code path, and it can’t rot quietly while nobody is playing multiplayer.

SocketTransport is a WebSocket, with SocketServer on the other end. WebSockets rather than raw UDP for now, and the reason is framing: a snapshot is a message with a length, and WebSocket already delivers whole messages in order. Sequencing, acknowledgement and reassembly on top of datagrams is a real piece of work, and it isn’t the piece that makes Orblit worth using. When the frame budget says otherwise, Transport is where a datagram transport goes, and a game needing one that Orblit doesn’t ship can write it in an afternoon.

There’s no matchmaking, no lobby service, no relay, and no server you can rent. orblit_net is replication and two transports. Everything above that is yours.