about summary refs log tree commit diff
path: root/pkgs/games/humblebundle
diff options
context:
space:
mode:
authoraszlig <aszlig@nix.build>2018-02-08 20:04:07 +0100
committeraszlig <aszlig@nix.build>2018-02-09 16:33:28 +0100
commitb014da8a00032fded8c249bcbe52d80bc9de8e48 (patch)
tree1139db49b6b06ddfbc514bed54faab837f1d656d /pkgs/games/humblebundle
parentaaf8390e5e0eab0d89fdd5c7e40359985871d74f (diff)
pkgs/games/humblebundle: Add Owlboy
Very similar to other games using Mono, but this has a similar problem
to what Opus Magnum had (see 523dcef1f77251a4cfeb3428a0b13c0ec1d9c342)
but instead of using Cecil for patching I'm using LD_PRELOAD instead
because the number of occasions we need to patch is not only higher but
also there are different constructors in use for System.IO.FileStream,
so patching becomes much much harder.

Signed-off-by: aszlig <aszlig@nix.build>
Diffstat (limited to 'pkgs/games/humblebundle')
-rw-r--r--pkgs/games/humblebundle/default.nix1
-rw-r--r--pkgs/games/humblebundle/owlboy.nix102
2 files changed, 103 insertions, 0 deletions
diff --git a/pkgs/games/humblebundle/default.nix b/pkgs/games/humblebundle/default.nix
index 3ed0b3b6..4a0792c4 100644
--- a/pkgs/games/humblebundle/default.nix
+++ b/pkgs/games/humblebundle/default.nix
@@ -25,6 +25,7 @@ let
     liads = callPackage ./liads.nix {};
     megabytepunch = callPackage_i686 ./megabytepunch.nix {};
     opus-magnum = callPackage ./opus-magnum.nix {};
+    owlboy = callPackage ./owlboy.nix {};
     pico-8 = callPackage ./pico-8.nix {};
     rocketbirds = callPackage ./rocketbirds.nix {};
     spaz = callPackage ./spaz.nix {};
diff --git a/pkgs/games/humblebundle/owlboy.nix b/pkgs/games/humblebundle/owlboy.nix
new file mode 100644
index 00000000..a6c42577
--- /dev/null
+++ b/pkgs/games/humblebundle/owlboy.nix
@@ -0,0 +1,102 @@
+{ stdenv, lib, buildGame, fetchHumbleBundle, unzip, makeWrapper, mono50
+, SDL2, SDL2_image, openal, libvorbis
+, writeText
+}:
+
+buildGame rec {
+  name = "owlboy-${version}";
+  version = "20171229";
+
+  src = fetchHumbleBundle {
+    suffix = "bin";
+    machineName = "owlboy_linux";
+    md5 = "c2e99502013c7d2529bc2aefb6416dcf";
+  };
+
+  unpackCmd = "${unzip}/bin/unzip -qq \"$curSrc\" 'data/*' || :";
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  libdir = if stdenv.system == "x86_64-linux" then "lib64" else "lib";
+
+  prePatch = ''
+    find -type f -name '*.ini' -exec sed -i -e 's/${"\r"}$//' {} +
+  '';
+
+  buildPhase = let
+    dllmap = {
+      SDL2 = "${SDL2}/lib/libSDL2.so";
+      SDL2_image = "${SDL2_image}/lib/libSDL2_image.so";
+      soft_oal = "${openal}/lib/libopenal.so";
+      libvorbisfile-3 = "${libvorbis}/lib/libvorbisfile.so";
+      MojoShader = "$out/lib/owlboy/libmojoshader.so";
+    };
+  in ''
+    cc -Werror -shared "$preloader" -o preloader.so -ldl -fPIC \
+      -DSTOREPATH=\"$out\"
+  '' + lib.concatStrings (lib.mapAttrsToList (dll: target: ''
+    sed -i -e '/<dllmap.*dll="${dll}\.dll".*os="linux"/ {
+      s!target="[^"]*"!target="'"${target}"'"!
+    }' FNA.dll.config
+  '') dllmap);
+
+  # The game tries to open data files in read-write mode, so use LD_PRELOAD to
+  # avoid this whenever a store path is involved.
+  preloader = writeText "owlboy-preloader.c" ''
+    #define _GNU_SOURCE
+    #include <dlfcn.h>
+    #include <fcntl.h>
+    #include <stdarg.h>
+    #include <stdio.h>
+    #include <stdbool.h>
+    #include <string.h>
+    #include <sys/stat.h>
+
+    static bool isDataPath(const char *path) {
+      return strncmp(path, "content/", 8) == 0
+          || strncmp(path, STOREPATH, sizeof(STOREPATH) - 1) == 0;
+    }
+
+    int access(const char *path, int mode) {
+      static int (*_access) (const char *, int) = NULL;
+      if (_access == NULL) _access = dlsym(RTLD_NEXT, "access");
+      if (isDataPath(path) && mode & W_OK)
+        mode = mode & ~W_OK | R_OK;
+      return _access(path, mode);
+    }
+
+    int open(const char *path, int flags, ...) {
+      va_list ap;
+      mode_t mode;
+      static int (*_open) (const char *, int, mode_t) = NULL;
+      if (_open == NULL) _open = dlsym(RTLD_NEXT, "open");
+      va_start(ap, flags);
+      mode = va_arg(ap, mode_t);
+      va_end(ap);
+      if (isDataPath(path) && flags & O_RDWR)
+        flags = flags & ~O_RDWR | O_RDONLY;
+      return _open(path, flags, mode);
+    }
+  '';
+
+  installPhase = ''
+    mkdir -p "$out/bin" "$out/share" "$out/libexec/owlboy"
+    install -vD preloader.so "$out/lib/owlboy/preloader.so"
+    cp -rv content "$out/share/owlboy"
+    cp -rv monoconfig "$out/libexec/owlboy/Owlboy.exe.config"
+    cp -rvt "$out/libexec/owlboy" Owlboy.exe \
+      FNA.dll* GamedevUtility.dll MoonSharp.Interpreter.dll TimSort.dll
+    cp -rvt "$out/lib/owlboy" "$libdir/libmojoshader.so"
+    ln -vs "$out/share/owlboy" "$out/libexec/owlboy/content"
+
+    makeWrapper ${lib.escapeShellArg mono50}/bin/mono \
+      "$out/bin/owlboy" \
+      --set LD_PRELOAD "$out/lib/owlboy/preloader.so" \
+      --add-flags "$out/libexec/owlboy/Owlboy.exe" \
+      --run "cd '$out/libexec/owlboy'"
+  '';
+
+  sandbox.paths.required = [
+    "$XDG_DATA_HOME/Owlboy" "$XDG_CONFIG_HOME/Owlboy"
+  ];
+}