###############################################################################################
# Copyright (C) 2024  Griefed
#
# This script is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
# USA
#
# The full license can be found at https:github.com/Griefed/ServerPackCreator/blob/main/LICENSE
###############################################################################################
#
# Start script generated by ServerPackCreator 5.2.5.
# The template which was used in the generation of this script can be found at:
#   https://github.com/Griefed/ServerPackCreator/blob/5.2.5/serverpackcreator-api/src/jvmMain/resources/de/griefed/resources/server_files/default_template.ps1
#
# By default, running Powershell scripts from untrusted sources is probably disabled on your system.
# As such, you will not be able to run the start.ps-scripts just yet. You need to allow running
# unsigned scripts first. See https://superuser.com/a/106363 for a short explanation on how to
# enable/allow running unsigned scripts with Powershell.
#   ATTENTION:
#       Bear in mind that this introduces a security risk on your system. After making the changes from the
#       link above, you can run any Powershell script you like, and as such, introduce any and all security
#       risk into your system. So, beware when running scripts from unknown sources.
#
# Powershell scripts by default can not be opened with a double-click if the path to said script
# contains spaces. If you wish to remedy this or want to read more about this behaviour, this article
# talks about it in great detail: https://blog.danskingdom.com/fix-problem-where-windows-powershell-cannot-run-script-whose-path-contains-spaces/
#   ATTENTION:
#       Keep in mind though that things may still break when working with paths with spaces in them. If
#       things still break with a path with spaces, even after trying the fixes from the link above, then I
#       suggest moving things to a folder whose path contains no spaces. I'm afraid there's nothing I can do
#       about that.
#
# Depending on which modloader is set, different checks are run to ensure the server will start accordingly.
# If the modloader checks and setup are passed, Minecraft and EULA checks are run.
# If everything is in order, the server is started.
#
# Depending on the Minecraft version you will require a different Java version to run the server.
#   1.16.5 and older requires Java 8 (Java 11 will run better and work with 99% of mods, give it a try)
#     You may acquire a Java 8 JRE here: https://adoptium.net/temurin/releases/?variant=openjdk8&version=8&package=jre&arch=x64&os=windows
#     You may acquire a java 11 JRE here: https://adoptium.net/temurin/releases/?variant=openjdk11&version=11&package=jre&arch=x64&os=windows
#   1.18.2 and newer requires Java 17 (Java 18 will run better and work with 99% of mods, give it a try)
#     You may acquire a Java 17 JRE here: https://adoptium.net/temurin/releases/?variant=openjdk17&version=17&package=jre&arch=x64&os=windows
#     You may acquire a Java 18 JRE here: https://adoptium.net/temurin/releases/?variant=openjdk18&version=18&package=jre&arch=x64&os=windows

