Network Tuning Guide¶
Tune from measurements, not labels such as “Wi-Fi” or “mobile.” Input delay trades local response latency for fewer/deeper rollbacks; the prediction window trades short outage tolerance for more speculative work. Increasing either does not repair nondeterministic game logic.
Measured baseline¶
The 2–4 player rows below are from tests/simulation/baselines/sweep-v3.json, schema v3, measured
on base commit 94f33a8. The 16-player rows come from the prior schema's release-mode full
matrix at commit 991559c (5,000 steps, seed 1). Sessions are configured for 60 FPS; the harness
advances once every 16 ms, providing 62.5 update opportunities per virtual second. Runs use input
delay 0, max prediction 8, and deterministic virtual time. Encoded payload demand is measured when
Fortress enqueues messages and excludes IP/UDP headers; it is not observed transport throughput.
Schema v3 also records protocol messages enqueued for eventual socket submission per player per
second. The clean two-player row is 135.8125, including one-time synchronization traffic.
| Players / path | Loss / RTT / jitter | Input | Rollbacks / 100 frames | Rollback p99 | Encoded KiB/s/player | Mean / max confirmation lag | Stalls/min |
|---|---|---|---|---|---|---|---|
| 2 / LAN | 0% / 10 ms / 0 ms | 4 B | 0.10 | 1 | 4.73 | 1.00 / 2 | 0 |
| 2 / Wi-Fi | 1% / 50 ms / 20 ms | 4 B | 66.65 | 4 | 5.24 | 2.62 / 8 | 0 |
| 2 / mobile | 5% / 100 ms / 20 ms | 4 B | 71.06 | 7 | 5.86 | 4.33 / 8 | 15 |
| 4 / Wi-Fi | 1% / 50 ms / 20 ms | 4 B | 97.23 | 4 | 17.78 | 6.12 / 8 | 69.38 |
| 4 / severe | 15% / 200 ms / 20 ms | 4 B | 119.51 | 6 | 6.95 | 6.69 / 8 | 2,064.38 |
| 16 / regional | 1% / 100 ms / 20 ms | 4 B | 144.91 | 4 | 117.09 | 7.39 / 8 | 1,218.42 |
The 32-byte input rows preserve the same rollback and lag results but cost 8.05, 13.45, 19.73, 41.90, 17.79, and 220.10 KiB/s/player respectively. The N=16 row remained at zero desyncs and confirmed through frame 3,292, but its stalls and encoded demand are a capacity warning, not a general endorsement of 16-player full mesh. Keep network inputs fixed-width and as small as the game permits.
Starting configurations¶
These are operational starting points from the user-guide presets, not claims measured by the baseline above. Re-run the sweep with your input width and game-state cost before shipping them.
| Measured condition | Input delay | Max prediction | Starting preset | Expected baseline behavior |
|---|---|---|---|---|
| Stable LAN, RTT under 20 ms | 0–1 | 4–6 | SyncConfig::lan() |
Near-zero rollback load; confirmation about 1–2 frames behind |
| Typical Wi-Fi, RTT around 50 ms and ~1% loss | 2 | 8 | defaults / TimeSyncConfig::smooth() |
Rollback p99 around 4 in the zero-delay baseline |
| Mobile, RTT around 100 ms and ~5% loss | 3 | 12–15 | SyncConfig::lossy() |
Baseline reaches the prediction limit and begins stalling |
| Four-player mixed Wi-Fi | 3 | 12 | defaults / TimeSyncConfig::smooth() |
Slowest link dominates; watch per-peer queues and lag |
| Transparent relay fallback, +20–80 ms additional RTT | Re-measure | Re-measure | Start from the direct-path preset, then tune against total RTT | Research-derived sensitivity range, not a measured Fortress baseline; include relayed sessions in qualification |
| Sustained 15% loss / 200 ms RTT | Do not silently accept | N/A | matchmaking warning or alternate topology | Default baseline spends much of the run stalled |
The relay fallback row models a transport transparently relaying the same peer-to-peer datagrams; it is not the future server-star input topology. Its latency range is a research-derived sensitivity assumption. Measure the direct and relayed populations separately and select input delay and prediction windows from the relayed path's observed total RTT and receipt-gap tail.
Frame-advantage measurement limits¶
Each endpoint estimates the remote frame by aging the last received frame with RTT/2. That
assumes symmetric one-way delay: a ping-pong exchange cannot identify how the RTT divides between
directions. Smoothing reduces short-term jitter, but it cannot remove a persistent asymmetric-path
bias. This RTT/2 packet-age estimate is separate from the controller's later division by two,
which damps the two-sided frame-advantage signal.
The bounded H-ASYM experiment compared constant 10 ms / 200 ms one-way delays against a matched
105 ms / 105 ms control at equal 210 ms RTT (N=2, 900 steps). The asymmetric run ended seven
visual frames apart and recorded stalls of 18 versus 11, but produced zero WaitRecommendation
events or obeyed skips; endpoint gauges stayed in [-1, +1], below the three-frame dead band.
That row demonstrates transport/prediction asymmetry without the hypothesized chronic pacing
correction. Jitter, N>2, and other asymmetry ratios remain outside that result, so qualify them
separately instead of treating timestamp-based one-way estimation as implemented.
Measurement loop¶
- Record RTT, loss bursts, jitter, player count, serialized input width, and simulation cost.
- Start with the smallest input delay users tolerate and a prediction window covering the p99 receipt gap.
- Compare
rollback_count, the depth histogram,resimulated_frames,stall_count, confirmation lag,pending_output_len, exact bytes and packets per second, plus the adapter's downstream service rate, queue depth, and oldest-message age. - Raise input delay when rollback work is the problem. Raise max prediction only when short gaps stall an otherwise healthy session and the game can afford the extra speculative work.
- Test the same configuration at N=2 and the max supported player count. Full-mesh traffic and confirmation work grow with peer count.
- Bless a new ledger only after explaining every material change.
WaitRecommendation is a runtime correction signal, not a replacement for tuning. Continue
network polling while obeying it so slowing simulation does not also delay packet processing.