1 { config, lib, pkgs, ... }:
3 CONTAINS_NEWLINE_RE = ".*\n.*";
4 # The following values are reserved as complete option values:
5 # { - start of a group.
6 # """ - start of a multi-line string.
7 RESERVED_VALUE_RE = "[[:space:]]*(\"\"\"|\\{)[[:space:]]*";
8 NEEDS_MULTILINE_RE = "${CONTAINS_NEWLINE_RE}|${RESERVED_VALUE_RE}";
10 # There is no way to encode """ on its own line in a Minetest config.
11 UNESCAPABLE_RE = ".*\n\"\"\"\n.*";
13 toConfMultiline = name: value:
15 ((builtins.match UNESCAPABLE_RE value) == null)
16 ''""" can't be on its own line in a minetest config.'';
17 "${name} = \"\"\"\n${value}\n\"\"\"\n";
23 bool = "${name} = ${toString value}\n";
24 int = "${name} = ${toString value}\n";
26 set = "${name} = {\n${toConf value}}\n";
28 if (builtins.match NEEDS_MULTILINE_RE value) != null
29 then toConfMultiline name value
30 else "${name} = ${value}\n";
31 }.${builtins.typeOf value})
34 cfg = config.services.minetest-server;
35 flag = val: name: lib.optionals (val != null) ["--${name}" "${toString val}"];
41 if cfg.configPath != null
42 then ["--config" cfg.configPath]
43 else ["--config" (builtins.toFile "minetest.conf" (toConf cfg.config))])
44 ++ (flag cfg.gameId "gameid")
45 ++ (flag cfg.world "world")
46 ++ (flag cfg.logPath "logfile")
47 ++ (flag cfg.port "port")
52 services.minetest-server = {
53 enable = lib.mkOption {
54 type = lib.types.bool;
56 description = "If enabled, starts a Minetest Server.";
59 gameId = lib.mkOption {
60 type = lib.types.nullOr lib.types.str;
63 Id of the game to use. To list available games run
64 `minetestserver --gameid list`.
66 If only one game exists, this option can be null.
70 world = lib.mkOption {
71 type = lib.types.nullOr lib.types.path;
74 Name of the world to use. To list available worlds run
75 `minetestserver --world list`.
77 If only one world exists, this option can be null.
81 configPath = lib.mkOption {
82 type = lib.types.nullOr lib.types.path;
85 Path to the config to use.
87 If set to null, the config of the running user will be used:
88 `~/.minetest/minetest.conf`.
92 config = lib.mkOption {
93 type = lib.types.attrsOf lib.types.anything;
96 Settings to add to the minetest config file.
98 This option is ignored if `configPath` is set.
102 logPath = lib.mkOption {
103 type = lib.types.nullOr lib.types.path;
106 Path to logfile for logging.
108 If set to null, logging will be output to stdout which means
109 all output will be caught by systemd.
113 port = lib.mkOption {
114 type = lib.types.nullOr lib.types.int;
117 Port number to bind to.
119 If set to null, the default 30000 will be used.
123 extraArgs = lib.mkOption {
124 type = lib.types.listOf lib.types.str;
127 Additional command line flags to pass to the minetest executable.
133 config = lib.mkIf cfg.enable {
134 users.users.minetest = {
135 description = "Minetest Server Service user";
136 home = "/var/lib/minetest";
138 uid = config.ids.uids.minetest;
141 users.groups.minetest.gid = config.ids.gids.minetest;
143 systemd.services.minetest-server = {
144 description = "Minetest Server Service";
145 wantedBy = [ "multi-user.target" ];
146 after = [ "network.target" ];
148 serviceConfig.Restart = "always";
149 serviceConfig.User = "minetest";
150 serviceConfig.Group = "minetest";
155 exec ${pkgs.minetest}/bin/minetest ${lib.escapeShellArgs flags}