OpenTTD Source  20240917-master-g9ab0a47812
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 
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 
56 void Randomizer::SetSeed(uint32_t seed)
57 {
58  this->state[0] = seed;
59  this->state[1] = seed;
60 }
61 
66 void SetRandomSeed(uint32_t seed)
67 {
68  _random.SetSeed(seed);
69  _interactive_random.SetSeed(seed * 0x1234567);
70 }
71 
72 #ifdef RANDOM_DEBUG
73 uint32_t Random(const std::source_location location)
74 {
75  if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) {
76  Debug(random, 0, "{:08x}; {:02x}; {:04x}; {:02x}; {}:{}", TimerGameEconomy::date, TimerGameEconomy::date_fract, _frame_counter, (uint8_t)_current_company, location.file_name(), location.line());
77  }
78 
79  return _random.Next();
80 }
81 #endif /* RANDOM_DEBUG */
82 
95 void RandomBytesWithFallback(std::span<uint8_t> buf)
96 {
97 #if defined(_WIN32)
98  auto res = BCryptGenRandom(nullptr, static_cast<PUCHAR>(buf.data()), static_cast<ULONG>(buf.size()), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
99  if (res >= 0) return;
100 #elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
101  arc4random_buf(buf.data(), buf.size());
102  return;
103 #elif defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))
104  auto res = getrandom(buf.data(), buf.size(), 0);
105  if (res > 0 && static_cast<size_t>(res) == buf.size()) return;
106 #elif defined(__EMSCRIPTEN__)
107  auto res = EM_ASM_INT({
108  var buf = $0;
109  var bytes = $1;
110 
111  var crypto = window.crypto;
112  if (crypto === undefined || crypto.getRandomValues === undefined) {
113  return -1;
114  }
115 
116  crypto.getRandomValues(Module.HEAPU8.subarray(buf, buf + bytes));
117  return 1;
118  }, buf.data(), buf.size());
119  if (res > 0) return;
120 #else
121 # warning "No cryptographically-strong random generator available; using a fallback instead"
122 #endif
123 
124  static bool warned_once = false;
125  Debug(misc, warned_once ? 1 : 0, "Cryptographically-strong random generator unavailable; using fallback");
126  warned_once = true;
127 
128  for (uint i = 0; i < buf.size(); i++) {
129  buf[i] = static_cast<uint8_t>(InteractiveRandom());
130  }
131 }
_network_server
bool _network_server
network-server is active
Definition: network.cpp:66
_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:56
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:66
_networking
bool _networking
are we in networking mode?
Definition: network.cpp:65
RandomBytesWithFallback
void RandomBytesWithFallback(std::span< uint8_t > buf)
Fill the given buffer with random bytes.
Definition: random_func.cpp:95
_current_company
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Randomizer
Structure to encapsulate the pseudo random number generators.
Definition: random_func.hpp:27
_frame_counter
uint32_t _frame_counter
The current frame.
Definition: network.cpp:78
random_func.hpp
Randomizer::state
uint32_t state[2]
The state of the randomizer.
Definition: random_func.hpp:29
TimerGameEconomy::date
static Date date
Current date in days (day counter).
Definition: timer_game_economy.h:37