OpenTTD Source: src/core/random_func.cpp Source File

OpenTTD Source 14.0-beta1

random_func.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10 #include "../stdafx.h"
11 #include "random_func.hpp"
12 #include "bitmath_func.hpp"
13 #include "../debug.h"
14
15 #ifdef RANDOM_DEBUG
16 #include "../network/network.h"
17 #include "../network/network_server.h"
18 #include "../network/network_internal.h"
19 #include "../company_func.h"
20 #include "../fileio_func.h"
21 #include "../timer/timer_game_calendar.h"
22 #endif /* RANDOM_DEBUG */
23
24 #if defined(_WIN32)
25 # include <windows.h>
26 # include <bcrypt.h>
27 #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
28 // No includes required.
29 #elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
30 # include <sys/random.h>
31 #elif defined(__EMSCRIPTEN__)
32 # include <emscripten.h>
33 #endif
34
35 #include "../safeguards.h"
36
37 Randomizer _random, _interactive_random;
38
43 uint32_t Randomizer::Next()
44 {
45 const uint32_t s = this->state[0];
46 const uint32_t t = this->state[1];
47
48 this->state[0] = s + std::rotr(t ^ 0x1234567F, 7) + 1;
49 return this->state[1] = std::rotr(s, 3) - 1;
50 }
51
58 uint32_t Randomizer::Next(uint32_t limit)
59 {
60 return ((uint64_t)this->Next() * (uint64_t)limit) >> 32;
61 }
62
67 void Randomizer::SetSeed(uint32_t seed)
68 {
69 this->state[0] = seed;
70 this->state[1] = seed;
71 }
72
77 void SetRandomSeed(uint32_t seed)
78 {
79 _random.SetSeed(seed);
80 _interactive_random.SetSeed(seed * 0x1234567);
81 }
82
83 #ifdef RANDOM_DEBUG
84 uint32_t DoRandom(int line, const char *file)
85 {
86 if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) {
87 Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, (byte)_current_company, file, line);
88 }
89
90 return _random.Next();
91 }
92
93 uint32_t DoRandomRange(uint32_t limit, int line, const char *file)
94 {
95 return ((uint64_t)DoRandom(line, file) * (uint64_t)limit) >> 32;
96 }
97 #endif /* RANDOM_DEBUG */
98
111 void RandomBytesWithFallback(std::span<uint8_t> buf)
112 {
113 #if defined(_WIN32)
114 auto res = BCryptGenRandom(nullptr, static_cast<PUCHAR>(buf.data()), static_cast<ULONG>(buf.size()), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
115 if (res >= 0) return;
116 #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
117 arc4random_buf(buf.data(), buf.size());
118 return;
119 #elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
120 auto res = getrandom(buf.data(), buf.size(), 0);
121 if (res > 0 && static_cast<size_t>(res) == buf.size()) return;
122 #elif defined(__EMSCRIPTEN__)
123 auto res = EM_ASM_INT({
124 var buf = $0;
125 var bytes = $1;
126
127 var crypto = window.crypto;
128 if (crypto === undefined || crypto.getRandomValues === undefined) {
129 return -1;
130 }
131
132 crypto.getRandomValues(Module.HEAPU8.subarray(buf, buf + bytes));
133 return 1;
134 }, buf.data(), buf.size());
135 if (res > 0) return;
136 #else
137 # warning "No cryptographically-strong random generator available; using a fallback instead"
138 #endif
139
140 static bool warned_once = false;
141 Debug(misc, warned_once ? 1 : 0, "Cryptographically-strong random generator unavailable; using fallback");
142 warned_once = true;
143
144 for (uint i = 0; i < buf.size(); i++) {
145 buf[i] = static_cast<uint8_t>(InteractiveRandom());
146 }
147 }
_network_server
bool _network_server
network-server is active
Definition: network.cpp:60
_random
Randomizer _random
Random used in the game state calculations.
Definition: random_func.cpp:37
TimerGameEconomy::date_fract
static DateFract date_fract
Fractional part of the day.
Definition: timer_game_economy.h:38
Debug
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
_interactive_random
Randomizer _interactive_random
Random used everywhere else, where it does not (directly) influence the game state.
Definition: random_func.cpp:37
bitmath_func.hpp
Randomizer::SetSeed
void SetSeed(uint32_t seed)
(Re)set the state of the random number generator.
Definition: random_func.cpp:67
Randomizer::Next
uint32_t Next()
Generate the next pseudo random number.
Definition: random_func.cpp:43
SetRandomSeed
void SetRandomSeed(uint32_t seed)
(Re)set the state of the random number generators.
Definition: random_func.cpp:77
_networking
bool _networking
are we in networking mode?
Definition: network.cpp:59
RandomBytesWithFallback
void RandomBytesWithFallback(std::span< uint8_t > buf)
Fill the given buffer with random bytes.
Definition: random_func.cpp:111
_current_company
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:50
Randomizer
Structure to encapsulate the pseudo random number generators.
Definition: random_func.hpp:21
_frame_counter
uint32_t _frame_counter
The current frame.
Definition: network.cpp:73
random_func.hpp
Randomizer::state
uint32_t state[2]
The state of the randomizer.
Definition: random_func.hpp:23
TimerGameEconomy::date
static Date date
Current date in days (day counter).
Definition: timer_game_economy.h:37