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
6 changes: 4 additions & 2 deletions soh/soh/Enhancements/audio/AudioEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ void UpdateCurrentBGM(u16 seqKey, SeqType seqType) {
}
}

static uint64_t seeded_audio_state = 0;

void RandomizeGroup(SeqType type, bool manual = true) {
std::vector<u16> values;

Expand All @@ -118,7 +120,7 @@ void RandomizeGroup(SeqType type, bool manual = true) {

uint32_t finalSeed = type + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));
Random_Init(finalSeed);
ShipUtils::RandInit(finalSeed, &seeded_audio_state);
}
}

Expand All @@ -139,7 +141,7 @@ void RandomizeGroup(SeqType type, bool manual = true) {
if (!values.size())
return;
}
Shuffle(values);
ShipUtils::Shuffle(values, &seeded_audio_state);
for (const auto& [seqId, seqData] : AudioCollection::Instance->GetAllSequences()) {
const std::string cvarKey = AudioCollection::Instance->GetCvarKey(seqData.sfxKey);
const std::string cvarLockKey = AudioCollection::Instance->GetCvarLockKey(seqData.sfxKey);
Expand Down
4 changes: 3 additions & 1 deletion soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2104,6 +2104,8 @@ void ApplySideEffects(CosmeticOption& cosmeticOption) {
}
}

static uint64_t seeded_cosmetics_state = 0;

