{ pkgs, config, lib, ... }: with lib; let cfg = config.services.minecraft.forge; in { options.services.minecraft.forge = { enable = mkEnableOption "Enable Minecraft server service."; modpackId = mkOption { type = types.int; }; versionId = mkOption { type = types.int; }; 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.forge.serverPackage = let forgeFod = pkgs.stdenv.mkDerivation { pname = "minecraft"; version = "unknown"; outputHashMode = "recursive"; outputHashAlgo = "sha256"; outputHash = cfg.modpacksChHash; buildInputs = with pkgs; [ unzip curl which cacert ]; phases = [ "fetchPhase" "installPhase" "fixupPhase "]; fetchPhase = '' curl https://api.modpacks.ch/public/modpack/${toString cfg.modpackId}/${toString cfg.versionId}/server/linux -o modpacks.ch # fuck creeperhost chmod +x modpacks.ch ''; installPhase = '' mkdir ebin $out cat > ebin/java < install-forge EOF chmod +x ebin/java export PATH=$PWD/ebin:$PATH ./modpacks.ch ${toString cfg.modpackId} ${toString cfg.versionId} --nojava --path $out --verbose ''; fixupPhase = '' # delete useless non-reproducible data that we really don't need. A less "shotgun" cleaning is possible rm $out/version.json ${cfg.extraFixup} ''; }; in pkgs.stdenv.mkDerivation { pname = "minecraft"; version = "unknown"; phases = [ "installPhase" ]; installPhase = '' mkdir -p $out/bin cp ${pkgs.writeShellScript "server.sh" '' export PATH=${makeBinPath (with pkgs; [ coreutils findutils bash cfg.javaPackage ])}:$PATH export _path=$PWD echo $0 echo $rw_paths function linkFile() { _rw_paths=${"( " + lib.concatMapStringsSep " " (x: ''"${x}"'') [ "config" "modpack/gamemodes.json" ] + " )"} _ignore_paths=${"( " + lib.concatMapStringsSep " " (x: ''"${x}"'') [ "start.sh" ] + " )"} echo $1 | grep MrTJP ignore=0 for ignore_path in ''${_ignore_paths[@]} ; do if [ "''${1##ignore_path}" != "$1" ] || [ "$ignore_path" = "$1" ] ; then ignore=1 break fi done if [ -f "$1" ] || [ $ignore = 1 ] ; then return fi mkdir -p "$_path/$(dirname "$1")" copy=0 for rw_path in ''${_rw_paths[@]} ; do if [ "''${1##$rw_path}" != "$1" ] || [ "$rw_path" = "$1" ] ; then copy=1 break fi done if [ "$copy" = 1 ] ; then cp --no-preserve=mode,ownership "${forgeFod}/$1" "$_path/$1" else ln -s "${forgeFod}/$1" "$_path/$1" fi } export -f linkFile echo $_path if [ "$_path" = "" ] || ! [ -d "$_path" ] ; then echo "invalid path" exit 1 fi find $_path -type l -lname '/nix/store/*' -delete find $_path -type d -empty -delete find ${forgeFod} -type f -printf '%P\n' | tr '\n' '\0' | xargs -0 -I {} sh -c 'linkFile "$1"' sh {} # mkdir -p "$_path/$(dirname "$1")" ; ln -s "${forgeFod}/$1" "$_path/$1" ln -s ${pkgs.writeShellScript "start.sh" '' ${lib.getExe cfg.javaPackage} $(cat ${forgeFod}/start.sh | grep -e "java" -e jar | sed 's/^"java" \(.*\) -jar .*$/\1/') "$@" -jar forge-*.jar ''} $_path/start.sh # [ -f $_path/install-forge ] && bash install-forge $_path/start.sh ''} $out/bin/server ''; }; init.services.minecraft-forge = { script = pkgs.writeShellScript "minecraft-run" '' set -xe mkdir -p /var/lib/minecraft/forge cd /var/lib/minecraft/forge echo "eula=true" > eula.txt ${pkgs.bash}/bin/bash -x ${cfg.serverPackage}/bin/server ${concatMapStringsSep " " (x: ''"${x}"'') cfg.extraJavaArguments} ''; enabled = true; }; assertions = [ { assertion = cfg.eulaAccept; message = "You must accept the EULA"; } ]; }; }