From b94d7f135d056874bd19ddbbd85524416c91c9a3 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 13 Aug 2023 18:45:45 -0400 Subject: [PATCH] #3040 give em to the distro packagers + LUS submodule bump (#3119) * implement for install method packagers * use std::filesystem::temp_directory_path * absolutely impeccable * include libultraship proof * fix windows compilation * rename "Installation" back to "Bundle" --------- Co-authored-by: Alto1772 <56553686+Alto1772@users.noreply.github.com> --- CMake/Packaging-2.cmake | 2 +- CMakeLists.txt | 18 ++++++------- soh/soh/Extractor/Extract.cpp | 50 ++++++++++++++++++++++++++++++++--- soh/soh/Extractor/Extract.h | 3 ++- soh/soh/OTRGlobals.cpp | 24 +++++++++++------ soh/soh/OTRGlobals.h | 1 + 6 files changed, 76 insertions(+), 22 deletions(-) diff --git a/CMake/Packaging-2.cmake b/CMake/Packaging-2.cmake index c6e501c73..3525ae1e4 100644 --- a/CMake/Packaging-2.cmake +++ b/CMake/Packaging-2.cmake @@ -1,6 +1,6 @@ set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY 0) -set(CPACK_COMPONENTS_ALL "ship" "appimage") +set(CPACK_COMPONENTS_ALL "ship" "extractor" "appimage") if (NOT CPACK_GENERATOR STREQUAL "External") list(REMOVE_ITEM CPACK_COMPONENTS_ALL "appimage") diff --git a/CMakeLists.txt b/CMakeLists.txt index 3091f8824..1c93f7df8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,14 +98,14 @@ set_property(TARGET soh PROPERTY APPIMAGE_ICON_FILE "${CMAKE_BINARY_DIR}/sohIcon if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") install(PROGRAMS "${CMAKE_SOURCE_DIR}/scripts/linux/appimage/soh.sh" DESTINATION . COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/soh.otr" DESTINATION . COMPONENT appimage) -install(TARGETS ZAPD DESTINATION ./assets/extractor COMPONENT appimage) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor COMPONENT appimage) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls COMPONENT appimage) -install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT appimage) -install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT appimage) +install(FILES "${CMAKE_SOURCE_DIR}/soh.otr" DESTINATION . COMPONENT ship) +install(TARGETS ZAPD DESTINATION ./assets/extractor COMPONENT extractor) +install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor COMPONENT extractor) +install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls COMPONENT extractor) +install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists COMPONENT extractor) +install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor) +install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor) +install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor) endif() find_package(Python3 COMPONENTS Interpreter) @@ -198,4 +198,4 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") endif() set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_SOURCE_DIR}/CMake/Packaging-2.cmake) -include(CMake/Packaging.cmake) +include(CMake/Packaging.cmake) \ No newline at end of file diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp index 143a86380..b5eff7bae 100644 --- a/soh/soh/Extractor/Extract.cpp +++ b/soh/soh/Extractor/Extract.cpp @@ -44,6 +44,8 @@ #include #include #include +#include +#include extern "C" uint32_t CRC32C(unsigned char* data, size_t dataSize); extern "C" void RomToBigEndian(void* rom, size_t romSize); @@ -496,14 +498,50 @@ const char* Extractor::GetZapdVerStr() const { } } +std::string Extractor::Mkdtemp() { + std::string temp_dir = std::filesystem::temp_directory_path().string(); + + // create 6 random alphanumeric characters + static const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dist(0, sizeof(charset) - 1); + + char randchr[7]; + for (int i = 0; i < 6; i++) { + randchr[i] = charset[dist(gen)]; + } + randchr[6] = '\0'; + + std::string tmppath = temp_dir + "/extractor-" + randchr; + std::filesystem::create_directory(tmppath); + return tmppath; +} + extern "C" int zapd_main(int argc, char** argv); -bool Extractor::CallZapd() { +bool Extractor::CallZapd(std::string installPath, std::string exportdir) { constexpr int argc = 16; char xmlPath[1024]; char confPath[1024]; std::array argv; const char* version = GetZapdVerStr(); + const char* otrFile = IsMasterQuest() ? "oot-mq.otr" : "oot.otr"; + + std::string romPath = std::filesystem::absolute(mCurrentRomPath).string(); + installPath = std::filesystem::absolute(installPath).string(); + exportdir = std::filesystem::absolute(exportdir).string(); + // Work this out in the temporary folder + std::string tempdir = Mkdtemp(); + std::string curdir = std::filesystem::current_path().string(); +#ifdef _WIN32 + std::filesystem::copy(installPath + "/assets", tempdir + "/assets", + std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing); +#else + std::filesystem::create_symlink(installPath + "/assets", tempdir + "/assets"); +#endif + + std::filesystem::current_path(tempdir); snprintf(xmlPath, 1024, "assets/extractor/xmls/%s", version); snprintf(confPath, 1024, "assets/extractor/Config_%s.xml", version); @@ -513,7 +551,7 @@ bool Extractor::CallZapd() { argv[2] = "-i"; argv[3] = xmlPath; argv[4] = "-b"; - argv[5] = mCurrentRomPath.c_str(); + argv[5] = romPath.c_str(); argv[6] = "-fl"; argv[7] = "assets/extractor/filelists"; argv[8] = "-gsf"; @@ -523,7 +561,7 @@ bool Extractor::CallZapd() { argv[12] = "-se"; argv[13] = "OTR"; argv[14] = "--otrfile"; - argv[15] = IsMasterQuest() ? "oot-mq.otr" : "oot.otr"; + argv[15] = otrFile; #ifdef _WIN32 // Grab a handle to the command window. @@ -541,6 +579,12 @@ bool Extractor::CallZapd() { ShowWindow(cmdWindow, SW_HIDE); #endif + std::filesystem::copy(otrFile, exportdir + "/" + otrFile, std::filesystem::copy_options::overwrite_existing); + + // Go back to where this game was executed from + std::filesystem::current_path(curdir); + std::filesystem::remove_all(tempdir); + return 0; } diff --git a/soh/soh/Extractor/Extract.h b/soh/soh/Extractor/Extract.h index e4eb2e5bb..6c9b4a078 100644 --- a/soh/soh/Extractor/Extract.h +++ b/soh/soh/Extractor/Extract.h @@ -57,7 +57,8 @@ class Extractor { bool IsMasterQuest() const; bool Run(RomSearchMode searchMode = RomSearchMode::Both); - bool CallZapd(); + bool CallZapd(std::string installPath, std::string exportdir); const char* GetZapdStr(); + std::string Mkdtemp(); }; #endif diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 9c48d7c77..02a079857 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -208,11 +208,11 @@ const char* constCameraStrings[] = { OTRGlobals::OTRGlobals() { std::vector OTRFiles; - std::string mqPath = LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr"); + std::string mqPath = LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); if (std::filesystem::exists(mqPath)) { OTRFiles.push_back(mqPath); } - std::string ootPath = LUS::Context::GetPathRelativeToAppDirectory("oot.otr"); + std::string ootPath = LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName); if (std::filesystem::exists(ootPath)) { OTRFiles.push_back(ootPath); } @@ -220,7 +220,7 @@ OTRGlobals::OTRGlobals() { if (std::filesystem::exists(sohOtrPath)) { OTRFiles.push_back(sohOtrPath); } - std::string patchesPath = LUS::Context::GetPathRelativeToAppDirectory("mods"); + std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName); if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { if (std::filesystem::is_directory(patchesPath)) { for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath)) { @@ -248,7 +248,7 @@ OTRGlobals::OTRGlobals() { OOT_PAL_GC_DBG2 }; // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) - context = LUS::Context::CreateInstance("Ship of Harkinian", "soh", "shipofharkinian.json", OTRFiles, {}, 3); + context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3); context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared()); context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared()); @@ -717,8 +717,16 @@ extern "C" void OTRExtScanner() { extern "C" void InitOTR() { #if not defined (__SWITCH__) && not defined(__WIIU__) - if (!std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr")) && - !std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot.otr"))){ + if (!std::filesystem::exists(LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName)) && + !std::filesystem::exists(LUS::Context::LocateFileAcrossAppDirs("oot.otr", appShortName))){ + + std::string installPath = LUS::Context::GetAppBundlePath(); + if (!std::filesystem::exists(installPath + "/assets/extractor")) { + Extractor::ShowErrorBox("Extractor assets not found", + "No OTR files found. Missing assets/extractor folder needed to generate OTR file. Exiting..."); + exit(1); + } + bool generatedOtrIsMQ = false; if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) { Extractor extract; @@ -726,7 +734,7 @@ extern "C" void InitOTR() { Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated. Exiting..."); exit(1); } - extract.CallZapd(); + extract.CallZapd(installPath, LUS::Context::GetAppDirectoryPath(appShortName)); generatedOtrIsMQ = extract.IsMasterQuest(); } else { exit(1); @@ -736,7 +744,7 @@ extern "C" void InitOTR() { if (!extract.Run(generatedOtrIsMQ ? RomSearchMode::Vanilla : RomSearchMode::MQ)) { Extractor::ShowErrorBox("Error", "An error occured, an OTR file may have been generated by a different step. Continuing..."); } else { - extract.CallZapd(); + extract.CallZapd(installPath, LUS::Context::GetAppDirectoryPath(appShortName)); } } } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 329f4f0bf..8250b0814 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -19,6 +19,7 @@ #include const std::string customMessageTableID = "BaseGameOverrides"; +const std::string appShortName = "soh"; class OTRGlobals {