push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
{
lib,
stdenv,
fetchurl,
love,
makeWrapper,
makeDesktopItem,
copyDesktopItems,
}:
let
pname = "90secondportraits";
icon = fetchurl {
url = "http://tangramgames.dk/img/thumb/90secondportraits.png";
sha256 = "13k6cq8s7jw77j81xfa5ri41445m778q6iqbfplhwdpja03c6faw";
};
desktopItems = [
(makeDesktopItem {
name = "90secondportraits";
exec = pname;
icon = icon;
comment = "A silly speed painting game";
desktopName = "90 Second Portraits";
genericName = "90secondportraits";
categories = [ "Game" ];
})
];
in
stdenv.mkDerivation rec {
inherit pname desktopItems;
version = "1.01b";
src = fetchurl {
url = "https://github.com/SimonLarsen/90-Second-Portraits/releases/download/${version}/${pname}-${version}.love";
sha256 = "0jj3k953r6vb02212gqcgqpb4ima87gnqgls43jmylxq2mcm33h5";
};
nativeBuildInputs = [
makeWrapper
copyDesktopItems
];
dontUnpack = true;
installPhase = ''
runHook preInstall
install -Dm444 $src $out/share/games/lovegames/${pname}.love
makeWrapper ${love}/bin/love $out/bin/${pname} \
--add-flags $out/share/games/lovegames/${pname}.love
runHook postInstall
'';
meta = with lib; {
description = "Silly speed painting game";
mainProgram = "90secondportraits";
maintainers = with maintainers; [ leenaars ];
platforms = platforms.linux;
license = with licenses; [
zlib
cc-by-sa-40
cc-by-sa-30 # vendored
x11
mit
];
downloadPage = "http://tangramgames.dk/games/90secondportraits";
};
}

View File

@@ -0,0 +1,28 @@
{
lib,
stdenv,
fetchurl,
}:
stdenv.mkDerivation rec {
pname = "amoeba-data";
version = "1.1";
src = fetchurl {
url = "http://http.debian.net/debian/pool/non-free/a/amoeba-data/amoeba-data_${version}.orig.tar.gz";
sha256 = "1bgclr1v63n14bj9nwzm5zxg48nm0cla9bq1rbd5ylxra18k0jbg";
};
installPhase = ''
mkdir -p $out/share/amoeba
cp demo.dat $out/share/amoeba/
'';
meta = with lib; {
description = "Fast-paced, polished OpenGL demonstration by Excess (data files)";
homepage = "https://packages.qa.debian.org/a/amoeba-data.html";
license = licenses.unfree;
maintainers = [ maintainers.dezgeg ];
platforms = platforms.all;
};
}

View File

@@ -0,0 +1,70 @@
{
lib,
stdenv,
fetchurl,
amoeba-data,
alsa-lib,
expat,
freetype,
gtk3,
libvorbis,
libGLU,
xorg,
pkg-config,
installShellFiles,
}:
stdenv.mkDerivation rec {
pname = "amoeba";
version = "1.1";
debver = "31";
srcs = [
(fetchurl {
url = "http://http.debian.net/debian/pool/contrib/a/amoeba/amoeba_${version}.orig.tar.gz";
hash = "sha256-NT6oMuAlTcVZEnYjMCF+BD+k3/w7LfWEmj6bkQln3sM=";
})
(fetchurl {
url = "http://http.debian.net/debian/pool/contrib/a/amoeba/amoeba_${version}-${debver}.debian.tar.xz";
hash = "sha256-Ga/YeXbPXjkG/6qd9Z201d14Hlj/Je6DxgzeIQOqrWc=";
})
];
sourceRoot = "amoeba-1.1.orig";
prePatch = ''
patches="${./include-string-h.patch} $(echo ../debian/patches/*.diff)"
'';
postPatch = ''
sed -i packer/pakfile.cpp -e 's|/usr/share/amoeba|${amoeba-data}/share/amoeba|'
sed -i main/linux-config/linux-config.cpp -e 's|libgdk-x11-2.0.so.0|${gtk3}/lib/&|'
sed -i main/linux-config/linux-config.cpp -e 's|libgtk-x11-2.0.so.0|${gtk3}/lib/&|'
'';
nativeBuildInputs = [
pkg-config
installShellFiles
];
buildInputs = [
alsa-lib
expat
freetype
gtk3
libvorbis
libGLU
xorg.libXxf86vm
];
installPhase = ''
mkdir -p $out/bin
cp amoeba $out/bin/
installManPage ../debian/amoeba.1
'';
meta = with lib; {
description = "Fast-paced, polished OpenGL demonstration by Excess";
homepage = "https://packages.qa.debian.org/a/amoeba.html";
license = licenses.gpl2Only; # Engine is GPLv2, data files in amoeba-data nonfree
maintainers = [ maintainers.dezgeg ];
platforms = platforms.linux;
};
}

View File

@@ -0,0 +1,12 @@
diff --git a/image/png_image.cpp b/image/png_image.cpp
index 37875fc..1531d6f 100644
--- a/image/png_image.cpp
+++ b/image/png_image.cpp
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <png.h>
#include "png_image.h"

View File

@@ -0,0 +1,23 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "adjust-sound-volume";
version = "0.0.6";
src = fetchFromGitHub {
owner = "mnogu";
repo = "adjust-sound-volume";
rev = "v${finalAttrs.version}";
hash = "sha256-6reIUz+tHKd4KQpuofLa/tIL5lCloj3yODZ8Cz29jFU=";
};
passthru.updateScript = nix-update-script { };
meta = {
description = "Add a new menu item for adjusting the sound volume";
homepage = "https://github.com/mnogu/adjust-sound-volume";
license = lib.licenses.agpl3Plus;
maintainers = with lib.maintainers; [ junestepp ];
};
})

View File

@@ -0,0 +1,27 @@
{
lib,
anki-utils,
fetchFromSourcehut,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "anki-connect";
version = "24.7.25.0";
src = fetchFromSourcehut {
owner = "~foosoft";
repo = "anki-connect";
rev = finalAttrs.version;
hash = "sha256-N98EoCE/Bx+9QUQVeU64FXHXSek7ASBVv1b9ltJ4G1U=";
};
sourceRoot = "${finalAttrs.src.name}/plugin";
passthru.updateScript = nix-update-script { };
meta = {
description = ''
Enable external applications such as Yomichan to communicate
with Anki over a simple HTTP API
'';
homepage = "https://foosoft.net/projects/anki-connect/";
license = lib.licenses.gpl3Plus;
maintainers = with lib.maintainers; [ junestepp ];
};
})

View File

@@ -0,0 +1,27 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "anki-quizlet-importer-extended";
version = "2025.03.13";
src = fetchFromGitHub {
owner = "sviatoslav-lebediev";
repo = "anki-quizlet-importer-extended";
tag = "v${finalAttrs.version}";
hash = "sha256-46j/CXhsrehu00P5QLuOj/08gNlFeJttslAFLgz7AJ8=";
};
passthru.updateScript = nix-update-script { };
meta = {
description = "Import Quizlet Decks into Anki";
homepage = "https://ankiweb.net/shared/info/1362209126";
downloadPage = "https://github.com/sviatoslav-lebediev/anki-quizlet-importer-extended";
changelog = "https://github.com/sviatoslav-lebediev/anki-quizlet-importer-extended/releases/tag/v${finalAttrs.version}";
# No license file, but it can be assumed to be AGPL3 based on
# https://ankiweb.net/account/terms.
license = lib.licenses.agpl3Only;
maintainers = with lib.maintainers; [ ethancedwards8 ];
};
})

View File

@@ -0,0 +1,127 @@
{
lib,
stdenv,
symlinkJoin,
lndir,
formats,
runCommand,
}:
{
buildAnkiAddon = lib.extendMkDerivation {
constructDrv = stdenv.mkDerivation;
extendDrvArgs =
finalAttrs:
{
pname,
version,
src,
sourceRoot ? "",
configurePhase ? ''
runHook preConfigure
runHook postConfigure
'',
buildPhase ? ''
runHook preBuild
runHook postBuild
'',
dontPatchELF ? true,
dontStrip ? true,
nativeBuildInputs ? [ ],
passthru ? { },
meta ? { },
# Script run after "user_files" folder is populated.
# Used when an add-on needs to process and change "user_files" based
# on what the user added to it.
processUserFiles ? "",
...
}:
{
inherit
version
src
sourceRoot
configurePhase
buildPhase
dontPatchELF
dontStrip
nativeBuildInputs
;
pname = "anki-addon-${pname}";
installPrefix = "share/anki/addons/${pname}";
installPhase = ''
runHook preInstall
mkdir -p "$out/$installPrefix/user_files"
find . -mindepth 1 -maxdepth 1 | xargs -d'\n' mv -t "$out/$installPrefix/"
runHook postInstall
'';
passthru = {
withConfig =
{
# JSON add-on config. The available options for an add-on are in its
# config.json file.
# See https://addon-docs.ankiweb.net/addon-config.html#config-json
config ? { },
# Path to a folder to be merged with the add-on "user_files" folder.
# See https://addon-docs.ankiweb.net/addon-config.html#user-files.
userFiles ? null,
}:
let
metaConfigFormat = formats.json { };
addonMetaConfig = metaConfigFormat.generate "meta.json" { inherit config; };
in
symlinkJoin {
pname = "${finalAttrs.pname}-with-config";
inherit (finalAttrs) version meta;
paths = [
finalAttrs.finalPackage
];
postBuild = ''
cd $out/${finalAttrs.installPrefix}
rm -f meta.json
ln -s ${addonMetaConfig} meta.json
${
if (userFiles != null) then
''
${lndir}/bin/lndir -silent "${userFiles}" user_files
''
else
""
}
${processUserFiles}
'';
};
}
// passthru;
meta = {
platforms = lib.platforms.all;
}
// meta;
};
};
buildAnkiAddonsDir =
addonPackages:
let
addonDirs = map (pkg: "${pkg}/share/anki/addons") addonPackages;
addons = lib.concatMapStringsSep " " (p: "${p}/*") addonDirs;
in
runCommand "anki-addons" { } ''
mkdir $out
[[ '${addons}' ]] || exit 0
for addon in ${addons}; do
ln -s "$addon" $out/
done
'';
}

View File

@@ -0,0 +1,24 @@
{
callPackage,
}:
{
adjust-sound-volume = callPackage ./adjust-sound-volume { };
anki-connect = callPackage ./anki-connect { };
anki-quizlet-importer-extended = callPackage ./anki-quizlet-importer-extended { };
local-audio-yomichan = callPackage ./local-audio-yomichan { };
passfail2 = callPackage ./passfail2 { };
puppy-reinforcement = callPackage ./puppy-reinforcement { };
recolor = callPackage ./recolor { };
reviewer-refocus-card = callPackage ./reviewer-refocus-card { };
review-heatmap = callPackage ./review-heatmap { };
yomichan-forvo-server = callPackage ./yomichan-forvo-server { };
}

View File

@@ -0,0 +1,73 @@
{
lib,
anki-utils,
fetchFromGitHub,
python3,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "local-audio-yomichan";
version = "0-unstable-2025-04-26";
src = fetchFromGitHub {
owner = "yomidevs";
repo = "local-audio-yomichan";
rev = "34750f1d8ca1cb473128fea7976a4d981e5e78a4";
sparseCheckout = [ "plugin" ];
hash = "sha256-2gyggcvxParay+1B7Sg2COKyocoxaRO1WTz+ymdRp4w=";
};
sourceRoot = "${finalAttrs.src.name}/plugin";
processUserFiles = ''
# Addon will try to load extra stuff unless Python package name is "plugin".
temp=$(mktemp -d)
ln -s $PWD $temp/plugin
# Addoon expects `user_files` dir at `$XDG_DATA_HOME/local-audio-yomichan`
ln -s $PWD/user_files $temp/local-audio-yomichan
PYTHONPATH=$temp \
WO_ANKI=1 \
XDG_DATA_HOME=$temp \
${lib.getExe python3} -c \
"from plugin import db_utils; \
db_utils.init_db()"
'';
passthru.updateScript = nix-update-script {
extraArgs = [ "--version=branch" ];
};
meta = {
description = "Run a local audio server for Yomitan";
longDescription = ''
This add-on must be configured with an audio collection.
Example:
```nix
pkgs.ankiAddons.local-audio-yomichan.withConfig {
userFiles =
let
audio-collection =
pkgs.runCommand "local-yomichan-audio-collection"
{
outputHashMode = "recursive";
outputHash = "sha256-NxbcXh2SDPfCd+ZHAWT5JdxRecNbT4Xpo0pxX5/DOfo=";
src = pkgs.requireFile {
name = "local-yomichan-audio-collection-2023-06-11-opus.tar.xz";
url = "https://github.com/yomidevs/local-audio-yomichan?tab=readme-ov-file#steps";
sha256 = "1xsxp8iggklv77rj972mqaa1i8f9hvr3ir0r2mwfqcdz4q120hr1";
};
}
'''
mkdir -p $out
cd $out
tar -xf "$src"
''';
in
"''${audio-collection}/user_files";
}
```
'';
homepage = "https://github.com/yomidevs/local-audio-yomichan";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ junestepp ];
};
})

View File

@@ -0,0 +1,34 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "passfail2";
version = "0.3.0-unstable-2024-10-17";
src = fetchFromGitHub {
owner = "lambdadog";
repo = "passfail2";
rev = "d5313e4f1217e968b36edbc0a4fe92386209ffe6";
hash = "sha256-HMe6/fHpYj/MN0dUFj3W71vK7qqcp9l1xm8SAiKkJLs=";
};
buildPhase = ''
runHook preBuild
substitute build_info.py.in build_info.py \
--replace-fail '$version' '"${finalAttrs.version}"'
runHook postBuild
'';
passthru.updateScript = nix-update-script { };
meta = {
description = ''
Replaces the default Anki review buttons with only two options:
Fail and Pass
'';
homepage = "https://github.com/lambdadog/passfail2";
license = lib.licenses.gpl3Plus;
maintainers = with lib.maintainers; [ junestepp ];
};
})

View File

@@ -0,0 +1,39 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "puppy-reinforcement";
version = "1.1.1";
src = fetchFromGitHub {
owner = "glutanimate";
repo = "puppy-reinforcement";
tag = "v${finalAttrs.version}";
hash = "sha256-y52AjmYrFTcTwd4QAcJzK5R9wwxUSlvnN3C2O/r5cHk=";
};
sourceRoot = "${finalAttrs.src.name}/src/puppy_reinforcement";
passthru.updateScript = nix-update-script { };
meta = {
description = "Encourage learners with pictures of cute puppies";
longDescription = ''
The options to configure this add-on can be found [here](https://github.com/glutanimate/puppy-reinforcement/blob/v${finalAttrs.version}/src/puppy_reinforcement/config.md).
Extra images can also be added with `userFiles`.
Example:
```nix
pkgs.ankiAddons.puppy-reinforcement.withConfig {
config = {
encourage_every = 5;
};
userFiles = ./my-folder-of-the-most-cute-dogos;
}
```
'';
homepage = "https://ankiweb.net/shared/info/1722658993";
license = lib.licenses.agpl3Plus;
maintainers = with lib.maintainers; [ lomenzel ];
};
})

View File

@@ -0,0 +1,27 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "recolor";
version = "3.1";
src = fetchFromGitHub {
owner = "AnKing-VIP";
repo = "AnkiRecolor";
rev = finalAttrs.version;
sparseCheckout = [ "src/addon" ];
hash = "sha256-28DJq2l9DP8O6OsbNQCZ0pm4S6CQ3Yz0Vfvlj+iQw8Y=";
};
sourceRoot = "${finalAttrs.src.name}/src/addon";
passthru.updateScript = nix-update-script { };
meta = {
description = "ReColor your Anki desktop to whatever aesthetic you like";
homepage = "https://github.com/AnKing-VIP/AnkiRecolor";
# No license file, but it can be assumed to be AGPL3 based on
# https://ankiweb.net/account/terms.
license = lib.licenses.agpl3Only;
maintainers = with lib.maintainers; [ junestepp ];
};
})

View File

@@ -0,0 +1,26 @@
---
src/web/main.ts | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/web/main.ts b/src/web/main.ts
index 389c7fc..0b7c702 100644
--- a/src/web/main.ts
+++ b/src/web/main.ts
@@ -29,8 +29,12 @@ listed here: <https://glutanimate.com/contact/>.
Any modifications to this file must keep this entire header intact.
*/
-import "./_vendor/cal-heatmap.css";
-import "./css/review-heatmap.css";
+import calHeatmapCss from "./_vendor/cal-heatmap.css";
+import reviewHeatmapCss from "./css/review-heatmap.css";
+
+var __vite_style__ = document.createElement('style');
+__vite_style__.textContent = calHeatmapCss + "\n" + reviewHeatmapCss;
+document.head.appendChild(__vite_style__);
import { CalHeatMap } from "./_vendor/cal-heatmap.js";
import { ReviewHeatmapOptions, ReviewHeatmapData } from "./types";
--
2.49.0

View File

@@ -0,0 +1,60 @@
{
lib,
anki-utils,
fetchFromGitHub,
esbuild,
aab,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "review-heatmap";
version = "1.0.1";
src = fetchFromGitHub {
owner = "glutanimate";
repo = "review-heatmap";
tag = "v${finalAttrs.version}";
hash = "sha256-CL98DYikumoPR/QTWcMMwpd/tEpKLIDVC1Rj5NEvWJ8=";
# Needed files are set to export-ignore in .gitattributes
forceFetchGit = true;
};
patches = [ ./0001-Apply-vite-style-to-anki-review-heatmap.js.patch ];
nativeBuildInputs = [
aab
esbuild
];
buildPhase = ''
runHook preBuild
# Work around missing icons
mkdir resources/icons/optional
touch resources/icons/optional/{patreon.svg,thanks.svg,twitter.svg,youtube.svg}
mkdir -p build/dist
cp -r src resources designer --target-directory build/dist
aab build_dist ${finalAttrs.version} --modtime -1
# build anki-review-heatmap.js
esbuild \
src/web/main.ts \
--bundle \
--minify \
--target=es2015 \
--loader:.css=text \
--outfile=build/dist/src/review_heatmap/web/anki-review-heatmap.js
cd build/dist/src/review_heatmap
runHook postBuild
'';
meta = {
description = "Anki add-on to help you keep track of your review activity";
homepage = "https://github.com/glutanimate/review-heatmap";
changelog = "https://github.com/glutanimate/review-heatmap/blob/v${finalAttrs.version}/CHANGELOG.md";
license = lib.licenses.agpl3Only;
maintainers = with lib.maintainers; [ eljamm ];
};
})

View File

@@ -0,0 +1,30 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon (finalAttrs: {
pname = "reviewer-refocus-card";
version = "0-unstable-2022-12-24";
src = fetchFromGitHub {
owner = "glutanimate";
repo = "anki-addons-misc";
rev = "7b981836e0a6637a1853f3e8d73d022ab95fed31";
sparseCheckout = [ "src/reviewer_refocus_card" ];
hash = "sha256-181hyc4ED+0lBzn1FnrBvNIYIUQF8xEDB3uHK6SkpHw=";
};
sourceRoot = "${finalAttrs.src.name}/src/reviewer_refocus_card";
passthru.updateScript = nix-update-script {
extraArgs = [ "--version=branch" ];
};
meta = {
description = ''
Set focus to the card area, allowing you to scroll through your cards using
Page Up / Page Down, etc
'';
homepage = "https://github.com/glutanimate/anki-addons-misc";
license = lib.licenses.agpl3Only;
maintainers = with lib.maintainers; [ junestepp ];
};
})

View File

@@ -0,0 +1,25 @@
{
lib,
anki-utils,
fetchFromGitHub,
nix-update-script,
}:
anki-utils.buildAnkiAddon {
pname = "yomichan-forvo-server";
version = "0-unstable-2024-10-21";
src = fetchFromGitHub {
owner = "jamesnicolas";
repo = "yomichan-forvo-server";
rev = "364fc6d5d10969f516e0fa283460dfaf08c98e15";
hash = "sha256-Jpee9hkXCiBmSW7hzJ1rAg45XVIiLC8WENc09+ySFVI=";
};
passthru.updateScript = nix-update-script {
extraArgs = [ "--version=branch" ];
};
meta = {
description = "Audio server for yomichan that scrapes forvo for audio files";
homepage = "https://github.com/jamesnicolas/yomichan-forvo-server";
license = lib.licenses.unlicense;
maintainers = with lib.maintainers; [ junestepp ];
};
}

139
pkgs/games/anki/bin.nix Normal file
View File

@@ -0,0 +1,139 @@
{
fetchurl,
stdenv,
lib,
buildFHSEnv,
appimageTools,
writeShellScript,
anki,
undmg,
zstd,
cacert,
commandLineArgs ? [ ],
}:
let
pname = "anki-bin";
# Update hashes for both Linux and Darwin!
version = "25.02.5";
sources = {
linux = fetchurl {
url = "https://github.com/ankitects/anki/releases/download/${version}/anki-${version}-linux-qt6.tar.zst";
hash = "sha256-wYFqT1g+rtoqOR7+Bb5mIJLZ5JdT2M1kcHqJUCuNElA=";
};
# For some reason anki distributes completely separate dmg-files for the aarch64 version and the x86_64 version
darwin-x86_64 = fetchurl {
url = "https://github.com/ankitects/anki/releases/download/${version}/anki-${version}-mac-intel-qt6.dmg";
hash = "sha256-PDlu+oFKWHraPdTuGDCUkO0bhPtkNVibo11B1QkCICw=";
};
darwin-aarch64 = fetchurl {
url = "https://github.com/ankitects/anki/releases/download/${version}/anki-${version}-mac-apple-qt6.dmg";
hash = "sha256-RqcGHXN29GDGGuFbrQCBmj3cctzoRQZ8svR5hMYPhxs=";
};
};
unpacked = stdenv.mkDerivation {
inherit pname version;
nativeBuildInputs = [ zstd ];
src = sources.linux;
installPhase = ''
runHook preInstall
xdg-mime () {
echo Stubbed!
}
export -f xdg-mime
PREFIX=$out bash install.sh
runHook postInstall
'';
};
meta = with lib; {
inherit (anki.meta)
license
homepage
description
mainProgram
longDescription
;
platforms = [
"x86_64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
maintainers = with maintainers; [
mahmoudk1000
cything
];
};
passthru = {
inherit sources;
};
fhsEnvAnki = buildFHSEnv (
appimageTools.defaultFhsEnvArgs
// {
inherit pname version;
profile = ''
# anki vendors QT and mixing QT versions usually causes crashes
unset QT_PLUGIN_PATH
# anki uses the system ssl cert, without it plugins do not download/update
export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
'';
# Dependencies of anki
targetPkgs =
pkgs:
(with pkgs; [
xorg.libxkbfile
xorg.libxshmfence
xcb-util-cursor-HEAD
krb5
zstd
]);
runScript = writeShellScript "anki-wrapper.sh" ''
exec ${unpacked}/bin/anki ${lib.strings.escapeShellArgs commandLineArgs} "$@"
'';
extraInstallCommands = ''
ln -s ${pname} $out/bin/anki
mkdir -p $out/share
cp -R ${unpacked}/share/applications \
${unpacked}/share/man \
${unpacked}/share/pixmaps \
$out/share/
'';
inherit meta passthru;
}
);
in
if stdenv.hostPlatform.isLinux then
fhsEnvAnki
else
stdenv.mkDerivation {
inherit pname version passthru;
src = if stdenv.hostPlatform.isAarch64 then sources.darwin-aarch64 else sources.darwin-x86_64;
nativeBuildInputs = [ undmg ];
sourceRoot = ".";
installPhase = ''
mkdir -p $out/Applications/
cp -a Anki.app $out/Applications/
'';
inherit meta;
}

327
pkgs/games/anki/default.nix Normal file
View File

