{ pkgs, lib, config, ... }: let inherit (lib) mkEnableOption mkIf mkOption types getExe makeBinPath ; cfg = config.services.minecraft.curseforge; in { options.services.minecraft.curseforge = { enable = mkEnableOption "Enable Minecraft server service."; modpackZip = mkOption { type = types.package; }; modpackName = mkOption { type = types.str; }; modpacksChHash = mkOption { type = types.str; }; javaPackage = mkOption { type = types.package; default = pkgs.jdk17; }; serverPackage = mkOption { type = types.package; readOnly = true; }; eulaAccept = mkOption { type = with types; bool; description = '' By changing the setting below to true you are indicating your agreement to Mojang's EULA (https://account.mojang.com/documents/minecraft_eula). ''; default = false; }; extraJavaArguments = mkOption { type = with types; listOf str; default = []; }; extraFixup = mkOption { type = types.lines; default = ""; }; }; config = mkIf cfg.enable { services.minecraft.curseforge.serverPackage = let curseforgeFod = pkgs.stdenv.mkDerivation { pname = "minecraft-curseforge-${cfg.modpackName}"; version = "unknown"; outputHashMode = "recursive"; outputHashAlgo = "sha256"; outputHash = cfg.modpacksChHash; buildInputs = with pkgs; [unzip curl which cacert cfg.javaPackage]; src = cfg.modpackZip; phases = ["installPhase" "fixupPhase "]; installPhase = '' mkdir -p $out/ cp $src/server-setup-config.yaml $out/ cd $out/ sh -vx $src/start-server.sh install rm installer.jar.log rm -r libraries/net/minecraft/server # libraries/net/minecraft/server/1.16.5-20210115.111550/server-1.16.5-20210115.111550-srg.jar ''; meta.license = with lib.licenses; unfree; }; in pkgs.writeShellScriptBin "minecraft-curseforge-unknown" '' export PATH="${makeBinPath (with pkgs; [curl cfg.javaPackage yq])}:$PATH" echo minecraft booting function cleanup() { echo "minecraft cleaning up..." kill -TERM $_server while kill -0 $_server ; do wait "$_server" done echo "minecraft server exited..." ${getExe pkgs.symlink-state} destroy ${curseforgeFod} $PWD exit 0 } trap cleanup TERM RW_PATHS=config:defaultconfigs ${getExe pkgs.symlink-state} setup ${curseforgeFod} $PWD MC_VERSION="$(yq -r '.install.mcVersion' ${curseforgeFod}/server-setup-config.yaml)" INSTALLER_URL="$(yq -r '.install.installerUrl' ${curseforgeFod}/server-setup-config.yaml)" LOADER_VERSION="$(yq -r '(.minecraft.modLoaders[] | select(.primary) | .).id' ${curseforgeFod}/manifest.json | cut -d '-' -f 2)" START_FILE="$(yq -r '.launch.startFile' ${curseforgeFod}/server-setup-config.yaml | sed -e 's/{{@mcversion@}}/'"$MC_VERSION/g" -e 's/{{@loaderversion@}}/'"$LOADER_VERSION/g" -)" START_COMMAND="$(yq -r '.launch.startCommand | join(" ")' ${curseforgeFod}/server-setup-config.yaml | sed -e 's/{{@startFile@}}/'"$START_FILE/g" -)" JAVA_ARGS="$(yq -r '.launch.javaArgs | join(" ")' ${curseforgeFod}/server-setup-config.yaml)" curl -L "$(sed -e 's/{{@loaderversion@}}/'"$LOADER_VERSION/g" -e 's/{{@mcversion@}}/'"$MC_VERSION/g" - <<<"$INSTALLER_URL")" -o forge-installer.jar java -jar forge-installer.jar --installServer >/dev/null 2>&1 java $JAVA_ARGS $START_COMMAND & _server="$!" wait "$_server" ''; init.services.minecraft-curseforge = { script = pkgs.writeShellScript "minecraft-run" '' mkdir -p /var/lib/minecraft/curseforge cd /var/lib/minecraft/curseforge echo "eula=true" > eula.txt exec ${getExe cfg.serverPackage} ''; enabled = true; }; assertions = [ { assertion = cfg.eulaAccept; message = "You must accept the EULA"; } ]; }; }