lol

nixos/xonotic: init

authored by

Charles Hall and committed by
Anderson Torres
94a42157 2d40e2e5

+199
+1
nixos/modules/module-list.nix
··· 499 499 ./services/games/quake3-server.nix 500 500 ./services/games/teeworlds.nix 501 501 ./services/games/terraria.nix 502 + ./services/games/xonotic.nix 502 503 ./services/hardware/acpid.nix 503 504 ./services/hardware/actkbd.nix 504 505 ./services/hardware/argonone.nix
+198
nixos/modules/services/games/xonotic.nix
··· 1 + { config 2 + , pkgs 3 + , lib 4 + , ... 5 + }: 6 + 7 + let 8 + cfg = config.services.xonotic; 9 + 10 + serverCfg = pkgs.writeText "xonotic-server.cfg" ( 11 + toString cfg.prependConfig 12 + + "\n" 13 + + builtins.concatStringsSep "\n" ( 14 + lib.mapAttrsToList (key: option: 15 + let 16 + escape = s: lib.escape [ "\"" ] s; 17 + quote = s: "\"${s}\""; 18 + 19 + toValue = x: quote (escape (toString x)); 20 + 21 + value = (if lib.isList option then 22 + builtins.concatStringsSep 23 + " " 24 + (builtins.map (x: toValue x) option) 25 + else 26 + toValue option 27 + ); 28 + in 29 + "${key} ${value}" 30 + ) cfg.settings 31 + ) 32 + + "\n" 33 + + toString cfg.appendConfig 34 + ); 35 + in 36 + 37 + { 38 + options.services.xonotic = { 39 + enable = lib.mkEnableOption (lib.mdDoc "Xonotic dedicated server"); 40 + 41 + package = lib.mkPackageOption pkgs "xonotic-dedicated" {}; 42 + 43 + openFirewall = lib.mkOption { 44 + type = lib.types.bool; 45 + default = false; 46 + description = lib.mdDoc '' 47 + Open the firewall for TCP and UDP on the specified port. 48 + ''; 49 + }; 50 + 51 + dataDir = lib.mkOption { 52 + type = lib.types.path; 53 + readOnly = true; 54 + default = "/var/lib/xonotic"; 55 + description = lib.mdDoc '' 56 + Data directory. 57 + ''; 58 + }; 59 + 60 + settings = lib.mkOption { 61 + description = lib.mdDoc '' 62 + Generates the `server.cfg` file. Refer to [upstream's example][0] for 63 + details. 64 + 65 + [0]: https://gitlab.com/xonotic/xonotic/-/blob/master/server/server.cfg 66 + ''; 67 + default = {}; 68 + type = lib.types.submodule { 69 + freeformType = with lib.types; let 70 + scalars = oneOf [ singleLineStr int float ]; 71 + in 72 + attrsOf (oneOf [ scalars (nonEmptyListOf scalars) ]); 73 + 74 + options.sv_public = lib.mkOption { 75 + type = lib.types.int; 76 + default = 0; 77 + example = [ (-1) 1 ]; 78 + description = lib.mdDoc '' 79 + Controls whether the server will be publicly listed. 80 + ''; 81 + }; 82 + 83 + options.hostname = lib.mkOption { 84 + type = lib.types.singleLineStr; 85 + default = "Xonotic $g_xonoticversion Server"; 86 + description = lib.mdDoc '' 87 + The name that will appear in the server list. `$g_xonoticversion` 88 + gets replaced with the current version. 89 + ''; 90 + }; 91 + 92 + options.sv_motd = lib.mkOption { 93 + type = lib.types.singleLineStr; 94 + default = ""; 95 + description = lib.mdDoc '' 96 + Text displayed when players join the server. 97 + ''; 98 + }; 99 + 100 + options.sv_termsofservice_url = lib.mkOption { 101 + type = lib.types.singleLineStr; 102 + default = ""; 103 + description = lib.mdDoc '' 104 + URL for the Terms of Service for playing on your server. 105 + ''; 106 + }; 107 + 108 + options.maxplayers = lib.mkOption { 109 + type = lib.types.int; 110 + default = 16; 111 + description = lib.mdDoc '' 112 + Number of player slots on the server, including spectators. 113 + ''; 114 + }; 115 + 116 + options.net_address = lib.mkOption { 117 + type = lib.types.singleLineStr; 118 + default = "0.0.0.0"; 119 + description = lib.mdDoc '' 120 + The address Xonotic will listen on. 121 + ''; 122 + }; 123 + 124 + options.port = lib.mkOption { 125 + type = lib.types.port; 126 + default = 26000; 127 + description = lib.mdDoc '' 128 + The port Xonotic will listen on. 129 + ''; 130 + }; 131 + }; 132 + }; 133 + 134 + # Still useful even though we're using RFC 42 settings because *some* keys 135 + # can be repeated. 136 + appendConfig = lib.mkOption { 137 + type = with lib.types; nullOr lines; 138 + default = null; 139 + description = lib.mdDoc '' 140 + Literal text to insert at the end of `server.cfg`. 141 + ''; 142 + }; 143 + 144 + # Certain changes need to happen at the beginning of the file. 145 + prependConfig = lib.mkOption { 146 + type = with lib.types; nullOr lines; 147 + default = null; 148 + description = lib.mdDoc '' 149 + Literal text to insert at the start of `server.cfg`. 150 + ''; 151 + }; 152 + }; 153 + 154 + config = lib.mkIf cfg.enable { 155 + systemd.services.xonotic = { 156 + description = "Xonotic server"; 157 + wantedBy = [ "multi-user.target" ]; 158 + 159 + environment = { 160 + # Required or else it tries to write the lock file into the nix store 161 + HOME = cfg.dataDir; 162 + }; 163 + 164 + serviceConfig = { 165 + DynamicUser = true; 166 + User = "xonotic"; 167 + StateDirectory = "xonotic"; 168 + ExecStart = "${cfg.package}/bin/xonotic-dedicated"; 169 + 170 + # Symlink the configuration from the nix store to where Xonotic actually 171 + # looks for it 172 + ExecStartPre = [ 173 + "${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/.xonotic/data" 174 + '' 175 + ${pkgs.coreutils}/bin/ln -sf ${serverCfg} \ 176 + ${cfg.dataDir}/.xonotic/data/server.cfg 177 + '' 178 + ]; 179 + 180 + # Cargo-culted from search results about writing Xonotic systemd units 181 + ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; 182 + 183 + Restart = "on-failure"; 184 + RestartSec = 10; 185 + StartLimitBurst = 5; 186 + }; 187 + }; 188 + 189 + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 190 + cfg.settings.port 191 + ]; 192 + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 193 + cfg.settings.port 194 + ]; 195 + }; 196 + 197 + meta.maintainers = with lib.maintainers; [ CobaltCause ]; 198 + }