@@ -0,0 +1,327 @@
{
lib,
stdenv,
writableTmpDirAsHomeHook,
cargo,
fetchFromGitHub,
fetchurl,
installShellFiles,
lame,
mpv-unwrapped,
ninja,
callPackage,
nixosTests,
nodejs,
jq,
protobuf,
python3,
python3Packages,
qt6,
rsync,
rustPlatform,
uv,
writeShellScriptBin,
yarn,
yarn-berry_4,
swift,
mesa,
}:
let
yarn-berry = yarn-berry_4;
pname = "anki";
version = "25.07.5";
rev = "7172b2d26684c7ef9d10e249bd43dc5bf73ae00c";
srcHash = "sha256-nWxRr55Hm40V3Ijw+WetBKNoreLpcvRscgbOZa0REcY=";
cargoHash = "sha256-H/xwPPL6VupSZGLPEThhoeMcg12FvAX3fmNM6zYfqRQ=";
yarnHash = "sha256-adHnV345oDm20R8zGdEiEW+8/mTQAz4oxraybRfmwew=";
pythonDeps = map (meta: {
url = meta.url;
path = toString (fetchurl meta);
}) (lib.importJSON ./uv-deps.json);
src = fetchFromGitHub {
owner = "ankitects";
repo = "anki";
rev = version;
hash = srcHash;
fetchSubmodules = true;
};
cargoDeps = rustPlatform.fetchCargoVendor {
inherit pname version src;
hash = cargoHash;
};
# a wrapper for yarn to skip 'install'
# We do this because we need to patchShebangs after install, so we do it
# ourselves beforehand.
# We also, confusingly, have to use yarn-berry to handle the lockfile (anki's
# lockfile is too new for yarn), but have to use 'yarn' here, because anki's
# build system uses yarn-1 style flags and such.
# I think what's going on here is that yarn-1 in anki's normal build system
# ends up noticing the yarn-file is too new and shelling out to yarn-berry
# itself.
noInstallYarn = writeShellScriptBin "yarn" ''
[[ "$1" == "install" ]] && exit 0
exec ${yarn}/bin/yarn "$@"
'';
uvWheels = stdenv.mkDerivation {
name = "uv-wheels";
phases = [ "installPhase" ];
# otherwise, it's too long of a string
passAsFile = [ "installCommand" ];
installCommand = ''
#!${stdenv.shell}
mkdir -p $out
# note: uv.lock doesn't contain build deps?? https://github.com/astral-sh/uv/issues/5190
# link them in manually
ln -vsf ${python3Packages.setuptools.dist}/*.whl $out
ln -vsf ${python3Packages.editables.dist}/*.whl $out
# we also force nixpkgs pyqt6 stuff because that needs to match the
# nixpkgs qt6 version, otherwise we get linker errors
ln -vsf ${python3Packages.pyqt6.dist}/*.whl $out
ln -vsf ${python3Packages.pyqt6-webengine.dist}/*.whl $out
ln -vsf ${python3Packages.pyqt6-sip.dist}/*.whl $out
''
+ (lib.strings.concatStringsSep "\n" (
map (dep: ''
if ! [[ "${baseNameOf dep.url}" =~ (PyQt|pyqt) ]]; then
ln -vsf ${dep.path} "$out/${baseNameOf dep.url}"
fi
'') pythonDeps
));
installPhase = ''bash $installCommandPath'';
};
in
python3Packages.buildPythonApplication rec {
format = "other";
inherit pname version;
outputs = [
"out"
"doc"
"man"
"lib"
];
inherit src;
patches = [
./patches/disable-auto-update.patch
./patches/remove-the-gl-library-workaround.patch
./patches/skip-formatting-python-code.patch
./patches/fix-compilation-under-rust-1.89.patch
# Used in with-addons.nix
./patches/allow-setting-addons-folder.patch
];
inherit cargoDeps;
missingHashes = ./missing-hashes.json;
yarnOfflineCache = yarn-berry.fetchYarnBerryDeps {
inherit missingHashes;
yarnLock = "${src}/yarn.lock";
hash = yarnHash;
};
nativeBuildInputs = [
uv
cargo
installShellFiles
jq
ninja
nodejs
qt6.wrapQtAppsHook
rsync
rustPlatform.cargoSetupHook
writableTmpDirAsHomeHook
yarn-berry_4.yarnBerryConfigHook
]
++ lib.optional stdenv.hostPlatform.isDarwin swift;
buildInputs = [
qt6.qtbase
qt6.qtsvg
]
++ lib.optional stdenv.hostPlatform.isLinux qt6.qtwayland;
nativeCheckInputs = with python3Packages; [
pytest
mock
astroid
];
# tests fail with too many open files
# TODO: verify if this is still true (I can't, no mac)
doCheck = !stdenv.hostPlatform.isDarwin;
checkFlags = [
# this test is flaky, see https://github.com/ankitects/anki/issues/3619
# also remove from anki-sync-server when removing this
"--skip=deckconfig::update::test::should_keep_at_least_one_remaining_relearning_step"
];
dontUseNinjaInstall = false;
dontWrapQtApps = true;
env = {
# Activate optimizations
RELEASE = true;
# https://github.com/ankitects/anki/blob/24.11/docs/linux.md#packaging-considerations
OFFLINE_BUILD = "1";
NODE_BINARY = lib.getExe nodejs;
PROTOC_BINARY = lib.getExe protobuf;
PYTHON_BINARY = lib.getExe python3;
UV_BINARY = lib.getExe uv;
UV_NO_MANAGED_PYTHON = "1";
UV_SYSTEM_PYTHON = true;
UV_PYTHON_DOWNLOADS = "never";
UV_OFFLINE = "1";
UV_FIND_LINKS = "${uvWheels}";
};
buildPhase = ''
export RUST_BACKTRACE=1
export RUST_LOG=debug
mkdir -p out/pylib/anki .git
echo ${builtins.substring 0 8 rev} > out/buildhash
echo ${python3.version} > .python-version
# Setup the python environment.
# We have 'UV_FIND_LINKS' set, so packages generally should just get picked
# up, so install everything anki wants.
# Note, for pyqt stuff, our versions may not match (see the comment above
# uvWheels), so we don't install those.
mkdir -p ./out/pyenv
uv export > requirements.txt
uv pip install --prefix ./out/pyenv -r requirements.txt
uv export --project qt --extra qt --extra audio \
--no-emit-package "pyqt6" \
--no-emit-package "pyqt6-qt6" \
--no-emit-package "pyqt6-webengine" \
--no-emit-package "pyqt6-webengine-qt6" \
--no-emit-package "pyqt6-sip" \
> requirements.txt
uv pip install --prefix ./out/pyenv -r requirements.txt
uv export --project pylib > requirements.txt
uv pip install --prefix ./out/pyenv -r requirements.txt
# anki's build tooling expects python in there too
ln -sf $PYTHON_BINARY ./out/pyenv/bin/python
mv node_modules out
# And finally build
patchShebangs ./ninja
export PYTHONPATH=$PYTHONPATH:$PWD/out/pyenv/${python3.sitePackages}
# Necessary for yarn to not complain about 'corepack'
jq 'del(.packageManager)' package.json > package.json.tmp && mv package.json.tmp package.json
YARN_BINARY="${lib.getExe noInstallYarn}" PIP_USER=1 \
./ninja build wheels
'';
# mimic https://github.com/ankitects/anki/blob/76d8807315fcc2675e7fa44d9ddf3d4608efc487/build/ninja_gen/src/python.rs#L232-L250
checkPhase =
let
disabledTestsString =
lib.pipe
[
# assumes / is not writeable, somehow fails on nix-portable brwap
"test_create_open"
]
[
(lib.map (test: "not ${test}"))
(lib.concatStringsSep " and ")
lib.escapeShellArg
];
in
''
runHook preCheck
export PYTHONPATH=$PYTHONPATH:$PWD/out/pyenv/${python3.sitePackages}
HOME=$TMP ANKI_TEST_MODE=1 PYTHONPATH=$PYTHONPATH:$PWD/out/pylib \
pytest -p no:cacheprovider pylib/tests -k ${disabledTestsString}
HOME=$TMP ANKI_TEST_MODE=1 PYTHONPATH=$PYTHONPATH:$PWD/out/pylib:$PWD/pylib:$PWD/out/qt \
pytest -p no:cacheprovider qt/tests -k ${disabledTestsString}
runHook postCheck
'';
installPhase = ''
runHook preInstall
mkdir -p $lib $out
uv pip install out/wheels/*.whl --prefix $lib
# remove non-anki bins from dependencies
find $lib/bin -type f ! -name "anki*" -delete
# and put bin into $out so people can access it. Leave $lib separate to avoid collisions, see
# https://github.com/NixOS/nixpkgs/issues/438598
mv $lib/bin $out/bin
install -D -t $out/share/applications qt/launcher/lin/anki.desktop
install -D -t $doc/share/doc/anki README* LICENSE*
install -D -t $out/share/mime/packages qt/launcher/lin/anki.xml
install -D -t $out/share/pixmaps qt/launcher/lin/anki.{png,xpm}
installManPage qt/launcher/lin/anki.1
runHook postInstall
'';
preFixup = ''
makeWrapperArgs+=(
"''${qtWrapperArgs[@]}"
--prefix PATH ':' "${lame}/bin:${mpv-unwrapped}/bin"
--prefix PYTHONPATH ':' "$lib/${python3.sitePackages}"
)
'';
passthru = {
withAddons = ankiAddons: callPackage ./with-addons.nix { inherit ankiAddons; };
tests.anki-sync-server = nixosTests.anki-sync-server;
};
meta = with lib; {
description = "Spaced repetition flashcard program";
mainProgram = "anki";
longDescription = ''
Anki is a program which makes remembering things easy. Because it is a lot
more efficient than traditional study methods, you can either greatly
decrease your time spent studying, or greatly increase the amount you learn.
Anyone who needs to remember things in their daily life can benefit from
Anki. Since it is content-agnostic and supports images, audio, videos and
scientific markup (via LaTeX), the possibilities are endless. For example:
learning a language, studying for medical and law exams, memorizing
people's names and faces, brushing up on geography, mastering long poems,
or even practicing guitar chords!
'';
homepage = "https://apps.ankiweb.net";
license = licenses.agpl3Plus;
inherit (mesa.meta) platforms;
maintainers = with maintainers; [
euank
junestepp
oxij
];
# Reported to crash at launch on darwin (as of 2.1.65)
broken = stdenv.hostPlatform.isDarwin;
badPlatforms = [
# pyqt6-webengine is broken on darwin
# https://github.com/NixOS/nixpkgs/issues/375059
lib.systems.inspect.patterns.isDarwin
];
};
}

View File

@@ -0,0 +1,92 @@
{
"@dprint/darwin-arm64@npm:0.47.4": "67db15f5ae385010d1d80435c1b856ffe461739ab5e9bfb9972d21ef627f610b4aae40d7c53985ddff7d1109e8fc3c283c5a3c0d529b4b010e690577b7d0a36d",
"@dprint/darwin-x64@npm:0.47.4": "fcbbb05193c9174eec7491f2bc4551681099c9930c6ec1bab96699031d6bc83a417e07d332c8e1b4881d18a2814dfa08b1723066ead0d2e93833300ada81ea3a",
"@dprint/linux-arm64-glibc@npm:0.47.4": "9c3d6afd31938f51fe1da6b6aa8f4007c674667ee51edffa8ed92f9ea343b08b3df779f5b4d843363eb656df164ecc2f337b929446e5e9151a1c783d42fef03e",
"@dprint/linux-arm64-musl@npm:0.47.4": "af08edd5fed8725daf6cc49ca5bad03bc6e550d7fa42b596fd3fdc2c5b15013f83a4ae36ee0986934170e18148baf5c4f12c414fba09360624e1cdcf957121f1",
"@dprint/linux-x64-glibc@npm:0.47.4": "215c4033a6f8b0f73cbce552c9e0b39a16169a82088b293bc14b54fc5115de8ecb4f703c943cbf0f9c10375396ff9aed510ed2476723fd31f767c51b408457ab",
"@dprint/linux-x64-musl@npm:0.47.4": "c8b4c979a92fe897220877b40d59aa6e899ca2a39ce5368ba181ef3c3a376a119f4608b2a5e5271d1d811e055882cad86b890abd91970a32fb32ecfb5bbebdd7",
"@dprint/win32-arm64@npm:0.47.4": "5278a87a006758a9fe2b870a571895a6b19afb938cff35a180f192413ddfb8a4b612fcd1817c92e03dc0b587ed0c8ff750213c59d60ef3f0d02a4e2a4c938c5a",
"@dprint/win32-x64@npm:0.47.4": "5c5737f28ca10e51f3a548ad0160868a0b643f56a32eae5c8c151944ff47cb79aa109630c1ecf458233c2a3b521d5d284d3a25b60bbcd38885e7908f0db25d16",
"@esbuild/aix-ppc64@npm:0.25.3": "5e3ec55997c8d3c9c0fa565cbd04f1566795fe47626d63f6a593a39190402869a2561c772d1db5621719fa9db174f4cbc201032447b97a1cc28e69a9426a893e",
"@esbuild/aix-ppc64@npm:0.25.5": "fb872b34a2843293dc60e809968fedf93e0d8f7174b062decffae6ba861eb56aaea0cd0aba87ba99162ceb2a690f0cde4fc29c000b52c035e40c91ec7861d43e",
"@esbuild/android-arm64@npm:0.25.3": "d840843df6b82cc918abea3e706235ae256caa7b6feaf4b78f47d97cfc476ffc905d5e4263f066ae96dcc997bdc4e33458ed3436d6a38d147cd401071dc92d10",
"@esbuild/android-arm64@npm:0.25.5": "c818e799b19b5587466bf68a27b578ccaaf866c1d144573fbde7659e3fd3f555422ec3e67f5bd186a87648957d1b6e74df4f847edea7219c16979c9916f36e91",
"@esbuild/android-arm@npm:0.25.3": "185f4827b86ebc797ec74a98a75256a401eda92af862d217c10268816e8c4feeb49d82e965916dd2df238d7f3eda98325085e8d36cccf63c6cb2d3a11b3c6ee0",
"@esbuild/android-arm@npm:0.25.5": "a5384933f9f2ffcadce2be49da6ff43249fe42f32a04071316434e9f633fc20c8d4029072e9a53555620c3531045786297607b852579eee30b6dbc3bc9d98cd9",
"@esbuild/android-x64@npm:0.25.3": "0328941aaedafe3e0164a93a0e57178ca5fbe5a336709bd24270329a504bdb76bfc4b7a63e07c2f6fdea1fbd4b25d53320ca5665351d477e8e77b2fd071732ee",
"@esbuild/android-x64@npm:0.25.5": "8ce115dc7e1e6735f23b4aadb2dfca29c0abd8577ce34802ea3d017a64e388928949134fe225dfe190babdc5ec01be5fc7794eca84738cdefc12c5e3789ce43b",
"@esbuild/darwin-arm64@npm:0.25.3": "c10ed8ec813cad217666f556481baa0c4286f2a0567ca662fbf3088cb960421729eaf6b5a8504b9c956a1497f88141549af5f7c0f907a27a2c546e75fb4c678e",
"@esbuild/darwin-arm64@npm:0.25.5": "a009eab62f2bd284a6f2001d5e08217059186ffc16907bbe873e1de40fe9b5ed92c0db2f4c4d0dc41545838850a430c8f2f35d7bdb9cd01a1a04293acd97afca",
"@esbuild/darwin-x64@npm:0.25.3": "9828c988e7a54e63c7afca426348bd09d5c70b4ec799908ec5310347a14c94900f58e14f2b2eeea87d68b382078977bd5d5629546b307e8ac093168a7c72712d",
"@esbuild/darwin-x64@npm:0.25.5": "cac8021a7a0c549263e076913346b35a5bb81f76ffbc1abfad5e7b67303f013ac0c76f111bf624ea8447b327ec86c18a60c6ff307d743a2269f5d47313f5b2de",
"@esbuild/freebsd-arm64@npm:0.25.3": "4b20547db6bc1dea0e14f4bb96fb474d6e80e8d01c4fdc141d77a1693be06aee5ea3d4968f80276f87037086822c336defa358cb315bd671a7af9c672a081811",
"@esbuild/freebsd-arm64@npm:0.25.5": "d248e7103b7094eb4288db7c9a78b2905a25b4a957f2b945531ca88d3394f45ceca2343a7c84954734534af6159bc741eb3d5c1ed9df990f7395337a1b14192c",
"@esbuild/freebsd-x64@npm:0.25.3": "083edc9e2de8f3dc407b52836b49ebea29d0d543786c706b744c77646f5fde53327b786d156b79b859fb61eaac191733d275a183807c8599d51cd4416d00f5d6",
"@esbuild/freebsd-x64@npm:0.25.5": "8a7be0740f07f5dbb3e24bf782ca6ef518a8ce9b53e5d864221722045713586d41774cbd531df97dc868b291b3b303c12e50ca8611c3cb7b5fe09a30b38285eb",
"@esbuild/linux-arm64@npm:0.25.3": "bad206365faf883e5f7615daef3d65b7a82d6c9e401fd67353352c532a42310dcf6491dbf0e094c8007fb6d73e45183bb63cc10585cfaadc1386fbf78c529dc1",
"@esbuild/linux-arm64@npm:0.25.5": "ce3c8fca47cf0a92148fb288eb35a5c4a4dcf7a700730b3a48fdd63c13e17c719eb6b350378203fba773477eb5be637f47a6d52c5d4ce5bdc0075ee917156006",
"@esbuild/linux-arm@npm:0.25.3": "4659e20bf62737bb6ba5e54f36f87260e8092f6c55aed6a73457cb002f7af990bb205ca48d0c19078540a210b65a1db1a1cecd7a4ed06f4fe4eb1c0d27c30bd0",
"@esbuild/linux-arm@npm:0.25.5": "cc81ea76ab86ed2a837c9da329f7c63412d288dc0aa608c8dcdf51705dc93d5b7f966a429be4896babe611074e5898c7e6c8e07ad7f50123a05478975294fbb4",
"@esbuild/linux-ia32@npm:0.25.3": "96cf22e5979c95aff499cf0ebd576e21964d9a7412bf5cd4eb1ab71cb555aef2b4d5d3e8aae34ab80354125f1ec571f0ddb3f728f9e19cebbeceff75bb9d0686",
"@esbuild/linux-ia32@npm:0.25.5": "bfed6750923afd56148f658f6ec8995479f5115116dc212ecb9e4c556064422e22eda855177e7c02cbc945494e4db1167101918c5fa932278115db2c7025a3f6",
"@esbuild/linux-loong64@npm:0.25.3": "9d12d8deaf0bdd5d64c062c65eb0e3ea24ab98b1e6ec34b2b14bb3902e5e3504442c3273f6dc05228f6104650ddaf0d37ba86033f19e7b065766c3d528c0f6a3",
"@esbuild/linux-loong64@npm:0.25.5": "e5c20140bbbdba53f0d86dd72961ed73e6255d2ada2d3a626f390b352170605644822ad7592f695b6e520edcefe0c5f6ba19d10694b5d11d725745d9792bde01",
"@esbuild/linux-mips64el@npm:0.25.3": "f117b06fe2d39b08571fd84ed191801cc9501342a514d5d83494219ad14bee9713b6332d0836f192c224b1f9a01405f3d6e2d22952e399bababd527bfeac9c0f",
"@esbuild/linux-mips64el@npm:0.25.5": "6b3559517efd0dd1301debc7af7e275b055859c26facdda2e229b1aaab6ebea4c480a1da151c46211ee4035d95bfa7f0cdacf735b57ee99d41b69c77357310b9",
"@esbuild/linux-ppc64@npm:0.25.3": "ef777920724eecd3bb20f9718901498001ed8b28ced1a6c9a8e947c5ae412d31856761556b9d89bdae1cd9af3ff53f9c83756fac3b4e99b53ebdce44c5ff0cdd",
"@esbuild/linux-ppc64@npm:0.25.5": "a1a1af99d758efce928335637924dcd8ddec4201af51014e1f831b012d53a0a673b1e0c31036ec9e8c5a0311439283419ec8abdfc67ecb245fa7f7b653006ed0",
"@esbuild/linux-riscv64@npm:0.25.3": "87d71b5c361f7d95c173f8c1051e8dce165ff3d6100ef0e5cbd090f8249c58d7f5a38e93774d081afe4fecf3a6e725102dbf9ffa51e5b4960ccd1b072cf86e10",
"@esbuild/linux-riscv64@npm:0.25.5": "6cd8dce6723b73e0f89898ab6cd52e0d009afdacdfc0d5529134de7b832c92c2e0421fbb5cbfc0e0c0b2b00a9b1ff2c4cdb9695b2c535ebc174960e986c727a7",
"@esbuild/linux-s390x@npm:0.25.3": "9972d82725c5818fca8ef1625c3f55a8033c2d678c809a01580780fd5171025e4f90b60fdfe6ff925a1738bb6cff85dea104fdce57badf0a270ed1d290345e23",
"@esbuild/linux-s390x@npm:0.25.5": "31b86dbc93d19eb362bad3353e65d6da771118346e723582d06c05f1b6ffad1c3765001b5215ef1e8f0c2bb29130d98815359bbc88e5c08304354d5a92e6ea94",
"@esbuild/linux-x64@npm:0.25.3": "434e21ed68e25e2043295fca9c382461bf50f031c45480a1482f297412f95ebfb183339001444e5d1e6b14358571c395f17ddb8bb9bbd22aefe82740463bc18c",
"@esbuild/linux-x64@npm:0.25.5": "f878a3e40edfd8a50de94bf982a9eaf03e636a0332af163a6c905490063aae652384fb392d4765c4338fb6f991034949c92ec768ee65c3b2fceeb494b89fe8b3",
"@esbuild/netbsd-arm64@npm:0.25.3": "4dbc6ef9a5ddcf44f2df0fe39c662189eb4cea38fe5778ecc81cc29af68fba2ac077c5b308ad84b8263bb6bea9f03732507b79966d051d860a2344b8fe8ddc4d",
"@esbuild/netbsd-arm64@npm:0.25.5": "941c5e28a63a93f19122271b5490e196db12815702c2266c6d66401b6909a4364ab889611ba81c5359624e3ce61f0505a680a1179ed9a555d1415fa1c485d75d",
"@esbuild/netbsd-x64@npm:0.25.3": "d42fca551f67c20b18d11cae67fed9675b90293c901b3b152d6e0c1153db1443f7b8a4f7786797b1946d19881db64b50f32e883d756ce3fdf8b844a1c71611f3",
"@esbuild/netbsd-x64@npm:0.25.5": "edbefdd88ca24a373497a7c8d1fdab418827ff89c6eee1c574159dbb4d9174552aa87753f35525a894964b77c14b012164ec5582b9f19dd4d6c1f5d45df411c7",
"@esbuild/openbsd-arm64@npm:0.25.3": "3aee3b70a7f41ce2355d93bd955718683861ffe9e6b5550c37caa28b8b16e6414222c806f413c37eb553c3990a22b8fdb88721c619f553d809db92cd070ed383",
"@esbuild/openbsd-arm64@npm:0.25.5": "d44633a374c109d2fb9c678882016e3ec3d79f0c5f21a6e6fb0114ea709bc539200b037a4e3ec52304eea2f8c5957bf16c6f0a7af5cfde41b652c4bac604bba6",
"@esbuild/openbsd-x64@npm:0.25.3": "d158b78f95feb68c6217f114a3178058aa93933e83897546ffecb6b9ab8e0fe5fed69940651b6c42c1ac9064a42a29fa1c2da316dc64ab146107c2c2599e68c6",
"@esbuild/openbsd-x64@npm:0.25.5": "efc4641ea653dedc9886f0603c2e7cfc6fbe94c34d4cdaee9b060a8b9d8143d1192c45da93b3e802af2c26f72ab1ad3a3fad0e0cb297d06de55814fe83ccd32c",
"@esbuild/sunos-x64@npm:0.25.3": "8b6bd4c43c023d0dcb9966349ec1f2ccdfb6163aea2c1c06060806795ed1fb083e22cb9e80e7853ba8c62a74d1bafa36dabab70881e7d6782c2dfb237f93bcc0",
"@esbuild/sunos-x64@npm:0.25.5": "29860663381b6098c0fda6f69235407654dfad953e83b3f9f06a270950d5c37da4ca60a4b5915b8e2606d468b560be6179870f64a22d5b046e8a930c31a7b554",
"@esbuild/win32-arm64@npm:0.25.3": "c49c827b8cae7eb2a4a6b38a1321c0c1bca1693826c7268d3c3b9361df360b897f583e91b9acff3eeb0c9f477d39c00a2d89c71436b64091442e74011a41f2ed",
"@esbuild/win32-arm64@npm:0.25.5": "a77d395251c8a62ab0cec07d5230222823fa02fbf3ef008d94b5213a335c9f949872c3f1c2f947abaa28098b669018e429af42f59616e049860a0072f3b006de",
"@esbuild/win32-ia32@npm:0.25.3": "84acc7f9d65de4875bfe09976620e94327bef444b1b8a795d98173ca777a2070b775763bd927ee475503455b2c1109bf5c911fdfe7c73de7d32124ccf3858afd",
"@esbuild/win32-ia32@npm:0.25.5": "ff1b6cbe835082aef5b93c3e2012d51be431d05c6ae5f90a5bc89687c687e8e2340c262dedddd124b27b511616bbc4088b5a4a949d3147f677084dc6ec572629",
"@esbuild/win32-x64@npm:0.25.3": "2b88dffa4814240cf7d88a6dee449361ae411a0d9cc6ebc327de59f4f6662a65fb2ef62fa38258bae422933d97a416db50ec4f04875ddf61d15f47bc0ec1ab22",
"@esbuild/win32-x64@npm:0.25.5": "266e69e8d37bd4deb77443588e49472e4e9791178cb39e1692eabb67cf65d8e85a932ac468e7ebb2072c8a9ee23ad413c8f0f7d954c474f643cedbbf7aad952a",
"@parcel/watcher-android-arm64@npm:2.4.1": "88cb813d54227fc25e487f00497cdd58974a07e1c22a5cc7cf922983d908b460e0876ec0c9acf333a5b6f5623dc50729f8b92612970bfbd5a12d4e5cffc025ff",
"@parcel/watcher-darwin-arm64@npm:2.4.1": "342502e0f175dbd0649f2edffc9f7d76823668e12184a62d8e542df454a067bcade1cfd298975bf7238a7575a9d721c6d7ccb0e8c9102dca5394c9fef2349561",
"@parcel/watcher-darwin-x64@npm:2.4.1": "175868753e64ea7bc70993a05a34694e8ad85d9d4a08bf9a36573925777369a0701f2971d6ff14f9ed525c9b7725ce40629cad97fd7c67dc653f247884d99a62",
"@parcel/watcher-freebsd-x64@npm:2.4.1": "844f009d836628ff11119c885bf490077f36a24800ccc2fe8d5acf88c59d29d2495ab5773d1960bc568e9225a4c91147c7804dce2eaace86f3ac619fb0357a44",
"@parcel/watcher-linux-arm-glibc@npm:2.4.1": "f75d589f7403934c39f01c51e89b0d2e43a07041b6d9b7bb14078971cc520a8cb2ca296f6bf19d68335db433fb4bdf7bfd5f445a2a0cebf763e2cc47cd0ecc0c",
"@parcel/watcher-linux-arm64-glibc@npm:2.4.1": "9831629227633c577dc9b3abc3cc7b6c1c5c3635128663cff1658f6cf4546f8ab7803e20f2e33243a566234edcb7591c4a900e2df5a6bed35f4d4b6e19875f04",
"@parcel/watcher-linux-arm64-musl@npm:2.4.1": "b2b1106f5403cbaf3953a8bd99ff82498b7f399ef9ec6e26701e8734db8bffeaeb83b373e71cf71fd936dbf1a0143c72248d94b3eebaced03dc25e529930b945",
"@parcel/watcher-linux-x64-glibc@npm:2.4.1": "fd0e4b06aa26f631b95fc3034d32c83dcce1818c57842ba2c29d79a15b9afa096fd5afc2cd099bb148e4816c3944b831ed1efa421c06317b9e0807664a852556",
"@parcel/watcher-linux-x64-musl@npm:2.4.1": "b7cb299eaeb400e92b0a0a19a343905fe5c4152a12535c9e414a0aa0d6a1151dc9a8b254598be2d82ccee902e9132a4b7a2bee4df85d8f8219d95083daf87d35",
"@parcel/watcher-win32-arm64@npm:2.4.1": "35fc4e90eb74a4e583377821775d5f90269deeaa61221fbb69127b3151279a37d4038df91beb38e51367ebb9d92f6b0295b58c0e4a7ac3ecc0adb0f27c935c69",
"@parcel/watcher-win32-ia32@npm:2.4.1": "0b12602039c1ebb6ea711bde1996ca66d814668a02d33b2b949c66111de9e3fbc6f4d8b9b6c985affa1eafa6089b4c13b0e0db8f8d3a7a2d19849c7d7f639f1c",
"@parcel/watcher-win32-x64@npm:2.4.1": "56f160729dc8c47d940187b4a2e9a4100be77fc2acc2dd5e4cb527d036676eecba454548cf00fb6d7c44757e42d77dc4d2d8ff19c1ce64759a7fde2097aa6bfe",
"@rollup/rollup-android-arm-eabi@npm:4.44.1": "ec8b655e2930312fe94eded1cfe439901bbd442a891494a512259caa0bd936c29b9d06debb061bece88f5d41f619ccb4d0d77d0fe190f1a5c25a3a1a724d255f",
"@rollup/rollup-android-arm64@npm:4.44.1": "5eb5c7de31f435afb97feebd06feefb93c2cb272002240b8530c1f274436ea578d8320d67fa49eb1409ddb20a47219efff59a09b22a426584b881d36adac7bea",
"@rollup/rollup-darwin-arm64@npm:4.44.1": "93cef94c44d1baabc5346148d59ebb5d640948b2895bbc5de6804908999857f331c388eb449f98eba98d2b239492e91211accee7eaf4b579ae3c007705d76246",
"@rollup/rollup-darwin-x64@npm:4.44.1": "d235e7f40080cc19295d45935b83a0238cb66962e7d6d4af0eb261012d80bc344fe073ec9dcc3d39092138a66e7a69c4e79cbac7c6ee49b8329b80d12d52968f",
"@rollup/rollup-freebsd-arm64@npm:4.44.1": "e26f6bf6914e190d72f74da4c8e47c27661fc99f6310f80e664acfcd6262f4981ff043ff53ccc06dc6a232d481f9f0055e32dba3b65442259316b18fc0ea9087",
"@rollup/rollup-freebsd-x64@npm:4.44.1": "d06455bfbe8bf71996864879b8b9b4f95617adda959a5a143be0df9a5bf749cd52740a9a3b2548e67be00eef9ccb99ef04368a052afceae2011e2a817baf4156",
"@rollup/rollup-linux-arm-gnueabihf@npm:4.44.1": "1bb6818627de1434f889c8a6bfc13a0205f25055bcc9f39483e445411c753111c7d082cfca2affdeeaad46c3711e3ece140fabb7173ef3cd19446d3682863854",
"@rollup/rollup-linux-arm-musleabihf@npm:4.44.1": "6e9eff8ad332d9923a7cadc0ce1911c4e0a2f8457a8131485f0bce241bb7c223dc811b976ffb9ca08d4930630c647219dbfcdab639c3a8bef075b68285c01960",
"@rollup/rollup-linux-arm64-gnu@npm:4.44.1": "a5382c59bf531afd774b7de82d1600bfb5915a0708ad6c7099ffd1af657b813a525de18902178120b247c95e21487f0c96a8eecc8d9ae9163da12ecb4a5ed3d3",
"@rollup/rollup-linux-arm64-musl@npm:4.44.1": "44944da3785383b8cdb5f8b4eb627737edc10e206ec66ec6a762f75f2dcc12dff7bfaae864d37941d5d30c50c8fee5f5a2b12c19627b356e0aea3186f80e2d48",
"@rollup/rollup-linux-loongarch64-gnu@npm:4.44.1": "1f7502f1777622abb717a3109bf69907ba46a277a6ea33b99d6cea8e33f74b6d8a979ac5bfa33398f31211687adf7458ef9680b7f2e3523d82088a3d59857c8f",
"@rollup/rollup-linux-powerpc64le-gnu@npm:4.44.1": "535c564216655518831098e5481f06b62452fad69209409776f4508e9c73265dfe531983a64b47c9090b244668b4c023c906061eee5a4c3c29c1c9822f1d1209",
"@rollup/rollup-linux-riscv64-gnu@npm:4.44.1": "423cb7d6578052d23374fe2ec3b996be9a420785fe324a0d1aa38e9e9d3f4b34ba3673f4ce5f622c7ed99bf82c4e24f55469b6e75deb5f27eb67369c052d8a9b",
"@rollup/rollup-linux-riscv64-musl@npm:4.44.1": "03a0530b45b554363296e938493e263aa26c342080aea72c9e2b673fc42d5ed2d9267d283ef136c71da64bc85a03fd360988aedbfc68029bd948567afafe71a6",
"@rollup/rollup-linux-s390x-gnu@npm:4.44.1": "93fecf841caf9621a99b8f0938d21a261ccc1ee7dced2ff47de659662a3bbbc0e3cc45ef38d3aca84918ecaeff51188a68a109db337892518ccfa393c305fafc",
"@rollup/rollup-linux-x64-gnu@npm:4.44.1": "b401ab19f21fb0f8ff50662a9fbe823d4c7904fdf0f8de17c3338107e3974ac89ba1189b7c6f0f2ff8734cfd07325bcb5e5dc6a5d53df076fe34757233063a72",
"@rollup/rollup-linux-x64-musl@npm:4.44.1": "87ef16e6ca9ae5d398f5b7e1b58033cf1b5f87efb0ab7c4b16dc7dd213a1b3a9305c2624b11e89539d75d146912eb7a41a139270464fc617fd1c2917e391fc56",
"@rollup/rollup-win32-arm64-msvc@npm:4.44.1": "5f4fe05f1c778d839ce22c2b1a1419d8c511fd10793326dab5a033978f259733b6d042519a26ad7df3f5b2cce75bfc2d2600d9c43ec9cf16d6acf105bedf00e7",
"@rollup/rollup-win32-ia32-msvc@npm:4.44.1": "5639edf6114f38055489c35f03f5d039b4719ae50309db235dc176c026fb8eb5bb028e0db2769ed4faec34722200f6a31df62c23a0f8c90a13568685a6f00140",
"@rollup/rollup-win32-x64-msvc@npm:4.44.1": "d23d4b88a0a96965ba20e75bb9f5bea6e22cab53b9658a54317634363a64aa43dd1ff66f569d0e4fecc34d60d554a64ae905fd85cbc436f78544d6f9d550ebe2"
}

View File

@@ -0,0 +1,15 @@
diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py
index 469908c1b2..34612d6e08 100644
--- a/qt/aqt/profiles.py
+++ b/qt/aqt/profiles.py
@@ -310,7 +310,9 @@ def profileFolder(self, create: bool = True) -> str:
return path
def addonFolder(self) -> str:
- return self._ensureExists(os.path.join(self.base, "addons21"))
+ path = Path(os.environ.get("ANKI_ADDONS") or Path(self.base) / "addons21")
+ path.mkdir(parents=True, exist_ok=True)
+ return str(path.resolve())
def backupFolder(self) -> str:
return self._ensureExists(os.path.join(self.profileFolder(), "backups"))

View File

@@ -0,0 +1,15 @@
diff --git a/qt/aqt/main.py b/qt/aqt/main.py
index 6c634132d..f3f3d4d10 100644
--- a/qt/aqt/main.py
+++ b/qt/aqt/main.py
@@ -1421,6 +1421,8 @@ title="{}" {}>{}</button>""".format(
##########################################################################
def setup_auto_update(self, _log: list[DownloadLogEntry]) -> None:
+ return
+
from aqt.update import check_for_update
check_for_update()
--
2.42.0

View File

@@ -0,0 +1,53 @@
From d8843c5fcaef79d209803849070e1a79ab380903 Mon Sep 17 00:00:00 2001
From: Euan Kemp <euank@euank.com>
Date: Sun, 24 Aug 2025 20:24:34 +0900
Subject: [PATCH] Fix compilation under rust 1.89
Rust 1.89 produces the following output:
```
error: unicode codepoint changing visible direction of text present in literal
...
warning: allow(text_direction_codepoint_in_literal) is ignored unless specified at crate level
--> rslib/i18n/src/generated.rs:7:10
|
7 | #![allow(text_direction_codepoint_in_literal)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
This change fixes it.
This ensures that some third-party crate that pulls in this code as
library code (and thus isn't subject to the rust-toolchain file in this
repo) doesn't hit this compilation error.
---
rslib/i18n/src/generated.rs | 1 -
rslib/i18n/src/lib.rs | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/rslib/i18n/src/generated.rs b/rslib/i18n/src/generated.rs
index f3526f79f..f3fa71ce8 100644
--- a/rslib/i18n/src/generated.rs
+++ b/rslib/i18n/src/generated.rs
@@ -4,6 +4,5 @@
// Include auto-generated content
#![allow(clippy::all)]
-#![allow(text_direction_codepoint_in_literal)]
include!(concat!(env!("OUT_DIR"), "/strings.rs"));
diff --git a/rslib/i18n/src/lib.rs b/rslib/i18n/src/lib.rs
index bfd6f5ba2..f9dbb1948 100644
--- a/rslib/i18n/src/lib.rs
+++ b/rslib/i18n/src/lib.rs
@@ -1,6 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
+#![allow(text_direction_codepoint_in_literal)]
mod generated;
use std::borrow::Cow;
--
2.50.1

View File

@@ -0,0 +1,17 @@
diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py
index b6d24080b..5e5faac7b 100644
--- a/qt/aqt/__init__.py
+++ b/qt/aqt/__init__.py
@@ -413,11 +413,5 @@ def setupGL(pm: aqt.profiles.ProfileManager) -> None:
# RHI errors are emitted multiple times so make sure we only handle them once
driver_failed = False
- # work around pyqt loading wrong GL library
- if is_lin and not sys.platform.startswith("freebsd"):
- import ctypes
-
- ctypes.CDLL("libGL.so.1", ctypes.RTLD_GLOBAL)
-
# catch opengl errors
def msgHandler(category: Any, ctx: Any, msg: Any) -> None:
if category == QtMsgType.QtDebugMsg:

View File

@@ -0,0 +1,31 @@
From 3d41c84cb5f5daf10b5b5ecffcb53aeed7f0584b Mon Sep 17 00:00:00 2001
From: Euan Kemp <euank@euank.com>
Date: Fri, 11 Jul 2025 15:59:16 +0900
Subject: [PATCH] Skip formatting Python code
This otherwise fails the nixpkgs build
---
pylib/tools/hookslib.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pylib/tools/hookslib.py b/pylib/tools/hookslib.py
index 99f08fa1e..2bb4b3f26 100644
--- a/pylib/tools/hookslib.py
+++ b/pylib/tools/hookslib.py
@@ -82,7 +82,7 @@ class Hook:
code = f"""\
class {self.classname()}:
{classdoc}{self.list_code()}
-
+
def append(self, callback: {self.callable()}) -> None:
'''{appenddoc}'''
self._hooks.append(callback)
@@ -205,4 +205,3 @@ def write_file(path: str, hooks: list[Hook], prefix: str, suffix: str):
with open(path, "wb") as file:
file.write(code.encode("utf8"))
- subprocess.run([sys.executable, "-m", "ruff", "format", "-q", path], check=True)
--
2.49.0

View File

@@ -0,0 +1,51 @@
{
lib,
rustPlatform,
anki,
openssl,
pkg-config,
buildPackages,
}:
rustPlatform.buildRustPackage {
pname = "anki-sync-server";
inherit (anki)
version
src
cargoDeps
patches
;
# only build sync server
cargoBuildFlags = [
"--bin"
"anki-sync-server"
];
checkFlags = [
# this test is flaky, see https://github.com/ankitects/anki/issues/3619
# also remove from anki when removing this
"--skip=deckconfig::update::test::should_keep_at_least_one_remaining_relearning_step"
];
nativeBuildInputs = [
pkg-config
];
buildInputs = [
openssl
];
env.PROTOC = lib.getExe buildPackages.protobuf;
__darwinAllowLocalNetworking = true;
meta = {
description = "Standalone official anki sync server";
homepage = "https://apps.ankiweb.net";
license = with lib.licenses; [ agpl3Plus ];
maintainers = with lib.maintainers; [ martinetd ];
mainProgram = "anki-sync-server";
};
}

89
pkgs/games/anki/update.sh Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl git wget jq common-updater-scripts yarn-berry_4 yarn-berry_4.yarn-berry-fetcher tomlq nix-prefetch-github
set -eu -o pipefail
set -x
TMPDIR=/tmp/anki-update-script
cleanup() {
if [ -e $TMPDIR/.done ]; then
rm -rf "$TMPDIR"
else
echo
read -p "Script exited prematurely. Do you want to delete the temporary directory $TMPDIR ? " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf "$TMPDIR"
fi
fi
}
trap cleanup EXIT
if [[ "$#" > 0 ]]; then
tag="$1"
else
tag="$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s 'https://api.github.com/repos/ankitects/anki/releases' | jq -r 'map(select(.prerelease == false)) | .[0].tag_name')"
fi
tag_sha="$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s "https://api.github.com/repos/ankitects/anki/git/ref/tags/$tag" | jq -r '.object.sha')"
rev="$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s "https://api.github.com/repos/ankitects/anki/git/tags/$tag_sha" | jq -r '.object.sha')"
nixpkgs="$(git rev-parse --show-toplevel)"
scriptDir="$nixpkgs/pkgs/games/anki"
ver=$(nix-instantiate --eval -E "(import \"$nixpkgs\" { config = {}; overlays = []; }).anki.version" | tr -d '"')
if [[ "$tag" == "$ver" ]]; then
echo "Latest version is $tag, already $ver, skipping update"
exit 0
fi
echo "Updating from $ver to $tag"
mkdir -p $TMPDIR
curl -o $TMPDIR/yarn.lock "https://raw.githubusercontent.com/ankitects/anki/refs/tags/$tag/yarn.lock"
echo "Generating missing-hashes.json"
yarn-berry-fetcher missing-hashes $TMPDIR/yarn.lock > $TMPDIR/missing-hashes.json
yarnHash=$(yarn-berry-fetcher prefetch $TMPDIR/yarn.lock $TMPDIR/missing-hashes.json)
echo "Copying missing-hashes.json back into nixpkgs"
cp $TMPDIR/missing-hashes.json "$scriptDir/missing-hashes.json"
sed -i -E "s|yarnHash = \".*\"|yarnHash = \"$yarnHash\"|" "$scriptDir/default.nix"
echo "yarnHash updated"
echo "Regenerating uv-deps.json"
curl -o $TMPDIR/uv.lock "https://raw.githubusercontent.com/ankitects/anki/refs/tags/$tag/uv.lock"
# Extract all urls to pre-compute hashes so we can download whatever uv needs for its cache.
# We skip pyqt because the derivation uses the nixos packaged ones for
# native-library compatibility.
tq -f $TMPDIR/uv.lock --output json '.' | jq '.. | objects | .url | select(. != null)' -cr | \
grep -Ev "PyQt|pyqt" \
> $TMPDIR/uv.urls
echo '[' > $TMPDIR/uv-deps.json
for url in $(cat $TMPDIR/uv.urls); do
urlHash="$(nix-prefetch-url --type sha256 "$url")"
echo '{"url": "'$url'", "hash": "'$(nix-hash --type sha256 --to-sri $urlHash)'"},' >> $TMPDIR/uv-deps.json
done
# strip final trailing comma
sed '$s/,$//' -i $TMPDIR/uv-deps.json
echo ']' >> $TMPDIR/uv-deps.json
# and jq format it on the way into nixpkgs too
jq '.' $TMPDIR/uv-deps.json > "$scriptDir/uv-deps.json"
echo "Wrote uv-deps.json"
# github as well
srcHash="$(nix-prefetch-github ankitects anki --fetch-submodules --rev "$tag" --json | jq -r '.hash')"
sed -i "s|version = \".*\";|version = \"$tag\";|" "$scriptDir/default.nix"
sed -i "s|rev = \".*\";|rev = \"$rev\";|" "$scriptDir/default.nix"
sed -i "s|srcHash = \".*\";|srcHash = \"$srcHash\";|" "$scriptDir/default.nix"
touch $TMPDIR/.done

2798
pkgs/games/anki/uv-deps.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
{
lib,
symlinkJoin,
makeWrapper,
anki,
anki-utils,
writeTextDir,
ankiAddons ? [ ],
}:
/*
`ankiAddons`
: A set of Anki add-ons to be installed. Here's a an example:
~~~
pkgs.anki.withAddons [
# When the add-on is already available in nixpkgs
pkgs.ankiAddons.anki-connect
# When the add-on is not available in nixpkgs
(pkgs.anki-utils.buildAnkiAddon (finalAttrs: {
pname = "recolor";
version = "3.1";
src = pkgs.fetchFromGitHub {
owner = "AnKing-VIP";
repo = "AnkiRecolor";
rev = finalAttrs.version;
sparseCheckout = [ "src/addon" ];
hash = "sha256-28DJq2l9DP8O6OsbNQCZ0pm4S6CQ3Yz0Vfvlj+iQw8Y=";
};
sourceRoot = "source/src/addon";
}))
# When the add-on needs to be configured
pkgs.ankiAddons.passfail2.withConfig {
config = {
again_button_name = "not quite";
good_button_name = "excellent";
};
user_files = ./dir-to-be-merged-into-addon-user-files-dir;
};
]
~~~
The original `anki` executable will be wrapped so that it uses the addons from
`ankiAddons`.
This only works with Anki versions patched to support the `ANKI_ADDONS` environment
variable. `pkgs.anki` has this, but `pkgs.anki-bin` does not.
*/
let
defaultAddons = [
(anki-utils.buildAnkiAddon {
pname = "nixos";
version = "1.0";
src = writeTextDir "__init__.py" ''
import aqt
from aqt.qt import QMessageBox
import json
def addons_dialog_will_show(dialog: aqt.addons.AddonsDialog) -> None:
dialog.setEnabled(False)
QMessageBox.information(
dialog,
"NixOS Info",
("These add-ons are managed by NixOS.<br>"
"See <a href='https://github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix'>"
"github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix</a>")
)
def addon_tried_to_write_config(module: str, conf: dict) -> None:
message_box = QMessageBox(
QMessageBox.Icon.Warning,
"NixOS Info",
(f"The add-on module: \"{module}\" tried to update its config.<br>"
"See <a href='https://github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix'>"
"github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix</a>"
" for how to configure add-ons managed by NixOS.")
)
message_box.setDetailedText(json.dumps(conf))
message_box.exec()
aqt.gui_hooks.addons_dialog_will_show.append(addons_dialog_will_show)
aqt.mw.addonManager.writeConfig = addon_tried_to_write_config
'';
meta.maintainers = with lib.maintainers; [ junestepp ];
})
];
in
symlinkJoin {
inherit (anki) version;
pname = "${anki.pname}-with-addons";
paths = [ anki ];
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram $out/bin/anki \
--set ANKI_ADDONS "${anki-utils.buildAnkiAddonsDir (ankiAddons ++ defaultAddons)}"
'';
meta = removeAttrs anki.meta [
"name"
"outputsToInstall"
"position"
];
}

View File

@@ -0,0 +1,261 @@
{
lib,
stdenv,
fetchFromGitLab,
autoconf,
automake,
gnum4,
pkg-config,
bison,
python3,
which,
boost,
ftgl,
freetype,
glew,
SDL,
SDL_image,
SDL_mixer,
SDL2,
SDL2_image,
SDL2_mixer,
libGL,
libGLU,
libpng,
libX11,
libxml2,
protobuf,
xvfb-run,
gnugrep,
nixosTests,
dedicatedServer ? false,
}:
let
latestVersionMajor = "0.2.9";
unstableVersionMajor = "0.4";
srcs =
let
fetchArmagetron =
rev: hash:
fetchFromGitLab {
owner = "armagetronad";
repo = "armagetronad";
inherit rev hash;
};
in
{
# https://gitlab.com/armagetronad/armagetronad/-/tags
${latestVersionMajor} =
let
version = "${latestVersionMajor}.2.3";
rev = "v${version}";
hash = "sha256-lfYJ3luGK9hB0aiiBiJIqq5ddANqGaVtKXckbo4fl2g=";
in
dedicatedServer: {
inherit version;
src = fetchArmagetron rev hash;
extraBuildInputs = lib.optionals (!dedicatedServer) [
libGL
libGLU
libX11
libpng
SDL
SDL_image
SDL_mixer
];
};
# https://gitlab.com/armagetronad/armagetronad/-/commits/trunk/?ref_type=heads
${unstableVersionMajor} =
let
rev = "813b684ab0de8ee9737c9fc1f9b90ba0543dd418";
hash = "sha256-01jWE9rSBJn+JS8p8LTFqIGquOY1avXsAZnfYfo5pPk=";
in
dedicatedServer: {
version = "${unstableVersionMajor}-${builtins.substring 0 8 rev}";
src = fetchArmagetron rev hash;
extraBuildInputs = [
protobuf
boost
]
++ lib.optionals (!dedicatedServer) [
glew
ftgl
freetype
libGL
libGLU
libX11
SDL2
SDL2_image
SDL2_mixer
];
extraNativeBuildInputs = [ bison ];
};
# https://gitlab.com/armagetronad/armagetronad/-/commits/hack-0.2.8-sty+ct+ap/?ref_type=heads
"${latestVersionMajor}-sty+ct+ap" =
let
rev = "5a17cc9fb6e1e27a358711afbd745ae54d4a8c60";
hash = "sha256-111C1j/hSaASGcvYy3//TyHs4Z+3fuiOvCmtcWLdFd4=";
in
dedicatedServer: {
version = "${latestVersionMajor}-sty+ct+ap-${builtins.substring 0 8 rev}";
src = fetchArmagetron rev hash;
extraBuildInputs = lib.optionals (!dedicatedServer) [
libGL
libGLU
libX11
libpng
SDL
SDL_image
SDL_mixer
];
};
};
# Creates an Armagetron build. Takes a function returning build inputs for a particular value of dedicatedServer.
mkArmagetron =
fn: dedicatedServer:
let
# Compute the build params.
resolvedParams = fn dedicatedServer;
# Figure out the binary name depending on whether this is a dedicated server.
mainProgram = if dedicatedServer then "armagetronad-dedicated" else "armagetronad";
# Split the version into the major and minor parts
versionParts = lib.splitString "-" resolvedParams.version;
splitVersion = lib.splitVersion (builtins.elemAt versionParts 0);
majorVersion = builtins.concatStringsSep "." (lib.lists.take 2 splitVersion);
minorVersionPart =
parts: sep: expectedSize:
if builtins.length parts > expectedSize then
sep + (builtins.concatStringsSep sep (lib.lists.drop expectedSize parts))
else
"";
minorVersion =
(minorVersionPart splitVersion "." 2) + (minorVersionPart versionParts "-" 1) + "-nixpkgs";
in
stdenv.mkDerivation {
pname = mainProgram;
inherit (resolvedParams) version src;
# Build works fine; install has a race.
enableParallelBuilding = true;
enableParallelInstalling = false;
preConfigure = ''
patchShebangs .
# Create the version.
echo "${majorVersion}" > major_version
echo "${minorVersion}" > minor_version
echo "Bootstrapping version: $(<major_version)$(<minor_version)" >&2
./bootstrap.sh
'';
configureFlags = [
"--enable-automakedefaults"
"--enable-authentication"
"--disable-memmanager"
"--disable-useradd"
"--disable-initscripts"
"--disable-etc"
"--disable-uninstall"
"--disable-sysinstall"
]
++ lib.optional dedicatedServer "--enable-dedicated"
++ lib.optional (!dedicatedServer) "--enable-music";
buildInputs =
lib.singleton (libxml2.override { enableHttp = true; }) ++ (resolvedParams.extraBuildInputs or [ ]);
nativeBuildInputs = [
autoconf
automake
gnum4
pkg-config
which
python3
]
++ (resolvedParams.extraNativeBuildInputs or [ ]);
nativeInstallCheckInputs = [
gnugrep
]
++ lib.optional (!dedicatedServer) xvfb-run
++ (resolvedParams.extraNativeInstallCheckInputs or [ ]);
postInstall = lib.optionalString (!dedicatedServer) ''
mkdir -p $out/share/{applications,icons/hicolor}
ln -s $out/share/games/armagetronad/desktop/armagetronad*.desktop $out/share/applications/
ln -s $out/share/games/armagetronad/desktop/icons $out/share/icons/hicolor
'';
doInstallCheck = true;
installCheckPhase = ''
export XDG_RUNTIME_DIR=/tmp
bin="$out/bin/${mainProgram}"
if command -v xvfb-run &>/dev/null; then
run="xvfb-run $bin"
else
run="$bin"
fi
echo "Checking game info:" >&2
version="$($run --version || true)"
echo " - Version: $version" >&2
prefix="$($run --prefix || true)"
echo " - Prefix: $prefix" >&2
rubber="$(($run --doc || true) | grep -m1 CYCLE_RUBBER)"
echo " - Docstring: $rubber" >&2
if [[ "$version" != *"${resolvedParams.version}"* ]] || \
[ "$prefix" != "$out" ] || \
[[ ! "$rubber" =~ ^CYCLE_RUBBER[[:space:]]+Niceness[[:space:]]factor ]]; then
echo "Something didn't match. :-(" >&2
exit 1
else
echo "Everything is ok." >&2
fi
'';
passthru =
if dedicatedServer then
{
# No passthru, end of the line.
# https://www.youtube.com/watch?v=NOMa56y_Was
}
else if (resolvedParams.version != (srcs.${latestVersionMajor} dedicatedServer).version) then
{
# Allow a "dedicated" passthru for versions other than the default.
dedicated = mkArmagetron fn true;
}
else
(lib.mapAttrs (name: value: mkArmagetron value dedicatedServer) (
lib.filterAttrs (
name: value: (value dedicatedServer).version != (srcs.${latestVersionMajor} dedicatedServer).version
) srcs
))
// {
# Allow both a "dedicated" passthru and a passthru for all the options other than the latest version, which this is.
dedicated = mkArmagetron fn true;
tests.armagetronad = nixosTests.armagetronad;
};
meta = with lib; {
inherit mainProgram;
homepage = "https://www.armagetronad.org";
description = "Multiplayer networked arcade racing game in 3D similar to Tron";
maintainers = with maintainers; [ numinit ];
license = licenses.gpl2Plus;
platforms = platforms.linux;
};
};
in
mkArmagetron srcs.${latestVersionMajor} dedicatedServer

