From 32c5967e2c31e48b2e1cede8dbf4e352c5db2f9b Mon Sep 17 00:00:00 2001 From: Jonas Heinrich Date: Mon, 3 Aug 2026 13:32:13 +0200 Subject: [PATCH] nixos/quake3-server: add settings option --- .../manual/release-notes/rl-2611.section.md | 2 + .../modules/services/games/quake3-server.nix | 82 +++++++++++++++---- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2611.section.md b/nixos/doc/manual/release-notes/rl-2611.section.md index d921a1ec1cb2..26306ef76d45 100644 --- a/nixos/doc/manual/release-notes/rl-2611.section.md +++ b/nixos/doc/manual/release-notes/rl-2611.section.md @@ -199,6 +199,8 @@ - `services.pfix-srsd` and the supporting `pfixtools` package have been removed, as the project is dormant and does not support pcre2. `services.postsrsd` is the recommended replacement for Sender Rewriting Scheme support with Postfix. +- `services.quake3-server.port` has been removed in favor of the structured [](#opt-services.quake3-server.settings.net_port) option. Use `services.quake3-server.settings.net_port` to set any custom UDP port directly. + - Package `overseerr` has been removed as the `overseerr` and `jellyseerr` projects were merged under `seerr`. - The papra NixOS module is now hardening the systemd unit by default. If this breaks any of the configured directories, please reconfigure them through `services.papra.environment` to enable sandbox passthrough. diff --git a/nixos/modules/services/games/quake3-server.nix b/nixos/modules/services/games/quake3-server.nix index 43aad73a4b04..a57535c88a3a 100644 --- a/nixos/modules/services/games/quake3-server.nix +++ b/nixos/modules/services/games/quake3-server.nix @@ -15,9 +15,16 @@ let ; cfg = config.services.quake3-server; - configFile = pkgs.writeText "q3ds-extra.cfg" '' - set net_port ${toString cfg.port} + toQuake3Value = value: if lib.isBool value then (if value then "1" else "0") else toString value; + toQuake3Config = + settings: + lib.concatStrings ( + lib.mapAttrsToList (name: value: ''seta ${name} "${toQuake3Value value}"'' + "\n") settings + ); + + configFile = pkgs.writeText "q3ds-extra.cfg" '' + ${toQuake3Config cfg.settings} ${cfg.extraConfig} ''; @@ -50,19 +57,19 @@ let ''; in { + + imports = [ + (lib.mkRenamedOptionModule + [ "services" "quake3-server" "port" ] + [ "services" "quake3-server" "settings" "net_port" ] + ) + ]; + options = { services.quake3-server = { enable = mkEnableOption "Quake 3 dedicated server"; package = lib.mkPackageOption pkgs "ioquake3" { }; - port = mkOption { - type = types.port; - default = 27960; - description = '' - UDP Port the server should listen on. - ''; - }; - openFirewall = mkOption { type = types.bool; default = false; @@ -71,16 +78,59 @@ in ''; }; + settings = mkOption { + type = types.submodule { + freeformType = types.attrsOf ( + types.nullOr ( + types.oneOf [ + types.str + types.bool + types.int + types.float + types.port + ] + ) + ); + options = { + net_port = lib.mkOption { + type = lib.types.port; + default = 27960; + description = "UDP port for the dedicated server to bind to."; + }; + }; + }; + default = { }; + example = { + sv_hostname = "My Quake 3 server"; + g_gametype = 0; + sv_pure = true; + }; + description = '' + Quake 3 cvars set via `seta` on server start (i.e. persisted, + archive-flagged cvars – the vast majority of server settings). + Note that options changed via RCON will not be persisted. To list + all possible options, use "cvarlist 1" via RCON. + ''; + }; + extraConfig = mkOption { type = types.lines; default = ""; example = '' - seta rconPassword "superSecret" // sets RCON password for remote console - seta sv_hostname "My Quake 3 server" // name that appears in server list + // map rotation and other things that don't map onto plain cvars + set d1 "map q3dm1 ; set nextmap vstr d2" + set d2 "map q3dm7 ; set nextmap vstr d1" + vstr d1 + + // rarely needed: cvars with a non-seta flag + sets sv_privatePassword "hidden" ''; description = '' - Extra configuration options. Note that options changed via RCON will not be persisted. To list all possible - options, use "cvarlist 1" via RCON. + Extra configuration lines appended after `settings`, for anything + that isn't a plain persisted cvar: map-rotation scripts, `exec`, + `vstr`, aliases, or cvars that need `set`/`sets`/`sett`/`setu` + instead of `seta`. Note that options changed via RCON will not be + persisted. To list all possible options, use "cvarlist 1" via RCON. ''; }; @@ -103,7 +153,7 @@ in baseq3InStore = builtins.typeOf cfg.baseq3 == "set"; in mkIf cfg.enable { - networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ cfg.port ]; + networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ cfg.settings.net_port ]; systemd.services.q3ds = { description = "Quake 3 dedicated server"; @@ -115,7 +165,7 @@ in serviceConfig = with lib; { Restart = "always"; DynamicUser = true; - WorkingDirectory = home; + WorkingDirectory = if baseq3InStore then home else cfg.baseq3; # It is possible to alter configuration files via RCON. To ensure reproducibility we have to prevent this ReadOnlyPaths = if baseq3InStore then home else cfg.baseq3;