From baaedd7ab06ee2acc9ad9f5de8d79abbbee43e5f Mon Sep 17 00:00:00 2001 From: Glought <663343+Glought@users.noreply.github.com> Date: Sat, 26 Jul 2025 08:24:57 -0700 Subject: [PATCH 1/4] Add "Delete All Saves" QoL Feature. *Added "Enable Delete All Saves" Checkbox. *Added "Delete All Saves" Button Both are in "Settings -> General -> General Settings" under the "Open App Files Folder" button. The "Enable Delete All Saves" Checkbox when checked enables the "Delete All Saves" Button.It is uncheck by default. The purpose for the "Enable Delete All Saves" checkbox is to prevent the possibility of accidentally pressing the "Delete All Saves" Button by mistake. When the "Delete All Saves" Button is pressed it will delete all 3 save files and resets SoH and then disables itself by turning off "Enable Delete All Saves" Checkbox. The Reasoning for this Qol is to have a quick way to delete all saves instead of deleting each file using the in-game file menu(takes a while took 30 actions to delete all 3 files) or navigating the App file folder(Would require closing Soh, the reset button doesn't clear the files slots in-game if files are deleted outside of SoH.). --- .../GameInteractor_HookTable.h | 1 + soh/soh/SaveManager.cpp | 9 ++++++++ soh/soh/SaveManager.h | 2 ++ soh/soh/SohGui/SohMenuSettings.cpp | 22 +++++++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index 51a6ab5a8..edbdf1500 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -47,6 +47,7 @@ DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, va_list or DEFINE_HOOK(OnSaveFile, (int32_t fileNum)); DEFINE_HOOK(OnLoadFile, (int32_t fileNum)); DEFINE_HOOK(OnDeleteFile, (int32_t fileNum)); +DEFINE_HOOK(OnDeleteAllFiles, ()); DEFINE_HOOK(OnDialogMessage, ()); DEFINE_HOOK(OnPresentTitleCard, ()); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 4b830f846..ae8db834d 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -124,6 +124,9 @@ SaveManager::SaveManager() { AddInitFunction(InitFileImpl); + GameInteractor::Instance->RegisterGameHook( + [this]() { this->DeleteAllZeldaFiles(); }); + GameInteractor::Instance->RegisterGameHook( [this](uint32_t fileNum) { ThreadPoolWait(); }); @@ -2371,6 +2374,12 @@ void SaveManager::DeleteZeldaFile(int fileNum) { GameInteractor::Instance->ExecuteHooks(fileNum); } +void SaveManager::DeleteAllZeldaFiles() { + for (int fileNum = 0; fileNum < MaxFiles; fileNum++) { + DeleteZeldaFile(fileNum); + } +} + bool SaveManager::IsRandoFile() { return IS_RANDO; } diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 6d7ef3b33..d89e090cb 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -103,6 +103,8 @@ class SaveManager { void CopyZeldaFile(int from, int to); void DeleteZeldaFile(int fileNum); + void DeleteAllZeldaFiles(); + bool IsRandoFile(); // Use a name of "" to save to an array. You must be in a SaveArray callback. diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp index bb7c82574..e2bff6154 100644 --- a/soh/soh/SohGui/SohMenuSettings.cpp +++ b/soh/soh/SohGui/SohMenuSettings.cpp @@ -187,6 +187,28 @@ void SohMenu::AddMenuSettings() { SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); }) .Options(ButtonOptions().Tooltip("Opens the folder that contains the save and mods folders, etc.")); + AddWidget(path, "Enable Delete All Saves", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_SETTING("EnableDeleteAllSaveFilesButton")) + .RaceDisable(false) + .Options(CheckboxOptions() + .Tooltip("Turn on to enable the \"Delete All Saves\" button.Turns off automatically " + "when \"Delete All Saves\" is pressed") + .DefaultValue(false)); + AddWidget(path, "Delete All Saves", WIDGET_BUTTON) + .RaceDisable(false) + .PreFunc([](WidgetInfo& info) { + info.options->disabled = !CVarGetInteger(CVAR_SETTING("EnableDeleteAllSaveFilesButton"), 0); + info.options->disabledTooltip = + "This button is disabled because \"Enable Delete All Saves\" is turned off."; + }) + .Callback([](WidgetInfo& info) { + GameInteractor::Instance->ExecuteHooks(); + CVarSetInteger(CVAR_SETTING("EnableDeleteAllSaveFilesButton"), 0); + std::reinterpret_pointer_cast( + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) + ->Dispatch("reset"); + }) + .Options(ButtonOptions().Tooltip("Warning deletes all save files")); AddWidget(path, "Boot", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Boot Sequence", WIDGET_CVAR_COMBOBOX) From dff2f76965f969a63bbc3b3d78fb1ac2a28d47e6 Mon Sep 17 00:00:00 2001 From: Glought <663343+Glought@users.noreply.github.com> Date: Sun, 27 Jul 2025 09:08:53 -0700 Subject: [PATCH 2/4] Add "Delete Selected Save file" in Settings -> General Menu * Add "Saves" Text Separator. * Renamed "Enable Delete All Saves" checkbox to "Enable Delete All/Selected Saves". * Add "Select Save File To Delete" Slider. * Add "Delete Selected Save File" Button. The User can use the Slider to select the file to delete then press the "Delete Selected Save File" Button to delete the selected file. It will Disable itself and reset SoH. --- .../GameInteractor_HookTable.h | 1 + soh/soh/SaveManager.cpp | 5 +++ soh/soh/SohGui/SohMenuSettings.cpp | 45 ++++++++++++++----- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index edbdf1500..c8a85aae4 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -47,6 +47,7 @@ DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, va_list or DEFINE_HOOK(OnSaveFile, (int32_t fileNum)); DEFINE_HOOK(OnLoadFile, (int32_t fileNum)); DEFINE_HOOK(OnDeleteFile, (int32_t fileNum)); +DEFINE_HOOK(OnDeleteSelectedFile, ()); DEFINE_HOOK(OnDeleteAllFiles, ()); DEFINE_HOOK(OnDialogMessage, ()); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index ae8db834d..ef5d1aa25 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -127,6 +127,11 @@ SaveManager::SaveManager() { GameInteractor::Instance->RegisterGameHook( [this]() { this->DeleteAllZeldaFiles(); }); + GameInteractor::Instance->RegisterGameHook([this]() { + int selectedFileNum = CVarGetInteger(CVAR_SETTING("DeleteSelectedSaveFileNum"), 0); + this->DeleteZeldaFile(selectedFileNum - 1 ); + }); + GameInteractor::Instance->RegisterGameHook( [this](uint32_t fileNum) { ThreadPoolWait(); }); diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp index e2bff6154..b507eb1ee 100644 --- a/soh/soh/SohGui/SohMenuSettings.cpp +++ b/soh/soh/SohGui/SohMenuSettings.cpp @@ -187,28 +187,51 @@ void SohMenu::AddMenuSettings() { SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); }) .Options(ButtonOptions().Tooltip("Opens the folder that contains the save and mods folders, etc.")); - AddWidget(path, "Enable Delete All Saves", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_SETTING("EnableDeleteAllSaveFilesButton")) + + AddWidget(path, "Saves", WIDGET_SEPARATOR_TEXT); + auto deleteSaveFilesDisabledFunc = [](WidgetInfo& info) { + info.options->disabled = !CVarGetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); + info.options->disabledTooltip = + "This button is disabled because \"Enable Delete All/Selected Saves\" is turned off."; + }; + AddWidget(path, "Enable Delete All/Selected Saves", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles")) .RaceDisable(false) .Options(CheckboxOptions() - .Tooltip("Turn on to enable the \"Delete All Saves\" button.Turns off automatically " - "when \"Delete All Saves\" is pressed") + .Tooltip("Turn on to enable the Save deletion options below.Turns off automatically " + "when \"Delete All/Selected Saves\" button is pressed") .DefaultValue(false)); AddWidget(path, "Delete All Saves", WIDGET_BUTTON) .RaceDisable(false) - .PreFunc([](WidgetInfo& info) { - info.options->disabled = !CVarGetInteger(CVAR_SETTING("EnableDeleteAllSaveFilesButton"), 0); - info.options->disabledTooltip = - "This button is disabled because \"Enable Delete All Saves\" is turned off."; - }) + .PreFunc(deleteSaveFilesDisabledFunc) .Callback([](WidgetInfo& info) { GameInteractor::Instance->ExecuteHooks(); - CVarSetInteger(CVAR_SETTING("EnableDeleteAllSaveFilesButton"), 0); + CVarSetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); std::reinterpret_pointer_cast( Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) ->Dispatch("reset"); }) - .Options(ButtonOptions().Tooltip("Warning deletes all save files")); + .Options(ButtonOptions().Tooltip("Warning deletes all save files")); + AddWidget(path, "Select Save File To Delete: ", WIDGET_CVAR_SLIDER_INT) + .CVar(CVAR_SETTING("DeleteSelectedSaveFileNum")) + .PreFunc(deleteSaveFilesDisabledFunc) + .Options(IntSliderOptions() + .Min(1) + .Max(3) + .DefaultValue(1) + .Format("File %d ") + .Tooltip("Select which save file to delete.Then press \"Delete Selected Save File\" to delete.")); + AddWidget(path, "Delete Selected Save File", WIDGET_BUTTON) + .RaceDisable(false) + .PreFunc(deleteSaveFilesDisabledFunc) + .Callback([](WidgetInfo& info) { + GameInteractor::Instance->ExecuteHooks(); + CVarSetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); + std::reinterpret_pointer_cast( + Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) + ->Dispatch("reset"); + }) + .Options(ButtonOptions().Tooltip("Warning deletes selected save file")); AddWidget(path, "Boot", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Boot Sequence", WIDGET_CVAR_COMBOBOX) From 564fdce5d46d631f87f5b2a62c4b7fa22e4b13a7 Mon Sep 17 00:00:00 2001 From: Glought <663343+Glought@users.noreply.github.com> Date: Sun, 27 Jul 2025 10:21:33 -0700 Subject: [PATCH 3/4] Removed the need for the "OnDeleteSelectedFile and "OnDeleteAllFiles Hooks. Reworked it to use the SaveManger's "DeleteZeldaFile()" function in the "Delete Selected Save File" and "Delete All Saves" button callback. --- .../game-interactor/GameInteractor_HookTable.h | 2 -- soh/soh/SaveManager.cpp | 14 -------------- soh/soh/SaveManager.h | 2 -- soh/soh/SohGui/SohMenuSettings.cpp | 14 ++++++++++---- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index c8a85aae4..51a6ab5a8 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -47,8 +47,6 @@ DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, va_list or DEFINE_HOOK(OnSaveFile, (int32_t fileNum)); DEFINE_HOOK(OnLoadFile, (int32_t fileNum)); DEFINE_HOOK(OnDeleteFile, (int32_t fileNum)); -DEFINE_HOOK(OnDeleteSelectedFile, ()); -DEFINE_HOOK(OnDeleteAllFiles, ()); DEFINE_HOOK(OnDialogMessage, ()); DEFINE_HOOK(OnPresentTitleCard, ()); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index ef5d1aa25..4b830f846 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -124,14 +124,6 @@ SaveManager::SaveManager() { AddInitFunction(InitFileImpl); - GameInteractor::Instance->RegisterGameHook( - [this]() { this->DeleteAllZeldaFiles(); }); - - GameInteractor::Instance->RegisterGameHook([this]() { - int selectedFileNum = CVarGetInteger(CVAR_SETTING("DeleteSelectedSaveFileNum"), 0); - this->DeleteZeldaFile(selectedFileNum - 1 ); - }); - GameInteractor::Instance->RegisterGameHook( [this](uint32_t fileNum) { ThreadPoolWait(); }); @@ -2379,12 +2371,6 @@ void SaveManager::DeleteZeldaFile(int fileNum) { GameInteractor::Instance->ExecuteHooks(fileNum); } -void SaveManager::DeleteAllZeldaFiles() { - for (int fileNum = 0; fileNum < MaxFiles; fileNum++) { - DeleteZeldaFile(fileNum); - } -} - bool SaveManager::IsRandoFile() { return IS_RANDO; } diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index d89e090cb..6d7ef3b33 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -103,8 +103,6 @@ class SaveManager { void CopyZeldaFile(int from, int to); void DeleteZeldaFile(int fileNum); - void DeleteAllZeldaFiles(); - bool IsRandoFile(); // Use a name of "" to save to an array. You must be in a SaveArray callback. diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp index b507eb1ee..1c8abe980 100644 --- a/soh/soh/SohGui/SohMenuSettings.cpp +++ b/soh/soh/SohGui/SohMenuSettings.cpp @@ -3,6 +3,7 @@ #include "soh/OTRGlobals.h" #include #include "soh/ResourceManagerHelpers.h" +#include "soh/SaveManager.h" #include "UIWidgets.hpp" #include @@ -187,7 +188,7 @@ void SohMenu::AddMenuSettings() { SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); }) .Options(ButtonOptions().Tooltip("Opens the folder that contains the save and mods folders, etc.")); - + AddWidget(path, "Saves", WIDGET_SEPARATOR_TEXT); auto deleteSaveFilesDisabledFunc = [](WidgetInfo& info) { info.options->disabled = !CVarGetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); @@ -205,13 +206,16 @@ void SohMenu::AddMenuSettings() { .RaceDisable(false) .PreFunc(deleteSaveFilesDisabledFunc) .Callback([](WidgetInfo& info) { - GameInteractor::Instance->ExecuteHooks(); + for (int fileNum = 0; fileNum < SaveManager::MaxFiles; fileNum++) { + SaveManager::Instance->DeleteZeldaFile(fileNum); + } + CVarSetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); std::reinterpret_pointer_cast( Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) ->Dispatch("reset"); }) - .Options(ButtonOptions().Tooltip("Warning deletes all save files")); + .Options(ButtonOptions().Tooltip("Warning deletes all save files")); AddWidget(path, "Select Save File To Delete: ", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_SETTING("DeleteSelectedSaveFileNum")) .PreFunc(deleteSaveFilesDisabledFunc) @@ -225,7 +229,9 @@ void SohMenu::AddMenuSettings() { .RaceDisable(false) .PreFunc(deleteSaveFilesDisabledFunc) .Callback([](WidgetInfo& info) { - GameInteractor::Instance->ExecuteHooks(); + int selectedFileNum = CVarGetInteger(CVAR_SETTING("DeleteSelectedSaveFileNum"), 0); + SaveManager::Instance->DeleteZeldaFile(selectedFileNum - 1); + CVarSetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); std::reinterpret_pointer_cast( Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) From 5bf813d706d8b7340187fc457ec402f519b1b477 Mon Sep 17 00:00:00 2001 From: Glought <663343+Glought@users.noreply.github.com> Date: Sun, 27 Jul 2025 11:12:23 -0700 Subject: [PATCH 4/4] Renamed "Enable Delete All/Selected Saves" Checkbox to "Enable Save Deletion Options" Renamed the "EnableDeleteAllSelectedSaveFiles" CVar to "EnableSaveDeletionOptions" --- soh/soh/SohGui/SohMenuSettings.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/soh/soh/SohGui/SohMenuSettings.cpp b/soh/soh/SohGui/SohMenuSettings.cpp index 1c8abe980..9710ce472 100644 --- a/soh/soh/SohGui/SohMenuSettings.cpp +++ b/soh/soh/SohGui/SohMenuSettings.cpp @@ -191,15 +191,14 @@ void SohMenu::AddMenuSettings() { AddWidget(path, "Saves", WIDGET_SEPARATOR_TEXT); auto deleteSaveFilesDisabledFunc = [](WidgetInfo& info) { - info.options->disabled = !CVarGetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); - info.options->disabledTooltip = - "This button is disabled because \"Enable Delete All/Selected Saves\" is turned off."; + info.options->disabled = !CVarGetInteger(CVAR_SETTING("EnableSaveDeletionOptions"), 0); + info.options->disabledTooltip = "This is disabled because \"Enable Save Deletion Options\" is turned off."; }; - AddWidget(path, "Enable Delete All/Selected Saves", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles")) + AddWidget(path, "Enable Save Deletion Options", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_SETTING("EnableSaveDeletionOptions")) .RaceDisable(false) .Options(CheckboxOptions() - .Tooltip("Turn on to enable the Save deletion options below.Turns off automatically " + .Tooltip("Turn on to enable the save deletion options below.Turns off automatically " "when \"Delete All/Selected Saves\" button is pressed") .DefaultValue(false)); AddWidget(path, "Delete All Saves", WIDGET_BUTTON) @@ -210,7 +209,7 @@ void SohMenu::AddMenuSettings() { SaveManager::Instance->DeleteZeldaFile(fileNum); } - CVarSetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); + CVarSetInteger(CVAR_SETTING("EnableSaveDeletionOptions"), 0); std::reinterpret_pointer_cast( Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) ->Dispatch("reset"); @@ -232,7 +231,7 @@ void SohMenu::AddMenuSettings() { int selectedFileNum = CVarGetInteger(CVAR_SETTING("DeleteSelectedSaveFileNum"), 0); SaveManager::Instance->DeleteZeldaFile(selectedFileNum - 1); - CVarSetInteger(CVAR_SETTING("EnableDeleteAllSelectedSaveFiles"), 0); + CVarSetInteger(CVAR_SETTING("EnableSaveDeletionOptions"), 0); std::reinterpret_pointer_cast( Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) ->Dispatch("reset");