Avoid randomizer generation races with file select (#7136)

Fixes both starting file while generating,
& starting generation in file loading transition

Remove RandoGenerating cvar
This commit is contained in:
Philip Dubé
2026-08-31 14:04:50 +00:00
committed by GitHub
parent 2dd51f1288
commit a7cd6c8113
9 changed files with 40 additions and 30 deletions
-1
View File
@@ -5,7 +5,6 @@
void BootCommands_Init() { void BootCommands_Init() {
// Clears vars to prevent randomizer menu from being disabled // Clears vars to prevent randomizer menu from being disabled
CVarClear(CVAR_GENERAL("RandoGenerating")); // Clear when a crash happened during rando seed generation
CVarClear(CVAR_GENERAL("NewSeedGenerated")); CVarClear(CVAR_GENERAL("NewSeedGenerated"));
CVarClear(CVAR_GENERAL("OnFileSelectNameEntry")); // Clear when soh is killed on the file name entry page CVarClear(CVAR_GENERAL("OnFileSelectNameEntry")); // Clear when soh is killed on the file name entry page
CVarClear(CVAR_GENERAL("BetterDebugWarpScreenMQMode")); CVarClear(CVAR_GENERAL("BetterDebugWarpScreenMQMode"));
+16 -17
View File
@@ -1,3 +1,4 @@
#include <atomic>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <tuple> #include <tuple>
@@ -43,7 +44,7 @@ std::unordered_map<std::string, HintType> SpoilerfileHintTypeNameToEnum;
std::set<RandomizerCheck> excludedLocations; std::set<RandomizerCheck> excludedLocations;
std::set<RandomizerCheck> spoilerExcludedLocations; std::set<RandomizerCheck> spoilerExcludedLocations;
bool generated; static std::atomic<bool> randoGenerating;
bool Rando_HandleSpoilerDrop(char* filePath) { bool Rando_HandleSpoilerDrop(char* filePath) {
if (SohUtils::IsStringEmpty(filePath)) { if (SohUtils::IsStringEmpty(filePath)) {
@@ -926,8 +927,6 @@ RandomizerCheck Randomizer::GetCheckFromRandomizerInf(RandomizerInf randomizerIn
std::thread randoThread; std::thread randoThread;
void GenerateRandomizerImgui(std::string seed = "") { void GenerateRandomizerImgui(std::string seed = "") {
CVarSetInteger(CVAR_GENERAL("RandoGenerating"), 1);
Ship::Context::GetRawInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
// RANDOTODO proper UI for selecting if a spoiler loaded should be used for settings // RANDOTODO proper UI for selecting if a spoiler loaded should be used for settings
Rando::Settings::GetInstance()->SetAllToContext(); Rando::Settings::GetInstance()->SetAllToContext();
@@ -963,32 +962,32 @@ void GenerateRandomizerImgui(std::string seed = "") {
} }
Rando::Context::GetInstance()->SetSeedGenerated(GenerateRandomizer(excludedLocations, enabledTricks, seed)); Rando::Context::GetInstance()->SetSeedGenerated(GenerateRandomizer(excludedLocations, enabledTricks, seed));
CVarSetInteger(CVAR_GENERAL("RandoGenerating"), 0);
Ship::Context::GetRawInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); Ship::Context::GetRawInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
generated = true;
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnGenerationCompletion>(); GameInteractor::Instance->ExecuteHooks<GameInteractor::OnGenerationCompletion>();
randoGenerating = false;
}
bool IsRandoGenerating() {
return randoGenerating;
} }
bool GenerateRandomizer(std::string seed /*= ""*/) { bool GenerateRandomizer(std::string seed /*= ""*/) {
if (generated) { if (randoGenerating) {
generated = false; return false;
randoThread.join();
} }
if (CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) == 0) { WaitForRandoGeneration();
randoThread = std::thread(&GenerateRandomizerImgui, seed); randoGenerating = true;
return true; randoThread = std::thread(&GenerateRandomizerImgui, seed);
} return true;
return false;
} }
static bool locationsTabOpen = false; static bool locationsTabOpen = false;
static bool tricksTabOpen = false; static bool tricksTabOpen = false;
void JoinRandoGenerationThread() { void WaitForRandoGeneration() {
if (generated) { if (randoThread.joinable()) {
generated = false;
randoThread.join(); randoThread.join();
} }
} }
+2 -1
View File
@@ -44,7 +44,8 @@ extern "C" {
#endif #endif
bool GenerateRandomizer(std::string seed = ""); bool GenerateRandomizer(std::string seed = "");
void JoinRandoGenerationThread(); bool IsRandoGenerating();
void WaitForRandoGeneration();
#ifdef __cplusplus #ifdef __cplusplus
} }
+8
View File
@@ -2418,6 +2418,14 @@ extern "C" uint8_t Randomizer_GenerateRandomizer() {
return GenerateRandomizer() ? 1 : 0; return GenerateRandomizer() ? 1 : 0;
} }
extern "C" bool Randomizer_IsGenerating() {
return IsRandoGenerating();
}
extern "C" void Randomizer_WaitForGeneration() {
WaitForRandoGeneration();
}
extern "C" void Randomizer_ShowRandomizerMenu() { extern "C" void Randomizer_ShowRandomizerMenu() {
SohGui::ShowRandomizerSettingsMenu(); SohGui::ShowRandomizerSettingsMenu();
} }
+2
View File
@@ -123,6 +123,8 @@ uint8_t Randomizer_IsSeedGenerated();
uint8_t Randomizer_IsSpoilerLoaded(); uint8_t Randomizer_IsSpoilerLoaded();
void Randomizer_SetSpoilerLoaded(bool spoilerLoaded); void Randomizer_SetSpoilerLoaded(bool spoilerLoaded);
uint8_t Randomizer_GenerateRandomizer(); uint8_t Randomizer_GenerateRandomizer();
bool Randomizer_IsGenerating();
void Randomizer_WaitForGeneration();
void Randomizer_ShowRandomizerMenu(); void Randomizer_ShowRandomizerMenu();
GetItemEntry ItemTable_Retrieve(int16_t getItemID); GetItemEntry ItemTable_Retrieve(int16_t getItemID);
GetItemEntry ItemTable_RetrieveEntry(s16 modIndex, s16 getItemID); GetItemEntry ItemTable_RetrieveEntry(s16 modIndex, s16 getItemID);
+4 -7
View File
@@ -71,7 +71,7 @@ void DrawLocationsMenu(WidgetInfo& info) {
int32_t currMQDungeonSetting = CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), 0) | int32_t currMQDungeonSetting = CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), 0) |
CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeonCount"), 0) << 8; CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeonCount"), 0) << 8;
static ImVec2 cellPadding(8.0f, 8.0f); static ImVec2 cellPadding(8.0f, 8.0f);
bool generating = CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0); bool generating = IsRandoGenerating();
bool disableEditingRandoSettings = generating || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0); bool disableEditingRandoSettings = generating || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0);
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings); ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding); ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding);
@@ -363,7 +363,7 @@ void DrawTricksMenu(WidgetInfo& info) {
auto ctx = Rando::Context::GetInstance(); auto ctx = Rando::Context::GetInstance();
auto randoSettings = Rando::Settings::GetInstance(); auto randoSettings = Rando::Settings::GetInstance();
static ImVec2 cellPadding(8.0f, 8.0f); static ImVec2 cellPadding(8.0f, 8.0f);
bool generating = CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0); bool generating = IsRandoGenerating();
bool disableEditingRandoSettings = generating || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0); bool disableEditingRandoSettings = generating || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0);
if (tricksDirty) { if (tricksDirty) {
tricksDirty = false; tricksDirty = false;
@@ -729,18 +729,15 @@ void SohMenu::AddMenuRandomizer() {
AddWidget(path, "Randomize All Settings", WIDGET_BUTTON) AddWidget(path, "Randomize All Settings", WIDGET_BUTTON)
.Callback([](WidgetInfo& info) { Rando::Settings::GetInstance()->RandomizeAllSettings(); }) .Callback([](WidgetInfo& info) { Rando::Settings::GetInstance()->RandomizeAllSettings(); })
.PreFunc([](WidgetInfo& info) { .PreFunc([](WidgetInfo& info) {
info.options->disabled = CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) || info.options->disabled = IsRandoGenerating() || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0);
CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0);
}) })
.Options(ButtonOptions() .Options(ButtonOptions()
.Size(ImVec2(250.f, 0.f)) .Size(ImVec2(250.f, 0.f))
.Tooltip("Randomizes all randomizer settings to random valid values (excludes tricks).")) .Tooltip("Randomizes all randomizer settings to random valid values (excludes tricks)."))
.SameLine(true); .SameLine(true);
AddWidget(path, "Spoiler File", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) { AddWidget(path, "Spoiler File", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) {
JoinRandoGenerationThread();
if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) { if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) {
std::string spoilerfilepath = CVarGetString(CVAR_GENERAL("SpoilerLog"), ""); ImGui::Text("Spoiler File: %s", CVarGetString(CVAR_GENERAL("SpoilerLog"), ""));
ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str());
} }
}); });
+2 -1
View File
@@ -7,6 +7,7 @@
#include "soh/SohGui/ImGuiUtils.h" #include "soh/SohGui/ImGuiUtils.h"
#include "soh/OTRGlobals.h" #include "soh/OTRGlobals.h"
#include "soh/cvar_prefixes.h" #include "soh/cvar_prefixes.h"
#include "soh/Enhancements/randomizer/randomizer.h"
#include "soh/Enhancements/randomizer/settings.h" #include "soh/Enhancements/randomizer/settings.h"
namespace SohGui { namespace SohGui {
@@ -144,7 +145,7 @@ static void StartingItemCombobox(RandomizerSettingKey rsk) {
} }
void DrawStartingItemsMenu(WidgetInfo& info) { void DrawStartingItemsMenu(WidgetInfo& info) {
bool generating = CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0); bool generating = IsRandoGenerating();
bool disableEditingRandoSettings = generating || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0); bool disableEditingRandoSettings = generating || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0);
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings); ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings);
-1
View File
@@ -12,7 +12,6 @@ struct Migration {
static const Migration version3Migrations[] = { static const Migration version3Migrations[] = {
{ "gSwitchAge", "gGeneral.SwitchAge" }, { "gSwitchAge", "gGeneral.SwitchAge" },
{ "gFrameAdvance", "gDeveloperTools.FrameAdvanceTick" }, { "gFrameAdvance", "gDeveloperTools.FrameAdvanceTick" },
{ "gRandoGenerating", "gGeneral.RandoGenerating" },
{ "gNewSeedGenerated", "gGeneral.NewSeedGenerated" }, { "gNewSeedGenerated", "gGeneral.NewSeedGenerated" },
{ "gOnFileSelectNameEntry", "gGeneral.OnFileSelectNameEntry" }, { "gOnFileSelectNameEntry", "gGeneral.OnFileSelectNameEntry" },
{ "gBetterDebugWarpScreenMQMode", "gGeneral.BetterDebugWarpScreenMQMode" }, { "gBetterDebugWarpScreenMQMode", "gGeneral.BetterDebugWarpScreenMQMode" },
@@ -389,11 +389,11 @@ int retries = 0;
bool fileSelectSpoilerFileLoaded = false; bool fileSelectSpoilerFileLoaded = false;
void FileChoose_UpdateRandomizer() { void FileChoose_UpdateRandomizer() {
if (CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) != 0 && generating == 0) { if (Randomizer_IsGenerating() && generating == 0) {
generating = 1; generating = 1;
Audio_PlaySequenceWithSeqPlayerIO(SEQ_PLAYER_BGM_MAIN, NA_BGM_HORSE, 0, 7, 1); Audio_PlaySequenceWithSeqPlayerIO(SEQ_PLAYER_BGM_MAIN, NA_BGM_HORSE, 0, 7, 1);
return; return;
} else if (CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) == 0 && generating) { } else if (!Randomizer_IsGenerating() && generating) {
if (Randomizer_IsSeedGenerated()) { if (Randomizer_IsSeedGenerated()) {
Audio_PlayFanfare(NA_BGM_HORSE_GOAL); Audio_PlayFanfare(NA_BGM_HORSE_GOAL);
retries = 0; retries = 0;
@@ -463,6 +463,9 @@ void FileChoose_UpdateMainMenu(GameState* thisx) {
u8 isDefaultNameOptionSet; u8 isDefaultNameOptionSet;
FileChoose_UpdateRandomizer(); FileChoose_UpdateRandomizer();
if (generating) {
return;
}
if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) { if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) {
if (this->buttonIndex <= FS_BTN_MAIN_FILE_3) { if (this->buttonIndex <= FS_BTN_MAIN_FILE_3) {
@@ -2544,6 +2547,7 @@ void FileChoose_LoadGame(GameState* thisx) {
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
gSaveContext.fileNum = this->buttonIndex; gSaveContext.fileNum = this->buttonIndex;
gSaveContext.gameMode = GAMEMODE_NORMAL; gSaveContext.gameMode = GAMEMODE_NORMAL;
Randomizer_WaitForGeneration();
if ((this->buttonIndex == FS_BTN_SELECT_FILE_1 && CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0)) || if ((this->buttonIndex == FS_BTN_SELECT_FILE_1 && CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0)) ||
this->buttonIndex == 0xFF) { this->buttonIndex == 0xFF) {