Skip to content
Back to skills

Multiplayer And Network Sync

ASecurity

Multiplayer networking -- LiveKit rooms, movement encoding, interpolation, profile sync, entity-participant mapping. Use when working with RoomHub, movement systems, EntityParticipantTable, or remote player sync.

  • 23 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
developmentgoapi

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add decentraland/unity-explorer --skill multiplayer-and-network-sync --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Multiplayer And Network Sync?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Multiplayer And Network Sync
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/decentraland-multiplayer-and-network-sync/badge)](https://www.skillsdirectory.com/skills/decentraland-multiplayer-and-network-sync)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: multiplayer-and-network-sync
description: "Multiplayer networking -- LiveKit rooms, movement encoding, interpolation, profile sync, entity-participant mapping. Use when working with RoomHub, movement systems, EntityParticipantTable, or remote player sync."
user-invocable: false
---

# Multiplayer & Network Sync

## Sources

- `docs/network-synchronization.md` -- Entity sync via LiveKit rooms, host vs remote entity semantics

---

## Dual-Room Architecture

`RoomHub` orchestrates four LiveKit rooms: **Island**, **Scene** (GateKeeper), **Chat**, and **VoiceChat**. Island + Scene are "local rooms" for entity synchronization; Chat + VoiceChat are independent.

`RoomHub.StartAsync()` starts Island + Scene + Chat in parallel; VoiceChat starts on demand. `AllLocalRoomsRemoteParticipantIdentities()` merges participants from Island + Scene (cached per frame).

### IConnectiveRoom Lifecycle

`ConnectiveRoom` runs an infinite reconnection loop: `PrewarmAsync` -> repeated `CycleStepAsync` with 1s heartbeat. State machine: `Stopped -> Starting -> Running -> Stopping -> Stopped`. Uses `Atomic<State>` for thread-safe state transitions (LiveKit callbacks arrive off main thread). Recovery delay on failure is 5 seconds.

**Why two rooms for entities:** The Scene room connects only to the scene the host is standing in, so only co-located players sync scene-specific CRDT state. The Island room provides global visibility -- remote avatars appear even when the host is in a different scene, but Island data is NOT used for scene CRDT synchronization (bandwidth concern).

---

## Host Entity Semantics (CRITICAL GOTCHA)

> See `docs/network-synchronization.md`

**Host components (`PBIdentityData`, `PBAvatarEquippedData`, `PBAvatarBase`) are ALWAYS present** on the scene from startup through the entire lifecycle -- regardless of whether the host is inside or outside the scene.

**Remote entities behave completely differently:**
- If the scene is NOT the current scene, remote entities cannot be present in CRDT state (even if visually nearby via Island room)
- When the host enters a scene, all remote participants within bounds are propagated as if they just entered
- When the host is within the scene and others enter/leave, it works as expected
- Remote entities themselves are never explicitly deleted; their CRDT entity range is reserved

**Implication for JS scenes:** Host identity components are always queryable. Do not assume their presence means the host is physically inside the scene. Remote player presence accurately reflects co-location only when the host is current.

---

## Movement Encoding & Transmission

### NetworkMovementMessage Fields

`timestamp`, `position`, `velocity`, `velocitySqrMagnitude`, `rotationY`, `headIKYawEnabled`, `headIKPitchEnabled`, `headYawAndPitch`, `movementKind`, `animState`, `velocityTier`, `isSliding`, `isStunned`, `isInstant`, `isEmoting`.

### Encoding Pipeline

- **`FloatQuantizer`** -- Fixed-size quantization via scaled integers. `Compress(value, min, max, bits)` / `Decompress`.
- **`ParcelEncoder`** -- Flattens 2D parcel coordinates `(x, y)` into a 1D index relative to the Genesis City grid.
- **`TimestampEncoder`** -- Circular buffer encoding with wraparound detection on decompression.

### Send Throttling

`PlayerMovementNetSendSystem` caps at **10 messages/sec**. Adaptive send rate: drops to `MoveSendRate` on movement, doubles (up to `StandSendRate`) when idle. Immediate sends on grounded/jump state changes. Messages are sent to both Island and Scene pipes via `MultiplayerMovementMessageBus.Send()`, supporting both compressed and uncompressed schemas.

---

## Movement Interpolation

### InterpolationSpline Types

| Type | Description |
|------|-------------|
| `Linear` | `Vector3.Lerp` wrapper |
| `Hermite` | Cubic Hermite spline matching start/end positions and velocities |
| `MonotoneYHermite` | Hermite with Y-axis monotonicity (prevents vertical overshoot) |
| `FullMonotonicHermite` | Monotonic on all axes |
| `Bezier` | Cubic Bezier with velocity-derived control points |
| `VelocityBlending` | Projective velocity blending (Murphy & Lengyel 2011) |
| `PositionBlending` | Projective position blending (Murphy & Lengyel 2011) |

### RemotePlayersMovementSystem

Runs in `PresentationSystemGroup`. Processes a priority queue of `NetworkMovementMessage` per remote player:

1. **First message** -- teleport to position
2. **Cooldown** -- wait 2x `MoveSendRate` for stability
3. **Interpolation** -- starts between past and new message using selected spline; falls back to `Linear` when velocity is near-zero or grounded state changes
4. **Extrapolation** -- when no messages arrive and speed > threshold, `ExtrapolationComponent` continues movement along last velocity for up to `TotalMoveDuration`
5. **Blend** -- after extrapolation stops, blends back with speed-limited interpolation

**Catch-Up:** When inbox has more messages than `CatchUpMessagesMin`, interpolation duration is shortened proportionally to smooth DeltaTime.

---

## Profile & Entity Sync

### EntityParticipantTable

Bidirectional mapping between wallet IDs and ECS entities, with room source tracking (`ISLAND`, `GATEKEEPER`, or both). NOT thread-safe -- only accessed from main thread.

Key API: `Register(walletId, entity, fromRoom)`, `Release(walletId, fromRoom)` (returns true only when `ConnectedTo == RoomSource.NONE`), `AddRoomSource(walletId, fromRoom)`.

`Release` only removes the entity when disconnected from all rooms. This allows a player visible via Island to remain alive when they leave the Scene room.

### ThreadSafe Disconnect Buffering

LiveKit participant callbacks fire off the main thread. `ThreadSafeRemoveIntentions` buffers disconnect events using `MutexSync`. Main thread consumes via `OwnedBunch<RemoveIntention>` which acquires the lock on construction, exposes the collection, and clears + releases on `Dispose()`.

### ProfileBroadcast

Sends `AnnounceProfileVersion` to both Island and Scene pipes. Async: fetches self-profile version before sending via `SendAndDisposeAsync` with `KindReliable`.

---

## SDK Propagation Systems

- **`PlayerTransformPropagationSystem`** (Global -> Scene) -- Copies `CharacterTransform` into the scene world's `SDKTransform` when transform has changed and player is assigned to scene.
- **`WritePlayerTransformSystem`** (Scene -> CRDT) -- Converts `SDKTransform` to scene-relative coordinates and writes via `IECSToCRDTWriter`.
- **`WritePlayerIdentityDataSystem`** (Scene -> CRDT) -- Writes `PBPlayerIdentityData` (address + isGuest) on dirty, with force-write on `Initialize()`. Uses static lambda to avoid closures.
- **`PlayerProfileDataPropagationSystem`** (Global -> Scene) -- Copies `Profile` data to scene entities via `CharacterDataPropagationUtility` when profile or CRDT entity assignment is dirty.

---

## Detailed Reference

For detailed code examples, see [reference.md](reference.md).

---

## Cross-References

- **ecs-system-and-component-design** -- System patterns, `ref var` mutation rules, cleanup lifecycle
- **async-programming** -- LiveKit async flows, `CancellationTokenSource` management, `UniTaskVoid` exception handling
- **scene-runtime-and-crdt** -- CRDT bridge (`IECSToCRDTWriter`), scene state machine, `MultiThreadSync`
- **cross-world-ecs-access** -- Global/scene world access, `PlayerCRDTEntity`/`PlayerSceneCRDTEntity` bridge, `ISceneIsCurrentListener`

Files in this skill

  • SKILL.md7.3 KB
  • reference.md5.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.