View File

@@ -0,0 +1,100 @@
{
lib,
stdenv,
fetchFromGitHub,
cmake,
zlib,
boost,
openal,
glm,
freetype,
libGLU,
SDL2,
libepoxy,
dejavu_fonts,
inkscape,
optipng,
imagemagick,
withCrashReporter ? !stdenv.hostPlatform.isDarwin,
qtbase ? null,
wrapQtAppsHook ? null,
curl ? null,
gdb ? null,
}:
let
inherit (lib)
licenses
maintainers
optionals
optionalString
platforms
;
in
stdenv.mkDerivation rec {
pname = "arx-libertatis";
version = "1.2.1";
src = fetchFromGitHub {
owner = "arx";
repo = "ArxLibertatis";
rev = version;
sha256 = "GBJcsibolZP3oVOTSaiVqG2nMmvXonKTp5i/0NNODKY=";
};
nativeBuildInputs = [
cmake
inkscape
imagemagick
optipng
]
++ optionals withCrashReporter [ wrapQtAppsHook ];
buildInputs = [
zlib
boost
openal
glm
freetype
libGLU
SDL2
libepoxy
]
++ optionals withCrashReporter [
qtbase
curl
]
++ optionals stdenv.hostPlatform.isLinux [ gdb ];
cmakeFlags = [
"-DDATA_DIR_PREFIXES=$out/share"
"-DImageMagick_convert_EXECUTABLE=${imagemagick.out}/bin/convert"
"-DImageMagick_mogrify_EXECUTABLE=${imagemagick.out}/bin/mogrify"
];
dontWrapQtApps = true;
postInstall = ''
ln -sf \
${dejavu_fonts}/share/fonts/truetype/DejaVuSansMono.ttf \
$out/share/games/arx/misc/dejavusansmono.ttf
''
+ optionalString withCrashReporter ''
wrapQtApp "$out/libexec/arxcrashreporter"
'';
meta = {
description = "First-person role-playing game / dungeon crawler";
longDescription = ''
A cross-platform, open source port of Arx Fatalis, a 2002
first-person role-playing game / dungeon crawler
developed by Arkane Studios.
'';
homepage = "https://arx-libertatis.org/";
license = licenses.gpl3;
maintainers = with maintainers; [ rnhmjoj ];
platforms = platforms.linux;
};
}

View File

@@ -0,0 +1,86 @@
{
fetchFromGitHub,
lib,
stdenv,
SDL,
SDL_image,
SDL_mixer,
SDL_sound,
libsigcxx,
physfs,
boost,
expat,
freetype,
libjpeg,
wxGTK32,
lua,
perl,
pkg-config,
zlib,
zip,
bzip2,
libpng,
libtiff,
fluidsynth,
libmikmod,
libvorbis,
flac,
libogg,
}:
stdenv.mkDerivation {
pname = "asc";
version = "2.6.3.0";
src = fetchFromGitHub {
owner = "ValHaris";
repo = "asc-hq";
rev = "fa3bca082a5cea2b35812349f99b877f0113aef0";
sha256 = "atamYCN2mOqxV6auToTeWdpKuFfC+GLfLdRsfT0ouwQ=";
};
nativeBuildInputs = [ pkg-config ];
buildInputs = [
SDL
SDL_image
SDL_mixer
SDL_sound
physfs
boost
expat
freetype
libjpeg
wxGTK32
lua
perl
zlib
zip
bzip2
libpng
libtiff
fluidsynth
libmikmod
flac
libvorbis
libogg
libsigcxx
];
meta = with lib; {
description = "Turn based strategy game";
longDescription = ''
Advanced Strategic Command is a free, turn based strategy game. It is
designed in the tradition of the Battle Isle series from Bluebyte and is
currently available for Windows and Linux.
'';
homepage = "https://www.asc-hq.org/";
license = licenses.gpl2Plus;
maintainers = with maintainers; [ raskin ];
platforms = platforms.linux;
};
}

View File

@@ -0,0 +1,79 @@
{
stdenv,
lib,
fetchFromGitHub,
rustPlatform,
pkg-config,
alsa-lib,
openssl,
withTTS ? false,
speechd-minimal,
}:
rustPlatform.buildRustPackage rec {
pname = "blightmud";
version = "5.3.1";
src = fetchFromGitHub {
owner = "blightmud";
repo = "blightmud";
rev = "v${version}";
hash = "sha256-9GUul5EoejcnCQqq1oX+seBtxttYIUhgcexaZk+7chk=";
};
cargoHash = "sha256-7cMd7pNWGV5DOSCLRW5fP3L1VnDTEsZZjhVz1AQLEXM=";
buildFeatures = lib.optional withTTS "tts";
nativeBuildInputs = [
pkg-config
rustPlatform.bindgenHook
];
buildInputs = [
openssl
]
++ lib.optionals (withTTS && stdenv.hostPlatform.isLinux) [ speechd-minimal ]
++ lib.optionals stdenv.hostPlatform.isLinux [ alsa-lib ];
checkFlags =
let
# Most of Blightmud's unit tests pass without trouble in the isolated
# Nixpkgs build env. The following tests need to be skipped.
skipList = [
"test_connect"
"test_gmcp_negotiation"
"test_ttype_negotiation"
"test_reconnect"
"test_is_connected"
"test_mud"
"test_server"
"test_lua_script"
"timer_test"
"validate_assertion_fail"
"regex_smoke_test"
"test_tls_init_verify_err"
"test_tls_init_no_verify"
"test_tls_init_verify"
];
skipFlag = test: "--skip " + test;
in
builtins.concatStringsSep " " (map skipFlag skipList);
meta = with lib; {
description = "Terminal MUD client written in Rust";
mainProgram = "blightmud";
longDescription = ''
Blightmud is a terminal client for connecting to Multi User Dungeon (MUD)
games. It is written in Rust and supports TLS, GMCP, MSDP, MCCP2, tab
completion, text searching and a split view for scrolling. Blightmud can
be customized with Lua scripting for aliases, triggers, timers, customized
status bars, and more. Blightmud supports several accessibility features
including an optional built-in text-to-speech engine and a screen reader
friendly mode.
'';
homepage = "https://github.com/Blightmud/Blightmud";
license = licenses.gpl3Plus;
maintainers = with maintainers; [ cpu ];
platforms = platforms.linux ++ platforms.darwin;
};
}

View File

@@ -0,0 +1,68 @@
{
stdenvNoCC,
lib,
type,
}:
assert lib.elem type [
"mod"
"soundpack"
"tileset"
];
{
modName,
version,
src,
...
}@args:
stdenvNoCC.mkDerivation (
args
// rec {
pname = args.pname or "cataclysm-dda-${type}-${modName}";
modRoot = args.modRoot or ".";
configurePhase =
args.configurePhase or ''
runHook preConfigure
runHook postConfigure
'';
buildPhase =
args.buildPhase or ''
runHook preBuild
runHook postBuild
'';
checkPhase =
args.checkPhase or ''
runHook preCheck
runHook postCheck
'';
installPhase =
let
baseDir =
{
mod = "mods";
soundpack = "sound";
tileset = "gfx";
}
.${type};
in
args.installPhase or ''
runHook preInstall
destdir="$out/share/cataclysm-dda/${baseDir}"
mkdir -p "$destdir"
cp -R "${modRoot}" "$destdir/${modName}"
runHook postInstall
'';
passthru = {
forTiles = true;
forCurses = type == "mod";
};
}
)

View File

