Lattice — High-Level Design (HLD)¶
Document:
01-high-level-design.mdStatus: Draft v1 · Audience: engine integrators, infra/platform engineers, gameplay engineers, reviewers Scope: System-wide architecture, topologies, authority models, deployment, and end-to-end flows. Defers to:02-netcode-lld.mdfor wire formats, channel internals, prediction/rollback math, and serialization.
Related documents¶
| Doc | Purpose |
|---|---|
README.md |
Suite intro, build, quickstart |
00-overview.md |
Vision, glossary, requirements, non-goals |
01-high-level-design.md |
This document — architecture & flows |
02-netcode-lld.md |
Transport/replication/prediction low-level design |
03-auth-service.md |
lattice-auth design, tokens, accounts |
04-social-library.md |
lattice-social friends/presence/parties |
05-engine-integration.md |
Unity / Unreal / Godot / Web bindings |
06-implementation-roadmap.md |
Milestones, sequencing, risks |
1. Purpose & scope¶
Lattice is a standalone, engine-agnostic networking suite that gives games Photon-Fusion-class netcode without binding them to one engine or one topology. The same gameplay simulation runs unchanged on a dedicated server, on a player acting as a peer-to-peer (P2P) host, or in a single-player/offline harness. Topology and role are injected at runtime; the compiled simulation logic is identical everywhere.
This HLD describes:
- The split between the data plane (latency-critical game traffic, C++) and the control plane (account/matchmaking/social, managed services).
- The three supported network topologies and when to use each.
- The two first-class authority models and how they coexist.
- Full system component and deployment architecture.
- End-to-end sequence flows for cold start, P2P create/join, and host migration.
- A high-level view of the replication & tick loop.
Anything below the wire is intentionally summarized and cross-referenced to 02-netcode-lld.md.
2. Architectural overview & design principles¶
2.1 Design principles¶
- Data plane vs control plane separation. Real-time game packets (
lattice-core,lattice-gameserver,lattice-relay) never depend on a synchronous call into a control-plane service during gameplay. Control-plane services (lattice-auth,lattice-director,lattice-social) are stateless request/response or pub/sub services that gate entry into a session, not the per-tick loop. - Deterministic shared simulation. Gameplay logic lives in a single shared simulation library compiled into both the dedicated server and the client. Given identical inputs and starting state, the simulation advances identically. This is the foundation of client prediction, server reconciliation/rollback, and "a client can be the host".
- Role injection, not role forking. There is no separate "server build" of the game logic. A runtime
Role(Authority / Predicted / Replicated) andTopology(Dedicated / P2PHost / P2PClient / Offline) are supplied at startup. The code path is the same; only authority and I/O wiring differ. - Stable C ABI core.
lattice-coreis C++20 but exposes a flatextern "C"boundary. Engine bindings (lattice-unity,lattice-unreal,lattice-godot,lattice-web) are thin idiomatic wrappers over that ABI. This keeps one battle-tested netcode implementation behind every engine. - Transport independence. The custom UDP transport, our Relay, and an optional QUIC/WebTransport backend all implement the same internal transport interface. Higher layers (reliability channels, replication) are transport-agnostic.
- Authority is a property of objects, not the build. Server/host-authoritative and shared/distributed authority are both first-class and can be mixed within one session at object granularity.
- Stateless, horizontally scalable control plane. Auth/Director/Social nodes hold no per-request state; all durable state lives in PostgreSQL/Redis (optional NATS for events). Game state lives in the data-plane processes.
2.2 Layered view of lattice-core¶
flowchart TB
subgraph App["Game + Engine"]
Bind["Engine binding<br/>(unity / unreal / godot / web)"]
Sim["Shared simulation library<br/>(deterministic, role-injected)"]
end
subgraph Core["lattice-core (C++20, C ABI)"]
ABI["Stable C ABI boundary (extern C)"]
Rep["Replication + interest management"]
Pred["Prediction / rollback / reconciliation"]
Snap["Snapshot + interpolation"]
Chan["Reliability + ordering channels"]
Ser["Serialization (delta / quantization)"]
Trans["Transport abstraction"]
Crypto["Crypto + session keys"]
end
subgraph Backends["Transport backends"]
UDP["Custom UDP"]
Relay["Relay client (P2P fallback)"]
QUIC["QUIC / WebTransport (web, optional)"]
end
Bind --> ABI
Sim --> ABI
ABI --> Rep
ABI --> Pred
Rep --> Snap
Pred --> Snap
Snap --> Chan
Rep --> Ser
Chan --> Ser
Ser --> Trans
Crypto --> Trans
Trans --> UDP
Trans --> Relay
Trans --> QUIC
2.3 Data plane vs control plane¶
flowchart LR
subgraph CP["Control plane (.NET 8 / C#) — stateless, scalable"]
Auth["lattice-auth<br/>:8443"]
Dir["lattice-director<br/>:8444"]
Soc["lattice-social<br/>:9443"]
end
subgraph DP["Data plane (C++) — latency-critical"]
GS["lattice-gameserver<br/>UDP 27015+"]
RL["lattice-relay<br/>UDP 7777"]
STUN["STUN<br/>:3478"]
end
subgraph Store["Shared stores"]
PG[("PostgreSQL")]
RD[("Redis")]
NATS[("NATS (optional)")]
end
Client["Client (engine binding + lattice-core)"]
Client -- "login / token (TLS)" --> Auth
Client -- "matchmake / session (TLS)" --> Dir
Client -- "friends / presence (TLS/WSS)" --> Soc
Client -- "game traffic (UDP, encrypted)" --> GS
Client -- "P2P / relayed traffic (UDP)" --> RL
Client -- "NAT discovery (UDP)" --> STUN
Auth --- PG
Auth --- RD
Dir --- PG
Dir --- RD
Soc --- PG
Soc --- RD
Dir -. "fleet events" .- NATS
Soc -. "presence events" .- NATS
Dir -- "allocate / health" --> GS
The dashed line is the principle in one picture: control-plane calls happen before and around a session (login, matchmake, presence), while the solid UDP arrows are the in-session hot path that must not block on any control-plane round trip.
3. Network topologies¶
Lattice supports three topologies behind the same API surface. A game selects topology at session creation; clients do not need separate code paths because the shared simulation and lattice-core adapt via role injection.
3.0 How the same sim runs as dedicated server or P2P host¶
The shared simulation library is compiled once and linked into:
lattice-gameserver(a headless C++ binary), and- the client application (via the engine binding).
At runtime the host of authority — whether a dedicated server or a peer — instantiates the simulation with Role = Authority. Everyone else instantiates the identical code with Role = Predicted (for owned objects) or Replicated (for remote objects). The only differences are:
| Aspect | Dedicated authority | P2P host authority |
|---|---|---|
| Process | lattice-gameserver |
Client app, same sim lib |
| Trust | Trusted infra | Semi-trusted peer (host) |
| Lifetime | Fleet-managed | Tied to host's connection |
| Failure handling | Fleet reschedule | Host migration (§7.3) |
| Wiring | Director allocates endpoint | Director registers peer endpoint |
stateDiagram-v2
[*] --> Boot
Boot --> RoleResolve: read Topology + Role (injected)
RoleResolve --> AuthoritySim: Role = Authority<br/>(dedicated OR p2p host)
RoleResolve --> ClientSim: Role = Predicted/Replicated
AuthoritySim --> Running: identical sim code
ClientSim --> Running: identical sim code
Running --> [*]
3.1 (a) Dedicated server / client (authoritative)¶
A fleet-managed lattice-gameserver owns authority. Clients predict locally and reconcile against server snapshots. Lag compensation runs on the server.
flowchart TB
subgraph DC["Game data center / region"]
GS["lattice-gameserver<br/>Role = Authority<br/>UDP 27015+"]
end
C1["Client A (Predicted)"] -- "inputs ↑ / snapshots ↓ (UDP)" --> GS
C2["Client B (Predicted)"] -- "inputs ↑ / snapshots ↓ (UDP)" --> GS
C3["Client C (Predicted)"] -- "inputs ↑ / snapshots ↓ (UDP)" --> GS
Dir["lattice-director"] -- "allocate / monitor" --> GS
When to use: competitive/ranked play, cheat-sensitive titles, persistent worlds, larger player counts, anything needing consistent low-latency authority and lag compensation. Highest infra cost; strongest integrity.
3.2 (b) P2P host-client (a peer hosts; authoritative host)¶
One peer runs the shared sim with Role = Authority; others connect to it as predicted clients. No dedicated infra needed for gameplay; Director is still used for discovery and session registration.
flowchart TB
Host["Peer HOST<br/>(client app + shared sim, Role = Authority)"]
P1["Peer (Predicted)"] -- "UDP (direct)" --> Host
P2["Peer (Predicted)"] -- "UDP (direct)" --> Host
Dir["lattice-director"] -. "register / discover session" .-> Host
Dir -. "session endpoint" .-> P1
Dir -. "session endpoint" .-> P2
When to use: co-op, casual/social sessions, small lobbies, cost-sensitive titles, LAN/console party play. Low infra cost; integrity bounded by host trust; vulnerable to host disconnect (mitigated by migration).
3.3 (c) P2P with relay fallback (NAT punch fails → relay)¶
Peers first try a direct connection via STUN-assisted hole punching. If that fails (symmetric NAT, restrictive firewalls), traffic falls back to lattice-relay, which forwards encrypted packets between peers. The relay is a dumb forwarder — it never sees plaintext and never runs sim logic.
flowchart TB
Host["Peer HOST (Role = Authority)"]
Peer["Joining peer (Predicted)"]
STUN["STUN :3478"]
Relay["lattice-relay<br/>UDP 7777"]
Peer -- "1 discover public mapping" --> STUN
Host -- "1 discover public mapping" --> STUN
Peer -- "2 attempt direct hole punch (UDP)" --- Host
Peer -- "3a SUCCESS: direct path" --> Host
Peer -- "3b FAIL → relay path (encrypted)" --> Relay
Relay -- "forward (encrypted)" --> Host
When to use: automatically, as the resilience layer under any P2P session. Direct is preferred for latency; relay guarantees connectivity at the cost of an extra hop and relay bandwidth. Selection is automatic per peer-pair (some peers direct, some relayed in the same session).
4. Authority models¶
Lattice treats authority as a per-object property, so both models are first-class and can coexist within one session.
4.1 Server/host-authoritative (prediction + rollback)¶
The authority (dedicated server or P2P host) is the single source of truth. Clients:
- Apply local input immediately (client-side prediction) for responsiveness.
- Receive authoritative snapshots and reconcile — replay un-acked inputs from the corrected state (rollback).
- Interpolate remote objects from a buffered snapshot history (~100 ms) for smoothness.
The authority runs lag compensation (rewinding hit targets to the shooter's view) for fairness. This is the default for competitive and cheat-sensitive gameplay.
sequenceDiagram
participant C as Client (Predicted)
participant A as Authority (server/host)
C->>C: apply input locally (predict)
C->>A: input(tick N) [reliable-seq]
A->>A: simulate authoritative tick
A-->>C: snapshot(tick N, ack input)
C->>C: reconcile: rewind to snapshot, replay un-acked inputs
Note over C,A: Remote objects interpolated from snapshot buffer (~100 ms)
4.2 Shared/distributed authority (per-object ownership)¶
Each replicated object has an owner that holds authority for it; ownership can be transferred at runtime (e.g., the player who grabbed a physics prop becomes its owner). Non-owners apply dead reckoning (extrapolation) between updates, and the system converges to eventual consistency. Conflicts are resolved by ownership + tie-break rules (e.g., authority tick / owner priority), detailed in 02-netcode-lld.md.
stateDiagram-v2
[*] --> OwnedByA
OwnedByA --> TransferPending: request transfer (B grabs object)
TransferPending --> OwnedByB: authority confirms
TransferPending --> OwnedByA: rejected / timeout
OwnedByB --> TransferPending: another transfer
OwnedByB --> [*]
OwnedByA --> [*]
When to use: large dynamic-physics sandboxes, many interactive objects, builder/social worlds, and cases where round-tripping every object through one authority would be too costly. Trades strict consistency for scalability and local responsiveness.
4.3 How a project chooses & whether they coexist¶
flowchart TD
Q1{"Cheat-sensitive /<br/>competitive?"}
Q1 -- Yes --> SA["Server/host-authoritative<br/>+ prediction & rollback"]
Q1 -- No --> Q2{"Many dynamic<br/>physics objects?"}
Q2 -- Yes --> DA["Distributed authority<br/>+ per-object ownership"]
Q2 -- No --> Q3{"Need low infra cost /<br/>small lobby?"}
Q3 -- Yes --> P2P["P2P host-authoritative"]
Q3 -- No --> SA
SA -.-> Mix["Coexist: critical objects authoritative,<br/>props distributed"]
DA -.-> Mix
P2P -.-> Mix
Coexistence is explicit and common. A typical shooter might keep players, projectiles, and scoring under host/server authority while letting destructible debris and grabbed props use distributed ownership. Authority is configured per object/prefab archetype; the runtime tags each replicated object with its model. The two models share the same transport, snapshot, and interest-management machinery.
5. System component architecture¶
flowchart TB
subgraph Clients["Clients (per engine)"]
U["lattice-unity"]
E["lattice-unreal"]
G["lattice-godot"]
W["lattice-web (stretch)"]
end
subgraph CoreLib["lattice-core (C ABI) + shared sim"]
CoreA["Transport / channels / crypto"]
CoreB["Replication / prediction / interest mgmt"]
end
subgraph Edge["Edge / LB"]
LB["Load balancer (TLS termination)"]
end
subgraph Control["Control plane (.NET 8)"]
Auth1["lattice-auth #1 :8443"]
Auth2["lattice-auth #2 :8443"]
Dir["lattice-director :8444<br/>matchmaking + directory + fleet orch"]
Soc["lattice-social :9443"]
end
subgraph DataPlane["Data plane (C++)"]
STUN["STUN :3478"]
Relay["lattice-relay :7777"]
subgraph Fleet["Game fleet"]
GS1["lattice-gameserver :27015"]
GS2["lattice-gameserver :27016"]
GSn["lattice-gameserver :2701n"]
end
end
subgraph Storage["Storage"]
PG[("PostgreSQL")]
RD[("Redis")]
NATS[("NATS (optional)")]
end
U --> CoreA
E --> CoreA
G --> CoreA
W --> CoreA
CoreA --- CoreB
CoreA -- "TLS" --> LB
LB --> Auth1
LB --> Auth2
LB --> Dir
LB --> Soc
CoreA -- "UDP game" --> GS1
CoreA -- "UDP game" --> GS2
CoreA -- "UDP relay" --> Relay
CoreA -- "UDP STUN" --> STUN
Dir -- "allocate / drain / health" --> Fleet
Dir -- "session token (Ed25519)" --> Auth1
GS1 -- "validate token" --> Auth1
Auth1 --- PG
Auth2 --- PG
Auth1 --- RD
Dir --- PG
Dir --- RD
Soc --- PG
Soc --- RD
Dir -. events .- NATS
Soc -. events .- NATS
GS1 -. session results .-> Dir
Component responsibilities
| Component | Plane | Language | Responsibility |
|---|---|---|---|
lattice-core |
Data | C++20 (C ABI) | Transport, reliability channels, serialization, replication, prediction/rollback, interest management, crypto |
| Engine bindings | Data | C#/C++/GDScript/JS | Idiomatic wrappers over the C ABI |
| Shared sim lib | Data | C++20 | Deterministic gameplay; linked into server and client |
lattice-gameserver |
Data | C++20 | Dedicated authoritative host; links core + sim |
lattice-relay |
Data | C++20 | Encrypted P2P packet forwarder (no plaintext, no sim) |
| STUN | Data | — | NAT mapping discovery for hole punching |
lattice-auth |
Control | .NET 8 | Accounts, login, Ed25519-signed tokens, session-token issuance |
lattice-director |
Control | .NET 8 | Matchmaking, session directory, fleet orchestration (allocate/drain) |
lattice-social |
Control | .NET 8 | Friends, presence, parties, invites |
| PostgreSQL | Store | — | Durable accounts, sessions, social graph |
| Redis | Store | — | Hot session/directory/presence cache, rate limits, ticket queues |
| NATS (optional) | Store | — | Fleet/presence/event fan-out |
6. Deployment & infrastructure¶
Control-plane nodes are stateless and replicated behind regional load balancers; game fleets are autoscaled per region; stores are shared (with read replicas/regional caches). Relay and STUN are deployed near players for latency.
flowchart TB
GLB["Global anycast / DNS<br/>(geo-routing)"]
subgraph R1["Region: us-east"]
LB1["Regional LB (TLS)"]
subgraph CP1["Stateless control nodes"]
A1["auth x N :8443"]
D1["director x N :8444"]
S1["social x N :9443"]
end
subgraph DP1["Data plane"]
ST1["STUN :3478"]
RL1["relay :7777"]
F1["game fleet :27015+ (autoscaled)"]
end
RDc1[("Redis (regional)")]
end
subgraph R2["Region: eu-west"]
LB2["Regional LB (TLS)"]
CP2["auth / director / social x N"]
DP2["STUN / relay / game fleet"]
RDc2[("Redis (regional)")]
end
subgraph Shared["Global shared stores"]
PGp[("PostgreSQL primary")]
PGr[("PostgreSQL read replicas")]
NATSc[("NATS cluster (optional)")]
end
GLB --> LB1
GLB --> LB2
LB1 --> A1
LB1 --> D1
LB1 --> S1
A1 --- RDc1
D1 --- RDc1
S1 --- RDc1
D1 --> F1
A1 --- PGp
D1 --- PGp
S1 --- PGp
A1 --- PGr
CP2 --- RDc2
CP2 --- PGp
PGp --> PGr
D1 -. events .- NATSc
CP2 -. events .- NATSc
Deployment notes
- Geo-routing: clients hit the nearest regional LB; Director may steer matchmaking to the lowest-latency region with capacity.
- Statelessness: any auth/director/social node can serve any request; horizontal scale is add-a-pod. All session state is in Redis/PostgreSQL.
- Fleet management: Director allocates/drains
lattice-gameserverinstances; cordoned servers finish active matches before shutdown. - Stores: PostgreSQL primary + read replicas for durable data; Redis regional caches for hot/low-latency lookups; optional NATS cluster for cross-node events.
- Edge data plane: STUN and Relay run per region near players; game fleet capacity autoscales on ticket demand.
7. End-to-end sequence flows¶
7.1 Cold start — login → matchmake → connect → spawn (dedicated)¶
sequenceDiagram
autonumber
participant Cl as Client (binding + core)
participant LB as Regional LB
participant Au as lattice-auth :8443
participant Di as lattice-director :8444
participant GS as lattice-gameserver :27015+
participant RD as Redis / PostgreSQL
Cl->>LB: login(credentials) [TLS]
LB->>Au: forward
Au->>RD: verify account
Au-->>Cl: auth token (Ed25519-signed)
Cl->>Di: matchmake / request session [TLS, auth token]
Di->>Au: validate auth token
Di->>RD: enqueue ticket / read fleet capacity
Di->>GS: allocate slot (region, mode)
Di->>Di: mint session token (Ed25519) bound to server + player
Di-->>Cl: assignment {server endpoint :2701x, session token}
Cl->>GS: UDP connect + handshake (X25519, session token)
GS->>Au: validate session token (Ed25519)
GS->>GS: spawn player into session (Role=Authority for sim)
GS-->>Cl: accepted + initial snapshot (baseline state)
Note over Cl,GS: In-session UDP loop begins (inputs ↑ / snapshots ↓)
7.2 P2P host create + peer join (hole punch success and relay fallback)¶
sequenceDiagram
autonumber
participant H as Host peer (Role=Authority)
participant Di as lattice-director
participant ST as STUN :3478
participant P as Joining peer (Predicted)
participant RL as lattice-relay :7777
H->>ST: discover public mapping
H->>Di: register session {host public/private endpoints}
P->>Di: discover / join session [auth token]
Di-->>P: session info {host candidates, relay endpoint, session token}
P->>ST: discover own public mapping
par Direct path attempt
P->>H: UDP hole punch (to host candidates)
H->>P: UDP hole punch (to peer candidates)
end
alt Hole punch SUCCESS
P->>H: direct UDP handshake (X25519, session token)
H-->>P: accepted + baseline snapshot
Note over P,H: Direct low-latency UDP session
else Hole punch FAIL (symmetric NAT)
P->>RL: connect via relay (encrypted)
RL->>H: forward (encrypted, opaque payload)
H-->>RL: accepted + baseline snapshot (encrypted)
RL-->>P: forward
Note over P,H: Relayed UDP session via RL (extra hop, end-to-end encrypted)
end
7.3 Host migration when a P2P host drops¶
sequenceDiagram
autonumber
participant P1 as Peer 1 (candidate)
participant P2 as Peer 2
participant H as Old host (dropping)
participant Di as lattice-director
Note over H: Host connection lost (crash / disconnect)
P1->>P1: detect host timeout (no snapshots)
P2->>P2: detect host timeout
P1->>Di: report host loss + last-known state digest
P2->>Di: report host loss + last-known state digest
Di->>Di: select new host (best connectivity / latency / last good tick)
Di-->>P1: you are new HOST (Role -> Authority)
Di-->>P2: new host = P1 {endpoint, refreshed session token}
P1->>P1: promote local replicated state to authoritative<br/>(reuse latest snapshot as baseline)
P2->>P1: reconnect (hole punch / relay fallback)
P1-->>P2: accepted + baseline snapshot (resync)
Di->>Di: update session directory (new host)
Note over P1,P2: Session resumes — same shared sim, new authority
State handoff relies on every peer keeping a recent snapshot buffer (the same buffer used for interpolation), so the promoted host already holds a near-current world state to use as the authoritative baseline. Reconnection reuses the §7.2 direct/relay logic.
8. High-level replication & tick flow¶
The in-session loop is the same shape for dedicated and P2P-host authority — only who holds Role=Authority changes.
flowchart LR
subgraph ClientIn["Client (predicted)"]
IN["Sample input @60 Hz"]
PRED["Predict locally (apply input)"]
SND["Send input (reliable-seq)"]
end
subgraph Authority["Authority (server / host) @60 Hz"]
RCV["Receive + buffer inputs"]
SIM["Authoritative sim tick"]
IM["Interest management (per-client view)"]
SNAP["Build delta snapshot @20-30 Hz"]
end
subgraph ClientOut["Client (recv)"]
RECON["Reconcile owned objects (rollback + replay)"]
INTERP["Interpolate remote objects (~100 ms buffer)"]
EXTRA["Extrapolate / dead reckoning (distributed-authority objects)"]
RENDER["Render"]
end
IN --> PRED --> SND --> RCV
RCV --> SIM --> IM --> SNAP
SNAP --> RECON
SNAP --> INTERP
SNAP --> EXTRA
RECON --> RENDER
INTERP --> RENDER
EXTRA --> RENDER
In prose:
- Input: clients sample input at the sim tick rate (60 Hz) and send it on a reliable-sequenced channel; locally they predict immediately.
- Authority sim: the authority buffers inputs and advances the deterministic sim at 60 Hz, running lag compensation for authoritative hit resolution.
- Interest management: per-client relevant sets are computed so each client only receives what it can perceive (bandwidth + anti-cheat).
- Snapshot: delta-compressed snapshots are emitted at 20–30 Hz (against ~1200 B MTU payload, fragmented as needed).
- Client reconcile/interp: owned objects reconcile via rollback + replay of un-acked inputs; remote objects interpolate from a ~100 ms buffer; distributed-authority objects extrapolate via dead reckoning toward their estimated destination.
Channel semantics (Unreliable / Unreliable-Sequenced / Reliable-Unordered / Reliable-Ordered), delta/quantization, congestion control, fragmentation, and the rollback algorithm are specified in 02-netcode-lld.md.
9. Request lifecycle summary¶
Each user action maps to a defined set of services. Data-plane actions (anything per-tick) never touch the control plane.
| User action | Plane | Services involved | Transport | Notes |
|---|---|---|---|---|
| Sign in | Control | lattice-auth → PostgreSQL/Redis |
TLS :8443 | Returns Ed25519 auth token |
| View friends / presence | Control | lattice-social → PostgreSQL/Redis |
TLS/WSS :9443 | See 04-social-library.md |
| Create / accept party | Control | lattice-social (→ NATS) |
TLS/WSS :9443 | Party state cached in Redis |
| Quick match | Control | lattice-director (validates via lattice-auth) → Redis |
TLS :8444 | Enqueues ticket, allocates fleet slot |
| Create dedicated session | Control | lattice-director → fleet |
TLS :8444 | Allocates lattice-gameserver |
| Create P2P host session | Control + Data | lattice-director (register), STUN |
TLS + UDP :3478 | Host = Role=Authority |
| Join P2P session | Control + Data | lattice-director (discover), STUN, maybe lattice-relay |
TLS + UDP :3478/:7777 | Direct or relay fallback |
| Connect to game server | Data | lattice-gameserver (token validated via lattice-auth) |
UDP :27015+ | X25519 handshake |
| Send input / receive snapshot | Data | lattice-gameserver or P2P host |
UDP | Hot path; no control-plane calls |
| Authority/ownership transfer | Data | Authority + peers | UDP | Distributed-authority objects |
| Host migration | Control + Data | lattice-director, peers, STUN/relay |
TLS + UDP | New host promoted (§7.3) |
| Match end / report | Control | lattice-gameserver → lattice-director → PostgreSQL |
TLS/event | Results, stats, fleet drain |
| Sign out | Control | lattice-auth, lattice-social |
TLS | Invalidate session, set offline |
10. Assumptions & invariants for sibling docs¶
These are HLD-level commitments other documents should honor:
- Parameters are fixed defaults across the suite: sim tick 60 Hz, snapshot 20–30 Hz, interp buffer ~100 ms, MTU payload ~1200 B, channels = Unreliable / Unreliable-Sequenced / Reliable-Unordered / Reliable-Ordered.
- Crypto: session encryption X25519 + ChaCha20-Poly1305; tokens Ed25519. Auth issues auth tokens; Director mints per-session tokens; game servers/hosts validate them.
- Ports: auth 8443, social 9443, director 8444, relay UDP 7777, game UDP 27015+, STUN 3478.
- Role/Topology is runtime-injected; there is exactly one shared simulation build.
02and05must not introduce a separate "server-only" sim build. - Authority is per-object; both authority models share one transport/snapshot/interest stack.
02owns the conflict-resolution and rollback specifics. - Control plane is stateless; all durable state in PostgreSQL/Redis (optional NATS).
03/04should not introduce node-local session state. - Relay is a blind forwarder — never plaintext, never sim. Anti-cheat reasoning in other docs must assume relayed traffic is opaque to the relay.
End of 01-high-level-design.md. Continue to 02-netcode-lld.md.