OpenTTD Source  14.0-beta3
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 
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