Protocol
Clients speak JSON over a WebSocket. The current protocol version is 6 (plugin 1.3, server 1.3), sent in hello and reported by GET /health as protocolVersion. A mismatch is refused with the error code version.
This page is for anyone building or debugging a client. Day-to-day setup does not require it.
Client to server
{"type":"hello","protocolVersion":6,"room":"MyProject","password":"...","clientId":"...","session":"...","state":{}}
Clients send at most 10 messages per second, and only when something changed. Past its limit, the server stops reading that client for a moment instead of dropping messages.
Identity
clientId and session are 16 to 64 letters, digits, or -. A hello without them is refused with protocol. An authorId cannot be sent back as a clientId, so seeing someone's messages does not let you act as them.
Two editors opened on the same copy of the project share one authorId, each with its own session. A hello with the clientId and session of a connection still in the room (its socket is not closed yet, as after a network drop) replaces it: the others get leave, then the new presence.
Server to client
On join, the server sends welcome (selfId, authorId, protocolVersion), roster (peers, each with id, authorId, and state), chatHistory (messages, complete), comments, and assets (records).
complete is true when no older chat remains. Joining returns the last 100 messages. A room keeps its last 10,000 chat messages and accepts up to 2,000 comment threads. A thread holds 500 messages.
State
state fields: name, color, map, cam, asset, graph, nodes, actors, active, pie, play, sequencer, branch, actorsMore, nodesMore.
branch is the Git branch, or null when HEAD is detached. actorsMore and nodesMore count selected actors or nodes that were not sent, past the limit of 64.
play is null, or the team game this editor hosts:
{"address":"203.0.113.8","port":17777,"map":"/Game/Maps/Lobby","public":true,"since":1710000000000}
public is false when the address is only reachable on the local network. since is when hosting started; when two editors host the same map, the earlier one wins.
Anchors
A comment or ping anchor.kind is map, graph, or asset. An asset anchor looks like:
{"kind":"asset","package":"/Game/Maps/Lobby"}
Errors
{"type":"error","code":"auth","reason":"...","message":"..."}
The English message is a fallback. The Unreal plugin translates code into the editor language.
What is stored
File records are kept per package and author. A record left under a name by an author who is not connected (a record from protocol 5, or from another copy of the project) is taken over by the next asset.modify or asset.clear under that name. Changing name moves the sender's records to the new name: assetCleared for the old one, then assetModified. A record not updated for 30 days is dropped.
When the last editor with an authorId disconnects, the server clears its "I'm working on this" marks and broadcasts each one as assetModified with working: false. Git LFS locks are not stored on the server. Chat text may contain [[comment:<id>]]. The server stores that as text. The plugin turns it into a button when Comment Links in Chat is on.
Upgrading from protocol 5
Update the plugin and the server together: each refuses the other's previous version with version. The database is kept as is. File records from protocol 5 are taken over by name, as above. Comment messages written under protocol 5 keep the connection id they were written with, so nobody can edit them anymore.