NetCrafter Relay — Manual
Full reference for every tab, field, and feature of the NetCrafter Relay editor window.
Full reference for the NetCrafter Relay editor window. Open it from Tools → Pivec Labs → NetCrafter Relay.
The window is divided into four top-level sections, each with a sidebar of sub-tabs: Definition, Code, Scenes, and Settings.
Definition section#
Schema bar
The schema bar runs across the top of every section. It shows a dropdown of all discovered definitions (schemas found anywhere under Assets/PivecLabs/NetCrafterRelay/Definitions/). Selecting a definition switches the entire window to that definition's assets.
Click Create Definition when no definition exists or to add a new one.
Messages tab
Displays all GameplayMessageDefinition assets found in Definitions/{Name}/Messages/.
To create a message: click Create Gameplay Message.
Message fields
| Field | Description |
|---|---|
| Message Name | The base class name. A ClientToHost message generates {Name}Request.cs. A HostToClient message generates {Name}Event.cs. |
| Direction | ClientToHost — client sends to whichever peer is hosting (becomes a Request). HostToClient — host pushes to a client (becomes an Event). ClientToHostBroadcast — client sends to host; host re-broadcasts to all (also becomes a Request). |
| Transport | Reliable — app-level ACK + retry wrapper. Unreliable — fire-and-forget, used for continuous transform sync. |
| Host Handler Name | The name that must match a Host Action's Handler Name. Validation will fail if no matching Host Action exists. |
| Fields | The data payload. Each field has a Name and a Type (see Field Types below). |
Field types
| Schema type | C# type | Wire format | Notes |
|---|---|---|---|
int |
int |
WriteInt32 / ReadInt32 |
|
float |
float |
WriteFloat / ReadFloat |
|
bool |
bool |
WriteBool / ReadBool |
|
string |
string |
WriteString / ReadString |
|
Vector2 |
Vector2 |
WriteVector2 / ReadVector2 |
|
Vector3 |
Vector3 |
WriteVector3 / ReadVector3 |
|
Quaternion |
Quaternion |
WriteQuaternion / ReadQuaternion |
Edit asset YAML directly to use |
PlayerId |
int |
WriteInt32 / ReadInt32 |
Semantic alias for player IDs |
ItemId |
string |
WriteString / ReadString |
Semantic alias for item identifiers |
| ModelName | ModelName | WriteTo(RelayWriter) / ReadFrom(RelayReader) |
Edit asset YAML: set type: ModelName |
Arrays: any field type can be made an array. Edit the asset YAML directly and set isArray: 1. The generated C# field becomes List<T>, written as a count prefix followed by each element in order.
The editor type dropdown exposes int, float, string, bool, Vector2, Vector3, PlayerId, and ItemId. To use Quaternion, nested model types, or array fields, open the .asset file in a text editor and edit the YAML directly.
There are no per-field keys on the wire — fields are written in schema declaration order, since client and host logic are generated together from one schema in one pass.
Data Definitions tab
Displays all DataDefinition assets in Definitions/{Name}/DataDefinitions/.
A Data Definition defines a reusable data model. The generator produces a {Name}.cs class with serialisation helpers (WriteTo(RelayWriter) and ReadFrom(RelayReader)).
To create a model: click Create Data Definition. Set a Model Name and add fields exactly as you would for a message.
Host Actions tab
Displays all HostActionDefinition assets in Definitions/{Name}/HostActions/.
Host Actions serve two purposes:
- They satisfy the validation check — every message's Host Handler Name must match at least one Host Action's Handler Name.
- They drive
HostActionRouter.csgeneration — the logic that runs only on whichever peer is currently hosting.
| Field | Description |
|---|---|
| Handler Name | Must match the Host Handler Name on one or more messages or events. |
| Trigger Message | Optional reference to the message that triggers this action. |
| Response Event | The HostToClient event sent back to peers after this action runs. |
| Logic Type | BroadcastAll (host relays to every peer), SenderOnly (echo back to the sender), TargetUser (relay to one specific peer — requires an int targetId field on the trigger message), or Custom. |
| Custom Host Code | Freeform C# for the Custom logic type, spliced directly into the generated handler method. |
There is no server to deploy: HostActionRouter.cs compiles straight into the same client build as everyone else.
Sync Rules tab
Displays all SyncRuleDefinition assets in Definitions/{Name}/SyncRules/.
Click Create Sync Rule to add a new rule to the list. Select a rule in the left panel to edit its details on the right.
| Field | Description |
|---|---|
| Rule Name | Identifier for this rule. Also used as the network command suffix: __nc_sync_{RuleName}. |
| Sync Target | The component property to synchronise. See the table below. |
| Sync Mode | Always, OnChange, or Interval. See below. |
| Interval | Seconds between syncs when Sync Mode is Interval. Default: 0.05 (20 Hz). |
Sync Targets
| Target | Component | Property |
|---|---|---|
Transform_Position |
Transform |
position (world space) |
Transform_Rotation |
Transform |
rotation (world space quaternion) |
Transform_Scale |
Transform |
localScale |
Rigidbody_Velocity |
Rigidbody |
linearVelocity |
Rigidbody_AngularVelocity |
Rigidbody |
angularVelocity |
Sync Modes
| Mode | Behaviour |
|---|---|
Always |
Sends every FixedUpdate. Use for values that change every frame (e.g. position of a moving character). |
OnChange |
Sends only when the value has changed by more than an epsilon since the last send (0.001 units for Vector3, 0.1 degrees for rotation). Lower bandwidth cost; adds a single-frame detection lag. |
Interval |
Sends every N seconds (interval field). Use for infrequently-changing values or where exact timing matters more than immediate response. |
Sync rules are stored in the schema and exported for validation. The runtime system is implemented via NetCrafterSyncManager and NetCrafterSyncBinding — see the Sync Rule Runtime section below.
Code section#
Build Code tab
| Control | Action |
|---|---|
| Validate Definition | Runs the validator and shows a success dialog or opens the error window. Does not generate any files. |
| Preview JSON | Opens a read-only window showing the raw schema JSON that will be passed to the generator. |
| Generate All Files | Validates, then generates client code, host code, and config. |
| Client Only | Validates, then generates client C# files only. |
| Host Only | Validates, then generates HostActionRouter.cs only. |
| Open Output Folder | Reveals the schema's Generated/ folder in Explorer. |
All generation paths run schema validation first. If validation fails the error window opens and generation is aborted.
Generated files land in:
Definitions/{Name}/Generated/Client/
Definitions/{Name}/Generated/Host/
Definitions/{Name}/Generated/Config/
Schema validation
The validator (NC_ValidateSchema) performs four checks in order:
- Duplicate names — no two messages, events, or models may share a name; no message and model may share a name.
- Invalid field types — all field types must be a supported primitive or a declared model name.
- Missing handler references — every message and event must name a handler that exists in the Host Actions list.
- Circular model references — model fields must not form a cycle (e.g. A references B which references A).
Errors are shown in a scrollable Validation Error Window. Fix all errors before generating.
Code Preview tab
Displays the generated files for the selected definition, split into three groups: Client, Host, Config.
| Group tab | Shows |
|---|---|
| Client (n) | All .cs files in Generated/Client/ |
| Host (n) | HostActionRouter.cs in Generated/Host/ |
| Config (n) | RelayConfig.json in Generated/Config/ |
Selecting a file displays it in the right panel with syntax highlighting (VS Code–style dark theme or a darker light theme, adapting to your editor skin).
Normal / Diff toggle: after you generate at least once, the toggle becomes active. Diff view compares the on-disk file against a snapshot captured immediately before the last generation run. Added lines have a green background; removed lines have a red background. The toggle is greyed out with a tooltip if no snapshot exists yet.
Action buttons (top of the file panel):
| Button | Action |
|---|---|
| Copy | Copies the file content to the clipboard |
| Open ↗ | Opens the file in the system default application |
| Normal / Diff | Toggles between syntax-highlighted view and diff view |
Config Generator tab
Generates RelayConfig.json from the current schema's Relay Settings asset — relay host/port, rendezvous URL, and credential mode. There is no zone/room/AOI concept here; every peer talks to the same fixed relay endpoint.
| Button | Action |
|---|---|
| Refresh Preview | Re-derives the JSON from the current Relay Settings without writing to disk. The preview can go stale if you edit Settings after opening the tab — click this to update it. |
| Generate RelayConfig.json | Writes the config to Definitions/{Name}/Generated/Config/RelayConfig.json. |
| Open Config Folder | Reveals Generated/Config/ in Explorer without writing. |
Settings section#
Relay Settings tab
Settings are stored in Definitions/{Name}/RelaySettings.asset — one asset per definition.
Relay
| Field | Default | Description |
|---|---|---|
| Relay Host | (empty — required) | Your self-hosted coturn TURN/STUN endpoint. No default; NetCrafter Relay does not ship with or point at any Pivec Labs-hosted relay. See Server Deployment Guide. |
| Relay Port | 3478 |
TURN default port |
| Rendezvous URL | (empty — required) | Your self-hosted join-code → host relayed-address lookup service. No default; see Server Deployment Guide. |
| Credential Mode | StaticSecret |
StaticSecret or RestApi — how TURN credentials are obtained |
| Shared Secret | (empty) | Used when Credential Mode is StaticSecret |
| Auto-Reconnect | true |
Reserved for future use |
| Debug Logging | true |
Enables relay client-side verbose logging |
Login
| Field | Default | Description |
|---|---|---|
| Login Mode | Guest |
Guest: assigns an auto-generated guest name. UsernamePassword and Custom are reserved for future use. |
| Guest Name Prefix | Player_ |
Prefix prepended to the auto-assigned guest name |
Transport
| Field | Default | Description |
|---|---|---|
| Send Queue Size | 4096 |
Bytes |
| Max Message Size | 32768 |
Bytes — a soft cap on the send queue, not a guarantee of delivery. See Message size limits below: payloads much above ~1200-1400 bytes are not reliably delivered over the relay. |
Click Save Settings to persist changes. Click Reset to Defaults to restore the values shown above.
Project Settings tab
Settings are stored in Definitions/{Name}/ProjectSettings.asset.
Output Folders
Read-only display of the three output paths, all derived from the schema's definition folder. Cannot be changed manually.
Template Settings
| Field | Description |
|---|---|
| Use Custom Templates | When enabled, the generator looks for override templates in Definitions/{Name}/Templates/ before falling back to the built-in templates. |
When Use Custom Templates is on:
- The Override Folder path is shown (read-only, auto-computed).
- Create Override Folder copies all nine built-in templates into the override folder and prepends a header comment identifying them as overrides. The button is disabled once the folder exists.
- The Template Files grid shows each template with a green
[✓]if an override exists or grey[ ]if the global fallback will be used. - Reset next to each template deletes the override file, reverting that template to the global fallback.
See the Template Guide for full details.
Naming Conventions
| Field | Default | Description |
|---|---|---|
| Namespace | PivecLabs.Generated |
C# namespace used in all generated files (client and host code share this namespace) |
| Class Prefix | (empty) | Prepended to every generated class name |
| Class Suffix | (empty) | Appended to every generated class name |
Generation Behavior
| Field | Default | Description |
|---|---|---|
| Overwrite Existing Files | true |
When false, the generator skips files that already exist on disk |
| Show Summary After Build | true |
Reserved — generation summary logging is always written to the Unity console |
Logging
| Field | Default | Description |
|---|---|---|
| Verbose Logging | false |
Passes the flag to the generator; currently only affects console log output |
Experimental Features
| Field | Description |
|---|---|
| Enable Partial Class Support | Reserved — not yet wired to the generator |
| Enable Advanced Sync Rules | Reserved — not yet wired to the generator |
Scenes section#
Prefab Generator tab
The Prefab Generator creates Unity prefabs for use in your multiplayer scene.
ConnectionManager Prefab
The Create ConnectionManager Prefab button packages whichever generated type implements INetCrafterConnection (normally RelayConnectionManager.cs) into a reusable prefab saved to:
Definitions/{Name}/Prefabs/ConnectionManager.prefab
Deliberately a sibling of Generated/, not inside it — this is a hand-configured runtime asset (your actual relay host, rendezvous URL, and TURN credentials once you set them in the Inspector), not codegen output, so it's never touched by Build Code's regeneration.
Requirements: client code must have been generated first (Build Code tab). If no INetCrafterConnection type is found in Generated/Client/, an error dialog explains what to do.
The panel shows the expected output path and whether the prefab already exists. The Scene Assistant tab reads this same path and prefers the prefab when setting up scenes. If the prefab is absent, the scene buttons fall back to creating a raw GameObject via reflection.
Coming Soon — Prefab Generator
The following sections are visible in the UI but greyed out.
| Section | What it will do |
|---|---|
| Player Prefab | Generate a player prefab from a base prefab, optionally adding NetworkIdentity, MovementSync, RotationSync, AnimationSync, and HealthSync components |
| Chat UI | Generate a UI prefab in Minimal, Modern, or MMO-Style layouts |
| NPC Prefab | Generate an NPC prefab with configurable AI and synchronisation options |
Scene Assistant tab
The Scene Assistant scaffolds a Unity scene with all required multiplayer GameObjects.
Settings are stored in Definitions/{Name}/SceneAssistantSettings.asset — one asset per definition, created automatically when you open the tab.
ConnectionManager Prefab Status
A banner at the top of the tab shows whether a ConnectionManager.prefab exists. If it is missing, a warning prompts you to create it in the Prefab Generator tab first. Scene buttons work either way — the prefab is preferred, but a raw GameObject is added via reflection if the prefab does not yet exist.
Scene Setup
| Control | Description |
|---|---|
| Scene Name | Filename for the generated scene. Default: GameScene. The scene is saved as Definitions/{Name}/{SceneName}.unity. |
| Create Multiplayer Scene | Creates a new empty scene containing: a Main Camera (with Camera and AudioListener), a ConnectionManager GameObject, an EventDispatcher GameObject (if the toggle is enabled), and a NetworkManager empty GameObject reserved for future use. Prompts you to save any unsaved changes first. Leaves the new scene open in the editor. |
| Add to Existing Scene | Adds only the ConnectionManager (and EventDispatcher if toggled) to the currently open scene. If a ConnectionManager is already present, a confirmation dialog asks before adding a second one. Does not add a camera or NetworkManager. |
Event Dispatcher
The Add Event Dispatcher toggle controls whether a NetCrafterEventDispatcher GameObject is included when a scene is created or patched. See the Event Dispatcher section below for full details on the API.
Player Spawning
| Field | Description |
|---|---|
| Spawn Mode | Auto or Manual — stored for future runtime use |
| Player Prefab | Project reference to your player prefab asset |
| Spawn Points | A list of Vector3 world positions |
Spawn point list controls:
[i] (x, y, z) Remove— one row per point. Remove deletes that entry and immediately renames anySpawnPoint_Nchildren in the active scene to stay in sequence.+ Add Spawn Point— appends a new point at(0, 0, 0).
Place Spawn Points in Scene — creates or updates a SpawnPoints parent GameObject in the active scene. Each child is named SpawnPoint_0, SpawnPoint_1, … and carries a NetCrafterSpawnPointGizmo that draws a green wire sphere with a Scene view label. Button is disabled with a tooltip when no spawn points are defined.
Place Player Prefab — instantiates the assigned player prefab at spawnPoints[0] (or Vector3.zero if no points are defined), registers the action with undo, and selects the new GameObject. Disabled when no prefab is assigned. A HelpBox below the button notes that spawn point 0 is always used and suggests using multiple points for team starts or respawn logic.
When you click Create Multiplayer Scene and spawn points are already defined, the SpawnPoints hierarchy is placed in the new scene automatically — no extra button click needed.
Additive Scenes
Each entry in the list has:
- A SceneAsset picker — the chosen scene's path is stored as a string in
SceneAssistantSettings.assetso it survives builds. - An Async toggle — when on, the scene is loaded with
SceneManager.LoadSceneAsync; when off, withSceneManager.LoadScene(synchronous, blocking). - A Remove button.
Generate Scene Loader — writes NetCrafterSceneLoader.cs to Generated/Client/ alongside the RelayConnectionManager. The file contains an IEnumerator Start() that loads each scene in list order. Re-generate any time the list changes; the file is overwritten.
All additive scenes must be added to File → Build Settings before building. Missing scenes cause runtime errors. A HelpBox warning appears in the tab whenever at least one scene is defined.
At these session sizes (2–4 players typical, up to 8–10) there's no proximity/area-of-interest management to configure — every peer sees the whole session, so there's no MMO bounds section here (unlike NetCrafter's SFS3-backed MMO mode).
Scene Events tab
Binds HostToClient network events to scene-level UnityEvent hooks without writing code.
Setup
- The tab discovers all
HostToClientGameplayMessageDefinitionassets in the current schema and displays one binding entry per event. - Click Add Router to Scene to create a
SceneEventRouterGameObject in the active scene. The tab header immediately changes to a green[✓] SceneEventRouterstatus with a Select button. A second click is disabled — only one router per scene. - Wire each event's On Received UnityEvent in the Inspector-style UI. Bindings are serialized into the scene and survive save/reopen.
- The enabled toggle on each entry silences that binding at runtime without removing it.
How it works at runtime
NetCrafterSceneEventRouter subscribes to NetCrafterEventDispatcher in Start(). When an event fires, the router stores the payload in an internal dictionary and calls onReceived.Invoke(). To read the event payload in your handler:
var ev = (ChatBroadcastEvent)
NetCrafterSceneEventRouter.Instance.GetLastPayload("ChatBroadcast");
A HelpBox below each event's UnityEvent shows the exact cast pattern for that event type.
Orphaned bindings
If an event is renamed or removed from the schema, its binding moves to an Orphaned Bindings section at the bottom of the tab with a warning and a Remove button.
Event Dispatcher#
NetCrafterEventDispatcher is a runtime MonoBehaviour that ships with NetCrafter Relay (Scripts/NetCrafterEventDispatcher.cs). It is not generated — it is a permanent part of the package available to any script in your project.
Why it exists
The generated RelayConnectionManager routes all incoming relay messages through a private dispatch switch. Traditionally, to intercept events you would either subclass the generated file or edit it directly — both approaches break on the next Generate run. NetCrafterEventDispatcher provides an alternative: a string-keyed publish–subscribe bus that any MonoBehaviour can subscribe to without touching the generated code.
Adding it to a scene
Enable Add Event Dispatcher in Scenes → Scene Assistant, then use Create Multiplayer Scene or Add to Existing Scene. The dispatcher is added as a separate EventDispatcher GameObject with DontDestroyOnLoad.
To add it manually: create a GameObject and attach NetCrafterEventDispatcher to it.
API
// Register a callback for a host event
NetCrafterEventDispatcher.Instance.Subscribe("ChatBroadcast", OnChatBroadcastReceived);
// Deregister — call this in OnDisable or OnDestroy
NetCrafterEventDispatcher.Instance.Unsubscribe("ChatBroadcast", OnChatBroadcastReceived);
The callback receives the already-deserialised typed event object as object. Cast it to the generated event class:
private void OnChatBroadcastReceived(object payload)
{
var ev = (ChatBroadcastEvent)payload;
chatWindow.AddMessage(ev.senderName, ev.message);
}
Command names match your schema event names exactly — schema event ChatBroadcast → command string "ChatBroadcast".
How the dispatcher integrates with generated code
Every switch case in the generated RelayConnectionManager.DispatchLocal calls Dispatch before the stub handler. Both always fire — the dispatcher fires first so subscribers receive the event, then the On{Event} stub runs so any direct override in a subclass also executes.
case "ChatBroadcast":
{
var ev = ChatBroadcastEvent.Deserialize(payload);
NetCrafterEventDispatcher.Instance?.Dispatch("ChatBroadcast", ev);
OnChatBroadcast(ev); // stub — override in a subclass if preferred
break;
}
Exception isolation
Each subscriber callback is wrapped in an individual try/catch. One failing subscriber cannot block other subscribers from receiving the same event. The error is logged to the Unity console with the command name and full stack trace.
Lifetime and cleanup
NetCrafterEventDispatcher is a singleton with DontDestroyOnLoad. Always call Unsubscribe in OnDisable or OnDestroy — failing to do so leaves a dangling reference and the callback will continue to fire for the lifetime of the dispatcher.
Sync Rule Runtime#
The Sync Rule Runtime automatically synchronises component values between peers according to the rules defined in the Sync Rules tab. It ships as three permanent runtime MonoBehaviours in Scripts/ — nothing is generated per-schema.
Components
| Script | Role |
|---|---|
NetCrafterSyncManager |
Singleton. Owns the object registry, routes incoming sync payloads to the correct binding, and sends outgoing data via INetCrafterConnection. |
NetCrafterSyncBinding |
Placed on each networked GameObject. Reads a SyncRuleDefinition from the Inspector, drives the tick loop, builds and sends payloads (if hasAuthority), or applies incoming payloads (if not). |
INetCrafterConnection |
Interface implemented by the generated RelayConnectionManager. Decouples the sync runtime from the generated namespace. |
Setting up sync in a scene
- Add
NetCrafterSyncManagerto a persistent GameObject in the scene (or enable Add Event Dispatcher in Scene Assistant and add it manually). It auto-detects theRelayConnectionManageratStart. If no connection is found, it logs a clear error and gates all send calls. - Add
NetCrafterSyncBindingto each networked GameObject. - In the Inspector, assign:
- Rule — drag a
SyncRuleDefinitionasset fromDefinitions/{Name}/SyncRules/. - Object Id — a unique integer identifying this object in the session. Assign from game logic (e.g.
RelayConnectionManager.Instance.LocalUserIdon connect for the local player). - Has Authority — check this for the local player. Leave unchecked for remote players.
- Rule — drag a
Authority and object ID
Each networked GameObject has an objectId and an authority flag:
hasAuthority = true(local player): The binding sends data unreliably every tick according to the sync mode. The host relays this to other peers viaBroadcastAll.hasAuthority = false(remote players): The binding subscribes to incoming sync events viaNetCrafterEventDispatcherand applies received values to its component.
objectId must be unique per session and agreed between sender and receiver. NetCrafter Relay does not assign or manage IDs — this is game-logic responsibility. RelayConnectionManager.Instance.LocalUserId is a natural choice for player objects.
Data flow
Outbound (local player → host):
NetCrafterSyncBinding.FixedUpdate → BuildPayload (RelayWriter → byte[])
→ NetCrafterSyncManager.TrySendSync
→ INetCrafterConnection.Send(cmd, payload, reliable: false)
→ relay client sends the raw UDP envelope
Inbound (host → remote peer binding):
Relay envelope "__nc_sync_{RuleName}" arrives
→ RelayConnectionManager default case
→ NetCrafterEventDispatcher.Dispatch(cmd, (object)new RelayReader(payload))
→ NetCrafterSyncManager callback (RelayReader payload)
→ bindings[data.ReadInt32()].ApplyIncoming(data)
→ transform.position = data.ReadVector3()
Wire format
All sync commands use the prefix __nc_sync_ followed by the rule name. The payload is a positional binary blob (no per-field keys):
| Order | Type | Description |
|---|---|---|
| 1st | int |
objectId of the sending binding |
| 2nd | Vector3 or Quaternion |
Position, scale, or velocity (Vector3); rotation (Quaternion) |
Payload convention note
Sync callbacks receive a RelayReader as the object payload — not a typed event class — with the "id" field already consumed by NetCrafterSyncManager before the binding's ApplyIncoming is called. This is different from normal event callbacks (which receive a deserialised event object). See the comment in NetCrafterSyncManager.SubscribeToSyncRule and the default case in the generated RelayConnectionManager.
What is NOT handled
- Interpolation / smoothing: values are applied directly. Use
Vector3.Lerpor a similar approach in game code if smoothing is needed. - Ownership transfer:
hasAuthorityis set in the Inspector and does not change at runtime. - Bandwidth budgeting: tick rate is controlled by Unity's
FixedUpdaterate and theintervalfield. - Duplicate suppression on sync messages: sync traffic is sent unreliably by design (no retry/dedupe) — only
Reliablemessages get the ACK+retry treatment.
Known Limitations#
Message size limits
Keep individual message payloads under roughly 1200-1400 bytes. Larger payloads are silently dropped, not truncated or fragmented — confirmed against a live coturn server: 100/500/1200/1400-byte payloads round-tripped correctly, a 4000-byte payload never arrived at all.
This isn't a relay bug — it's an inherent limit of sending raw UDP through TURN with no application-level fragmentation. Payloads that push the underlying UDP datagram past the typical ~1500-byte Ethernet MTU get IP-fragmented, and fragmented UDP is unreliable across the public internet (many routers, NAT devices, and firewalls drop fragments). The Max Message Size setting (default 32768 bytes) only limits what's queued for send — it does not mean payloads that large will actually arrive.
If a message needs to carry more data than that (e.g. a large snapshot or asset chunk), split it into multiple smaller messages at the application level and reassemble on the receiving side. NetCrafter Relay does not do this chunking automatically today.
Disconnect detection
OnPeerDisconnected is basic silence-based detection, not a full connection-quality or reconnection system. There's no distinction between "brief lag spike" and "peer actually gone" — it's purely: no traffic for ~15 seconds, fire once.
RelayConnectionManager sends a tiny liveness heartbeat to the connected peer every 5 seconds (piggybacked on the same timer that refreshes the TURN allocation/permission — see API Reference). If no traffic at all — heartbeat or any real message — has been received from a peer for about 15 seconds (3x the heartbeat interval), OnPeerDisconnected(peerId) fires exactly once for that peer. Confirmed live: after a force-killed peer, the surviving side fired the event in ~15 seconds, versus no signal at all previously.
What it does not do: reconnect automatically, retry the underlying TURN allocation on the disconnected peer's behalf, or fire more than once per peer. Treat it as "this peer is gone, handle it in your own game logic" (show a disconnect screen, end the session, etc.) — not as a building block for resilience against flaky connections.
Coming Soon#
The following features are visible in the UI but not yet fully implemented.
| Feature | Status |
|---|---|
| Prefab Generator — Player / Chat UI / NPC | Coming. Sections visible in the UI but greyed out. |
| Partial classes / Advanced sync | Coming. |
| Rendezvous REST-API credential mode | Placeholder — RelayConnectionManager's TURN credential wiring currently only stubs StaticSecret. |
| coturn channel binding (RFC 5766 §11) | Not yet implemented — the relay client uses Send/Data indications only, which have higher per-packet overhead than a bound channel. |