@@ -0,0 +1,133 @@
{
lib,
stdenv,
runtimeShell,
pkg-config,
gettext,
ncurses,
tiles,
SDL2,
SDL2_image,
SDL2_mixer,
SDL2_ttf,
libX11,
freetype,
zlib,
debug,
useXdgDir,
}:
let
inherit (lib) optionals optionalString;
commonDeps = [
gettext
zlib
];
cursesDeps = commonDeps ++ [ ncurses ];
tilesDeps = commonDeps ++ [
SDL2
SDL2_image
SDL2_mixer
SDL2_ttf
libX11
freetype
];
patchDesktopFile = ''
substituteInPlace $out/share/applications/org.cataclysmdda.CataclysmDDA.desktop \
--replace-fail "Exec=cataclysm-tiles" "Exec=$out/bin/cataclysm-tiles"
'';
installMacOSAppLauncher = ''
app=$out/Applications/Cataclysm.app
install -D -m 444 build-data/osx/Info.plist -t $app/Contents
install -D -m 444 build-data/osx/AppIcon.icns -t $app/Contents/Resources
mkdir $app/Contents/MacOS
launcher=$app/Contents/MacOS/Cataclysm.sh
cat << EOF > $launcher
#!${runtimeShell}
$out/bin/cataclysm-tiles
EOF
chmod 555 $launcher
'';
in
stdenv.mkDerivation {
pname = "cataclysm-dda";
nativeBuildInputs = [ pkg-config ];
buildInputs = if tiles then tilesDeps else cursesDeps;
postPatch = ''
patchShebangs lang/compile_mo.sh
'';
makeFlags = [
"PREFIX=$(out)"
"LANGUAGES=all"
(if useXdgDir then "USE_XDG_DIR=1" else "USE_HOME_DIR=1")
]
++ optionals (!debug) [
"RELEASE=1"
]
++ optionals tiles [
"TILES=1"
"SOUND=1"
]
++ optionals stdenv.hostPlatform.isDarwin [
"NATIVE=osx"
"CLANG=1"
"OSX_MIN=${stdenv.hostPlatform.darwinMinVersion}"
];
postInstall = optionalString tiles (
if !stdenv.hostPlatform.isDarwin then patchDesktopFile else installMacOSAppLauncher
);
dontStrip = debug;
enableParallelBuilding = true;
passthru = {
isTiles = tiles;
isCurses = !tiles;
};
meta = with lib; {
description = "Free, post apocalyptic, zombie infested rogue-like";
mainProgram = "cataclysm-tiles";
longDescription = ''
Cataclysm: Dark Days Ahead is a roguelike set in a post-apocalyptic world.
Surviving is difficult: you have been thrown, ill-equipped, into a
landscape now riddled with monstrosities of which flesh eating zombies are
neither the strangest nor the deadliest.
Yet with care and a little luck, many things are possible. You may try to
eke out an existence in the forests silently executing threats and
providing sustenance with your longbow. You can ride into town in a
jerry-rigged vehicle, all guns blazing, to settle matters in a fug of
smoke from your molotovs. You could take a more measured approach and
construct an impregnable fortress, surrounded by traps to protect you from
the horrors without. The longer you survive, the more skilled and adapted
you will get and the better equipped and armed to deal with the threats
you are presented with.
In the course of your ordeal there will be opportunities and temptations
to improve or change your very nature. There are tales of survivors fitted
with extraordinary cybernetics giving great power and stories too of
gravely mutated survivors who, warped by their ingestion of exotic
substances or radiation, now more closely resemble insects, birds or fish
than their original form.
'';
homepage = "https://cataclysmdda.org/";
license = licenses.cc-by-sa-30;
maintainers = with maintainers; [
mnacamura
DeeUnderscore
];
platforms = platforms.unix;
};
}

View File

@@ -0,0 +1,41 @@
{ newScope }:
let
callPackage = newScope self;
stable = rec {
tiles = callPackage ./stable.nix { };
curses = tiles.override { tiles = false; };
};
git = rec {
tiles = callPackage ./git.nix { };
curses = tiles.override { tiles = false; };
};
lib = callPackage ./lib.nix { };
pkgs = callPackage ./pkgs { };
self = {
inherit
callPackage
stable
git
;
inherit (lib)
buildMod
buildSoundPack
buildTileSet
wrapCDDA
attachPkgs
;
inherit pkgs;
};
in
self

View File

@@ -0,0 +1,45 @@
{
lib,
callPackage,
fetchFromGitHub,
pkgs,
attachPkgs,
tiles ? true,
debug ? false,
useXdgDir ? false,
version ? "2024-12-11",
rev ? "b871679a2d54dbc6bf3e6566033fadd2dc651592",
sha256 ? "sha256-t9R0QPky7zvjgGMq4kV8DdQFToJ/qngbJCw+8FlQztM=",
}:
let
common = callPackage ./common.nix {
inherit tiles debug useXdgDir;
};
self = common.overrideAttrs (common: rec {
pname = common.pname + "-git";
inherit version;
src = fetchFromGitHub {
owner = "CleverRaven";
repo = "Cataclysm-DDA";
inherit rev sha256;
};
patches = [
# Unconditionally look for translation files in $out/share/locale
./locale-path-git.patch
];
makeFlags = common.makeFlags ++ [
"VERSION=git-${version}-${lib.substring 0 8 src.rev}"
];
meta = common.meta // {
maintainers = with lib.maintainers; common.meta.maintainers ++ [ rardiol ];
};
});
in
attachPkgs pkgs self

View File

@@ -0,0 +1,47 @@
{ callPackage }:
rec {
buildMod = callPackage ./builder.nix {
type = "mod";
};
buildSoundPack = callPackage ./builder.nix {
type = "soundpack";
};
buildTileSet = callPackage ./builder.nix {
type = "tileset";
};
wrapCDDA = callPackage ./wrapper.nix { };
# Required to fix `pkgs` and `withMods` attrs after applying `overrideAttrs`.
#
# Example:
# let
# myBuild = cataclysmDDA.jenkins.latest.tiles.overrideAttrs (_: {
# x = "hello";
# });
#
# # This refers to the derivation before overriding! So, `badExample.x` is not accessible.
# badExample = myBuild.withMods (_: []);
#
# # `myBuild` is correctly referred by `withMods` and `goodExample.x` is accessible.
# goodExample = let
# inherit (cataclysmDDA) attachPkgs pkgs;
# in
# (attachPkgs pkgs myBuild).withMods (_: []);
# in
# goodExample.x # returns "hello"
attachPkgs =
pkgs: super:
let
self = super.overrideAttrs (old: {
passthru = old.passthru // {
pkgs = pkgs.override { build = self; };
withMods = wrapCDDA self;
};
});
in
self;
}

View File

@@ -0,0 +1,17 @@
diff --git a/src/translations.cpp b/src/translations.cpp
--- a/src/translations.cpp
+++ b/src/translations.cpp
@@ -52,13 +52,11 @@ std::string locale_dir()
#define CATA_IS_ON_BSD
#endif
-#if !defined(__ANDROID__) && ((defined(__linux__) || defined(CATA_IS_ON_BSD) || (defined(MACOSX) && !defined(TILES))))
if( !PATH_INFO::base_path().get_logical_root_path().empty() ) {
loc_dir = ( PATH_INFO::base_path() / "share" / "locale" ).generic_u8string();
} else {
loc_dir = PATH_INFO::langdir();
}
-#endif
#endif // LOCALIZE
return loc_dir;
}

View File

@@ -0,0 +1,17 @@
diff --git a/src/translations.cpp b/src/translations.cpp
--- a/src/translations.cpp
+++ b/src/translations.cpp
@@ -52,13 +52,11 @@ std::string locale_dir()
#define CATA_IS_ON_BSD
#endif
-#if !defined(__ANDROID__) && ((defined(__linux__) || defined(CATA_IS_ON_BSD) || (defined(MACOSX) && !defined(TILES))))
if( !PATH_INFO::base_path().empty() ) {
loc_dir = PATH_INFO::base_path() + "share/locale";
} else {
loc_dir = PATH_INFO::langdir();
}
-#endif
#endif // LOCALIZE
return loc_dir;
}

View File

@@ -0,0 +1,34 @@
{
lib,
callPackage,
build ? null,
}:
let
pkgs = {
mod = {
};
soundpack = {
};
tileset = {
UndeadPeople = callPackage ./tilesets/UndeadPeople { };
};
};
pkgs' = lib.mapAttrs (_: mods: lib.filterAttrs isAvailable mods) pkgs;
isAvailable =
_: mod:
if (build == null) then
true
else if build.isTiles then
mod.forTiles or false
else if build.isCurses then
mod.forCurses or false
else
false;
in
lib.makeExtensible (_: pkgs')

View File

@@ -0,0 +1,27 @@
{
lib,
buildTileSet,
fetchFromGitHub,
}:
buildTileSet {
modName = "UndeadPeople";
version = "2020-07-08";
src = fetchFromGitHub {
owner = "jmz-b";
repo = "UndeadPeopleTileset";
rev = "f7f13b850fafe2261deee051f45d9c611a661534";
sha256 = "0r06srjr7rq51jk9yfyxz80nfgb98mkn86cbcjfxpibgbqvcp0zm";
};
modRoot = "MSX++UnDeadPeopleEdition";
meta = with lib; {
description = "Cataclysm DDA tileset based on MSX++ tileset";
homepage = "https://github.com/jmz-b/UndeadPeopleTileset";
license = licenses.unfree;
maintainers = with maintainers; [ mnacamura ];
platforms = platforms.all;
};
}

View File

@@ -0,0 +1,46 @@
{
lib,
callPackage,
fetchFromGitHub,
fetchpatch,
pkgs,
wrapCDDA,
attachPkgs,
tiles ? true,
debug ? false,
useXdgDir ? false,
}:
let
common = callPackage ./common.nix {
inherit tiles debug useXdgDir;
};
self = common.overrideAttrs (common: rec {
version = "0.H";
src = fetchFromGitHub {
owner = "CleverRaven";
repo = "Cataclysm-DDA";
tag = "${version}-RELEASE";
sha256 = "sha256-ZCD5qgqYSX7sS+Tc1oNYq9soYwNUUuWamY2uXfLjGoY=";
};
patches = [
# fix compilation of the vendored flatbuffers under gcc14
(fetchpatch {
name = "fix-flatbuffers-with-gcc14";
url = "https://github.com/CleverRaven/Cataclysm-DDA/commit/1400b1018ff37196bd24ba4365bd50beb571ac14.patch";
hash = "sha256-H0jct6lSQxu48eOZ4f8HICxo89qX49Ksw+Xwwtp7iFM=";
})
# Unconditionally look for translation files in $out/share/locale
./locale-path.patch
];
meta = common.meta // {
changelog = "https://github.com/CleverRaven/Cataclysm-DDA/blob/${version}/data/changelog.txt";
};
});
in
attachPkgs pkgs self

View File

@@ -0,0 +1,50 @@
{
lib,
symlinkJoin,
makeWrapper,
}:
unwrapped:
pkgsSpec:
let
mods = if lib.isFunction pkgsSpec then pkgsSpec unwrapped.pkgs else pkgsSpec;
in
if builtins.length mods == 0 then
unwrapped
else
symlinkJoin {
name = unwrapped.name + "-with-mods";
paths = [ unwrapped ] ++ mods;
nativeBuildInputs = [ makeWrapper ];
postBuild = ''
if [ -x $out/bin/cataclysm ]; then
wrapProgram $out/bin/cataclysm \
--add-flags "--datadir $out/share/cataclysm-dda/"
fi
if [ -x $out/bin/cataclysm-tiles ]; then
wrapProgram $out/bin/cataclysm-tiles \
--add-flags "--datadir $out/share/cataclysm-dda/"
fi
# Launch the wrapped program
replaceProgram() {
cp "$1" "''${1}.bk"
unlink "$1"
mv "''${1}.bk" "$1"
sed -i "$1" -e "s,${builtins.storeDir}/.\+\(/bin/cataclysm-tiles\),$out\1,"
}
for script in "$out/share/applications/cataclysm-dda.desktop" \
"$out/Applications/Cataclysm.app/Contents/MacOS/Cataclysm.sh"
do
if [ -e "$script" ]; then
replaceProgram "$script"
fi
done
'';
}

View File

@@ -0,0 +1,123 @@
{
lib,
fetchFromGitHub,
stdenv,
cmake,
pkg-config,
protobuf,
python3,
ffmpeg,
libopus,
wrapQtAppsHook,
qtbase,
qtmultimedia,
qtsvg,
qtwayland,
qtdeclarative,
qtwebengine,
SDL2,
libevdev,
udev,
curlFull,
hidapi,
json_c,
fftw,
miniupnpc,
nanopb,
speexdsp,
libplacebo,
vulkan-loader,
vulkan-headers,
libunwind,
shaderc,
lcms2,
libdovi,
xxHash,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "chiaki-ng";
version = "1.9.9";
src = fetchFromGitHub {
owner = "streetpea";
repo = "chiaki-ng";
rev = "v${finalAttrs.version}";
hash = "sha256-7pDQnlElnBkW+Nr6R+NaylZbsGH8dB31nd7jxYD66yQ=";
fetchSubmodules = true;
};
nativeBuildInputs = [
cmake
pkg-config
wrapQtAppsHook
protobuf
python3
python3.pkgs.wrapPython
python3.pkgs.protobuf
python3.pkgs.setuptools
];
buildInputs = [
ffmpeg
libopus
qtbase
qtmultimedia
qtsvg
qtdeclarative
qtwayland
qtwebengine
protobuf
SDL2
curlFull
hidapi
json_c
fftw
miniupnpc
nanopb
libevdev
udev
speexdsp
libplacebo
vulkan-headers
libunwind
shaderc
lcms2
libdovi
xxHash
];
cmakeFlags = [
"-Wno-dev"
(lib.cmakeFeature "CHIAKI_USE_SYSTEM_CURL" "true")
];
qtWrapperArgs = [
"--prefix LD_LIBRARY_PATH : ${vulkan-loader}/lib"
];
pythonPath = [
python3.pkgs.requests
];
postInstall = ''
install -Dm755 $src/scripts/psn-account-id.py $out/bin/psn-account-id
'';
postFixup = ''
wrapPythonPrograms
'';
meta = with lib; {
homepage = "https://streetpea.github.io/chiaki-ng/";
description = "Next-Generation of Chiaki (the open-source remote play client for PlayStation)";
# Includes OpenSSL linking exception that we currently have no way
# to represent.
#
# See also: <https://github.com/spdx/license-list-XML/issues/939>
license = licenses.agpl3Only;
maintainers = with maintainers; [ devusb ];
platforms = platforms.linux;
mainProgram = "chiaki";
};
})

View File

@@ -0,0 +1,65 @@
{
lib,
stdenv,
fetchgit,
cmake,
pkg-config,
ffmpeg,
libopus,
mkDerivation,
qtbase,
qtmultimedia,
qtsvg,
SDL2,
libevdev,
udev,
qtmacextras,
nanopb,
}:
mkDerivation rec {
pname = "chiaki";
version = "2.2.0";
src = fetchgit {
url = "https://git.sr.ht/~thestr4ng3r/chiaki";
rev = "v${version}";
fetchSubmodules = true;
hash = "sha256-mLx2ygMlIuDJt9iT4nIj/dcLGjMvvmneKd49L7C3BQk=";
};
nativeBuildInputs = [
cmake
pkg-config
];
buildInputs = [
ffmpeg
libopus
qtbase
qtmultimedia
qtsvg
SDL2
nanopb
]
++ lib.optionals stdenv.hostPlatform.isLinux [
libevdev
udev
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
qtmacextras
];
doCheck = true;
installCheckPhase = "$out/bin/chiaki --help";
meta = with lib; {
homepage = "https://git.sr.ht/~thestr4ng3r/chiaki";
description = "Free and Open Source PlayStation Remote Play Client";
license = licenses.agpl3Only;
maintainers = [ ];
platforms = platforms.all;
mainProgram = "chiaki";
};
}

View File

@@ -0,0 +1,45 @@
{
lib,
fetchFromGitHub,
mkDerivation,
cmake,
protobuf,
qtbase,
qtmultimedia,
qttools,
qtwebsockets,
wrapQtAppsHook,
}:
mkDerivation rec {
pname = "cockatrice";
version = "2025-04-03-Release-2.10.2";
src = fetchFromGitHub {
owner = "Cockatrice";
repo = "Cockatrice";
rev = version;
sha256 = "sha256-zXAK830SdGT3xN3ST8h9LLy/oWr4MH6TZf57gLfI0e8=";
};
buildInputs = [
qtbase
qtmultimedia
protobuf
qttools
qtwebsockets
];
nativeBuildInputs = [
cmake
wrapQtAppsHook
];
meta = {
homepage = "https://github.com/Cockatrice/Cockatrice";
description = "Cross-platform virtual tabletop for multiplayer card games";
license = lib.licenses.gpl2Plus;
maintainers = with lib.maintainers; [ evanjs ];
platforms = with lib.platforms; linux;
};
}

View File

@@ -0,0 +1,42 @@
{
lib,
stdenv,
fetchurl,
libX11,
zlib,
xorgproto,
libGL ? null,
libGLU ? null,
libglut ? null,
}:
stdenv.mkDerivation rec {
pname = "construo";
version = "0.2.3";
src = fetchurl {
url = "https://github.com/Construo/construo/releases/download/v${version}/${pname}-${version}.tar.gz";
sha256 = "1wmj527hbj1qv44cdsj6ahfjrnrjwg2dp8gdick8nd07vm062qxa";
};
buildInputs = [
libX11
zlib
xorgproto
]
++ lib.optional (libGL != null) libGL
++ lib.optional (libGLU != null) libGLU
++ lib.optional (libglut != null) libglut;
preConfigure = ''
substituteInPlace src/Makefile.in \
--replace games bin
'';
meta = {
description = "Masses and springs simulation game";
mainProgram = "construo.x11";
homepage = "http://fs.fsf.org/construo/";
license = lib.licenses.gpl3;
};
}

View File

@@ -0,0 +1,137 @@
{
stdenv,
lib,
fetchFromGitHub,
which,
sqlite,
lua5_1,
perl,
python3,
zlib,
pkg-config,
ncurses,
dejavu_fonts,
libpng,
SDL2,
SDL2_image,
SDL2_mixer,
libGLU,
libGL,
freetype,
pngcrush,
advancecomp,
tileMode ? false,
enableSound ? tileMode,
buildPackages,
}:
stdenv.mkDerivation rec {
pname = "crawl${lib.optionalString tileMode "-tiles"}";
version = "0.33.1";
src = fetchFromGitHub {
owner = "crawl";
repo = "crawl";
rev = version;
hash = "sha256-GXrYLGoQ1UwDHs+kLLcaBNpJ2BVMv4NhmpyfNFxPmg8=";
};
# Patch hard-coded paths and remove force library builds
postPatch = ''
substituteInPlace crawl-ref/source/util/find_font \
--replace '/usr/share/fonts /usr/local/share/fonts /usr/*/lib/X11/fonts' '${fontsPath}/share/fonts'
substituteInPlace crawl-ref/source/windowmanager-sdl.cc \
--replace 'SDL_image.h' 'SDL2/SDL_image.h'
'';
nativeBuildInputs = [
pkg-config
which
perl
pngcrush
advancecomp
];
# Still unstable with luajit
buildInputs = [
lua5_1
zlib
sqlite
ncurses
]
++ (with python3.pkgs; [ pyyaml ])
++ lib.optionals tileMode [
libpng
SDL2
SDL2_image
freetype
libGLU
libGL
]
++ lib.optional enableSound SDL2_mixer;
preBuild = ''
cd crawl-ref/source
echo "${version}" > util/release_ver
patchShebangs 'util'
patchShebangs util/gen-mi-enum
rm -rf contrib
mkdir -p $out/xdg-data
''
+ lib.optionalString tileMode "mv xdg-data/*_tiles.* $out/xdg-data"
+ lib.optionalString (!tileMode) "mv xdg-data/*_console.* $out/xdg-data";
fontsPath = lib.optionalString tileMode dejavu_fonts;
makeFlags = [
"prefix=${placeholder "out"}"
"FORCE_CC=${stdenv.cc.targetPrefix}cc"
"FORCE_CXX=${stdenv.cc.targetPrefix}c++"
"HOSTCXX=${buildPackages.stdenv.cc.targetPrefix}c++"
"FORCE_PKGCONFIG=y"
"SAVEDIR=~/.crawl"
"sqlite=${sqlite.dev}"
"DATADIR=${placeholder "out"}"
]
++ lib.optional tileMode "TILES=y"
++ lib.optional enableSound "SOUND=y";
postInstall =
lib.optionalString tileMode ''
mv $out/bin/crawl $out/bin/crawl-tiles
echo "Exec=crawl-tiles" >> $out/xdg-data/org.develz.Crawl_tiles.desktop
echo "Icon=crawl" >> $out/xdg-data/org.develz.Crawl_tiles.desktop
install -Dm444 $out/xdg-data/org.develz.Crawl_tiles.desktop -t $out/share/applications
install -Dm444 $out/xdg-data/org.develz.Crawl_tiles.appdata.xml -t $out/share/metainfo
''
+ lib.optionalString (!tileMode) ''
echo "Exec=crawl" >> $out/xdg-data/org.develz.Crawl_console.desktop
echo "Icon=crawl" >> $out/xdg-data/org.develz.Crawl_console.desktop
install -Dm444 $out/xdg-data/org.develz.Crawl_console.desktop -t $out/share/applications
install -Dm444 $out/xdg-data/org.develz.Crawl_console.appdata.xml -t $out/share/metainfo
''
+ "install -Dm444 dat/tiles/stone_soup_icon-512x512.png $out/share/icons/hicolor/512x512/apps/crawl.png";
enableParallelBuilding = true;
meta = with lib; {
description = "Open-source, single-player, role-playing roguelike game";
homepage = "http://crawl.develz.org/";
longDescription = ''
Dungeon Crawl: Stone Soup, an open-source, single-player, role-playing
roguelike game of exploration and treasure-hunting in dungeons filled
with dangerous and unfriendly monsters in a quest to rescue the
mystifyingly fabulous Orb of Zot.
'';
platforms = platforms.linux ++ platforms.darwin;
license = with licenses; [
gpl2Plus
bsd2
bsd3
mit
licenses.zlib
cc0
];
maintainers = [ ];
};
}

View File

@@ -0,0 +1,39 @@
{
lib,
stdenv,
fetchFromGitHub,
ncurses,
SDL,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "curseofwar";
version = "1.3.0";
src = fetchFromGitHub {
owner = "a-nikolaev";
repo = "curseofwar";
rev = "v${finalAttrs.version}";
sha256 = "1wd71wdnj9izg5d95m81yx3684g4zdi7fsy0j5wwnbd9j34ilz1i";
};
buildInputs = [
ncurses
SDL
];
makeFlags = (lib.optionals (SDL != null) [ "SDL=yes" ]) ++ [
"PREFIX=$(out)"
# force platform's cc on darwin, otherwise gcc is used
"CC=${stdenv.cc.targetPrefix}cc"
];
meta = with lib; {
description = "Fast-paced action strategy game";
homepage = "https://a-nikolaev.github.io/curseofwar/";
license = licenses.gpl3;
mainProgram = if SDL != null then "curseofwar-sdl" else "curseofwar";
maintainers = with maintainers; [ fgaz ];
platforms = platforms.all;
};
})

View File

@@ -0,0 +1,46 @@
{
stdenv,
fetchFromGitHub,
cmake,
pkg-config,
wrapQtAppsHook,
qtbase,
lib,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "cutechess";
version = "1.4.0";
src = fetchFromGitHub {
owner = "cutechess";
repo = "cutechess";
rev = "v${finalAttrs.version}";
hash = "sha256-vhS3Eenxcq7D8E5WVON5C5hCTytcEVbYUeuCkfB0apA=";
};
nativeBuildInputs = [
cmake
pkg-config
wrapQtAppsHook
];
buildInputs = [
qtbase
];
postInstall = ''
install -Dm555 cutechess{,-cli} -t $out/bin/
install -Dm444 libcutechess.a -t $out/lib/
install -Dm444 $src/docs/cutechess-cli.6 -t $out/share/man/man6/
install -Dm444 $src/docs/cutechess-engines.json.5 -t $out/share/man/man5/
'';
meta = with lib; {
description = "GUI, CLI, and library for playing chess";
homepage = "https://cutechess.com/";
license = licenses.gpl3Plus;
maintainers = [ ];
platforms = with platforms; (linux ++ windows);
mainProgram = "cutechess";
};
})

View File

@@ -0,0 +1,59 @@
{
lib,
stdenv,
fetchurl,
cmake,
qttools,
wrapQtAppsHook,
qtbase,
qtwayland,
qtsvg,
}:
stdenv.mkDerivation rec {
pname = "cutemaze";
version = "1.3.5";
src = fetchurl {
url = "https://gottcode.org/cutemaze/cutemaze-${version}.tar.bz2";
hash = "sha256-a+QIOD0TB0AGnqIUgtkMBZuPUCQbXp4NtZ6b0vk/J0c=";
};
nativeBuildInputs = [
cmake
qttools
wrapQtAppsHook
];
buildInputs = [
qtbase
qtsvg
]
++ lib.optionals stdenv.hostPlatform.isLinux [
qtwayland
];
installPhase =
if stdenv.hostPlatform.isDarwin then
''
runHook preInstall
mkdir -p $out/Applications
mv CuteMaze.app $out/Applications
makeWrapper $out/Applications/CuteMaze.app/Contents/MacOS/CuteMaze $out/bin/cutemaze
runHook postInstall
''
else
null;
meta = with lib; {
changelog = "https://github.com/gottcode/cutemaze/blob/v${version}/ChangeLog";
description = "Simple, top-down game in which mazes are randomly generated";
mainProgram = "cutemaze";
homepage = "https://gottcode.org/cutemaze/";
license = licenses.gpl3Plus;
maintainers = with maintainers; [ dotlambda ];
platforms = platforms.unix;
};
}

View File

@@ -0,0 +1,17 @@
diff --git a/src/core/gitinfo.h b/src/core/gitinfo.h
new file mode 100644
index 00000000..6f330552
--- /dev/null
+++ b/src/core/gitinfo.h
@@ -0,0 +1,11 @@
+// 4cce0a37b134283ed38ee4814bb282773f9c2ed1
+//
+// This file was automatically generated by the
+// updaterevision tool. Do not edit by hand.
+
+#define GIT_DESCRIPTION "1.4.1-29-g4cce0a37"
+#define GIT_HASH "4cce0a37b134283ed38ee4814bb282773f9c2ed1"
+#define GIT_TIME "2023-08-09 13:55:37 +0200"
+#define HG_REVISION_NUMBER 1691582137
+#define HG_REVISION_HASH_STRING "4cce0a37b134"
+#define HG_TIME "230809-1155"

View File

