Learn/Networking

Networking

Networking is the layer that lets several machines share one running Space: a server owns the simulation and players connect to it. Today every Space runs in a single process, so this page covers the connections Eustress Engine does make, the authority rules already written in code, and the plan for multiplayer.

Time12 min readLevelIntermediateUpdatedUpdated Sep 2026

01Overview

Where Networking Stands

A shared session needs three things: a transport that carries messages between processes, rules for who owns each moving thing, and a description of what to send. Eustress has the rules and most of the description in code. The transport is the missing piece, so Play in Studio and the standalone Player each run one simulation in one process, for one person.

PieceStateWhat that means today
Play in StudioWorksPhysics, scripts and your character run inside the editor.
Ownership rulesWrittenServer-owned by default, one client owner at a time, arbitration on request.
Interest and delta trackingWrittenPer-player area of interest and change thresholds.
QUIC endpoint and messagesWrittenNothing in Studio starts it.
Headless serverPartialDownloads and unpacks a published Universe, but does not load it or accept players.
Transport between processesPlannedlightyear 0.29, described in What's Next.
Joining from the websitePlannedThe play page reports that no server is available.
Info
Written is not running

Rows marked Written are real code with nothing to carry its messages between machines. This page describes them as the model a networked Space will use, not as something you can switch on.

Two Halves in the Code

The networking code sits in two modules that were written separately and never joined. Each has what the other lacks.

Shared networking crateOwnership rulesInterest and deltasPhysics validationno socketEngine play serverQUIC endpoint, TLSMessage protocolSessionsnever startedplanned:lightyear 0.29Today: Play in Studio and the Player each run one process for one person
Each half has what the other lacks. The plan keeps the ownership rules and the message families, and replaces both transports with one library.
ModuleHasLacks
Shared networking crateOwnership arbitration, per-player interest, delta tracking, physics validation, prediction and interpolation markersA socket. Its start handler marks the server as running without opening a port.
Engine play serverA QUIC endpoint with TLS, a typed message protocol with delivery channels, player sessionsA caller for its accept loop, a join handshake, and anything that marks entities to send.

In a normal build neither module marks a single entity for replication, so a working transport would have nothing to send yet. The plan in What's Next keeps the ownership rules and the message families and replaces the rest with one library.

02Local Play

Play Runs In-Process

Play simulates the open Space inside the editor process. Physics, scripts and the character tick locally, and Stop returns the Space to the state it had before you pressed Play. Each mode is covered on the Studio page.

KeyAction
F5Play, with your character
F7Run, with no character
F6Pause or resume
F8Stop

The Roblox keymap preset moves Run to F8 and Stop to Shift+F5. The standalone Player works the same way for one person: it opens one Space from disk when it starts and runs it locally.

Server Controls

The Network menu and the Test tab already carry the controls a hosted session will need: Start Local Server, Stop Server, Join as Client, synthetic clients and a stress test. They arrive ahead of the transport they depend on.

Advanced
Start Local Server does not start a server yet

Start Local Server (F9), Stop Server, the Test tab's Server, Client, Local, Spawn and Disconnect buttons, the Network Panel item and the stress test have no working server behind them. Studio's play code reserves a hosting mode and a joining mode, but no menu, key or command selects either one, so these controls change nothing today.

03Connections

Ports Studio Opens

A Studio session listens on the network in three places, and a fourth listener exists only in a special build. Each one serves a single job on your machine; none of them carries a multiplayer session.

ListenerAddressWhenUsed by
Engine BridgeTCP on 127.0.0.1, a port the OS assigns, written to .eustress/engine.port in the UniverseEvery sessionThe MCP server and other tools on this machine
Rune LSPTCP on 127.0.0.1, a port the OS assigns, written to .eustress/lsp.portEvery session where the language server ships beside StudioYour editor, through Rune LSP
Bliss nodeTCP 7777 on every network interfaceAt launch, while Bliss is enabled (the default)Bliss co-signing and identity checks, see Earning
Stream nodeTCP 33000 and HTTP 43000 on 127.0.0.1Only in builds with the stream-node featureTools that follow event streams
Advanced
The Bliss node listens on every interface

It binds 0.0.0.0, so other machines on your network can reach port 7777. Studio reads the setting only at startup: set bliss_enabled to false in ~/.eustress_engine/settings.json and restart to keep the node off.

Event Streams

Inside the engine, changes flow through EustressStream, an append-only log of named topics held in memory. scene_deltas carries scene edits, sim_results carries simulation outcomes and log/output mirrors the Output panel. In the default build these topics stay inside the process.

A build with the stream-node feature exposes the same topics to other programs on the machine over TCP, with an HTTP interface beside it. The node binds 127.0.0.1 and authenticates nobody, which is why it stays out of the default build.

Bash (stream-node builds)
# List topics with their stats
curl http://127.0.0.1:43000/topics

# Follow scene edits live as server-sent events
curl -N http://127.0.0.1:43000/topics/scene_deltas/stream

# Replay a topic's ring buffer from offset 0
curl -N "http://127.0.0.1:43000/topics/scene_deltas/replay?from=0"

Calls to eustress.dev

Studio also makes HTTPS requests to the Eustress API at api.eustress.dev. Signing in fetches a challenge from the API, which Studio signs with the Ed25519 key in your identity file, and publishing uploads your Universe. These are requests from your machine to a web service, not connections between players. The upload path is described on the Publishing page.

04Authority

Owners

Authority decides whose word counts for an entity. The rules are written in the shared networking crate and wait for a transport to carry them. Every networked entity has exactly one owner, recorded as a client id in which 0 means the server.

