From 8e6f6c3be11563d4f87a15a48bc1ad567a67c7c1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sat, 29 Sep 2018 16:17:25 +0300 Subject: [PATCH] Port to MT19337 PRNG. Get rid of evil rand_byte(). Code still using rand() remains semi-broken until the following commit. --- inc/shared/shared.h | 19 ++++----------- src/baseq2/g_local.h | 4 +-- src/baseq2/g_main.c | 2 ++ src/common/common.c | 4 +-- src/server/init.c | 3 +-- src/server/main.c | 2 +- src/server/mvd/client.c | 3 +-- src/server/user.c | 4 +-- src/shared/shared.c | 54 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 70 insertions(+), 25 deletions(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 49ea3e9e1..a028c1390 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -320,18 +320,6 @@ static inline float anglemod(float a) return a; } -static inline int rand_byte(void) -{ - int r = rand(); - - int b1 = (r >> 24) & 255; - int b2 = (r >> 16) & 255; - int b3 = (r >> 8) & 255; - int b4 = (r) & 255; - - return b1 ^ b2 ^ b3 ^ b4; -} - static inline int Q_align(int value, int align) { int mod = value % align; @@ -348,6 +336,9 @@ static inline int Q_gcd(int a, int b) return a; } +void Q_srand(uint32_t seed); +uint32_t Q_rand(void); + #define clamp(a,b,c) ((a)<(b)?(a)=(b):(a)>(c)?(a)=(c):(a)) #define cclamp(a,b,c) ((b)>(c)?clamp(a,c,b):clamp(a,b,c)) @@ -359,8 +350,8 @@ static inline int Q_gcd(int a, int b) #define min(a,b) ((a)<(b)?(a):(b)) #endif -#define frand() ((rand() & 32767) * (1.0f / 32767)) -#define crand() ((rand() & 32767) * (2.0f / 32767) - 1) +#define frand() ((int32_t)Q_rand() * 0x1p-32f + 0.5f) +#define crand() ((int32_t)Q_rand() * 0x1p-31f) #define Q_rint(x) ((x) < 0 ? ((int)((x) - 0.5f)) : ((int)((x) + 0.5f))) diff --git a/src/baseq2/g_local.h b/src/baseq2/g_local.h index a70df8a64..309ea3328 100644 --- a/src/baseq2/g_local.h +++ b/src/baseq2/g_local.h @@ -501,8 +501,8 @@ extern edict_t *g_edicts; #define GLOFS(x) q_offsetof(game_locals_t, x) #define CLOFS(x) q_offsetof(gclient_t, x) -#define random() ((rand () & 0x7fff) / ((float)0x7fff)) -#define crandom() (2.0f * (random() - 0.5f)) +#define random() frand() +#define crandom() crand() extern cvar_t *maxentities; extern cvar_t *deathmatch; diff --git a/src/baseq2/g_main.c b/src/baseq2/g_main.c index ccb8d653f..a6fc04755 100644 --- a/src/baseq2/g_main.c +++ b/src/baseq2/g_main.c @@ -115,6 +115,8 @@ void InitGame(void) { gi.dprintf("==== InitGame ====\n"); + Q_srand(time(NULL)); + gun_x = gi.cvar("gun_x", "0", 0); gun_y = gi.cvar("gun_y", "0", 0); gun_z = gi.cvar("gun_z", "0", 0); diff --git a/src/common/common.c b/src/common/common.c index d151492e2..c282fb79f 100644 --- a/src/common/common.c +++ b/src/common/common.c @@ -665,7 +665,7 @@ size_t Com_UptimeLong_m(char *buffer, size_t size) static size_t Com_Random_m(char *buffer, size_t size) { - return Q_scnprintf(buffer, size, "%d", rand_byte() % 10); + return Q_scnprintf(buffer, size, "%d", Q_rand() % 10); } static size_t Com_MapList_m(char *buffer, size_t size) @@ -894,7 +894,7 @@ void Qcommon_Init(int argc, char **argv) Com_SetLastError(NULL); - srand(time(NULL)); + Q_srand(time(NULL)); // prepare enough of the subsystems to handle // cvar and command buffer management diff --git a/src/server/init.c b/src/server/init.c index c80d7b441..d87a0984c 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -172,8 +172,7 @@ void SV_SpawnServer(mapcmd_t *cmd) // wipe the entire per-level structure memset(&sv, 0, sizeof(sv)); - sv.spawncount = (rand() | ((unsigned)rand() << 16)) ^ Sys_Milliseconds(); - sv.spawncount &= 0x7FFFFFFF; + sv.spawncount = Q_rand() & 0x7fffffff; // set legacy spawncounts FOR_EACH_CLIENT(client) { diff --git a/src/server/main.c b/src/server/main.c index 87f690e1d..5185b7053 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -591,7 +591,7 @@ static void SVC_GetChallenge(void) } } - challenge = (((unsigned)rand() << 16) | rand()) & 0x7fffffff; + challenge = Q_rand() & 0x7fffffff; if (i == MAX_CHALLENGES) { // overwrite the oldest svs.challenges[oldest].challenge = challenge; diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index af49d811a..71348d24d 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -1641,8 +1641,7 @@ void MVD_Spawn(void) #endif // generate spawncount for Waiting Room - sv.spawncount = (rand() | ((unsigned)rand() << 16)) ^ Sys_Milliseconds(); - sv.spawncount &= 0x7FFFFFFF; + sv.spawncount = Q_rand() & 0x7fffffff; #if USE_FPS // just fixed base FPS diff --git a/src/server/user.c b/src/server/user.c index fb2e799c3..3cf2cd8e0 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -328,7 +328,7 @@ static void stuff_junk(void) for (i = 0; i < 8; i++) { for (j = 0; j < 15; j++) { - k = rand_byte() % (sizeof(junkchars) - 1); + k = Q_rand() % (sizeof(junkchars) - 1); junk[i][j] = junkchars[k]; } junk[i][15] = 0; @@ -339,7 +339,7 @@ static void stuff_junk(void) SV_ClientCommand(sv_client, "set %s set\n", junk[0]); SV_ClientCommand(sv_client, "$%s %s connect\n", junk[0], junk[1]); - if (rand_byte() & 1) { + if (Q_rand() & 1) { SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[2], junk[3]); SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[4], sv_force_reconnect->string); diff --git a/src/shared/shared.c b/src/shared/shared.c index 7d1ee3195..f10d6be8a 100644 --- a/src/shared/shared.c +++ b/src/shared/shared.c @@ -859,6 +859,60 @@ void Q_setenv(const char *name, const char *value) #endif // !_WIN32 } +/* +===================================================================== + + MT19337 PRNG + +===================================================================== +*/ + +#define N 624 +#define M 397 + +static uint32_t mt_state[N]; +static uint32_t mt_index; + +void Q_srand(uint32_t seed) +{ + mt_index = N; + mt_state[0] = seed; + for (int i = 1; i < N; i++) + mt_state[i] = seed = 1812433253U * (seed ^ seed >> 30) + i; +} + +uint32_t Q_rand(void) +{ + uint32_t x, y; + int i; + + if (mt_index >= N) { + mt_index = 0; + +#define STEP(j, k) do { \ + x = mt_state[i] & (1U << 31); \ + x += mt_state[j] & ((1U << 31) - 1); \ + y = x >> 1; \ + y ^= 0x9908B0DF & -(x & 1); \ + mt_state[i] = mt_state[k] ^ y; \ + } while (0) + + for (i = 0; i < N - M; i++) + STEP(i + 1, i + M); + for ( ; i < N - 1; i++) + STEP(i + 1, i - N + M); + STEP(0, M - 1); + } + + y = mt_state[mt_index++]; + y ^= y >> 11; + y ^= y << 7 & 0x9D2C5680; + y ^= y << 15 & 0xEFC60000; + y ^= y >> 18; + + return y; +} + /* =====================================================================