diff --git a/include/helpers.hpp b/include/helpers.hpp index f806c232..b899b7f8 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -164,6 +164,7 @@ bool IsEntityVisiblePenetration(CachedEntity *entity, int hb); // void EndPrediction(); float RandFloatRange(float min, float max); +int UniformRandomInt(int min, int max); bool Developer(CachedEntity *ent); diff --git a/src/hack.cpp b/src/hack.cpp index 7ac340ac..322020b4 100644 --- a/src/hack.cpp +++ b/src/hack.cpp @@ -143,6 +143,22 @@ void critical_error_handler(int signum) ::raise(SIGABRT); } +static void InitRandom() +{ + int rand_seed; + FILE *rnd = fopen("/dev/urandom", "rb"); + if (!rnd || fread(&rand_seed, sizeof(rand_seed), 1, rnd) < 1) + { + logging::Info("Warning!!! Failed read from /dev/urandom (%s). Randomness is going to be weak", strerror(errno)); + timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + rand_seed = t.tv_nsec ^ t.tv_sec & getpid(); + } + srand(rand_seed); + if (rnd) + fclose(rnd); +} + void hack::Initialize() { ::signal(SIGSEGV, &critical_error_handler); @@ -178,9 +194,8 @@ free(logname);*/ } #endif /* TEXTMODE */ - logging::Info("Initializing..."); - srand(time(0)); + InitRandom(); sharedobj::LoadAllSharedObjects(); CreateInterfaces(); CDumper dumper; diff --git a/src/helpers.cpp b/src/helpers.cpp index 0763d68f..17730d3d 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -801,6 +801,30 @@ float RandFloatRange(float min, float max) return (min + 1) + (((float) rand()) / (float) RAND_MAX) * (max - (min + 1)); } +int UniformRandomInt(int min, int max) +{ + uint32_t bound, len, r, result = 0; + /* Protect from random stupidity */ + if (min > max) + std::swap(min, max); + + len = max - min + 1; + /* RAND_MAX is implementation dependent. + * It's guaranteed that this value is at least 32767. + * glibc's RAND_MAX is 2^31 - 1 exactly. Since source games hard + * depend on glibc, we will do so as well + */ + while (len) + { + bound = (1U + RAND_MAX) % len; + while ((r = rand()) < bound); + result *= 1U + RAND_MAX; + result += r % len; + len -= len > RAND_MAX ? RAND_MAX : len; + } + return int(result) + min; +} + bool IsEntityVisible(CachedEntity *entity, int hb) { if (g_Settings.bInvalid)