dwarf-fortress: update to 50

This commit is contained in:
Morgan Jones 2024-03-30 20:36:51 -07:00
parent 55b7756b7d
commit e73e690717
No known key found for this signature in database
GPG Key ID: 52BAC54ED447974E
13 changed files with 460 additions and 139 deletions

View File

@ -46,31 +46,28 @@ let
# The latest Dwarf Fortress version. Maintainers: when a new version comes
# out, ensure that (unfuck|dfhack|twbt) are all up to date before changing
# this.
latestVersion = "0.47.05";
# this. Note that unfuck and twbt are not required for v50.
latestVersion = "50.12";
# Converts a version to a package name.
versionToName = version: "dwarf-fortress_${replaceStrings ["."] ["_"] version}";
dwarf-therapist-original = libsForQt5.callPackage ./dwarf-therapist {
texlive = texliveBasic.withPackages (ps: with ps; [ float caption wrapfig adjmulticol sidecap preprint enumitem ]);
};
# A map of names to each Dwarf Fortress package we know about.
df-games = listToAttrs (map
(dfVersion: {
name = versionToName dfVersion;
value =
let
# I can't believe this syntax works. Spikes of Nix code indeed...
isV50 = lib.versionAtLeast dfVersion "50.0";
dwarf-fortress-unfuck = if isV50 then null else callPackage ./unfuck.nix { inherit dfVersion; };
dwarf-fortress = callPackage ./game.nix {
inherit dfVersion;
inherit dwarf-fortress-unfuck;
};
dwarf-fortress-unfuck = callPackage ./unfuck.nix { inherit dfVersion; };
twbt = callPackage ./twbt { inherit dfVersion; };
twbt = if isV50 then null else callPackage ./twbt { inherit dfVersion; };
dfhack = callPackage ./dfhack {
inherit (perlPackages) XMLLibXML XMLLibXSLT;
@ -80,7 +77,10 @@ let
dwarf-therapist = libsForQt5.callPackage ./dwarf-therapist/wrapper.nix {
inherit dwarf-fortress;
dwarf-therapist = dwarf-therapist-original;
dwarf-therapist = libsForQt5.callPackage ./dwarf-therapist {
texlive = texliveBasic.withPackages (ps: with ps; [ float caption wrapfig adjmulticol sidecap preprint enumitem ]);
inherit isV50;
};
};
in
callPackage ./wrapper {
@ -97,7 +97,6 @@ let
# Aliases for the latest Dwarf Fortress and the selected Therapist install
dwarf-fortress = getAttr (versionToName latestVersion) df-games;
inherit dwarf-therapist-original;
dwarf-therapist = dwarf-fortress.dwarf-therapist;
dwarf-fortress-original = dwarf-fortress.dwarf-fortress;

View File

@ -1,20 +1,27 @@
{ stdenv
, buildEnv
, lib
, fetchFromGitHub
, fetchpatch
, cmake
, ninja
, writeScriptBin
, perl
, XMLLibXML
, XMLLibXSLT
, makeWrapper
, zlib
, ruby
, enableStoneSense ? false
, allegro5
, libGLU
, libGL
, SDL
, SDL2
, coreutils
, util-linux
, ncurses
, strace
, binutils
, gnused
, dfVersion
}:
@ -28,48 +35,73 @@ let
optional
optionals
optionalString
platforms
versionOlder
versionAtLeast
;
dfhack-releases = {
"0.44.10" = {
dfHackRelease = "0.44.10-r2";
sha256 = "19bxsghxzw3bilhr8sm4axz7p7z8lrvbdsd1vdjf5zbg04rs866i";
hash = "sha256-0RikMwFv/eJk26Hptnam6J97flekapQhjWvw3+HTfaU=";
xmlRev = "321bd48b10c4c3f694cc801a7dee6be392c09b7b";
prerelease = false;
};
"0.44.11" = {
dfHackRelease = "0.44.11-beta2.1";
sha256 = "1jgwcqg9m1ybv3szgnklp6zfpiw5mswla464dlj2gfi5v82zqbv2";
hash = "sha256-Yi/8BdoluickbcQQRbmuhcfrvrl02vf12MuHmh5m/Mk=";
xmlRev = "f27ebae6aa8fb12c46217adec5a812cd49a905c8";
prerelease = true;
};
"0.44.12" = {
dfHackRelease = "0.44.12-r1";
sha256 = "0j03lq6j6w378z6cvm7jspxc7hhrqm8jaszlq0mzfvap0k13fgyy";
hash = "sha256-3j83wgRXbfcrwPRrJVHFGcLD+tXy1M3MR2dwIw2mA0g=";
xmlRev = "23500e4e9bd1885365d0a2ef1746c321c1dd5094";
prerelease = false;
};
"0.47.02" = {
dfHackRelease = "0.47.02-alpha0";
sha256 = "19lgykgqm0si9vd9hx4zw8b5m9188gg8r1a6h25np2m2ziqwbjj9";
hash = "sha256-ScrFcfyiimuLgEaFjN5DKKRaFuKfdJjaTlGDit/0j6Y=";
xmlRev = "23500e4e9bd1885365d0a2ef1746c321c1dd509a";
prerelease = true;
};
"0.47.04" = {
dfHackRelease = "0.47.04-r5";
sha256 = "sha256-0s+/LKbqsS/mrxKPDeniqykE5+Gy3ZzCa8yEDzMyssY=";
hash = "sha256-0s+/LKbqsS/mrxKPDeniqykE5+Gy3ZzCa8yEDzMyssY=";
xmlRev = "be0444cc165a1abff053d5893dc1f780f06526b7";
prerelease = false;
};
"0.47.05" = {
dfHackRelease = "0.47.05-r7";
sha256 = "sha256-vBKUTSjfCnalkBzfjaIKcxUuqsGGOTtoJC1RHJIDlNc=";
hash = "sha256-vBKUTSjfCnalkBzfjaIKcxUuqsGGOTtoJC1RHJIDlNc=";
xmlRev = "f5019a5c6f19ef05a28bd974c3e8668b78e6e2a4";
};
"50.10" = {
dfHackRelease = "50.10-r1.1";
hash = "sha256-k2j8G4kJ/RYE8W0YDOxcsRb5qjjn4El+rigf0v3AqZU=";
xmlRev = "041493b221e0799c106abeac1f86df4535ab80d3";
needsPatches = true;
};
"50.11" = {
dfHackRelease = "50.11-r7";
hash = "sha256-3KsFc0i4XkzoeRvcl5GUlx/fJB1HyqfZm+xL6T4oT/A=";
xmlRev = "cca87907c1cbfcf4af957b0bea3a961a345b1581";
needsPatches = true;
};
"50.10" = {
dfHackRelease = "50.10-r1.1";
hash = "sha256-k2j8G4kJ/RYE8W0YDOxcsRb5qjjn4El+rigf0v3AqZU=";
xmlRev = "041493b221e0799c106abeac1f86df4535ab80d3";
prerelease = false;
};
"50.11" = {
dfHackRelease = "50.11-r7";
hash = "sha256-3KsFc0i4XkzoeRvcl5GUlx/fJB1HyqfZm+xL6T4oT/A=";
xmlRev = "cca87907c1cbfcf4af957b0bea3a961a345b1581";
prerelease = false;
};
"50.12" = {
dfHackRelease = "50.12-r3rc1";
hash = "sha256-EcM/FLulGVJgaERFMpYi9O5i1QKZyFb0X4HQagVnO8k=";
xmlRev = "425bb89041565432bb5e9574baadbc15a7c5db0e";
prerelease = true;
};
};
release =
@ -80,6 +112,8 @@ let
else throw "[DFHack] Unsupported Dwarf Fortress version: ${dfVersion}";
version = release.dfHackRelease;
isV50 = versionAtLeast version "50.0";
needsV50Patches = isV50 && (release.needsPatches or false);
# revision of library/xml submodule
xmlRev = release.xmlRev;
@ -119,7 +153,7 @@ in
owner = "DFHack";
repo = "dfhack";
rev = release.dfHackRelease;
sha256 = release.sha256;
inherit (release) hash;
fetchSubmodules = true;
};
@ -133,6 +167,14 @@ in
name = "fix-protobuf.patch";
url = "https://github.com/DFHack/dfhack/commit/7bdf958518d2892ee89a7173224a069c4a2190d8.patch";
hash = "sha256-p+mKhmYbnhWKNiGPMjbYO505Gcg634n0nudqH0NX3KY=";
}) ++ optional needsV50Patches (fetchpatch {
name = "use-system-sdl2.patch";
url = "https://github.com/DFHack/dfhack/commit/734fb730d72e53ebe67f4a041a24dd7c50307ee3.patch";
hash = "sha256-uLX0gdVSzKEVibyUc1UxcQzdYkRm6D8DF+1eSOxM+qU=";
}) ++ optional needsV50Patches (fetchpatch {
name = "rename-lerp.patch";
url = "https://github.com/DFHack/dfhack/commit/389dcf5cfcdb8bfb8deeb05fa5756c9f4f5709d1.patch";
hash = "sha256-QuDtGURhP+nM+x+8GIKO5LrMcmBkl9JSHHIeqzqGIPQ=";
});
# gcc 11 fix
@ -150,27 +192,71 @@ in
sed -i 's@cached_path = path_string.*@cached_path = getenv("DF_DIR");@' library/Process-linux.cpp
'';
nativeBuildInputs = [ cmake perl XMLLibXML XMLLibXSLT fakegit ];
nativeBuildInputs = [ cmake ninja perl XMLLibXML XMLLibXSLT makeWrapper fakegit ];
# We don't use system libraries because dfhack needs old C++ ABI.
buildInputs = [ zlib SDL ]
buildInputs = [ zlib ]
++ optional isV50 SDL2
++ optional (!isV50) SDL
++ optionals enableStoneSense [ allegro5 libGLU libGL ];
preConfigure = ''
# Trick build system into believing we have .git
# Trick the build system into believing we have .git.
mkdir -p .git/modules/library/xml
touch .git/index .git/modules/library/xml/index
'';
cmakeFlags = [ "-DDFHACK_BUILD_ARCH=${arch}" "-DDOWNLOAD_RUBY=OFF" ]
++ optionals enableStoneSense [ "-DBUILD_STONESENSE=ON" "-DSTONESENSE_INTERNAL_SO=OFF" ];
cmakeFlags = [
# Race condition in `Generating codegen.out.xml and df/headers` that is fixed when using Ninja.
"-GNinja"
"-DDFHACK_BUILD_ARCH=${arch}"
# dfhack expects an unversioned libruby.so to be present in the hack
# subdirectory for ruby plugins to function.
postInstall = ''
ln -s ${ruby}/lib/libruby-*.so $out/hack/libruby.so
# Don't download anything.
"-DDOWNLOAD_RUBY=OFF"
"-DUSE_SYSTEM_SDL2=ON"
# Ruby support with dfhack is very spotty and was removed in version 50.
"-DBUILD_RUBY=OFF"
] ++ optionals enableStoneSense [ "-DBUILD_STONESENSE=ON" "-DSTONESENSE_INTERNAL_SO=OFF" ];
NIX_CFLAGS_COMPILE = [ "-Wno-error=deprecated-enum-enum-conversion" ]
++ optionals (versionOlder version "0.47") [ "-fpermissive" ];
preFixup = ''
# Wrap dfhack scripts.
if [ -f $out/dfhack ]; then
wrapProgram $out/dfhack \
--inherit-argv0 \
--set-default SteamAppId 0 \
--set-default DFHACK_NO_RENAME_LIBSTDCXX 1 \
--suffix PATH : ${lib.makeBinPath [
coreutils util-linux strace gnused binutils ncurses
]}
fi
if [ -f $out/dfhack-run ]; then
wrapProgram $out/dfhack-run \
--inherit-argv0 \
--suffix PATH : ${lib.makeBinPath [
coreutils
]}
fi
# Create a dfhackrc that changes to the correct home directory.
cat <<EOF > $out/.dfhackrc
#!/usr/bin/env bash
# nixpkgs dfhackrc helper
if [ -d "\$NIXPKGS_DF_HOME" ]; then
cd "\$NIXPKGS_DF_HOME"
DF_DIR="\$NIXPKGS_DF_HOME"
fi
export DF_DIR
EOF
'';
passthru = { inherit dfVersion; };
passthru = {
inherit dfVersion;
};
meta = {
description = "Memory hacking library for Dwarf Fortress and a set of tools that use it";

View File

@ -6,22 +6,32 @@
, cmake
, texlive
, ninja
, isV50 ? true
}:
stdenv.mkDerivation rec {
pname = "dwarf-therapist";
version = "41.2.2";
# 41.2.5 is the last version to support Dwarf Fortress 0.47.
version = if isV50 then "42.1.5" else "41.2.5";
src = fetchFromGitHub {
owner = "Dwarf-Therapist";
repo = "Dwarf-Therapist";
rev = "v${version}";
sha256 = "sha256-zsEG68ioSw64UfmqlTLO1i5sObg8C4zxvdPxdQGMhhU=";
hash = if isV50 then # latest
"sha256-aUakfUjnIZWNDhCkG3A6u7BaaCG8kPMV/Fu2S73CoDg="
else # 41.2.5
"sha256-xfYBtnO1n6OcliVt07GsQ9alDJIfWdVhtuyWwuvXSZs=";
};
nativeBuildInputs = [ texlive cmake ninja ];
buildInputs = [ qtbase qtdeclarative ];
enableParallelBuilding = true;
cmakeFlags = [ "-GNinja" ];
installPhase =
if stdenv.isDarwin then ''
mkdir -p $out/Applications
@ -31,8 +41,8 @@ stdenv.mkDerivation rec {
dontWrapQtApps = true;
meta = with lib; {
description = "Tool to manage dwarves in a running game of Dwarf Fortress";
mainProgram = "dwarftherapist";
description = "Tool to manage dwarves in a running game of Dwarf Fortress";
maintainers = with maintainers; [ abbradar bendlas numinit jonringer ];
license = licenses.mit;
platforms = platforms.x86;

View File

@ -1,10 +1,12 @@
{ stdenv, dwarf-therapist, dwarf-fortress, substituteAll, coreutils, wrapQtAppsHook }:
{ stdenv, dwarf-therapist, dwarf-fortress, substituteAll, coreutils, wrapQtAppsHook
}:
let
platformSlug =
if stdenv.hostPlatform.is32bit then
"linux32" else "linux64";
inifile = "linux/v0.${dwarf-fortress.baseVersion}.${dwarf-fortress.patchVersion}_${platformSlug}.ini";
platformSlug = let
prefix = if dwarf-fortress.baseVersion >= 50 then "-classic_" else "_";
base = if stdenv.hostPlatform.is32bit then "linux32" else "linux64";
in prefix + base;
inifile = "linux/v0.${builtins.toString dwarf-fortress.baseVersion}.${dwarf-fortress.patchVersion}${platformSlug}.ini";
in
@ -40,8 +42,9 @@ stdenv.mkDerivation {
wrapQtApp $out/bin/dwarftherapist
# Fix up memory layouts
rm -rf $out/share/dwarftherapist/memory_layouts/linux
mkdir -p $out/share/dwarftherapist/memory_layouts/linux
ini_path="$out/share/dwarftherapist/memory_layouts/${inifile}"
rm -f "$ini_path"
mkdir -p "$(dirname -- "$ini_path")"
orig_md5=$(cat "${dwarf-fortress}/hash.md5.orig" | cut -c1-8)
patched_md5=$(cat "${dwarf-fortress}/hash.md5" | cut -c1-8)
input_file="${dwarf-therapist}/share/dwarftherapist/memory_layouts/${inifile}"
@ -53,7 +56,7 @@ stdenv.mkDerivation {
echo " Output: $output_file"
echo " Replace: $patched_md5"
substitute "$input_file" "$output_file" --replace "$orig_md5" "$patched_md5"
substitute "$input_file" "$output_file" --replace-fail "$orig_md5" "$patched_md5"
'';
preferLocalBuild = true;

View File

@ -135,5 +135,14 @@
"legacy_s": "1rb7h8lzlsjs08rvhhl3nwbrpj54zijijp4y0qdp4vyzsig6nisk",
"legacy32": "0ayw09x9smihh8qp5pdvr6vvhwkvcqz36h3lh4g1b5kzxj7g9cyf",
"legacy32_s": "10gfxlysfs9gyi1mv52idp5xk45g9h517g2jq4a8cqp2j7594v9c"
},
"50.10": {
"linux": "13s5p7205r9ha2j5n7carrwd0y7krq34bcdl08khp0kh2v4470a3"
},
"50.11": {
"linux": "0iz2d88gzvn0vjxlr99f13j4awhvh2lggjmipdwpbxhfsqih7dx0"
},
"50.12": {
"linux": "070014fzwszfgjyxjyij0k0hadah6s62lpi91ykp3vs220azya1m"
}
}

View File

@ -2,11 +2,15 @@
, lib
, fetchurl
, SDL
, SDL2
, SDL2_image
, SDL2_mixer
, fmodex
, dwarf-fortress-unfuck
, autoPatchelfHook
# Our own "unfuck" libs for macOS
, ncurses
, fmodex
, gcc
, dfVersion
@ -23,12 +27,13 @@ let
licenses
maintainers
makeLibraryPath
optional
optionals
optionalString
splitVersion
toInt
;
libpath = makeLibraryPath [ stdenv.cc.cc stdenv.cc.libc dwarf-fortress-unfuck SDL ];
# Map Dwarf Fortress platform names to Nixpkgs platform names.
# Other srcs are avilable like 32-bit mac & win, but I have only
# included the ones most likely to be needed by Nixpkgs users.
@ -41,9 +46,21 @@ let
i686-cygwin = "win32";
};
dfVersionTriple = splitVersion dfVersion;
baseVersion = elemAt dfVersionTriple 1;
patchVersion = elemAt dfVersionTriple 2;
dfVersionTuple = splitVersion dfVersion;
dfVersionBaseIndex = let
x = (builtins.length dfVersionTuple) - 2;
in if x >= 0 then x else 0;
baseVersion = toInt (elemAt dfVersionTuple dfVersionBaseIndex);
patchVersion = elemAt dfVersionTuple (dfVersionBaseIndex + 1);
isV50 = baseVersion >= 50;
enableUnfuck = !isV50 && dwarf-fortress-unfuck != null;
libpath = makeLibraryPath (
[ stdenv.cc.cc stdenv.cc.libc ]
++ optional (!isV50) SDL
++ optional enableUnfuck dwarf-fortress-unfuck
);
game =
if hasAttr dfVersion df-hashes
@ -57,7 +74,10 @@ let
if hasAttr dfPlatform game
then getAttr dfPlatform game
else throw "Unsupported dfPlatform: ${dfPlatform}";
exe = if stdenv.isLinux then
if baseVersion >= 50 then "dwarfort" else "libs/Dwarf_Fortress"
else
"dwarfort.exe";
in
stdenv.mkDerivation {
@ -65,21 +85,44 @@ stdenv.mkDerivation {
version = dfVersion;
src = fetchurl {
url = "https://www.bay12games.com/dwarves/df_${baseVersion}_${patchVersion}_${dfPlatform}.tar.bz2";
url = "https://www.bay12games.com/dwarves/df_${toString baseVersion}_${toString patchVersion}_${dfPlatform}.tar.bz2";
inherit sha256;
};
sourceRoot = ".";
postUnpack = optionalString stdenv.isLinux ''
if [ -d df_linux ]; then
mv df_linux/* .
fi
'' + optionalString stdenv.isDarwin ''
if [ -d df_osx ]; then
mv df_osx/* .
fi
'';
nativeBuildInputs = optional isV50 autoPatchelfHook;
buildInputs = optionals isV50 [ SDL2 SDL2_image SDL2_mixer stdenv.cc.cc.lib ];
installPhase = ''
runHook preInstall
exe=$out/${exe}
mkdir -p $out
cp -r * $out
rm $out/libs/lib*
exe=$out/${if stdenv.isLinux then "libs/Dwarf_Fortress"
else "dwarfort.exe"}
# Lots of files are +x in the newer releases...
find $out -type d -exec chmod 0755 {} \;
find $out -type f -exec chmod 0644 {} \;
chmod +x $exe
[ -f $out/df ] && chmod +x $out/df
[ -f $out/run_df ] && chmod +x $out/run_df
# Store the original hash
md5sum $exe | awk '{ print $1 }' > $out/hash.md5.orig
'' + optionalString stdenv.isLinux ''
echo "Original MD5: $(<$out/hash.md5.orig)" >&2
'' + optionalString (!isV50 && stdenv.isLinux) ''
rm -f $out/libs/*.so
patchelf \
--set-interpreter $(cat ${stdenv.cc}/nix-support/dynamic-linker) \
--set-rpath "${libpath}" \
@ -101,12 +144,22 @@ stdenv.mkDerivation {
@executable_path/libs/libstdc++.6.dylib \
$exe
'' + ''
# Store the new hash
ls -al $out
runHook postInstall
'';
fixupPhase = ''
runHook preFixup
runHook postFixup
# Store the new hash as the very last step.
exe=$out/${exe}
md5sum $exe | awk '{ print $1 }' > $out/hash.md5
echo "Patched MD5: $(<$out/hash.md5)" >&2
'';
passthru = {
inherit baseVersion patchVersion dfVersion;
inherit baseVersion patchVersion dfVersion exe;
updateScript = ./update.sh;
};

View File

@ -41,6 +41,8 @@ let
then getAttr dfGame df-games
else throw "Unknown Dwarf Fortress version: ${dfVersion}";
dwarf-therapist = dwarf-fortress.dwarf-therapist;
mainProgram = if enableDFHack then "dfhack" else "dwarf-fortress";
in
buildEnv {
name = "dwarf-fortress-full";
@ -54,6 +56,7 @@ buildEnv {
++ optional enableLegendsBrowser legends-browser;
meta = {
inherit mainProgram;
description = "An opinionated wrapper for Dwarf Fortress";
maintainers = with maintainers; [ Baughn numinit ];
license = licenses.mit;

View File

@ -1,6 +1,7 @@
{ stdenv
, lib
, fetchFromGitHub
, fetchpatch
, cmake
, libGL
, libSM
@ -32,43 +33,43 @@ let
unfuck-releases = {
"0.43.05" = {
unfuckRelease = "0.43.05";
sha256 = "173dyrbxlzqvjf1j3n7vpns4gfjkpyvk9z16430xnmd5m6nda8p2";
hash = "sha256-4iLVrKmlVdvBICb8NLe/U7pHtL372CGDkxt/2lf2bZw=";
};
"0.44.05" = {
unfuckRelease = "0.44.05";
sha256 = "00yj4l4gazxg4i6fj9rwri6vm17i6bviy2mpkx0z5c0mvsr7s14b";
hash = "sha256-iwR9st4VsPJBn7cKH/cy8YS6Tcw8J+lMJK9/9Qgl0gM=";
};
"0.44.09" = {
unfuckRelease = "0.44.09";
sha256 = "138p0v8z2x47f0fk9k6g75ikw5wb3vxldwv5ggbkf4hhvlw6lvzm";
hash = "sha256-9W9qON0QEjfXe2XzRvseixc+YznPzDQdcId08dEGF40=";
};
"0.44.10" = {
unfuckRelease = "0.44.10";
sha256 = "0vb19qx2ibc79j4bgbk9lskb883qfb0815zw1dfz9k7rqwal8mzj";
hash = "sha256-8ldEFcf5zPRdC/yXgMByeCC0pqZprreITIetKDpOYW0=";
};
"0.44.11" = {
unfuckRelease = "0.44.11.1";
sha256 = "1kszkb1d1vll8p04ja41nangsaxb5lv4p3xh2jhmsmipfixw7nvz";
hash = "sha256-f9vDe3Q3Vl2hFLCPSzYtqyv9rLKBKEnARZTu0MKaX88=";
};
"0.44.12" = {
unfuckRelease = "0.44.12";
sha256 = "1kszkb1d1vll8p04ja41nangsaxb5lv4p3xh2jhmsmipfixw7nvz";
hash = "sha256-f9vDe3Q3Vl2hFLCPSzYtqyv9rLKBKEnARZTu0MKaX88=";
};
"0.47.01" = {
unfuckRelease = "0.47.01";
sha256 = "11xvb3qh4crdf59pwfwpi73rzm3ysd1r1xp2k1jp7527jmqapk4k";
hash = "sha256-k8yrcJVHlHNlmOL2kEPTftSfx4mXO35TcS0zAvFYu4c=";
};
"0.47.02" = {
unfuckRelease = "0.47.01";
sha256 = "11xvb3qh4crdf59pwfwpi73rzm3ysd1r1xp2k1jp7527jmqapk4k";
hash = "sha256-k8yrcJVHlHNlmOL2kEPTftSfx4mXO35TcS0zAvFYu4c=";
};
"0.47.04" = {
unfuckRelease = "0.47.04";
sha256 = "1wa990xbsyiiz7abq153xmafvvk1dmgz33rp907d005kzl1z86i9";
hash = "sha256-KRr0A/2zANAOSDeP8V9tYe7tVO2jBLzU+TF6vTpISfE=";
};
"0.47.05" = {
unfuckRelease = "0.47.04";
sha256 = "1wa990xbsyiiz7abq153xmafvvk1dmgz33rp907d005kzl1z86i9";
unfuckRelease = "0.47.05-final";
hash = "sha256-kBdzU6KDpODOBP9XHM7lQRIEWUGOj838vXF1FbSr0Xw=";
};
};
@ -86,9 +87,17 @@ stdenv.mkDerivation {
owner = "svenstaro";
repo = "dwarf_fortress_unfuck";
rev = release.unfuckRelease;
sha256 = release.sha256;
inherit (release) hash;
};
patches = lib.optionals (versionOlder release.unfuckRelease "0.47.05") [(
fetchpatch {
name = "fix-noreturn-returning.patch";
url = "https://github.com/svenstaro/dwarf_fortress_unfuck/commit/6dcfe5ae869fddd51940c6c37a95f7bc639f4389.patch";
hash = "sha256-b9eI3iR7dmFqCrktPyn6QJ9U2A/7LvfYRS+vE3BOaqk=";
}
)];
postPatch = ''
# https://github.com/svenstaro/dwarf_fortress_unfuck/pull/27
substituteInPlace CMakeLists.txt --replace \''${GLEW_LIBRARIES} GLEW::glew

View File

@ -2,9 +2,7 @@
#! nix-shell -i bash -p jq nix coreutils curl
# systems to generate hashes for
systems='linux linux32 osx osx32
win win_s win32 win32_s
legacy legacy_s legacy32 legacy32_s'
systems='linux osx'
if [ $# -eq 0 ]; then
versions="$(curl http://www.bay12games.com/dwarves/ \

View File

@ -2,6 +2,7 @@
, lib
, buildEnv
, substituteAll
, makeWrapper
, runCommand
, coreutils
, gawk
@ -12,6 +13,9 @@
, enableSoundSense ? false
, soundSense
, jdk
, expect
, xvfb-run
, writeText
, enableStoneSense ? false
, enableTWBT ? false
, twbt
@ -31,10 +35,14 @@
}:
let
dfhack_ = dfhack.override {
dfhack' = dfhack.override {
inherit enableStoneSense;
};
isV50 = dwarf-fortress.baseVersion >= 50;
enableTWBT' = enableTWBT && (twbt != null);
ptheme =
if builtins.isString theme
then builtins.getAttr theme themes
@ -46,19 +54,19 @@ let
# These are in inverse order for first packages to override the next ones.
paths = extraPackages
++ lib.optional (theme != null) ptheme
++ lib.optional enableDFHack dfhack_
++ lib.optional enableDFHack dfhack'
++ lib.optional enableSoundSense soundSense
++ lib.optionals enableTWBT [ twbt.lib twbt.art ]
++ lib.optionals enableTWBT' [ twbt.lib twbt.art ]
++ [ dwarf-fortress ];
ignoreCollisions = true;
};
settings_ = lib.recursiveUpdate {
settings' = lib.recursiveUpdate {
init = {
PRINT_MODE =
if enableTextMode then "TEXT"
else if enableTWBT then "TWBT"
else if enableTWBT' then "TWBT"
else if stdenv.hostPlatform.isDarwin then "STANDARD" # https://www.bay12games.com/dwarves/mantisbt/view.php?id=11680
else null;
INTRO = enableIntro;
@ -77,23 +85,31 @@ let
else throw "dwarf-fortress: unsupported configuration value ${toString v}";
config = runCommand "dwarf-fortress-config" {
nativeBuildInputs = [ gawk ];
nativeBuildInputs = [ gawk makeWrapper ];
} (''
mkdir -p $out/data/init
edit_setting() {
v=''${v//'&'/'\&'}
if ! gawk -i inplace -v RS='\r?\n' '
{ n += sub("\\[" ENVIRON["k"] ":[^]]*\\]", "[" ENVIRON["k"] ":" ENVIRON["v"] "]"); print }
END { exit(!n) }
' "$out/$file"; then
echo "error: no setting named '$k' in $file" >&2
exit 1
if [ -f "$out/$file" ]; then
if ! gawk -i inplace -v RS='\r?\n' '
{ n += sub("\\[" ENVIRON["k"] ":[^]]*\\]", "[" ENVIRON["k"] ":" ENVIRON["v"] "]"); print }
END { exit(!n) }
' "$out/$file"; then
echo "error: no setting named '$k' in $out/$file" >&2
exit 1
fi
else
echo "warning: no file $out/$file; cannot edit" >&2
fi
}
'' + forEach settings_ (file: kv: ''
'' + forEach settings' (file: kv: ''
file=data/init/${lib.escapeShellArg file}.txt
cp ${baseEnv}/"$file" "$out/$file"
if [ -f "${baseEnv}/$file" ]; then
cp "${baseEnv}/$file" "$out/$file"
else
echo "warning: no file ${baseEnv}/$file; cannot copy" >&2
fi
'' + forEach kv (k: v: lib.optionalString (v != null) ''
export k=${lib.escapeShellArg k} v=${lib.escapeShellArg (toTxt v)}
edit_setting
@ -103,7 +119,7 @@ let
# Patch the MD5
orig_md5=$(< "${dwarf-fortress}/hash.md5.orig")
patched_md5=$(< "${dwarf-fortress}/hash.md5")
input_file="${dfhack_}/hack/symbols.xml"
input_file="${dfhack'}/hack/symbols.xml"
output_file="$out/hack/symbols.xml"
echo "[DFHack Wrapper] Fixing Dwarf Fortress MD5:"
@ -112,7 +128,7 @@ let
echo " Output: $output_file"
echo " Replace: $patched_md5"
substitute "$input_file" "$output_file" --replace "$orig_md5" "$patched_md5"
substitute "$input_file" "$output_file" --replace-fail "$orig_md5" "$patched_md5"
'');
# This is a separate environment because the config files to modify may come
@ -124,11 +140,11 @@ let
};
in
lib.throwIf (enableTWBT && !enableDFHack) "dwarf-fortress: TWBT requires DFHack to be enabled"
lib.throwIf (enableTWBT' && !enableDFHack) "dwarf-fortress: TWBT requires DFHack to be enabled"
lib.throwIf (enableStoneSense && !enableDFHack) "dwarf-fortress: StoneSense requires DFHack to be enabled"
lib.throwIf (enableTextMode && enableTWBT) "dwarf-fortress: text mode and TWBT are mutually exclusive"
lib.throwIf (enableTextMode && enableTWBT') "dwarf-fortress: text mode and TWBT are mutually exclusive"
stdenv.mkDerivation {
stdenv.mkDerivation rec {
pname = "dwarf-fortress";
version = dwarf-fortress.dfVersion;
@ -136,36 +152,40 @@ stdenv.mkDerivation {
name = "dwarf-fortress-init";
src = ./dwarf-fortress-init.in;
inherit env;
exe =
if stdenv.isLinux then "libs/Dwarf_Fortress"
else "dwarfort.exe";
inherit (dwarf-fortress) exe;
stdenv_shell = "${stdenv.shell}";
cp = "${coreutils}/bin/cp";
rm = "${coreutils}/bin/rm";
ln = "${coreutils}/bin/ln";
cat = "${coreutils}/bin/cat";
mkdir = "${coreutils}/bin/mkdir";
printf = "${coreutils}/bin/printf";
uname = "${coreutils}/bin/uname";
};
runDF = ./dwarf-fortress.in;
runDFHack = ./dfhack.in;
runSoundSense = ./soundSense.in;
passthru = {
inherit dwarf-fortress dwarf-therapist twbt env;
dfhack = dfhack_;
dfhack = dfhack';
};
buildCommand = ''
dontUnpack = true;
dontBuild = true;
preferLocalBuild = true;
installPhase = ''
mkdir -p $out/bin
substitute $runDF $out/bin/dwarf-fortress \
--subst-var-by stdenv_shell ${stdenv.shell} \
--subst-var-by dfExe ${dwarf-fortress.exe} \
--subst-var dfInit
chmod 755 $out/bin/dwarf-fortress
'' + lib.optionalString enableDFHack ''
substitute $runDFHack $out/bin/dfhack \
substitute $runDF $out/bin/dfhack \
--subst-var-by stdenv_shell ${stdenv.shell} \
--subst-var-by dfExe dfhack \
--subst-var dfInit
chmod 755 $out/bin/dfhack
'' + lib.optionalString enableSoundSense ''
@ -176,7 +196,51 @@ stdenv.mkDerivation {
chmod 755 $out/bin/soundsense
'';
preferLocalBuild = true;
doInstallCheck = true;
nativeInstallCheckInputs = [ expect xvfb-run ];
installCheckPhase = let
commonExpectComponents = fmod: ''
${lib.optionalString isV50 ''expect "Loading audio..."''}
${lib.optionalString (!fmod && isV50) ''expect "Failed to load fmod, trying SDL_mixer"''}
${lib.optionalString isV50 ''expect "Audio loaded successfully!"''}
expect "Loading bindings from data/init/interface.txt"
'';
dfHackExpectScript = writeText "dfhack-test.exp" ''
spawn xvfb-run $env(out)/bin/dfhack
${commonExpectComponents false}
expect "DFHack version ${version}"
expect "\[DFHack\]#"
send -- "lua print(os.getenv('out'))\r"
expect "$env(out)"
# Don't send 'die' here; just exit. Some versions of dfhack crash on exit.
exit 0
'';
vanillaExpectScript = fmod: writeText "vanilla-test.exp" ''
spawn ${lib.optionalString fmod "env NIXPKGS_DF_OPTS=fmod"} xvfb-run $env(out)/bin/dwarf-fortress
${commonExpectComponents fmod}
exit 0
'';
in
''
export HOME="$(mktemp -dt dwarf-fortress.XXXXXX)"
'' + lib.optionalString enableDFHack ''
expect ${dfHackExpectScript}
df_home="$(find ~ -name "df_*" | head -n1)"
test -f "$df_home/dfhack"
'' + lib.optionalString isV50 ''
expect ${vanillaExpectScript true}
df_home="$(find ~ -name "df_*" | head -n1)"
test ! -f "$df_home/dfhack"
test -f "$df_home/libfmod_plugin.so"
'' + ''
expect ${vanillaExpectScript false}
df_home="$(find ~ -name "df_*" | head -n1)"
test ! -f "$df_home/dfhack"
test ! -f "$df_home/libfmod_plugin.so"
'' + ''
test -d "$df_home/data"
'';
inherit (dwarf-fortress) meta;
}

View File

@ -1,11 +0,0 @@
#!@stdenv_shell@ -e
source @dfInit@
for i in *.init *.init-example dfhack-config/default dfhack-config/init hack/* stonesense/*; do
if [ -e "$i" ]; then update_path "$i"; fi
done
cd "$DF_DIR"
LD_LIBRARY_PATH="$env_dir/hack/libs:$env_dir/hack${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" \
LD_PRELOAD="$env_dir/hack/libdfhack.so:$LD_PRELOAD" exec $env_dir/libs/Dwarf_Fortress "$@"

View File

@ -1,45 +1,113 @@
#!@stdenv_shell@ -e
shopt -s extglob
[ -z "$DF_DIR" ] && export DF_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/df_linux"
env_dir="@env@"
exe="$env_dir/@exe@"
if [ -n "$DF_DIR" ]; then
# Compatibility for users that were using DF_DIR, since the dfhack script clobbers this variable.
export NIXPKGS_DF_HOME="$DF_DIR"
fi
if [ -z "$NIXPKGS_DF_HOME" ]; then
export NIXPKGS_DF_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/df_linux"
fi
# Compatibility.
export DF_DIR="$NIXPKGS_DF_HOME"
update_path() {
local path="$1"
@mkdir@ -p "$DF_DIR/$(dirname "$path")"
@mkdir@ -p "$NIXPKGS_DF_HOME/$(dirname "$path")"
# If user has replaced these data directories, let them stay.
if [ ! -e "$DF_DIR/$path" ] || [ -L "$DF_DIR/$path" ]; then
@rm@ -f "$DF_DIR/$path"
@ln@ -s "$env_dir/$path" "$DF_DIR/$path"
if [ ! -e "$NIXPKGS_DF_HOME/$path" ] || [ -L "$NIXPKGS_DF_HOME/$path" ]; then
@rm@ -f "$NIXPKGS_DF_HOME/$path"
@ln@ -s "$env_dir/$path" "$NIXPKGS_DF_HOME/$path"
fi
}
cleanup_path() {
local path="$1"
# Let them stay if not a link.
if [ ! -e "$NIXPKGS_DF_HOME/$path" ] || [ -L "$NIXPKGS_DF_HOME/$path" ]; then
@rm@ -f "$NIXPKGS_DF_HOME/$path"
fi
}
forcecopy_path() {
local path="$1"
@mkdir@ -p "$DF_DIR/$(dirname "$path")"
@rm@ -rf "$DF_DIR/$path"
@cp@ -rL --no-preserve=all "$env_dir/$path" "$DF_DIR/$path"
@mkdir@ -p "$NIXPKGS_DF_HOME/$(dirname "$path")"
@rm@ -rf "$NIXPKGS_DF_HOME/$path"
@cp@ -rL --no-preserve=all "$env_dir/$path" "$NIXPKGS_DF_HOME/$path"
}
@mkdir@ -p "$DF_DIR"
declare -A _NIXPKGS_DF_OPTS
# Don't use fmod by default.
_NIXPKGS_DF_OPTS[fmod]=0
IFS=',' read -ra split_options <<< "$NIXPKGS_DF_OPTS"
for option in "${split_options[@]}"; do
key="${option%=*}"
value="${option##*=}"
if [ -z "$value" ] || [ "$key" == "$value" ]; then
value=1
fi
_NIXPKGS_DF_OPTS["$key"]="$value"
done
@mkdir@ -p "$NIXPKGS_DF_HOME"
@cat@ <<EOF >&2
Using $DF_DIR as Dwarf Fortress overlay directory.
If you do any changes in it, don't forget to clean it when updating the game version!
We try to detect changes based on data directories being symbolic links -- keep this in mind.
/------------------------------------------------------------------------------\\
| Hello from the nixpkgs Dwarf Fortress wrapper! |
| |
| Using the following Dwarf Fortress overlay directory as NIXPKGS_DF_HOME: |
| $(@printf@ '% -76s' "$NIXPKGS_DF_HOME") |
| |
| If you make any changes in it, don't forget to clean it when updating the |
| game version! We detect changes if data directories are symbolic links. |
| |
| Even though we do our best on our own, this script may miss some. Submit a |
| pull request if there are any that become a problem. |
| |
| We started with the following nixpkgs launch options as NIXPKGS_DF_OPTS: |
| $(@printf@ '% -76s' "$(IFS=',' echo "${_NIXPKGS_DF_OPTS[@]@K}")") |
| |
| If you want to try fmod over SDL_mixer, set NIXPKGS_DF_OPTS=fmod. |
\\------------------------------------------------------------------------------/
EOF
cd "$env_dir"
for i in data/init/* data/!(init|index|announcement) raw; do
update_path "$i"
# All potential important files in DF 50 and below.
for path in dwarfort *.so libs raw data/init/* data/!(init|index|announcement); do
force_delete=0
if [[ "$path" == libfmod*.so* ]] && [ "${_NIXPKGS_DF_OPTS[fmod]}" -eq 0 ]; then
force_delete=1
fi
if [ -e "$path" ] && [ "$force_delete" -eq 0 ]; then
update_path "$path"
else
cleanup_path "$path"
fi
done
forcecopy_path data/index
# For some reason, it's needed to be writable...
forcecopy_path data/announcement
forcecopy_path data/help
forcecopy_path data/dipscript
# These need to be copied due to read only flags on older versions of DF.
for path in index announcement help dipscript; do
if [ -e "data/$path" ]; then
forcecopy_path "data/$path"
else
@rm@ -f "$NIXPKGS_DF_HOME/$path" &>/dev/null
fi
done
# Handle library paths on Darwin.
if [ "$(@uname@)" == Darwin ]; then
export DYLD_LIBRARY_PATH="$env_dir/libs"
export DYLD_FRAMEWORK_PATH="$env_dir/libs"
fi

View File

@ -2,8 +2,38 @@
source @dfInit@
export DYLD_LIBRARY_PATH="$env_dir/libs"
export DYLD_FRAMEWORK_PATH="$env_dir/libs"
set -euo pipefail
cd "$DF_DIR"
exec "$exe" "$@"
exe="@dfExe@"
# If we're switching back from dfhack to vanilla, cleanup all dfhack
# links so Dwarf Fortress doesn't autoload its leftover libdfhooks.so.
# Otherwise, populate them.
dfhack_files=(
dfhack
dfhack-run
.dfhackrc
libdfhooks.so
dfhack-config/default
dfhack-config/init
hack/*
stonesense/*
*.init *.init-example
)
if [ "${exe##*/}" == dfhack ]; then
for i in "${dfhack_files[@]}"; do
if [ -e "$i" ]; then
update_path "$i"
else
cleanup_path "$i"
fi
done
else
for i in "${dfhack_files[@]}"; do
cleanup_path "$i"
done
fi
# Go!
cd "$NIXPKGS_DF_HOME" && exec "./$exe" "$@"