QW-Group / mvdsv

MVDSV: a QuakeWorld server
GNU General Public License v2.0
59 stars 56 forks source link

replace rng seed generation #141

Closed phylter-qw closed 3 months ago

phylter-qw commented 4 months ago

Motivation

Duelers were alarmed by an apparent lack of randomness in starting spawns.

Some kind of seeding problem was suspected.

Investigation

phylter and Zorak discovered the following:

Sys_DoubleTime returns approximate seconds since MVDSV launch.

RNG is seeded with randomSeed = (int)(Sys_DoubleTime() * 100000).

Maximum value randomSeed can hold is 2147483647.

(int)(Sys_DoubleTime() * 100000) exceeds 2147483647 in just under 6 hours, after which the value stops increasing (or potentially behaves in an undefined way).

The code in question was introduced in 2021 (commit 837bdfcbd5bd061b6f34fec1737bfcfc3d7e58f2).

On affected servers, after 6 hours of uptime, it is possible to lock the starting spawns entirely by minimizing player activity (which can trigger RNG calls) during pre-war.

Solution

Seed the RNG directly with elapsed seconds since epoch.

Replace

(int)(Sys_DoubleTime() * 100000)

with

(int)time(NULL)

This provides a source of unique seeds for a very long time.

Notes

There is some concern that epoch functions might behave badly in the year 2038 on some old 32-bit machines... the so-called "2038 problem".

We figure such systems, already in the extreme minority, will face much bigger problems than running quakeworld.

Most MVDSV instances are already 64-bit, and are therefore unaffected.

There is a non-epoch alternative worthy of mention (suggested by foobar):

Replace

(int)(Sys_DoubleTime() * 100000)

with something like

double t = Sys_DoubleTime();
randomSeed = *(int*)&t;

This is elegant but cannot make any guarantees about seeds being unique. Presumably the repeats would be far apart.

ciscon commented 4 months ago

it should probably be mentioned that we can also introduce more entropy into the seed in ktx's g_seed_random function, as of now we're just using this data and turning it into something large enough for what is expected, but nothing is stopping us from using other sources as well when we actually do the seeding.

VVD commented 4 months ago

This is related to issue #141

https://github.com/QW-Group/mvdsv/issues/140

ciscon commented 4 months ago

This is related to issue #141

140

thanks, it autocompleted while i was typing it and i thought it knew better than i, heh.

krizej commented 4 months ago
double t = Sys_DoubleTime();
randomSeed = *(int*)&t;

This is elegant but cannot make any guarantees about seeds being unique. Presumably the repeats would be far apart.

it's also undefined behavior afaik