{ config, lib, ... }: let cfg = config.guests.palworld; steamDir = "/data/steamcmd"; installDir = "/data/server"; stateDir = "/data/state"; in { options.guests.palworld = { steamPath = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; example = "/srv/steamcmd"; description = "Host path bind-mounted as SteamCMD's metadata directory."; }; installPath = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; example = "/srv/palworld/server"; description = "Host path bind-mounted as Palworld's server install directory."; }; statePath = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; example = "/srv/palworld/state"; description = "Host path bind-mounted as Palworld's durable state directory."; }; serverName = lib.mkOption { type = lib.types.str; default = "palworld"; description = "Name shown for the Palworld server."; }; port = lib.mkOption { type = lib.types.port; default = 8211; description = "UDP port for the Palworld server."; }; publicIP = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = "Public IP address advertised by the Palworld server."; }; passwordSecret = lib.mkOption { type = lib.types.str; default = "services/game-servers/password"; description = "SOPS secret name containing the Palworld server password."; }; adminPasswordSecret = lib.mkOption { type = lib.types.str; default = "services/game-servers/password"; description = "SOPS secret name containing the Palworld admin password."; }; }; config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.steamPath != null; message = "guests.palworld.steamPath must point at the host directory that stores SteamCMD metadata."; } { assertion = cfg.installPath != null; message = "guests.palworld.installPath must point at the host directory that stores Palworld server files."; } { assertion = cfg.statePath != null; message = "guests.palworld.statePath must point at the host directory that stores Palworld durable state."; } ]; guests.palworld = { interior.modules.services.games.palworld = { enable = true; inherit (cfg) serverName port publicIP; inherit steamDir installDir stateDir; passwordFile = "/run/secrets/${cfg.passwordSecret}"; adminPasswordFile = "/run/secrets/${cfg.adminPasswordSecret}"; }; mounts = { ${steamDir} = { directory = cfg.steamPath; owner = config.registry."stable-uid".${config.networking.hostName}.steamcmd; group = "storage"; mode = "0770"; }; ${installDir} = { directory = cfg.installPath; owner = config.registry."stable-uid".${config.networking.hostName}.steamcmd; group = "storage"; mode = "0770"; }; ${stateDir} = { directory = cfg.statePath; owner = config.registry."stable-uid".${config.networking.hostName}.steamcmd; group = "storage"; mode = "0770"; }; ${"/run/secrets/${cfg.passwordSecret}"} = { file = config.sops.secrets.${cfg.passwordSecret}.path; readOnly = true; }; } // lib.optionalAttrs (cfg.adminPasswordSecret != cfg.passwordSecret) { ${"/run/secrets/${cfg.adminPasswordSecret}"} = { file = config.sops.secrets.${cfg.adminPasswordSecret}.path; readOnly = true; }; }; limits = { memory = lib.mkDefault "8G"; cpu = lib.mkDefault "400%"; tasksMax = lib.mkDefault 2048; }; }; sops.secrets = { ${cfg.passwordSecret} = { owner = "root"; group = "storage"; mode = "0440"; }; } // lib.optionalAttrs (cfg.adminPasswordSecret != cfg.passwordSecret) { ${cfg.adminPasswordSecret} = { owner = "root"; group = "storage"; mode = "0440"; }; }; }; }