summary refs log tree commit diff
path: root/pkgs/games
diff options
context:
space:
mode:
authorIvv <41924494+IvarWithoutBones@users.noreply.github.com>2023-06-09 21:32:59 +0200
committerGitHub <noreply@github.com>2023-06-09 21:32:59 +0200
commitc2fd98a5ae4603c6b42293b424af11e582c6d8b5 (patch)
treec0f12c1f8182ce2016ada0c716cda3160f0357ae /pkgs/games
parent66c418d299cd454bd74644eaad905ec4ba2f81a1 (diff)
parent02ea919a89de89569c036f9de11ff64ab91e8fc1 (diff)
downloadnixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.tar
nixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.tar.gz
nixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.tar.bz2
nixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.tar.lz
nixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.tar.xz
nixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.tar.zst
nixpkgs-c2fd98a5ae4603c6b42293b424af11e582c6d8b5.zip
Merge pull request #207770 from j0lol/shipwright
shipwright: init at 7.0.2
Diffstat (limited to 'pkgs/games')
-rw-r--r--pkgs/games/shipwright/default.nix222
-rw-r--r--pkgs/games/shipwright/lus-install-paths.patch146
-rw-r--r--pkgs/games/shipwright/soh-misc-otr-patches.patch119
3 files changed, 487 insertions, 0 deletions
diff --git a/pkgs/games/shipwright/default.nix b/pkgs/games/shipwright/default.nix
new file mode 100644
index 00000000000..182e2cf654a
--- /dev/null
+++ b/pkgs/games/shipwright/default.nix
@@ -0,0 +1,222 @@
+{ stdenv
+, cmake
+, lsb-release
+, ninja
+, lib
+, fetchFromGitHub
+, fetchurl
+, makeDesktopItem
+, python3
+, libX11
+, libXrandr
+, libXinerama
+, libXcursor
+, libXi
+, libXext
+, glew
+, boost
+, SDL2
+, SDL2_net
+, pkg-config
+, libpulseaudio
+, libpng
+, imagemagick
+, requireFile
+
+, oot ? rec {
+    enable = true;
+    variant = "debug";
+
+    rom = requireFile {
+      name = "oot-${variant}.z64";
+      message = ''
+        This nix expression requires that oot-${variant}.z64 is already part of the store.
+        To get this file you can dump your Ocarina of Time's cartridge to a file,
+        and add it to the nix store with nix-store --add-fixed sha1 <FILE>, or override the package:
+          shipwright.override { oot = { enable = true; variant = "debug"; rom = path/to/oot-debug-mq.z64; } }
+
+        The supported variants are:
+         - debug: Ocarina of Time Debug PAL GC (not Master Quest)
+         - pal-gc: Ocarina of Time PAL GameCube (may lead to crashes and instability)
+
+        This is optional if you have imported an Ocarina of Time Master Quest ROM.
+        If so, please set oot.enable to false and ootMq.enable to true.
+        If both are enabled, Ship of Harkinian will be built with both ROMs.
+      '';
+
+      # From upstream: https://github.com/HarbourMasters/Shipwright/blob/e46c60a7a1396374e23f7a1f7122ddf9efcadff7/README.md#1-check-your-sha1
+      sha1 = {
+        debug = "cee6bc3c2a634b41728f2af8da54d9bf8cc14099";
+        pal-gc = "0227d7c0074f2d0ac935631990da8ec5914597b4";
+      }.${variant} or (throw "Unsupported romVariant ${variant}. Valid options are 'debug' and 'pal-gc'.");
+    };
+  }
+
+, ootMq ? rec {
+    enable = false;
+    variant = "debug-mq";
+
+    rom = requireFile {
+      name = "oot-${variant}.z64";
+      message = ''
+        This nix expression requires that oot-${variant}.z64 is already part of the store.
+        To get this file you can dump your Ocarina of Time Master Quest's cartridge to a file,
+        and add it to the nix store with nix-store --add-fixed sha1 <FILE>, or override the package:
+          shipwright.override { ootMq = { enable = true; variant = "debug-mq"; rom = path/to/oot-debug-mq.z64; } }
+
+        The supported variants are:
+         - debug-mq: Ocarina of Time Debug PAL GC MQ (Dungeons will be Master Quest)
+         - debug-mq-alt: Alternate ROM, not produced by decompilation.
+
+        This is optional if you have imported an Ocarina of Time ROM.
+        If so, please set oot.enable to true and ootMq.enable to false.
+        If both are enabled, Ship of Harkinian will be built with both ROMs.
+      '';
+
+      # From upstream: https://github.com/HarbourMasters/Shipwright/blob/e46c60a7a1396374e23f7a1f7122ddf9efcadff7/README.md#1-check-your-sha1
+      sha1 = {
+        debug-mq = "079b855b943d6ad8bd1eb026c0ed169ecbdac7da";
+        debug-mq-alt = "50bebedad9e0f10746a52b07239e47fa6c284d03";
+      }.${variant} or (throw "Unsupported mqRomVariant ${variant}. Valid options are 'debug-mq' and 'debug-mq-alt'.");
+    };
+  }
+}:
+
+let
+  checkAttrs = attrs:
+    let
+      validAttrs = [ "enable" "rom" "variant" ];
+    in
+    lib.all (name: lib.elem name validAttrs) (lib.attrNames attrs);
+in
+assert (lib.assertMsg (checkAttrs oot) "oot must have the attributes 'enable' and 'rom', and none other");
+assert (lib.assertMsg (checkAttrs ootMq) "ootMq must have the attributes 'enable' and 'rom', and none other");
+assert (lib.assertMsg (oot.enable || ootMq.enable) "At least one of 'oot.enable' and 'ootMq.enable' must be true");
+
+stdenv.mkDerivation rec {
+  pname = "shipwright";
+  version = "7.0.2";
+
+  src = fetchFromGitHub {
+    owner = "harbourmasters";
+    repo = "shipwright";
+    rev = version;
+    hash = "sha256-2VCcczGWSvp6hk8FTA1/T1E1KkrrvWyOdkEw8eiYYnY=";
+    fetchSubmodules = true;
+  };
+
+  # This would get fetched at build time otherwise, see:
+  # https://github.com/HarbourMasters/Shipwright/blob/e46c60a7a1396374e23f7a1f7122ddf9efcadff7/soh/CMakeLists.txt#L736
+  gamecontrollerdb = fetchurl {
+    name = "gamecontrollerdb.txt";
+    url = "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/c5b4df0e1061175cb11e3ebbf8045178339864a5/gamecontrollerdb.txt";
+    hash = "sha256-2VFCsaalXoe+JYWCH6IbgjnLXNKxe0UqSyJNGZMn5Ko=";
+  };
+
+  nativeBuildInputs = [
+    cmake
+    ninja
+    pkg-config
+    lsb-release
+    python3
+    imagemagick
+  ];
+
+  buildInputs = [
+    boost
+    libX11
+    libXrandr
+    libXinerama
+    libXcursor
+    libXi
+    libXext
+    glew
+    SDL2
+    SDL2_net
+    libpulseaudio
+    libpng
+  ];
+
+  patches = [
+    # These patches make soh look inside the nix store for data files (the controller database and the OTRs)
+    ./lus-install-paths.patch
+    ./soh-misc-otr-patches.patch
+  ];
+
+  cmakeFlags = [
+    "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}/lib"
+  ];
+
+  dontAddPrefix = true;
+
+  # Linking fails without this
+  hardeningDisable = [ "format" ];
+
+  postBuild = ''
+    cp ${gamecontrollerdb} ${gamecontrollerdb.name}
+
+    pushd ../OTRExporter
+    ${lib.optionalString oot.enable "python3 ./extract_assets.py -z ../build/ZAPD/ZAPD.out ${oot.rom}"}
+    ${lib.optionalString ootMq.enable "python3 ./extract_assets.py -z ../build/ZAPD/ZAPD.out ${ootMq.rom}"}
+    popd
+  '';
+
+  preInstall = ''
+    # Cmake likes it here for its install paths
+    cp ../OTRExporter/soh.otr ..
+  '';
+
+  postInstall = ''
+    mkdir -p $out/bin
+
+    # Copy the extracted assets, required to be in the same directory as the executable
+    ${lib.optionalString oot.enable "cp ../OTRExporter/oot.otr $out/lib"}
+    ${lib.optionalString ootMq.enable "cp ../OTRExporter/oot-mq.otr $out/lib"}
+
+    ln -s $out/lib/soh.elf $out/bin/soh
+  '';
+
+  desktopItems = [
+    (makeDesktopItem {
+      name = "soh";
+      icon = "soh";
+      exec = "soh";
+      genericName = "Ship of Harkinian";
+      desktopName = "soh";
+      categories = [ "Game" ];
+    })
+  ];
+
+  meta = with lib; {
+    homepage = "https://github.com/HarbourMasters/Shipwright";
+    description = "A PC port of Ocarina of Time with modern controls, widescreen, high-resolution, and more";
+    longDescription = ''
+      An PC port of Ocarina of Time with modern controls, widescreen, high-resolution and more, based off of decompilation.
+      Note that you must supply an OoT rom yourself to use this package because propietary assets are extracted from it.
+
+      You can change the game variant like this:
+        shipwright.override { oot.enable = false; ootMq.enable = true }
+
+      The default ROM variants for Oot and OotMq are debug and debug-mq respectively.
+      If you have a pal-gc rom, you should override like this:
+        shipwright.override { oot = { enable = true; variant = "pal-gc"; rom = path/to/oot-pal-gc.z64; } }
+
+      The supported Oot variants are:
+       - debug: Ocarina of Time Debug PAL GC (not Master Quest)
+       - pal-gc: Ocarina of Time PAL GameCube (may lead to crashes and instability)
+
+      The supported OotMq variants are:
+       - debug-mq: Ocarina of Time Debug PAL GC MQ (Dungeons will be Master Quest)
+       - debug-mq-alt: Alternate ROM, not produced by decompilation.
+    '';
+    mainProgram = "soh";
+    platforms = [ "x86_64-linux" ];
+    maintainers = with maintainers; [ ivar j0lol ];
+    license = with licenses; [
+      # OTRExporter, OTRGui, ZAPDTR, libultraship
+      mit
+      # Ship of Harkinian itself
+      unfree
+    ];
+  };
+}
diff --git a/pkgs/games/shipwright/lus-install-paths.patch b/pkgs/games/shipwright/lus-install-paths.patch
new file mode 100644
index 00000000000..c14ecccfed0
--- /dev/null
+++ b/pkgs/games/shipwright/lus-install-paths.patch
@@ -0,0 +1,146 @@
+Submodule libultraship contains modified content
+diff --git a/libultraship/src/CMakeLists.txt b/libultraship/src/CMakeLists.txt
+index f95c3c9..5b967b9 100644
+--- a/libultraship/src/CMakeLists.txt
++++ b/libultraship/src/CMakeLists.txt
+@@ -74,7 +74,10 @@ target_sources(libultraship PRIVATE ${Source_Files__Controller})
+ 
+ #=================== Core ===================
+ 
++configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/install_config.h.in ${CMAKE_BINARY_DIR}/install_config.h @ONLY)
++
+ set(Source_Files__Core
++    ${CMAKE_BINARY_DIR}/install_config.h
+     ${CMAKE_CURRENT_SOURCE_DIR}/core/Window.h
+     ${CMAKE_CURRENT_SOURCE_DIR}/core/Window.cpp
+     ${CMAKE_CURRENT_SOURCE_DIR}/core/ConsoleVariable.h
+@@ -329,7 +332,7 @@ endif()
+ #=================== Packages & Includes ===================
+ 
+ target_include_directories(libultraship
+-    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../extern
++    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../extern ${CMAKE_BINARY_DIR}
+     PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../extern/spdlog/include ${CMAKE_CURRENT_SOURCE_DIR}/../extern/stb
+ )
+ 
+diff --git a/libultraship/src/core/Context.cpp b/libultraship/src/core/Context.cpp
+index 776333e..fa546e6 100644
+--- a/libultraship/src/core/Context.cpp
++++ b/libultraship/src/core/Context.cpp
+@@ -14,6 +14,7 @@
+ #elif defined(__WIIU__)
+ #include "port/wiiu/WiiUImpl.h"
+ #endif
++#include "install_config.h"
+ 
+ namespace LUS {
+ std::weak_ptr<Context> Context::mContext;
+@@ -281,6 +282,18 @@ std::string Context::GetShortName() {
+ }
+ 
+ std::string Context::GetAppBundlePath() {
++#ifdef CMAKE_INSTALL_PREFIX
++    static const std::string fpath = CMAKE_INSTALL_PREFIX;
++    static int exists = -1;
++
++    if (exists == -1) {
++        exists = fpath.size() > 0 && std::filesystem::is_directory(fpath);
++    }
++
++    if (exists) {
++        return fpath;
++    }
++#else
+ #ifdef __APPLE__
+     FolderManager folderManager;
+     return folderManager.getMainBundlePath();
+@@ -291,6 +304,7 @@ std::string Context::GetAppBundlePath() {
+     if (fpath != NULL) {
+         return std::string(fpath);
+     }
++#endif
+ #endif
+ 
+     return ".";
+@@ -304,6 +318,13 @@ std::string Context::GetAppDirectoryPath() {
+     }
+ #endif
+ 
++    char *prefpath = SDL_GetPrefPath(NULL, "soh");
++    if (prefpath != NULL) {
++        std::string ret(prefpath);
++        SDL_free(prefpath);
++        return ret;
++    }
++
+     return ".";
+ }
+ 
+@@ -315,7 +336,24 @@ std::string Context::GetPathRelativeToAppDirectory(const char* path) {
+     return GetAppDirectoryPath() + "/" + path;
+ }
+ 
++std::string Context::FindFileFromAllAppDirectories(const char* path) {
++    std::string fpath;
++
++    // app configuration dir (eg. ~/.local/share)
++    fpath = GetPathRelativeToAppDirectory(path);
++    if (std::filesystem::exists(fpath)) {
++        return fpath;
++    }
++    // app install dir (eg. /usr/)
++    fpath = GetPathRelativeToAppBundle(path);
++    if (std::filesystem::exists(fpath)) {
++        return fpath;
++    }
++    // current dir
++    return "./" + std::string(path);
++}
++
+ bool Context::DoesOtrFileExist() {
+     return mOtrFileExists;
+ }
+-} // namespace LUS
+\ No newline at end of file
++} // namespace LUS
+diff --git a/libultraship/src/core/Context.h b/libultraship/src/core/Context.h
+index c32f4dd..a9f1639 100644
+--- a/libultraship/src/core/Context.h
++++ b/libultraship/src/core/Context.h
+@@ -26,6 +26,7 @@ class Context {
+     static std::string GetAppDirectoryPath();
+     static std::string GetPathRelativeToAppDirectory(const char* path);
+     static std::string GetPathRelativeToAppBundle(const char* path);
++    static std::string FindFileFromAllAppDirectories(const char* path);
+ 
+     Context(std::string name, std::string shortName);
+ 
+diff --git a/libultraship/src/core/libultra/os.cpp b/libultraship/src/core/libultra/os.cpp
+index 9058fe1..7d9387e 100644
+--- a/libultraship/src/core/libultra/os.cpp
++++ b/libultraship/src/core/libultra/os.cpp
+@@ -21,8 +21,8 @@ int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* statu
+     }
+ 
+ #ifndef __SWITCH__
+-    const char* controllerDb = "gamecontrollerdb.txt";
+-    int mappingsAdded = SDL_GameControllerAddMappingsFromFile(controllerDb);
++    std::string controllerDb = LUS::Context::GetPathRelativeToAppBundle("gamecontrollerdb.txt");
++    int mappingsAdded = SDL_GameControllerAddMappingsFromFile(controllerDb.c_str());
+     if (mappingsAdded >= 0) {
+         SPDLOG_INFO("Added SDL game controllers from \"{}\" ({})", controllerDb, mappingsAdded);
+     } else {
+@@ -90,4 +90,4 @@ int32_t osRecvMesg(OSMesgQueue* mq, OSMesg* msg, int32_t flag) {
+     mq->validCount--;
+     return 0;
+ }
+-}
+\ No newline at end of file
++}
+diff --git a/libultraship/src/install_config.h.in b/libultraship/src/install_config.h.in
+new file mode 100644
+index 0000000..029753c
+--- /dev/null
++++ b/libultraship/src/install_config.h.in
+@@ -0,0 +1 @@
++#cmakedefine CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
diff --git a/pkgs/games/shipwright/soh-misc-otr-patches.patch b/pkgs/games/shipwright/soh-misc-otr-patches.patch
new file mode 100644
index 00000000000..2be31092e28
--- /dev/null
+++ b/pkgs/games/shipwright/soh-misc-otr-patches.patch
@@ -0,0 +1,119 @@
+diff --git a/soh/soh/Extractor/Extract.cpp b/soh/soh/Extractor/Extract.cpp
+index a9ddc4f4..f6d45fe2 100644
+--- a/soh/soh/Extractor/Extract.cpp
++++ b/soh/soh/Extractor/Extract.cpp
+@@ -490,28 +490,27 @@ const char* Extractor::GetZapdVerStr() const {
+ 
+ extern "C" int zapd_main(int argc, char** argv);
+ 
+-bool Extractor::CallZapd() {
++bool Extractor::CallZapd(std::string &assetPath) {
+     constexpr int argc = 16;
+-    char xmlPath[100];
+-    char confPath[100];
+     std::array<const char*, argc> argv;
+     const char* version = GetZapdVerStr();
+ 
+-    snprintf(xmlPath, 100, "assets/extractor/xmls/%s", version);
+-    snprintf(confPath, 100, "assets/extractor/Config_%s.xml", version);
++    std::string xmlPath = assetPath + "/assets/extractor/xmls/" + version;
++    std::string confPath = assetPath + "/assets/extractor/Config_" + version + ".xml";
++    std::string fileListsPath = assetPath + "/assets/extractor/filelists";
+ 
+     argv[0] = "ZAPD";
+     argv[1] = "ed";
+     argv[2] = "-i";
+-    argv[3] = xmlPath;
++    argv[3] = xmlPath.c_str();
+     argv[4] = "-b";
+     argv[5] = mCurrentRomPath.c_str();
+     argv[6] = "-fl";
+-    argv[7] = "assets/extractor/filelists";
++    argv[7] = fileListsPath.c_str();
+     argv[8] = "-gsf";
+-    argv[9] = "1";
++    argv[9] = "0";
+     argv[10] = "-rconf";
+-    argv[11] = confPath;
++    argv[11] = confPath.c_str();
+     argv[12] = "-se";
+     argv[13] = "OTR";
+     argv[14] = "--otrfile";
+diff --git a/soh/soh/Extractor/Extract.h b/soh/soh/Extractor/Extract.h
+index e4eb2e5b..3c95b025 100644
+--- a/soh/soh/Extractor/Extract.h
++++ b/soh/soh/Extractor/Extract.h
+@@ -57,7 +57,7 @@ class Extractor {
+     bool IsMasterQuest() const;
+ 
+     bool Run(RomSearchMode searchMode = RomSearchMode::Both);
+-    bool CallZapd();
++    bool CallZapd(std::string& assetPath);
+     const char* GetZapdStr();
+ };
+ #endif
+diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
+index d192de6a..cc516085 100644
+--- a/soh/soh/OTRGlobals.cpp
++++ b/soh/soh/OTRGlobals.cpp
+@@ -201,11 +201,11 @@ const char* constCameraStrings[] = {
+ 
+ OTRGlobals::OTRGlobals() {
+     std::vector<std::string> OTRFiles;
+-    std::string mqPath = LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr");
++    std::string mqPath = LUS::Context::FindFileFromAllAppDirectories("oot-mq.otr");
+     if (std::filesystem::exists(mqPath)) { 
+         OTRFiles.push_back(mqPath);
+     } 
+-    std::string ootPath = LUS::Context::GetPathRelativeToAppDirectory("oot.otr");
++    std::string ootPath = LUS::Context::FindFileFromAllAppDirectories("oot.otr");
+     if (std::filesystem::exists(ootPath)) {
+         OTRFiles.push_back(ootPath);
+     }
+@@ -213,7 +213,7 @@ OTRGlobals::OTRGlobals() {
+     if (std::filesystem::exists(sohOtrPath)) {
+         OTRFiles.push_back(sohOtrPath);
+     }
+-    std::string patchesPath = LUS::Context::GetPathRelativeToAppDirectory("mods");
++    std::string patchesPath = LUS::Context::FindFileFromAllAppDirectories("mods");
+     if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) {
+         if (std::filesystem::is_directory(patchesPath)) {
+             for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath)) {
+@@ -709,8 +709,10 @@ 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::FindFileFromAllAppDirectories("oot-mq.otr")) &&
++        !std::filesystem::exists(LUS::Context::FindFileFromAllAppDirectories("oot.otr"))){
++        std::string exporterAssetPath = LUS::Context::GetAppBundlePath();
++
+         bool generatedOtrIsMQ = false;
+         if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) {
+             Extractor extract;
+@@ -718,7 +720,7 @@ extern "C" void InitOTR() {
+                 Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated. Exiting...");
+                 exit(1);
+             }
+-            extract.CallZapd();
++            extract.CallZapd(exporterAssetPath);
+             generatedOtrIsMQ = extract.IsMasterQuest();
+         } else {
+             exit(1);
+@@ -728,7 +730,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(exporterAssetPath);
+             }
+         }
+     }
+@@ -2018,4 +2020,4 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla
+ 
+ extern "C" void SaveManager_ThreadPoolWait() {
+     SaveManager::Instance->ThreadPoolWait();
+-}
+\ No newline at end of file
++}