{
  pkgs,
  lib,
  config,
  ...
}:
let
  inherit (lib) mapAttrs' nameValuePair;

  servers = {
    #bungeecord = {
    #  cmdline = "${pkgs.graalvmCEPackages.graalvm-ce}/bin/java -Xms2G -Xmx4G -XX:+UseG1GC -XX:G1HeapRegionSize=4M -XX:+UnlockExperimentalVMOptions -XX:+ParallelRefProcEnabled -XX:+AlwaysPreTouch -jar waterfall-1.20-578.jar";
    #  stop = "end";
    #};

    #limbo = {
    #  cmdline = "${pkgs.graalvmCEPackages.graalvm-ce}/bin/java -Xms1G -Xmx1G -jar NanoLimbo-1.8-all.jar";
    #  stop = "stop";
    #};

    greedycraft = {
      cmdline = "${pkgs.jdk8}/bin/java -Xmx10G -Xms10G -Xss4M -Dfile.encoding=GBK -Dsun.rmi.dgc.server.gcInterval=1800000 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1ReservePercent=20 -XX:MaxGCPauseMillis=50 -XX:+AlwaysPreTouch -XX:+UseStringDeduplication -Dfml.ignorePatchDiscrepancies=true -Dfml.ignoreInvalidMinecraftCertificates=true -XX:-OmitStackTraceInFastThrow -XX:+OptimizeStringConcat -XX:+UseAdaptiveGCBoundary -XX:G1HeapRegionSize=32M -jar forge-1.12.2-14.23.5.2855.jar nogui";
      stop = "stop";
    };

    nfwc = {
      cmdline = "${pkgs.jdk}/bin/java @user_jvm_args.txt @libraries/net/minecraftforge/forge/1.19.2-43.3.8/unix_args.txt";
      stop = "stop";
    };
  };

  prefix = "minecraft-server-";
  data = "/nix/persist/service/minecraft";
in
{
  # https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/games/minecraft-server.nix
  users.users.minecraft = {
    description = "Minecraft server service user";
    home = data;
    createHome = true;
    isSystemUser = true;
    uid = 1021;
    group = "minecraft";
  };
  users.groups.minecraft.gid = 1021;

  systemd.sockets = mapAttrs' (
    name: value:
    with value;
    (nameValuePair "${prefix}${name}" {
      bindsTo = [ "${prefix}${name}.service" ];
      socketConfig = {
        ListenFIFO = "/run/minecraft-server/${name}.stdin";
        SocketMode = "0660";
        SocketUser = "minecraft";
        SocketGroup = "minecraft";
        RemoveOnStop = true;
        FlushPending = true;
      };
    })
  ) servers;

  systemd.services =
    let
      stopScript =
        { name, stop }:
        pkgs.writeShellScript "minecraft-server-stop" ''
          echo ${stop} > ${config.systemd.sockets."${prefix}${name}".socketConfig.ListenFIFO}

          # Wait for the PID of the minecraft server to disappear before
          # returning, so systemd doesn't attempt to SIGKILL it.
          while kill -0 "$1" 2> /dev/null; do
            sleep 1s
          done
        '';
    in
    mapAttrs' (
      name: value:
      with value;
      (nameValuePair "${prefix}${name}" {
        description = "Minecraft Server Service for ${name}";
        wantedBy = [ "multi-user.target" ];
        requires = [ "${prefix}${name}.socket" ];
        after = [
          "network.target"
          "${prefix}${name}.socket"
        ];
        path = [ pkgs.bash ];

        serviceConfig = {
          ExecStart = cmdline;
          ExecStop = "${stopScript { inherit name stop; }} $MAINPID";
          Restart = "always";
          User = "minecraft";
          WorkingDirectory = "${data}/${name}";

          StandardInput = "socket";
          StandardOutput = "journal";
          StandardError = "journal";

          # Hardening
          CapabilityBoundingSet = [ "" ];
          DeviceAllow = [ "" ];
          LockPersonality = true;
          PrivateDevices = true;
          PrivateTmp = true;
          PrivateUsers = true;
          ProtectClock = true;
          ProtectControlGroups = true;
          ProtectHome = true;
          ProtectHostname = true;
          ProtectKernelLogs = true;
          ProtectKernelModules = true;
          ProtectKernelTunables = true;
          ProtectProc = "invisible";
          RestrictAddressFamilies = [
            "AF_INET"
            "AF_INET6"
          ];
          RestrictNamespaces = true;
          RestrictRealtime = true;
          RestrictSUIDSGID = true;
          SystemCallArchitectures = "native";
          UMask = "0077";
        };
      })
    ) servers;

  global.fs.zfs.mountpoints.${data} = "service/minecraft";
  networking.firewall.allowedTCPPorts = [ 25565 ];
}