void RandomizeColor(CosmeticOption& cosmeticOption, bool manual = true) {
ImVec4 randomColor;

Expand All @@ -2115,7 +2117,7 @@ void RandomizeColor(CosmeticOption& cosmeticOption, bool manual = true) {
(IS_RANDO ? Rando::Context::GetInstance()->GetSeed()
: static_cast<uint32_t>(gSaveContext.ship.stats.fileCreatedAt));

randomColor = GetRandomValue(finalSeed);
randomColor = GetRandomValue(finalSeed, &seeded_cosmetics_state);
} else {
randomColor = GetRandomValue();
}
Expand Down
36 changes: 5 additions & 31 deletions soh/soh/Enhancements/randomizer/3drando/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,25 @@
#include <cassert>

static bool init = false;
static uint64_t state = 0;
uint64_t rando_state = 0;
const uint64_t multiplier = 6364136223846793005ULL;
const uint64_t increment = 11634580027462260723ULL;

// Initialize with seed specified
void Random_Init(uint64_t seed) {
init = true;
state = seed;
ShipUtils::RandInit(seed, &rando_state);
}

uint32_t next32() {
if (!init) {
// No seed given, get a random number from device to seed
#if !defined(__SWITCH__) && !defined(__WIIU__)
uint64_t seed = static_cast<uint64_t>(std::random_device{}());
#else
uint64_t seed = static_cast<uint64_t>(std::hash<std::string>{}(std::to_string(rand())));
#endif
Random_Init(seed);
}

state = state * multiplier + increment;
uint32_t xorshifted = static_cast<uint32_t>(((state >> 18) ^ state) >> 27);
uint32_t rot = static_cast<int>(state >> 59);
return std::rotr(xorshifted, rot);
return ShipUtils::next32(&rando_state);
}

// Returns a random integer in range [min, max-1]
uint32_t Random(uint32_t min, uint32_t max) {
if (min == max) {
return min;
}
assert(max > min);

uint32_t n = max - min;
uint32_t cutoff = UINT32_MAX - UINT32_MAX % static_cast<uint32_t>(n);
for (;;) {
uint32_t r = next32();
if (r <= cutoff) {
return min + r % n;
}
}
return ShipUtils::Random(min, max, &rando_state);
}

// Returns a random floating point number in [0.0, 1.0)
double RandomDouble() {
return ldexp(next32(), -32);
return ShipUtils::RandomDouble(&rando_state);
}
25 changes: 7 additions & 18 deletions soh/soh/Enhancements/randomizer/3drando/random.hpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,32 @@
#pragma once

#include "soh/ShipUtils.h"
#include <array>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>
#include <set>

extern uint64_t rando_state;

void Random_Init(uint64_t seed);
uint32_t Random(uint32_t min, uint32_t max);
double RandomDouble();

// Get a random element from a vector or array
template <typename T> T RandomElement(std::vector<T>& vector, bool erase) {
const auto idx = Random(0, static_cast<uint32_t>(vector.size()));
const T selected = vector[idx];
if (erase) {
vector.erase(vector.begin() + idx);
}
return selected;
return ShipUtils::RandomElement(vector, erase, &rando_state);
}
template <typename Container> auto& RandomElement(Container& container) {
return container[Random(0, static_cast<uint32_t>(std::size(container)))];
return ShipUtils::RandomElement(container, &rando_state);
}
template <typename Container> const auto& RandomElement(const Container& container) {
return container[Random(0, static_cast<uint32_t>(std::size(container)))];
return ShipUtils::RandomElement(container, &rando_state);
}

template <typename T> const T RandomElementFromSet(const std::set<T>& set) {
if (set.size() == 1) {
return *set.begin();
}
uint32_t rand = Random(0, static_cast<uint32_t>(set.size()));
auto it = set.begin();
for (uint32_t i = 0; i < rand; i++) {
it++;
}
auto test = *it;
return *it;
return ShipUtils::RandomElementFromSet(set, &rando_state);
}

// Shuffle items within a vector or array
Expand Down
58 changes: 58 additions & 0 deletions soh/soh/ShipUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ShipUtils.h"
#include <libultraship/libultraship.h>
#include <random>
#include "soh_assets.h"

extern "C" {
Expand Down Expand Up @@ -96,3 +97,60 @@ extern "C" void* Ship_GetCharFontTexture(u8 character) {

return (void*)fontTbl[adjustedChar];
}

static bool rand_init = false;
uint64_t default_state = 0;
const uint64_t multiplier = 6364136223846793005ULL;
const uint64_t increment = 11634580027462260723ULL;

// Initialize with seed specified
void ShipUtils::RandInit(uint64_t seed, uint64_t* state) {
rand_init = true;
if (state == nullptr) {
state = &default_state;
}
*state = seed;
}

uint32_t ShipUtils::next32(uint64_t* state) {
if (state == nullptr) {
state = &default_state;
}

if (!rand_init) {
// No seed given, get a random number from device to seed
#if !defined(__SWITCH__) && !defined(__WIIU__)
uint64_t seed = static_cast<uint64_t>(std::random_device{}());
#else
uint64_t seed = static_cast<uint64_t>(std::hash<std::string>{}(std::to_string(rand())));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint64_t seed = static_cast<uint64_t>(std::hash<std::string>{}(std::to_string(rand())));
uint64_t seed = static_cast<uint64_t>(rand());

Beyond this PR's scope, but we should go ahead & rely on rand without the string-then-hash song & dance

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this was on dev-copper instead of dev I'd say it's probably out of scope but since its on dev I might as well go ahead and make the bigger changes, so I'm thinking this is maybe not quite out of scope after all.

#endif
ShipUtils::RandInit(seed, state);
}

*state = *state * multiplier + increment;
uint32_t xorshifted = static_cast<uint32_t>(((*state >> 18) ^ *state) >> 27);
uint32_t rot = static_cast<int>(*state >> 59);
return std::rotr(xorshifted, rot);
}

// Returns a random integer in range [min, max-1]
uint32_t ShipUtils::Random(uint32_t min, uint32_t max, uint64_t* state) {
if (min == max) {
return min;
}
assert(max > min);

uint32_t n = max - min;
uint32_t cutoff = UINT32_MAX - UINT32_MAX % static_cast<uint32_t>(n);
for (;;) {
uint32_t r = next32(state);
if (r <= cutoff) {
return min + r % n;
}
}
}

// Returns a random floating point number in [0.0, 1.0)
double ShipUtils::RandomDouble(uint64_t* state) {
return ldexp(next32(state), -32);
}
47 changes: 47 additions & 0 deletions soh/soh/ShipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,53 @@ void* Ship_GetCharFontTexture(u8 character);

#ifdef __cplusplus
}

namespace ShipUtils {
void RandInit(uint64_t seed, uint64_t* state = nullptr);
uint32_t next32(uint64_t* state = nullptr);
uint32_t Random(uint32_t min, uint32_t max, uint64_t* state = nullptr);
double RandomDouble(uint64_t* state = nullptr);

// Get a random element from a vector or array
template <typename T> T RandomElement(std::vector<T>& vector, bool erase, uint64_t* state = nullptr) {
const auto idx = Random(0, static_cast<uint32_t>(vector.size()), state);
const T selected = vector[idx];
if (erase) {
vector.erase(vector.begin() + idx);
}
return selected;
}
template <typename Container> auto& RandomElement(Container& container, uint64_t* state = nullptr) {
return container[Random(0, static_cast<uint32_t>(std::size(container)), state)];
}
template <typename Container> const auto& RandomElement(const Container& container, uint64_t* state = nullptr) {
return container[Random(0, static_cast<uint32_t>(std::size(container)), state)];
}

template <typename T> const T RandomElementFromSet(const std::set<T>& set, uint64_t* state = nullptr) {
if (set.size() == 1) {
return *set.begin();
}
uint32_t rand = Random(0, static_cast<uint32_t>(set.size()), state);
auto it = set.begin();
for (uint32_t i = 0; i < rand; i++) {
it++;
}
auto test = *it;
return *it;
}

template <typename T> void Shuffle(std::vector<T>& vector, uint64_t* state = nullptr) {
for (size_t i = 0; i + 1 < vector.size(); i++) {
std::swap(vector[i], vector[Random(static_cast<uint32_t>(i), static_cast<uint32_t>(vector.size()), state)]);
}
}
template <typename T, size_t size> void Shuffle(std::array<T, size>& arr, uint64_t* state = nullptr) {
for (size_t i = 0; i + 1 < arr.size(); i++) {
std::swap(arr[i], arr[Random(static_cast<uint32_t>(i), static_cast<uint32_t>(arr.size()), state)]);
}
}
} // namespace ShipUtils
#endif

#endif // SHIP_UTILS_H
31 changes: 8 additions & 23 deletions soh/soh/SohGui/UIWidgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1154,34 +1154,19 @@ void DrawFlagArray8Mask(const std::string& name, uint8_t& flags, Colors color) {
} // namespace UIWidgets

ImVec4 GetRandomValue() {
#if !defined(__SWITCH__) && !defined(__WIIU__)
std::random_device rd;
std::mt19937 rng(rd());
#else
size_t seed = std::hash<std::string>{}(std::to_string(rand()));
std::mt19937_64 rng(seed);
#endif
std::uniform_int_distribution<int> dist(0, 255 - 1);

ImVec4 NewColor;
NewColor.x = (float)(dist(rng)) / 255.0f;
NewColor.y = (float)(dist(rng)) / 255.0f;
NewColor.z = (float)(dist(rng)) / 255.0f;
NewColor.x = (float)ShipUtils::RandomDouble();
NewColor.y = (float)ShipUtils::RandomDouble();
NewColor.z = (float)ShipUtils::RandomDouble();
return NewColor;
}

ImVec4 GetRandomValue(uint32_t seed) {
#if !defined(__SWITCH__) && !defined(__WIIU__)
std::mt19937 rng(seed);
#else
std::mt19937_64 rng(seed);
#endif
std::uniform_int_distribution<int> dist(0, 255 - 1);

ImVec4 GetRandomValue(uint32_t seed, uint64_t* state) {
ShipUtils::RandInit(seed, state);
ImVec4 NewColor;
NewColor.x = (float)(dist(rng)) / 255.0f;
NewColor.y = (float)(dist(rng)) / 255.0f;
NewColor.z = (float)(dist(rng)) / 255.0f;
NewColor.x = (float)ShipUtils::RandomDouble(state);
NewColor.y = (float)ShipUtils::RandomDouble(state);
NewColor.z = (float)ShipUtils::RandomDouble(state);
return NewColor;
}

Expand Down
2 changes: 1 addition & 1 deletion soh/soh/SohGui/UIWidgets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ void InsertHelpHoverText(const char* text);
} // namespace UIWidgets

ImVec4 GetRandomValue();
ImVec4 GetRandomValue(uint32_t seed);
ImVec4 GetRandomValue(uint32_t seed, uint64_t* state = nullptr);

Color_RGBA8 RGBA8FromVec(ImVec4 vec);
ImVec4 VecFromRGBA8(Color_RGBA8 color);
Expand Down
Loading