if ( (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
    Write-Host "Warning! Running with administrator-privileges is not recommended."
}

Write-Host "Start script generated by ServerPackCreator 5.2.5."
Write-Host "To change the launch settings of this server, such as JVM args / flags, Minecraft version, modloader version etc., edit the variables.txt-file."

# Acquire variable hashtable from variables.txt
$ExternalVariablesFile = Split-Path $script:MyInvocation.MyCommand.Path
$ExternalVariablesFile += "\variables.txt"
$ExternalVariables = Get-Content -raw -LiteralPath $ExternalVariablesFile | ConvertFrom-StringData

# Set our in-script variables from contents of variables.txt-hashtable
$MinecraftVersion = $ExternalVariables['MINECRAFT_VERSION']
$ModLoader = $ExternalVariables['MODLOADER']
$ModLoaderVersion = $ExternalVariables['MODLOADER_VERSION']
$LegacyFabricInstallerVersion = $ExternalVariables['LEGACYFABRIC_INSTALLER_VERSION']
$FabricInstallerVersion = $ExternalVariables['FABRIC_INSTALLER_VERSION']
$QuiltInstallerVersion =$ExternalVariables['QUILT_INSTALLER_VERSION']
$MinecraftServerUrl = $ExternalVariables['MINECRAFT_SERVER_URL']
$NeoForgeInstallerUrl = $ExternalVariables['NEOFORGE_INSTALLER_URL']
$JavaArgs = $ExternalVariables['JAVA_ARGS']
$Java = $ExternalVariables['JAVA']
$WaitForUserInput = $ExternalVariables['WAIT_FOR_USER_INPUT']

# Clean up quotes from the Java variable
if ($Java[0] -eq '"')
{
    $Java = $Java.Substring(1,$Java.Length-1)
}
if ($Java[$Java.Length-1] -eq '"')
{
    $Java = $Java.Substring(0,$Java.Length-1)
}

# Clean up quotes from the Java Args variable
if ($JavaArgs[0] -eq '"')
{
    $JavaArgs = $JavaArgs.Substring(1,$JavaArgs.Length-1)
}
if ($JavaArgs[$JavaArgs.Length-1] -eq '"')
{
    $JavaArgs = $JavaArgs.Substring(0,$JavaArgs.Length-1)
}

# Variables with do_not_manually_edit are set automatically during script execution,
# so manually editing them will have no effect, as they will be overridden.
$MinecraftServerJarLocation = "do_not_manually_edit"
$LauncherJarLocation = "do_not_manually_edit"
$ServerRunCommand = "do_not_manually_edit"

Function DeleteFileSilently
{
    param ($FileToDelete)

    $ErrorActionPreference = "SilentlyContinue";
    if ((Get-Item "${FileToDelete}").PSIsContainer)
    {
        Remove-Item "${FileToDelete}" -Recurse
    }
    else
    {
        Remove-Item "${FileToDelete}"
    }
    $ErrorActionPreference = "Continue";
}

Function PauseScript
{
    Write-Host "Press any key to continue" -ForegroundColor Yellow
    $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyDown") > $null
}

Function QuitServer
{
    Write-Host "Exiting..."
    if ("${WaitForUserInput}" -eq "true")
    {
        PauseScript
    }
    exit 0
}

Function global:RunJavaCommand
{
    param ($CommandToRun)

    CMD /C "`"${Java}`" ${CommandToRun}"
}

Function global:CheckJavaBitness
{
    $Bit = CMD /C "`"${Java}`" -version 2>&1"
    if ( ( ${Bit} | Select-String "32-Bit" ).Length -gt 0)
    {
        Write-Host "WARNING! 32-Bit Java detected! It is highly recommended to use a 64-Bit version of Java!"
    }
}

# $1 = Filename to check for
# $2 = Filename to save download as
# $3 = URL to download $2 from
# true if the File was successfully downloaded, false if it already exists
Function DownloadIfNotExists
{
    param ($FileToCheck, $FileToDownload, $DownloadURL)

    if (!(Test-Path -Path $FileToCheck -PathType Leaf))
    {

        Write-Host "${FileToCheck} could not be found."
        Write-Host "Downloading ${FileToDownload}"
        Write-Host "from ${DownloadURL}"

        Invoke-WebRequest -URI "${DownloadURL}" -OutFile "${FileToDownload}"

        if (Test-Path -Path "${FileToDownload}" -PathType Leaf)
        {
            Write-Host "Download complete."
            return $true
        }

    }
    else
    {
        Write-Host "${FileToCheck} present."
        return $false
    }

}

# If modloader = Forge, run Forge-specific checks
Function global:SetupForge
{
    ""
    "Running Forge checks and setup..."
    $ForgeInstallerUrl = "https://files.minecraftforge.net/maven/net/minecraftforge/forge/${MinecraftVersion}-${ModLoaderVersion}/forge-${MinecraftVersion}-${ModLoaderVersion}-installer.jar"
    $ForgeJarLocation = "do_not_manually_edit"
    $MINOR = ${MinecraftVersion}.Split(".")

    if ([int]$MINOR[1] -le 16)
    {
        $ForgeJarLocation = "forge.jar"
        $script:LauncherJarLocation = "forge.jar"
        $script:MinecraftServerJarLocation = "minecraft_server.${MinecraftVersion}.jar"
        $script:ServerRunCommand = "-Dlog4j2.formatMsgNoLookups=true ${JavaArgs} -jar ${LauncherJarLocation} nogui"
    }
    else
    {
        $ForgeJarLocation = "libraries/net/minecraftforge/forge/${MinecraftVersion}-${ModLoaderVersion}/forge-${MinecraftVersion}-${ModLoaderVersion}-server.jar"
        $script:MinecraftServerJarLocation = "libraries/net/minecraft/server/${MinecraftVersion}/server-${MinecraftVersion}.jar"
        $script:ServerRunCommand = "-Dlog4j2.formatMsgNoLookups=true @user_jvm_args.txt @libraries/net/minecraftforge/forge/${MinecraftVersion}-${ModLoaderVersion}/win_args.txt nogui"

        Write-Host "Generating user_jvm_args.txt from variables..."
        Write-Host "Edit JAVA_ARGS in your variables.txt. Do not edit user_jvm_args.txt directly!"
        Write-Host "Manually made changes to user_jvm_args.txt will be lost in the nether!"

        DeleteFileSilently  'user_jvm_args.txt'

        "# Xmx and Xms set the maximum and minimum RAM usage, respectively.`n" +
                "# They can take any number, followed by an M or a G.`n" +
                "# M means Megabyte, G means Gigabyte.`n" +
                "# For example, to set the maximum to 3GB: -Xmx3G`n" +
                "# To set the minimum to 2.5GB: -Xms2500M`n" +
                "# A good default for a modded server is 4GB.`n" +
                "# Uncomment the next line to set it.`n" +
                "# -Xmx4G`n" +
                "${script:JavaArgs}" | Out-File user_jvm_args.txt -encoding utf8
    }

    if ((DownloadIfNotExists "${ForgeJarLocation}" "forge-installer.jar" "${ForgeInstallerUrl}"))
    {
        "Forge Installer downloaded. Installing..."
        RunJavaCommand "-jar forge-installer.jar --installServer"

        if ([int]$MINOR[1] -gt 16)
        {
            DeleteFileSilently  'run.bat'
            DeleteFileSilently  'run.sh'
        }
        else
        {
            "Renaming forge-${MinecraftVersion}-${ModLoaderVersion}.jar to forge.jar"
            Move-Item "forge-${MinecraftVersion}-${ModLoaderVersion}.jar" 'forge.jar'
            Move-Item "forge-${MinecraftVersion}-${ModLoaderVersion}-universal.jar" 'forge.jar'
        }

        if ((Test-Path -Path "${ForgeJarLocation}" -PathType Leaf))
        {
            DeleteFileSilently  'forge-installer.jar'
            DeleteFileSilently  'forge-installer.jar.log'
            "Installation complete. forge-installer.jar deleted."
        }
        else
        {
            DeleteFileSilently  'forge-installer.jar'
            "Something went wrong during the server installation. Please try again in a couple of minutes and check your internet connection."
            QuitServer
        }
    }
}

# If modloader = NeoForge, run NeoForge-specific checks
Function global:SetupNeoForge
{
    ""
    "Running NeoForge checks and setup..."
    $ForgeJarLocation = "libraries/net/neoforged/forge/${MinecraftVersion}-${ModLoaderVersion}/forge-${MinecraftVersion}-${ModLoaderVersion}-server.jar"
    $script:MinecraftServerJarLocation = "libraries/net/minecraft/server/${MinecraftVersion}/server-${MinecraftVersion}.jar"
    $script:ServerRunCommand = "-Dlog4j2.formatMsgNoLookups=true @user_jvm_args.txt @libraries/net/neoforged/forge/${MinecraftVersion}-${ModLoaderVersion}/win_args.txt nogui"

    Write-Host "Generating user_jvm_args.txt from variables..."
    Write-Host "Edit JAVA_ARGS in your variables.txt. Do not edit user_jvm_args.txt directly!"
    Write-Host "Manually made changes to user_jvm_args.txt will be lost in the nether!"

    DeleteFileSilently  'user_jvm_args.txt'

    "# Xmx and Xms set the maximum and minimum RAM usage, respectively.`n" +
            "# They can take any number, followed by an M or a G.`n" +
            "# M means Megabyte, G means Gigabyte.`n" +
            "# For example, to set the maximum to 3GB: -Xmx3G`n" +
            "# To set the minimum to 2.5GB: -Xms2500M`n" +
            "# A good default for a modded server is 4GB.`n" +
            "# Uncomment the next line to set it.`n" +
            "# -Xmx4G`n" +
            "${script:JavaArgs}" | Out-File user_jvm_args.txt -encoding utf8


    if ((DownloadIfNotExists "${ForgeJarLocation}" "neoforge-installer.jar" "${NeoForgeInstallerUrl}"))
    {
        "NeoForge Installer downloaded. Installing..."
        RunJavaCommand "-jar neoforge-installer.jar --installServer"
        "Renaming forge-${MinecraftVersion}-${ModLoaderVersion}.jar to forge.jar"
        Move-Item "forge-${MinecraftVersion}-${ModLoaderVersion}.jar" 'forge.jar'

        if ((Test-Path -Path "${ForgeJarLocation}" -PathType Leaf))
        {
            DeleteFileSilently  'neoforge-installer.jar'
            DeleteFileSilently  'neoforge-installer.jar.log'
            "Installation complete. forge-installer.jar deleted."
        }
        else
        {
            DeleteFileSilently  'neoforge-installer.jar'
            "Something went wrong during the server installation. Please try again in a couple of minutes and check your internet connection."
            QuitServer
        }
    }
}

# If modloader = Fabric, run Fabric-specific checks
Function global:SetupFabric
{
    ""
    "Running Fabric checks and setup..."
    $FabricInstallerUrl = "https://maven.fabricmc.net/net/fabricmc/fabric-installer/${FabricInstallerVersion}/fabric-installer-${FabricInstallerVersion}.jar"
    $ImprovedFabricLauncherUrl = "https://meta.fabricmc.net/v2/versions/loader/${MinecraftVersion}/${ModLoaderVersion}/${FabricInstallerVersion}/server/jar"

    $ErrorActionPreference = "SilentlyContinue";
    $script:ImprovedFabricLauncherAvailable = [int][System.Net.WebRequest]::Create("${ImprovedFabricLauncherUrl}").GetResponse().StatusCode
    $ErrorActionPreference = "Continue";

    if ("${ImprovedFabricLauncherAvailable}" -eq "200")
    {
        "Improved Fabric Server Launcher available..."
        "The improved launcher will be used to run this Fabric server."
        $script:LauncherJarLocation = "fabric-server-launcher.jar"
        (DownloadIfNotExists "${script:LauncherJarLocation}" "${script:LauncherJarLocation}" "${ImprovedFabricLauncherUrl}") > $null
    }
    else
    {
        try
        {
            $ErrorActionPreference = "SilentlyContinue";
            $FabricAvailable = [int][System.Net.WebRequest]::Create("https://meta.fabricmc.net/v2/versions/loader/${MinecraftVersion}/${ModLoaderVersion}/server/json").GetResponse().StatusCode
            $ErrorActionPreference = "Continue";
        }
        catch
        {
            $FabricAvailable = "400"
        }
        if ("${FabricAvailable}" -ne "200")
        {
            "Fabric is not available for Minecraft ${MinecraftVersion}, Fabric ${ModLoaderVersion}."
            QuitServer
        }

        if ((DownloadIfNotExists "fabric-server-launch.jar" "fabric-installer.jar" "${FabricInstallerUrl}"))
        {
            "Installer downloaded..."
            $script:LauncherJarLocation = "fabric-server-launch.jar"
            $script:MinecraftServerJarLocation = "server.jar"
            RunJavaCommand "-jar fabric-installer.jar server -mcversion ${MinecraftVersion} -loader ${ModLoaderVersion} -downloadMinecraft"

            if ((Test-Path -Path 'fabric-server-launch.jar' -PathType Leaf))
            {
                DeleteFileSilently '.fabric-installer' -Recurse
                DeleteFileSilently 'fabric-installer.jar'
                "Installation complete. fabric-installer.jar deleted."
            }
            else
            {
                DeleteFileSilently  'fabric-installer.jar'
                "fabric-server-launch.jar not found. Maybe the Fabric servers are having trouble."
                "Please try again in a couple of minutes and check your internet connection."
                QuitServer
            }
        }
        else
        {
            $script:LauncherJarLocation = "fabric-server-launcher.jar"
            $script:MinecraftServerJarLocation = "server.jar"
        }
    }
    $script:ServerRunCommand = "-Dlog4j2.formatMsgNoLookups=true ${script:JavaArgs} -jar ${script:LauncherJarLocation} nogui"
}

# If modloader = Quilt, run Quilt-specific checks
Function global:SetupQuilt
{
    ""
    "Running Quilt checks and setup..."

    $QuiltInstallerUrl = "https://maven.quiltmc.org/repository/release/org/quiltmc/quilt-installer/${QuiltInstallerVersion}/quilt-installer-${QuiltInstallerVersion}.jar"

    if ((ConvertFrom-JSON (Invoke-WebRequest -Uri "https://meta.fabricmc.net/v2/versions/intermediary/${MinecraftVersion}")).Length -eq 0)
    {
        "Quilt is not available for Minecraft ${MinecraftVersion}, Quilt ${ModLoaderVersion}."
        QuitServer
    }
    elseif ((DownloadIfNotExists "quilt-server-launch.jar" "quilt-installer.jar" "${QuiltInstallerUrl}"))
    {
        "Installer downloaded. Installing..."
        RunJavaCommand "-jar quilt-installer.jar install server ${MinecraftVersion} --download-server --install-dir=."

        if ((Test-Path -Path 'quilt-server-launch.jar' -PathType Leaf))
        {
            DeleteFileSilently 'quilt-installer.jar'
            "Installation complete. quilt-installer.jar deleted."
        }
        else
        {
            DeleteFileSilently 'quilt-installer.jar'
            "quilt-server-launch.jar not found. Maybe the Quilt servers are having trouble."
            "Please try again in a couple of minutes and check your internet connection."
            QuitServer
        }

    }

    $script:LauncherJarLocation = "quilt-server-launch.jar"
    $script:MinecraftServerJarLocation = "server.jar"
    $script:ServerRunCommand = "-Dlog4j2.formatMsgNoLookups=true ${JavaArgs} -jar ${LauncherJarLocation} nogui"
}

# If modloader = LegacyFabric, run LegacyFabric-specific checks
Function global:SetupLegacyFabric
{
    ""
    "Running LegacyFabric checks and setup..."

    $LegacyFabricInstallerUrl = "https://maven.legacyfabric.net/net/legacyfabric/fabric-installer/${LegacyFabricInstallerVersion}/fabric-installer-${LegacyFabricInstallerVersion}.jar"

    if ((ConvertFrom-JSON (Invoke-WebRequest -Uri "https://meta.legacyfabric.net/v2/versions/loader/${MinecraftVersion}")).Length -eq 0)
    {
        "LegacyFabric is not available for Minecraft ${MinecraftVersion}, LegacyFabric ${ModLoaderVersion}."
        QuitServer
    }
    elseif ((DownloadIfNotExists "fabric-server-launch.jar" "legacyfabric-installer.jar" "${LegacyFabricInstallerUrl}"))
    {
        "Installer downloaded. Installing..."
        RunJavaCommand "-jar legacyfabric-installer.jar server -mcversion ${MinecraftVersion} -loader ${ModLoaderVersion} -downloadMinecraft"

        if ((Test-Path -Path 'fabric-server-launch.jar' -PathType Leaf))
        {
            DeleteFileSilently 'legacyfabric-installer.jar'
            "Installation complete. legacyfabric-installer.jar deleted."
        }
        else
        {
            DeleteFileSilently 'legacyfabric-installer.jar'
            "fabric-server-launch.jar not found. Maybe the LegacyFabric servers are having trouble."
            "Please try again in a couple of minutes and check your internet connection."
            QuitServer
        }

    }

    $script:LauncherJarLocation = "fabric-server-launch.jar"
    $script:MinecraftServerJarLocation = "server.jar"
    $script:ServerRunCommand = "-Dlog4j2.formatMsgNoLookups=true ${JavaArgs} -jar ${LauncherJarLocation} nogui"
}

# Check for a minecraft server and download it if necessary
Function global:Minecraft
{
    if (($ModLoader -eq "Fabric") -and (${ImprovedFabricLauncherAvailable} -eq "200"))
    {
        "Skipping Minecraft Server JAR checks because we are using the improved Fabric Server Launcher."
    }
    else
    {
        (DownloadIfNotExists "${MinecraftServerJarLocation}" "${MinecraftServerJarLocation}" "${MinecraftServerUrl}") > $null
    }
}

# Check for eula.txt and generate if necessary
Function Eula
{
    if (!(Test-Path -Path 'eula.txt' -PathType Leaf))
    {
        "Mojang's EULA has not yet been accepted. In order to run a Minecraft server, you must accept Mojang's EULA."
        "Mojang's EULA is available to read at https://aka.ms/MinecraftEULA"
        "If you agree to Mojang's EULA then type 'I agree'"
        $Answer = Read-Host -Prompt 'Answer: '

        if (${Answer} -eq "I agree")
        {
            "User agreed to Mojang's EULA."
            "#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA).`n" +
                    "eula=true" | Out-File eula.txt -encoding utf8
        }
        else
        {
            "User did not agree to Mojang's EULA."
            "Entered: ${Answer}"
            "You can not run a Minecraft server unless you agree to Mojang#s EULA."
            QuitServer
        }
    }
}

if ( ${PSScriptRoot}.Contains(" "))
{
    "WARNING! The current location of this script contains spaces. This may cause this server to crash!"
    "It is strongly recommended to move this server pack to a location whose path does NOT contain SPACES!"
    "Current path:"
    "${PSScriptRoot}"

    $WhyMustPowerShellBeThisWayLikeSeriouslyWhatTheFrag = Read-Host -Prompt 'Are you sure you want to continue? (Yes/No): '

    if (${WhyMustPowerShellBeThisWayLikeSeriouslyWhatTheFrag} -eq "Yes")
    {
        "Alrighty. Prepare for unforseen consequences, Mr. Freeman..."
    }
    else
    {
        QuitServer
    }
}

# Main
switch ( ${ModLoader} )
{
    Forge
    {
        SetupForge
    }
    NeoForge
    {
        SetupNeoForge
    }
    Fabric
    {
        SetupFabric
    }
    Quilt
    {
        SetupQuilt
    }
    LegacyFabric
    {
        SetupLegacyFabric
    }
    default
    {
        "Incorrect modloader specified: ${ModLoader}"
        QuitServer
    }
}

CheckJavaBitness
Minecraft
Eula

""
"Starting server..."
"Minecraft version: ${MinecraftVersion}"
"Modloader:         ${ModLoader}"
"Modloader version: ${ModLoaderVersion}"
if (!("${LauncherJarLocation}" -eq "do_not_manually_edit"))
{
    "Launcher JAR:      ${LauncherJarLocation}"
}
""
"Java args:         ${JavaArgs}"
"Java path:         ${Java}"
"Run Command:       ${Java} ${ServerRunCommand}"
"Java version:"
RunJavaCommand "-version"
""

RunJavaCommand "${ServerRunCommand}"

""
QuitServer
