Major changes to the minecraft-clj service
This commit is contained in:
parent
4c31509ad3
commit
38a4d75c82
@ -40,13 +40,58 @@ let
|
|||||||
"-Daikars.new.flags=true"
|
"-Daikars.new.flags=true"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
worldOpts = { name, ... }:
|
||||||
|
let world-name = name;
|
||||||
in {
|
in {
|
||||||
options.fudo.minecraft-clj = with types; {
|
options = with types; {
|
||||||
enable = mkEnableOption "Enable Minecraft server with Clojure repl.";
|
enable = mkEnableOption "Enable this world.";
|
||||||
|
|
||||||
data-dir = mkOption {
|
world-name = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path at which to store Minecraft data.";
|
description = "Name of this world.";
|
||||||
|
default = world-name;
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Port on which to run this Minecraft world.";
|
||||||
|
default = 25565;
|
||||||
|
};
|
||||||
|
|
||||||
|
difficulty = mkOption {
|
||||||
|
type = enum [ "peaceful" "easy" "medium" "hard" ];
|
||||||
|
description = "Difficulty setting of this server.";
|
||||||
|
default = "medium";
|
||||||
|
};
|
||||||
|
|
||||||
|
game-mode = mkOption {
|
||||||
|
type = enum [ "survival" "creative" "adventure" "spectator" ];
|
||||||
|
description = "Game mode of the server.";
|
||||||
|
default = "survival";
|
||||||
|
};
|
||||||
|
|
||||||
|
hardcore = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Give players only one life to live.";
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
world-seed = mkOption {
|
||||||
|
type = nullOr int;
|
||||||
|
description = "Seed to use while generating the world.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
motd = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Message with which to greet users.";
|
||||||
|
default = "Welcome to ${world-name}";
|
||||||
|
};
|
||||||
|
|
||||||
|
allow-cheats = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Allow cheats on this server.";
|
||||||
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
allocated-memory = mkOption {
|
allocated-memory = mkOption {
|
||||||
@ -55,6 +100,57 @@ in {
|
|||||||
default = 4;
|
default = 4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pvp = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Allow player-vs-player combat.";
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
validChar = c: !isNull (builtins.match "^[a-zA-Z0-9_-]$" c);
|
||||||
|
|
||||||
|
swapSpace = replaceStrings [ " " ] [ "_" ];
|
||||||
|
|
||||||
|
sanitizeName = name:
|
||||||
|
concatStringsSep ""
|
||||||
|
(filter validChar (stringToCharacters (swapSpace name)));
|
||||||
|
|
||||||
|
worldStateDir = worldOpts:
|
||||||
|
"${cfg.state-directory}/${sanitizeName worldOpts.world-name}";
|
||||||
|
|
||||||
|
genProps = worldOpts: {
|
||||||
|
level-name = worldOpts.world-name;
|
||||||
|
level-seed = worldOpts.world-seed;
|
||||||
|
motd = worldOpts.motd;
|
||||||
|
difficulty = worldOpts.difficulty;
|
||||||
|
gamemode = cfg.game-mode;
|
||||||
|
allow-cheats = worldOpts.allowCheats;
|
||||||
|
server-port = worldOpts.port;
|
||||||
|
hardcore = worldOpts.hardcore;
|
||||||
|
pvp = worldOpts.pvp;
|
||||||
|
};
|
||||||
|
|
||||||
|
toProps = attrs:
|
||||||
|
let
|
||||||
|
boolToString = v: if v then "true" else "false";
|
||||||
|
toVal = v: if isBool v then boolToString v else toString v;
|
||||||
|
toProp = k: v: "${k}=${toVal v}";
|
||||||
|
in concatStringsSep "\n" (mapAttrsToList toProp attrs);
|
||||||
|
|
||||||
|
genPropsFile = worldOpts:
|
||||||
|
pkgs.writeText "mc-${sanitizeName worldOpts.world-name}.properties"
|
||||||
|
(toProps (genProps worldOpts));
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.minecraft-clj = with types; {
|
||||||
|
enable = mkEnableOption "Enable Minecraft server with Clojure repl.";
|
||||||
|
|
||||||
|
state-directory = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Path at which to store Minecraft data.";
|
||||||
|
};
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "User as which to run the minecraft server.";
|
description = "User as which to run the minecraft server.";
|
||||||
@ -66,6 +162,18 @@ in {
|
|||||||
description = "Group as which to run the minecraft server.";
|
description = "Group as which to run the minecraft server.";
|
||||||
default = "minecraft-clj";
|
default = "minecraft-clj";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
admins = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "List of users to treat as administrators.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
worlds = mkOption {
|
||||||
|
type = attrsOf (submodule worldOpts);
|
||||||
|
description = "List of worlds to run on this server.";
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@ -79,15 +187,39 @@ in {
|
|||||||
groups."${cfg.group}" = { members = [ cfg.user ]; };
|
groups."${cfg.group}" = { members = [ cfg.user ]; };
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.minecraft-clj = {
|
systemd = {
|
||||||
description = "Minecraft server with Clojure REPL.";
|
tmpfiles.rules = map (worldOpts:
|
||||||
|
"d ${worldStateDir worldOpts} 0700 ${cfg.user} ${cfg.group} - -")
|
||||||
|
(attrValues cfg.worlds);
|
||||||
|
|
||||||
|
services = mapAttrs' (_: worldOpts:
|
||||||
|
let
|
||||||
|
sanitizedName = sanitizeName worldOpts.world-name;
|
||||||
|
serverName = "minecraft-clj-${sanitizedName}";
|
||||||
|
stateDir = worldStateDir worldOpts;
|
||||||
|
startScript = let
|
||||||
|
admins-file = pkgs.writeText "${sanitizedName}-ops.txt"
|
||||||
|
(concatStringsSep "\n" cfg.admins);
|
||||||
|
props-file = genPropsFile worldOpts;
|
||||||
|
|
||||||
|
in pkgs.writeShellScript "mc-initialize-${sanitizedName}.sh" ''
|
||||||
|
cp -f ${admins-file} ${stateDir}/ops.txt
|
||||||
|
cp -f ${props-file} ${stateDir}/server.properties
|
||||||
|
chmod u+w ${stateDir}/server.properties
|
||||||
|
'';
|
||||||
|
|
||||||
|
in nameValuePair serverName {
|
||||||
|
enable = worldOpts.enable;
|
||||||
|
description =
|
||||||
|
"${worldOpts.world-name} Minecraft Server with Clojure REPL";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
Group = cfg.group;
|
Group = cfg.group;
|
||||||
|
WorkingDirectory = stateDir;
|
||||||
ExecStart = let
|
ExecStart = let
|
||||||
mem = "${toString cfg.allocated-memory}G";
|
mem = "${toString worldOpts.allocated-memory}G";
|
||||||
memFlags = [ "-Xms${mem}" "-Xmx${mem}" ];
|
memFlags = [ "-Xms${mem}" "-Xmx${mem}" ];
|
||||||
flags = commonFlags ++ memFlags
|
flags = commonFlags ++ memFlags
|
||||||
++ (optionals (cfg.allocated-memory >= 12) highMemFlags);
|
++ (optionals (cfg.allocated-memory >= 12) highMemFlags);
|
||||||
@ -106,8 +238,8 @@ in {
|
|||||||
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
||||||
RestrictRealtime = true;
|
RestrictRealtime = true;
|
||||||
RestrictNamespaces = true;
|
RestrictNamespaces = true;
|
||||||
MemoryDenyWriteExecute = true;
|
|
||||||
};
|
};
|
||||||
|
}) cfg.worlds;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user