@@ -0,0 +1,63 @@
{
lib,
stdenv,
cmake,
fetchFromBitbucket,
wrapQtAppsHook,
pkg-config,
qtbase,
qttools,
qtmultimedia,
zlib,
bzip2,
xxd,
}:
stdenv.mkDerivation {
pname = "doomseeker";
version = "2023-08-09";
src = fetchFromBitbucket {
owner = "Doomseeker";
repo = "doomseeker";
rev = "4cce0a37b134283ed38ee4814bb282773f9c2ed1";
hash = "sha256-J7gesOo8NUPuVaU0o4rCGzLrqr3IIMAchulWZG3HTqg=";
};
patches = [
./dont_update_gitinfo.patch
./add_gitinfo.patch
./fix_paths.patch
];
nativeBuildInputs = [
wrapQtAppsHook
cmake
qttools
pkg-config
xxd
];
buildInputs = [
qtbase
qtmultimedia
zlib
bzip2
];
hardeningDisable = lib.optional stdenv.hostPlatform.isDarwin "format";
# Doomseeker looks for the engines in the program directory
postInstall = ''
mv $out/bin/* $out/lib/doomseeker/
ln -s $out/lib/doomseeker/doomseeker $out/bin/
'';
meta = with lib; {
homepage = "http://doomseeker.drdteam.org/";
description = "Multiplayer server browser for many Doom source ports";
mainProgram = "doomseeker";
license = licenses.gpl2Plus;
platforms = platforms.unix;
maintainers = [ ];
};
}

View File

@@ -0,0 +1,45 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4b26e04..338858f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -149,11 +149,8 @@ set(CXX_STANDARD_REQUIRED ON)
if(WIN32)
set(WITH_AUTOUPDATES 1)
- add_subdirectory(tools/updateinstaller)
endif()
-add_subdirectory(tools/updaterevision)
-
add_subdirectory(src/core)
add_subdirectory(src/plugins)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 089e3889..8add598d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -50,13 +50,6 @@ configure_file(doomseeker_copts.h.in doomseeker_copts.h)
option(DOOMSEEKER_INSTALL_NONFREE "Install non-free resources?" ${DEFAULT_NONFREE_INSTALL})
set(DOOMSEEKER_IP2C_DAT "" CACHE FILEPATH "Path to IpToCountry.dat; optional")
-# Get the revision from vcs
-add_custom_target(revision_check ALL
- COMMAND updaterevision ${CMAKE_CURRENT_SOURCE_DIR}/gitinfo.h
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- DEPENDS updaterevision
-)
-
# In case gitinfo.h isn't yet generated create a dummy file so our file listing
# will contain it. We can't just add it to the file listing since then CMake
# would complain that it doesn't exist.
@@ -178,10 +171,6 @@ endif()
target_compile_definitions(doomseeker PRIVATE "-DINSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"" "-DINSTALL_LIBDIR=\"${CMAKE_INSTALL_LIBDIR}\"")
-# Make sure the vcs version file is created before we attempt to compile
-# Doomseeker.
-add_dependencies(doomseeker revision_check)
-
target_link_libraries(doomseeker
LINK_PRIVATE
Wadseeker::wadseeker

View File

@@ -0,0 +1,30 @@
diff --git a/src/core/pathfinder/pathfinder.cpp b/src/core/pathfinder/pathfinder.cpp
index f277283a..454a8145 100644
--- a/src/core/pathfinder/pathfinder.cpp
+++ b/src/core/pathfinder/pathfinder.cpp
@@ -137,9 +137,7 @@ PathFinder PathFinder::genericPathFinder(const QStringList &suffixes)
<< DataPaths::programFilesDirectory(DataPaths::x64)
<< DataPaths::programFilesDirectory(DataPaths::x86);
#else
- paths << "/usr/bin" << "/usr/local/bin" << "/usr/share/bin"
- << "/usr/games/" << "/usr/local/games/"
- << "/usr/share/games/" << QCoreApplication::applicationDirPath() << ".";
+ paths << gDefaultDataPaths->workingDirectory() << ".";
#endif
QStringList pathsCopy(paths);
for (const QString &path : pathsCopy)
diff --git a/src/core/pathfinder/wadpathfinder.cpp b/src/core/pathfinder/wadpathfinder.cpp
index 07df0b64..6300542d 100644
--- a/src/core/pathfinder/wadpathfinder.cpp
+++ b/src/core/pathfinder/wadpathfinder.cpp
@@ -84,10 +84,6 @@ public:
QStringList defaultPaths()
{
QStringList paths;
- #ifdef Q_OS_UNIX
- paths << "/usr/local/share/games/doom/"
- << "/usr/share/games/doom/";
- #endif
return paths;
}
};

View File

@@ -0,0 +1,32 @@
{
mkDerivation,
lib,
fetchFromGitLab,
cmake,
qtbase,
}:
mkDerivation rec {
pname = "enyo-launcher";
version = "2.0.6";
src = fetchFromGitLab {
owner = "sdcofer70";
repo = "enyo-launcher";
rev = version;
hash = "sha256-k6Stc1tQOcdS//j+bFUNfnOUlwuhIPKxf9DHU+ng164=";
};
nativeBuildInputs = [ cmake ];
buildInputs = [ qtbase ];
meta = {
homepage = "https://gitlab.com/sdcofer70/enyo-launcher";
description = "Frontend for Doom engines";
mainProgram = "enyo-launcher";
license = lib.licenses.gpl3Plus;
platforms = lib.platforms.unix;
maintainers = [ lib.maintainers.usrfriendly ];
};
}

View File

@@ -0,0 +1,15 @@
diff -r 4178904d7698 src/gitinfo.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gitinfo.h Fri Dec 01 13:02:42 2023 -0300
@@ -0,0 +1,11 @@
+// 4178904d769879e6c2919fb647ee6dd2736399e9
+//
+// This file was automatically generated by the
+// updaterevision tool. Do not edit by hand.
+
+#define GIT_DESCRIPTION "ZA_3.0.1-572-4178904d7698"
+#define GIT_HASH "4178904d769879e6c2919fb647ee6dd2736399e9"
+#define GIT_TIME "2021-12-11 16:35:55 -0500"
+#define HG_REVISION_NUMBER 1639258555
+#define HG_REVISION_HASH_STRING "4178904d7698"
+#define HG_TIME "211211-2135"

View File

@@ -0,0 +1,15 @@
diff -r 89bccf7127ba src/gitinfo.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gitinfo.h Fri Dec 01 10:18:23 2023 -0300
@@ -0,0 +1,11 @@
+// 89bccf7127ba1ebe92558f674be69549bf2c4bd4
+//
+// This file was automatically generated by the
+// updaterevision tool. Do not edit by hand.
+
+#define GIT_DESCRIPTION "ZA_3.1-404-89bccf7127ba"
+#define GIT_HASH "89bccf7127ba1ebe92558f674be69549bf2c4bd4"
+#define GIT_TIME "2023-07-09 15:14:38 -0400"
+#define HG_REVISION_NUMBER 1688930078
+#define HG_REVISION_HASH_STRING "89bccf7127ba"
+#define HG_TIME "230709-1914"

View File

@@ -0,0 +1,127 @@
{
stdenv,
lib,
fetchhg,
cmake,
pkg-config,
makeWrapper,
callPackage,
soundfont-fluid,
SDL_compat,
libGL,
glew,
bzip2,
zlib,
libjpeg,
fluidsynth,
fmodex,
openssl,
gtk2,
python3,
game-music-emu,
serverOnly ? false,
}:
let
suffix = lib.optionalString serverOnly "-server";
fmod = fmodex; # fmodex is on nixpkgs now
sqlite = callPackage ../sqlite.nix { };
clientLibPath = lib.makeLibraryPath [ fluidsynth ];
in
stdenv.mkDerivation {
pname = "zandronum-alpha${suffix}";
version = "3.2-230709-1914";
src = fetchhg {
# expired ssl certificate
url = "http://hg.osdn.net/view/zandronum/zandronum-stable";
rev = "89bccf7127ba";
hash = "sha256-waD9hKk0A0zMPyqEvAKxaz2e2TBG2G0MJRrzjx1LyB0=";
};
# zandronum tries to download sqlite now when running cmake, don't let it
# it also needs the current mercurial revision info embedded in gitinfo.h
# otherwise, the client will fail to connect to servers because the
# protocol version doesn't match.
patches = [
./zan_configure_impurity.patch
./dont_update_gitinfo.patch
./add_gitinfo.patch
];
# I have no idea why would SDL and libjpeg be needed for the server part!
# But they are.
buildInputs = [
openssl
bzip2
zlib
SDL_compat
libjpeg
sqlite
game-music-emu
]
++ lib.optionals (!serverOnly) [
libGL
glew
fmod
fluidsynth
gtk2
];
nativeBuildInputs = [
cmake
pkg-config
makeWrapper
python3
];
preConfigure = ''
ln -s ${sqlite}/* sqlite/
sed -i -e 's| restrict| _restrict|g' dumb/include/dumb.h \
dumb/src/it/*.c
''
+ lib.optionalString (!serverOnly) ''
sed -i \
-e "s@/usr/share/sounds/sf2/@${soundfont-fluid}/share/soundfonts/@g" \
-e "s@FluidR3_GM.sf2@FluidR3_GM2-2.sf2@g" \
src/sound/music_fluidsynth_mididevice.cpp
'';
cmakeFlags = [
"-DFORCE_INTERNAL_GME=OFF"
]
++ (if serverOnly then [ "-DSERVERONLY=ON" ] else [ "-DFMOD_LIBRARY=${fmod}/lib/libfmodex.so" ]);
hardeningDisable = [ "format" ];
# Won't work well without C or en_US. Setting LANG might not be enough if the user is making use of LC_* so wrap with LC_ALL instead
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/lib/zandronum
cp zandronum${suffix} \
*.pk3 \
${lib.optionalString (!serverOnly) "liboutput_sdl.so"} \
$out/lib/zandronum
makeWrapper $out/lib/zandronum/zandronum${suffix} $out/bin/zandronum-alpha${suffix}
wrapProgram $out/bin/zandronum-alpha${suffix} \
--set LC_ALL="C"
'';
postFixup = lib.optionalString (!serverOnly) ''
patchelf --set-rpath $(patchelf --print-rpath $out/lib/zandronum/zandronum):$out/lib/zandronum:${clientLibPath} \
$out/lib/zandronum/zandronum
'';
passthru = {
inherit fmod sqlite;
};
meta = with lib; {
homepage = "https://zandronum.com/";
description = "Multiplayer oriented port, based off Skulltag, for Doom and Doom II by id Software";
maintainers = with maintainers; [ lassulus ];
license = licenses.sleepycat;
platforms = platforms.linux;
};
}

View File

@@ -0,0 +1,19 @@
diff -r 89bccf7127ba src/CMakeLists.txt
--- a/src/CMakeLists.txt Sun Jul 09 15:14:38 2023 -0400
+++ b/src/CMakeLists.txt Fri Dec 01 10:16:26 2023 -0300
@@ -642,15 +642,6 @@
add_definitions( -DBACKPATCH )
endif( BACKPATCH )
-# Update gitinfo.h
-
-get_target_property( UPDATEREVISION_EXE updaterevision LOCATION )
-
-add_custom_target( revision_check ALL
- COMMAND ${UPDATEREVISION_EXE} src/gitinfo.h
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- DEPENDS updaterevision )
-
# Libraries ZDoom needs
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )

View File

@@ -0,0 +1,69 @@
diff -r 89bccf7127ba sqlite/CMakeLists.txt
--- a/sqlite/CMakeLists.txt Sun Jul 09 15:14:38 2023 -0400
+++ b/sqlite/CMakeLists.txt Fri Dec 01 10:10:35 2023 -0300
@@ -1,65 +1,5 @@
cmake_minimum_required( VERSION 2.4 )
-# [BB/EP] Download SQLite archive and extract the sources if necessary.
-set( ZAN_SQLITE_VERSION 3360000 ) # SQL version 3.36.0
-set( ZAN_SQLITE_YEAR 2021 )
-set( ZAN_SQLITE_SHA1 "a4bcf9e951bfb9745214241ba08476299fc2dc1e" )
-set( ZAN_SQLITE_DOWNLOAD_NAME "sqlite-autoconf-${ZAN_SQLITE_VERSION}" )
-set( ZAN_SQLITE_TEMP_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}.tar.gz" )
-set( ZAN_SQLITE_HASHED_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/sqlite-${ZAN_SQLITE_SHA1}.tar.gz" )
-
-if( IS_DIRECTORY ${ZAN_SQLITE_HASHED_ARCHIVE} OR IS_SYMLINK ${ZAN_SQLITE_HASHED_ARCHIVE} )
- message( FATAL_ERROR "SQLite: ${ZAN_SQLITE_HASHED_ARCHIVE} must be a valid file.\n"
- "SQLite: Please remove it and try again." )
-elseif( ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sqlite3.c ) OR ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sqlite3.h ) OR ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sqlite3ext.h ) )
-
- if( NOT EXISTS ${ZAN_SQLITE_HASHED_ARCHIVE} )
- if( IS_DIRECTORY ${ZAN_SQLITE_TEMP_ARCHIVE} OR IS_SYMLINK ${ZAN_SQLITE_TEMP_ARCHIVE} )
- message( FATAL_ERROR "SQLite: ${ZAN_SQLITE_TEMP_ARCHIVE} must be a valid file.\n"
- "SQLite: Please remove it and try again." )
- endif()
-
- message( STATUS "SQLite: downloading the archive..." )
-
- file( DOWNLOAD https://www.sqlite.org/${ZAN_SQLITE_YEAR}/${ZAN_SQLITE_DOWNLOAD_NAME}.tar.gz ${ZAN_SQLITE_TEMP_ARCHIVE}
- SHOW_PROGRESS
- STATUS ZAN_SQLITE_DOWNLOAD_STATUS )
-
- # Report any problem if present and abort immediately.
- list( GET ZAN_SQLITE_DOWNLOAD_STATUS 0 ZAN_SQLITE_DOWNLOAD_ERROR_CODE )
- if( ZAN_SQLITE_DOWNLOAD_ERROR_CODE )
- list( GET ZAN_SQLITE_DOWNLOAD_STATUS 1 ZAN_SQLITE_DOWNLOAD_ERROR_MESSAGE )
- message( FATAL_ERROR "SQLite: download failed. Reason: ${ZAN_SQLITE_DOWNLOAD_ERROR_MESSAGE}" )
- endif()
-
- # Check the hash. Abort immediately if it's not valid (something is wrong with the download)
- file( SHA1 ${ZAN_SQLITE_TEMP_ARCHIVE} ZAN_SQLITE_CURRENT_SHA1 )
- if( NOT ZAN_SQLITE_CURRENT_SHA1 STREQUAL ZAN_SQLITE_SHA1 )
- message( FATAL_ERROR "SQLite: download failed. The downloaded file has a different hash:\n"
- "SQLite: valid: ${ZAN_SQLITE_SHA1}\n"
- "SQLite: downloaded: ${ZAN_SQLITE_CURRENT_SHA1}" )
- endif()
-
- # Rename the archive.
- execute_process( COMMAND ${CMAKE_COMMAND} -E rename ${ZAN_SQLITE_TEMP_ARCHIVE} ${ZAN_SQLITE_HASHED_ARCHIVE} )
- endif()
-
- message( STATUS "SQLite: saving the source files into the 'sqlite' directory." )
-
- # Extract the archive.
- execute_process( COMMAND ${CMAKE_COMMAND} -E tar xzf ${ZAN_SQLITE_HASHED_ARCHIVE} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
-
- # Copy the required files.
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}/sqlite3.c ${CMAKE_CURRENT_SOURCE_DIR} )
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}/sqlite3.h ${CMAKE_CURRENT_SOURCE_DIR} )
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}/sqlite3ext.h ${CMAKE_CURRENT_SOURCE_DIR} )
-
- # Remove the extracted folder.
- execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME} )
-
- message( STATUS "SQLite: done." )
-endif()
-
# [BB] Silence all GCC warnings
IF ( CMAKE_COMPILER_IS_GNUCXX )
ADD_DEFINITIONS ( -w )

View File

@@ -0,0 +1,128 @@
{
stdenv,
lib,
fetchhg,
cmake,
pkg-config,
makeWrapper,
callPackage,
soundfont-fluid,
SDL_compat,
libGL,
glew,
bzip2,
zlib,
libjpeg,
fluidsynth,
fmodex,
openssl,
gtk2,
python3,
game-music-emu,
serverOnly ? false,
}:
let
suffix = lib.optionalString serverOnly "-server";
fmod = fmodex; # fmodex is on nixpkgs now
sqlite = callPackage ./sqlite.nix { };
clientLibPath = lib.makeLibraryPath [ fluidsynth ];
in
stdenv.mkDerivation {
pname = "zandronum${suffix}";
version = "3.1.0";
src = fetchhg {
# expired ssl certificate
url = "http://hg.osdn.net/view/zandronum/zandronum-stable";
rev = "4178904d7698";
hash = "sha256-5t36CoRPPjDKQE0DVSv2Qqpqko6JAXBI53tuAYiylHQ=";
};
# zandronum tries to download sqlite now when running cmake, don't let it
# it also needs the current mercurial revision info embedded in gitinfo.h
# otherwise, the client will fail to connect to servers because the
# protocol version doesn't match.
patches = [
./zan_configure_impurity.patch
./dont_update_gitinfo.patch
./add_gitinfo.patch
];
# I have no idea why would SDL and libjpeg be needed for the server part!
# But they are.
buildInputs = [
openssl
bzip2
zlib
SDL_compat
libjpeg
sqlite
game-music-emu
]
++ lib.optionals (!serverOnly) [
libGL
glew
fmod
fluidsynth
gtk2
];
nativeBuildInputs = [
cmake
pkg-config
makeWrapper
python3
];
preConfigure = ''
ln -s ${sqlite}/* sqlite/
sed -i -e 's| restrict| _restrict|g' dumb/include/dumb.h \
dumb/src/it/*.c
''
+ lib.optionalString (!serverOnly) ''
sed -i \
-e "s@/usr/share/sounds/sf2/@${soundfont-fluid}/share/soundfonts/@g" \
-e "s@FluidR3_GM.sf2@FluidR3_GM2-2.sf2@g" \
src/sound/music_fluidsynth_mididevice.cpp
'';
cmakeFlags = [
"-DFORCE_INTERNAL_GME=OFF"
]
++ (if serverOnly then [ "-DSERVERONLY=ON" ] else [ "-DFMOD_LIBRARY=${fmod}/lib/libfmodex.so" ]);
hardeningDisable = [ "format" ];
# Won't work well without C or en_US. Setting LANG might not be enough if the user is making use of LC_* so wrap with LC_ALL instead
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/lib/zandronum
cp zandronum${suffix} \
*.pk3 \
${lib.optionalString (!serverOnly) "liboutput_sdl.so"} \
$out/lib/zandronum
makeWrapper $out/lib/zandronum/zandronum${suffix} $out/bin/zandronum${suffix}
wrapProgram $out/bin/zandronum${suffix} \
--set LC_ALL="C"
'';
postFixup = lib.optionalString (!serverOnly) ''
patchelf --set-rpath $(patchelf --print-rpath $out/lib/zandronum/zandronum):$out/lib/zandronum:${clientLibPath} \
$out/lib/zandronum/zandronum
'';
passthru = {
inherit fmod sqlite;
};
meta = with lib; {
homepage = "https://zandronum.com/";
description = "Multiplayer oriented port, based off Skulltag, for Doom and Doom II by id Software";
mainProgram = "zandronum-server";
maintainers = with maintainers; [ lassulus ];
license = licenses.sleepycat;
platforms = platforms.linux;
};
}

View File

@@ -0,0 +1,19 @@
diff -r 4178904d7698 src/CMakeLists.txt
--- a/src/CMakeLists.txt Sat Dec 11 16:35:55 2021 -0500
+++ b/src/CMakeLists.txt Fri Dec 01 13:00:32 2023 -0300
@@ -642,15 +642,6 @@
add_definitions( -DBACKPATCH )
endif( BACKPATCH )
-# Update gitinfo.h
-
-get_target_property( UPDATEREVISION_EXE updaterevision LOCATION )
-
-add_custom_target( revision_check ALL
- COMMAND ${UPDATEREVISION_EXE} src/gitinfo.h
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- DEPENDS updaterevision )
-
# Libraries ZDoom needs
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )

View File

@@ -0,0 +1,68 @@
{
stdenv,
lib,
fetchurl,
alsa-lib,
libpulseaudio,
undmg,
}:
let
bits = lib.optionalString (stdenv.hostPlatform.system == "x86_64-linux") "64";
libPath = lib.makeLibraryPath [
stdenv.cc.cc
alsa-lib
libpulseaudio
];
in
stdenv.mkDerivation rec {
pname = "fmod";
version = "4.44.64";
shortVersion = builtins.replaceStrings [ "." ] [ "" ] version;
src = fetchurl (
if stdenv.hostPlatform.isLinux then
{
url = "https://zdoom.org/files/fmod/fmodapi${shortVersion}linux.tar.gz";
sha256 = "047hk92xapwwqj281f4zwl0ih821rrliya70gfj82sdfjh9lz8i1";
}
else
{
url = "https://zdoom.org/files/fmod/fmodapi${shortVersion}mac-installer.dmg";
sha256 = "1m1y4cpcwpkl8x31d3s68xzp107f343ma09w2437i2adn5y7m8ii";
}
);
nativeBuildInputs = [ undmg ];
dontStrip = true;
dontPatchELF = true;
dontBuild = true;
installPhase =
lib.optionalString stdenv.hostPlatform.isLinux ''
install -Dm755 api/lib/libfmodex${bits}-${version}.so $out/lib/libfmodex-${version}.so
ln -s libfmodex-${version}.so $out/lib/libfmodex.so
patchelf --set-rpath ${libPath} $out/lib/libfmodex.so
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
install -D api/lib/libfmodex.dylib $out/lib/libfmodex.dylib
install -D api/lib/libfmodexL.dylib $out/lib/libfmodexL.dylib
''
+ ''
cp -r api/inc $out/include
'';
meta = with lib; {
description = "Programming library and toolkit for the creation and playback of interactive audio";
homepage = "http://www.fmod.org/";
license = licenses.unfreeRedistributable;
platforms = [
"x86_64-linux"
"i686-linux"
"x86_64-darwin"
];
maintainers = [ maintainers.lassulus ];
};
}

View File

@@ -0,0 +1,29 @@
{
lib,
stdenv,
fetchurl,
}:
stdenv.mkDerivation {
pname = "sqlite-zandronum";
version = "3.0";
src = fetchurl {
url = "https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz";
sha256 = "1qxwkfvd185dfcqbakrzikrsw6ffr5jp1gl3dch9dsdyjvmw745x";
};
buildPhase = ''
mkdir -p $out
cp sqlite3.c $out/
cp sqlite3.h $out/
cp sqlite3ext.h $out/
'';
meta = {
homepage = "http://www.sqlite.org/";
description = "Single C code file, named sqlite3.c, that contains all C code for the core SQLite library and the FTS3 and RTREE extensions";
platforms = lib.platforms.unix;
maintainers = [ lib.maintainers.lassulus ];
};
}

View File

@@ -0,0 +1,69 @@
diff -r 4178904d7698 sqlite/CMakeLists.txt
--- a/sqlite/CMakeLists.txt Sat Dec 11 16:35:55 2021 -0500
+++ b/sqlite/CMakeLists.txt Fri Dec 01 12:57:55 2023 -0300
@@ -1,65 +1,5 @@
cmake_minimum_required( VERSION 2.4 )
-# [BB/EP] Download SQLite archive and extract the sources if necessary.
-set( ZAN_SQLITE_VERSION 3360000 ) # SQL version 3.36.0
-set( ZAN_SQLITE_YEAR 2021 )
-set( ZAN_SQLITE_SHA1 "a4bcf9e951bfb9745214241ba08476299fc2dc1e" )
-set( ZAN_SQLITE_DOWNLOAD_NAME "sqlite-autoconf-${ZAN_SQLITE_VERSION}" )
-set( ZAN_SQLITE_TEMP_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}.tar.gz" )
-set( ZAN_SQLITE_HASHED_ARCHIVE "${CMAKE_CURRENT_SOURCE_DIR}/sqlite-${ZAN_SQLITE_SHA1}.tar.gz" )
-
-if( IS_DIRECTORY ${ZAN_SQLITE_HASHED_ARCHIVE} OR IS_SYMLINK ${ZAN_SQLITE_HASHED_ARCHIVE} )
- message( FATAL_ERROR "SQLite: ${ZAN_SQLITE_HASHED_ARCHIVE} must be a valid file.\n"
- "SQLite: Please remove it and try again." )
-elseif( ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sqlite3.c ) OR ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sqlite3.h ) OR ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/sqlite3ext.h ) )
-
- if( NOT EXISTS ${ZAN_SQLITE_HASHED_ARCHIVE} )
- if( IS_DIRECTORY ${ZAN_SQLITE_TEMP_ARCHIVE} OR IS_SYMLINK ${ZAN_SQLITE_TEMP_ARCHIVE} )
- message( FATAL_ERROR "SQLite: ${ZAN_SQLITE_TEMP_ARCHIVE} must be a valid file.\n"
- "SQLite: Please remove it and try again." )
- endif()
-
- message( STATUS "SQLite: downloading the archive..." )
-
- file( DOWNLOAD https://www.sqlite.org/${ZAN_SQLITE_YEAR}/${ZAN_SQLITE_DOWNLOAD_NAME}.tar.gz ${ZAN_SQLITE_TEMP_ARCHIVE}
- SHOW_PROGRESS
- STATUS ZAN_SQLITE_DOWNLOAD_STATUS )
-
- # Report any problem if present and abort immediately.
- list( GET ZAN_SQLITE_DOWNLOAD_STATUS 0 ZAN_SQLITE_DOWNLOAD_ERROR_CODE )
- if( ZAN_SQLITE_DOWNLOAD_ERROR_CODE )
- list( GET ZAN_SQLITE_DOWNLOAD_STATUS 1 ZAN_SQLITE_DOWNLOAD_ERROR_MESSAGE )
- message( FATAL_ERROR "SQLite: download failed. Reason: ${ZAN_SQLITE_DOWNLOAD_ERROR_MESSAGE}" )
- endif()
-
- # Check the hash. Abort immediately if it's not valid (something is wrong with the download)
- file( SHA1 ${ZAN_SQLITE_TEMP_ARCHIVE} ZAN_SQLITE_CURRENT_SHA1 )
- if( NOT ZAN_SQLITE_CURRENT_SHA1 STREQUAL ZAN_SQLITE_SHA1 )
- message( FATAL_ERROR "SQLite: download failed. The downloaded file has a different hash:\n"
- "SQLite: valid: ${ZAN_SQLITE_SHA1}\n"
- "SQLite: downloaded: ${ZAN_SQLITE_CURRENT_SHA1}" )
- endif()
-
- # Rename the archive.
- execute_process( COMMAND ${CMAKE_COMMAND} -E rename ${ZAN_SQLITE_TEMP_ARCHIVE} ${ZAN_SQLITE_HASHED_ARCHIVE} )
- endif()
-
- message( STATUS "SQLite: saving the source files into the 'sqlite' directory." )
-
- # Extract the archive.
- execute_process( COMMAND ${CMAKE_COMMAND} -E tar xzf ${ZAN_SQLITE_HASHED_ARCHIVE} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} )
-
- # Copy the required files.
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}/sqlite3.c ${CMAKE_CURRENT_SOURCE_DIR} )
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}/sqlite3.h ${CMAKE_CURRENT_SOURCE_DIR} )
- execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME}/sqlite3ext.h ${CMAKE_CURRENT_SOURCE_DIR} )
-
- # Remove the extracted folder.
- execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_SOURCE_DIR}/${ZAN_SQLITE_DOWNLOAD_NAME} )
-
- message( STATUS "SQLite: done." )
-endif()
-
# [BB] Silence all GCC warnings
IF ( CMAKE_COMPILER_IS_GNUCXX )
ADD_DEFINITIONS ( -w )

View File

@@ -0,0 +1,65 @@
{
lib,
stdenv,
fetchurl,
love,
lua,
makeWrapper,
makeDesktopItem,
}:
stdenv.mkDerivation rec {
pname = "duckmarines";
version = "1.0c";
icon = fetchurl {
url = "http://tangramgames.dk/img/thumb/duckmarines.png";
sha256 = "07ypbwqcgqc5f117yxy9icix76wlybp1cmykc8f3ivdps66hl0k5";
};
desktopItem = makeDesktopItem {
name = "duckmarines";
exec = "duckmarines";
icon = icon;
comment = "Duck-themed action puzzle video game";
desktopName = "Duck Marines";
genericName = "duckmarines";
categories = [ "Game" ];
};
src = fetchurl {
url = "https://github.com/SimonLarsen/duckmarines/releases/download/v${version}/duckmarines-1.0c.love";
sha256 = "1rvgpkvi4h9zhc4fwb4knhsa789yjcx4a14fi4vqfdyybhvg5sh9";
};
nativeBuildInputs = [ makeWrapper ];
buildInputs = [
lua
love
];
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin
mkdir -p $out/share/games/lovegames
cp -v ${src} $out/share/games/lovegames/duckmarines.love
makeWrapper ${love}/bin/love $out/bin/duckmarines --add-flags $out/share/games/lovegames/duckmarines.love
chmod +x $out/bin/duckmarines
mkdir -p $out/share/applications
ln -s ${desktopItem}/share/applications/* $out/share/applications/
'';
meta = with lib; {
description = "Duck-themed action puzzle video game";
maintainers = with maintainers; [ leenaars ];
platforms = platforms.linux;
hydraPlatforms = [ ];
license = licenses.free;
downloadPage = "http://tangramgames.dk/games/duckmarines";
};
}

View File

@@ -0,0 +1,9 @@
# dwarf-fortress
Maintainers, please read me!
The policy for updates is currently keeping one major version of DF around since 0.44.
See [Save Compatibility](https://dwarffortresswiki.org/index.php/Save_compatibility)
on the DF wiki. Note that saves are backwards compatible, but not forwards-compatible.
This policy has been in effect since Nixpkgs 25.05.

View File

@@ -0,0 +1,167 @@
{
stdenv,
stdenvNoCC,
gccStdenv,
lib,
recurseIntoAttrs,
libsForQt5,
newScope,
perlPackages,
}:
# To whomever it may concern:
#
# This directory menaces with spikes of Nix code. It is terrifying.
#
# If this is your first time here, you should probably install the dwarf-fortress-full package,
# for instance with:
#
# environment.systemPackages = [ pkgs.dwarf-fortress-packages.dwarf-fortress-full ];
#
# You can adjust its settings by using override, or compile your own package by
# using the other packages here.
#
# For example, you can enable the FPS indicator, disable the intro, pick a
# theme other than phoebus (the default for dwarf-fortress-full), _and_ use
# an older version with something like:
#
# environment.systemPackages = [
# (pkgs.dwarf-fortress-packages.dwarf-fortress-full.override {
# dfVersion = "0.44.11";
# theme = "cla";
# enableIntro = false;
# enableFPS = true;
# })
# ]
#
# Take a look at lazy-pack.nix to see all the other options.
#
# You will find the configuration files in ~/.local/share/df_linux/data/init. If
# you un-symlink them and edit, then the scripts will avoid overwriting your
# changes on later launches, but consider extending the wrapper with your
# desired options instead.
let
inherit (lib)
attrNames
getAttr
importJSON
listToAttrs
optionalAttrs
recurseIntoAttrs
replaceStrings
versionAtLeast
;
callPackage = newScope self;
# 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. Note that unfuck and twbt are not required for 50.
latestVersion =
self.dfVersions.game.latest.${
if stdenv.hostPlatform.isLinux then
"linux"
else if stdenv.hostPlatform.isDarwin then
"darwin"
else
throw "Unsupported system"
};
# Converts a version to a package name.
versionToName = version: "dwarf-fortress_${replaceStrings [ "." ] [ "_" ] version}";
# A map of names to each Dwarf Fortress package we know about.
df-games = listToAttrs (
map (dfVersion: {
name = versionToName dfVersion;
value =
let
isAtLeast50 = versionAtLeast dfVersion "50.0";
dwarf-fortress-unfuck = optionalAttrs (!isAtLeast50 && stdenv.hostPlatform.isLinux) (
callPackage ./unfuck.nix { inherit dfVersion; }
);
dwarf-fortress = callPackage ./game.nix {
inherit dfVersion;
inherit dwarf-fortress-unfuck;
};
twbt = optionalAttrs (!isAtLeast50) (callPackage ./twbt { inherit dfVersion; });
dfhack = callPackage ./dfhack {
inherit (perlPackages) XMLLibXML XMLLibXSLT;
inherit dfVersion;
stdenv = gccStdenv;
};
mkDfWrapper =
{
dwarf-fortress,
dfhack,
dwarf-therapist ? null,
...
}@args:
callPackage ./wrapper (
{
inherit (self) themes;
inherit
dwarf-fortress
twbt
dfhack
dwarf-therapist
;
}
// args
);
dwarf-therapist = libsForQt5.callPackage ./dwarf-therapist/wrapper.nix {
inherit dwarf-fortress dfhack mkDfWrapper;
dwarf-therapist =
(libsForQt5.callPackage ./dwarf-therapist {
inherit (self) dfVersions;
}).override
(
optionalAttrs (!isAtLeast50) {
# 41.2.5 is the last version to support Dwarf Fortress 0.47.
version = "41.2.5";
maxDfVersion = "0.47.05";
hash = "sha256-xfYBtnO1n6OcliVt07GsQ9alDJIfWdVhtuyWwuvXSZs=";
}
);
};
in
mkDfWrapper { inherit dwarf-fortress dfhack dwarf-therapist; };
}) (attrNames self.dfVersions.game.versions)
);
self = rec {
dfVersions = importJSON ./df.lock.json;
# Aliases for the latest Dwarf Fortress and the selected Therapist install
dwarf-fortress = getAttr (versionToName latestVersion) df-games;
dwarf-therapist = dwarf-fortress.dwarf-therapist;
dwarf-fortress-original = dwarf-fortress.dwarf-fortress;
dwarf-fortress-full = callPackage ./lazy-pack.nix {
inherit df-games versionToName latestVersion;
};
soundSense = callPackage ./soundsense.nix { };
legends-browser = callPackage ./legends-browser { };
themes = recurseIntoAttrs (
callPackage ./themes {
stdenv = stdenvNoCC;
}
);
# Theme aliases
phoebus-theme = themes.phoebus;
cla-theme = themes.cla;
};
in
self // df-games

View File

@@ -0,0 +1,127 @@
{
"game": {
"latest": {
"linux": "52.04",
"darwin": "0.47.05"
},
"versions": {
"52.04": {
"df": {
"version": "52.04",
"urls": {
"linux": {
"url": "https://www.bay12games.com/dwarves/df_52_04_linux.tar.bz2",
"outputHash": "sha256-x/v4yWuojnbea0N7KUAINBdhPBjl0DoWy8Pi/eDCpec="
}
}
},
"hack": {
"version": "52.04-r1",
"git": {
"url": "https://github.com/DFHack/dfhack.git",
"revision": "52.04-r1",
"outputHash": "sha256-DPW+fvurUYnwfGrEqV3JEN1TfllOJPHqGIlNJ3Wha90="
},
"xmlRev": "7b691d256f9427036e7ff24fa795a0f9334739e7"
}
},
"51.13": {
"df": {
"version": "51.13",
"urls": {
"linux": {
"url": "https://www.bay12games.com/dwarves/df_51_13_linux.tar.bz2",
"outputHash": "sha256-Fdb3QS+P0xL4/U0z6nZyMh78KVHDiu9TI3fF6saAw3I="
}
}
},
"hack": {
"version": "51.13-r1",
"git": {
"url": "https://github.com/DFHack/dfhack.git",
"revision": "51.13-r1",
"outputHash": "sha256-Z6ZmXl4BmSg9jRwPpYKMIw3fW6DYxBJEv8oboh+PbZQ="
},
"xmlRev": "ae7424d3f40bf60b3906b5b9b472cb9a7209a3a8"
}
},
"50.15": {
"df": {
"version": "50.15",
"urls": {
"linux": {
"url": "https://www.bay12games.com/dwarves/df_50_15_linux.tar.bz2",
"outputHash": "sha256-KkKcXfXjD7dUjQDfKtXiaKfoieRN8wJSYxyN6liBwU4="
}
}
},
"hack": {
"version": "50.15-r2",
"git": {
"url": "https://github.com/DFHack/dfhack.git",
"revision": "50.15-r2",
"outputHash": "sha256-6T1RXdBJdo/tvHXwYATS8emLIfDg7/0cGL4i982iHdY="
},
"xmlRev": "c6c8f15afec05d457813c003a869509901993af4"
}
},
"0.47.05": {
"df": {
"version": "0.47.05",
"urls": {
"linux": {
"url": "https://www.bay12games.com/dwarves/df_47_05_linux.tar.bz2",
"outputHash": "sha256-rHSm27fX2WIfQwQFCAMiq1DDX2YyNS/y6pI/bcWv/KM="
},
"darwin": {
"url": "https://www.bay12games.com/dwarves/df_47_05_osx.tar.bz2",
"outputHash": "sha256-vHmpKtuWSX1ZVGN46MmrLvZ8oiq/vZdjYW3pwuAOXyQ="
}
}
},
"hack": {
"version": "0.47.05-r8",
"git": {
"url": "https://github.com/DFHack/dfhack.git",
"revision": "0.47.05-r8",
"outputHash": "sha256-y5XluaNU0ewUg2uAd77+h80CYDwNr1rsxB8IslZWip8="
},
"xmlRev": "afe7e908e9e7e863412e8983f9feb2b999fae498"
}
},
"0.44.12": {
"df": {
"version": "0.44.12",
"urls": {
"linux": {
"url": "https://www.bay12games.com/dwarves/df_44_12_linux.tar.bz2",
"outputHash": "sha256-Wi0Vcw0htBpo2gnOPDtww+Km/RW5XGy/toV47S0tuXk="
},
"darwin": {
"url": "https://www.bay12games.com/dwarves/df_44_12_osx.tar.bz2",
"outputHash": "sha256-IY1TGZ9+ufWMA146XUTYgvG2ngfvY/mKZZDWGm/IptU="
}
}
},
"hack": {
"version": "0.44.12-r3",
"git": {
"url": "https://github.com/DFHack/dfhack.git",
"revision": "0.44.12-r3",
"outputHash": "sha256-8ChD4P7SpSNlhhOsrbIxoJ/T/CWobwvOY7QswxP0KK0="
},
"xmlRev": "4053321b202a29f667d64d824ba8339ec1b1df4f"
}
}
}
},
"therapist": {
"version": "42.1.18",
"maxDfVersion": "52.03",
"git": {
"url": "https://github.com/Dwarf-Therapist/Dwarf-Therapist.git",
"revision": "v42.1.18",
"outputHash": "sha256-RdBUpVkjvsNjTowHpQ2FQUCtJiwfqls4dnoUIwKoXGg="
}
}
}

View File

@@ -0,0 +1,40 @@
From tarn.adams@gmail.com Sat Oct 30 00:56:16 2010
Date: Fri, 29 Oct 2010 16:56:15 -0800
From: Tarn Adams <tarn.adams@gmail.com>
To: roconnor@theorem.ca
Subject: Re: Dwarf Fortress Redistribution for NixOS
Sure, that redistribution is fine. I think I've handled the movie
issue for next time now. Thanks for the heads up on that.
Tarn
On Fri, Oct 29, 2010 at 6:56 AM, <roconnor@theorem.ca> wrote:
> I'd like to distribute a *slightly* modified version of Dwarf Fortress which
> is needed to run it under the NixOS distribution of Linux (see
> <https://nixos.org/>
>
> Modification: The interpreter location /lib/ld-linux.so.2 in
> lib/Dwarf_Fortress is replaced with the location of ld-linux.so.2 under the
> NixOS distribution (which is currently
> /nix/store/l8x3fdy1r6zf441vnqa87lzsvxrjbdz9-glibc-2.11.1/lib/ld-linux.so.2
> but might change at a later date to something similar).
>
> I don't need you to recompile Dwarf Fortress.  I can patch the binary itself
> using patchelf.  I just would like your permission to redistrubute this
> modified binary.
>
> Thanks, I'm looking forward to trying out your game and letting other Nix
> users try it out too.
>
> P.S. the inital_movies are open in read/write mode instead of read-only mode
> which causes some issues under NixOS because the inital_movies are stored
> read-only.  I have a workaround, but you may want to consider opening these
> files in read-only mode.
>
> --
> Russell O'Connor                                      <http://r6.ca/>
> ``All talk about `theft,''' the general counsel of the American Graphophone
> Company wrote, ``is the merest claptrap, for there exists no property in
> ideas musical, literary or artistic, except as defined by statute.''
>

View File

@@ -0,0 +1,57 @@
From: Tarn Adams <tarn.adams@gmail.com>
Date: Thu, 4 Apr 2024 20:18:35 -0700
Subject: Re: Dwarf Fortress v50 Redistribution for NixOS
To: Morgan <me@numin.it>
Yeah, it's fine to continue redistributing the classic version as before.
Ah, yeah, I'm aware of the command line issue. Hopefully it can be cleaned
up with some of the other missing functionality like legends mode image
export.
Tarn
On Wed, Apr 3, 2024 at 1:26 AM Morgan <me@numin.it> wrote:
> Tarn,
>
> I maintain the Dwarf Fortress package for NixOS (<https://nixos.org>),
> and wanted to double check with you that packaging v50.x and later is
> still okay. One of our maintainers previously received permission, but
> that was 14(!) years ago:
>
>
> https://github.com/NixOS/nixpkgs/blob/master/pkgs/games/dwarf-fortress/df_permission
>
> Users installing Dwarf Fortress using Nix automatically pull the
> tar.bz2 classic builds from the Bay 12 Games site. The Nix package
> recipes make minor changes to some of the executable files; namely,
> patching paths to shared object files like SDL, ld-linux.so, and
> libc++ using patchelf. Users who install Nix or run NixOS can run this
> whole process automatically and have a working Dwarf Fortress with:
>
> `nix run nixpkgs#dwarf-fortress`
>
> We don't and can't distribute any of the files from Steam, though
> users who buy the game can link the Steam game data directory into
> their Nix Dwarf Fortress data directory and use the tile packs from
> the Steam version, if they like.
>
> ~
>
> Enough of that formality: thanks for the game, it's a blast and a joy
> for the imagination. I use it to make maps for large scale (50+
> people) D&D campaigns in Southern California.
>
> BTW, automatic world generation mode using the command line seems to
> be broken in v50.12. It navigates to the worldgen menu but doesn't get
> farther. I'm hoping I can release some Nix scripts that people can use
> to export world images and such in batch mode at some point, so I
> don't have to even mess with extracting the game files to get
> interesting map exports.
>
> Thanks,
> Morgan Jones
> ----
> < We are failing in translating hyperreal concepts > -The Board
>

View File

@@ -0,0 +1,243 @@
{
stdenv,
lib,
fetchFromGitHub,
fetchpatch,
cmake,
ninja,
writeScriptBin,
perl,
XMLLibXML,
XMLLibXSLT,
makeWrapper,
zlib,
enableStoneSense ? false,
allegro5,
libGLU,
libGL,
SDL,
SDL2,
coreutils,
util-linux,
ncurses,
strace,
binutils,
gnused,
dfVersion,
dfVersions,
}:
let
inherit (lib)
getAttr
hasAttr
isAttrs
licenses
maintainers
optional
optionals
optionalString
versionOlder
versionAtLeast
;
release =
if isAttrs dfVersion then
dfVersion
else if hasAttr dfVersion dfVersions.game.versions then
(getAttr dfVersion dfVersions.game.versions).hack
else
throw "[DFHack] Unsupported Dwarf Fortress version: ${dfVersion}";
inherit (release) version;
isAtLeast50 = versionAtLeast version "50.0";
needs50Patches = isAtLeast50 && (release.needsPatches or false);
# revision of library/xml submodule
inherit (release) xmlRev;
arch =
if stdenv.hostPlatform.system == "x86_64-linux" then
"64"
else if stdenv.hostPlatform.system == "i686-linux" then
"32"
else
throw "Unsupported architecture";
fakegit = writeScriptBin "git" ''
#! ${stdenv.shell}
if [ "$*" = "describe --tags --long" ]; then
echo "${version}-unknown"
elif [ "$*" = "describe --tags --abbrev=8 --long" ]; then
echo "${version}-unknown"
elif [ "$*" = "describe --tags --abbrev=8 --exact-match" ]; then
echo "${version}"
elif [ "$*" = "rev-parse HEAD" ]; then
if [ "$(dirname "$(pwd)")" = "xml" ]; then
echo "${xmlRev}"
else
echo "refs/tags/${version}"
fi
elif [ "$*" = "rev-parse HEAD:library/xml" ]; then
echo "${xmlRev}"
else
exit 1
fi
'';
in
stdenv.mkDerivation {
pname = "dfhack";
inherit version;
# Beware of submodules
src = fetchFromGitHub {
owner = "DFHack";
repo = "dfhack";
tag = release.git.revision;
hash = release.git.outputHash;
fetchSubmodules = true;
};
patches =
optional (versionOlder version "0.44.12-r3") (fetchpatch {
name = "fix-stonesense.patch";
url = "https://github.com/DFHack/stonesense/commit/f5be6fe5fb192f01ae4551ed9217e97fd7f6a0ae.patch";
extraPrefix = "plugins/stonesense/";
stripLen = 1;
hash = "sha256-wje6Mkct29eyMOcJnbdefwBOLJko/s4JcJe52ojuW+8=";
})
++ optional (versionOlder version "0.47.04-r1") (fetchpatch {
name = "fix-protobuf.patch";
url = "https://github.com/DFHack/dfhack/commit/7bdf958518d2892ee89a7173224a069c4a2190d8.patch";
hash = "sha256-p+mKhmYbnhWKNiGPMjbYO505Gcg634n0nudqH0NX3KY=";
})
++ optional needs50Patches (fetchpatch {
name = "use-system-sdl2.patch";
url = "https://github.com/DFHack/dfhack/commit/734fb730d72e53ebe67f4a041a24dd7c50307ee3.patch";
hash = "sha256-uLX0gdVSzKEVibyUc1UxcQzdYkRm6D8DF+1eSOxM+qU=";
})
++ optional needs50Patches (fetchpatch {
name = "rename-lerp.patch";
url = "https://github.com/DFHack/dfhack/commit/389dcf5cfcdb8bfb8deeb05fa5756c9f4f5709d1.patch";
hash = "sha256-QuDtGURhP+nM+x+8GIKO5LrMcmBkl9JSHHIeqzqGIPQ=";
})
# Newer versions use SDL_GetBasePath and SDL_GetPrefPath with a Windows-esque directory
# that mismatches where we have historically stored data in nixpkgs:
# https://github.com/libsdl-org/SDL/blob/release-2.24.x/src/filesystem/unix/SDL_sysfilesystem.c#L136
# Use SDL_GetPrefPath since this takes XDG_DATA_HOME into account (which is correct).
++ optional (versionAtLeast version "52.02-r2") ./use-df-linux-dir.patch;
# gcc 11 fix
CXXFLAGS = optionalString (versionOlder version "0.47.05-r3") "-fpermissive";
nativeBuildInputs = [
cmake
ninja
perl
XMLLibXML
XMLLibXSLT
makeWrapper
fakegit
];
# We don't use system libraries because dfhack needs old C++ ABI.
buildInputs = [
zlib
]
++ optional isAtLeast50 SDL2
++ optional (!isAtLeast50) SDL
++ optionals enableStoneSense [
allegro5
libGLU
libGL
];
preConfigure = ''
# Trick the build system into believing we have .git.
mkdir -p .git/modules/library/xml
touch .git/index .git/modules/library/xml/index
'';
cmakeFlags = [
# Race condition in `Generating codegen.out.xml and df/headers` that is fixed when using Ninja.
"-GNinja"
"-DDFHACK_BUILD_ARCH=${arch}"
# 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;
};
meta = {
description = "Memory hacking library for Dwarf Fortress and a set of tools that use it";
homepage = "https://github.com/DFHack/dfhack/";
license = licenses.zlib;
platforms = [
"x86_64-linux"
"i686-linux"
];
maintainers = with maintainers; [
robbinch
a1russell
numinit
ncfavier
];
};
}

View File

@@ -0,0 +1,25 @@
diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp
index 7a6b09a50..d5827f016 100644
--- a/library/modules/Filesystem.cpp
+++ b/library/modules/Filesystem.cpp
@@ -232,17 +232,10 @@ std::filesystem::path Filesystem::canonicalize(std::filesystem::path p) noexcept
std::filesystem::path Filesystem::getInstallDir() noexcept
{
- return std::filesystem::path{ DFSDL::DFSDL_GetBasePath() };
+ return std::filesystem::path{ DFSDL::DFSDL_GetPrefPath("", "df_linux") };
}
std::filesystem::path Filesystem::getBaseDir() noexcept
{
- auto getsavebase = []() {
- // assume portable mode is _on_ if init is missing
- if (!df::global::init || df::global::init->media.flag.is_set(df::enums::init_media_flags::PORTABLE_MODE))
- return DFSDL::DFSDL_GetBasePath();
- else
- return DFSDL::DFSDL_GetPrefPath("Bay 12 Games", "Dwarf Fortress");
- };
- return std::filesystem::path{ getsavebase() };
+ return std::filesystem::path{ DFSDL::DFSDL_GetPrefPath("", "df_linux") };
}

View File

@@ -0,0 +1,68 @@
{
lib,
stdenv,
fetchFromGitHub,
qtbase,
qtdeclarative,
cmake,
ninja,
dfVersions,
# see: https://github.com/Dwarf-Therapist/Dwarf-Therapist/releases
version ? dfVersions.therapist.version,
maxDfVersion ? dfVersions.therapist.maxDfVersion,
hash ? dfVersions.therapist.git.outputHash,
}:
stdenv.mkDerivation rec {
pname = "dwarf-therapist";
inherit version;
src = fetchFromGitHub {
owner = "Dwarf-Therapist";
repo = "Dwarf-Therapist";
tag = "v${version}";
inherit hash;
};
nativeBuildInputs = [
cmake
ninja
];
buildInputs = [
qtbase
qtdeclarative
];
enableParallelBuilding = true;
cmakeFlags = [ "-GNinja" ];
installPhase =
if stdenv.hostPlatform.isDarwin then
''
mkdir -p $out/Applications
cp -r DwarfTherapist.app $out/Applications
''
else
null;
dontWrapQtApps = true;
passthru = {
inherit maxDfVersion;
};
meta = with lib; {
mainProgram = "dwarftherapist";
description = "Tool to manage dwarves in a running game of Dwarf Fortress";
maintainers = with maintainers; [
bendlas
numinit
];
license = licenses.mit;
platforms = platforms.x86;
homepage = "https://github.com/Dwarf-Therapist/Dwarf-Therapist";
};
}

View File

@@ -0,0 +1,25 @@
#!@stdenv_shell@ -e
[ -z "$DT_DIR" ] && DT_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/dwarftherapist"
install_dir="@install@"
therapist_dir="@therapist@"
@cat@ <<EOF >&2
Using $DT_DIR as Dwarf Therapist overlay directory.
EOF
update_path() {
local path="$1"
@mkdir@ -p "$DT_DIR/$(@dirname@ "$path")"
if [ ! -e "$DT_DIR/$path" ] || [ -L "$DT_DIR/$path" ]; then
@rm@ -f "$DT_DIR/$path"
@ln@ -s "$install_dir/share/dwarftherapist/$path" "$DT_DIR/$path"
fi
}
cd "$install_dir/share/dwarftherapist"
update_path memory_layouts
exec "$therapist_dir/bin/dwarftherapist" "$@"

View File

@@ -0,0 +1,136 @@
{
lib,
stdenv,
writeText,
dwarf-therapist,
dwarf-fortress,
dfhack,
mkDfWrapper,
replaceVars,
coreutils,
wrapQtAppsHook,
expect,
xvfb-run,
}:
let
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.${toString dwarf-fortress.baseVersion}.${dwarf-fortress.patchVersion}${platformSlug}.ini";
unsupportedVersion = lib.versionOlder dwarf-therapist.maxDfVersion dwarf-fortress.dfVersion;
# Used to run dfhack to produce a Therapist ini file for the current memory map.
# See: http://www.bay12forums.com/smf/index.php?topic=168411.msg8532557#msg8532557
dfHackExpectScript = writeText "dfhack.exp" ''
spawn xvfb-run dfhack +devel/export-dt-ini
expect "DFHack is ready. Have a nice day!"
send "die\r"
'';
dfHackWrapper = mkDfWrapper {
inherit dwarf-fortress dfhack;
enableDFHack = true;
};
in
stdenv.mkDerivation {
pname = "dwarf-therapist";
inherit (dwarf-therapist) version meta maxDfVersion;
inherit (dwarf-fortress) dfVersion;
wrapper = replaceVars ./dwarf-therapist.in {
stdenv_shell = "${stdenv.shell}";
rm = "${coreutils}/bin/rm";
ln = "${coreutils}/bin/ln";
cat = "${coreutils}/bin/cat";
mkdir = "${coreutils}/bin/mkdir";
dirname = "${coreutils}/bin/dirname";
therapist = "${dwarf-therapist}";
# replaced in buildCommand
install = null;
};
paths = [ dwarf-therapist ];
nativeBuildInputs = [
wrapQtAppsHook
]
++ lib.optionals unsupportedVersion [
expect
xvfb-run
dfHackWrapper
];
passthru = { inherit dwarf-fortress dwarf-therapist; };
buildCommand =
lib.optionalString unsupportedVersion ''
fixupMemoryMaps() (
local output="$1"
local orig_md5="$2"
local patched_md5="$3"
echo "It doesn't support DF $dfVersion out of the box, so we're doing it the hard way."
export HOME="$(mktemp -dt dfhack.XXXXXX)"
export XDG_DATA_HOME="$HOME/.local/share"
expect ${dfHackExpectScript}
local ini="$XDG_DATA_HOME/df_linux/therapist.ini"
if [ -f "$ini" ]; then
if grep -q "$patched_md5" "$ini"; then
cp -v "$ini" "$output"
else
echo "Couldn't find MD5 ($patched_md5) in $ini"
exit 1
fi
else
echo "Couldn't find $ini!"
exit 1
fi
)
''
+ lib.optionalString (!unsupportedVersion) ''
fixupMemoryMaps() {
echo "It should support DF $dfVersion, but we couldn't find any memory maps."
echo "This is a nixpkgs bug, please report it!"
exit 1
}
''
+ ''
mkdir -p $out/bin
install -Dm755 $wrapper $out/bin/dwarftherapist
ln -s $out/bin/dwarftherapist $out/bin/DwarfTherapist
substituteInPlace $out/bin/dwarftherapist \
--subst-var-by install $out
wrapQtApp $out/bin/dwarftherapist
# Fix up memory layouts
input_file="${dwarf-therapist}/share/dwarftherapist/memory_layouts/${inifile}"
output_file="$out/share/dwarftherapist/memory_layouts/${inifile}"
rm -f "$output_file"
mkdir -p "$(dirname -- "$output_file")"
orig_md5=$(cat "${dwarf-fortress}/hash.md5.orig" | cut -c1-8)
patched_md5=$(cat "${dwarf-fortress}/hash.md5" | cut -c1-8)
if [ -f "$input_file" ]; then
echo "[Dwarf Therapist Wrapper] Fixing Dwarf Fortress MD5 prefix:"
echo " Input: $input_file"
echo " Search: $orig_md5"
echo " Output: $output_file"
echo " Replace: $patched_md5"
substitute "$input_file" "$output_file" --replace-fail "$orig_md5" "$patched_md5"
else
echo "[Dwarf Therapist Wrapper] OH NO! No memory maps found!"
echo "This version of Therapist ($dfVersion) has max DF version $maxDfVersion."
fixupMemoryMaps "$output_file" "$orig_md5" "$patched_md5"
fi
'';
preferLocalBuild = true;
}

View File

@@ -0,0 +1,203 @@
{
stdenv,
lib,
fetchurl,
SDL,
SDL2,
SDL2_image,
SDL2_mixer,
fmodex,
dwarf-fortress-unfuck,
autoPatchelfHook,
# Our own "unfuck" libs for macOS
ncurses,
gcc,
dfVersion,
dfVersions,
}:
let
inherit (lib)
attrNames
elemAt
getAttr
getLib
hasAttr
licenses
maintainers
optional
optionals
optionalString
splitVersion
toInt
;
# Map Dwarf Fortress platform names to Nixpkgs platform names.
platforms = {
x86_64-linux = "linux";
x86_64-darwin = "darwin";
};
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);
isAtLeast50 = baseVersion >= 50;
enableUnfuck =
!isAtLeast50
&& dwarf-fortress-unfuck != null
&& (dwarf-fortress-unfuck.dfVersion or null) == dfVersion;
game =
if hasAttr dfVersion dfVersions.game.versions then
(getAttr dfVersion dfVersions.game.versions).df
else
throw "Unknown Dwarf Fortress version: ${dfVersion}";
dfPlatform =
if hasAttr stdenv.hostPlatform.system platforms then
getAttr stdenv.hostPlatform.system platforms
else
throw "Unsupported system: ${stdenv.hostPlatform.system}";
url =
if hasAttr dfPlatform game.urls then
getAttr dfPlatform game.urls
else
throw "Unsupported dfPlatform: ${dfPlatform}";
exe =
if stdenv.hostPlatform.isLinux then
if baseVersion >= 50 then "dwarfort" else "libs/Dwarf_Fortress"
else
"dwarfort.exe";
in
stdenv.mkDerivation {
pname = "dwarf-fortress";
version = dfVersion;
src = fetchurl {
inherit (url) url;
hash = url.outputHash;
};
sourceRoot = ".";
postUnpack = ''
directory=${
if stdenv.hostPlatform.isLinux then
"df_linux"
else if stdenv.hostPlatform.isDarwin then
"df_osx"
else
throw "Unsupported system"
}
if [ -d "$directory" ]; then
mv "$directory/"* .
fi
'';
nativeBuildInputs = optional stdenv.hostPlatform.isLinux autoPatchelfHook;
buildInputs =
optionals isAtLeast50 [
SDL2
SDL2_image
SDL2_mixer
]
++ optional (!isAtLeast50) SDL
++ optional enableUnfuck dwarf-fortress-unfuck
++ [ (lib.getLib stdenv.cc.cc) ];
installPhase = ''
runHook preInstall
exe=$out/${exe}
mkdir -p $out
cp -r * $out
# Clean up OS X detritus in the tarball.
find $out -type f -name '._*' -exec rm -rf {} \;
# 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
# We don't need any of these since they will just break autoPatchelf on <version 50.
[ -d $out/libs ] && rm -rf $out/libs/*.so $out/libs/*.so.* $out/libs/*.dylib
# Store the original hash
md5sum $exe | awk '{ print $1 }' > $out/hash.md5.orig
echo "Original MD5: $(<$out/hash.md5.orig)" >&2
''
+ optionalString stdenv.hostPlatform.isDarwin ''
# My custom unfucked dwarfort.exe for macOS. Can't use
# absolute paths because original doesn't have enough
# header space. Someone plz break into Tarn's house & put
# -headerpad_max_install_names into his LDFLAGS.
ln -s ${getLib ncurses}/lib/libncurses.dylib $out/libs
ln -s ${getLib gcc.cc}/lib/libstdc++.6.dylib $out/libs
ln -s ${getLib gcc.cc}/lib/libgcc_s.1.dylib $out/libs
ln -s ${getLib fmodex}/lib/libfmodex.dylib $out/libs
install_name_tool \
-change /usr/lib/libncurses.5.4.dylib \
@executable_path/libs/libncurses.dylib \
-change /usr/local/lib/x86_64/libstdc++.6.dylib \
@executable_path/libs/libstdc++.6.dylib \
$exe
''
+ ''
runHook postInstall
'';
preFixup = ''
recompute_hash() {
# 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
}
# Ensure that this runs after autoPatchelfHook.
trap recompute_hash EXIT
'';
passthru = {
inherit
baseVersion
patchVersion
dfVersion
exe
;
updateScript = {
command = [ ./update.rb ];
attrPath = "dwarf-fortress-packages";
supportedFeatures = [ "commit" ];
};
};
meta = {
description = "Single-player fantasy game with a randomly generated adventure world";
homepage = "https://www.bay12games.com/dwarves/";
license = licenses.unfreeRedistributable;
platforms = attrNames platforms;
maintainers = with maintainers; [
a1russell
robbinch
roconnor
numinit
shazow
ncfavier
];
sourceProvenance = [ lib.sourceTypes.binaryNativeCode ];
};
}

View File

@@ -0,0 +1,81 @@
{
stdenvNoCC,
lib,
buildEnv,
df-games,
themes,
latestVersion,
versionToName,
dfVersion ? latestVersion,
# This package should, at any given time, provide an opinionated "optimal"
# DF experience. It's the equivalent of the Lazy Newbie Pack, that is, and
# should contain every utility available unless you disable them.
enableDFHack ? stdenvNoCC.hostPlatform.isLinux,
enableTWBT ? enableDFHack,
enableSoundSense ? true,
enableStoneSense ? true,
enableDwarfTherapist ? true,
enableLegendsBrowser ? true,
legends-browser,
theme ? themes.phoebus,
# General config options:
enableIntro ? true,
enableTruetype ? null, # defaults to 24, see init.txt
enableFPS ? false,
enableTextMode ? false,
enableSound ? true,
}:
let
inherit (lib)
getAttr
hasAttr
licenses
maintainers
optional
platforms
;
dfGame = versionToName dfVersion;
dwarf-fortress =
if hasAttr dfGame df-games 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";
paths = [
(dwarf-fortress.override {
inherit
enableDFHack
enableTWBT
enableSoundSense
enableStoneSense
theme
enableIntro
enableTruetype
enableFPS
enableTextMode
enableSound
;
})
]
++ optional enableDwarfTherapist dwarf-therapist
++ optional enableLegendsBrowser legends-browser;
meta = {
inherit mainProgram;
description = "Opinionated wrapper for Dwarf Fortress";
maintainers = with maintainers; [
Baughn
numinit
];
license = licenses.mit;
platforms = platforms.all;
homepage = "https://github.com/NixOS/nixpkgs/";
};
}

View File

@@ -0,0 +1,46 @@
{
lib,
buildEnv,
writeShellScriptBin,
fetchurl,
jre,
}:
let
name = "legends-browser-${version}";
version = "1.19.2";
jar = fetchurl {
url = "https://github.com/robertjanetzko/LegendsBrowser/releases/download/${version}/legendsbrowser-${version}.jar";
hash = "sha256-jkv7InwaRn0K3VAa0LqkYpH6TnrT/tGYBtbvNGM6t98=";
};
script = writeShellScriptBin "legends-browser" ''
set -eu
BASE="$HOME/.local/share/df_linux/legends-browser/"
mkdir -p "$BASE"
cd "$BASE"
if [[ ! -e legendsbrowser.properties ]]; then
echo 'Creating initial configuration for legends-browser'
echo "last=$(cd ..; pwd)" > legendsbrowser.properties
fi
exec ${jre}/bin/java -jar ${jar}
'';
in
buildEnv {
inherit name;
paths = [ script ];
meta = with lib; {
description = "Multi-platform, open source, java-based legends viewer for dwarf fortress";
maintainers = with maintainers; [
Baughn
numinit
];
sourceProvenance = with sourceTypes; [ binaryBytecode ];
license = licenses.mit;
platforms = platforms.all;
homepage = "https://github.com/robertjanetzko/LegendsBrowser";
};
}

View File

@@ -0,0 +1,49 @@
{
lib,
stdenv,
fetchzip,
dos2unix,
soundPack ? stdenv.mkDerivation {
name = "soundsense-soundpack";
src = fetchzip {
url = "https://df.zweistein.cz/soundsense/soundpack.zip";
hash = "sha256-yjlhBLYYv/FXsk5IpiZNDG2ugDldaD5mf+Dyc6es4GM=";
};
installPhase = ''
cp -r . $out
'';
},
}:
stdenv.mkDerivation rec {
version = "2016-1_196";
dfVersion = "0.44.12";
inherit soundPack;
pname = "soundsense";
src = fetchzip {
url = "https://df.zweistein.cz/soundsense/soundSense_${version}.zip";
hash = "sha256-c+LOUxmJaZ3VqVOBYSQypiZxWyNAXOlRQVD3QZPReb4=";
};
nativeBuildInputs = [ dos2unix ];
buildPhase = ''
dos2unix soundSense.sh
chmod +x soundSense.sh
'';
installPhase = ''
mkdir $out
cp -R . $out/soundsense
ln -s $out/soundsense/dfhack $out/hack
ln -s $soundPack $out/soundsense/packs
'';
passthru = { inherit version dfVersion; };
meta = {
description = "Plays sound based on Dwarf Fortress game logs";
maintainers = with lib.maintainers; [
numinit
];
sourceProvenance = with lib.sourceTypes; [ binaryBytecode ];
license = lib.licenses.gpl3Only;
platforms = lib.platforms.all;
homepage = "https://df.zweistein.cz/soundsense";
};
}

View File

@@ -0,0 +1,32 @@
{ lib, fetchFromGitHub, ... }:
let
inherit (lib)
importJSON
licenses
listToAttrs
maintainers
platforms
;
in
listToAttrs (
map (v: {
inherit (v) name;
value = fetchFromGitHub {
name = "${v.name}-theme-${v.version}";
owner = "DFgraphics";
repo = v.name;
rev = v.version;
sha256 = v.sha256;
meta = {
platforms = platforms.all;
maintainers = [
maintainers.matthewbauer
maintainers.shazow
];
license = licenses.unfree;
};
};
}) (importJSON ./themes.json)
)

View File

@@ -0,0 +1,87 @@
[
{
"name": "afro-graphics",
"version": "47.05",
"sha256": "0gqrxb4bbx1h93xjz4ygd7yp8g5barj2zc6y7xvr94ww8b9a2r28"
},
{
"name": "autoreiv",
"version": "47.01",
"sha256": "1c2xchlfq7ajpcq8qgrzkw5yfgm0k3fiwq6n7l4724dlbim3rjp2"
},
{
"name": "cla",
"version": "0.47.xx-v26.3",
"sha256": "0ca81r3821jja4pqib75qxcsgg3s0wxzyq1jb4jc0495cvzxw7qa"
},
{
"name": "dfgraphics",
"version": "42.05",
"sha256": "18xyqn458hh8l2qgbvrvz17nbp6yk91d7rqlxlp1g5wr9qfq28rp"
},
{
"name": "gemset",
"version": "47.05",
"sha256": "1ivsbj71w3zwxnaz0405xhqhn4yzdfziijc0s0vmbmcphhhqnjaj"
},
{
"name": "ironhand",
"version": "47.05",
"sha256": "003yrwishkzf6nvr6xlldbnd3x7rf5ds7l91mc0npdq1lcl0br9w"
},
{
"name": "jolly-bastion",
"version": "47.04",
"sha256": "0799ad90g62nvpdcl6zq3vr2nvfc62lprm4br9n2hbs8wgrra6rq"
},
{
"name": "mayday",
"version": "47.05",
"sha256": "17sdvr9a98xx5r2nrr3m4jlddvlb4h6qlch8r23g9g4mj0hsifnj"
},
{
"name": "meph",
"version": "47.05_v5.5.1-V",
"sha256": "1kiqxiqw686dii5x7zav2nsw15csg0grv4h8hrb764rl4fw6x9nl"
},
{
"name": "obsidian",
"version": "47.05",
"sha256": "1dkwdwm52fsj4gqqqr5vppbsk8a4kd3i7d3qawawgl0qn6q139xs"
},
{
"name": "phoebus",
"version": "47.05",
"sha256": "18pn3dqyk9hp82gva92c6y3vk52s366rrx74rdnvahswdr5dmq4d"
},
{
"name": "rally-ho",
"version": "47.05",
"sha256": "1h3jqq0yq2rbzbl70sq85lgdpwswczpay16kqfwq1n8zdisl4gqn"
},
{
"name": "spacefox",
"version": "47.05a",
"sha256": "1y1rbsxr1m0mb2k02q6gh24c4nyqc9lw98dvfckp2bzc5f9cx3ks"
},
{
"name": "taffer",
"version": "47.04",
"sha256": "1ly2sc0pb2kybb8grj19zx372whblmd0bj8p64akpi2rrywi13sy"
},
{
"name": "tergel",
"version": "47.01",
"sha256": "142sd1i11vvirn68rp4gqzl67ww597df1lc57ycnpnz0n3q39kxy"
},
{
"name": "vettlingr",
"version": "47.05",
"sha256": "0s1vy3ssp1hk8f6wlkz09xy5v747dpbsgw5vi6i1mq3lnlcy68vq"
},
{
"name": "wanderlust",
"version": "47.04",
"sha256": "1z56m8zplq5d18sbkwg5lwcy8iwfa5hbxixsm3hdxm04qyld1z89"
}
]

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p jq nix coreutils curl nix-prefetch-git
curl "https://api.github.com/users/dfgraphics/repos" | jq -r '.[].name | ascii_downcase' | while read repo; do
version="$(curl "https://api.github.com/repos/DFgraphics/${repo}/releases/latest" | jq -r .tag_name)"
sha256="$(nix-prefetch-git "https://github.com/DFgraphics/${repo}" "${version}" | jq -r ".sha256")"
echo "{}" | jq ".name=\"${repo}\" | .version=\"${version}\" | .sha256=\"${sha256}\""
done | jq -s . > themes.json

View File

@@ -0,0 +1,83 @@
{
stdenvNoCC,
lib,
fetchurl,
unzip,
dfVersion,
}:
let
inherit (lib)
getAttr
hasAttr
licenses
maintainers
platforms
;
twbt-releases = {
"0.44.12" = {
twbtRelease = "6.54";
hash = "sha256-cKomZmTLHab9K8k0pZsB2uMf3D5/SVhy2GRusLdp7oE=";
prerelease = false;
};
"0.47.05" = {
twbtRelease = "6.xx";
dfhackRelease = "0.47.05-r8";
hash = "sha256-qiNs6iMAUNGiq0kpXqEs4u4Wcrjf6/qA/dzBe947Trc=";
prerelease = false;
};
};
release =
if hasAttr dfVersion twbt-releases then
getAttr dfVersion twbt-releases
else
throw "[TWBT] Unsupported Dwarf Fortress version: ${dfVersion}";
in
stdenvNoCC.mkDerivation rec {
pname = "twbt";
version = release.twbtRelease;
src = fetchurl {
url =
if version == "6.xx" then
"https://github.com/thurin/df-twbt/releases/download/${release.dfhackRelease}/twbt-${version}-linux64-${release.dfhackRelease}.zip"
else
"https://github.com/mifki/df-twbt/releases/download/v${version}/twbt-${version}-linux.zip";
inherit (release) hash;
};
sourceRoot = ".";
outputs = [
"lib"
"art"
"out"
];
nativeBuildInputs = [ unzip ];
installPhase = ''
mkdir -p $lib/hack/{plugins,lua} $art/data/art
cp -a */twbt.plug.so $lib/hack/plugins/
cp -a *.lua $lib/hack/lua/
cp -a *.png $art/data/art/
'';
passthru = {
inherit dfVersion;
};
meta = {
description = "Plugin for Dwarf Fortress / DFHack that improves various aspects of the game interface";
maintainers = with maintainers; [
Baughn
numinit
];
license = licenses.mit;
platforms = platforms.linux;
homepage = "https://github.com/mifki/df-twbt";
};
}

