at 16.09-beta 4.1 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.factorio; 7 factorio = pkgs.factorio-headless; 8 name = "Factorio"; 9 stateDir = "/var/lib/factorio"; 10 mkSavePath = name: "${stateDir}/saves/${name}.zip"; 11 configFile = pkgs.writeText "factorio.conf" '' 12 use-system-read-write-data-directories=true 13 [path] 14 read-data=${factorio}/share/factorio/data 15 write-data=${stateDir} 16 ''; 17 modDir = pkgs.factorio-mkModDirDrv cfg.mods; 18in 19{ 20 options = { 21 services.factorio = { 22 enable = mkEnableOption name; 23 port = mkOption { 24 type = types.int; 25 default = 34197; 26 description = '' 27 The port to which the service should bind. 28 29 This option will also open up the UDP port in the firewall configuration. 30 ''; 31 }; 32 saveName = mkOption { 33 type = types.string; 34 default = "default"; 35 description = '' 36 The name of the savegame that will be used by the server. 37 38 When not present in ${stateDir}/saves, a new map with default 39 settings will be generated before starting the service. 40 ''; 41 }; 42 # TODO Add more individual settings as nixos-options? 43 # TODO XXX The server tries to copy a newly created config file over the old one 44 # on shutdown, but fails, because it's in the nix store. When is this needed? 45 # Can an admin set options in-game and expect to have them persisted? 46 configFile = mkOption { 47 type = types.path; 48 default = configFile; 49 defaultText = "configFile"; 50 description = '' 51 The server's configuration file. 52 53 The default file generated by this module contains lines essential to 54 the server's operation. Use its contents as a basis for any 55 customizations. 56 ''; 57 }; 58 mods = mkOption { 59 type = types.listOf types.package; 60 default = []; 61 description = '' 62 Mods the server should install and activate. 63 64 The derivations in this list must "build" the mod by simply copying 65 the .zip, named correctly, into the output directory. Eventually, 66 there will be a way to pull in the most up-to-date list of 67 derivations via nixos-channel. Until then, this is for experts only. 68 ''; 69 }; 70 autosave-interval = mkOption { 71 type = types.nullOr types.int; 72 default = null; 73 example = 2; 74 description = '' 75 The time, in minutes, between autosaves. 76 ''; 77 }; 78 }; 79 }; 80 81 config = mkIf cfg.enable { 82 users = { 83 users.factorio = { 84 uid = config.ids.uids.factorio; 85 description = "Factorio server user"; 86 group = "factorio"; 87 home = stateDir; 88 createHome = true; 89 }; 90 91 groups.factorio = { 92 gid = config.ids.gids.factorio; 93 }; 94 }; 95 96 systemd.services.factorio = { 97 description = "Factorio headless server"; 98 wantedBy = [ "multi-user.target" ]; 99 after = [ "network.target" ]; 100 101 preStart = toString [ 102 "test -e ${stateDir}/saves/${cfg.saveName}.zip" 103 "||" 104 "${factorio}/bin/factorio" 105 "--config=${cfg.configFile}" 106 "--create=${mkSavePath cfg.saveName}" 107 (optionalString (cfg.mods != []) "--mod-directory=${modDir}") 108 ]; 109 110 serviceConfig = { 111 User = "factorio"; 112 Group = "factorio"; 113 Restart = "always"; 114 KillSignal = "SIGINT"; 115 WorkingDirectory = stateDir; 116 PrivateTmp = true; 117 UMask = "0007"; 118 ExecStart = toString [ 119 "${factorio}/bin/factorio" 120 "--config=${cfg.configFile}" 121 "--port=${toString cfg.port}" 122 "--start-server=${mkSavePath cfg.saveName}" 123 (optionalString (cfg.mods != []) "--mod-directory=${modDir}") 124 (optionalString (cfg.autosave-interval != null) "--autosave-interval ${toString cfg.autosave-interval}") 125 ]; 126 }; 127 }; 128 129 networking.firewall.allowedUDPPorts = [ cfg.port ]; 130 }; 131}