From 8e5d3291b2aa3901c6dc77a982450667d930dc86 Mon Sep 17 00:00:00 2001 From: aszlig Date: Sat, 14 Jul 2018 22:48:31 +0200 Subject: games/bastion: Refactor Nix expression and update With fetchHumbleBundle finally being able to fetch the game with my account, I think it's time to update the Nix expression. :-) The game's binary is basically nothing more than just a wrapped Mono, so we can use directly Mono from instead of patching the wrapper. I also stubbed out the symbols for libsteam_api.so, which might be a good idea to provide for other games as well but in a more generic way. Another thing that was needed solely because of my stubbornness was to patch out the system() libc library call in libfmodex.so, because I didn't want to add /bin/sh to the sandbox. So in summary: The new expression now is sandboxed, doesn't use the wrapper anymore and also has a desktop entry :-) Unfortunately I haven't found a changelog online to see what has changed between the 20120620 and 20161016. Signed-off-by: aszlig Cc: @layus --- pkgs/games/humblebundle/bastion.nix | 188 +++++++++++++++++++++++++----------- 1 file changed, 134 insertions(+), 54 deletions(-) (limited to 'pkgs/games') diff --git a/pkgs/games/humblebundle/bastion.nix b/pkgs/games/humblebundle/bastion.nix index b4acda6b..7edfec2e 100644 --- a/pkgs/games/humblebundle/bastion.nix +++ b/pkgs/games/humblebundle/bastion.nix @@ -1,62 +1,142 @@ -{ stdenv, fetchHumbleBundle, lzma, xorg, libpulseaudio}: +{ lib, stdenv, buildGame, fetchHumbleBundle, makeWrapper, unzip, imagemagick +, mono, SDL2, SDL2_image, openal, libvorbis, libGL +}: -let - arch = { - "i686-linux" = "x86"; - "x86_64-linux" = "x86_64"; - }.${stdenv.system}; -in stdenv.mkDerivation rec { - name = "bastion-1.4"; +buildGame rec { + name = "bastion-${version}"; + version = "20161016"; src = fetchHumbleBundle { - name = "Bastion-HIB-2012-06-20.sh"; + name = "bastion-20161016.bin"; machineName = "bastion_linux"; - downloadName = ".sh"; - md5 = "aa6ccaead3b4b8a5fbd156f4019e8c8b"; + downloadName = "Download"; + md5 = "19fea173ff2da0f990f60bd5e7c3b237"; }; - dontStrip = true; - phases = ["installPhase"]; - - installPhase = let - rpath = stdenv.lib.makeLibraryPath [ - "$dest" - xorg.libX11 - xorg.libXi - stdenv.cc.cc - libpulseaudio - ]; - in '' - dest="$out/opt/games/bastion" - libdir="$dest/lib" #${stdenv.lib.optionalString (arch=="x86_64") "64"}" - - # Unpack binaries and data into $dest - mkdir -p "$dest" - sh "$src" --tar xf ./instarchive_all -O | ${lzma}/bin/lzcat | tar x -C "$dest" - sh "$src" --tar xf ./instarchive_linux_${arch} -O | ${lzma}/bin/lzcat | tar x -C "$dest" - - # Ensure that $dest is a valid library path. - mv $dest/lib64 $libdir || true - - # Patch heavily :-) - patchelf \ - --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ - --set-rpath "${rpath}" "$dest/Bastion.bin.${arch}" - patchelf --set-rpath "${rpath}" "$libdir/libmono-2.0.so.1" - patchelf --set-rpath "${rpath}" "$libdir/libfmodex.so" - patchelf --set-rpath "${rpath}" "$libdir/libSDL-1.2.so.0" - - # Fixup permissions, just to be sure. - find "$dest" -type f -exec chmod 644 "{}" + - chmod 755 "$dest/Bastion.bin.${arch}" - - # Taken from ArchLinux; might be useful to actually implement - #install -Dm644 "''${pkgname}".desktop "''${pkgdir}"/usr/share/applications/"''${pkgname}".desktop - #install -Dm755 "mesa''${pkgname}" "''${pkgdir}"/usr/bin/"''${pkgname}"mesa - #install -Dm644 "''${pkgdir}"/opt/games/Bastion/Bastion.png "''${pkgdir}"/usr/share/icons/"''${pkgname}".png - - # XXX: Make wrapper instead of symlink ? See ArchLinux's bastionmesa above. - mkdir -p "$out/bin" - ln -s "$dest/Bastion.bin.${arch}" "$out/bin/bastion" + unpackCmd = "${unzip}/bin/unzip -qq \"$curSrc\" 'data/*' || :"; + + nativeBuildInputs = [ makeWrapper imagemagick ]; + + libDir = + if stdenv.system == "i686-linux" then "lib" + else if stdenv.system == "x86_64-linux" then "lib64" + else throw "Unsupported architecture ${stdenv.system}."; + + buildPhase = let + dllmap = { + SDL2 = "${SDL2}/lib/libSDL2.so"; + SDL2_image = "${SDL2_image}/lib/libSDL2_image.so"; + soft_oal = "${openal}/lib/libopenal.so"; + libvorbisfile = "${libvorbis}/lib/libvorbisfile.so"; + MojoShader = "$out/libexec/bastion/libmojoshader.so"; + }; + in lib.concatStrings (lib.mapAttrsToList (dll: target: '' + sed -i -e '/ + int SteamAPI_Init(void) { return 0; } + void SteamAPI_Shutdown(void) {} + void SteamAPI_RunCallbacks() {} + /* All the symbols for the global accessors for Steamworks C++ APIs */ + ${lib.concatMapStrings (sym: '' + void *Steam${sym}(void) { return NULL; } + '') [ + "Client" "User" "Friends" "Utils" "Matchmaking" "UserStats" "Apps" + "Networking" "MatchmakingServers" "RemoteStorage" "Screenshots" "HTTP" + "UnifiedMessages" "Controller" "UGC" "AppList" "Music" "MusicRemote" + "HTMLSurface" "Inventory" "Video" + ]} + EOF + patchelf --remove-needed libsteam_api.so "$libDir/libSteamWrapper.so" + patchelf --add-needed libSteamStub.so "$libDir/libSteamWrapper.so" + + # FMOD Ex tries to run /bin/sh -c 'pulseaudio --check > /dev/null 2>&1', so + # we need to prevent this by replacing the system() call with a successful + # return value (0). If someone doesn't have or want to have PulseAudio, + # FMOD Ex still falls back to ALSA if it can't load libpulse-simple.so. + if [ "$libDir" = lib64 ]; then + addr="$(objdump -d lib64/libfmodex.so | sed -n -e ' + /callq.*system@plt/s/^ *\([^:]\+\).*/\1/p + ')" + + # This is quite easy, just replace the system() call with XOR EAX so we + # get a return value of 0 and pad the rest with NOP. + offset=$(("0x$addr")) + ( printf '\x31\xc0' # XOR the EAX register + printf '\x90\x90\x90' # Fill with NOPs + ) | dd of="$libDir/libfmodex.so" obs=1 seek=$offset count=5 conv=notrunc + else + relocSystem="$(readelf -r lib/libfmodex.so | sed -n -e ' + /system@/s/^0*\([^ ]\+\).*/\1/p + ')" + addr="$(objdump -d lib/libfmodex.so | sed -n -e ' + /call *'"$relocSystem"' /s/^ *\([^:]\+\).*/\1/p + ')" + + # For the 32 bit library it's not so easy as the 4 bytes coming after the + # CALL opcode will be replaced by the dynamic linker, so we just XOR the + # EAX register with the relocation address and replace the TEST opcode + # afterwards. + offset=$(("0x$addr")) + ( printf '\x35\xfc\xff\xff\xff' # XOR EAX with the relocation address + printf '\x39\xc0' # CMP EAX, EAX + ) | dd of="$libDir/libfmodex.so" obs=1 seek=$offset conv=notrunc + fi + + # For the Desktop icon + convert Bastion.bmp Bastion.png + ''; + + installPhase = '' + for lib in fmodex mojoshader SteamWrapper SteamStub; do + install -vD "$libDir/lib$lib.so" "$out/libexec/bastion/lib$lib.so" + done + + cp -rvt "$out/libexec/bastion" Bastion.exe FNA.dll* \ + FMOD.dll Lidgren.Network.dll MonoGame.Framework.Net.dll + + mkdir -p "$out/share" + cp -rv Content "$out/share/bastion" + cp -vt "$out/libexec/bastion" Bastion.bmp + ln -s "$out/share/bastion" "$out/libexec/bastion/Content" + + makeWrapper ${lib.escapeShellArg mono}/bin/mono "$out/bin/bastion" \ + --add-flags "$out/libexec/bastion/Bastion.exe" \ + --set SDL_OPENGL_LIBRARY ${lib.escapeShellArg "${libGL}/lib/libGL.so"} \ + --run "cd '$out/libexec/bastion'" + + install -vD -m 0644 Bastion.png "$out/share/icons/bastion.png" + + mkdir -p "$out/share/applications" + cat > "$out/share/applications/bastion.desktop" <