diff options
| author | Garrett Cox <garrettjcox@gmail.com> | 2026-01-20 20:37:14 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-20 20:37:14 -0600 |
| commit | 77cbefd28023d21f73fcd169f57015a21ad87bac (patch) | |
| tree | fddb1b91ff4c6a8d40f5fd5350f9452da3ad2cd7 | |
| parent | 31f902da390b38dcae0cc7f3ee2d81dfa796ba1a (diff) | |
Emit notification on seed generation failure (#1478)
| -rw-r--r-- | mm/2s2h/Rando/Logic/GlitchlessLogic.cpp | 6 | ||||
| -rw-r--r-- | mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp | 25 | ||||
| -rw-r--r-- | mm/2s2h/Rando/Spoiler/Apply.cpp | 13 | ||||
| -rw-r--r-- | mm/2s2h/Rando/Spoiler/File.cpp | 4 |
4 files changed, 36 insertions, 12 deletions
diff --git a/mm/2s2h/Rando/Logic/GlitchlessLogic.cpp b/mm/2s2h/Rando/Logic/GlitchlessLogic.cpp index f92c6528c..af266198f 100644 --- a/mm/2s2h/Rando/Logic/GlitchlessLogic.cpp +++ b/mm/2s2h/Rando/Logic/GlitchlessLogic.cpp @@ -61,7 +61,7 @@ void ApplyGlitchlessLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std while (true) { // Break if we've been running for too long if (GetUnixTimestamp() - tick > 10000) { - handleError("Logic Generation Timeout"); + handleError("Generation took too long, aborting"); } bool regionsInLogicChanged = false; @@ -168,7 +168,7 @@ void ApplyGlitchlessLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std if (!regionsInLogicChanged && !checksInLogicChanged && !eventsInLogicChanged) { if (checkWithJunk == RC_UNKNOWN) { if (checksWithJunk.empty()) { - handleError("No checks with junk, not sure what to do"); + handleError("Out of checks to replace, cannot place remaining items"); } if (checksWithJunk.size() == 1) { @@ -202,7 +202,7 @@ void ApplyGlitchlessLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std } if (!anyNonJunkItemsLeft) { - handleError("No non-junk items left"); + handleError("No non-junk items left to place, progression is impossible"); } if (nonJunkItemsThatWeHaveNotTried.empty()) { diff --git a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp index 86188a056..be39bacd9 100644 --- a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp +++ b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp @@ -6,6 +6,7 @@ #include <libultraship/bridge/consolevariablebridge.h> #include "ClockShuffle.h" #include <spdlog/spdlog.h> +#include "2s2h/BenGui/Notification.h" extern "C" { #include "functions.h" @@ -76,10 +77,10 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) { Rando::Logic::GeneratePools(gSaveContext.save.shipSaveInfo.rando, checkPool, itemPool); if (checkPool.empty()) { - throw std::runtime_error("No checks in logic"); + throw std::runtime_error("Check pool is empty"); } if (itemPool.empty()) { - throw std::runtime_error("No items in logic"); + throw std::runtime_error("Item pool is empty"); } // Balance pools @@ -124,15 +125,24 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) { continue; } - SPDLOG_ERROR("Could not match item pool size to check pool size {}/{}", itemPool.size(), + SPDLOG_ERROR("Could not balance item/check pools. Too many items. {}/{}", itemPool.size(), checkPool.size()); - throw std::runtime_error("Could not match item pool size to check pool size"); + throw std::runtime_error("Could not balance item/check pools. Too many items."); } } // Grant the starting stuff Rando::GrantStartingItems(); + // Run prelim compatibility/validation checks before attempting to place items + + // Verify we have at least one time item if clock shuffle is enabled + if (RANDO_SAVE_OPTIONS[RO_CLOCK_SHUFFLE] != 0) { + if (Rando::Logic::ClockCount() == 0) { + throw std::runtime_error("Shuffle Time is enabled but no starting time was given"); + } + } + if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_VANILLA) { GiveItem(RI_SWORD_KOKIRI); GiveItem(RI_SHIELD_HERO); @@ -185,8 +195,13 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) { GameInteractor::Instance->ExecuteHooks<GameInteractor::OnRandoSeedGeneration>(); } catch (const std::exception& e) { - SPDLOG_ERROR("Error with randomizer save creation: {}", e.what()); + SPDLOG_ERROR("Seed Failure: {}", e.what()); Audio_PlaySfx(NA_SE_SY_QUIZ_INCORRECT); + Notification::Emit({ + .prefix = "Seed Failure:", + .prefixColor = ImVec4(1.0f, 0.2f, 0.2f, 1.0f), + .message = e.what(), + }); gSaveContext.save.shipSaveInfo.saveType = SAVETYPE_VANILLA; char invalidName[8] = { 18, 23, 31, 10, 21, 18, 13, 62 }; memcpy(gSaveContext.save.saveInfo.playerData.playerName, invalidName, sizeof(invalidName)); diff --git a/mm/2s2h/Rando/Spoiler/Apply.cpp b/mm/2s2h/Rando/Spoiler/Apply.cpp index cb9cb43c9..724e37804 100644 --- a/mm/2s2h/Rando/Spoiler/Apply.cpp +++ b/mm/2s2h/Rando/Spoiler/Apply.cpp @@ -15,7 +15,8 @@ void ApplyToSaveContext(nlohmann::json spoiler) { gSaveContext.save.shipSaveInfo.rando.finalSeed = spoiler["finalSeed"].get<uint32_t>(); for (auto& [randoOptionId, randoStaticOption] : Rando::StaticData::Options) { - RANDO_SAVE_OPTIONS[randoOptionId] = spoiler["options"][randoStaticOption.name].get<uint32_t>(); + RANDO_SAVE_OPTIONS[randoOptionId] = + spoiler["options"].value(randoStaticOption.name, (uint32_t)randoStaticOption.defaultValue); } if (!RANDO_SAVE_OPTIONS[RO_SHUFFLE_GOLD_SKULLTULAS]) { @@ -41,6 +42,11 @@ void ApplyToSaveContext(nlohmann::json spoiler) { std::string itemName = spoiler["checks"][randoStaticCheck.name]["randoItemId"].get<std::string>(); RandoItemId randoItemId = Rando::StaticData::GetItemIdFromName(itemName.c_str()); + if (randoItemId == RI_UNKNOWN) { + SPDLOG_ERROR("Unknown item in spoiler for check {}: {}", randoStaticCheck.name, itemName); + throw std::runtime_error("Unknown item in spoiler: " + itemName); + } + RANDO_SAVE_CHECKS[randoCheckId].randoItemId = randoItemId; RANDO_SAVE_CHECKS[randoCheckId].shuffled = true; @@ -53,6 +59,11 @@ void ApplyToSaveContext(nlohmann::json spoiler) { std::string itemName = spoiler["checks"][randoStaticCheck.name].get<std::string>(); RandoItemId randoItemId = Rando::StaticData::GetItemIdFromName(itemName.c_str()); + if (randoItemId == RI_UNKNOWN) { + SPDLOG_ERROR("Unknown item in spoiler for check {}: {}", randoStaticCheck.name, itemName); + throw std::runtime_error("Unknown item in spoiler: " + itemName); + } + RANDO_SAVE_CHECKS[randoCheckId].randoItemId = randoItemId; RANDO_SAVE_CHECKS[randoCheckId].shuffled = true; } diff --git a/mm/2s2h/Rando/Spoiler/File.cpp b/mm/2s2h/Rando/Spoiler/File.cpp index c54f6ac3b..e2f610dfe 100644 --- a/mm/2s2h/Rando/Spoiler/File.cpp +++ b/mm/2s2h/Rando/Spoiler/File.cpp @@ -26,9 +26,7 @@ nlohmann::json LoadFromFile(const std::string& fileName) { nlohmann::json spoiler; try { fileStream >> spoiler; - } catch (nlohmann::json::exception& e) { - throw std::runtime_error("Failed to parse spoiler file: " + std::string(e.what())); - } + } catch (nlohmann::json::exception& e) { throw std::runtime_error("Failed to parse spoiler file"); } if (!spoiler.contains("type") || spoiler["type"] != "2S2H_RANDO_SPOILER") { throw std::runtime_error("Spoiler file is not a valid spoiler file"); |
