mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 05:09:20 +02:00
Merge pull request #176 from MaSzyna-EU07/random-seed-entropy
Random seed entropy
This commit is contained in:
@@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "utilities/dictionary.h"
|
#include "utilities/dictionary.h"
|
||||||
#include "version_info.h"
|
#include "version_info.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <format>
|
||||||
#include "utilities/translation.h"
|
#include "utilities/translation.h"
|
||||||
|
|
||||||
#if WITH_DISCORD_RPC
|
#if WITH_DISCORD_RPC
|
||||||
@@ -320,9 +321,13 @@ int eu07_application::init(int Argc, char *Argv[])
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the run's seed, settled once and kept in Globals: the engines come out of it.
|
||||||
|
// narrowed on purpose - mt19937 and seed_of() both work on 32 bits, and that is
|
||||||
|
// the seed somebody can write down and pass on
|
||||||
if (!Global.random_seed)
|
if (!Global.random_seed)
|
||||||
Global.random_seed = std::random_device{}();
|
Global.random_seed = static_cast<std::uint32_t>(true_random_seed());
|
||||||
Global.random_engine.seed(Global.random_seed);
|
Global.random_engine.seed(Global.random_seed);
|
||||||
|
Global.local_random_engine.seed(Global.random_seed);
|
||||||
|
|
||||||
// configure the OS console according to Globals.ShowSystemConsole.
|
// configure the OS console according to Globals.ShowSystemConsole.
|
||||||
// must run AFTER init_settings (so the ini-loaded value is honoured) and
|
// must run AFTER init_settings (so the ini-loaded value is honoured) and
|
||||||
@@ -1140,10 +1145,21 @@ int eu07_application::init_settings(int Argc, char *Argv[])
|
|||||||
Global.local_start_vehicle = ToLower(Argv[++i]);
|
Global.local_start_vehicle = ToLower(Argv[++i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (token == "-seed")
|
||||||
|
{
|
||||||
|
// a number is the seed; anything else is a word that stands for one. said in the
|
||||||
|
// log as it was given, because that is what gets passed on to somebody else
|
||||||
|
if (i + 1 < Argc)
|
||||||
|
{
|
||||||
|
Global.random_seed = seed_of(Argv[++i]);
|
||||||
|
WriteLog(std::format("seed given on the command line: {} -> {}", Argv[i], Global.random_seed));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "usage: " << std::string(Argv[0]) << " [-s sceneryfilepath]"
|
std::cout << "usage: " << std::string(Argv[0]) << " [-s sceneryfilepath]"
|
||||||
<< " [-v vehiclename]" << std::endl;
|
<< " [-v vehiclename]"
|
||||||
|
<< " [-seed number|word]" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1421,7 +1437,7 @@ int eu07_application::init_data()
|
|||||||
|
|
||||||
int eu07_application::init_modes()
|
int eu07_application::init_modes()
|
||||||
{
|
{
|
||||||
Global.local_random_engine.seed(std::random_device{}());
|
Global.local_random_engine.seed(static_cast<std::mt19937::result_type>(true_random_seed()));
|
||||||
|
|
||||||
if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty())
|
if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -403,10 +403,9 @@ std::string *brush_object_list::GetRandomObject()
|
|||||||
if (Objects.empty())
|
if (Objects.empty())
|
||||||
return ∅
|
return ∅
|
||||||
|
|
||||||
static std::mt19937 rng{std::random_device{}()};
|
|
||||||
std::uniform_int_distribution<size_t> dist(0, Objects.size() - 1);
|
std::uniform_int_distribution<size_t> dist(0, Objects.size() - 1);
|
||||||
|
|
||||||
return &Objects[dist(rng)];
|
return &Objects[dist(Global.local_random_engine)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void brush_object_list::render()
|
void brush_object_list::render()
|
||||||
|
|||||||
@@ -726,7 +726,9 @@ bool global_settings::ConfigParseSimulation(cParser& Parser, const std::string&
|
|||||||
|
|
||||||
if (token == "randomseed")
|
if (token == "randomseed")
|
||||||
{
|
{
|
||||||
ParseOne(Parser, Global.random_seed, 1);
|
std::string text;
|
||||||
|
ParseOne(Parser, text);
|
||||||
|
Global.random_seed = seed_of(text);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Copyright (C) 2007-2014 Maciej Cierniak
|
|||||||
//
|
//
|
||||||
//#include <sys/types.h>
|
//#include <sys/types.h>
|
||||||
//#include <sys/stat.h>
|
//#include <sys/stat.h>
|
||||||
|
#include <charconv>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
//#ifndef WIN32
|
//#ifndef WIN32
|
||||||
//#include <unistd.h>
|
//#include <unistd.h>
|
||||||
@@ -28,9 +29,9 @@ Copyright (C) 2007-2014 Maciej Cierniak
|
|||||||
#include "utilities/Globals.h"
|
#include "utilities/Globals.h"
|
||||||
#include "utilities/parser.h"
|
#include "utilities/parser.h"
|
||||||
#include "utilities/U8.h"
|
#include "utilities/U8.h"
|
||||||
|
#include "utilities/Logs.h"
|
||||||
|
|
||||||
|
|
||||||
//#include "utilities/Logs.h"
|
|
||||||
|
|
||||||
// TODO: This shouldn't be in Globals?
|
// TODO: This shouldn't be in Globals?
|
||||||
bool DebugModeFlag = false;
|
bool DebugModeFlag = false;
|
||||||
@@ -137,15 +138,51 @@ int Random(int min, int max)
|
|||||||
return dist(Global.random_engine);
|
return dist(Global.random_engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint64_t true_random_seed()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
if (rd.entropy() > 0.0)
|
||||||
|
{
|
||||||
|
// NOTE: both halves have to be 64 bit wide before the shift - shifting a std::uint32_t
|
||||||
|
// by 32 is undefined behaviour, and drops the high half of the seed
|
||||||
|
std::uint64_t const high{rd()};
|
||||||
|
std::uint64_t const low{rd()};
|
||||||
|
return (high << 32) | low;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception const &Error)
|
||||||
|
{
|
||||||
|
// std::random_device throws when the machine has no usable hardware entropy source;
|
||||||
|
// the clock below stands in for it, which is worth saying out loud since it is a
|
||||||
|
// weaker seed than the caller asked for
|
||||||
|
WriteLog(std::format("random: no hardware entropy source ({}), seeding from the clock instead", Error.what()));
|
||||||
|
}
|
||||||
|
return static_cast<std::uint64_t>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t seed_of(std::string const &Text)
|
||||||
|
{
|
||||||
|
if (std::uint32_t number{}; std::from_chars(Text.data(), Text.data() + Text.size(), number).ec == std::errc{})
|
||||||
|
{
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
std::uint32_t hash{};
|
||||||
|
for (auto const character : Text)
|
||||||
|
{
|
||||||
|
hash = hash * 31u + static_cast<std::uint32_t>(static_cast<unsigned char>(character));
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
std::string generate_uuid_v4()
|
std::string generate_uuid_v4()
|
||||||
{
|
{
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 gen(rd());
|
|
||||||
std::uniform_int_distribution<int> dist(0, 255);
|
std::uniform_int_distribution<int> dist(0, 255);
|
||||||
|
|
||||||
std::array<uint8_t, 16> bytes;
|
std::array<uint8_t, 16> bytes;
|
||||||
for (auto &b : bytes)
|
for (auto &b : bytes)
|
||||||
b = static_cast<uint8_t>(dist(gen));
|
b = static_cast<uint8_t>(dist(Global.random_engine));
|
||||||
|
|
||||||
// UUID v4 (RFC 4122)
|
// UUID v4 (RFC 4122)
|
||||||
bytes[6] = bytes[6] & 0x0F | 0x40;
|
bytes[6] = bytes[6] & 0x0F | 0x40;
|
||||||
|
|||||||
@@ -62,6 +62,18 @@ inline long Round(double const f)
|
|||||||
|
|
||||||
double Random(double a, double b);
|
double Random(double a, double b);
|
||||||
int Random(int min, int max);
|
int Random(int min, int max);
|
||||||
|
|
||||||
|
/// @author lxvia
|
||||||
|
/// @brief Returns a random seed from the system's entropy source, if available. Otherwise, falls back to a clock-based seed.
|
||||||
|
/// @return A random seed as 64 bit unsigned integer
|
||||||
|
std::uint64_t true_random_seed();
|
||||||
|
|
||||||
|
// The seed a word stands for. A number is taken as it is written; anything else is
|
||||||
|
// hashed the way Java's String.hashCode does it, so the same word gives the same
|
||||||
|
// world on every platform and every build - which is the whole point of telling
|
||||||
|
// somebody a seed.
|
||||||
|
std::uint32_t seed_of(std::string const &Text);
|
||||||
|
|
||||||
std::string generate_uuid_v4();
|
std::string generate_uuid_v4();
|
||||||
double LocalRandom(double a, double b);
|
double LocalRandom(double a, double b);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "utilities/utilities.h"
|
||||||
|
#include "utilities/Globals.h"
|
||||||
|
|
||||||
class UID {
|
class UID {
|
||||||
public:
|
public:
|
||||||
@@ -13,10 +15,9 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
static UID random() {
|
static UID random() {
|
||||||
static thread_local std::mt19937_64 gen(std::random_device{}());
|
|
||||||
UID u;
|
UID u;
|
||||||
uint64_t a = gen();
|
uint64_t a = Global.random_engine();
|
||||||
uint64_t b = gen();
|
uint64_t b = Global.random_engine();
|
||||||
for (int i = 0; i < 8; ++i) u.bytes[i] = uint8_t(a >> (i * 8) & 0xFF);
|
for (int i = 0; i < 8; ++i) u.bytes[i] = uint8_t(a >> (i * 8) & 0xFF);
|
||||||
for (int i = 0; i < 8; ++i) u.bytes[8 + i] = uint8_t(b >> (i * 8) & 0xFF);
|
for (int i = 0; i < 8; ++i) u.bytes[8 + i] = uint8_t(b >> (i * 8) & 0xFF);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user