diff options
Diffstat (limited to 'pkgs/games/humblebundle')
-rw-r--r-- | pkgs/games/humblebundle/default.nix | 1 | ||||
-rw-r--r-- | pkgs/games/humblebundle/starbound.nix | 327 |
2 files changed, 328 insertions, 0 deletions
diff --git a/pkgs/games/humblebundle/default.nix b/pkgs/games/humblebundle/default.nix index d0e564b8..1c1e7a21 100644 --- a/pkgs/games/humblebundle/default.nix +++ b/pkgs/games/humblebundle/default.nix @@ -23,6 +23,7 @@ let megabytepunch = callPackage ./megabytepunch.nix {}; rocketbirds = callPackage ./rocketbirds.nix {}; spaz = callPackage ./spaz.nix {}; + starbound = callPackage ./starbound.nix {}; swordsandsoldiers = callPackage ./swordsandsoldiers.nix {}; unepic = callPackage ./unepic.nix {}; }; diff --git a/pkgs/games/humblebundle/starbound.nix b/pkgs/games/humblebundle/starbound.nix new file mode 100644 index 00000000..0b6ce1c2 --- /dev/null +++ b/pkgs/games/humblebundle/starbound.nix @@ -0,0 +1,327 @@ +{ stdenv, fetchHumbleBundle, unzip, fetchurl, writeText, SDL2, mesa +, makeDesktopItem +}: + +let + binaryDeps = { + starbound.deps = [ SDL2 mesa ]; + starbound.needsBootconfig = true; + + starbound_server.name = "starbound-server"; + starbound_server.needsBootconfig = true; + + asset_packer.name = "starbound-asset-packer"; + asset_unpacker.name = "starbound-asset-unpacker"; + + dump_versioned_json.name = "starbound-dump-versioned-json"; + make_versioned_json.name = "starbound-make-versioned-json"; + + planet_mapgen.name = "starbound-planet-mapgen"; + update_tilesets.name = "starbound-update-tilesets"; + }; + + desktopItem = makeDesktopItem { + name = "starbound"; + exec = "starbound"; + icon = fetchurl { + url = "http://i1305.photobucket.com/albums/s544/ClockworkBarber/" + + "logo_zps64c4860d.png"; + sha256 = "11fiiy0vcxzix1j81732cjh16wi48k4vag040vmbhad50ps3mg0q"; + }; + comment = "An extraterrestrial sandbox adventure game"; + desktopName = "Starbound"; + genericName = "starbound"; + categories = "Game;"; + }; + + patchBinary = bin: attrs: '' + mkdir -p "patched/$(dirname "${bin}")" + cp -t "patched/$(dirname "${bin}")" "linux/${bin}" + chmod +x "patched/$(basename "${bin}")" + ${stdenv.lib.optionalString (attrs.needsBootconfig or false) '' + for offset in $( + grep -abz '^sbinit\.config''$' "patched/$(basename "${bin}")" \ + | cut -d: -f1 -z | xargs -0 + ); do + for i in $(seq 13); do printf '\x07'; done \ + | dd of="patched/$(basename "${bin}")" \ + obs=1 seek="$offset" \ + count=13 conv=notrunc + done + patchelf \ + --add-needed "$lib/lib/libstarbound-preload.so" \ + "patched/$(basename "${bin}")" + ''} + patchelf \ + --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ + --set-rpath "${stdenv.lib.makeLibraryPath (attrs.deps or [])}" \ + "patched/$(basename "${bin}")" + if ldd "patched/$(basename "${bin}")" | grep -F 'not found' \ + | grep -v 'libstarbound-preload\.so\|libsteam_api\.so'; then + exit 1; + fi + ''; + + preloaderSource = writeText "starbound-preloader.c" '' + #define _GNU_SOURCE + #include <dlfcn.h> + #include <fcntl.h> + #include <malloc.h> + #include <stdarg.h> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <sys/stat.h> + #include <sys/wait.h> + #include <unistd.h> + + #define MAGIC "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + static char *getXdgDataHome(void) { + int envlen; + char *result; + const char *env; + + if ((env = getenv("XDG_DATA_HOME")) != NULL) + return strdup(env); + if ((env = getenv("HOME")) == NULL) + return NULL; + + envlen = strlen(env); + if ((result = malloc(envlen + 14)) == NULL) + return NULL; + strncpy(result, env, envlen); + strncpy(result + envlen, "/.local/share", 14); + return result; + } + + static char *mkJsonString(const char *str) { + char *result, *out; + + if ((result = malloc(strlen(str) * 6 + 3)) == NULL) + return NULL; + + out = result; + *out++ = '"'; + + for (; *str != '\0'; str++) { + switch (*str) { + case '"': *out++ = '\\'; *out++ = '"'; break; + case '\\': *out++ = '\\'; *out++ = '\\'; break; + case '\b': *out++ = '\\'; *out++ = 'b'; break; + case '\f': *out++ = '\\'; *out++ = 'f'; break; + case '\n': *out++ = '\\'; *out++ = 'n'; break; + case '\r': *out++ = '\\'; *out++ = 'r'; break; + case '\t': *out++ = '\\'; *out++ = 't'; break; + default: + if (*str >= 0 && *str <= 31) { + *out++ = '\\'; + *out++ = 'u'; + snprintf(out, 4, "%04x", *str); + out += 4; + } else { + *out++ = *str; + } + break; + } + } + + *out++ = '"'; + *out = 0; + + return result; + } + + static char *mkDataDir(const char *dataHome, const char *append) { + char *buf, *out; + int homeLen = strlen(dataHome); + int appendLen = strlen(append); + + if ((buf = malloc(homeLen + appendLen + 2)) == NULL) + return NULL; + + snprintf(buf, homeLen + appendLen + 2, "%s/%s", dataHome, append); + + out = mkJsonString(buf); + free(buf); + + return out; + } + + static int makedirs(const char *path) { + char *buf, *p; + + if (strlen(path) == 0) + return 1; + + if ((buf = strdup(path)) == NULL) + return 1; + + for (p = buf + 1; *p != '\0'; p++) { + if (*p != '/') continue; + *p = '\0'; + mkdir(buf, 0777); + *p = '/'; + } + + free(buf); + return 0; + } + + static int writeSBInit(FILE *sbinit) { + char *buf, *dataHome; + int homeLen, ret; + + if ((dataHome = getXdgDataHome()) == NULL) + return 1; + + homeLen = strlen(dataHome); + if ((buf = malloc(homeLen + 12)) == NULL) + goto errout; + strncpy(buf, dataHome, homeLen); + strncpy(buf + homeLen, "/starbound/", 12); + ret = makedirs(buf); + free(buf); + if (ret != 0) goto errout; + + fputs("{\"assetDirectories\":[", sbinit); + + if ((buf = mkJsonString(STARBOUND_ASSET_DIR)) == NULL) + goto errout; + fputs(buf, sbinit); + free(buf); + + fputc(',', sbinit); + + if ((buf = mkDataDir(dataHome, "starbound/mods/")) == NULL) + goto errout; + fputs(buf, sbinit); + free(buf); + + fputs("],\"storageDirectory\":", sbinit); + + if ((buf = mkDataDir(dataHome, "starbound/")) == NULL) + goto errout; + fputs(buf, sbinit); + free(buf); + + fputs("}", sbinit); + free(dataHome); + return 0; + errout: + free(dataHome); + return 1; + } + + static FILE *fakeSBInitHandle = NULL; + + static int fakeSBInit(void) { + fakeSBInitHandle = tmpfile(); + if (writeSBInit(fakeSBInitHandle) != 0) { + fclose(fakeSBInitHandle); + fakeSBInitHandle = NULL; + return -1; + } + rewind(fakeSBInitHandle); + return fileno(fakeSBInitHandle); + } + + 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 (strncmp(path, MAGIC, 14) != 0) + return _open(path, flags, mode); + + return fakeSBInit(); + } + + int close(int fd) { + int ret; + static int (*_close) (int) = NULL; + + if (_close == NULL) + _close = dlsym(RTLD_NEXT, "close"); + + if (fakeSBInitHandle != NULL) { + ret = fclose(fakeSBInitHandle); + fakeSBInitHandle = NULL; + } else { + ret = _close(fd); + } + + return ret; + } + + int SteamAPI_Init(void) { + return 0; + } + ''; + +in stdenv.mkDerivation rec { + name = "starbound-${version}"; + version = "1.0.5"; + + src = fetchHumbleBundle { + name = "starbound-linux-${version}.zip"; + machineName = "starbound_linux"; + md5 = "0416fa1ddd6a420644fcf3ec18feb90c"; + }; + + outputs = [ "out" "lib" "assets" ]; + + nativeBuildInputs = [ unzip ]; + + buildPhase = with stdenv.lib; '' + cc -Werror -shared "${preloaderSource}" -o preload.so -ldl -fPIC \ + -DSTARBOUND_ASSET_DIR="\"$assets\"" + ${concatStrings (mapAttrsToList patchBinary binaryDeps)} + patchelf --remove-needed libsteam_api.so patched/starbound + ''; + + doCheck = true; + + checkPhase = '' + checkFailed= + for i in linux/*; do + [ -f "$i" ] || continue + + case "$(basename "$i")" in + sbinit.config) continue;; + *.s[ho]) continue;; + esac + + [ ! -e "patched/$(basename "$i")" ] || continue + + echo "Found missing binary $i from the upstream tree." + checkFailed=1 + done + + [ -z "$checkFailed" ] + ''; + + installPhase = '' + install -vsD preload.so "$lib/lib/libstarbound-preload.so" + + ${stdenv.lib.concatStrings (stdenv.lib.mapAttrsToList (bin: attrs: let + basename = builtins.baseNameOf bin; + in '' + install -vD "patched/${basename}" "$out/bin/${attrs.name or basename}" + '') binaryDeps)} + + install -m 0644 -vD "${desktopItem}/share/applications/starbound.desktop" \ + "$out/share/applications/starbound.desktop" + + cp -vr assets "$assets" + ''; + + dontStrip = true; +} |