Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions code/asteroid/asteroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "ship/shipfx.h"
#include "ship/shiphit.h"
#include "stats/scoring.h"
#include "utils/Random.h"
#include "weapon/weapon.h"

#include <algorithm>
Expand Down Expand Up @@ -1900,8 +1901,8 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
roids_to_create.push_back(split->asteroid_type);
}

std::random_device rd;
std::shuffle(roids_to_create.begin(), roids_to_create.end(), std::mt19937(rd()));
std::mt19937 shuffle_rng(util::Random::shuffle_seed());
std::shuffle(roids_to_create.begin(), roids_to_create.end(), shuffle_rng);

size_t total_roids = roids_to_create.size();
for (size_t i = 0; i < total_roids; i++) {
Expand Down
4 changes: 2 additions & 2 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15506,8 +15506,8 @@ void sexp_send_builtin_message(int n) {
}

if (shuffle) {
std::random_device rd;
std::shuffle(sender_names.begin(), sender_names.end(), std::mt19937(rd()));
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(sender_names.begin(), sender_names.end(), rng);
}

auto subject = have_subject ? subject_entry->shipp() : nullptr;
Expand Down
28 changes: 14 additions & 14 deletions code/ship/ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11158,8 +11158,8 @@ static void ship_set_default_weapons(ship *shipp, ship_info *sip)
for (int fp = 0; fp < pm->gun_banks[i].num_slots; fp++) {
fpi.push_back(fp);
}
std::random_device rd;
std::shuffle(fpi.begin(), fpi.end(), std::mt19937(rd()));
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(fpi.begin(), fpi.end(), rng);
}

swp->num_secondary_banks = sip->num_secondary_banks;
Expand Down Expand Up @@ -11745,8 +11745,8 @@ static void ship_model_change(int n, int ship_type)
for (int fp = 0; fp < pm->gun_banks[bank_i].num_slots; fp++) {
fpi.push_back(fp);
}
std::random_device rd;
std::shuffle(fpi.begin(), fpi.end(), std::mt19937(rd()));
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(fpi.begin(), fpi.end(), rng);
}

model_delete_instance(sp->model_instance_num);
Expand Down Expand Up @@ -13496,8 +13496,8 @@ int ship_fire_primary(object * obj, int force, bool rollback_shot)
for (int fp = 0; fp < num_slots; fp++) {
fpi.push_back(fp);
}
std::random_device rd;
std::shuffle(fpi.begin(), fpi.end(), std::mt19937(rd()));
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(fpi.begin(), fpi.end(), rng);
}

// The energy-consumption code executes even for ballistic primaries, because
Expand Down Expand Up @@ -13783,26 +13783,26 @@ int ship_fire_primary(object * obj, int force, bool rollback_shot)
switch (firing_pattern) {
case FiringPattern::RANDOM_EXHAUSTIVE: {
if (num_slots < (swp->primary_firepoint_next_to_fire_index[bank_to_fire] + point_count)) {
std::random_device rd;
std::shuffle(&swp->primary_firepoint_indices[bank_to_fire][0], &swp->primary_firepoint_indices[bank_to_fire][swp->primary_firepoint_next_to_fire_index[bank_to_fire]-1], std::mt19937(rd())); //NOLINT
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(&swp->primary_firepoint_indices[bank_to_fire][0], &swp->primary_firepoint_indices[bank_to_fire][swp->primary_firepoint_next_to_fire_index[bank_to_fire]-1], rng); //NOLINT
} else if (swp->primary_firepoint_next_to_fire_index[bank_to_fire] < point_count) {
std::random_device rd;
std::shuffle(swp->primary_firepoint_indices[bank_to_fire].begin(), swp->primary_firepoint_indices[bank_to_fire].end(), std::mt19937(rd()));
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(swp->primary_firepoint_indices[bank_to_fire].begin(), swp->primary_firepoint_indices[bank_to_fire].end(), rng);
}
break;
}
case FiringPattern::RANDOM_NONREPEATING: {
int shuffle_start = MIN(point_count, num_slots - point_count);
std::random_device rd;
std::mt19937 rng(util::Random::shuffle_seed());
auto middle_iterator = swp->primary_firepoint_indices[bank_to_fire].begin();
std::advance(middle_iterator, shuffle_start);
std::shuffle(middle_iterator, swp->primary_firepoint_indices[bank_to_fire].end(), std::mt19937(rd()));
std::shuffle(middle_iterator, swp->primary_firepoint_indices[bank_to_fire].end(), rng);
std::rotate(swp->primary_firepoint_indices[bank_to_fire].begin(), middle_iterator, swp->primary_firepoint_indices[bank_to_fire].end());
break;
}
case FiringPattern::RANDOM_REPEATING: {
std::random_device rd;
std::shuffle(swp->primary_firepoint_indices[bank_to_fire].begin(), swp->primary_firepoint_indices[bank_to_fire].end(), std::mt19937(rd()));
std::mt19937 rng(util::Random::shuffle_seed());
std::shuffle(swp->primary_firepoint_indices[bank_to_fire].begin(), swp->primary_firepoint_indices[bank_to_fire].end(), rng);
break;
}
default: {
Expand Down
20 changes: 20 additions & 0 deletions code/utils/Random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <cstdint>

#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"

extern bool Cmdline_reuse_rng_seed;

namespace util {

Expand Down Expand Up @@ -54,6 +57,23 @@ void Random::seed(unsigned int val)
SCP_rng.seed(val);
}

void Random::seed_ranges(unsigned int val)
{
Assert(val > 0);
seeder.seed(val);
}

unsigned int Random::shuffle_seed()
{
// multiplayer seeds the main RNG from the netgame and ignores -seed, so don't draw from it there
if (Cmdline_reuse_rng_seed && !(Game_mode & GM_MULTIPLAYER)) {
return static_cast<unsigned int>(next());
}

std::random_device rd;
return rd();
}

int Random::next()
{
return SCP_rng.next();
Expand Down
6 changes: 6 additions & 0 deletions code/utils/Random.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ class Random {

// seed(1) will result in RNG using its default seed
static void seed(unsigned int val);
// Seed independent RandomRange instances created after this call.
static void seed_ranges(unsigned int val);

// Seed for a one-off generator handed to std::shuffle. With -seed (outside multiplayer) it is drawn
// from the main RNG, so shuffles repeat from run to run; otherwise it comes from the OS, as before.
static unsigned int shuffle_seed();

// return a value in [0, MAX_VALUE]
static int next(); // uniformly between 0 and MAX_VALUE
Expand Down
11 changes: 9 additions & 2 deletions freespace2/freespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1882,8 +1882,15 @@ void game_init()

Game_current_mission_filename[0] = 0;

// seed the random number generator
Random::seed(static_cast<unsigned int>(time(nullptr)));
// Seed both game RNG families from the command line when reproducible runs
// are requested. RandomRange instances must receive their seed before the
// tables are parsed during game initialization.
if (Cmdline_reuse_rng_seed) {
Random::seed(Cmdline_rng_seed);
Random::seed_ranges(Cmdline_rng_seed);
} else {
Random::seed(static_cast<unsigned int>(time(nullptr)));
}

ImGui::CreateContext();

Expand Down