summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------ZAPDTR0
m---------libultraship0
-rw-r--r--soh/soh/Extractor/Extract.cpp33
-rw-r--r--soh/soh/Extractor/Extract.h9
-rw-r--r--soh/soh/OTRGlobals.cpp833
-rw-r--r--soh/soh/OTRGlobals.h19
-rw-r--r--soh/soh/SohGui/Menu.cpp3
-rw-r--r--soh/soh/SohGui/SohGui.cpp40
-rw-r--r--soh/soh/SohGui/SohGui.hpp4
-rw-r--r--soh/soh/SohGui/SohMenu.cpp13
-rw-r--r--soh/soh/SohGui/SohMenu.h2
-rw-r--r--soh/soh/SohGui/SohModals.cpp7
-rw-r--r--soh/soh/SohGui/SohModals.h1
13 files changed, 596 insertions, 368 deletions
diff --git a/ZAPDTR b/ZAPDTR
-Subproject 684f21a475dcfeee89938ae1f4afc42768a3e7e
+Subproject ee3397a365c5f350a60538c88f0643f15594483
diff --git a/libultraship b/libultraship
-Subproject 3ef24c3d1645fe1fc2a7065d1c2e132973ebc15
+Subproject 8c55f607f2249f3ac696fc0f7277553fe3ce75a
diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp
index 024edda43..b567f4c7c 100644
--- a/soh/soh/Extractor/Extract.cpp
+++ b/soh/soh/Extractor/Extract.cpp
@@ -401,7 +401,6 @@ bool Extractor::ManuallySearchForRom() {
std::ifstream inFile;
if (!GetRomPathFromBox()) {
- ShowErrorBox("No rom selected", "No Rom selected. Exiting");
return false;
}
@@ -481,11 +480,15 @@ bool Extractor::RunFileStandalone(std::string rom) {
return true;
}
+void Extractor::SetSearchPath(const std::string& path) {
+ mSearchPath = path;
+}
+
bool Extractor::Run(std::string searchPath, RomSearchMode searchMode) {
std::vector<std::string> roms;
std::ifstream inFile;
- mSearchPath = searchPath;
+ SetSearchPath(searchPath);
GetRoms(roms);
FilterRoms(roms, searchMode);
@@ -631,10 +634,11 @@ std::string Extractor::Mkdtemp() {
return tmppath;
}
-extern "C" int zapd_main(int argc, char** argv);
+extern "C" int zapd_report(int argc, char** argv, std::atomic<size_t>* extractCount, std::atomic<size_t>* totalExtract);
static void MessageboxWorker();
-bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
+bool Extractor::CallZapd(std::string installPath, std::string exportdir, std::atomic<size_t>* extractCount,
+ std::atomic<size_t>* totalExtract) {
constexpr int argc = 22;
char xmlPath[1024];
char confPath[1024];
@@ -685,26 +689,7 @@ bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
argv[20] = "-osf";
argv[21] = "placeholder";
-#ifdef _WIN32
- // Grab a handle to the command window.
- HWND cmdWindow = GetConsoleWindow();
-
- // Normally the command window is hidden. We want the window to be shown here so the user can see the progess of the
- // extraction.
- ShowWindow(cmdWindow, SW_SHOW);
- SetWindowPos(cmdWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
-#else
- // Show extraction in background message until linux/mac can have visual progress
- std::thread mbThread(MessageboxWorker);
- mbThread.detach();
-#endif
-
- zapd_main(argc, (char**)argv.data());
-
-#ifdef _WIN32
- // Hide the command window again.
- ShowWindow(cmdWindow, SW_HIDE);
-#endif
+ zapd_report(argc, (char**)argv.data(), extractCount, totalExtract);
std::filesystem::copy(otrFile, exportdir + "/" + otrFile, std::filesystem::copy_options::overwrite_existing);
diff --git a/soh/soh/Extractor/Extract.h b/soh/soh/Extractor/Extract.h
index 691233aba..552d5bf4e 100644
--- a/soh/soh/Extractor/Extract.h
+++ b/soh/soh/Extractor/Extract.h
@@ -1,6 +1,7 @@
#ifndef EXTRACT_H
#define EXTRACT_H
+#include <atomic>
#include <stdint.h>
#include <string>
#include <memory>
@@ -45,23 +46,25 @@ class Extractor {
void SetRomInfo(const std::string& path);
void FilterRoms(std::vector<std::string>& roms, RomSearchMode searchMode);
- void GetRoms(std::vector<std::string>& roms);
void ShowSizeErrorBox() const;
void ShowCrcErrorBox() const;
void ShowCompressedErrorBox() const;
int ShowRomPickBox(uint32_t verCrc) const;
bool ManuallySearchForRom();
- bool ManuallySearchForRomMatchingType(RomSearchMode searchMode);
public:
// TODO create some kind of abstraction for message boxes.
static int ShowYesNoBox(const char* title, const char* text);
static void ShowErrorBox(const char* title, const char* text);
bool IsMasterQuest() const;
+ bool ManuallySearchForRomMatchingType(RomSearchMode searchMode);
+ void SetSearchPath(const std::string& path);
+ void GetRoms(std::vector<std::string>& roms);
bool RunFileStandalone(std::string file);
bool Run(std::string searchPath, RomSearchMode searchMode = RomSearchMode::Both);
- bool CallZapd(std::string installPath, std::string exportdir);
+ bool CallZapd(std::string installPath, std::string exportdir, std::atomic<size_t>* extractCount,
+ std::atomic<size_t>* totalExtract);
const char* GetZapdStr();
std::string Mkdtemp();
};
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index 0982fe2ca..13e4e3132 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -2,8 +2,10 @@
#include "OTRAudio.h"
#include <iostream>
#include <algorithm>
+#include <atomic>
#include <filesystem>
#include <fstream>
+#include <vector>
#include <chrono>
#include "ResourceManagerHelpers.h"
@@ -37,6 +39,8 @@
#include "Enhancements/gameplaystats.h"
#include "ObjectExtension/ObjectExtension.h"
#include "frame_interpolation.h"
+#include "SohGui/SohMenu.h"
+#include "SohGui/SohGui.hpp"
#include "variables.h"
#include "z64.h"
#include "macros.h"
@@ -145,6 +149,8 @@ Sail* Sail::Instance;
Anchor* Anchor::Instance;
extern "C" char** cameraStrings;
+
+extern "C" void PadMgr_ThreadEntry(PadMgr* padMgr);
std::vector<std::shared_ptr<std::string>> cameraStdStrings;
Color_RGB8 kokiriColor = { 0x1E, 0x69, 0x1B };
@@ -263,25 +269,520 @@ const char* constCameraStrings[] = {
GFXP_KATAKANA "キ- / ",
};
+typedef struct {
+ uint16_t major;
+ uint16_t minor;
+ uint16_t patch;
+} OTRVersion;
+
+std::shared_ptr<Fast::Fast3dWindow> sohFast3dWindow;
+static OTRVersion DetectOTRVersion(std::string path, bool isMq);
+static bool VerifyArchiveVersion(OTRVersion version);
+std::string portArchivePath = "";
+static bool sohArchiveVersionMatch = false;
+
OTRGlobals::OTRGlobals() {
context = Ship::Context::CreateUninitializedInstance("Ship of Harkinian", appShortName, "shipofharkinian.json");
+
+ portArchivePath = Ship::Context::LocateFileAcrossAppDirs("soh.o2r");
+ OTRVersion portArchiveVersion = DetectOTRVersion(portArchivePath, false);
+ sohArchiveVersionMatch = portArchiveVersion.major == gBuildVersionMajor &&
+ portArchiveVersion.minor == gBuildVersionMinor &&
+ portArchiveVersion.patch == gBuildVersionPatch;
+
+ context->InitConfiguration();
+ context->InitConsoleVariables();
+
+ auto controlDeck = std::make_shared<LUS::ControlDeck>(std::vector<CONTROLLERBUTTONS_T>({
+ BTN_CUSTOM_MODIFIER1,
+ BTN_CUSTOM_MODIFIER2,
+ BTN_CUSTOM_OCARINA_NOTE_D4,
+ BTN_CUSTOM_OCARINA_NOTE_F4,
+ BTN_CUSTOM_OCARINA_NOTE_A4,
+ BTN_CUSTOM_OCARINA_NOTE_B4,
+ BTN_CUSTOM_OCARINA_NOTE_D5,
+ BTN_CUSTOM_OCARINA_DISABLE_SONGS,
+ BTN_CUSTOM_OCARINA_PITCH_UP,
+ BTN_CUSTOM_OCARINA_PITCH_DOWN,
+ }));
+ context->InitControlDeck(controlDeck);
+ context->InitResourceManager({ portArchivePath }, {}, 3, true);
+ context->InitConsole();
+
+ auto sohInputEditorWindow =
+ std::make_shared<SohInputEditorWindow>(CVAR_WINDOW("ControllerConfiguration"), "Configure Controller");
+ sohFast3dWindow =
+ std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({ sohInputEditorWindow }));
+ context->InitWindow(sohFast3dWindow);
+
+ SohGui::SetupMenu();
+
+ if (sohArchiveVersionMatch) {
+
+ auto overlay = context->GetInstance()->GetWindow()->GetGui()->GetGameOverlay();
+ overlay->LoadFont("Press Start 2P", 12.0f, "fonts/PressStart2P-Regular.ttf");
+ overlay->LoadFont("Fipps", 32.0f, "fonts/Fipps-Regular.otf");
+ overlay->SetCurrentFont(CVarGetString(CVAR_GAME_OVERLAY_FONT, "Press Start 2P"));
+
+ fontMonoSmall = CreateFontWithSize(14.0f, "fonts/Inconsolata-Regular.ttf");
+ fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf");
+ fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf");
+ fontMonoLargest = CreateFontWithSize(24.0f, "fonts/Inconsolata-Regular.ttf");
+ fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf");
+ fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf");
+ fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf");
+ fontJapanese = CreateFontWithSize(24.0f, "fonts/NotoSansJP-Regular.ttf", true);
+ ImGui::GetIO().FontDefault = fontStandardLarger;
+ }
+
+ previousImGuiScaleIndex = -1;
+ previousImGuiScale = defaultImGuiScale;
+ ScaleImGui();
+}
+
+typedef enum ExtractSteps {
+ ES_PORT_ARCHIVE,
+ ES_WINDOWS,
+ ES_EXTRACT_ARGS,
+ ES_EXTRACT,
+ ES_VERIFY,
+} ExtractSteps;
+
+typedef enum PromptSteps {
+ PS_FILE_CHECK,
+ PS_LOCAL,
+ PS_FIRST,
+ PS_SECOND,
+ PS_DUPE,
+ PS_WAIT,
+ PS_NONE,
+} PromptSteps;
+
+typedef enum WindowsSteps {
+ WS_TEMP,
+ WS_PERMS,
+ WS_ONEDRIVE,
+ WS_DONE,
+} WindowsSteps;
+
+bool IsSubpath(const std::filesystem::path& path, const std::filesystem::path& base) {
+ auto rel = std::filesystem::relative(path, base);
+ return !rel.empty() && rel.native()[0] != '.';
+}
+
+bool PathTestCleanup(FILE* tfile) {
+ try {
+ if (std::filesystem::exists("./text.txt"))
+ std::filesystem::remove("./text.txt");
+ if (std::filesystem::exists("./test/"))
+ std::filesystem::remove("./test/");
+ } catch (std::filesystem::filesystem_error const& ex) { return false; }
+ return true;
+}
+
+void CheckAndCreateModFolder() {
+ try {
+ std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName);
+ if (!std::filesystem::exists(modsPath)) {
+ // Create mods folder relative to app dir
+ modsPath = Ship::Context::GetPathRelativeToAppDirectory("mods", appShortName);
+ std::string filePath = modsPath + "/custom_mod_files_go_here.txt";
+ if (std::filesystem::create_directories(modsPath)) {
+ std::ofstream(filePath).close();
+ }
+ }
+ } catch (std::filesystem::filesystem_error const& ex) {
+ // Couldn't make the folder, continue silently
+ return;
+ }
+}
+
+namespace SohGui {
+extern std::shared_ptr<SohGui::SohMenu> mSohMenu;
+}
+
+void OTRGlobals::RunExtract(int argc, char* argv[]) {
+ bool extractDone = false;
+ ExtractSteps extractStep = ES_PORT_ARCHIVE;
+ WindowsSteps windowsStep = WS_TEMP;
+ auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(OTRGlobals::Instance->context->GetWindow());
+ auto gui = wnd->GetGui();
+
+ OTRVersion vanillaVersion = DetectOTRVersion("oot.o2r", false);
+ OTRVersion mqVersion = DetectOTRVersion("oot-mq.o2r", true);
+
+ bool shouldRegen = VerifyArchiveVersion(vanillaVersion) || VerifyArchiveVersion(mqVersion);
+
+ std::filesystem::path ownPath;
+ std::vector<std::string> args;
+ if (argc > 1) {
+ for (int i = 1; i < argc; i++) {
+ args.push_back(argv[argc]);
+ }
+ }
+ Extractor extract;
+ PromptSteps promptStep = PS_FILE_CHECK;
+ bool generatedIsMQ = false;
+ std::atomic<bool> extracting = false;
+ std::atomic<size_t> extractCount = 0, totalExtract = 0;
+
+ std::string installPath = Ship::Context::GetAppBundlePath();
+ std::string file;
+
+#if defined(__SWITCH__)
+ SohGui::RegisterPopup("Outdated ROM Archives",
+ "\x1b[2;2HYou've launched the Ship with an old ROM O2R file."
+ "\x1b[4;2HPlease regenerate a new ROM O2R and relaunch."
+ "\x1b[6;2HPress the Home button to exit...",
+ "OK", "", [&]() { exit(1); });
+#elif defined(__WIIU__)
+ SohGui::RegisterPopup("Outdated ROM Archives",
+ "You've launched the Ship with an old a ROM O2R file.\n\n"
+ "Please generate a ROM O2R and relaunch.\n\n"
+ "Press and hold the Power button to shutdown...",
+ "OK", "", [&]() { exit(1); });
+ OSFatal();
+#endif
+
+ if (!std::filesystem::exists(installPath + "/assets")) {
+ SohGui::RegisterPopup("Extractor assets not found",
+ "No O2R files found. Missing 'assets/' folder needed to generate OTR file.\nPlease "
+ "re-extract them from the download or.\n\nExiting...",
+ "OK", "", [&]() { exit(1); });
+ } else if (shouldRegen) {
+ SohGui::RegisterPopup("Outdated ROM Archives",
+ "Your oot.o2r or oot-mq.o2r were created with incompatible versions of SoH.\nYou will "
+ "now be redirected to re-extract them.");
+ std::filesystem::remove("oot.o2r");
+ std::filesystem::remove("oot-mq.o2r");
+ }
+
+ std::shared_ptr<BS::thread_pool> threadPool = std::make_shared<BS::thread_pool>(1);
+ while (!extractDone) {
+ if (SohGui::PopupsQueued() > 0 || extracting) {
+ goto render;
+ }
+ switch (extractStep) {
+ case ES_PORT_ARCHIVE: {
+ if (sohArchiveVersionMatch) {
+#ifdef _WIN32
+ extractStep = ES_WINDOWS;
+#elif (defined(__WIIU__) || defined(__SWITCH__))
+ extractStep = ES_VERIFY;
+#else
+ extractStep = ES_EXTRACT;
+#endif
+ } else {
+ std::string msg;
+
+#if defined(__SWITCH__)
+ msg = "\x1b[4;2HPlease re-extract it from the download.\n"
+ "\x1b[6;2HPress the Home button to exit...";
+#elif defined(__WIIU__)
+ msg = "Please extract the soh.o2r from the Ship of Harkinian download\nto your folder.\n\nPress "
+ "and hold the power\n"
+ "button to shutdown...";
+#else
+ msg =
+ "Please extract the soh.o2r from the Ship of Harkinian download to your folder.\n\nExiting...";
+#endif
+ std::string title =
+ !std::filesystem::exists(portArchivePath) ? "Missing soh.o2r" : "soh.o2r is outdated";
+ SohGui::RegisterPopup(title, msg, "OK", "", [&]() { exit(1); });
+ }
+ continue;
+ }
+ case ES_WINDOWS: {
+ switch (windowsStep) {
+ case WS_TEMP: {
+#ifdef _WIN32
+ char* tempVar = getenv("TEMP");
+ std::filesystem::path tempPath;
+ try {
+ tempPath = std::filesystem::canonical(tempVar);
+ } catch (std::filesystem::filesystem_error const& ex) {
+ std::string userPath = getenv("USERPROFILE");
+ userPath.append("\\AppData\\Local\\Temp");
+ tempPath = std::filesystem::canonical(userPath);
+ }
+ wchar_t buffer[MAX_PATH];
+ GetModuleFileName(NULL, buffer, _countof(buffer));
+ ownPath = std::filesystem::canonical(buffer).parent_path();
+ if (IsSubpath(ownPath, tempPath)) {
+ SohGui::RegisterPopup("SoH Path Error",
+ "SoH is running in a temp folder.\nExtract the .zip and run again.",
+ "OK", "", [&]() { exit(0); });
+ } else {
+ windowsStep = WS_PERMS;
+ }
+#endif
+ continue;
+ }
+ case WS_PERMS: {
+ FILE* tfile = fopen("./text.txt", "w");
+ std::filesystem::path tfolder = std::filesystem::path("./test/");
+ bool error = false;
+ try {
+ create_directories(tfolder);
+ } catch (std::filesystem::filesystem_error const& ex) { error = true; }
+ if (tfile == NULL || error) {
+ SohGui::RegisterPopup("SoH Permissions Error",
+ "SoH does not have proper file permissions.\nPlease move it to a "
+ "folder that does and run again.",
+ "OK", "", [&]() {
+ fclose(tfile);
+ PathTestCleanup(tfile);
+ exit(0);
+ });
+ } else {
+ fclose(tfile);
+ if (!PathTestCleanup(tfile)) {
+ SohGui::RegisterPopup("SoH Permissions Error",
+ "SoH does not have proper file permissions.\nPlease move it to a "
+ "folder that does and run again.",
+ "OK", "", [&]() { exit(0); });
+ }
+ windowsStep = WS_ONEDRIVE;
+ }
+ continue;
+ }
+ case WS_ONEDRIVE: {
+ if (ownPath.string().find("OneDrive") != std::string::npos) {
+ SohGui::RegisterPopup("SoH Path Error",
+ "SoH appears to be in a OneDrive folder, which will cause issues.\n"
+ "Please move it to a folder outside of OneDrive, like the root of a\n"
+ "drive (e.g. \"C:\\Games\\SoH\").",
+ "OK", "", [&]() { exit(0); });
+ } else {
+ windowsStep = WS_DONE;
+ if (args.size() > 0) {
+ extractStep = ES_EXTRACT_ARGS;
+ } else {
+ extractStep = ES_EXTRACT;
+ }
+ }
+ continue;
+ }
+ default:
+ continue;
+ }
+ break;
+ }
+ case ES_EXTRACT_ARGS: {
+#if !defined(__SWITCH__) && !defined(__WIIU__)
+ if (args.size() == 0) {
+ SohGui::RegisterPopup(
+ "Run Ship of Harkinian", "All files have been processed. Run SoH?", "Yes", "No",
+ [&]() {
+ if (!std::filesystem::exists(Ship::Context::GetAppDirectoryPath(appShortName) +
+ "/oot.o2r") &&
+ !std::filesystem::exists(Ship::Context::GetAppDirectoryPath(appShortName) +
+ "/oot-mq.o2r")) {
+ extractStep = ES_EXTRACT;
+ promptStep = PS_FILE_CHECK;
+ } else {
+ extractStep = ES_VERIFY;
+ }
+ },
+ [&]() { exit(0); });
+ break;
+ }
+ file = args.at(0);
+ args.erase(args.begin());
+ extract = Extractor();
+ if (extract.RunFileStandalone(file)) {
+ bool doExtract = true;
+ std::string archive = (extract.IsMasterQuest() ? "oot-mq.o2r" : "oot.o2r");
+ if (std::filesystem::exists(Ship::Context::GetAppDirectoryPath(appShortName) + "/" + archive)) {
+ std::string msg = "Archive for current ROM, " + archive + ", already exists.\nExtract again?";
+ SohGui::RegisterPopup("Confirm Re-extract", msg.c_str(), "Yes", "No", [&]() {
+ extracting = true;
+ threadPool->submit_task([&]() -> void {
+ extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName),
+ &extractCount, &totalExtract);
+ extracting = false;
+ extractCount = totalExtract = 0;
+ });
+ });
+ } else {
+ extracting = true;
+ threadPool->submit_task([&]() -> void {
+ extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName),
+ &extractCount, &totalExtract);
+ extracting = false;
+ extractCount = totalExtract = 0;
+ });
+ }
+ } else {
+ bool open = true;
+ std::string msg = "File\n" + std::string(file) + "\nis not a ROM or does not match supported ROMs.";
+ SohGui::RegisterPopup("SoH ROM Error", msg.c_str());
+ }
+#else
+ extractStep = ES_VERIFY;
+#endif
+ break;
+ }
+ case ES_EXTRACT: {
+ switch (promptStep) {
+ case PS_FILE_CHECK: {
+ const bool ootO2RExists =
+ std::filesystem::exists(
+ Ship::Context::LocateFileAcrossAppDirs("oot-mq.o2r", appShortName)) ||
+ std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot.o2r", appShortName));
+
+ if (!ootO2RExists) {
+ SohGui::RegisterPopup(
+ "No O2R Files", "No O2R files found. Generate one now?", "Yes", "No",
+ [&]() { promptStep = PS_LOCAL; }, [&]() { exit(0); });
+ } else {
+ extractStep = ES_VERIFY;
+ }
+ continue;
+ }
+ case PS_LOCAL: {
+ extract = Extractor();
+ extract.SetSearchPath(installPath);
+ extract.GetRoms(args);
+ if (!args.empty()) {
+ promptStep = PS_WAIT;
+ SohGui::RegisterPopup(
+ "ROMs found", "ROMs found in application directory. Would you like to process them?",
+ "Yes", "No", [&]() { extractStep = ES_EXTRACT_ARGS; },
+ [&]() { promptStep = PS_FIRST; });
+ } else {
+ promptStep = PS_FIRST;
+ }
+ continue;
+ }
+ case PS_FIRST: {
+ if (!extract.ManuallySearchForRomMatchingType(RomSearchMode::Both)) {
+ promptStep = PS_FILE_CHECK;
+ continue;
+ }
+ extracting = true;
+ threadPool->submit_task([&]() -> void {
+ extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName),
+ &extractCount, &totalExtract);
+ generatedIsMQ = extract.IsMasterQuest();
+ extracting = false;
+ promptStep = PS_SECOND;
+ extractCount = 0;
+ totalExtract = 0;
+ });
+ continue;
+ }
+ case PS_SECOND: {
+ SohGui::RegisterPopup(
+ "Extraction Complete", "ROM Extracted. Extract another?", "Yes", "No",
+ [&]() {
+ if (!extract.ManuallySearchForRomMatchingType(generatedIsMQ ? RomSearchMode::Vanilla
+ : RomSearchMode::MQ)) {
+ extractStep = ES_VERIFY;
+ } else {
+ extracting = true;
+ threadPool->submit_task([&]() -> void {
+ extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName),
+ &extractCount, &totalExtract);
+ extracting = false;
+ extractStep = ES_VERIFY;
+ extractCount = 0;
+ totalExtract = 0;
+ });
+ }
+ },
+ [&]() { extractStep = ES_VERIFY; });
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case ES_VERIFY: {
+ const bool ootO2RExists =
+ std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot-mq.o2r", appShortName)) ||
+ std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot.o2r", appShortName));
+
+ if (!ootO2RExists) {
+ SohGui::RegisterPopup("No ROM Archives",
+ "No ROM O2R files detected. Please generate a ROM O2R and relaunch.", "OK",
+ "", [&]() { exit(0); });
+ }
+ extractDone = true;
+ continue;
+ }
+ default:
+ break;
+ }
+
+ render:
+ if (!WindowIsRunning()) {
+ exit(0);
+ }
+ // Process window events for resize, mouse, keyboard events
+ wnd->HandleEvents();
+ UIWidgets::Colors themeColor =
+ static_cast<UIWidgets::Colors>(CVarGetInteger(CVAR_SETTING("Menu.Theme"), UIWidgets::Colors::LightBlue));
+ ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIWidgets::ColorValues.at(themeColor));
+ ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, UIWidgets::ColorValues.at(UIWidgets::Colors::DarkGray));
+
+ // Skip dropped frames
+ if (!wnd->IsFrameReady()) {
+ continue;
+ }
+ gui->StartDraw();
+ sohFast3dWindow->StartFrame();
+ sohFast3dWindow->RunGuiOnly();
+ if (extracting && !ImGui::IsPopupOpen("ROM Extraction")) {
+ ImGui::OpenPopup("ROM Extraction");
+ }
+ if (extracting) {
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
+ auto color = UIWidgets::ColorValues.at(THEME_COLOR);
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
+ if (ImGui::BeginPopupModal("ROM Extraction", NULL,
+ ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
+ ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
+ ImGuiWindowFlags_NoSavedSettings)) {
+ float progress = (totalExtract > 0.0f ? (float)extractCount / (float)totalExtract : 0) * 100.0f;
+ auto filename = std::filesystem::path(file).filename().string();
+ ImGui::Text("Extracting %s...%s", filename.c_str(),
+ roundf(progress) == 100.0f ? " Done. Finishing up." : "");
+ std::string overlay = extractCount > 0 ? fmt::format("{:.0f}%", progress) : "Starting Up";
+ ImGui::ProgressBar(progress / 100.0f, ImVec2(600.0f, 50.0f), overlay.c_str());
+ ImGui::EndPopup();
+ }
+ ImGui::PopStyleColor(3);
+ ImGui::PopStyleVar(2);
+ }
+ gui->EndDraw();
+ sohFast3dWindow->EndFrame();
+ ImGui::PopStyleColor(2);
+ }
+
+#ifdef __SWITCH__
+ Ship::Switch::Init(Ship::PreInitPhase);
+#elif defined(__WIIU__)
+ Ship::WiiU::Init(appShortName);
+#endif
+
+#if not defined(__SWITCH__) && not defined(__WIIU__)
+ CheckAndCreateModFolder();
+#endif
}
void OTRGlobals::Initialize() {
- std::vector<std::string> OTRFiles;
std::string mqPath = Ship::Context::LocateFileAcrossAppDirs("oot-mq.o2r", appShortName);
if (std::filesystem::exists(mqPath)) {
- OTRFiles.push_back(mqPath);
+ context->GetResourceManager()->GetArchiveManager()->AddArchive(mqPath);
}
std::string ootPath = Ship::Context::LocateFileAcrossAppDirs("oot.o2r", appShortName);
if (std::filesystem::exists(ootPath)) {
- OTRFiles.push_back(ootPath);
- }
-
- std::string sohOtrPath = Ship::Context::LocateFileAcrossAppDirs("soh.o2r");
-
- if (std::filesystem::exists(sohOtrPath)) {
- OTRFiles.push_back(sohOtrPath);
+ context->GetResourceManager()->GetArchiveManager()->AddArchive(ootPath);
}
std::unordered_set<uint32_t> ValidHashes = {
@@ -306,42 +807,15 @@ void OTRGlobals::Initialize() {
context->InitFileDropMgr();
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
- context->InitResourceManager(OTRFiles, {}, 3);
prevAltAssets = CVarGetInteger(CVAR_SETTING("AltAssets"), 1);
context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets);
- auto controlDeck = std::make_shared<LUS::ControlDeck>(std::vector<CONTROLLERBUTTONS_T>({
- BTN_CUSTOM_MODIFIER1,
- BTN_CUSTOM_MODIFIER2,
- BTN_CUSTOM_OCARINA_NOTE_D4,
- BTN_CUSTOM_OCARINA_NOTE_F4,
- BTN_CUSTOM_OCARINA_NOTE_A4,
- BTN_CUSTOM_OCARINA_NOTE_B4,
- BTN_CUSTOM_OCARINA_NOTE_D5,
- BTN_CUSTOM_OCARINA_DISABLE_SONGS,
- BTN_CUSTOM_OCARINA_PITCH_UP,
- BTN_CUSTOM_OCARINA_PITCH_DOWN,
- }));
- context->InitControlDeck(controlDeck);
-
context->InitCrashHandler();
- context->InitConsole();
-
- auto sohInputEditorWindow =
- std::make_shared<SohInputEditorWindow>(CVAR_WINDOW("ControllerConfiguration"), "Configure Controller");
- auto sohFast3dWindow =
- std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({ sohInputEditorWindow }));
- context->InitWindow(sohFast3dWindow);
context->GetWindow()->SetAutoCaptureMouse(CVarGetInteger(CVAR_SETTING("EnableMouse"), 0) &&
CVarGetInteger(CVAR_SETTING("AutoCaptureMouse"), 1));
context->GetWindow()->SetForceCursorVisibility(CVarGetInteger(CVAR_SETTING("CursorVisibility"), 0));
- auto overlay = context->GetInstance()->GetWindow()->GetGui()->GetGameOverlay();
- overlay->LoadFont("Press Start 2P", 12.0f, "fonts/PressStart2P-Regular.ttf");
- overlay->LoadFont("Fipps", 32.0f, "fonts/Fipps-Regular.otf");
- overlay->SetCurrentFont(CVarGetString(CVAR_GAME_OVERLAY_FONT, "Press Start 2P"));
-
context->InitAudio({ .SampleRate = 32000, .SampleLength = 1024, .DesiredBuffered = 1680 });
SPDLOG_INFO("Starting Ship of Harkinian version {} (Branch: {} | Commit: {})", (char*)gBuildVersion,
@@ -430,20 +904,6 @@ void OTRGlobals::Initialize() {
hasMasterQuest = hasOriginal = false;
- previousImGuiScaleIndex = -1;
- previousImGuiScale = defaultImGuiScale;
-
- fontMonoSmall = CreateFontWithSize(14.0f, "fonts/Inconsolata-Regular.ttf", false);
- fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf", false);
- fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf", false);
- fontMonoLargest = CreateFontWithSize(24.0f, "fonts/Inconsolata-Regular.ttf", false);
- fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf", false);
- fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf", false);
- fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf", false);
- fontJapanese = CreateFontWithSize(24.0f, "fonts/NotoSansJP-Regular.ttf", true);
- ImGui::GetIO().FontDefault = fontStandardLarger;
- ScaleImGui();
-
// Move the camera strings from read only memory onto the heap (writable memory)
// This is in OTRGlobals right now because this is a place that will only ever be run once at the beginning of
// startup. We should probably find some code in db_camera that does initialization and only run once, and then
@@ -961,12 +1421,6 @@ extern "C" void OTRExtScanner() {
}
}
-typedef struct {
- uint16_t major;
- uint16_t minor;
- uint16_t patch;
-} OTRVersion;
-
// Read the port version from an OTR file
OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
OTRVersion version = {};
@@ -989,284 +1443,38 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
return version;
}
-// Check that a soh.o2r exists and matches the version of soh running
-// Otherwise show a message and exit
-void CheckSoHOTRVersion(std::string otrPath) {
- std::string msg;
-
-#if defined(__SWITCH__)
- msg = "\x1b[4;2HPlease re-extract it from the download."
- "\x1b[6;2HPress the Home button to exit...";
-#elif defined(__WIIU__)
- msg = "Please extract the soh.o2r from the Ship of Harkinian download\nto your folder.\n\nPress and hold the power "
- "button to shutdown...";
-#else
- msg = "Please extract the soh.o2r from the Ship of Harkinian download to your folder.\n\nExiting...";
-#endif
-
- if (!std::filesystem::exists(otrPath)) {
-#if not defined(__SWITCH__) && not defined(__WIIU__)
- Extractor::ShowErrorBox("soh.o2r file is missing", msg.c_str());
- exit(1);
-#elif defined(__SWITCH__)
- Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou are missing the soh.o2r file." + msg).c_str());
-#elif defined(__WIIU__)
- OSFatal(("You are missing the soh.o2r file\n\n" + msg).c_str());
-#endif
- }
-
- OTRVersion otrVersion = ReadPortVersionFromOTR(otrPath);
-
- if (otrVersion.major != gBuildVersionMajor || otrVersion.minor != gBuildVersionMinor ||
- otrVersion.patch != gBuildVersionPatch) {
-#if not defined(__SWITCH__) && not defined(__WIIU__)
- Extractor::ShowErrorBox("soh.o2r file version does not match", msg.c_str());
- exit(1);
-#elif defined(__SWITCH__)
- Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou have an old soh.o2r file." + msg).c_str());
-#elif defined(__WIIU__)
- OSFatal(("You have an old soh.o2r file\n\n" + msg).c_str());
-#endif
- }
-}
-
// Checks the program version stored in the otr and compares the major value to soh
// For Windows/Mac/Linux if the version doesn't match, offer to
-void DetectOTRVersion(std::string fileName, bool isMQ) {
+OTRVersion DetectOTRVersion(std::string fileName, bool isMQ) {
bool isOtrOld = false;
std::string otrPath = Ship::Context::LocateFileAcrossAppDirs(fileName, appShortName);
// Doesn't exist so nothing to do here
if (!std::filesystem::exists(otrPath)) {
- return;
- }
-
- OTRVersion otrVersion = ReadPortVersionFromOTR(otrPath);
-
- if (otrVersion.major != gBuildVersionMajor) {
- isOtrOld = true;
+ return { INT16_MAX, INT16_MAX, INT16_MAX };
}
- if (isOtrOld) {
-#if not defined(__SWITCH__) && not defined(__WIIU__)
- char msgBuf[250];
- char version[18]; // 5 digits for int16_max (x3) + separators + terminator
-
- if (otrVersion.major != 0 || otrVersion.minor != 0 || otrVersion.patch != 0) {
- snprintf(version, 18, "%d.%d.%d", otrVersion.major, otrVersion.minor, otrVersion.patch);
- } else {
- snprintf(version, 18, "no version found");
- }
-
- snprintf(msgBuf, 250,
- "The %s file was generated with a different version of Ship of Harkinian.\nOTR version: %s\n\n"
- "You must regenerate to be able to play, otherwise the program will exit.\nWould you like to "
- "regenerate it now?",
- fileName.c_str(), version);
-
- if (Extractor::ShowYesNoBox("Old OTR File Found", msgBuf) == IDYES) {
- std::string installPath = Ship::Context::GetAppBundlePath();
- if (!std::filesystem::exists(installPath + "/assets")) {
- Extractor::ShowErrorBox(
- "Extractor assets not found",
- "Unable to regenerate. Missing assets/ folder needed to generate OTR file.\n\nExiting...");
- exit(1);
- }
-
- Extractor extract;
- if (!extract.Run(Ship::Context::GetAppDirectoryPath(appShortName),
- isMQ ? RomSearchMode::MQ : RomSearchMode::Vanilla)) {
- Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated.\n\nExiting...");
- exit(1);
- }
- extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName));
- } else {
- exit(1);
- }
-
-#elif defined(__SWITCH__)
- Ship::Switch::PrintErrorMessageToScreen("\x1b[2;2HYou've launched the Ship with an old game OTR file."
- "\x1b[4;2HPlease regenerate a new game OTR and relaunch."
- "\x1b[6;2HPress the Home button to exit...");
-#elif defined(__WIIU__)
- OSFatal("You've launched the Ship with an old a game OTR file.\n\n"
- "Please generate a game OTR and relaunch.\n\n"
- "Press and hold the Power button to shutdown...");
-#endif
- }
+ return ReadPortVersionFromOTR(otrPath);
}
extern "C" void Messagebox_ShowErrorBox(char* title, char* body) {
Extractor::ShowErrorBox(title, body);
}
-bool IsSubpath(const std::filesystem::path& path, const std::filesystem::path& base) {
- auto rel = std::filesystem::relative(path, base);
- return !rel.empty() && rel.native()[0] != '.';
-}
-
-bool PathTestCleanup(FILE* tfile) {
- try {
- if (std::filesystem::exists("./text.txt"))
- std::filesystem::remove("./text.txt");
- if (std::filesystem::exists("./test/"))
- std::filesystem::remove("./test/");
- } catch (std::filesystem::filesystem_error const& ex) { return false; }
- return true;
-}
-
-void CheckAndCreateModFolder() {
- try {
- std::string modsPath = Ship::Context::LocateFileAcrossAppDirs("mods", appShortName);
- if (!std::filesystem::exists(modsPath)) {
- // Create mods folder relative to app dir
- modsPath = Ship::Context::GetPathRelativeToAppDirectory("mods", appShortName);
- std::string filePath = modsPath + "/custom_mod_files_go_here.txt";
- if (std::filesystem::create_directories(modsPath)) {
- std::ofstream(filePath).close();
- }
- }
- } catch (std::filesystem::filesystem_error const& ex) {
- // Couldn't make the folder, continue silently
- return;
+bool VerifyArchiveVersion(OTRVersion version) {
+ if (version.major != INT16_MAX && version.major != gBuildVersionMajor) {
+ return true;
}
+ return false;
}
extern "C" void InitOTR(int argc, char* argv[]) {
-#if !defined(__SWITCH__) && !defined(__WIIU__)
- if (argc > 1) {
- for (int i = 1; i < argc; i++) {
- std::string installPath = Ship::Context::GetAppBundlePath();
- Extractor extract;
- if (extract.RunFileStandalone(argv[i])) {
- bool doExtract = true;
- std::string archive = (extract.IsMasterQuest() ? "oot-mq.o2r" : "oot.o2r");
- if (std::filesystem::exists(Ship::Context::GetAppBundlePath() + "/" + archive)) {
- std::string msg = "Archive for current ROM, " + archive + ", already exists. Extract again?";
- doExtract = extract.ShowYesNoBox("Confirm Re-extract", msg.c_str()) == IDYES;
- }
- if (doExtract) {
- extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName));
- }
- } else {
- std::string msg = "File " + std::string(argv[i]) + " is not a ROM or does not match supported ROMs.";
- extract.ShowErrorBox("Incompatible File", msg.c_str());
- }
- }
- if (Extractor::ShowYesNoBox("Run Ship of Harkinian", "All files have been processed. Run SoH?") != IDYES) {
- exit(0);
- }
- }
-#endif
OTRGlobals::Instance = new OTRGlobals();
-#ifdef __SWITCH__
- Ship::Switch::Init(Ship::PreInitPhase);
-#elif defined(__WIIU__)
- Ship::WiiU::Init(appShortName);
-#endif
-
-#ifdef _WIN32
- char* tempVar = getenv("TEMP");
- std::filesystem::path tempPath;
- try {
- tempPath = std::filesystem::canonical(tempVar);
- } catch (std::filesystem::filesystem_error const& ex) {
- std::string userPath = getenv("USERPROFILE");
- userPath.append("\\AppData\\Local\\Temp");
- tempPath = std::filesystem::canonical(userPath);
- }
- wchar_t buffer[MAX_PATH];
- GetModuleFileName(NULL, buffer, _countof(buffer));
- auto ownPath = std::filesystem::canonical(buffer).parent_path();
- if (IsSubpath(ownPath, tempPath)) {
- Extractor::ShowErrorBox("Error", "SoH is running in a temp folder. Extract the .zip and run again.");
- exit(1);
- }
- FILE* tfile = fopen("./text.txt", "w");
- std::filesystem::path tfolder = std::filesystem::path("./test/");
- bool error = false;
- try {
- create_directories(tfolder);
- } catch (std::filesystem::filesystem_error const& ex) { error = true; }
- if (tfile == NULL || error) {
- Extractor::ShowErrorBox(
- "Error", "SoH does not have proper file permissions. Please move it to a folder that does and run again.");
- PathTestCleanup(tfile);
- exit(1);
- }
- fclose(tfile);
- if (!PathTestCleanup(tfile)) {
- Extractor::ShowErrorBox(
- "Error", "SoH does not have proper file permissions. Please move it to a folder that does and run again.");
- exit(1);
- }
- if (ownPath.string().find("OneDrive") != std::string::npos) {
- Extractor::ShowErrorBox(
- "Error",
- "SoH appears to be in a OneDrive folder, which will cause issues. "
- "Please move it to a folder outside of OneDrive, like the root of a drive (e.g. \"C:\\Games\\SoH\").");
- exit(1);
- }
-#endif
-
-#if not defined(__SWITCH__) && not defined(__WIIU__)
- CheckAndCreateModFolder();
-#endif
- const bool ootO2RExists =
- std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot-mq.o2r", appShortName)) ||
- std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot.o2r", appShortName));
-
- if (!ootO2RExists) {
-
-#if not defined(__SWITCH__) && not defined(__WIIU__)
- std::string installPath = Ship::Context::GetAppBundlePath();
- if (!std::filesystem::exists(installPath + "/assets")) {
- Extractor::ShowErrorBox(
- "Extractor assets not found",
- "No OTR files found. Missing assets/ folder needed to generate OTR file.\n\nExiting...");
- exit(1);
- }
-
- bool generatedOtrIsMQ = false;
- if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) {
- Extractor extract;
- if (!extract.Run(Ship::Context::GetAppDirectoryPath(appShortName))) {
- Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated.\n\nExiting...");
- exit(1);
- }
- extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName));
- generatedOtrIsMQ = extract.IsMasterQuest();
- } else {
- exit(1);
- }
- if (Extractor::ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?") == IDYES) {
- Extractor extract;
- if (!extract.Run(Ship::Context::GetAppDirectoryPath(appShortName),
- generatedOtrIsMQ ? RomSearchMode::Vanilla : RomSearchMode::MQ)) {
- Extractor::ShowErrorBox(
- "Error",
- "An error occured, an OTR file may have been generated by a different step.\n\nContinuing...");
- } else {
- extract.CallZapd(installPath, Ship::Context::GetAppDirectoryPath(appShortName));
- }
- }
-
-#elif defined(__SWITCH__)
- Ship::Switch::PrintErrorMessageToScreen("\x1b[2;2HYou've launched the Ship without a game OTR file."
- "\x1b[4;2HPlease generate a game OTR and relaunch."
- "\x1b[6;2HPress the Home button to exit...");
-#elif defined(__WIIU__)
- OSFatal("You've launched the Ship without a game OTR file.\n\n"
- "Please generate a game OTR and relaunch.\n\n"
- "Press and hold the Power button to shutdown...");
-#endif
- }
-
- DetectOTRVersion("oot.o2r", false);
- DetectOTRVersion("oot-mq.o2r", true);
+ OTRGlobals::Instance->RunExtract(argc, argv);
OTRGlobals::Instance->Initialize();
CustomMessageManager::Instance = new CustomMessageManager();
+ Randomizer::CreateCustomMessages();
ItemTableManager::Instance = new ItemTableManager();
GameInteractor::Instance = new GameInteractor();
SaveManager::Instance = new SaveManager();
@@ -1279,7 +1487,7 @@ extern "C" void InitOTR(int argc, char* argv[]) {
conf->RunVersionUpdates();
SohGui::SetupGuiElements();
- ShipInit::InitAll();
+ SohGui::SetupMenuElements();
Rando::StaticData::InitHashMaps();
OTRGlobals::Instance->gRandoContext->AddExcludedOptions();
@@ -1338,6 +1546,7 @@ extern "C" void InitOTR(int argc, char* argv[]) {
if (CVarGetInteger(CVAR_REMOTE_ANCHOR("Enabled"), 0)) {
Anchor::Instance->Enable();
}
+ ShipInit::InitAll();
}
extern "C" void SaveManager_ThreadPoolWait() {
diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h
index 08cee6e88..5e1a85d20 100644
--- a/soh/soh/OTRGlobals.h
+++ b/soh/soh/OTRGlobals.h
@@ -58,20 +58,21 @@ class OTRGlobals {
ImFont* defaultFontLarger;
ImFont* defaultFontLargest;
- ImFont* fontMonoSmall;
- ImFont* fontStandard;
- ImFont* fontStandardLarger;
- ImFont* fontStandardLargest;
- ImFont* fontMono;
- ImFont* fontMonoLarger;
- ImFont* fontMonoLargest;
- ImFont* fontJapanese;
+ ImFont* fontMonoSmall = nullptr;
+ ImFont* fontStandard = nullptr;
+ ImFont* fontStandardLarger = nullptr;
+ ImFont* fontStandardLargest = nullptr;
+ ImFont* fontMono = nullptr;
+ ImFont* fontMonoLarger = nullptr;
+ ImFont* fontMonoLargest = nullptr;
+ ImFont* fontJapanese = nullptr;
OTRGlobals();
~OTRGlobals();
void ScaleImGui();
void Initialize();
+ void RunExtract(int argc, char* argv[]);
bool HasMasterQuest();
bool HasOriginal();
uint32_t GetInterpolationFPS();
@@ -82,7 +83,7 @@ class OTRGlobals {
bool hasMasterQuest;
bool hasOriginal;
ImFont* CreateDefaultFontWithSize(float size);
- ImFont* CreateFontWithSize(float size, std::string fontPath, bool isJapaneseFont);
+ ImFont* CreateFontWithSize(float size, std::string fontPath, bool isJapaneseFont = false);
};
#endif
diff --git a/soh/soh/SohGui/Menu.cpp b/soh/soh/SohGui/Menu.cpp
index 1cb28f620..cddb68877 100644
--- a/soh/soh/SohGui/Menu.cpp
+++ b/soh/soh/SohGui/Menu.cpp
@@ -559,6 +559,9 @@ void Menu::Draw() {
static bool freshOpen = true;
void Menu::DrawElement() {
+ if (OTRGlobals::Instance->fontStandardLargest == nullptr) {
+ return;
+ }
for (auto& [reason, info] : disabledMap) {
info.active = info.evaluation(info);
}
diff --git a/soh/soh/SohGui/SohGui.cpp b/soh/soh/SohGui/SohGui.cpp
index 286beb180..de0b8be09 100644
--- a/soh/soh/SohGui/SohGui.cpp
+++ b/soh/soh/SohGui/SohGui.cpp
@@ -104,23 +104,22 @@ UIWidgets::Colors GetMenuThemeColor() {
return mSohMenu->GetMenuThemeColor();
}
-void SetupGuiElements() {
+void SetupMenu() {
auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
+ mSohMenu = std::make_shared<SohMenu>(CVAR_WINDOW("Menu"), "Port Menu");
+ gui->SetMenu(mSohMenu);
- /*mSohMenuBar = std::make_shared<SohMenuBar>(CVAR_MENU_BAR_OPEN, CVarGetInteger(CVAR_MENU_BAR_OPEN, 0));
- gui->SetMenuBar(std::reinterpret_pointer_cast<Ship::GuiMenuBar>(mSohMenuBar));
+ mModalWindow = std::make_shared<SohModalWindow>(CVAR_WINDOW("ModalWindow"), "Modal Window");
+ gui->AddGuiWindow(mModalWindow);
+ mModalWindow->Show();
+}
- if (!gui->GetMenuBar() && !CVarGetInteger("gSettings.DisableMenuShortcutNotify", 0)) {
-#if defined(__SWITCH__) || defined(__WIIU__)
- gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press - to access enhancements menu");
-#else
- gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu");
- gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press F2 to enable the mouse cursor");
-#endif
- }*/
+void SetupMenuElements() {
+ mSohMenu->AddMenuElements();
+}
- mSohMenu = std::make_shared<SohMenu>(CVAR_WINDOW("Menu"), "Port Menu");
- gui->SetMenu(mSohMenu);
+void SetupGuiElements() {
+ auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
mConsoleWindow = std::make_shared<SohConsoleWindow>(CVAR_WINDOW("SohConsole"), "Console##SoH", ImVec2(820, 630));
gui->AddGuiWindow(mConsoleWindow);
@@ -195,9 +194,6 @@ void SetupGuiElements() {
mPlandomizerWindow =
std::make_shared<PlandomizerWindow>(CVAR_WINDOW("PlandomizerEditor"), "Plandomizer Editor", ImVec2(850, 760));
gui->AddGuiWindow(mPlandomizerWindow);
- mModalWindow = std::make_shared<SohModalWindow>(CVAR_WINDOW("ModalWindow"), "Modal Window");
- gui->AddGuiWindow(mModalWindow);
- mModalWindow->Show();
mNotificationWindow = std::make_shared<Notification::Window>(CVAR_WINDOW("Notifications"), "Notifications Window");
gui->AddGuiWindow(mNotificationWindow);
mNotificationWindow->Show();
@@ -247,6 +243,18 @@ void RegisterPopup(std::string title, std::string message, std::string button1,
mModalWindow->RegisterPopup(title, message, button1, button2, button1callback, button2callback);
}
+size_t PopupsQueued() {
+ return mModalWindow->PopupsQueued();
+}
+
+bool DismissPopup(std::string title) {
+ if (mModalWindow->IsPopupOpen(title)) {
+ mModalWindow->DismissPopup();
+ return true;
+ }
+ return false;
+}
+
void ShowRandomizerSettingsMenu() {
CVarSetString(CVAR_SETTING("Menu.ActiveHeader"), "Randomizer");
CVarSetString(CVAR_SETTING("Menu.RandomizerSidebarSection"), "General");
diff --git a/soh/soh/SohGui/SohGui.hpp b/soh/soh/SohGui/SohGui.hpp
index 941772bba..2af5ef0fd 100644
--- a/soh/soh/SohGui/SohGui.hpp
+++ b/soh/soh/SohGui/SohGui.hpp
@@ -32,11 +32,15 @@
namespace SohGui {
void SetupHooks();
+void SetupMenu();
+void SetupMenuElements();
void SetupGuiElements();
void Draw();
void Destroy();
void RegisterPopup(std::string title, std::string message, std::string button1 = "OK", std::string button2 = "",
std::function<void()> button1callback = nullptr, std::function<void()> button2callback = nullptr);
+size_t PopupsQueued();
+bool DismissPopup(std::string title);
void ShowRandomizerSettingsMenu();
void ShowEscMenu();
UIWidgets::Colors GetMenuThemeColor();
diff --git a/soh/soh/SohGui/SohMenu.cpp b/soh/soh/SohGui/SohMenu.cpp
index 5ad59853a..3a077920a 100644
--- a/soh/soh/SohGui/SohMenu.cpp
+++ b/soh/soh/SohGui/SohMenu.cpp
@@ -81,8 +81,7 @@ SohMenu::SohMenu(const std::string& consoleVariable, const std::string& name)
: Menu(consoleVariable, name, 0, UIWidgets::Colors::LightBlue) {
}
-void SohMenu::InitElement() {
- Ship::Menu::InitElement();
+void SohMenu::AddMenuElements() {
AddMenuSettings();
AddMenuEnhancements();
AddMenuRandomizer();
@@ -97,6 +96,12 @@ void SohMenu::InitElement() {
initFunc();
}
+ mMenuElementsInitialized = true;
+}
+
+void SohMenu::InitElement() {
+ Ship::Menu::InitElement();
+
disabledMap = {
{ DISABLE_FOR_NO_VSYNC,
{ [](disabledInfo& info) -> bool {
@@ -166,6 +171,8 @@ void SohMenu::Draw() {
}
void SohMenu::DrawElement() {
- Ship::Menu::DrawElement();
+ if (mMenuElementsInitialized) {
+ Ship::Menu::DrawElement();
+ }
}
} // namespace SohGui
diff --git a/soh/soh/SohGui/SohMenu.h b/soh/soh/SohGui/SohMenu.h
index 5d24dbcce..3f147eddc 100644
--- a/soh/soh/SohGui/SohMenu.h
+++ b/soh/soh/SohGui/SohMenu.h
@@ -38,6 +38,7 @@ class SohMenu : public Ship::Menu {
void AddSidebarEntry(std::string sectionName, std::string sidbarName, uint32_t columnCount);
WidgetInfo& AddWidget(WidgetPath& pathInfo, std::string widgetName, WidgetType widgetType);
+ void AddMenuElements();
void AddMenuSettings();
void AddMenuEnhancements();
void AddMenuDevTools();
@@ -48,6 +49,7 @@ class SohMenu : public Ship::Menu {
private:
char mGitCommitHashTruncated[8];
bool mIsTaggedVersion;
+ bool mMenuElementsInitialized = false;
};
} // namespace SohGui
diff --git a/soh/soh/SohGui/SohModals.cpp b/soh/soh/SohGui/SohModals.cpp
index 339511e75..8cdd1a09b 100644
--- a/soh/soh/SohGui/SohModals.cpp
+++ b/soh/soh/SohGui/SohModals.cpp
@@ -42,6 +42,7 @@ void SohModalWindow::DrawElement() {
modals.erase(modals.begin());
closePopup = false;
}
+ ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal(curModal.title_.c_str(), NULL,
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
@@ -68,8 +69,8 @@ void SohModalWindow::DrawElement() {
}
UIWidgets::PopStyleButton();
}
+ ImGui::EndPopup();
}
- ImGui::EndPopup();
}
}
@@ -78,6 +79,10 @@ void SohModalWindow::RegisterPopup(std::string title, std::string message, std::
modals.push_back({ title, message, button1, button2, button1callback, button2callback });
}
+size_t SohModalWindow::PopupsQueued() {
+ return modals.size();
+}
+
bool SohModalWindow::IsPopupOpen(std::string title) {
return !modals.empty() && modals.at(0).title_ == title;
}
diff --git a/soh/soh/SohGui/SohModals.h b/soh/soh/SohGui/SohModals.h
index 68a9b8510..fbb123735 100644
--- a/soh/soh/SohGui/SohModals.h
+++ b/soh/soh/SohGui/SohModals.h
@@ -16,5 +16,6 @@ class SohModalWindow final : public Ship::GuiWindow {
std::function<void()> button1callback = nullptr,
std::function<void()> button2callback = nullptr);
bool IsPopupOpen(std::string title);
+ size_t PopupsQueued();
void DismissPopup();
}; \ No newline at end of file