Skip to content

feat(network): Control arrival cushion and starting runahead, and start the match in sync - #664

Open
tintinhamans wants to merge 25 commits into
GeneralsOnlineDevelopmentTeam:mainfrom
tintinhamans:arctic/go/stack2/09-runahead-controller
Open

tintinhamans wants to merge 25 commits into
GeneralsOnlineDevelopmentTeam:mainfrom
tintinhamans:arctic/go/stack2/09-runahead-controller

Conversation

@tintinhamans

@tintinhamans tintinhamans commented Oct 25, 2026 •

Copy link
Copy Markdown

Merge after #663.

A latency formula sizes the run ahead from a round trip, but what stalls the game is whether the commands of the slowest sender arrive before the frame that needs them. The formula also has to guess a start value, and after a loss burst it kept the run ahead high for a long time.

With input_delay.controller (true) the run ahead follows the arrival cushion instead. Every player reports its lowest cushion per sender with its late commands and stall time, and the packet router sums the two directions of each pair and keeps input_delay.margin_frames (1) spare per direction. A baseline from a forgetting quantile of the normal windows is raised only for spikes that recur. With input_delay.fast_recovery (true) the run ahead falls a third of the excess per step after an isolated spike. input_delay.max_frames (64, retail 128) caps it. A slow producer is left out, an outage holds the run ahead, screenshot capture stalls do not count, and without a complete pair the formula of the previous PR takes over. At match start the router decides the run ahead from every player's lobby round trip, and the load waits for it. The lobby popup also shows the expected input delay.

The match start is synchronized on the new NETWORK_CHANNEL_START. Players send READY at two sync points: on the load screen once loading is done (waiting up to 3 s for the direct path), and after local setup with the load screen still up. The router answers with GO and a per-peer delay from the seed latency (at most 250 ms), each stage times out after 10 s, players that were lost are left out, and it is online only. The stock fade-in from black advances only on logic frames, so a start stall showed a black screen.

Wire change: the run ahead metrics message carries the cushion, late count, stall ms and screenshot flag, and the start channel is new. Trade-off: the controller returns to a low run ahead quickly when loss ends, which costs more stall time if loss returns. In the returning-loss rig run the old code stayed at R 56 to 64 and this went back to about 7, but stalled about 30 s of 110 s against 18.7 s. The synchronized start costs about 60 to 80 ms per stage, and relay-only players add up to 3 s. controller and fast_recovery are on by default as in the tester build, and the service can turn them off.

Tested: builds x86 Release z_generals. Rig runs of the full stack, 3 players, 0 CRC mismatches, n=1. On a slow CPU-bound host R stayed at 4 to 5 instead of hitting the old 64 cap. Start sync rig: frame-1 skew went from 1.5 to 2 s down to 6 to 15 ms, no start stalls, the fade takes 0.6 s on both.

xezon added 7 commits October 24, 2026 23:10
…ile::getFileInfo(), StdBIGFile::getFileInfo() (TheSuperHackers#3415)

(cherry picked from commit b805c12)
…File (TheSuperHackers#3505)

Both classes are identical apart from their name and contain no platform specific code.
Nothing in them depends on the BIG format either: they open a file from an offset and a
size inside the archive file. ArchiveFile takes over their functions and is no longer an
abstract class.

(cherry picked from commit 52a777a)
…ystem into BIGFileSystem (TheSuperHackers#3505)

Both classes are identical apart from their name and go through the local file system
for all file access. The one class that remains sits next to ArchiveFileSystem in
Core/GameEngine.

(cherry picked from commit e4b4d1e)
…e loadBigFilesFromDirectory (TheSuperHackers#3505)

loadMods refers to BIG files, which nothing else in ArchiveFileSystem does. It becomes a
virtual function that BIGFileSystem implements. loadBigFilesFromDirectory is renamed to
loadArchiveFilesFromDirectory, because the base class is not tied to one archive format.

(cherry picked from commit f299561)
@tintinhamans
tintinhamans force-pushed the arctic/go/stack2/09-runahead-controller branch from a3681d2 to e3feda5 Compare October 25, 2026 11:15
@tintinhamans tintinhamans changed the title feat(network): Control arrival cushion and starting runahead feat(network): Control arrival cushion and starting runahead, and start the match in sync Oct 25, 2026
@tintinhamans
tintinhamans force-pushed the arctic/go/stack2/09-runahead-controller branch from e3feda5 to 4c5132e Compare October 25, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants