Proof of Concept

This commit is contained in:
Pepe20129 2025-01-11 21:14:36 +01:00
commit 0683d965e9
5 changed files with 168 additions and 2 deletions

View file

@ -0,0 +1,135 @@
#include "mod_menu.h"
#include "utils/StringHelper.h"
#include <libultraship/classes.h>
#include "soh/OTRGlobals.h"
#include <map>
#include <ranges>
std::shared_ptr<Ship::ArchiveManager> GetArchiveManager() {
return Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager();
}
std::map<std::string, bool> modFiles;
bool is_enabled(const std::pair<std::string, bool>& p) {
return p.second;
}
std::vector<std::string> GetEnabledModFiles() {
std::map<std::string, bool> enabledMods;
std::copy_if(modFiles.begin(), modFiles.end(), std::inserter(enabledMods, enabledMods.begin()), is_enabled);
auto ks = std::views::keys(enabledMods);
std::vector<std::string> keys{ ks.begin(), ks.end() };
return keys;
}
bool is_disabled(const std::pair<std::string, bool>& p) {
return !p.second;
}
std::vector<std::string> GetDisabledModFiles() {
std::map<std::string, bool> disabledMods;
std::copy_if(modFiles.begin(), modFiles.end(), std::inserter(disabledMods, disabledMods.begin()), is_disabled);
auto ks = std::views::keys(disabledMods);
std::vector<std::string> 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<std::string> 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("<None>");
}
ImGui::EndChild();
}
ImGui::TableNextColumn();
if (ImGui::BeginChild("Disabled Mods", ImVec2(0, -8))) {
std::vector<std::string> 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("<None>");
}
ImGui::EndChild();
}
ImGui::EndTable();
}
}
void ModMenuWindow::InitElement() {
UpdateModFiles();
}

View file

@ -0,0 +1,14 @@
#pragma once
#include <libultraship/libultraship.h>
#ifdef __cplusplus
class ModMenuWindow : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void InitElement() override;
void DrawElement() override;
void UpdateElement() override {};
};
#endif

View file

@ -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<std::string> 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<uint32_t> ValidHashes = {
OOT_PAL_MQ,
OOT_NTSC_JP_MQ,

View file

@ -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<Ship::GuiWindow> mGfxDebuggerWindow;
std::shared_ptr<Ship::GuiWindow> mInputEditorWindow;
std::shared_ptr<ModMenuWindow> mModMenuWindow;
std::shared_ptr<AudioEditor> mAudioEditorWindow;
std::shared_ptr<InputViewer> mInputViewer;
std::shared_ptr<InputViewerSettingsWindow> mInputViewerSettings;
@ -170,6 +172,8 @@ namespace SohGui {
SPDLOG_ERROR("Could not find input editor window");
}
mModMenuWindow = std::make_shared<ModMenuWindow>(CVAR_WINDOW("ModMenu"), "Mod Menu", ImVec2(820, 630));
gui->AddGuiWindow(mModMenuWindow);
mAudioEditorWindow = std::make_shared<AudioEditor>(CVAR_WINDOW("AudioEditor"), "Audio Editor", ImVec2(820, 630));
gui->AddGuiWindow(mAudioEditorWindow);
mInputViewer = std::make_shared<InputViewer>(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;

View file

@ -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<CosmeticsEditorWindow> mCosmeticsEditorWindow;
extern std::shared_ptr<GameplayStatsWindow> mGameplayStatsWindow;
extern std::shared_ptr<TimeSplitWindow> mTimeSplitWindow;
extern std::shared_ptr<TimeDisplayWindow> mTimeDisplayWindow;
extern std::shared_ptr<ModMenuWindow> 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);