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.
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.
| Piece | State | What that means today |
|---|---|---|
| Play in Studio | Works | Physics, scripts and your character run inside the editor. |
| Ownership rules | Written | Server-owned by default, one client owner at a time, arbitration on request. |
| Interest and delta tracking | Written | Per-player area of interest and change thresholds. |
| QUIC endpoint and messages | Written | Nothing in Studio starts it. |
| Headless server | Partial | Downloads and unpacks a published Universe, but does not load it or accept players. |
| Transport between processes | Planned | lightyear 0.29, described in What's Next. |
| Joining from the website | Planned | The play page reports that no server is available. |
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.
| Module | Has | Lacks |
|---|---|---|
| Shared networking crate | Ownership arbitration, per-player interest, delta tracking, physics validation, prediction and interpolation markers | A socket. Its start handler marks the server as running without opening a port. |
| Engine play server | A QUIC endpoint with TLS, a typed message protocol with delivery channels, player sessions | A 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.
| Key | Action |
|---|---|
F5 | Play, with your character |
F7 | Run, with no character |
F6 | Pause or resume |
F8 | Stop |
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.
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.
| Listener | Address | When | Used by |
|---|---|---|---|
| Engine Bridge | TCP on 127.0.0.1, a port the OS assigns, written to .eustress/engine.port in the Universe | Every session | The MCP server and other tools on this machine |
| Rune LSP | TCP on 127.0.0.1, a port the OS assigns, written to .eustress/lsp.port | Every session where the language server ships beside Studio | Your editor, through Rune LSP |
| Bliss node | TCP 7777 on every network interface | At launch, while Bliss is enabled (the default) | Bliss co-signing and identity checks, see Earning |
| Stream node | TCP 33000 and HTTP 43000 on 127.0.0.1 | Only in builds with the stream-node feature | Tools that follow event streams |
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.
# 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.
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.
| Family | Messages | Channel |
|---|---|---|
| Connection | Join, JoinAccepted, JoinRejected, Disconnect | Reliable, ordered |
| Heartbeat | Ping, Pong, AckTick | Unreliable |
| Players | PlayerSpawned, PlayerDespawned | Reliable, ordered |
| Input | PlayerInput | Unreliable, latest wins |
| Chat | ChatMessage, ChatBroadcast | Reliable, ordered |
| World | WorldSnapshot (reliable); Replication, WorldDelta | Unreliable, latest wins |
| Physics | PhysicsAuthority, PhysicsCorrection | Reliable, ordered |
| Scripts | RemoteEvent, RemoteFunction, RemoteFunctionReturn | Reliable, 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:
| Phase | Work | Done when |
|---|---|---|
| 0. Safety | Harden release builds, bind the Bliss node to loopback, commit the lockfile, and build the server and Player in CI | CI fails on a broken server or Player build |
| 1. Storage | Regenerate files from the WorldDb at publish, ship an allowlisted package, keep the listing id | Republishing an unchanged Space produces byte-identical packages |
| 2. Server opens a world | Give the headless server the storage it needs to load the Universe it downloads | It reports the same entity count Studio shows for that Space |
| 3. Transport spike | Two apps in one process, in a separate workspace, with one avatar replicated under prediction and rollback | It works with no engine code involved, or the plan switches to the fallback |
| 4. Studio dev server | Start Local Server hosts on 127.0.0.1, with LAN behind an explicit toggle and a token | Play in Studio, connect the Player, and two avatars move in both windows |
| 5. Join from the website | Play links that open the Player, servers that register their address, single-use join tokens | A 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.