diff --git a/soh/soh/Enhancements/Presets/Presets.cpp b/soh/soh/Enhancements/Presets/Presets.cpp index 952a900429..fc21dfd50a 100644 --- a/soh/soh/Enhancements/Presets/Presets.cpp +++ b/soh/soh/Enhancements/Presets/Presets.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "soh/OTRGlobals.h" @@ -225,7 +226,7 @@ std::vector> GetSpeedrunPresets() { std::vector> found; for (auto& [name, info] : presets) { - if (name.rfind(prefix, 0) == 0) { + if (info.isBuiltIn && name.rfind(prefix, 0) == 0) { std::string label = name.substr(prefix.size()); size_t digits = label.find_first_not_of("0123456789"); if (digits > 0 && digits != std::string::npos && label[digits] == ' ') { @@ -247,6 +248,20 @@ nlohmann::json GetPresetExempt(const std::string& presetName) { return entry->second.presetValues["exempt"]; } +std::string GetPresetFileContents(const std::string& presetName) { + auto entry = presets.find(presetName); + if (entry == presets.end()) { + return ""; + } + + auto file = Ship::Context::GetRawInstance()->GetResourceManager()->GetArchiveManager()->LoadFile( + "presets/" + entry->second.fileName + ".json"); + if (file == nullptr || file->Buffer == nullptr) { + return ""; + } + return std::string(file->Buffer->begin(), file->Buffer->end()); +} + void DrawPresetSelector(std::vector includeSections, std::string presetLoc, bool disabled) { std::vector includedPresets; for (auto& [name, info] : presets) { diff --git a/soh/soh/Enhancements/Presets/Presets.h b/soh/soh/Enhancements/Presets/Presets.h index 5856a0b93d..05a14c942e 100644 --- a/soh/soh/Enhancements/Presets/Presets.h +++ b/soh/soh/Enhancements/Presets/Presets.h @@ -24,8 +24,11 @@ void applyPreset(std::string presetName, std::vector includeSecti nlohmann::json applyPresetToBlocks(std::string presetName, nlohmann::json blocks, std::vector includeSections = {}); -// {display name, preset name} of every preset whose file is named "Speedrun - " +// {display name, preset name} of every built-in preset whose file is named "Speedrun - " std::vector> GetSpeedrunPresets(); // The preset's "exempt" list of cvar json pointers, or an empty array if it has none. nlohmann::json GetPresetExempt(const std::string& presetName); + +// The raw contents of a built-in preset's file in the archive, or an empty string if there's none. +std::string GetPresetFileContents(const std::string& presetName); diff --git a/soh/soh/Enhancements/speedrun/Speedrun.cpp b/soh/soh/Enhancements/speedrun/Speedrun.cpp index 00a9686ffe..2c0f3082e8 100644 --- a/soh/soh/Enhancements/speedrun/Speedrun.cpp +++ b/soh/soh/Enhancements/speedrun/Speedrun.cpp @@ -8,6 +8,7 @@ #include "soh/ShipInit.hpp" #include "soh/SohGui/SohGui.hpp" #include "soh/config/ConfigUpdaters.h" +#include "soh/util.h" #include #include @@ -55,7 +56,7 @@ static std::vector> sPresetChoices; static nlohmann::json sSettings = nlohmann::json::object(); static uint32_t sConfigVersion = 0; // Paths of settings the player keeps even under a preset, from the preset's "exempt" list. Copied over file's -// settings on create and load. Values left out of settings hash, but paths are not. Saved with file. +// settings on create and load. Saved with file. static nlohmann::json sExempt = nlohmann::json::array(); static std::string sPresetName = SPEEDRUN_PRESET_NONE; static uint32_t sSettingsHash = 0; @@ -253,27 +254,6 @@ extern "C" bool Ship_QuestDebugEnabled(u8 questId) { CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); } -// FNV-1a hash of the build version, the file's settings without exempt values, and the exempt paths. Same hash means -// same build and settings. nlohmann sorts object keys, so the dump is stable. -static uint32_t HashSettings() { - nlohmann::json stripped = sSettings; - for (const auto& path : GetExemptPaths(sExempt)) { - if (stripped.contains(path)) { - stripped[path.parent_pointer()].erase(path.back()); - } - } - - std::string data = std::string((const char*)gBuildVersion) + stripped.dump() + sExempt.dump(); - uint32_t hash = 0x811C9DC5; - - for (char c : data) { - hash ^= (uint8_t)c; - hash *= 0x01000193; - } - - return hash; -} - static void EmitHashNotification() { Notification::Emit({ .prefix = "Speedrun", @@ -399,7 +379,7 @@ extern "C" void Speedrun_InitSaveFile(u8 presetIndex) { // Runs are always timed in real time, whatever the "RTA Timing on new files" option says. gSaveContext.ship.stats.rtaTiming = 1; - sSettingsHash = HashSettings(); + sSettingsHash = SohUtils::Hash(std::string((const char*)gBuildVersion) + GetPresetFileContents(presetKey)); EmitHashNotification(); } @@ -422,6 +402,7 @@ static void LoadSaveSection() { LockMenu(); SaveManager::Instance->LoadData("presetName", sPresetName); + SaveManager::Instance->LoadData("settingsHash", sSettingsHash); SaveManager::Instance->LoadData("settings", sSettings); SaveManager::Instance->LoadData("configVersion", sConfigVersion); SaveManager::Instance->LoadData("exempt", sExempt); @@ -465,7 +446,6 @@ static void LoadSaveSection() { blocks[CVAR_PREFIX_COSMETIC] = nlohmann::json::object(); SetOwnedBlocks(blocks); - sSettingsHash = HashSettings(); EmitHashNotification(); }