aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE12
-rw-r--r--README.md38
-rw-r--r--default.nix7
-rw-r--r--flake.lock27
-rw-r--r--flake.nix10
-rw-r--r--overlay.nix3
-rw-r--r--srcds-pkgs/ambuild.nix23
-rw-r--r--srcds-pkgs/bad/libfinite.nix20
-rw-r--r--srcds-pkgs/bad/mysql_5_5.nix14
-rw-r--r--srcds-pkgs/build-sm-plugin.nix71
-rw-r--r--srcds-pkgs/default.nix55
-rw-r--r--srcds-pkgs/depotdownloader-json/0001-emit-json-in-.DepotDownload.patch51
-rw-r--r--srcds-pkgs/depotdownloader-json/0002-ProtoManifest-sort-files-in-constructor.patch24
-rw-r--r--srcds-pkgs/depotdownloader-json/default.nix10
-rw-r--r--srcds-pkgs/extensions/SM-Memory.nix51
-rw-r--r--srcds-pkgs/extensions/SM-neocurl-ext.nix43
-rw-r--r--srcds-pkgs/fetchdepotcache.nix27
-rw-r--r--srcds-pkgs/fetchdepotfile.nix46
-rw-r--r--srcds-pkgs/hl2sdk-2013.nix9
-rw-r--r--srcds-pkgs/metamod-source.nix66
-rw-r--r--srcds-pkgs/mkdepot.nix19
-rw-r--r--srcds-pkgs/plugins/Chat-Logger-Redux.nix19
-rw-r--r--srcds-pkgs/plugins/Open-Fortress-Tools.nix15
-rw-r--r--srcds-pkgs/plugins/SteamTools.nix21
-rw-r--r--srcds-pkgs/plugins/SteamWorks.nix19
-rw-r--r--srcds-pkgs/plugins/Updater.nix28
-rw-r--r--srcds-pkgs/plugins/ftz_cheats.nix14
-rw-r--r--srcds-pkgs/plugins/morecolors.nix20
-rw-r--r--srcds-pkgs/plugins/nativevotes-updated.nix16
-rw-r--r--srcds-pkgs/plugins/openfrags.nix16
-rw-r--r--srcds-pkgs/plugins/smlib.nix22
-rw-r--r--srcds-pkgs/plugins/socket.nix27
-rw-r--r--srcds-pkgs/plugins/yuuko_votes.nix13
-rw-r--r--srcds-pkgs/sourcemod/default.nix82
-rw-r--r--srcds-pkgs/sourcemod/setup-hook.sh16
35 files changed, 954 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..30604de
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,12 @@
+Copyright (C) 2024 by yuuko <yuuko@partyvan.io>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5d0f767
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+### /!\ ALART /!\ ALPHA PROOF OF CONCEPT /!\ ALART /!\
+
+Currently the SM/MMS side of things builds exclusively against SDK 2013
+Multiplayer. Accordingly, there are some underlying 32-bit assumptions.
+
+srcds-nix
+=========
+
+This is a Nix package set and library for Source Engine dedicated servers.
+It currently features:
+
+* fetchers for Steam content: `fetchDepotCache`, `fetchDepotFile`, `mkDepot`
+ * Courtesy of a patched DepotDownloader, derivations are fixed-output on the
+ contents of deterministic manifests, then on the SHA1 hashes within.
+ * This is quite distinct from the usual `steamcmd` approach, but yields a
+ far more reproducible server environment. Additionally, the network traffic
+ between `lib.fakeHash` and TOFU is measured in kilobytes, not potential
+ gigabytes as with [steam-fetcher].
+* AMBuild
+* MetaMod: Source
+* SourceMod
+ * a standard extensible package set for plugins and extensions, including:
+ * `mkDerivation` analogue: `buildSMPlugin`
+ * setup hook for `spcomp` include paths
+ * coming soon: development shells to replicate your server setup
+
+Usage
+-----
+
+* `default.nix` lets you `callPackage` this repository the old-fashioned way
+ to get the top-level package set.
+* `overlay.nix` adds it as `srcdsPackages` to the target. `srcdsPackages` is
+ considered its canonical place in nixpkgs.
+* `flake.nix` exposes:
+ * `packages.${system}.default` is the top-level package set.
+ * `overlays.default` points to `overlay.nix`.
+
+[steam-fetcher]: https://github.com/nix-community/steam-fetcher
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..6254ecb
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,7 @@
+let
+ purity = if builtins ? currentSystem then
+ import <nixpkgs> {}
+ else
+ throw "OOPS: srcds-nix/default.nix called without pkgs in a pure context";
+in
+{ pkgs ? purity, ... }: pkgs.callPackage ./srcds-pkgs {}
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..c261cf8
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,27 @@
+{
+ "nodes": {
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1724727824,
+ "narHash": "sha256-0XH9MJk54imJm+RHOLTUJ7e+ponLW00tw5ke4MTVa1Y=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "36bae45077667aff5720e5b3f1a5458f51cf0776",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-24.05",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..5c2bc84
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,10 @@
+{
+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
+
+ outputs = { self, nixpkgs, ... }@inputs: {
+ overlays.default = import ./overlay.nix;
+ packages = builtins.mapAttrs
+ (_arch: pkgs: { default = import ./default.nix pkgs; })
+ nixpkgs.legacyPackages;
+ };
+}
diff --git a/overlay.nix b/overlay.nix
new file mode 100644
index 0000000..8a51cc3
--- /dev/null
+++ b/overlay.nix
@@ -0,0 +1,3 @@
+self: _super: {
+ srcdsPackages = import ./default.nix self;
+}
diff --git a/srcds-pkgs/ambuild.nix b/srcds-pkgs/ambuild.nix
new file mode 100644
index 0000000..5621f49
--- /dev/null
+++ b/srcds-pkgs/ambuild.nix
@@ -0,0 +1,23 @@
+{ lib, buildPythonPackage, fetchFromGitHub }:
+let
+ owner = "alliedmodders";
+in buildPythonPackage rec {
+ pname = "ambuild";
+ version = "2024-07-07";
+
+ src = fetchFromGitHub {
+ inherit owner;
+ repo = pname;
+ rev = "551dd3f630f90377cbe536fbaf12e0b6bca91253";
+ sha256 = "1xfjxs3ajrrz66pdspwrnr5faifk1r3i5nha8vmz510z07h5g6g3";
+ };
+
+ # doCheck = false;
+
+ meta = with lib; {
+ description = "Lightweight build system designed for performance and accuracy";
+ homepage = "https://github.com/${owner}/${pname}";
+ platforms = platforms.unix;
+ license = licenses.bsd3;
+ };
+}
diff --git a/srcds-pkgs/bad/libfinite.nix b/srcds-pkgs/bad/libfinite.nix
new file mode 100644
index 0000000..300bd18
--- /dev/null
+++ b/srcds-pkgs/bad/libfinite.nix
@@ -0,0 +1,20 @@
+# https://sourceware.org/git/?p=glibc.git;a=commit;h=7bdb921d
+{ runCommandWith, multiStdenv, writeText }:
+runCommandWith {
+ stdenv = multiStdenv;
+ name = "libfinite.a";
+} ''
+ cc -o finite.o -m32 -c ${writeText "finite.c" ''
+ #include <math.h>
+ /* metamod */
+ double __pow_finite(double x, double y) { return pow(x, y); }
+ /* sourcemod */
+ float __acosf_finite(float x) { return acosf(x); };
+ double __acos_finite(double x) { return acos(x); };
+ double __asin_finite(double x) { return asin(x); };
+ float __atan2f_finite(double y, double x) { return atan2f(y, x); }
+ double __atan2_finite(double y, double x) { return atan2(y, x); }
+ double __log_finite(double x) { return log(x); }
+ ''}
+ ar rcs $out finite.o
+''
diff --git a/srcds-pkgs/bad/mysql_5_5.nix b/srcds-pkgs/bad/mysql_5_5.nix
new file mode 100644
index 0000000..bd7534c
--- /dev/null
+++ b/srcds-pkgs/bad/mysql_5_5.nix
@@ -0,0 +1,14 @@
+# TODO: find out if sourcemod is lying about needing to build against 5.5
+{ lib, stdenv, fetchurl, ncurses, cmake }:
+stdenv.mkDerivation rec {
+ pname = "mysql";
+ version = "5.5.62";
+
+ src = fetchurl {
+ url = "https://downloads.mysql.com/archives/get/p/23/file/mysql-${version}.tar.gz";
+ hash = "sha256-seeFO8HwSqv2dx4K2UfzWsjSN/SzXQcG0QlclSb/mdc=";
+ };
+
+ nativeBuildInputs = [ cmake ];
+ buildInputs = [ ncurses ];
+}
diff --git a/srcds-pkgs/build-sm-plugin.nix b/srcds-pkgs/build-sm-plugin.nix
new file mode 100644
index 0000000..d55338d
--- /dev/null
+++ b/srcds-pkgs/build-sm-plugin.nix
@@ -0,0 +1,71 @@
+/* there is a lot of hideous directory-shuffling bureaucracy here. it
+ * encompasses all that has been found necessary out in the wild. sourcemod
+ * plugins following a sane standard project structure is a fairly recent
+ * development.
+ */
+{ lib, stdenvNoCC, sourcemod }:
+{ scriptingPath ? "scripting"
+, includePath ? "scripting/include"
+, pluginsPath ? "plugins"
+, translationsPath ? "translations"
+, gamedataPath ? "gamedata"
+, removePrebuilt ? true
+, nativeBuildInputs ? []
+, ...
+}@args:
+let
+ inherit (lib) hasSuffix;
+in
+assert !hasSuffix "/" scriptingPath;
+assert !hasSuffix "/" includePath;
+assert !hasSuffix "/" pluginsPath;
+assert !hasSuffix "/" translationsPath;
+assert !hasSuffix "/" gamedataPath;
+stdenvNoCC.mkDerivation ({
+ inherit
+ scriptingPath includePath pluginsPath translationsPath gamedataPath
+ removePrebuilt;
+ configurePhase = ''
+ runHook preConfigure
+ source <(for d in scripting include plugins translations gamedata; do
+ echo "''${d}Path=$PWD/"\$"''${d}Path"
+ done)
+ cd /build
+ for p in scripting plugins translations gamedata; do
+ path="$(eval echo \$"''${p}Path")"
+ [ -d "$path" ] && cp -rT "$path" ./"$p"
+ done
+ case "$includePath" in
+ "$scriptingPath/include") :;;
+ "$scriptingPath"/*) echo TODO; exit 1;;
+ *) cp -r "$includePath" ./scripting/include;;
+ esac
+ [ -n "''${removePrebuilt:-}" ] && rm -f plugins/*.smx;
+ mkdir -p scripting/include plugins/disabled translations gamedata
+ runHook postConfigure
+ '';
+
+ buildPhase = ''
+ runHook preBuild
+ cd /build/scripting
+ [ -d ./include ] && SPCOMPFLAGS="$SPCOMPFLAGS -i ./include"
+ for plug in *.sp; do
+ spcomp -o "../plugins/disabled/''${plug%.sp}.smx" "$plug"
+ done
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+ cd /build
+ find . -type d -empty -delete
+ odir=$out/share/addons/sourcemod
+ mkdir -p $odir
+ for d in scripting plugins translation gamedata; do
+ [ -d $d ] && cp -r $d $odir/$d
+ done
+ runHook postInstall
+ '';
+} // args // {
+ nativeBuildInputs = nativeBuildInputs ++ [ sourcemod ];
+})
diff --git a/srcds-pkgs/default.nix b/srcds-pkgs/default.nix
new file mode 100644
index 0000000..1b8294c
--- /dev/null
+++ b/srcds-pkgs/default.nix
@@ -0,0 +1,55 @@
+let f = self: with self; {
+ inherit (self) callPackage;
+
+ libfinite = callPackage ./bad/libfinite.nix {};
+ mysql_5_5 = pkgs.pkgsi686Linux.callPackage ./bad/mysql_5_5.nix {};
+
+ ambuild = callPackage ./ambuild.nix {
+ inherit (pkgs.python3Packages) buildPythonPackage;
+ };
+
+ hl2sdk-2013 = callPackage ./hl2sdk-2013.nix {};
+
+ metamod-source = callPackage ./metamod-source.nix {
+ hl2sdk = hl2sdk-2013;
+ };
+ sourcemod = callPackage ./sourcemod {
+ hl2sdk = hl2sdk-2013;
+ };
+
+ buildSMPlugin = callPackage ./build-sm-plugin.nix {};
+ # TODO: see if it even makes sense to abstract this hard
+ # buildSMExtension = callPackage ./build-sm-extension.nix {};
+
+ depotdownloader-json = callPackage ./depotdownloader-json {};
+
+ fetchDepotCache = callPackage ./fetchdepotcache.nix {
+ depotdownloader = depotdownloader-json;
+ };
+ fetchDepotFile = callPackage ./fetchdepotfile.nix {
+ depotdownloader = depotdownloader-json;
+ };
+ mkDepot = callPackage ./mkdepot.nix {};
+
+ SM-Memory = callPackage ./extensions/SM-Memory.nix {};
+ SM-neocurl-ext = callPackage ./extensions/SM-neocurl-ext.nix {};
+
+ Chat-Logger-Redux = callPackage ./plugins/Chat-Logger-Redux.nix {};
+ Open-Fortress-Tools = callPackage ./plugins/Open-Fortress-Tools.nix {};
+ SteamTools = callPackage ./plugins/SteamTools.nix {};
+ SteamWorks = callPackage ./plugins/SteamWorks.nix {};
+ Updater = callPackage ./plugins/Updater.nix {};
+ ftz_cheats = callPackage ./plugins/ftz_cheats.nix {};
+ morecolors = callPackage ./plugins/morecolors.nix {};
+ nativevotes-updated = callPackage ./plugins/nativevotes-updated.nix {};
+ openfrags = callPackage ./plugins/openfrags.nix {};
+ smlib = callPackage ./plugins/smlib.nix {};
+ socket = callPackage ./plugins/socket.nix {};
+ yuuko_votes = callPackage ./plugins/yuuko_votes.nix {};
+}; in
+{ lib
+, newScope
+, recurseIntoAttrs
+, pkgs
+}:
+recurseIntoAttrs (lib.makeScope newScope (self: f self // { inherit pkgs; }))
diff --git a/srcds-pkgs/depotdownloader-json/0001-emit-json-in-.DepotDownload.patch b/srcds-pkgs/depotdownloader-json/0001-emit-json-in-.DepotDownload.patch
new file mode 100644
index 0000000..6a58ac6
--- /dev/null
+++ b/srcds-pkgs/depotdownloader-json/0001-emit-json-in-.DepotDownload.patch
@@ -0,0 +1,51 @@
+From 5ca2011ef9c6463c6e5953101792b663b6546373 Mon Sep 17 00:00:00 2001
+From: yuuko <yuuko@kurofuku.me>
+Date: Fri, 31 Mar 2023 16:03:32 -0700
+Subject: [PATCH] emit json in .DepotDownload
+
+---
+ DepotDownloader/ContentDownloader.cs | 1 +
+ DepotDownloader/ProtoManifest.cs | 8 ++++++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs
+index 7cee83f7..3bf79aa5 100644
+--- a/DepotDownloader/ContentDownloader.cs
++++ b/DepotDownloader/ContentDownloader.cs
+@@ -929,6 +929,7 @@ namespace DepotDownloader
+
+ newProtoManifest = new ProtoManifest(depotManifest, depot.manifestId);
+ newProtoManifest.SaveToFile(newManifestFileName, out checksum);
++ newProtoManifest.SaveToJSON(newManifestFileName.Replace(".bin", ".json"));
+ File.WriteAllBytes(newManifestFileName + ".sha", checksum);
+
+ Console.WriteLine(" Done!");
+diff --git a/DepotDownloader/ProtoManifest.cs b/DepotDownloader/ProtoManifest.cs
+index 70389a05..c5e12cfc 100644
+--- a/DepotDownloader/ProtoManifest.cs
++++ b/DepotDownloader/ProtoManifest.cs
+@@ -2,6 +2,8 @@
+ using System.Collections.Generic;
+ using System.IO;
+ using System.IO.Compression;
++using System.Text;
++using System.Text.Json;
+ using ProtoBuf;
+ using SteamKit2;
+
+@@ -142,6 +144,12 @@ namespace DepotDownloader
+ }
+ }
+
++ public void SaveToJSON(string filename)
++ {
++ var jsonBytes = new UTF8Encoding(true).GetBytes(JsonSerializer.Serialize(this));
++ File.Open(filename, FileMode.Create).Write(jsonBytes, 0, jsonBytes.Length);
++ }
++
+ public void SaveToFile(string filename, out byte[] checksum)
+ {
+ using (var ms = new MemoryStream())
+--
+2.38.4
+
diff --git a/srcds-pkgs/depotdownloader-json/0002-ProtoManifest-sort-files-in-constructor.patch b/srcds-pkgs/depotdownloader-json/0002-ProtoManifest-sort-files-in-constructor.patch
new file mode 100644
index 0000000..ac4fe97
--- /dev/null
+++ b/srcds-pkgs/depotdownloader-json/0002-ProtoManifest-sort-files-in-constructor.patch
@@ -0,0 +1,24 @@
+From 7c067e609efabd54039905dc35edf91afb6c5dad Mon Sep 17 00:00:00 2001
+From: yuuko <yuuko@kurofuku.me>
+Date: Wed, 1 Nov 2023 06:46:57 -0700
+Subject: [PATCH] ProtoManifest: sort files in constructor
+
+---
+ DepotDownloader/ProtoManifest.cs | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/DepotDownloader/ProtoManifest.cs b/DepotDownloader/ProtoManifest.cs
+index c5e12cfc..5f66595c 100644
+--- a/DepotDownloader/ProtoManifest.cs
++++ b/DepotDownloader/ProtoManifest.cs
+@@ -21,6 +21,7 @@ namespace DepotDownloader
+ public ProtoManifest(DepotManifest sourceManifest, ulong id) : this()
+ {
+ sourceManifest.Files.ForEach(f => Files.Add(new FileData(f)));
++ Files.Sort((f1,f2) => f1.FileName.CompareTo(f2.FileName));
+ ID = id;
+ CreationTime = sourceManifest.CreationTime;
+ }
+--
+2.42.0
+
diff --git a/srcds-pkgs/depotdownloader-json/default.nix b/srcds-pkgs/depotdownloader-json/default.nix
new file mode 100644
index 0000000..c09422d
--- /dev/null
+++ b/srcds-pkgs/depotdownloader-json/default.nix
@@ -0,0 +1,10 @@
+{ depotdownloader }:
+depotdownloader.overrideAttrs({ patches ? [], version, ... }: {
+ patches = assert builtins.elem version [ "2.4.7" "2.5.0" ]; patches ++ [
+ # with this, nix has access to the hashes in the manifest
+ ./0001-emit-json-in-.DepotDownload.patch
+ # the manifest can arrive out of order across requests to the same build!
+ # luckily that singular reproducibility snag is patched in 1 line.
+ ./0002-ProtoManifest-sort-files-in-constructor.patch
+ ];
+})
diff --git a/srcds-pkgs/extensions/SM-Memory.nix b/srcds-pkgs/extensions/SM-Memory.nix
new file mode 100644
index 0000000..5d1761a
--- /dev/null
+++ b/srcds-pkgs/extensions/SM-Memory.nix
@@ -0,0 +1,51 @@
+{ lib, multiStdenv, fetchFromGitHub
+, metamod-source, sourcemod, ambuild
+, ed
+}:
+multiStdenv.mkDerivation rec {
+ pname = "SM-Memory";
+ version = "1.5.1";
+
+ src = fetchFromGitHub {
+ owner = "Scags";
+ repo = pname;
+ rev = "V${version}";
+ sha256 = "031nbx18hhqgnryzy00rv5bc8v1k7fbkb3677ndm7nkif13p12aa";
+ };
+
+ nativeBuildInputs = [ ambuild sourcemod ed ];
+
+ patchPhase = ''
+ pushd pawn/sourcemod/scripting
+ substituteInPlace memtest_{func,vec}.sp --replace smmem_ smmem/
+ ed memtest.sp <<EOF
+ /#include/a
+ #include <smmem/dynlib.inc>
+ .
+ w
+ EOF
+ popd
+ '';
+
+ configurePhase = ''
+ cd build
+ python ../configure.py \
+ --sm-path ${sourcemod.src} \
+ --mms-path ${metamod-source.src}
+ '';
+
+ buildPhase = ''
+ ambuild
+ pushd package/addons/sourcemod/scripting
+ mkdir -p ../plugins/disabled
+ for i in *.sp; do
+ spcomp -i include $i -o ../plugins/disabled/''${i%.sp}.smx
+ done
+ popd
+ '';
+
+ installPhase = ''
+ mkdir $out
+ mv package $out/share
+ '';
+}
diff --git a/srcds-pkgs/extensions/SM-neocurl-ext.nix b/srcds-pkgs/extensions/SM-neocurl-ext.nix
new file mode 100644
index 0000000..8ac2e02
--- /dev/null
+++ b/srcds-pkgs/extensions/SM-neocurl-ext.nix
@@ -0,0 +1,43 @@
+# pkgsi686Linux.pkgsStatic.callPackage
+{ lib, multiStdenv, fetchgit, ed
+, metamod-source, sourcemod, ambuild, pkg-config, pkg-config-unwrapped
+, pkgsi686Linux
+}:
+multiStdenv.mkDerivation rec {
+ pname = "SM-neocurl-ext";
+ version = "2.0.1";
+
+ src = fetchgit {
+ url = "https://git.partyvan.io/${pname}";
+ rev = "0f0f543d79966fc938b3205e5273820e4c2edc56";
+ hash = "sha256-zRZddNWc6rl4E/StpTuwtMoL0GVuPRAbcihJ0ViKddo=";
+ };
+
+ patchPhase = ''
+ ed AMBuilder <<EOF
+ g/pkg_config/s/static/dynamic/
+ w
+ EOF
+ '';
+
+ nativeBuildInputs = [ ed ambuild sourcemod pkg-config pkg-config-unwrapped ];
+ buildInputs = with pkgsi686Linux; [ openssl curl curl.dev ];
+
+ configurePhase = ''
+ mkdir build
+ cd build
+ python ../configure.py \
+ --sm-path ${sourcemod.src} \
+ --mms-path ${metamod-source.src}
+ '';
+
+ buildPhase = ''
+ ambuild
+ '';
+
+ installPhase = ''
+ mkdir -p $out
+ cp -r package $out/share
+ '';
+}
+ \ No newline at end of file
diff --git a/srcds-pkgs/fetchdepotcache.nix b/srcds-pkgs/fetchdepotcache.nix
new file mode 100644
index 0000000..6546126
--- /dev/null
+++ b/srcds-pkgs/fetchdepotcache.nix
@@ -0,0 +1,27 @@
+{ lib, runCommand
+, depotdownloader, cacert
+}:
+{ app, depot, manifest, hash }:
+let
+ app' = builtins.toString app;
+ depot' = builtins.toString depot;
+in
+runCommand "depotcache-${manifest}" {
+ nativeBuildInputs = [ depotdownloader cacert ];
+ outputHashMode = "recursive";
+ outputHashAlgo = null;
+ outputHash = hash;
+ passthru = { inherit app depot manifest; };
+} ''
+ mkdir -p $out
+ export HOME=$out
+ cd $out
+ DepotDownloader \
+ -app ${app'} \
+ -depot ${depot'} \
+ -manifest ${manifest} \
+ -filelist /dev/null \
+ -dir .
+
+ rm -rf .local
+''
diff --git a/srcds-pkgs/fetchdepotfile.nix b/srcds-pkgs/fetchdepotfile.nix
new file mode 100644
index 0000000..6af2507
--- /dev/null
+++ b/srcds-pkgs/fetchdepotfile.nix
@@ -0,0 +1,46 @@
+# as nice as it would be to just put the file in its expected directory
+# structure and symlinkJoin them together at the end, creating that structure
+# sacrifices the use of steam's hashes -- nix hashing isn't hierarchical
+# or anything, just "archive everything and hash it like another flat file".
+{ lib, runCommand
+, depotdownloader, cacert
+}:
+{ FileName, FileHash, Flags, cache, ... }:
+with lib;
+assert !hasPrefix "/" FileName;
+let
+ dirname = dirOf FileName;
+ basename = baseNameOf FileName;
+ src = runCommand basename {
+ inherit (cache.passthru) app depot manifest;
+ inherit basename dirname FileName;
+ cache = "${cache}";
+
+ passthru = { inherit dirname basename; };
+ nativeBuildInputs = [ depotdownloader cacert ];
+ outputHashMode = "flat";
+ outputHashAlgo = "sha1";
+ outputHash = FileHash;
+ } ''
+ export HOME=$PWD
+ cp -r $cache/.DepotDownloader ./
+ chmod -R 777 .DepotDownloader
+ DepotDownloader \
+ -app $app -depot $depot -manifest $manifest \
+ -filelist <(echo "$FileName") -dir .
+
+ mv $FileName $out
+ chmod -x $out
+ '';
+# nix refuses to flat hash executables lol
+in if bitAnd Flags 32 != 0 then
+ runCommand src.name {
+ inherit src;
+ inherit (src) passthru;
+ } ''
+ cp $src $out
+ chmod +x $out
+ ''
+else src
+
+
diff --git a/srcds-pkgs/hl2sdk-2013.nix b/srcds-pkgs/hl2sdk-2013.nix
new file mode 100644
index 0000000..1d386fc
--- /dev/null
+++ b/srcds-pkgs/hl2sdk-2013.nix
@@ -0,0 +1,9 @@
+{ lib, fetchFromGitHub }:
+fetchFromGitHub {
+ owner = "alliedmodders";
+ repo = "hl2sdk";
+ rev = "4c27c1305c5e042ae1f62f6dc6ba7e96fd06e05d";
+ sha256 = "02ffi72whmbjfjalp23l5s5gqwk2rbqxfkba1rncd22mird93pqh";
+
+ name = "hl2sdk-sdk2013";
+} \ No newline at end of file
diff --git a/srcds-pkgs/metamod-source.nix b/srcds-pkgs/metamod-source.nix
new file mode 100644
index 0000000..2f9c92e
--- /dev/null
+++ b/srcds-pkgs/metamod-source.nix
@@ -0,0 +1,66 @@
+{ lib, multiStdenv
+, fetchFromGitHub, ed
+, hl2sdk, ambuild, libfinite
+}: let
+ owner = "alliedmodders";
+ buildno = "1155";
+in multiStdenv.mkDerivation rec {
+ pname = "metamod-source";
+ version = "1.11_${buildno}";
+
+ src = fetchFromGitHub rec {
+ inherit owner;
+ repo = pname;
+ rev = "2009298c32735b6de1712ff88e2309c";
+ fetchSubmodules = true;
+ hash = "sha256-cPrllC3IljtV9SWn2NZbV8yHvehqLNGkZQ0RK07yCz4=";
+ };
+
+ nativeBuildInputs = [ ambuild ed ];
+
+ hardeningDisable = [ "all" ];
+
+ CXXFLAGS="-Wno-error=class-memaccess -Wno-error=format-truncation";
+
+ postPatch = ''
+ mkdir .git
+ echo "ref: refs/heads/main" > .git/HEAD
+ ed support/buildbot/generate_headers.py <<EOF
+ /^def get_git_version/;/return/a
+ def get_git_version():
+ return '${buildno}', '${builtins.substring 0 7 src.rev}', '${src.rev}'
+ .
+ w
+ EOF
+ ed AMBuildScript <<EOF
+ /tier1]/s|]|, '${libfinite}' ]|
+ w
+ EOF
+ '';
+
+ configurePhase = ''
+ ln -s ${hl2sdk} ${hl2sdk.name}
+
+ mkdir -p build
+ pushd build
+ python ../configure.py --sdks present
+ '';
+
+ buildPhase = ''
+ ambuild
+ popd
+ '';
+
+ installPhase = ''
+ mkdir $out
+ mv build/package $out/share
+ cp -r $src $out/include
+ '';
+
+ meta = with lib; {
+ description = "C++ plugin environment and detour library for the Source Engine";
+ homepage = "https://github.com/${owner}/${pname}";
+ platforms = platforms.unix;
+ license = licenses.zlib;
+ };
+}
diff --git a/srcds-pkgs/mkdepot.nix b/srcds-pkgs/mkdepot.nix
new file mode 100644
index 0000000..8c1acaa
--- /dev/null
+++ b/srcds-pkgs/mkdepot.nix
@@ -0,0 +1,19 @@
+{ lib, runCommand, fetchDepotFile }:
+name: caches: ps:
+with lib;
+let
+ emitStep = { FileName, Flags, Chunks, ... }@file:
+ if bitAnd Flags 64 != 0 || Chunks == [] then ''
+ mkdir -p $out/'${FileName}'
+ '' else let drv = fetchDepotFile file; in ''
+ mkdir -p $out/'${drv.passthru.dirname}'
+ ln -s '${drv}' $out/'${FileName}'
+ '';
+ emitManifest = cache: with cache.passthru; let
+ json = "${cache}/.DepotDownloader/${toString depot}_${manifest}.json";
+ mkStep = file: emitStep (file // { inherit cache; });
+ in concatMapStrings mkStep (importJSON json).Files;
+in runCommand name {} ''
+ ${concatMapStringsSep "\n" emitManifest caches}
+ ${ps}
+''
diff --git a/srcds-pkgs/plugins/Chat-Logger-Redux.nix b/srcds-pkgs/plugins/Chat-Logger-Redux.nix
new file mode 100644
index 0000000..7acbc79
--- /dev/null
+++ b/srcds-pkgs/plugins/Chat-Logger-Redux.nix
@@ -0,0 +1,19 @@
+{ lib, buildSMPlugin, fetchFromGitHub }:
+buildSMPlugin rec {
+ pname = "Chat-Logger-Redux";
+ version = "2021-09-06";
+
+ src = fetchFromGitHub {
+ owner = "Drixevel-Archive";
+ repo = pname;
+ rev = "5a297b1f3680d2c862ba914476902105c89a9213";
+ hash = "sha256-9jVRIRKX3axPYGV0vAWpikQuEQgzIdhcAMMIO2dPWU8=";
+ };
+
+ preBuild = ''
+ # the entire set of sourcemod headers are vendored in here for some reason
+ rm /build/scripting/include/*.inc
+ # i don't even know what to say about this one
+ rm /build/scripting/{compile.{dat,bat},spcomp.exe}
+ '';
+}
diff --git a/srcds-pkgs/plugins/Open-Fortress-Tools.nix b/srcds-pkgs/plugins/Open-Fortress-Tools.nix
new file mode 100644
index 0000000..86269ab
--- /dev/null
+++ b/srcds-pkgs/plugins/Open-Fortress-Tools.nix
@@ -0,0 +1,15 @@
+{ lib, buildSMPlugin, fetchFromGitHub }:
+buildSMPlugin rec {
+ pname = "Open-Fortress-Tools";
+ version = "2024-08-22";
+
+ src = fetchFromGitHub {
+ owner = "openfortress";
+ repo = "SM-${pname}";
+ rev = "05cb78a9411843e16ddab5f651edec5f481200b1";
+ hash = "sha256-Y2uCVB2fivzQq7bC7g8KK/qiido7qopv9tcLhEr/h6w=";
+ };
+
+ removePrebuilt = false;
+ dontBuild = true;
+}
diff --git a/srcds-pkgs/plugins/SteamTools.nix b/srcds-pkgs/plugins/SteamTools.nix
new file mode 100644
index 0000000..2755fa5
--- /dev/null
+++ b/srcds-pkgs/plugins/SteamTools.nix
@@ -0,0 +1,21 @@
+{ lib, buildSMPlugin, fetchFromGitHub, runCommand }:
+let
+ pname = "SteamTools";
+ src' = fetchFromGitHub {
+ # transitional syntax fork that's been sitting in PRs for 4 years ww
+ owner = "JoinedSenses";
+ repo = pname;
+ rev = "0ce8122e5d2a453c5b4b23fb2871bc24b35e27fe";
+ hash = "sha256-Vq60/GxwlyfYgQKjnMR8CaeyfMApJIvvZWD94o4LwYc=";
+ };
+in
+buildSMPlugin /* rec */ {
+ inherit pname;
+ version = "2020-05-01";
+
+ src = runCommand "source" {} ''
+ odir=$out/scripting/include
+ mkdir -p $odir
+ cp ${src'}/plugin/steamtools.inc $odir/
+ '';
+}
diff --git a/srcds-pkgs/plugins/SteamWorks.nix b/srcds-pkgs/plugins/SteamWorks.nix
new file mode 100644
index 0000000..169f6d0
--- /dev/null
+++ b/srcds-pkgs/plugins/SteamWorks.nix
@@ -0,0 +1,19 @@
+{ buildSMPlugin, fetchFromGitHub, runCommand }:
+let
+ src' = fetchFromGitHub {
+ owner = "KyleSanderson";
+ repo = "SteamWorks";
+ rev = "f0c1b62dff615511b27824aaa2815c7dc58d2716";
+ hash = "sha256-ugjaM04Jm1MKGmdtTAYVRD+ONOevc0PHAWqxBFSeu4o=";
+ };
+in
+buildSMPlugin rec {
+ pname = "SteamWorks";
+ version = "2023-04-02";
+
+ src = runCommand "source" {} ''
+ odir=$out/scripting/
+ mkdir -p $odir
+ cp -r ${src'}/Pawn/includes $odir/include
+ '';
+}
diff --git a/srcds-pkgs/plugins/Updater.nix b/srcds-pkgs/plugins/Updater.nix
new file mode 100644
index 0000000..3c252fd
--- /dev/null
+++ b/srcds-pkgs/plugins/Updater.nix
@@ -0,0 +1,28 @@
+{ fetchzip, buildSMPlugin, ed
+, SM-neocurl-ext, SteamTools, SteamWorks, socket
+}:
+buildSMPlugin rec {
+ pname = "Updater";
+ version = "1.2.1";
+
+ src = fetchzip {
+ url = "https://forums.alliedmods.net/attachment.php?attachmentid=183438";
+ extension = "zip";
+ stripRoot = false;
+ hash = "sha256-M+kUvHzwiJXOGIdbUql5nbFdCPdzYdRM1BCq6Y8Fuls=";
+ };
+
+ nativeBuildInputs = [ ed ];
+ buildInputs = [ SM-neocurl-ext SteamTools SteamWorks socket ];
+
+ postPatch = ''
+ ed scripting/updater.sp <<EOF
+ /"sm_updater"/s/2/1/
+ w
+ EOF
+ ed scripting/updater/plugins.sp <<EOF
+ /64] /s//64], /
+ w
+ EOF
+ '';
+}
diff --git a/srcds-pkgs/plugins/ftz_cheats.nix b/srcds-pkgs/plugins/ftz_cheats.nix
new file mode 100644
index 0000000..3e8d32c
--- /dev/null
+++ b/srcds-pkgs/plugins/ftz_cheats.nix
@@ -0,0 +1,14 @@
+{ lib, fetchzip, buildSMPlugin, smlib }:
+buildSMPlugin rec {
+ pname = "ftz_cheats";
+ version = "1.1";
+
+ src = fetchzip {
+ url = "https://forums.alliedmods.net/attachment.php?attachmentid=109393";
+ extension = "zip";
+ stripRoot = false;
+ hash = "sha256-05RRJuIldc6gvYkYcpQokFwKYvR+wMCgy7KylUi1vTY=";
+ };
+
+ buildInputs = [ smlib ];
+}
diff --git a/srcds-pkgs/plugins/morecolors.nix b/srcds-pkgs/plugins/morecolors.nix
new file mode 100644
index 0000000..325b353
--- /dev/null
+++ b/srcds-pkgs/plugins/morecolors.nix
@@ -0,0 +1,20 @@
+{ lib, fetchFromGitHub, stdenvNoCC }:
+stdenvNoCC.mkDerivation rec {
+ pname = "morecolors";
+ version = "2022-07-07";
+
+ src = fetchFromGitHub {
+ owner = "DoctorMcKay";
+ repo = "sourcemod-plugins";
+ rev = "6c7ffca2b580b3b313ee2027ac4dd12b7fad226a";
+ hash = "sha256-zmwyIMSwr2BV3feuiAZhUj2SAh5C+vp/HnGufYMpu60=";
+ };
+
+ phases = [ "unpackPhase" "installPhase" ];
+
+ installPhase = ''
+ odir=$out/share/addons/sourcemod/scripting/include
+ mkdir -p $odir
+ cp scripting/include/morecolors.inc $odir/
+ '';
+}
diff --git a/srcds-pkgs/plugins/nativevotes-updated.nix b/srcds-pkgs/plugins/nativevotes-updated.nix
new file mode 100644
index 0000000..4044294
--- /dev/null
+++ b/srcds-pkgs/plugins/nativevotes-updated.nix
@@ -0,0 +1,16 @@
+{ buildSMPlugin, fetchFromGitHub }:
+buildSMPlugin rec {
+ pname = "nativevotes-updated";
+ version = "2023-10-17";
+
+ src = fetchFromGitHub {
+ owner = "sapphonie";
+ repo = "sourcemod-${pname}";
+ rev = "47d00d636fd7bee3419fb310e4c3d8674278248d";
+ sha256 = "0yvlsclhdjsy0amrff3a6y2k2bfalcyrjp57s5jnxv30gqc3d1rg";
+ };
+
+ preConfigure = ''
+ cd addons/sourcemod
+ '';
+}
diff --git a/srcds-pkgs/plugins/openfrags.nix b/srcds-pkgs/plugins/openfrags.nix
new file mode 100644
index 0000000..07bb629
--- /dev/null
+++ b/srcds-pkgs/plugins/openfrags.nix
@@ -0,0 +1,16 @@
+{ buildSMPlugin, fetchFromGitHub
+, Updater, morecolors, Open-Fortress-Tools
+}:
+buildSMPlugin rec {
+ pname = "openfrags";
+ version = "2.2";
+
+ src = fetchFromGitHub {
+ owner = "TheRatest";
+ repo = pname;
+ rev = "3cece524f0b91364300c8c8618d41430af86be95";
+ hash = "sha256-qK3zcQm8+FA/xA0gFMlo2K6d+u+mpupMLyToOG3eMeg=";
+ };
+
+ buildInputs = [ morecolors Updater Open-Fortress-Tools ];
+}
diff --git a/srcds-pkgs/plugins/smlib.nix b/srcds-pkgs/plugins/smlib.nix
new file mode 100644
index 0000000..5f283c9
--- /dev/null
+++ b/srcds-pkgs/plugins/smlib.nix
@@ -0,0 +1,22 @@
+{ fetchFromGitHub, buildSMPlugin }:
+buildSMPlugin rec {
+ pname = "smlib";
+ version = "2022-01-11";
+
+ src = fetchFromGitHub {
+ owner = "bcserv";
+ repo = pname;
+ # transitional_syntax branch
+ rev = "2c14acb85314e25007f5a61789833b243e7d0cab";
+ hash = "sha256-yonYBCaEZGjbxhKvQ2NNVBpiUqyMxuchEgL+bsWomuo=";
+ };
+
+ postPatch = ''
+ sed -i \
+ '/#include <sdktools_entinput>/a #include <sdktools_variant_t>' \
+ scripting/include/smlib/entities.inc
+ '';
+
+ # technically unnecessary as buildPhase simply won't find anything to build
+ dontBuild = true;
+}
diff --git a/srcds-pkgs/plugins/socket.nix b/srcds-pkgs/plugins/socket.nix
new file mode 100644
index 0000000..5a7cdc2
--- /dev/null
+++ b/srcds-pkgs/plugins/socket.nix
@@ -0,0 +1,27 @@
+{ buildSMPlugin, fetchFromGitHub, runCommand }:
+let
+ src' = fetchFromGitHub {
+ owner = "nefarius";
+ repo = "sm-ext-socket";
+ rev = "ed6bf7a12bd3f801610592301e12062b367fa27b";
+ hash = "sha256-M13Nt58tlXXBO1fB2Y3vQLyD4Wlzrwd6mHWSf5JTUwY=";
+ };
+ /*
+ socket.src = fetchzip {
+ url = "http://forums.alliedmods.net/attachment.php?attachmentid=83286";
+ extension = "zip";
+ stripRoot = false;
+ hash = "sha256-EDCEyzSynz8Uotgx6xVmEiGgXf1FBtOzW1YNfsOad+U=";
+ };
+ */
+in
+buildSMPlugin rec {
+ pname = "socket";
+ version = "2018-11-14";
+
+ src = runCommand "source" {} ''
+ odir=$out/scripting/include
+ mkdir -p $odir
+ cp ${src'}/socket.inc $odir/
+ '';
+}
diff --git a/srcds-pkgs/plugins/yuuko_votes.nix b/srcds-pkgs/plugins/yuuko_votes.nix
new file mode 100644
index 0000000..fb11fad
--- /dev/null
+++ b/srcds-pkgs/plugins/yuuko_votes.nix
@@ -0,0 +1,13 @@
+{ lib, buildSMPlugin, fetchgit, SM-Memory }:
+buildSMPlugin rec {
+ pname = "yuuko_votes";
+ version = "2024-08-12";
+
+ src = fetchgit {
+ url = "https://git.partyvan.io/yuuko_votes";
+ rev = "acafa384e1dfec7d877bc4fcac0dc78e8f9429db";
+ hash = "sha256-PNCl9oM2j0CSiJp6jt0Cn9gGwGsbwmZ55xt/m05Tmzc=";
+ };
+
+ buildInputs = [ SM-Memory ];
+}
diff --git a/srcds-pkgs/sourcemod/default.nix b/srcds-pkgs/sourcemod/default.nix
new file mode 100644
index 0000000..90c31f9
--- /dev/null
+++ b/srcds-pkgs/sourcemod/default.nix
@@ -0,0 +1,82 @@
+{ lib, multiStdenv, pkgsi686Linux
+, writeShellScript
+, fetchFromGitHub, ed
+, hl2sdk, ambuild, metamod-source, libfinite
+, mysql_5_5
+}: let
+ inherit (pkgsi686Linux) zlib;
+ owner = "alliedmodders";
+ buildno = "6968";
+in multiStdenv.mkDerivation rec {
+ pname = "sourcemod";
+ version = "1.11_${buildno}";
+
+ src = fetchFromGitHub rec {
+ inherit owner;
+ repo = pname;
+ rev = "13510eab809a98b6a62354fc9848641";
+ fetchSubmodules = true;
+ hash = "sha256-leV0Q7g5bnJljzQxv3z6t5p/1d9TxILPvIuSYuq8LmE=";
+ };
+
+ nativeBuildInputs = [ ambuild ed ];
+ buildInputs = [ zlib mysql_5_5 ];
+
+ hardeningDisable = [ "all" ];
+
+ CXXFLAGS="-Wno-error=sign-compare -Wno-error=ignored-attributes";
+
+ postPatch = ''
+ mkdir .git
+ echo "ref: refs/heads/main" > .git/HEAD
+ ed tools/buildbot/generate_headers.py <<EOF
+ /^def get_git_version/;/return/a
+ def get_git_version():
+ return '${buildno}', '${builtins.substring 0 7 src.rev}', '${src.rev}'
+ .
+ w
+ EOF
+ for i in sdktools dhooks sdkhooks; do
+ sed -i '/invalid-offsetof/s,no-,no-error=,' extensions/$i/AMBuilder
+ done
+ ed AMBuildScript <<EOF
+ /'mathlib.a'/s|$|, '${libfinite}',|
+ w
+ EOF
+ '';
+
+ configurePhase = ''
+ ln -s ${hl2sdk} ${hl2sdk.name}
+ ln -s ${metamod-source}/include metamod-source
+ mkdir -p build
+ cd build
+ python ../configure.py --sdks present --mysql-path ${mysql_5_5}
+ '';
+
+ buildPhase = ''
+ ambuild
+ '';
+
+ installPhase = ''
+ mkdir $out
+ mv package $out/share
+ cd $out/share/addons/sourcemod/plugins
+ mv *.smx disabled/
+ mkdir -p $out/bin
+ cd $out/bin
+ cp ${writeShellScript "spcomp" ''
+ echo OUT/share/addons/sourcemod/scripting/spcomp $SPCOMPFLAGS "$@"
+ OUT/share/addons/sourcemod/scripting/spcomp $SPCOMPFLAGS "$@"
+ ''} ./spcomp
+ substituteInPlace ./spcomp --replace OUT "$out"
+ '';
+
+ setupHook = ./setup-hook.sh;
+
+ meta = with lib; {
+ description = "Source Engine scripting and administration";
+ homepage = "https://github.com/${owner}/${pname}";
+ platforms = platforms.unix;
+ license = licenses.gpl3;
+ };
+}
diff --git a/srcds-pkgs/sourcemod/setup-hook.sh b/srcds-pkgs/sourcemod/setup-hook.sh
new file mode 100644
index 0000000..17d8617
--- /dev/null
+++ b/srcds-pkgs/sourcemod/setup-hook.sh
@@ -0,0 +1,16 @@
+SPCOMPFLAGS=${SPCOMPFLAGS:-}
+dontUseSourcepawnFindHeaders=${dontUseSourcepawnFindHeaders:-}
+sourcepawnFindHeaders(){
+ [ -n "${dontUseSourcepawnFindHeaders:-}" ] && return
+ for plug in $buildInputs; do
+ local ipath="$plug/share/addons/sourcemod/scripting/include"
+ if [ -d "$ipath" ]; then
+ echo "found sourcepawn headers: \"$ipath\""
+ SPCOMPFLAGS="$SPCOMPFLAGS -i $ipath"
+ fi
+ done
+ dontUseSourcepawnFindHeaders=1
+ export SPCOMPFLAGS dontUseSourcepawnFindHeaders
+}
+
+addEnvHooks "$targetOffset" sourcepawnFindHeaders