about summary refs log tree commit diff
path: root/pkgs/games/humblebundle
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2017-07-28 20:00:28 +0200
committeraszlig <aszlig@redmoonstudios.org>2017-07-28 20:47:31 +0200
commitfb43ad0db601e579be47ec32f8ed5590ed285498 (patch)
tree4eed6c4476de9f23d9910b8a7e0afda9a8e60afa /pkgs/games/humblebundle
parent224a63100f6233fda762c72818cad57173411802 (diff)
games: Add DOTT and Grim Fandango
Both are the remastered versions available via Humble Bundle and both
also needed a bit of patching via an LD preloader in order to work as
intended.

Day of the Tentacle conforms to XDG but it assumes that the data
directory is in the same directory of the executable, so we fake
/proc/self/exe to point to the "$out/share/dott/DUMMY". The "DUMMY" here
is because the implementation does a dirname() on the directory.

Grim Fandango on the other hand needs a bit more patching, so we first
of all override the _first_ chdir() the game does to point to the data
directory but we also override fopen64() and opendir() to use the
XDG_DATA_HOME-based save directory whenever one of these calls point to
"./Saves/..." because the data directory resides inside the store and
thus is (of course) read-only.

I had the expressions for these two games laying around for quite a
while, so while merging another game from a PR I thought it would be a
good opportinity to merge them as well.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'pkgs/games/humblebundle')
-rw-r--r--pkgs/games/humblebundle/default.nix2
-rw-r--r--pkgs/games/humblebundle/dott.nix70
-rw-r--r--pkgs/games/humblebundle/grim-fandango.nix177
3 files changed, 249 insertions, 0 deletions
diff --git a/pkgs/games/humblebundle/default.nix b/pkgs/games/humblebundle/default.nix
index e1c7c0e1..c7d760ac 100644
--- a/pkgs/games/humblebundle/default.nix
+++ b/pkgs/games/humblebundle/default.nix
@@ -14,9 +14,11 @@ let
     bastion = callPackage ./bastion.nix {};
     brigador = callPackage ./brigador.nix {};
     cavestoryplus = callPackage ./cavestoryplus.nix {};
+    dott = callPackage_i686 ./dott.nix {};
     fez = callPackage ./fez.nix {};
     ftl = callPackage ./ftl.nix {};
     guacamelee = callPackage_i686 ./guacamelee.nix {};
+    grim-fandango = callPackage_i686 ./grim-fandango.nix {};
     hammerwatch = callPackage ./hammerwatch.nix {};
     jamestown = callPackage ./jamestown.nix {};
     liads = callPackage ./liads.nix {};
