From 0683d965e9c77f98e48676de2ee40a6e8ac9b836 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Sat, 11 Jan 2025 21:14:36 +0100 Subject: [PATCH 01/10] Proof of Concept --- soh/soh/Enhancements/mod_menu.cpp | 135 ++++++++++++++++++++++++++++++ soh/soh/Enhancements/mod_menu.h | 14 ++++ soh/soh/OTRGlobals.cpp | 5 +- soh/soh/SohGui.cpp | 7 +- soh/soh/SohMenuBar.cpp | 9 ++ 5 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 soh/soh/Enhancements/mod_menu.cpp create mode 100644 soh/soh/Enhancements/mod_menu.h diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp new file mode 100644 index 000000000..609edf4d4 --- /dev/null +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -0,0 +1,135 @@ +#include "mod_menu.h" +#include "utils/StringHelper.h" +#include +#include "soh/OTRGlobals.h" +#include +#include + +std::shared_ptr GetArchiveManager() { + return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager(); +} + +std::map modFiles; + +bool is_enabled(const std::pair& p) { + return p.second; +} + +std::vector GetEnabledModFiles() { + std::map enabledMods; + + std::copy_if(modFiles.begin(), modFiles.end(), std::inserter(enabledMods, enabledMods.begin()), is_enabled); + + auto ks = std::views::keys(enabledMods); + std::vector keys{ ks.begin(), ks.end() }; + + return keys; +} + +bool is_disabled(const std::pair& p) { + return !p.second; +} + +std::vector GetDisabledModFiles() { + std::map disabledMods; + + std::copy_if(modFiles.begin(), modFiles.end(), std::inserter(disabledMods, disabledMods.begin()), is_disabled); + + auto ks = std::views::keys(disabledMods); + std::vector keys{ ks.begin(), ks.end() }; + + return keys; +} + +void UpdateModFiles() { + modFiles.clear(); + std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); + if (modsPath.length() > 0 && std::filesystem::exists(modsPath)) { + if (std::filesystem::is_directory(modsPath)) { + for (const std::filesystem::directory_entry& p : std::filesystem::recursive_directory_iterator(modsPath, std::filesystem::directory_options::follow_directory_symlink)) { + std::string extension = p.path().extension().string(); + if ( + StringHelper::IEquals(extension, ".otr") || + StringHelper::IEquals(extension, ".mpq") || + StringHelper::IEquals(extension, ".o2r") || + StringHelper::IEquals(extension, ".zip") + ) { + modFiles.emplace(p.path().generic_string(), false); + } + } + } + } + + /* + std::sort(modFiles.begin(), modFiles.end(), [](const std::string& a, const std::string& b) { + return std::lexicographical_compare( + a.begin(), a.end(), + b.begin(), b.end(), + [](char c1, char c2) { + return std::tolower(c1) < std::tolower(c2); + } + ); + }); + */ +} + +void ModMenuWindow::DrawElement() { + if (ImGui::Button("Update")) { + UpdateModFiles(); + } + + if (ImGui::BeginTable("tableMods", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) { + ImGui::TableSetupColumn("Enabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f); + ImGui::TableSetupColumn("Disabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f); + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::TableHeadersRow(); + ImGui::PopItemFlag(); + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + + if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { + std::vector enabledMods = GetEnabledModFiles(); + if (!enabledMods.empty()) { + for (std::string file : enabledMods) { + if (ImGui::Button(("Disable##" + file).c_str())) { + modFiles[file] = false; + Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->RemoveArchive(file); + } + ImGui::SameLine(); + ImGui::Text(file.c_str()); + } + } else { + ImGui::Text(""); + } + + ImGui::EndChild(); + } + + ImGui::TableNextColumn(); + + if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) { + std::vector disabledMods = GetDisabledModFiles(); + if (!disabledMods.empty()) { + for (std::string file : disabledMods) { + if (ImGui::Button(("Enable##" + file).c_str())) { + modFiles[file] = true; + Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->AddArchive(file); + } + ImGui::SameLine(); + ImGui::Text(file.c_str()); + } + } else { + ImGui::Text(""); + } + + ImGui::EndChild(); + } + + ImGui::EndTable(); + } +} + +void ModMenuWindow::InitElement() { + UpdateModFiles(); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/mod_menu.h b/soh/soh/Enhancements/mod_menu.h new file mode 100644 index 000000000..0a69e0769 --- /dev/null +++ b/soh/soh/Enhancements/mod_menu.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#ifdef __cplusplus +class ModMenuWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + + void InitElement() override; + void DrawElement() override; + void UpdateElement() override {}; +}; +#endif \ No newline at end of file diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7856de88f..867fdecc3 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -265,7 +265,7 @@ OTRGlobals::OTRGlobals() { std::string mqPath = Ship::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); - } + } std::string ootPath = Ship::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); if (std::filesystem::exists(ootPath)) { OTRFiles.push_back(ootPath); @@ -274,6 +274,7 @@ OTRGlobals::OTRGlobals() { if (std::filesystem::exists(sohOtrPath)) { OTRFiles.push_back(sohOtrPath); } + /* std::string patchesPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); std::vector patchOTRs = {}; if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { @@ -297,7 +298,9 @@ OTRGlobals::OTRGlobals() { } ); }); + OTRFiles.insert(OTRFiles.end(), patchOTRs.begin(), patchOTRs.end()); + */ std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, diff --git a/soh/soh/SohGui.cpp b/soh/soh/SohGui.cpp index 6cc4e1de6..f4c483211 100644 --- a/soh/soh/SohGui.cpp +++ b/soh/soh/SohGui.cpp @@ -36,6 +36,7 @@ #include "Enhancements/debugger/MessageViewer.h" #include "soh/Notification/Notification.h" #include "soh/Enhancements/TimeDisplay/TimeDisplay.h" +#include "soh/Enhancements/mod_menu.h" bool isBetaQuestEnabled = false; @@ -110,6 +111,7 @@ namespace SohGui { std::shared_ptr mGfxDebuggerWindow; std::shared_ptr mInputEditorWindow; + std::shared_ptr mModMenuWindow; std::shared_ptr mAudioEditorWindow; std::shared_ptr mInputViewer; std::shared_ptr mInputViewerSettings; @@ -170,6 +172,8 @@ namespace SohGui { SPDLOG_ERROR("Could not find input editor window"); } + mModMenuWindow = std::make_shared(CVAR_WINDOW("ModMenu"), "Mod Menu", ImVec2(820, 630)); + gui->AddGuiWindow(mModMenuWindow); mAudioEditorWindow = std::make_shared(CVAR_WINDOW("AudioEditor"), "Audio Editor", ImVec2(820, 630)); gui->AddGuiWindow(mAudioEditorWindow); mInputViewer = std::make_shared(CVAR_WINDOW("InputViewer"), "Input Viewer"); @@ -227,8 +231,9 @@ namespace SohGui { void Destroy() { auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); gui->RemoveAllGuiWindows(); - + mNotificationWindow = nullptr; + mModMenuWindow = nullptr; mModalWindow = nullptr; mAdvancedResolutionSettingsWindow = nullptr; mRandomizerSettingsWindow = nullptr; diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index f3a9557c2..562660dbf 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -44,6 +44,7 @@ #include "Enhancements/timesplits/TimeSplits.h" #include "Enhancements/randomizer/Plandomizer.h" #include "Enhancements/TimeDisplay/TimeDisplay.h" +#include "Enhancements/mod_menu.h" // FA icons are kind of wonky, if they worked how I expected them to the "+ 2.0f" wouldn't be needed, but // they don't work how I expect them to so I added that because it looked good when I eyeballed it @@ -608,6 +609,7 @@ extern std::shared_ptr mCosmeticsEditorWindow; extern std::shared_ptr mGameplayStatsWindow; extern std::shared_ptr mTimeSplitWindow; extern std::shared_ptr mTimeDisplayWindow; +extern std::shared_ptr mModMenuWindow; void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Enhancements")) @@ -1769,6 +1771,13 @@ void DrawEnhancementsMenu() { } } } + + if (mModMenuWindow) { + if (ImGui::Button(GetWindowButtonText("Mod Menu", CVarGetInteger(CVAR_WINDOW("ModMenu"), 0)).c_str(), ImVec2(-1.0f, 0.0f))) { + mModMenuWindow->ToggleVisibility(); + } + } + ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); From b45563da60750e1c2c3aa75aff189ce8b968acd2 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:22:27 +0100 Subject: [PATCH 02/10] Fixed saving/loading --- soh/soh/Enhancements/mod_menu.cpp | 55 ++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index 609edf4d4..7b7cbaa8f 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -2,8 +2,10 @@ #include "utils/StringHelper.h" #include #include "soh/OTRGlobals.h" +#include "soh/resource/type/Skeleton.h" #include #include +extern "C" void gfx_texture_cache_clear(); std::shared_ptr GetArchiveManager() { return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager(); @@ -11,6 +13,34 @@ std::shared_ptr GetArchiveManager() { std::map modFiles; +#define CVAR_ENABLED_MODS_NAME CVAR_GENERAL("EnabledMods") +#define CVAR_ENABLED_MODS_DEFAULT "" +#define CVAR_ENABLED_MODS_VALUE CVarGetString(CVAR_ENABLED_MODS_NAME, CVAR_ENABLED_MODS_DEFAULT) + +#define SEPARATOR "|" + +void SaveEnabledModsCVarValue() { + std::string s = ""; + + for (auto& [modPath, enabled] : modFiles) { + if (enabled) { + s += modPath + SEPARATOR; + } + } + + //remove trailing separator if present + if (s.length() != 0) { + s.pop_back(); + } + + CVarSetString(CVAR_ENABLED_MODS_NAME, s.c_str()); +} + +std::vector GetEnabledModsFromCVar() { + std::string enabledModsCVarValue = CVAR_ENABLED_MODS_VALUE; + return StringHelper::Split(enabledModsCVarValue, SEPARATOR); +} + bool is_enabled(const std::pair& p) { return p.second; } @@ -41,8 +71,9 @@ std::vector GetDisabledModFiles() { return keys; } -void UpdateModFiles() { +void UpdateModFiles(bool init = false) { modFiles.clear(); + std::vector enabledMods = GetEnabledModsFromCVar(); std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); if (modsPath.length() > 0 && std::filesystem::exists(modsPath)) { if (std::filesystem::is_directory(modsPath)) { @@ -54,7 +85,12 @@ void UpdateModFiles() { StringHelper::IEquals(extension, ".o2r") || StringHelper::IEquals(extension, ".zip") ) { - modFiles.emplace(p.path().generic_string(), false); + std::string path = p.path().generic_string(); + bool shouldBeEnabled = std::find(enabledMods.begin(), enabledMods.end(), path) != enabledMods.end(); + if (init && shouldBeEnabled) { + GetArchiveManager()->AddArchive(path); + } + modFiles.emplace(path, shouldBeEnabled); } } } @@ -73,6 +109,13 @@ void UpdateModFiles() { */ } +void AfterModChange() { + SaveEnabledModsCVarValue(); + gfx_texture_cache_clear(); + SOH::SkeletonPatcher::UpdateSkeletons(); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); +} + void ModMenuWindow::DrawElement() { if (ImGui::Button("Update")) { UpdateModFiles(); @@ -94,7 +137,8 @@ void ModMenuWindow::DrawElement() { for (std::string file : enabledMods) { if (ImGui::Button(("Disable##" + file).c_str())) { modFiles[file] = false; - Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->RemoveArchive(file); + GetArchiveManager()->RemoveArchive(file); + AfterModChange(); } ImGui::SameLine(); ImGui::Text(file.c_str()); @@ -114,7 +158,8 @@ void ModMenuWindow::DrawElement() { for (std::string file : disabledMods) { if (ImGui::Button(("Enable##" + file).c_str())) { modFiles[file] = true; - Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->AddArchive(file); + GetArchiveManager()->AddArchive(file); + AfterModChange(); } ImGui::SameLine(); ImGui::Text(file.c_str()); @@ -131,5 +176,5 @@ void ModMenuWindow::DrawElement() { } void ModMenuWindow::InitElement() { - UpdateModFiles(); + UpdateModFiles(true); } \ No newline at end of file From 1e33244fbf31d44e8c62edbd66e5cd28a264ad44 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:48:29 +0100 Subject: [PATCH 03/10] Switch sides & add arrow buttons --- soh/soh/Enhancements/mod_menu.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index 7b7cbaa8f..5c68d550a 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -122,8 +122,8 @@ void ModMenuWindow::DrawElement() { } if (ImGui::BeginTable("tableMods", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) { - ImGui::TableSetupColumn("Enabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f); ImGui::TableSetupColumn("Disabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f); + ImGui::TableSetupColumn("Enabled Mods", ImGuiTableColumnFlags_WidthStretch, 200.0f); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::TableHeadersRow(); ImGui::PopItemFlag(); @@ -131,13 +131,13 @@ void ModMenuWindow::DrawElement() { ImGui::TableNextColumn(); - if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { - std::vector enabledMods = GetEnabledModFiles(); - if (!enabledMods.empty()) { - for (std::string file : enabledMods) { - if (ImGui::Button(("Disable##" + file).c_str())) { - modFiles[file] = false; - GetArchiveManager()->RemoveArchive(file); + if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) { + std::vector disabledMods = GetDisabledModFiles(); + if (!disabledMods.empty()) { + for (std::string file : disabledMods) { + if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Right)) { + modFiles[file] = true; + GetArchiveManager()->AddArchive(file); AfterModChange(); } ImGui::SameLine(); @@ -152,13 +152,13 @@ void ModMenuWindow::DrawElement() { ImGui::TableNextColumn(); - if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) { - std::vector disabledMods = GetDisabledModFiles(); - if (!disabledMods.empty()) { - for (std::string file : disabledMods) { - if (ImGui::Button(("Enable##" + file).c_str())) { - modFiles[file] = true; - GetArchiveManager()->AddArchive(file); + if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { + std::vector enabledMods = GetEnabledModFiles(); + if (!enabledMods.empty()) { + for (std::string file : enabledMods) { + if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Left)) { + modFiles[file] = false; + GetArchiveManager()->RemoveArchive(file); AfterModChange(); } ImGui::SameLine(); From 9a8b87d431b03f30b11336b746410b7d27a7011a Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:55:38 +0100 Subject: [PATCH 04/10] Update mod_menu.cpp --- soh/soh/Enhancements/mod_menu.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index 5c68d550a..b4f415ab1 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -116,6 +116,10 @@ void AfterModChange() { Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); } +void DrawModInfo(std::string file) { + ImGui::Text(file.c_str()); +} + void ModMenuWindow::DrawElement() { if (ImGui::Button("Update")) { UpdateModFiles(); @@ -141,7 +145,7 @@ void ModMenuWindow::DrawElement() { AfterModChange(); } ImGui::SameLine(); - ImGui::Text(file.c_str()); + DrawModInfo(file); } } else { ImGui::Text(""); @@ -162,7 +166,7 @@ void ModMenuWindow::DrawElement() { AfterModChange(); } ImGui::SameLine(); - ImGui::Text(file.c_str()); + DrawModInfo(file); } } else { ImGui::Text(""); From 6277194c48e7c991404e8ee0e2504cb5ee2f611b Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Mon, 27 Jan 2025 20:45:55 +0100 Subject: [PATCH 05/10] Remove old mod loading code --- soh/soh/OTRGlobals.cpp | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index ffc80a137..d030e08f0 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -263,7 +263,7 @@ const char* constCameraStrings[] = { OTRGlobals::OTRGlobals() { std::vector OTRFiles; std::string mqPath = Ship::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); - if (std::filesystem::exists(mqPath)) { + if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); } std::string ootPath = Ship::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); @@ -274,33 +274,7 @@ OTRGlobals::OTRGlobals() { if (std::filesystem::exists(sohOtrPath)) { OTRFiles.push_back(sohOtrPath); } - /* - std::string patchesPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); - std::vector patchOTRs = {}; - if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { - if (std::filesystem::is_directory(patchesPath)) { - for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath, std::filesystem::directory_options::follow_directory_symlink)) { - if (StringHelper::IEquals(p.path().extension().string(), ".otr") || - StringHelper::IEquals(p.path().extension().string(), ".mpq") || - StringHelper::IEquals(p.path().extension().string(), ".o2r") || - StringHelper::IEquals(p.path().extension().string(), ".zip")) { - patchOTRs.push_back(p.path().generic_string()); - } - } - } - } - std::sort(patchOTRs.begin(), patchOTRs.end(), [](const std::string& a, const std::string& b) { - return std::lexicographical_compare( - a.begin(), a.end(), - b.begin(), b.end(), - [](char c1, char c2) { - return std::tolower(c1) < std::tolower(c2); - } - ); - }); - OTRFiles.insert(OTRFiles.end(), patchOTRs.begin(), patchOTRs.end()); - */ std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, From ea4340cab5f8b19f0843e935daa4806f86f2a3b3 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Mon, 27 Jan 2025 21:33:41 +0100 Subject: [PATCH 06/10] Small cleanup --- soh/soh/Enhancements/ExtraTraps.cpp | 2 +- soh/soh/Enhancements/mod_menu.cpp | 65 ++++++++++++++++------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/soh/soh/Enhancements/ExtraTraps.cpp b/soh/soh/Enhancements/ExtraTraps.cpp index 27d64d1c7..196fc63f4 100644 --- a/soh/soh/Enhancements/ExtraTraps.cpp +++ b/soh/soh/Enhancements/ExtraTraps.cpp @@ -65,7 +65,7 @@ std::vector getEnabledAddTraps () { }; static void RollRandomTrap(uint32_t seed) { - uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); + uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); Random_Init(finalSeed); roll = RandomElement(getEnabledAddTraps()); diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index b4f415ab1..82b05ba9f 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -117,9 +117,44 @@ void AfterModChange() { } void DrawModInfo(std::string file) { + ImGui::SameLine(); ImGui::Text(file.c_str()); } +void DrawEnabledMods() { + std::vector enabledMods = GetEnabledModFiles(); + if (enabledMods.empty()) { + ImGui::Text(""); + return; + } + + for (std::string file : enabledMods) { + if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Left)) { + modFiles[file] = false; + GetArchiveManager()->RemoveArchive(file); + AfterModChange(); + } + DrawModInfo(file); + } +} + +void DrawDisabledMods() { + std::vector disabledMods = GetDisabledModFiles(); + if (disabledMods.empty()) { + ImGui::Text(""); + return; + } + + for (std::string file : disabledMods) { + if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Right)) { + modFiles[file] = true; + GetArchiveManager()->AddArchive(file); + AfterModChange(); + } + DrawModInfo(file); + } +} + void ModMenuWindow::DrawElement() { if (ImGui::Button("Update")) { UpdateModFiles(); @@ -136,20 +171,7 @@ void ModMenuWindow::DrawElement() { ImGui::TableNextColumn(); if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) { - std::vector disabledMods = GetDisabledModFiles(); - if (!disabledMods.empty()) { - for (std::string file : disabledMods) { - if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Right)) { - modFiles[file] = true; - GetArchiveManager()->AddArchive(file); - AfterModChange(); - } - ImGui::SameLine(); - DrawModInfo(file); - } - } else { - ImGui::Text(""); - } + DrawDisabledMods(); ImGui::EndChild(); } @@ -157,20 +179,7 @@ void ModMenuWindow::DrawElement() { ImGui::TableNextColumn(); if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { - std::vector enabledMods = GetEnabledModFiles(); - if (!enabledMods.empty()) { - for (std::string file : enabledMods) { - if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Left)) { - modFiles[file] = false; - GetArchiveManager()->RemoveArchive(file); - AfterModChange(); - } - ImGui::SameLine(); - DrawModInfo(file); - } - } else { - ImGui::Text(""); - } + DrawEnabledMods(); ImGui::EndChild(); } From a20250d3bc7dc4c3c501a15f69e6a8195192acab Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Mon, 5 May 2025 17:35:17 +0200 Subject: [PATCH 07/10] Post-merge fixes --- soh/soh/Enhancements/mod_menu.cpp | 15 ++++++++++++--- soh/soh/SohGui/SohMenuEnhancements.cpp | 8 ++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index 82b05ba9f..1e288d7ce 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -1,10 +1,12 @@ #include "mod_menu.h" #include "utils/StringHelper.h" #include +#include "soh/SohGui/SohGui.hpp" #include "soh/OTRGlobals.h" #include "soh/resource/type/Skeleton.h" #include #include + extern "C" void gfx_texture_cache_clear(); std::shared_ptr GetArchiveManager() { @@ -17,6 +19,9 @@ std::map modFiles; #define CVAR_ENABLED_MODS_DEFAULT "" #define CVAR_ENABLED_MODS_VALUE CVarGetString(CVAR_ENABLED_MODS_NAME, CVAR_ENABLED_MODS_DEFAULT) +// "|" was chosen as the separator due to +// it being an invalid character in NTFS +// and being rarely used in ext4 #define SEPARATOR "|" void SaveEnabledModsCVarValue() { @@ -129,7 +134,7 @@ void DrawEnabledMods() { } for (std::string file : enabledMods) { - if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Left)) { + if (UIWidgets::StateButton(file.c_str(), ICON_FA_ARROW_LEFT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { modFiles[file] = false; GetArchiveManager()->RemoveArchive(file); AfterModChange(); @@ -146,7 +151,7 @@ void DrawDisabledMods() { } for (std::string file : disabledMods) { - if (ImGui::ArrowButton(file.c_str(), ImGuiDir_Right)) { + if (UIWidgets::StateButton(file.c_str(), ICON_FA_ARROW_RIGHT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { modFiles[file] = true; GetArchiveManager()->AddArchive(file); AfterModChange(); @@ -156,7 +161,9 @@ void DrawDisabledMods() { } void ModMenuWindow::DrawElement() { - if (ImGui::Button("Update")) { + ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0)); + + if (UIWidgets::Button("Update", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) { UpdateModFiles(); } @@ -186,6 +193,8 @@ void ModMenuWindow::DrawElement() { ImGui::EndTable(); } + + ImGui::EndDisabled(); } void ModMenuWindow::InitElement() { diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 0b78892d4..9bfd62511 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1758,6 +1758,14 @@ void SohMenu::AddMenuEnhancements() { .CVar(timer.timeEnable) .Callback([](WidgetInfo& info) { TimeDisplayUpdateDisplayOptions(); }); } + + // Mod Menu + path.sidebarName = "Mod Menu"; + AddSidebarEntry("Enhancements", path.sidebarName, 1); + AddWidget(path, "Toggle Mod Menu Window", WIDGET_WINDOW_BUTTON) + .CVar(CVAR_WINDOW("ModMenu")) + .WindowName("Mod Menu") + .Options(WindowButtonOptions().Tooltip("Enables the separate Mod Menu Window.")); } } // namespace SohGui From 212799cd1603eac5dcf2964fbad0a94ac57bd057 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Sun, 20 Jul 2025 01:33:40 +0200 Subject: [PATCH 08/10] Update mod_menu.cpp --- soh/soh/Enhancements/mod_menu.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index 1e288d7ce..e77b04eee 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -117,7 +117,7 @@ void UpdateModFiles(bool init = false) { void AfterModChange() { SaveEnabledModsCVarValue(); gfx_texture_cache_clear(); - SOH::SkeletonPatcher::UpdateSkeletons(); + SOH::SkeletonPatcher::ClearSkeletons(); Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); } @@ -160,11 +160,16 @@ void DrawDisabledMods() { } } +const std::string updateButtonTooltip = "Re-check the mods folder for new files"; + void ModMenuWindow::DrawElement() { ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0)); if (UIWidgets::Button("Update", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) { + UIWidgets::Tooltip(updateButtonTooltip.c_str()); UpdateModFiles(); + } else { + UIWidgets::Tooltip(updateButtonTooltip.c_str()); } if (ImGui::BeginTable("tableMods", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) { From 0e92e82493ca0a9b9da2222ec6b5f48540d5ebd3 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Thu, 31 Jul 2025 21:11:02 +0200 Subject: [PATCH 09/10] Lots of changes --- soh/soh/Enhancements/mod_menu.cpp | 193 ++++++++++++++++++------------ 1 file changed, 116 insertions(+), 77 deletions(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index e77b04eee..9715fcf10 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -6,14 +6,10 @@ #include "soh/resource/type/Skeleton.h" #include #include +#include -extern "C" void gfx_texture_cache_clear(); - -std::shared_ptr GetArchiveManager() { - return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager(); -} - -std::map modFiles; +std::vector enabledModFiles; +std::vector disabledModFiles; #define CVAR_ENABLED_MODS_NAME CVAR_GENERAL("EnabledMods") #define CVAR_ENABLED_MODS_DEFAULT "" @@ -22,15 +18,20 @@ std::map modFiles; // "|" was chosen as the separator due to // it being an invalid character in NTFS // and being rarely used in ext4 +// it is also an ASCII character +// improving portability + +// if being an ASCII character is not a requirement, +// other possible candidates include: +// - U+FFFF: non-character +// - any private use character #define SEPARATOR "|" -void SaveEnabledModsCVarValue() { +void SetEnabledModsCVarValue() { std::string s = ""; - for (auto& [modPath, enabled] : modFiles) { - if (enabled) { - s += modPath + SEPARATOR; - } + for (auto& modPath : enabledModFiles) { + s += modPath + SEPARATOR; } //remove trailing separator if present @@ -46,38 +47,19 @@ std::vector GetEnabledModsFromCVar() { return StringHelper::Split(enabledModsCVarValue, SEPARATOR); } -bool is_enabled(const std::pair& p) { - return p.second; +std::vector& GetModFiles(bool enabled) { + return enabled ? enabledModFiles : disabledModFiles; } -std::vector GetEnabledModFiles() { - std::map enabledMods; - - std::copy_if(modFiles.begin(), modFiles.end(), std::inserter(enabledMods, enabledMods.begin()), is_enabled); - - auto ks = std::views::keys(enabledMods); - std::vector keys{ ks.begin(), ks.end() }; - - return keys; -} - -bool is_disabled(const std::pair& p) { - return !p.second; -} - -std::vector GetDisabledModFiles() { - std::map disabledMods; - - std::copy_if(modFiles.begin(), modFiles.end(), std::inserter(disabledMods, disabledMods.begin()), is_disabled); - - auto ks = std::views::keys(disabledMods); - std::vector keys{ ks.begin(), ks.end() }; - - return keys; +std::shared_ptr GetArchiveManager() { + return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager(); } void UpdateModFiles(bool init = false) { - modFiles.clear(); + if (init) { + enabledModFiles.clear(); + } + disabledModFiles.clear(); std::vector enabledMods = GetEnabledModsFromCVar(); std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); if (modsPath.length() > 0 && std::filesystem::exists(modsPath)) { @@ -85,24 +67,43 @@ void UpdateModFiles(bool init = false) { for (const std::filesystem::directory_entry& p : std::filesystem::recursive_directory_iterator(modsPath, std::filesystem::directory_options::follow_directory_symlink)) { std::string extension = p.path().extension().string(); if ( +#ifndef EXCLUDE_MPQ_SUPPORT StringHelper::IEquals(extension, ".otr") || StringHelper::IEquals(extension, ".mpq") || +#endif StringHelper::IEquals(extension, ".o2r") || StringHelper::IEquals(extension, ".zip") ) { std::string path = p.path().generic_string(); bool shouldBeEnabled = std::find(enabledMods.begin(), enabledMods.end(), path) != enabledMods.end(); - if (init && shouldBeEnabled) { - GetArchiveManager()->AddArchive(path); + + if (shouldBeEnabled) { + if (init) { + enabledModFiles.push_back(path); + GetArchiveManager()->AddArchive(path); + } + } else { + disabledModFiles.push_back(path); } - modFiles.emplace(path, shouldBeEnabled); } } } } +} +extern "C" void gfx_texture_cache_clear(); + +void AfterModChange() { + SetEnabledModsCVarValue(); + //TODO: runtime changes /* - std::sort(modFiles.begin(), modFiles.end(), [](const std::string& a, const std::string& b) { + gfx_texture_cache_clear(); + SOH::SkeletonPatcher::ClearSkeletons(); + */ + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); + + //disabled mods are always sorted + std::sort(disabledModFiles.begin(), disabledModFiles.end(), [](const std::string& a, const std::string& b) { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end(), @@ -111,14 +112,24 @@ void UpdateModFiles(bool init = false) { } ); }); - */ } -void AfterModChange() { - SaveEnabledModsCVarValue(); - gfx_texture_cache_clear(); - SOH::SkeletonPatcher::ClearSkeletons(); - Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); +void EnableMod(std::string file) { + disabledModFiles.erase(std::find(disabledModFiles.begin(), disabledModFiles.end(), file)); + enabledModFiles.insert(enabledModFiles.begin(), file); + + //TODO: runtime changes + //GetArchiveManager()->AddArchive(file); + AfterModChange(); +} + +void DisableMod(std::string file) { + enabledModFiles.erase(std::find(enabledModFiles.begin(), enabledModFiles.end(), file)); + disabledModFiles.insert(disabledModFiles.begin(), file); + + //TODO: runtime changes + //GetArchiveManager()->RemoveArchive(file); + AfterModChange(); } void DrawModInfo(std::string file) { @@ -126,45 +137,73 @@ void DrawModInfo(std::string file) { ImGui::Text(file.c_str()); } -void DrawEnabledMods() { - std::vector enabledMods = GetEnabledModFiles(); - if (enabledMods.empty()) { - ImGui::Text(""); +void DrawMods(bool enabled) { + std::vector& selectedModFiles = GetModFiles(enabled); + if (selectedModFiles.empty()) { return; } - for (std::string file : enabledMods) { - if (UIWidgets::StateButton(file.c_str(), ICON_FA_ARROW_LEFT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { - modFiles[file] = false; - GetArchiveManager()->RemoveArchive(file); - AfterModChange(); + bool madeAnyChange = false; + int switchFromIndex = -1; + int switchToIndex = -1; + + for (int i = 0; i < selectedModFiles.size(); i += 1) { + std::string file = selectedModFiles[i]; + if (UIWidgets::StateButton((file + "_left_right").c_str(), enabled ? ICON_FA_ARROW_LEFT : ICON_FA_ARROW_RIGHT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { + if (enabled) { + DisableMod(file); + } else { + EnableMod(file); + } } + + //it's not relevant to reorder disabled mods + if (enabled) { + ImGui::SameLine(); + if (i == 0) { + ImGui::BeginDisabled(); + } + if (UIWidgets::StateButton((file + "_up").c_str(), ICON_FA_ARROW_UP, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { + madeAnyChange = true; + switchFromIndex = i; + switchToIndex = i - 1; + } + if (i == 0) { + ImGui::EndDisabled(); + } + + ImGui::SameLine(); + if (i == selectedModFiles.size() - 1) { + ImGui::BeginDisabled(); + } + if (UIWidgets::StateButton((file + "_down").c_str(), ICON_FA_ARROW_DOWN, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { + madeAnyChange = true; + switchFromIndex = i; + switchToIndex = i + 1; + } + if (i == selectedModFiles.size() - 1) { + ImGui::EndDisabled(); + } + } + DrawModInfo(file); } -} -void DrawDisabledMods() { - std::vector disabledMods = GetDisabledModFiles(); - if (disabledMods.empty()) { - ImGui::Text(""); - return; - } - - for (std::string file : disabledMods) { - if (UIWidgets::StateButton(file.c_str(), ICON_FA_ARROW_RIGHT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { - modFiles[file] = true; - GetArchiveManager()->AddArchive(file); - AfterModChange(); - } - DrawModInfo(file); + if (madeAnyChange) { + std::iter_swap(selectedModFiles.begin() + switchFromIndex, selectedModFiles.begin() + switchToIndex); + AfterModChange(); } } -const std::string updateButtonTooltip = "Re-check the mods folder for new files"; - void ModMenuWindow::DrawElement() { ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0)); + const ImVec4 yellow = ImVec4(1, 1, 0, 1); + + ImGui::TextColored(yellow, "Mods are currently not reloaded at runtime.\nClose and re-open Ship for the changes to take effect."); + + const std::string updateButtonTooltip = "Re-check the mods folder for new files"; + if (UIWidgets::Button("Update", UIWidgets::ButtonOptions().Size(ImVec2(250.0f, 0.0f)).Color(THEME_COLOR))) { UIWidgets::Tooltip(updateButtonTooltip.c_str()); UpdateModFiles(); @@ -183,7 +222,7 @@ void ModMenuWindow::DrawElement() { ImGui::TableNextColumn(); if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) { - DrawDisabledMods(); + DrawMods(false); ImGui::EndChild(); } @@ -191,7 +230,7 @@ void ModMenuWindow::DrawElement() { ImGui::TableNextColumn(); if (ImGui::BeginChild("Enabled Mods", ImVec2(0, -8))) { - DrawEnabledMods(); + DrawMods(true); ImGui::EndChild(); } From 0ccd0cbe3dacd05f5b1ce7f1a8aa295378286cf3 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Thu, 31 Jul 2025 21:23:42 +0200 Subject: [PATCH 10/10] clang format --- soh/soh/Enhancements/mod_menu.cpp | 47 +++++++++++++++---------------- soh/soh/Enhancements/mod_menu.h | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/soh/soh/Enhancements/mod_menu.cpp b/soh/soh/Enhancements/mod_menu.cpp index 9715fcf10..5ffe64744 100644 --- a/soh/soh/Enhancements/mod_menu.cpp +++ b/soh/soh/Enhancements/mod_menu.cpp @@ -34,7 +34,7 @@ void SetEnabledModsCVarValue() { s += modPath + SEPARATOR; } - //remove trailing separator if present + // remove trailing separator if present if (s.length() != 0) { s.pop_back(); } @@ -64,16 +64,14 @@ void UpdateModFiles(bool init = false) { std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName); if (modsPath.length() > 0 && std::filesystem::exists(modsPath)) { if (std::filesystem::is_directory(modsPath)) { - for (const std::filesystem::directory_entry& p : std::filesystem::recursive_directory_iterator(modsPath, std::filesystem::directory_options::follow_directory_symlink)) { + for (const std::filesystem::directory_entry& p : std::filesystem::recursive_directory_iterator( + modsPath, std::filesystem::directory_options::follow_directory_symlink)) { std::string extension = p.path().extension().string(); if ( #ifndef EXCLUDE_MPQ_SUPPORT - StringHelper::IEquals(extension, ".otr") || - StringHelper::IEquals(extension, ".mpq") || + StringHelper::IEquals(extension, ".otr") || StringHelper::IEquals(extension, ".mpq") || #endif - StringHelper::IEquals(extension, ".o2r") || - StringHelper::IEquals(extension, ".zip") - ) { + StringHelper::IEquals(extension, ".o2r") || StringHelper::IEquals(extension, ".zip")) { std::string path = p.path().generic_string(); bool shouldBeEnabled = std::find(enabledMods.begin(), enabledMods.end(), path) != enabledMods.end(); @@ -95,22 +93,17 @@ extern "C" void gfx_texture_cache_clear(); void AfterModChange() { SetEnabledModsCVarValue(); - //TODO: runtime changes + // TODO: runtime changes /* gfx_texture_cache_clear(); SOH::SkeletonPatcher::ClearSkeletons(); */ Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); - //disabled mods are always sorted + // disabled mods are always sorted std::sort(disabledModFiles.begin(), disabledModFiles.end(), [](const std::string& a, const std::string& b) { - return std::lexicographical_compare( - a.begin(), a.end(), - b.begin(), b.end(), - [](char c1, char c2) { - return std::tolower(c1) < std::tolower(c2); - } - ); + return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), + [](char c1, char c2) { return std::tolower(c1) < std::tolower(c2); }); }); } @@ -118,8 +111,8 @@ void EnableMod(std::string file) { disabledModFiles.erase(std::find(disabledModFiles.begin(), disabledModFiles.end(), file)); enabledModFiles.insert(enabledModFiles.begin(), file); - //TODO: runtime changes - //GetArchiveManager()->AddArchive(file); + // TODO: runtime changes + // GetArchiveManager()->AddArchive(file); AfterModChange(); } @@ -127,8 +120,8 @@ void DisableMod(std::string file) { enabledModFiles.erase(std::find(enabledModFiles.begin(), enabledModFiles.end(), file)); disabledModFiles.insert(disabledModFiles.begin(), file); - //TODO: runtime changes - //GetArchiveManager()->RemoveArchive(file); + // TODO: runtime changes + // GetArchiveManager()->RemoveArchive(file); AfterModChange(); } @@ -149,7 +142,8 @@ void DrawMods(bool enabled) { for (int i = 0; i < selectedModFiles.size(); i += 1) { std::string file = selectedModFiles[i]; - if (UIWidgets::StateButton((file + "_left_right").c_str(), enabled ? ICON_FA_ARROW_LEFT : ICON_FA_ARROW_RIGHT, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { + if (UIWidgets::StateButton((file + "_left_right").c_str(), enabled ? ICON_FA_ARROW_LEFT : ICON_FA_ARROW_RIGHT, + ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { if (enabled) { DisableMod(file); } else { @@ -157,13 +151,14 @@ void DrawMods(bool enabled) { } } - //it's not relevant to reorder disabled mods + // it's not relevant to reorder disabled mods if (enabled) { ImGui::SameLine(); if (i == 0) { ImGui::BeginDisabled(); } - if (UIWidgets::StateButton((file + "_up").c_str(), ICON_FA_ARROW_UP, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { + if (UIWidgets::StateButton((file + "_up").c_str(), ICON_FA_ARROW_UP, ImVec2(25, 25), + UIWidgets::ButtonOptions().Color(THEME_COLOR))) { madeAnyChange = true; switchFromIndex = i; switchToIndex = i - 1; @@ -176,7 +171,8 @@ void DrawMods(bool enabled) { if (i == selectedModFiles.size() - 1) { ImGui::BeginDisabled(); } - if (UIWidgets::StateButton((file + "_down").c_str(), ICON_FA_ARROW_DOWN, ImVec2(25, 25), UIWidgets::ButtonOptions().Color(THEME_COLOR))) { + if (UIWidgets::StateButton((file + "_down").c_str(), ICON_FA_ARROW_DOWN, ImVec2(25, 25), + UIWidgets::ButtonOptions().Color(THEME_COLOR))) { madeAnyChange = true; switchFromIndex = i; switchToIndex = i + 1; @@ -200,7 +196,8 @@ void ModMenuWindow::DrawElement() { const ImVec4 yellow = ImVec4(1, 1, 0, 1); - ImGui::TextColored(yellow, "Mods are currently not reloaded at runtime.\nClose and re-open Ship for the changes to take effect."); + ImGui::TextColored( + yellow, "Mods are currently not reloaded at runtime.\nClose and re-open Ship for the changes to take effect."); const std::string updateButtonTooltip = "Re-check the mods folder for new files"; diff --git a/soh/soh/Enhancements/mod_menu.h b/soh/soh/Enhancements/mod_menu.h index 0a69e0769..cb29b4001 100644 --- a/soh/soh/Enhancements/mod_menu.h +++ b/soh/soh/Enhancements/mod_menu.h @@ -9,6 +9,6 @@ class ModMenuWindow : public Ship::GuiWindow { void InitElement() override; void DrawElement() override; - void UpdateElement() override {}; + void UpdateElement() override{}; }; #endif \ No newline at end of file