Skip to content

Make seeded runs reproducible across the RNG families the simulation uses - #7893

Open
BTawaifi wants to merge 1 commit into
scp-fs2open:masterfrom
BTawaifi:feature/seeded-rng
Open

BTawaifi wants to merge 1 commit into
scp-fs2open:masterfrom
BTawaifi:feature/seeded-rng

Conversation

@BTawaifi

Copy link
Copy Markdown

Split out of #7874.

-seed only seeded the main RNG. The generator that RandomRange instances draw their seeds from was seeded from std::random_device, and the ship firepoint, asteroid-split and random-message-sender shuffles each created a fresh std::random_device, so two runs with the same seed could diverge from the first frame.

  • Random::seed_ranges() seeds the generator RandomRange instances take their seeds from; game_init() calls it, with the main RNG, before the tables are parsed when -seed is given.
  • Random::shuffle_seed() gives each std::shuffle its seed: a draw from the main RNG under -seed, OS entropy otherwise. The three std::random_device sites use it.

Without -seed nothing changes: the main RNG is seeded from the time as before, and the shuffles still use OS entropy.

Multiplayer seeds the main RNG from the netgame and ignores -seed, so the shuffles keep using OS entropy there and the shared sequence is not consumed differently on one machine.

Known limit: RandomRange instances are seeded once, when they are created (mostly while the tables are parsed), so a mission restarted in the same process does not repeat their draws. Reproducible runs need one process per run. Making restarts repeat would need every instance reseeded, which is a separate change.

Testing: headless runs of a retail mission with seeds 77, 77, 78, 78 gave identical end states (positions, hull totals) for equal seeds and different ones for different seeds. Each changed file compiles on this branch alone; the combined branches build with FSO_FATAL_WARNINGS=ON on Windows (MSVC) and Linux (gcc-13, clang-16), and the unit tests pass.

…uses


-seed only seeded the main RNG. RandomRange instances (seeded from a separate
generator before tables parse) and the std::random_device shuffles of weapon
firepoints, asteroid splits and random-message senders stayed unseeded, so two
runs with the same seed could diverge from the first frame.

- Random::seed_ranges() seeds the generator that RandomRange instances draw from.
- game_init() seeds both families when -seed is given, before table parsing.
- Random::shuffle_seed() gives each std::shuffle its generator seed: a draw from
  the seeded main RNG under -seed, OS entropy otherwise (normal gameplay is
  unchanged). The ship firepoint, asteroid-split and message-sender shuffles use
  it instead of three separate std::random_device sites.

In multiplayer the main RNG is seeded from the netgame and -seed is ignored, so
the shuffles keep using OS entropy there and the shared sequence is unchanged.

RandomRange instances are seeded once, when they are created (mostly while the
tables are parsed), so a mission restarted in the same process does not repeat
their draws. Reproducible runs need one process per run.
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.

1 participant