View File

@@ -0,0 +1,130 @@
{
stdenv,
lib,
fetchFromGitHub,
fetchpatch,
cmake,
libGL,
libSM,
SDL,
SDL_image,
SDL_ttf,
glew,
openalSoft,
ncurses,
glib,
gtk2,
gtk3,
libsndfile,
zlib,
dfVersion,
pkg-config,
}:
let
inherit (lib)
getAttr
hasAttr
licenses
maintainers
platforms
versionOlder
;
unfuck-releases = {
"0.44.12" = {
unfuckRelease = "0.44.12";
hash = "sha256-f9vDe3Q3Vl2hFLCPSzYtqyv9rLKBKEnARZTu0MKaX88=";
};
"0.47.05" = {
unfuckRelease = "0.47.05-final";
hash = "sha256-kBdzU6KDpODOBP9XHM7lQRIEWUGOj838vXF1FbSr0Xw=";
};
};
release =
if hasAttr dfVersion unfuck-releases then
getAttr dfVersion unfuck-releases
else
throw "[unfuck] Unknown Dwarf Fortress version: ${dfVersion}";
in
stdenv.mkDerivation {
pname = "dwarf_fortress_unfuck";
version = release.unfuckRelease;
src = fetchFromGitHub {
owner = "svenstaro";
repo = "dwarf_fortress_unfuck";
rev = release.unfuckRelease;
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
'';
cmakeFlags = [
"-DGTK2_GLIBCONFIG_INCLUDE_DIR=${glib.out}/lib/glib-2.0/include"
"-DGTK2_GDKCONFIG_INCLUDE_DIR=${gtk2.out}/lib/gtk-2.0/include"
];
nativeBuildInputs = [
cmake
pkg-config
];
buildInputs = [
libSM
SDL
SDL_image
SDL_ttf
glew
openalSoft
ncurses
libsndfile
zlib
libGL
]
# switched to gtk3 in 0.47.05
++ (
if versionOlder release.unfuckRelease "0.47.05" then
[
gtk2
]
else
[
gtk3
]
);
# Don't strip unused symbols; dfhack hooks into some of them.
dontStrip = true;
installPhase = ''
install -D -m755 ../build/libgraphics.so $out/lib/libgraphics.so
'';
# Breaks dfhack because of inlining.
hardeningDisable = [ "fortify" ];
passthru = { inherit dfVersion; };
meta = {
description = "Unfucked multimedia layer for Dwarf Fortress";
homepage = "https://github.com/svenstaro/dwarf_fortress_unfuck";
license = licenses.free;
platforms = platforms.linux;
maintainers = with maintainers; [
numinit
];
};
}

View File

@@ -0,0 +1,642 @@
#!/usr/bin/env nix-shell
#!nix-shell -i ruby -p "ruby.withPackages (ps: with ps; [ curb nokogiri ])" nix-prefetch-git
require 'set'
require 'json'
require 'uri'
require 'shellwords'
require 'erb'
require 'rubygems'
require 'curb'
require 'nokogiri'
# Performs a GET to an arbitrary address.
# +url+:: the URL
def get url, &block
curl = Curl::Easy.new(url) do |http|
http.follow_location = false
http.headers['User-Agent'] = 'nixpkgs dwarf fortress update bot'
yield http if block_given?
end
curl.perform
curl.body_str
end
# Performs a GET on the Github API.
# +url+:: the relative URL to api.github.com
def get_gh url, &block
ret = get URI.join('https://api.github.com/', url) do |http|
http.headers['Accept'] = 'application/vnd.github+json'
http.headers['Authorization'] = "Bearer #{ENV['GH_TOKEN']}" if ENV.include?('GH_TOKEN')
http.headers['X-GitHub-Api-Version'] = '2022-11-28'
yield http if block_given?
end
JSON.parse(ret, symbolize_names: true)
end
def normalize_keys hash
Hash[hash.map {
[
_1.to_s,
_2.is_a?(Hash) ? normalize_keys(_2) : _2
]
}]
end
module Mergeable
# Merges this Mergeable with something else.
# +other+:: The other Mergeable.
def merge other
if !other
return self
end
if !other.is_a?(Mergeable) || self.members != other.members
raise "invalid right-hand operand for merge: #{other.members}"
end
hash = {}
self.members.each do |member|
if @@expensive && @@expensive.include?(member)
# Already computed
hash[member] = other[member] || self.send(member)
elsif self.send(member) && self.send(member).is_a?(Mergeable)
# Merge it
hash[member] = self.send(member).merge(other.send(member))
elsif self.send(member) && self.send(member).is_a?(Hash)
hash[member] = Hash[other.send(member).map {
[_1, self.send(member)[_1] && self.send(member)[_1].is_a?(Mergeable) ? self.send(member)[_1].merge(_2) : _2]
}]
else
# Compute it
hash[member] = other.send(member)
end
end
self.class.new(**hash)
end
# Marks some attributes as expensive.
def expensive *attrs
@@expensive ||= Set.new
attrs.each {@@expensive << _1}
self
end
# Materializes this object.
def materialize!
self.members.each do |name|
member = self.send(name)
if member.respond_to?(:materialize!)
member.materialize!
end
self[name] = member
end
self
end
end
module Versionable
# Parses the version.
def parsed_version
@version ||= Gem::Version.create(self.version.partition('-').first)
end
# Drops the last component of the version for chunking.
def major_version
@major_version ||= Gem::Version.create(self.parsed_version.canonical_segments[..-2].join('.'))
end
# Compares the major version.
def =~ other
self.major_version == other.major_version
end
# Negation of the above.
def !~ other
!(self =~ other)
end
# Compares two versions.
def <=> other
other.parsed_version <=> self.parsed_version
end
end
class DFUrl < Struct.new(:url, :output_hash, keyword_init: true)
include Mergeable
extend Mergeable
expensive :output_hash
# Converts this DFUrl to a hash.
def to_h
{
url: self.url,
outputHash: self.output_hash
}
end
# Returns or computes the output hash.
def output_hash
return super if super
self.output_hash = `nix-prefetch-url #{Shellwords.escape(self.url.to_s)} | xargs nix-hash --to-sri --type sha256`.strip
super
end
# Converts this DFUrl from a hash.
# +hash+:: The hash
def self.from_hash hash
DFUrl.new(
url: hash.fetch(:url),
output_hash: hash[:outputHash]
)
end
end
class DFGithub < Struct.new(:url, :revision, :output_hash, keyword_init: true)
include Mergeable
extend Mergeable
expensive :output_hash
# Converts this DFGithub to a hash.
def to_h
{
url: self.url,
revision: self.revision,
outputHash: self.output_hash
}
end
# Returns or computes the output hash.
def output_hash
return super if super
url = URI.parse(self.url.to_s)
if ENV['GH_TOKEN']
url.userinfo = ENV['GH_TOKEN']
end
self.output_hash = JSON.parse(`nix-prefetch-git --no-deepClone --fetch-submodules #{Shellwords.escape(url.to_s)} #{Shellwords.escape(self.revision.to_s)}`, symbolize_names: true).fetch(:hash)
super
end
# Converts a hash to a DFGithub.
# +hash+:: The hash
def self.from_hash hash
DFGithub.new(
url: hash.fetch(:url),
revision: hash.fetch(:revision),
output_hash: hash[:outputHash]
)
end
end
class DFVersion < Struct.new(:version, :urls, keyword_init: true)
include Mergeable
extend Mergeable
include Versionable
# Converts a DFVersion to a hash.
def to_h
{
version: self.version,
urls: Hash[self.urls.map {
[_1, _2.to_h]
}]
}
end
# Converts a hash to a DFVersion.
# +hash+:: The hash
def self.from_hash hash
DFVersion.new(
version: hash.fetch(:version),
urls: Hash[hash.fetch(:urls).map {
[_1, DFUrl.from_hash(_2)]
}]
)
end
# Converts an HTML node to a DFVersion.
# +base+:: The base URL for DF downloads.
# +node+:: The HTML node
def self.from_node base, node
match = node.text.match(/DF\s+(\d+\.\d+(?:\.\d+)?)/)
if match
systems = {}
node.css('a').each do |a|
case a['href']
when /osx\.tar/ then systems[:darwin] = DFUrl.new(url: URI.join(base, a['href']).to_s)
when /linux\.tar/ then systems[:linux] = DFUrl.new(url: URI.join(base, a['href']).to_s)
end
end
if systems.empty?
nil
else
DFVersion.new(version: match[1], urls: systems)
end
else
nil
end
end
# Returns all DFVersions from the download page.
# +cutoff+:: The minimum version
def self.all cutoff:
cutoff = Gem::Version.create(cutoff)
base = 'https://www.bay12games.com/dwarves/'
res = get URI.join(base, 'older_versions.html')
parsed = Nokogiri::HTML(res)
# Figure out which versions we care about.
parsed.css('p.menu').map {DFVersion.from_node(base, _1)}.select {
_1 && _1.parsed_version >= cutoff
}.sort.chunk {
_1.major_version
}.map {|*, versions|
versions.max_by {_1.parsed_version}
}.to_a
end
end
class DFHackVersion < Struct.new(:version, :git, :xml_rev, keyword_init: true)
include Mergeable
extend Mergeable
include Versionable
expensive :xml_rev
# Returns the download URL.
def git
return super if super
self.git = DFGithub.new(
url: "https://github.com/DFHack/dfhack.git",
revision: self.version
)
super
end
# Converts this DFHackVersion to a hash.
def to_h
{
version: self.version,
git: self.git.to_h,
xmlRev: self.xml_rev,
}
end
# Returns the revision number in the version. Defaults to 0.
def rev
return @rev if @rev
rev = self.version.match(/-r([\d\.]+)\z/)
@rev = rev[1].to_f if rev
@rev ||= 0
@rev
end
# Returns the XML revision, fetching it if necessary.
def xml_rev
return super if super
url = "repos/dfhack/dfhack/contents/library/xml?ref=#{URI.encode_uri_component(self.git.revision)}"
body = get_gh url
self.xml_rev = body.fetch(:sha)
super
end
# Compares two DFHack versions.
# +other+:: the other dfhack version
def <=> other
ret = super
ret = other.rev <=> self.rev if ret == 0
ret
end
# Returns a version from a hash.
# +hash+:: the hash
def self.from_hash hash
DFHackVersion.new(
version: hash.fetch(:version),
git: DFGithub.from_hash(hash.fetch(:git)),
xml_rev: hash[:xmlRev]
)
end
# Returns a release from a github object.
# +github_obj+:: The github object. Returns null for prereleases.
def self.from_github github_obj
if github_obj.fetch(:prerelease)
return nil
end
version = github_obj.fetch(:tag_name)
DFHackVersion.new(version: version)
end
# Returns all dfhack versions.
# +cutoff+:: The cutoff version.
def self.all cutoff:
cutoff = Gem::Version.create(cutoff)
ret = {}
(1..).each do |page|
url = "repos/dfhack/dfhack/releases?per_page=100&page=#{page}"
releases = get_gh url
releases.each do |release|
release = DFHackVersion.from_github(release)
if release && release.parsed_version >= cutoff
ret[release.major_version] ||= {}
ret[release.major_version][release.parsed_version] ||= []
ret[release.major_version][release.parsed_version] << release
end
end
break if releases.length < 1
end
ret.each do |_, dfhack_major_versions|
dfhack_major_versions.each do |_, dfhack_minor_versions|
dfhack_minor_versions.sort!
end
end
ret
end
end
class DFWithHackVersion < Struct.new(:df, :hack, keyword_init: true)
include Mergeable
extend Mergeable
# Converts this DFWithHackVersion to a hash.
def to_h
{
df: self.df.to_h,
hack: self.hack.to_h
}
end
# Converts a hash to a DFWithHackVersion.
# +hash+:: the hash to convert
def self.from_hash hash
DFWithHackVersion.new(
df: DFVersion.from_hash(hash.fetch(:df)),
hack: DFHackVersion.from_hash(hash.fetch(:hack))
)
end
end
class DFWithHackVersions < Struct.new(:latest, :versions, keyword_init: true)
include Mergeable
extend Mergeable
# Initializes this DFWithHackVersions.
def initialize *args, **kw
super *args, **kw
self.latest ||= {}
self.versions ||= {}
end
# Converts this DFWithHackVersions to a hash.
def to_h
{
latest: self.latest,
versions: Hash[self.versions.map {
[_1.to_s, _2.to_h]
}]
}
end
# Loads this DFWithHackVersions.
# +cutoff+:: The minimum version to load.
def load! cutoff:
df_versions = DFVersion.all(cutoff: cutoff)
dfhack_versions = DFHackVersion.all(cutoff: cutoff)
df_versions.each do |df_version|
latest_dfhack_version = nil
corresponding_dfhack_versions = dfhack_versions.dig(df_version.major_version, df_version.parsed_version)
if corresponding_dfhack_versions
latest_dfhack_version = corresponding_dfhack_versions.first
end
if latest_dfhack_version
df_version.urls.each do |platform, url|
if !self.latest[platform] || df_version.parsed_version > Gem::Version.create(self.latest[platform])
self.latest[platform] = df_version.version
end
end
self.versions[df_version.version] = DFWithHackVersion.new(df: df_version, hack: latest_dfhack_version)
end
end
self.materialize!
self
end
# Converts a hash to a DFWithHackVersions.
# +hash+:: The hash
def self.from_hash hash
DFWithHackVersions.new(
latest: hash.fetch(:latest),
versions: Hash[hash.fetch(:versions).map {
[_1.to_s, DFWithHackVersion.from_hash(_2)]
}]
)
end
end
class Therapist < Struct.new(:version, :max_df_version, :git, keyword_init: true)
include Mergeable
extend Mergeable
include Versionable
expensive :max_df_version
# Converts this Therapist instance to a hash.
def to_h
{
version: self.version,
maxDfVersion: self.max_df_version,
git: self.git.to_h
}
end
# Returns the max supported DF version.
def max_df_version
return super if super
url = "repos/Dwarf-Therapist/Dwarf-Therapist/contents/share/memory_layouts/linux?ref=#{URI.encode_uri_component(self.git.revision)}"
body = get_gh url
# Figure out the max supported memory layout.
max_version = nil
max_version_str = nil
body.each do |item|
name = item[:name] || ""
match = name.match(/\Av(?:0\.)?(\d+\.\d+)-classic_linux\d*\.ini/)
if match
version = Gem::Version.create(match[1])
if !max_version || version > max_version
max_version = version
max_version_str = match[1]
end
end
end
self.max_df_version = max_version_str
super
end
# Returns a Github URL.
def git
return super if super
self.git = DFGithub.new(
url: "https://github.com/Dwarf-Therapist/Dwarf-Therapist.git",
revision: 'v' + self.version
)
super
end
# Loads this therapist instance from Github.
def load!
latest = self.class.latest
self.version = latest.version
self.max_df_version = latest.max_df_version
self.git = latest.git
self.materialize!
self
end
# Loads a hash into this Therapist instance.
# +hash+: the hash
def self.from_hash hash
Therapist.new(
version: hash.fetch(:version),
max_df_version: hash[:maxDfVersion],
git: DFGithub.from_hash(hash.fetch(:git))
)
end
# Returns a release from a github object.
# +github_obj+:: The github object. Returns null for prereleases.
def self.from_github github_obj
if github_obj.fetch(:prerelease)
return nil
end
version = github_obj.fetch(:tag_name)
match = version.match(/\Av([\d\.]+)\z/)
if match
Therapist.new(version: match[1])
else
nil
end
end
# Returns the latest Therapist version.
def self.latest
url = "repos/Dwarf-Therapist/Dwarf-Therapist/releases"
releases = get_gh url
releases.each do |release|
release = Therapist.from_github(release)
if release
return release
end
end
nil
end
end
class DFLock < Struct.new(:game, :therapist, keyword_init: true)
include Mergeable
extend Mergeable
# Initializes this DFLock.
def initialize *args, **kw
super *args, **kw
self.game ||= DFWithHackVersions.new
self.therapist ||= Therapist.new
end
# Converts this DFLock to a hash.
def to_h
{
game: self.game.to_h,
therapist: self.therapist.to_h
}
end
# Returns an array containing all versions.
def all_versions
[self.game.versions.keys.lazy.map {"DF #{_1}"}.first] + ["DT #{self.therapist.version}"]
end
# Loads this DFLock.
# +cutoff+:: The minimum DF version to load.
def load! cutoff:
self.game.load! cutoff: cutoff
self.therapist.load!
end
# Converts a hash to a DFLock.
# +hash+:: The hash
def self.from_hash hash
DFLock.new(
game: DFWithHackVersions.from_hash(hash.fetch(:game)),
therapist: Therapist.from_hash(hash.fetch(:therapist))
)
end
end
# 0.43 and below has a broken dfhack.
new_df_lock = DFLock.new
new_df_lock.load! cutoff: '0.44'
df_lock_file = File.join(__dir__, 'df.lock.json')
df_lock, df_lock_json = if File.file?(df_lock_file)
json = JSON.parse(File.read(df_lock_file), symbolize_names: true)
[DFLock.from_hash(json), json]
else
[DFLock.new, {}]
end
new_df_lock_json = df_lock.merge(new_df_lock).to_h
json = JSON.pretty_generate(new_df_lock_json)
json << "\n"
STDERR.puts json
File.write(df_lock_file, json)
# See if there were any changes.
changed_paths = []
if normalize_keys(df_lock_json) != normalize_keys(new_df_lock_json)
all_old_versions = df_lock.all_versions
all_new_versions = new_df_lock.all_versions
just_old_versions = all_old_versions - all_new_versions
just_new_versions = all_new_versions - all_old_versions
changes = just_old_versions.zip(just_new_versions)
template = ERB.new(<<-EOF, trim_mode: '<>-')
dwarf-fortress-packages: <%= changes.map {|old, new| '%s -> %s' % [old, new]}.join('; ') %>
Performed the following automatic DF updates:
<% changes.each do |old, new| %>
- <%= old -%> -> <%= new -%>
<% end %>
EOF
changed_paths << {
attrPath: 'dwarf-fortress-packages',
oldVersion: just_old_versions.join('; '),
newVersion: just_new_versions.join('; '),
files: [
File.realpath(df_lock_file)
],
commitMessage: template.result(binding)
}
end
STDOUT.puts JSON.pretty_generate(changed_paths)

View File

@@ -0,0 +1,305 @@
{
stdenv,
lib,
buildEnv,
replaceVars,
makeWrapper,
runCommand,
coreutils,
gawk,
dwarf-fortress,
dwarf-therapist,
SDL2_mixer,
enableDFHack ? false,
dfhack,
enableSoundSense ? false,
soundSense,
jre,
expect,
xvfb-run,
writeText,
enableStoneSense ? false,
enableTWBT ? false,
twbt,
themes ? { },
theme ? null,
extraPackages ? [ ],
# General config options:
enableIntro ? true,
enableTruetype ? null, # defaults to 24, see init.txt
enableFPS ? false,
enableTextMode ? false,
enableSound ? true,
# An attribute set of settings to override in data/init/*.txt.
# For example, `init.FOO = true;` is translated to `[FOO:YES]` in init.txt
settings ? { },
# TODO world-gen.txt, interface.txt require special logic
}:
let
dfhack' = dfhack.override {
inherit enableStoneSense;
};
isAtLeast50 = dwarf-fortress.baseVersion >= 50;
# If TWBT is null or the dfVersion is wrong, it isn't supported (for example, on version 50).
enableTWBT' = enableTWBT && twbt != null && (twbt.dfVersion or null) == dwarf-fortress.version;
ptheme = if builtins.isString theme then builtins.getAttr theme themes else theme;
baseEnv = buildEnv {
name = "dwarf-fortress-base-env-${dwarf-fortress.dfVersion}";
# 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 enableSoundSense soundSense
++ lib.optionals enableTWBT' [
twbt.lib
twbt.art
]
++ [ dwarf-fortress ];
ignoreCollisions = true;
};
settings' = lib.recursiveUpdate {
init = {
PRINT_MODE =
if enableTextMode then
"TEXT"
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;
TRUETYPE = enableTruetype;
FPS = enableFPS;
SOUND = enableSound;
};
} settings;
forEach = attrs: f: lib.concatStrings (lib.mapAttrsToList f attrs);
toTxt =
v:
if lib.isBool v then
if v then "YES" else "NO"
else if lib.isInt v then
toString v
else if lib.isString v then
v
else
throw "dwarf-fortress: unsupported configuration value ${toString v}";
config =
runCommand "dwarf-fortress-config"
{
nativeBuildInputs = [
gawk
makeWrapper
];
}
(
''
mkdir -p $out/data/init
edit_setting() {
v=''${v//'&'/'\&'}
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:
''
file=data/init/${lib.escapeShellArg file}.txt
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
''
)
)
+ lib.optionalString enableDFHack ''
mkdir -p $out/hack
# Patch the MD5
orig_md5=$(< "${dwarf-fortress}/hash.md5.orig")
patched_md5=$(< "${dwarf-fortress}/hash.md5")
input_file="${dfhack'}/hack/symbols.xml"
output_file="$out/hack/symbols.xml"
echo "[DFHack Wrapper] Fixing Dwarf Fortress MD5:"
echo " Input: $input_file"
echo " Search: $orig_md5"
echo " Output: $output_file"
echo " Replace: $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
# from any of the paths in baseEnv.
env = buildEnv {
name = "dwarf-fortress-env-${dwarf-fortress.dfVersion}";
paths = [
config
baseEnv
];
ignoreCollisions = true;
};
in
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"
stdenv.mkDerivation
{
pname = "dwarf-fortress";
version = dwarf-fortress.dfVersion;
dfInit = replaceVars ./dwarf-fortress-init.in {
inherit env;
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";
SDL2_mixer = "${SDL2_mixer}/lib/libSDL2_mixer.so";
};
runDF = ./dwarf-fortress.in;
runSoundSense = ./soundSense.in;
passthru = {
inherit
dwarf-fortress
dwarf-therapist
twbt
env
;
dfhack = dfhack';
};
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 $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 ''
substitute $runSoundSense $out/bin/soundsense \
--subst-var-by stdenv_shell ${stdenv.shell} \
--subst-var-by jre ${jre} \
--subst-var dfInit
chmod 755 $out/bin/soundsense
'';
doInstallCheck = stdenv.hostPlatform.isLinux;
nativeInstallCheckInputs = lib.optionals stdenv.hostPlatform.isLinux [
expect
xvfb-run
];
installCheckPhase =
let
commonExpectStatements = ''
expect "Loading bindings from data/init/interface.txt"
'';
dfHackExpectScript = writeText "dfhack-test.exp" (
''
spawn env NIXPKGS_DF_OPTS=debug xvfb-run $env(out)/bin/dfhack
''
+ commonExpectStatements
+ ''
expect "DFHack is ready. Have a nice day!"
expect "DFHack version ${dfhack'.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 env NIXPKGS_DF_OPTS=debug,${lib.optionalString fmod "fmod"} xvfb-run $env(out)/bin/dwarf-fortress
''
+ commonExpectStatements
+ ''
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 isAtLeast50 ''
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

@@ -0,0 +1,192 @@
#!@stdenv_shell@ -e
set -euo pipefail
shopt -s extglob
export NIXPKGS_DF_ENV="@env@"
### BEGIN: Default DF options
declare -A _NIXPKGS_DF_OPTS
_NIXPKGS_DF_OPTS[fmod]=0 # Don't use fmod by default.
_NIXPKGS_DF_OPTS[debug]=0 # No debugging output by default.
### END: Default DF options
# Read NIXPKGS_DF_OPTS.
if [[ ! -v NIXPKGS_DF_OPTS ]]; then
NIXPKGS_DF_OPTS=''
fi
IFS=',' read -ra options <<< "$NIXPKGS_DF_OPTS"
for option in ${options[@]+"${options[@]}"}; do
key="${option%=*}"
value="${option##*=}"
if [ -n "$key" ]; then
if [ -z "$value" ] || [ "$key" == "$value" ]; then
value=1
fi
_NIXPKGS_DF_OPTS["$key"]="$value"
fi
done
# Rebuild the canonical option string from the read options.
NIXPKGS_DF_OPTS=''
for key in "${!_NIXPKGS_DF_OPTS[@]}"; do
value="${_NIXPKGS_DF_OPTS["${key}"]}"
NIXPKGS_DF_OPTS="$NIXPKGS_DF_OPTS$key=$value,"
done
NIXPKGS_DF_OPTS="${NIXPKGS_DF_OPTS%,}"
# Echoes a log.
# $@: log messages
log() {
for msg in "$@"; do
echo "[nixpkgs] $msg" >&2
done
}
# Echoes a log if NIXPKGS_DF_OPTS includes debug.
# $@: log messages
debug() {
if [ "${_NIXPKGS_DF_OPTS[debug]}" -ne 0 ]; then
log "$@"
fi
}
# Updates a path in $NIXPKGS_DF_HOME from $NIXPKGS_DF_ENV.
# $1: The environment path.
update_path() {
local path="$1"
local orig="$NIXPKGS_DF_ENV/$path"
local final="$NIXPKGS_DF_HOME/$path"
# If user has replaced these data directories, let them stay.
@mkdir@ -p "$(dirname -- "$final")"
if [ ! -e "$final" ] || [ -L "$final" ]; then
debug "Linking: $final -> $orig"
@rm@ -f "$final"
@ln@ -s "$orig" "$final"
else
debug "Not updating: $final"
fi
}
# Cleans up a path in $NIXPKGS_DF_HOME that may or may not be in $NIXPKGS_DF_ENV.
# $1: The environment path.
cleanup_path() {
local path="$1"
local final="$NIXPKGS_DF_HOME/$path"
# Let them stay if not a link.
if [ ! -e "$final" ] || [ -L "$final" ]; then
debug "Cleaning up: $final"
@rm@ -f "$final"
else
debug "Not cleaning: $final"
fi
}
# Force copies a path in $NIXPKGS_DF_HOME that may or may not be in $NIXPKGS_DF_ENV.
# $1: The environment path.
forcecopy_path() {
local path="$1"
if [ -z "$NIXPKGS_DF_ENV" ] || [ -z "$path" ]; then
# Avoid producing "/" for any `rm -rf`
return
fi
local orig="$NIXPKGS_DF_ENV/$path"
local final="$NIXPKGS_DF_HOME/$path"
if [ -e "$orig" ]; then
debug "Force copying: $orig -> $final"
@mkdir@ -p "$(dirname -- "$final")"
@rm@ -rf "$final"
@cp@ -rL --no-preserve=all "$orig" "$final"
else
debug "Removing: $final"
@rm@ -rf "$final"
fi
}
# Runs the final executable. Expects NIXPKGS_DF_HOME and NIXPKGS_DF_EXE to be set.
go() {
cd "$NIXPKGS_DF_HOME"
debug "Executing: $NIXPKGS_DF_HOME/$NIXPKGS_DF_EXE"
# Only mess with the library paths if we're starting Dwarf Fortress (not Soundsense).
if [ "$NIXPKGS_DF_GAME" -eq 1 ]; then
# Handle library paths on Darwin.
if [ "$NIXPKGS_DF_PLATFORM" == df_osx ]; then
if [ "${NIXPKGS_DF_PLATFORM_REV%%.*}" -ge 11 ]; then
export DYLD_LIBRARY_PATH="$NIXPKGS_DF_ENV/libs"
export DYLD_FRAMEWORK_PATH="$NIXPKGS_DF_ENV/libs"
else
export DYLD_FALLBACK_LIBRARY_PATH="$NIXPKGS_DF_ENV/libs"
export DYLD_FALLBACK_FRAMEWORK_PATH="$NIXPKGS_DF_ENV/libs"
fi
fi
if [ "$NIXPKGS_DF_PLATFORM" == df_linux ]; then
# We have to preload the audio plugin for audio to work. See Nix Pill #12 for this pattern:
# https://nixos.org/guides/nix-pills/12-inputs-design-pattern.html
if [ "${_NIXPKGS_DF_OPTS[fmod]}" -eq 0 ] && [ -f "$NIXPKGS_DF_HOME/libfmod.so.13" ]; then
export LD_PRELOAD="$NIXPKGS_DF_HOME/libfmod.so.13${LD_PRELOAD:+:}${LD_PRELOAD:-}"
else
export LD_PRELOAD="@SDL2_mixer@${LD_PRELOAD:+:}${LD_PRELOAD:-}"
fi
fi
fi
# If we make it past here, we want to log.
# shellcheck disable=SC2093
exec -a "$NIXPKGS_DF_EXE" "$NIXPKGS_DF_HOME/$NIXPKGS_DF_EXE" "$@"
log "Execution of $NIXPKGS_DF_HOME/$NIXPKGS_DF_EXE failed!"
exit 1
}
# Figure out the Dwarf Fortress directory (df_linux or df_osx).
os_name="$(@uname@)"
if [ "$os_name" == Linux ]; then
export NIXPKGS_DF_PLATFORM="df_linux"
elif [ "$os_name" == Darwin ]; then
export NIXPKGS_DF_PLATFORM="df_osx"
else
log "Unknown platform: $os_name"
exit 1
fi
export NIXPKGS_DF_PLATFORM_REV="$(@uname@ -r)"
if [[ -v DF_DIR ]] && [ -n "$DF_DIR" ] && { [[ ! -v NIXPKGS_DF_HOME ]] || [ -z "$NIXPKGS_DF_HOME" ]; }; then
# Compatibility for users that were using DF_DIR, since the dfhack script clobbers this variable.
export NIXPKGS_DF_HOME="$DF_DIR"
fi
if [[ ! -v NIXPKGS_DF_HOME ]] || [ -z "$NIXPKGS_DF_HOME" ]; then
export NIXPKGS_DF_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/$NIXPKGS_DF_PLATFORM"
fi
# Compatibility.
export DF_DIR="$NIXPKGS_DF_HOME"
@mkdir@ -p "$NIXPKGS_DF_HOME"
@cat@ <<EOF >&2
/------------------------------------------------------------------------------\\
| 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' "$NIXPKGS_DF_OPTS") |
| |
| If you want to try fmod over SDL_mixer, set NIXPKGS_DF_OPTS=fmod. |
\\------------------------------------------------------------------------------/
EOF
cd "$NIXPKGS_DF_ENV"

View File

@@ -0,0 +1,59 @@
#!@stdenv_shell@ -e
export NIXPKGS_DF_EXE="@dfExe@"
export NIXPKGS_DF_GAME=1
source @dfInit@
# All potential important files in DF 50 and below.
for path in dwarfort dwarfort.exe df *.so* libs raw data/init/* data/!(init|index|announcement); do
force_delete=0
if [[ "$path" == *fmod*.so* ]] && [ "${_NIXPKGS_DF_OPTS[fmod]}" -eq 0 ]; then
# Delete fmod plugins if we're using SDL_mixer.
force_delete=1
elif [[ "$path" == *mixer*.so* ]] && [ "${_NIXPKGS_DF_OPTS[fmod]}" -ne 0 ]; then
# Delete SDL_mixer plugins if we're using fmod.
force_delete=1
fi
if [ -e "$path" ] && [ "$force_delete" -eq 0 ]; then
update_path "$path"
else
cleanup_path "$path"
fi
done
# These need to be copied due to read only flags on older versions of DF.
for path in index announcement help dipscript; do
forcecopy_path "data/$path"
done
# 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 [ "${NIXPKGS_DF_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 "$@"

View File

@@ -0,0 +1,11 @@
#!@stdenv_shell@ -e
export NIXPKGS_DF_EXE="soundsense/soundSense.sh"
export NIXPKGS_DF_GAME=0
source @dfInit@
for path in soundsense/*; do
update_path "$path"
done
JDK_JAVA_OPTIONS='--add-opens=java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED' PATH="@jre@/bin:$PATH" go "$@"

View File

@@ -0,0 +1,64 @@
{
lib,
stdenv,
requireFile,
gogUnpackHook,
}:
let
generic =
ver: source:
let
pname = "descent${toString ver}";
in
stdenv.mkDerivation rec {
name = "${pname}-assets-${version}";
version = "2.0.0.7";
src = requireFile rec {
name = "setup_descent12_${version}.exe";
sha256 = "1r1drbfda6czg21f9qqiiwgnkpszxgmcn5bafp5ljddh34swkn3f";
message = ''
While the Descent ${toString ver} game engine is free, the game assets are not.
Please purchase the game on gog.com and download the Windows installer.
Once you have downloaded the file, please use the following command and re-run the
installation:
nix-prefetch-url file://\$PWD/${name}
'';
};
nativeBuildInputs = [ gogUnpackHook ];
dontBuild = true;
dontFixup = true;
installPhase = ''
runHook preInstall
mkdir -p $out/share/{games/${pname},doc/${pname}/examples}
pushd "app/${source}"
mv dosbox*.conf $out/share/doc/${pname}/examples
mv *.txt *.pdf $out/share/doc/${pname}
cp -r * $out/share/games/descent${toString ver}
popd
runHook postInstall
'';
meta = with lib; {
description = "Descent ${toString ver} assets from GOG";
homepage = "https://www.dxx-rebirth.com/";
license = licenses.unfree;
maintainers = with maintainers; [ peterhoeg ];
hydraPlatforms = [ ];
};
};
in
{
descent1-assets = generic 1 "descent";
descent2-assets = generic 2 "descent 2";
}

View File

@@ -0,0 +1,74 @@
{
lib,
stdenv,
fetchFromGitHub,
fetchurl,
scons,
pkg-config,
SDL2,
SDL2_image,
SDL2_mixer,
libGLU,
libGL,
libpng,
physfs,
unstableGitUpdater,
}:
let
music = fetchurl {
url = "https://www.dxx-rebirth.com/download/dxx/res/d2xr-sc55-music.dxa";
sha256 = "05mz77vml396mff43dbs50524rlm4fyds6widypagfbh5hc55qdc";
};
in
stdenv.mkDerivation {
pname = "dxx-rebirth";
version = "0.60.0-beta2-unstable-2025-05-24";
src = fetchFromGitHub {
owner = "dxx-rebirth";
repo = "dxx-rebirth";
rev = "7a84b3f307ac6f72fd440e55b149d7c2c942dfaf";
hash = "sha256-b3rMitf2kw8y0EXwxeKKB8bqzCUaIaMQmpV1gtdcLis=";
};
nativeBuildInputs = [
pkg-config
scons
];
buildInputs = [
libGLU
libGL
libpng
physfs
SDL2
SDL2_image
SDL2_mixer
];
enableParallelBuilding = true;
sconsFlags = [ "sdl2=1" ];
env.NIX_CFLAGS_COMPILE = toString [
"-Wno-format-nonliteral"
"-Wno-format-truncation"
];
postInstall = ''
install -Dm644 ${music} $out/share/games/dxx-rebirth/${music.name}
install -Dm644 -t $out/share/doc/dxx-rebirth *.txt
'';
passthru.updateScript = unstableGitUpdater { };
meta = with lib; {
description = "Source Port of the Descent 1 and 2 engines";
homepage = "https://www.dxx-rebirth.com/";
license = licenses.gpl3;
maintainers = with maintainers; [ peterhoeg ];
platforms = with platforms; linux;
};
}

View File

@@ -0,0 +1,42 @@
{
lib,
stdenv,
makeWrapper,
dxx-rebirth,
descent1-assets,
descent2-assets,
}:
let
generic =
ver: assets:
stdenv.mkDerivation {
name = "d${toString ver}x-rebirth-full-${assets.version}";
nativeBuildInputs = [ makeWrapper ];
buildCommand = ''
mkdir -p $out/bin
makeWrapper ${dxx-rebirth}/bin/d${toString ver}x-rebirth $out/bin/descent${toString ver} \
--add-flags "-hogdir ${assets}/share/games/descent${toString ver}"
'';
meta = with lib; {
description = "Descent ${toString ver} using the DXX-Rebirth project engine and game assets from GOG";
homepage = "https://www.dxx-rebirth.com/";
license = with licenses; [
free
unfree
];
maintainers = with maintainers; [ peterhoeg ];
platforms = with platforms; linux;
hydraPlatforms = [ ];
};
};
in
{
d1x-rebirth-full = generic 1 descent1-assets;
d2x-rebirth-full = generic 2 descent2-assets;
}

View File

@@ -0,0 +1,87 @@
{
cmake,
fpattern,
lib,
SDL2,
stdenv,
writeShellScript,
extraBuildInputs ? [ ],
extraMeta,
patches,
pname,
version,
src,
}:
let
launcher = writeShellScript "${pname}" ''
set -eu
assetDir="''${XDG_DATA_HOME:-$HOME/.local/share}/${pname}"
[ -d "$assetDir" ] || mkdir -p "$assetDir"
cd "$assetDir"
notice=0 fault=0
requiredFiles=(master.dat critter.dat)
for f in "''${requiredFiles[@]}"; do
if [ ! -f "$f" ]; then
echo "Required file $f not found in $PWD, note the files are case-sensitive"
notice=1 fault=1
fi
done
if [ ! -d "data/sound/music" ]; then
echo "data/sound/music directory not found in $PWD. This may prevent in-game music from functioning."
notice=1
fi
if [ $notice -ne 0 ]; then
echo "Please reference the installation instructions at https://github.com/alexbatalov/fallout2-ce"
fi
if [ $fault -ne 0 ]; then
exit $fault;
fi
exec @out@/libexec/${pname} "$@"
'';
in
stdenv.mkDerivation {
inherit
pname
version
src
patches
;
nativeBuildInputs = [ cmake ];
buildInputs = [ SDL2 ] ++ extraBuildInputs;
hardeningDisable = [ "format" ];
cmakeBuildType = "RelWithDebInfo";
postPatch = ''
substituteInPlace third_party/fpattern/CMakeLists.txt \
--replace "FetchContent_Populate" "#FetchContent_Populate" \
--replace "{fpattern_SOURCE_DIR}" "${fpattern}/include" \
--replace "$/nix/" "/nix/"
'';
installPhase = ''
runHook preInstall
install -D ${pname} $out/libexec/${pname}
install -D ${launcher} $out/bin/${pname}
substituteInPlace $out/bin/${pname} --subst-var out
runHook postInstall
'';
meta =
with lib;
{
license = licenses.sustainableUse;
maintainers = with maintainers; [ hughobrien ];
platforms = platforms.linux;
}
// extraMeta;
}

View File

@@ -0,0 +1,30 @@
{
callPackage,
fetchFromGitHub,
fetchpatch2,
}:
callPackage ./build.nix rec {
pname = "fallout-ce";
version = "1.1.0";
src = fetchFromGitHub {
owner = "alexbatalov";
repo = "fallout1-ce";
rev = "v${version}";
hash = "sha256-ZiBoF3SL00sN0QrD3fkWG9SAknumOvzRB1oQJff6ITA=";
};
patches = [
# Fix case-sensitive filesystems issue when save/load games
(fetchpatch2 {
url = "https://github.com/alexbatalov/fallout1-ce/commit/aa3c5c1e3e3f9642d536406b2d8d6b362c9e402f.patch";
sha256 = "sha256-quFRbKMS2pNDCNTWc1ZoB3jnB5qzw0b+2OeJUi8IPBc=";
})
];
extraMeta = {
description = "Fully working re-implementation of Fallout, with the same original gameplay, engine bugfixes, and some quality of life improvements";
homepage = "https://github.com/alexbatalov/fallout1-ce";
};
}

View File

@@ -0,0 +1,33 @@
{
callPackage,
fetchFromGitHub,
fetchpatch2,
zlib,
}:
callPackage ./build.nix rec {
pname = "fallout2-ce";
version = "1.3.0";
src = fetchFromGitHub {
owner = "alexbatalov";
repo = "fallout2-ce";
rev = "v${version}";
hash = "sha256-r1pnmyuo3uw2R0x9vGScSHIVNA6t+txxABzgHkUEY5U=";
};
patches = [
# Fix case-sensitive filesystems issue when save/load games
(fetchpatch2 {
url = "https://github.com/alexbatalov/fallout2-ce/commit/d843a662b3ceaf01ac363e9abb4bfceb8b805c36.patch";
sha256 = "sha256-r4sfl1JolWRNd2xcf4BMCxZw3tbN21UJW4TdyIbQzgs=";
})
];
extraBuildInputs = [ zlib ];
extraMeta = {
description = "Fully working re-implementation of Fallout 2, with the same original gameplay, engine bugfixes, and some quality of life improvements";
homepage = "https://github.com/alexbatalov/fallout2-ce";
};
}

View File

@@ -0,0 +1,118 @@
{
lib,
stdenv,
fetchFromGitLab,
wrapQtAppsHook,
callPackage,
libglut,
freealut,
libGLU,
libGL,
libICE,
libjpeg,
openal,
plib,
libSM,
libunwind,
libX11,
xorgproto,
libXext,
libXi,
libXmu,
libXt,
simgear,
zlib,
boost,
cmake,
libpng,
udev,
fltk13,
apr,
qtbase,
qtquickcontrols2,
qtdeclarative,
glew,
curl,
}:
let
version = "2024.1.1";
data = stdenv.mkDerivation rec {
pname = "flightgear-data";
inherit version;
src = fetchFromGitLab {
owner = "flightgear";
repo = "fgdata";
tag = "v${version}";
hash = "sha256-PdqsIZw9mSrvnqqB/fVFjWPW9njhXLWR/2LQCMoBLQI=";
};
dontUnpack = true;
installPhase = ''
mkdir -p "$out/share/FlightGear"
cp ${src}/* -a "$out/share/FlightGear/"
'';
};
openscenegraph = callPackage ./openscenegraph-flightgear.nix { };
in
stdenv.mkDerivation rec {
pname = "flightgear";
# inheriting data for `nix-prefetch-url -A pkgs.flightgear.data.src`
inherit version data;
src = fetchFromGitLab {
owner = "flightgear";
repo = "flightgear";
tag = "v${version}";
hash = "sha256-h4N18VAbJGQSBKA+eEQxej5e5MEwAcZpvH+dpTypM+k=";
};
nativeBuildInputs = [
cmake
wrapQtAppsHook
];
buildInputs = [
libglut
freealut
libGLU
libGL
libICE
libjpeg
openal
openscenegraph
plib
libSM
libunwind
libX11
xorgproto
libXext
libXi
libXmu
libXt
(simgear.override { openscenegraph = openscenegraph; })
zlib
boost
libpng
udev
fltk13
apr
qtbase
qtquickcontrols2
glew
qtdeclarative
curl
];
qtWrapperArgs = [ "--set FG_ROOT ${data}/share/FlightGear" ];
meta = with lib; {
description = "Flight simulator";
maintainers = with maintainers; [ raskin ];
platforms = platforms.linux;
hydraPlatforms = [ ]; # disabled from hydra because it's so big
license = licenses.gpl2Plus;
mainProgram = "fgfs";
};
}

View File

@@ -0,0 +1,93 @@
{
lib,
stdenv,
fetchFromGitLab,
pkg-config,
cmake,
doxygen,
fetchpatch,
fetchurl,
glib,
libxml2,
pcre,
zlib,
libjpeg,
giflib,
libtiff,
libpng,
curl,
freetype,
boost,
libGLU,
libGL,
libX11,
libXinerama,
libXrandr,
}:
stdenv.mkDerivation {
pname = "openscenegraph";
version = "2024-build";
src = fetchFromGitLab {
owner = "flightgear";
repo = "openscenegraph";
# release/2024-build as of 2025-08-08
rev = "a4ea8ec535cc969e31e2026b13be147dcb978689";
sha256 = "sha256-wnxm4G40j2e6Paqx0vfAR4s4L7esfCHcgxUJWNxk1SM=";
};
nativeBuildInputs = [
pkg-config
cmake
doxygen
];
buildInputs =
lib.optionals (!stdenv.hostPlatform.isDarwin) [
libX11
libXinerama
libXrandr
libGLU
libGL
]
++ [
glib
libxml2
pcre
zlib
libjpeg
giflib
libtiff
libpng
curl
freetype
boost
];
patches = [
(fetchpatch {
name = "opencascade-api-patch";
url = "https://github.com/openscenegraph/OpenSceneGraph/commit/bc2daf9b3239c42d7e51ecd7947d31a92a7dc82b.patch";
hash = "sha256-VR8YKOV/YihB5eEGZOGaIfJNrig1EPS/PJmpKsK284c=";
})
# Fix compiling with libtiff when libtiff is compiled using CMake
(fetchurl {
url = "https://github.com/openscenegraph/OpenSceneGraph/commit/9da8d428f6666427c167b951b03edd21708e1f43.patch";
hash = "sha256-YGG/DIHU1f6StbeerZoZrNDm348wYB3ydmVIIGTM7fU=";
})
];
cmakeFlags = [ "-DBUILD_OSG_APPLICATIONS=OFF" ];
meta = with lib; {
description = "3D graphics toolkit";
homepage = "http://www.openscenegraph.org/";
maintainers = with maintainers; [
aanderse
raskin
];
platforms = with platforms; linux ++ darwin;
license = "OpenSceneGraph Public License - free LGPL-based license";
};
}

Some files were not shown because too many files have changed in this diff Show More