anchor.diff:        wantedBy      = [ "multi-user.target" ];
         after         = [ "network.target" ];
   
  -      serviceConfig.Restart = "always";
  -      serviceConfig.User    = "minecraft";
  -      script = ''
  -        cd ${cfg.dataDir}
  -        exec ${pkgs.minecraft-server}/bin/minecraft-server ${cfg.jvmOpts}
  -      '';
  +      serviceConfig = {
  +        ExecStart = "${cfg.package}/bin/minecraft-server ${cfg.jvmOpts}";
  +        Restart = "always";
  +        User = "minecraft";
  +        WorkingDirectory = cfg.dataDir;
  +      };
  +
  +      preStart = ''
  +        ln -sf ${eulaFile} eula.txt
  +      '' + (if cfg.declarative then ''
  +
  +        if [ -e .declarative ]; then
  +
  +          # Was declarative before, no need to back up anything
  +          ln -sf ${whitelistFile} whitelist.json
  +          cp -f ${serverPropertiesFile} server.properties
  +
  +        else
  +
  +          # Declarative for the first time, backup stateful files
  +          ln -sb --suffix=.stateful ${whitelistFile} whitelist.json
  +          cp -b --suffix=.stateful ${serverPropertiesFile} server.properties
  +
  +          # server.properties must have write permissions, because every time
  +          # the server starts it first parses the file and then regenerates it..
  +          chmod +w server.properties
  +          echo "Autogenerated file that signifies that this server configuration is managed declaratively by NixOS" \
  +            > .declarative
  +
  +        fi
  +      '' else ''
  +        if [ -e .declarative ]; then
  +          rm .declarative
  +        fi
  +      '');
       };
   
  -    networking.firewall = mkIf cfg.openFirewall {
  -      allowedUDPPorts = [ 25565 ];
  -      allowedTCPPorts = [ 25565 ];
  -    };
  +    networking.firewall = mkIf cfg.openFirewall (if cfg.declarative then {
  +      allowedUDPPorts = [ serverPort ];
  +      allowedTCPPorts = [ serverPort ]
  +        ++ optional (! isNull queryPort) queryPort
  +        ++ optional (! isNull rconPort) rconPort;
  +    } else {
  +      allowedUDPPorts = [ defaultServerPort ];
  +      allowedTCPPorts = [ defaultServerPort ];
  +    });
  +
  +    assertions = [
  +      { assertion = cfg.eula;
  +        message = "You must agree to Mojangs EULA to run minecraft-server."
  +          + " Read https://account.mojang.com/documents/minecraft_eula and"
  +          + " set `services.minecraft-server.eula` to `true` if you agree.";
  +      }
  +    ];
  +
     };
   }
  
positive.code:         type = types.path;
          default = "/var/lib/minecraft";
          description = ''
            Directory to store minecraft database and other state/data files.
          '';
        };
  
  
negative.code:         type = types.bool;
          default = false;
          description = ''
            Whether to open ports in the firewall for the server.
          '';
        };
  
        whitelist = mkOption {
          type = let
            minecraftUUID = types.strMatching
              "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // {
                description = "Minecraft UUID";
              };
            in types.attrsOf minecraftUUID;
          default = {};
          description = ''
            Whitelisted players, only has an effect when
            <option>services.minecraft-server.declarative</option> is
            <literal>true</literal> and the whitelist is enabled
            via <option>services.minecraft-server.serverProperties</option> by
            setting <literal>white-list</literal> to <literal>true</literal>.
            This is a mapping from Minecraft usernames to UUIDs.
            You can use <link xlink:href="https://mcuuid.net/"/> to get a
            Minecraft UUID for a username.
          '';
          example = literalExample ''
            {
              username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
              username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
            };
          '';
        };
  
        serverProperties = mkOption {
          type = with types; attrsOf (either bool (either int str));
          default = {};
          example = literalExample ''
            {
              server-port = 43000;
              difficulty = 3;
              gamemode = 1;
              max-players = 5;
              motd = "NixOS Minecraft server!";
              white-list = true;
              enable-rcon = true;
              "rcon.password" = "hunter2";
            }
          '';
          description = ''
            Minecraft server properties for the server.properties file. Only has
            an effect when <option>services.minecraft-server.declarative</option>
            is set to <literal>true</literal>. See
            <link xlink:href="https://minecraft.gamepedia.com/Server.properties#Java_Edition_3"/>
            for documentation on these values.
          '';
        };
  
        package = mkOption {
          type = types.package;
          default = pkgs.minecraft-server;
          defaultText = "pkgs.minecraft-server";
          example = literalExample "pkgs.minecraft-server_1_12_2";
          description = "Version of minecraft-server to run.";
        };
  
        jvmOpts = mkOption {
          type = types.separatedString " ";
          default = "-Xmx2048M -Xms2048M";
          # Example options from https://minecraft.gamepedia.com/Tutorials/Server_startup_script
          example = "-Xmx2048M -Xms4092M -XX:+UseG1GC -XX:+CMSIncrementalPacing "
            + "-XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 "
            + "-XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10";
          description = "JVM options for the Minecraft server.";
        };
      };
    };
  
    config = mkIf cfg.enable {
  
      users.users.minecraft = {
        description     = "Minecraft server service user";
        home            = cfg.dataDir;
        createHome      = true;
        uid             = config.ids.uids.minecraft;
  