DevLog #5 How I Built RiftNet & the SyncServer (No Illusions, Only Signal)

Premise: build the transport I can trust. No outsourced truth, no visual band-aids. Compress, encrypt, acknowledge; then ship the bytes the server actually simulated.

🧱 Architecture in One Pass

  • Raw sockets → Channel → Reliability → Compressor → Packer
  • Channel: X25519 key exchange. Payloads stay blocked until keys are derived. Compress then encrypt.
  • AEAD: pluggable; AES‑GCM by default via libsodium.
  • Reliability: custom reliable UDP with seq/ack, sliding window, dedupe.
  • Timing: RFC‑6298 RTT estimator (srtt, rttvar, rto) driving retransmits.
  • Diagnostics: log every window: inputs, snapshot_ms, dispatch_ms, baseline/delta counts.

🔐 Handshake & Keys

  • Client/Server exchange ephemeral X25519 pubkeys.
  • Derive sharedTx/sharedRx keys. Until that’s set, any reliable/encrypted message is rejected.
  • All pre-secure payloads (e.g., HELLO) live on a tiny side queue then drain post‑init.

📦 Packet Layout & Order of Operations

  1. Serialize minimal header (flags | seq | ack | ackBits | nonce).
  2. Pack delta payload(s) against the active baseline.
  3. Run LZ4 on the payload segment.
  4. Seal with AEAD (AES‑GCM) using the channel’s nonce discipline.
  5. Send via UDP. Receiver verifies, inflates, applies, acks.

🕒 The Loop (SyncServer)

  1. Ingest inputs for tick T.
  2. Advance simulation (authoritative).
  3. Produce snapshot: baseline (periodic) + delta (per‑tick).
  4. Dispatch to clients; update reliability state.

Target cadence: 200 Hz (DT_US = 5000).

🧮 Determinism Guard

For every received frame, compute a canonical FNV‑1a hash on serialized entity fields after sorting IDs. Any divergence trips alarms in test—no “close enough.”

🧵 Concurrency Notes

  • Encryption/compression run on a worker path; hot structures are std::atomic guarded; minimal mutex spans.
  • Per‑client send rings to avoid cross‑talk; preallocated buffers to keep the allocator cold.
  • Back‑pressure when a client falls behind; reliability takes precedence over stuffing more deltas.

📊 What the Numbers Said

  • Snapshot build: ~2–3 ms @ modest entity counts.
  • Dispatch: < 0.5 ms per window.
  • Frame size: ~26–94 bytes depending on movement/delta density.
  • Scale: 50 → 500 → 5,000 connection soak (local env) without reliability collapse.

🌐 Beyond One Box

Spec’d a GlobalShardSyncServer to gossip shard truths. Implementation lands after zones/spawns, once there’s something worth gossiping.

Why It’s Built This Way

  • Truth first: server is the source of truth; clients draw what the server simulates.
  • No illusions: no hidden TCP, no jitter make‑up stories. Reliable UDP, explicit.
  • Security native: crypto/compression aren’t add‑ons; they’re in the pipeline.

RiftForged™ is a trademark of RiftForged Development Corp. © 2025 RiftForged Development Corp.