diff --git a/pkgs/games/humblebundle/dott.nix b/pkgs/games/humblebundle/dott.nix
new file mode 100644
index 00000000..8f098d05
--- /dev/null
+++ b/pkgs/games/humblebundle/dott.nix
@@ -0,0 +1,70 @@
+{ stdenv, fetchHumbleBundle, mesa, libpulseaudio, alsaLib, libudev
+, writeText
+}:
+
+stdenv.mkDerivation rec {
+  name = "dott-remastered-${version}";
+  version = "1.4.1";
+
+  src = fetchHumbleBundle {
+    machineName = "dayofthetentacle_linux_beYLi";
+    suffix = "tar.gz";
+    md5 = "667b2a8a082702832242321515e55e70";
+  };
+
+  unpackCmd = "mkdir \"$name\" && tar xf \"$curSrc\" -C \"$name\"";
+
+  preloader = writeText "dott-preloader.c" ''
+    #define _GNU_SOURCE
+    #include <dlfcn.h>
+    #include <fcntl.h>
+    #include <string.h>
+    #include <unistd.h>
+
+    static int datadir_size = sizeof(DOTT_DATADIR) - 1;
+
+    ssize_t readlink(const char *path, char *buf, size_t bufsize) {
+      static ssize_t (*_readlink) (const char *, char *, size_t) = NULL;
+      if (_readlink == NULL) _readlink = dlsym(RTLD_NEXT, "readlink");
+
+      if (strncmp(path, "/proc/self/exe", 15) == 0) {
+        ssize_t copylen = datadir_size > bufsize ? bufsize : datadir_size;
+        memcpy(buf, DOTT_DATADIR, copylen);
+        return copylen;
+      } else {
+        return _readlink(path, buf, bufsize);
+      }
+    }
+
+    int SteamAPI_Init(void) {
+      return 0;
+    }
+  '';
+
+  rpath = stdenv.lib.makeLibraryPath [
+    mesa stdenv.cc.cc libpulseaudio alsaLib.out libudev
+  ];
+
+  buildPhase = ''
+    cc -Werror -Wall -std=gnu11 -shared "$preloader" -o preload.so -fPIC \
+      -DDOTT_DATADIR="\"$out/share/dott/DUMMY\""
+    patchelf --set-rpath "$rpath" lib/libfmod.so.8
+    patchelf \
+      --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
+      --remove-needed libsteam_api.so \
+      --add-needed "$out/libexec/dott/libdott-preload.so" \
+      Dott
+    patchelf --set-rpath "$out/libexec/dott:$rpath" Dott
+  '';
+
+  installPhase = ''
+    install -vsD preload.so "$out/libexec/dott/libdott-preload.so"
+    install -vD lib/libfmod.so.8 "$out/libexec/dott/libfmod.so.8"
+    install -vD Dott "$out/bin/dott"
+    if ldd "$out/bin/dott" | grep -F 'not found'; then exit 1; fi
+    install -vD -m 0644 tenta.cle "$out/share/dott/tenta.cle"
+  '';
+
+  dontStrip = true;
+  dontPatchELF = true;
+}
diff --git a/pkgs/games/humblebundle/grim-fandango.nix b/pkgs/games/humblebundle/grim-fandango.nix
new file mode 100644
index 00000000..c2b450e5
--- /dev/null
+++ b/pkgs/games/humblebundle/grim-fandango.nix
@@ -0,0 +1,177 @@
+{ stdenv, fetchHumbleBundle, mesa, libpulseaudio, alsaLib, SDL2, writeText
+, xorg
+}:
+
+stdenv.mkDerivation rec {
+  name = "grim-fandango-remastered-${version}";
+  version = "1.4.0";
+
+  src = fetchHumbleBundle {
+    machineName = "grimfandango_linux";
+    suffix = "tar.gz";
+    md5 = "52e0590850102a1ae0db907bef413e57";
+  };
+
+  preloader = writeText "grim-preloader.c" ''
+    #define _GNU_SOURCE
+    #include <dlfcn.h>
+    #include <dirent.h>
+    #include <fcntl.h>
+    #include <unistd.h>
+    #include <stdlib.h>
+    #include <stdio.h>
+    #include <string.h>
+    #include <sys/stat.h>
+    #include <sys/types.h>
+
+    int chdir(const char *path) {
+      static int (*_chdir) (const char *) = NULL;
+      if (_chdir == NULL) {
+        _chdir = dlsym(RTLD_NEXT, "chdir");
+        return _chdir(GRIM_DATADIR);
+      }
+      return _chdir(path);
+    }
+
+    #define CONCAT_ENV(path) \
+      if (asprintf(&result, "%s/%s", env, path) == -1) { \
+        perror("asprintf"); \
+        exit(1); \
+      }
+
+    static char *getSaveDir(void) {
+      const char *env;
+      static char *result = NULL;
+
+      if (result == NULL) {
+        if ((env = getenv("XDG_DATA_HOME")) != NULL) {
+          CONCAT_ENV("grim-fandango");
+        } else if ((env = getenv("HOME")) != NULL) {
+          CONCAT_ENV(".local/share/grim-fandango");
+        } else {
+          fputs("Unable to determine XDG_DATA_HOME or HOME.\n", stderr);
+          exit(1);
+        }
+      }
+
+      return result;
+    }
+
+    static void makedirs(char *path)
+    {
+      int pathlen = strlen(path);
+
+      static int (*_mkdir) (const char *, mode_t) = NULL;
+      if (_mkdir == NULL) _mkdir = dlsym(RTLD_NEXT, "mkdir");
+
+      for (int i = 1; i < pathlen; ++i) {
+        if (path[i] == '/') {
+          path[i] = '\0';
+          _mkdir(path, 0777);
+          path[i] = '/';
+        }
+      }
+    }
+
+    static char *mkSavePath(const char *path)
+    {
+      int savelen, pathlen;
+      char *buf, *savedir;
+
+      savedir = getSaveDir();
+      savelen = strlen(savedir);
+      pathlen = strlen(path);
+      buf = malloc(savelen + pathlen + 1);
+      strncpy(buf, savedir, savelen);
+      strncpy(buf + savelen, path, pathlen + 1);
+
+      return buf;
+    }
+
+    int mkdir(const char *pathname, mode_t mode) {
+      return 0;
+    }
+
+    FILE *fopen64(const char *path, const char *mode) {
+      FILE *fp;
+      char *buf;
+
+      static FILE *(*_fopen) (const char *, const char *) = NULL;
+      if (_fopen == NULL) _fopen = dlsym(RTLD_NEXT, "fopen64");
+
+      if (strncmp(path, "./Saves/", 8) == 0) {
+        path += 7;
+        buf = mkSavePath(path);
+        if ((fp = _fopen(buf, mode)) == NULL) {
+          makedirs(buf);
+          fp = _fopen(buf, mode);
+        }
+        free(buf);
+        return fp;
+      }
+
+      return _fopen(path, mode);
+    }
+
+    DIR *opendir(const char *name) {
+      DIR *dp;
+      char *buf;
+
+      static DIR *(*_opendir) (const char *) = NULL;
+      if (_opendir == NULL) _opendir = dlsym(RTLD_NEXT, "opendir");
+
+      if (strncmp(name, "./Saves/", 8) == 0) {
+        name += 7;
+        buf = mkSavePath(name);
+        if ((dp = _opendir(buf)) == NULL) {
+          makedirs(buf);
+          dp = _opendir(buf);
+        }
+        free(buf);
+        return dp;
+      }
+
+      return _opendir(name);
+    }
+  '';
+
+  rpath = stdenv.lib.makeLibraryPath [
+    mesa stdenv.cc.cc libpulseaudio alsaLib.out SDL2 xorg.libX11
+  ];
+
+  buildPhase = ''
+    cc -Werror -Wall -std=gnu11 -shared "$preloader" -o preload.so -fPIC \
+      -DGRIM_DATADIR="\"$out/share/grim-fandango\""
+    patchelf --set-rpath "$rpath" bin/libchore.so
+    patchelf --set-rpath "$rpath" bin/libLua.so
+    patchelf \
+      --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
+      --add-needed "$out/libexec/grim-fandango/libgrim-preload.so" \
+      bin/GrimFandango
+    patchelf --replace-needed libSDL2-2.0.so.1 libSDL2.so bin/GrimFandango
+    patchelf --set-rpath "$out/libexec/grim-fandango:$rpath" bin/GrimFandango
+  '';
+
+  installPhase = ''
+    install -vsD preload.so "$out/libexec/grim-fandango/libgrim-preload.so"
+    install -vD bin/libchore.so "$out/libexec/grim-fandango/libchore.so"
+    install -vD bin/libLua.so "$out/libexec/grim-fandango/libLua.so"
+    install -vD bin/GrimFandango "$out/bin/grim-fandango"
+    if ldd "$out/bin/grim-fandango" | grep -F 'not found'; then exit 1; fi
+
+    mkdir -p "$out/share/grim-fandango"
+    find bin -maxdepth 1 -mindepth 1 \
+      \( -path bin/i386 \
+      -o -path bin/amd64 \
+      -o -path bin/common-licenses \
+      -o -path bin/scripts \
+      -o -path bin/GrimFandango \
+      -o -name '*.so' \
+      -o -name '*.so.*' \
+      -o -name '*.txt' \
+      \) -prune -o -print | xargs cp -vrt "$out/share/grim-fandango"
+  '';
+
+  dontStrip = true;
+  dontPatchELF = true;
+}