OwnerWho simulates itEveryone else
Server (the default)The serverClients interpolate between the states they receive
One clientThat client, predicting aheadThe server validates it; other clients interpolate
LockedThe serverEvery ownership request is refused

Client ownership keeps the controls responsive for the player driving something while the server keeps the final say. The first entity planned for it is each player's own avatar, as described in The First Shared Session.

Ownership Requests

A client asks for an entity, and the server runs the same checks in order every time:

Clientrequests entityServer checkslock, distance,cooldown, other requestsGrantednew owner predictsDeniedreason sent backIdle 30 s: ownership returns to the server, blended over 1.5 s
Every request runs the same checks in the same order, so the server alone decides who owns what.
  1. A locked entity is refused.
  2. A request from the current owner changes nothing.
  3. A client too far from the entity is refused, and the reason gives the distance.
  4. An entity that changed owner in the last 100 ms is refused while it cools down.
  5. If another client's request is still pending, the lower ping wins. A client with no ping on record counts as 100 ms. Pending requests expire after 500 ms.
  6. Otherwise ownership transfers: the old owner stops simulating the entity and the new owner starts predicting it.

A client-owned entity with no activity for 30 seconds returns to the server on its own. The hand-off is blended over 1.5 seconds so physics authority moves gradually rather than in one step.

Validation

The server checks what client owners report. It compares the speed of every client-owned entity with a ceiling and counts a violation for each breach. Violations decay over time, one per second by default, and the server raises a disconnect for any client that reaches 10.

Speed is the only check the server runs. An acceleration check exists in an optional physics module that normal builds leave out, and the teleport-distance and input-queue limits in the same configuration are not read by any system yet.

05Replication

What Replicates

Replication is the server sending each client the state it needs to show the shared world. In the design, an entity takes part when it carries a replication marker. The server then gives it a network id and works out, for each client, what changed:

  • Motion: position, rotation and velocity, sent only when the change passes a small threshold.
  • Data: attributes, tags, parameters, documents, and image and video assets, mirrored into network copies whenever they change.
  • Interest: each client receives only the entities inside its area of interest, found on a spatial grid. An entity joins inside the radius and leaves only past a wider band, so objects at the edge do not flicker in and out.
  • Ownership: a client never receives updates for an entity it owns, because its own simulation is the source.

Nothing attaches the replication marker in a normal build yet, which is why the plan starts with a single, deliberate choice of what to send.

The Message Protocol

The engine's play server defines the messages a session will exchange, each on a delivery channel that suits it. Messages are serialized with bincode and travel over QUIC with TLS, using a certificate the server generates for localhost when it starts.

FamilyMessagesChannel
ConnectionJoin, JoinAccepted, JoinRejected, DisconnectReliable, ordered
HeartbeatPing, Pong, AckTickUnreliable
PlayersPlayerSpawned, PlayerDespawnedReliable, ordered
InputPlayerInputUnreliable, latest wins
ChatChatMessage, ChatBroadcastReliable, ordered
WorldWorldSnapshot (reliable); Replication, WorldDeltaUnreliable, latest wins
PhysicsPhysicsAuthority, PhysicsCorrectionReliable, ordered
ScriptsRemoteEvent, RemoteFunction, RemoteFunctionReturnReliable, ordered

The script family is the part your code will touch: a remote event is a name with serialized arguments, and a remote function call carries an id that its return value echoes, so the caller can match the answer to the question.

06What's Next

Transport: lightyear

Multiplayer will adopt lightyear 0.29, pinned exactly, behind a multiplayer build feature that is off by default. Three facts decided it. lightyear 0.29 targets Bevy 0.19, the version Eustress runs on. Its Avian integration depends on avian3d 0.7, the version Eustress already uses, which avoids two copies of the physics engine fighting over replicated bodies. And its host-server mode runs client and server in one app, which is exactly the shape of Play in Studio.

The ownership rules will stay as they are, the message families will move onto lightyear channels, and the separate replication markers in the two modules will collapse into one. If the transport spike fails, the fallback is bevy_replicon 0.42 with bevy_replicon_renet 0.18.

The Phases

Each phase ends with a test that has to pass before the next one starts:

PhaseWorkDone when
0. SafetyHarden release builds, bind the Bliss node to loopback, commit the lockfile, and build the server and Player in CICI fails on a broken server or Player build
1. StorageRegenerate files from the WorldDb at publish, ship an allowlisted package, keep the listing idRepublishing an unchanged Space produces byte-identical packages
2. Server opens a worldGive the headless server the storage it needs to load the Universe it downloadsIt reports the same entity count Studio shows for that Space
3. Transport spikeTwo apps in one process, in a separate workspace, with one avatar replicated under prediction and rollbackIt works with no engine code involved, or the plan switches to the fallback
4. Studio dev serverStart Local Server hosts on 127.0.0.1, with LAN behind an explicit toggle and a tokenPlay in Studio, connect the Player, and two avatars move in both windows
5. Join from the websitePlay links that open the Player, servers that register their address, single-use join tokensA second machine joins from the website, and a forged or expired token is refused

The First Shared Session

The first multiplayer release will replicate one thing: each player's avatar. The shared avatar runtime already has a local-player mode and a remote mode, so the local avatar will be marked for replication and every other machine will spawn it as remote. Anchored geometry will not travel over the network at all, because every machine loads the same published package.

Team Create, matchmaking, voice chat, always-on servers and mobile players sit outside that first release.

One avatar across two machines is the first milestone. Everything else builds on it.

Loading Eustress Engine...