[
    {
        "UpdateStageName": "Instance Directory Creation",
        "UpdateSourcePlatform": "Linux",
        "UpdateSource": "CreateDirectory",
        "UpdateSourceArgs": "{{$FullBaseDir}}game",
        "SkipOnFailure": false
    },
    {
        "UpdateStageName": "Proton GE Download",
        "UpdateSourcePlatform": "Linux",
        "UpdateSource": "Executable",
        "UpdateSourceData": "/bin/bash",
        "UpdateSourceArgs": "-c \"cd \\\"{{$FullRootDir}}\\\"; mkdir -p \\\"{{$FullRootDir}}.proton/compatdata\\\" \\\"{{$FullBaseDir}}.steam/steam\\\" \\\"{{$FullBaseDir}}.config/protonfixes\\\" || exit 1; ProtonVersion=\\\"{{SpecificReleaseVersion}}\\\"; ProtonVersion=\\\"${ProtonVersion// /}\\\"; if [[ -x \\\"{{$FullRootDir}}.proton/proton\\\" && -f \\\"{{$FullRootDir}}.proton/version\\\" ]]; then read _ InstalledVersion < \\\"{{$FullRootDir}}.proton/version\\\"; else InstalledVersion=\\\"\\\"; fi; if [[ -z \\\"$ProtonVersion\\\" ]]; then ProtonVersion=$(wget -qO- https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | jq -r .tag_name); fi; if [[ ! \\\"$ProtonVersion\\\" =~ ^GE-Proton[0-9]+-[0-9]+$ ]]; then echo \\\"Invalid Proton GE release version specified\\\" && exit 1; elif [[ -n \\\"$InstalledVersion\\\" && \\\"$InstalledVersion\\\" == \\\"$ProtonVersion\\\"* ]]; then echo \\\"Proton GE version $ProtonVersion already installed. Skipping\\\" && exit 0; else rm -f GE-Proton.tar.gz >/dev/null 2>&1; suffix=\\\"\\\"; ver=\\\"${ProtonVersion#GE-Proton}\\\"; major=\\\"${ver%%-*}\\\"; minor=\\\"${ver#*-}\\\"; if (( major > 11 || (major == 11 && minor >= 4) )); then suffix=\\\"-x86_64\\\"; fi; wget -qO GE-Proton.tar.gz https://github.com/GloriousEggroll/proton-ge-custom/releases/download/$ProtonVersion/${ProtonVersion}${suffix}.tar.gz || { echo \\\"Proton GE download failed from GitHub. Aborting\\\"; exit 1; }; rm -rf \\\"{{$FullRootDir}}.proton/compatdata/\\\"* >/dev/null 2>&1; tar -xzf GE-Proton.tar.gz -C \\\"{{$FullRootDir}}.proton\\\" --strip-components=1 && rm -f GE-Proton.tar.gz >/dev/null 2>&1 && echo \\\"Proton GE version $ProtonVersion installed\\\" && { STEAM_COMPAT_DATA_PATH=\\\"{{$FullRootDir}}.proton/compatdata\\\" STEAM_COMPAT_CLIENT_INSTALL_PATH=\\\"{{$FullBaseDir}}.steam/steam\\\" HOME=\\\"{{$FullBaseDir}}\\\" WINEDEBUG=-all \\\"{{$FullRootDir}}.proton/proton\\\" runinprefix cmd /c exit >/dev/null 2>&1; exit 0; }; fi\"",
        "SkipOnFailure": false
    },
    {
        "UpdateStageName": "Game Download and Install",
        "UpdateSourcePlatform": "Linux",
        "UpdateSource": "Executable",
        "UpdateSourceData": "/bin/bash",
        "UpdateSourceArgs": "-c \"#!/bin/bash\nset -uo pipefail\n\nKEY=\\\"\\\"\nDOWNLOAD_URL=\\\"\\\"\nGAME_DIR=\\\"\\\"\nWORK_DIR=\\\"\\\"\nwhile [[ $# -gt 0 ]]; do\n    case \\\"$1\\\" in\n        --key) KEY=\\\"$2\\\"; shift 2 ;;\n        --url) DOWNLOAD_URL=\\\"$2\\\"; shift 2 ;;\n        --gamedir) GAME_DIR=\\\"${2%/}\\\"; shift 2 ;;\n        --workdir) WORK_DIR=\\\"${2%/}\\\"; shift 2 ;;\n        *) echo \\\"ERROR: unknown argument '$1'\\\"; exit 1 ;;\n    esac\ndone\n[[ -n \\\"$GAME_DIR\\\" && -n \\\"$WORK_DIR\\\" ]] || { echo \\\"ERROR: --gamedir and --workdir are required\\\"; exit 1; }\n\nPORTAL=\\\"https://eshop.giants-software.com/downloads.php\\\"\nUA=\\\"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\\\"\nINNOEXTRACT_URL=\\\"https://github.com/dscharrer/innoextract/releases/download/1.9/innoextract-1.9-linux.tar.xz\\\"\nINNOEXTRACT_SHA256=\\\"008efe5011476ccc4aae17c3e22038b5a1bc5c7aad2b9d4d869537bf3874d21f\\\"\n\nINSTALLED_MARKER=\\\"$GAME_DIR/.amp-install-complete\\\"\nINSTALLED_SOURCE=\\\"\\\"\n[[ -f \\\"$INSTALLED_MARKER\\\" ]] && INSTALLED_SOURCE=$(tr -d '[:space:]' < \\\"$INSTALLED_MARKER\\\" 2>/dev/null)\n\ninstalled_version() { [[ -s \\\"$GAME_DIR/VERSION\\\" ]] && tr -d '[:space:]' < \\\"$GAME_DIR/VERSION\\\" || printf 'an unknown version'; }\n\nif [[ -z \\\"$DOWNLOAD_URL\\\" ]]; then\n    if [[ -z \\\"$KEY\\\" ]]; then\n        if [[ -n \\\"$INSTALLED_SOURCE\\\" ]]; then\n            echo \\\"Farming Simulator 19 $(installed_version) is installed and no product key is set to check for a newer version. Skipping\\\"\n            exit 0\n        fi\n        echo \\\"ERROR: No product key is set, so the download link cannot be looked up.\\\"\n        echo \\\"       Set the Product Key setting on this instance, then update it again.\\\"\n        exit 1\n    fi\n    echo \\\"Looking up the download link from the GIANTS download portal...\\\"\n    PAGE=$(curl -sS -A \\\"$UA\\\" --data-urlencode \\\"activationKey=$KEY\\\" --data-urlencode \\\"foobar=DOWNLOAD\\\" \\\"$PORTAL\\\") || PAGE=\\\"\\\"\n    if [[ -z \\\"$PAGE\\\" ]]; then\n        if [[ -n \\\"$INSTALLED_SOURCE\\\" ]]; then\n            echo \\\"Could not reach the GIANTS download portal, so Farming Simulator 19 $(installed_version) has been left as it is\\\"\n            exit 0\n        fi\n        echo \\\"ERROR: Could not reach the GIANTS download portal.\\\"\n        exit 1\n    fi\n    mapfile -t LINKS < <(grep -oE 'https://cdn[0-9]*\\.giants-software\\.com/eshop/[^\\\"]+' <<<\\\"$PAGE\\\" | sort -u)\n    if [[ ${#LINKS[@]} -eq 0 ]]; then\n        echo \\\"ERROR: The download portal returned no downloads for that product key.\\\"\n        echo \\\"       Check the Product Key setting, or confirm the key at the portal in a browser.\\\"\n        exit 1\n    fi\n    DOWNLOAD_URL=$(printf '%s\\n' \\\"${LINKS[@]}\\\" | grep -E 'FarmingSimulator2019.*\\.img$' | head -1)\n    if [[ -z \\\"$DOWNLOAD_URL\\\" ]]; then\n        echo \\\"ERROR: No Farming Simulator 19 download was found for that product key.\\\"\n        exit 1\n    fi\n    echo \\\"Found ${DOWNLOAD_URL##*/}\\\"\nfi\n\nAVAILABLE_SOURCE=\\\"${DOWNLOAD_URL##*/}\\\"\n\nif [[ -n \\\"$INSTALLED_SOURCE\\\" ]]; then\n    if [[ \\\"$INSTALLED_SOURCE\\\" == \\\"$AVAILABLE_SOURCE\\\" ]]; then\n        echo \\\"Farming Simulator 19 $(installed_version) already installed. Skipping\\\"\n        exit 0\n    elif [[ \\\"$INSTALLED_SOURCE\\\" != *.img ]]; then\n        echo \\\"Farming Simulator 19 $(installed_version) is installed but the download it came from was never recorded, so it is being reinstalled once\\\"\n    else\n        echo \\\"Updating Farming Simulator 19: the download has changed from $INSTALLED_SOURCE to $AVAILABLE_SOURCE\\\"\n    fi\nelif [[ -f \\\"$GAME_DIR/dedicatedServer.exe\\\" ]]; then\n    echo \\\"A previous install did not finish; installing over it\\\"\nfi\n\nrm -f \\\"$INSTALLED_MARKER\\\"\n\nmkdir -p \\\"$GAME_DIR\\\" \\\"$WORK_DIR\\\" || exit 1\n\nFREE_GB=$(( $(df -P -k \\\"$GAME_DIR\\\" | awk 'NR==2{print $4}') / 1024 / 1024 ))\nif [[ $FREE_GB -lt 17 ]]; then\n    echo \\\"ERROR: Only ${FREE_GB}GB is free on the instance drive, and installing Farming Simulator 19 needs about 17GB.\\\"\n    exit 1\nfi\n\nIMG=\\\"$WORK_DIR/fs19_download.img\\\"\nUNPACK=\\\"$WORK_DIR/fs19_unpack\\\"\nSTAGING=\\\"$WORK_DIR/fs19_staging\\\"\nTOOLS=\\\"$WORK_DIR/tools\\\"\nrm -rf \\\"$UNPACK\\\" \\\"$STAGING\\\"; rm -f \\\"$IMG\\\"\n\necho \\\"Downloading Farming Simulator 19. This is a multi-gigabyte download and will take a while\\\"\nTOTAL=$(curl -fsSLI -A \\\"$UA\\\" -e \\\"$PORTAL\\\" \\\"$DOWNLOAD_URL\\\" 2>/dev/null \\\n        | tr -d '\\r' | awk 'BEGIN{IGNORECASE=1} /^content-length:/{n=$2} END{print n+0}')\ncurl -fsS -A \\\"$UA\\\" -e \\\"$PORTAL\\\" -o \\\"$IMG\\\" \\\"$DOWNLOAD_URL\\\" &\nCURL_PID=$!\nwhile kill -0 \\\"$CURL_PID\\\" 2>/dev/null; do\n    sleep 10\n    CUR=$(stat -c%s \\\"$IMG\\\" 2>/dev/null || echo 0)\n    (( TOTAL > 0 && CUR > 0 )) && awk -v c=\\\"$CUR\\\" -v t=\\\"$TOTAL\\\" \\\n        'BEGIN { printf \\\"Downloading: %.1f%% (%.2f GB of %.2f GB)\\n\\\", c*100/t, c/1073741824, t/1073741824 }'\ndone\nif ! wait \\\"$CURL_PID\\\"; then\n    echo \\\"ERROR: The download failed.\\\"\n    echo \\\"       Clear the Download Link setting so a fresh link is looked up from your key.\\\"\n    rm -f \\\"$IMG\\\"; exit 1\nfi\necho \\\"Downloaded $(awk -v b=\\\"$(stat -c%s \\\"$IMG\\\")\\\" 'BEGIN{printf \\\"%.2f\\\", b/1073741824}') GB\\\"\n\nu8()  { echo \\\"${BYTES[$1]}\\\"; }\nu32() { echo $(( ${BYTES[$1]} | ${BYTES[$(($1+1))]}<<8 | ${BYTES[$(($1+2))]}<<16 | ${BYTES[$(($1+3))]}<<24 )); }\n\nextract_iso() {\n    local img=\\\"$1\\\" dest=\\\"$2\\\"\n    local magic\n    magic=$(dd if=\\\"$img\\\" bs=1 skip=32769 count=5 2>/dev/null)\n    [[ \\\"$magic\\\" == \\\"CD001\\\" ]] || { echo \\\"ERROR: the download is not an ISO9660 disc image\\\"; return 1; }\n\n    mapfile -t BYTES < <(dd if=\\\"$img\\\" bs=2048 skip=16 count=1 2>/dev/null | od -An -tu1 -v | tr -s ' ' '\\n' | grep -v '^$')\n    local root_lba root_size\n    root_lba=$(u32 158); root_size=$(u32 166)\n\n    mapfile -t BYTES < <(dd if=\\\"$img\\\" bs=2048 skip=\\\"$root_lba\\\" count=$(( (root_size + 2047) / 2048 )) 2>/dev/null | od -An -tu1 -v | tr -s ' ' '\\n' | grep -v '^$')\n\n    mkdir -p \\\"$dest\\\"\n    local p=0 len lba size flags filen name\n    while (( p < root_size )); do\n        len=$(u8 $p)\n        if (( len == 0 )); then p=$(( (p / 2048 + 1) * 2048 )); continue; fi\n        lba=$(u32 $((p+2))); size=$(u32 $((p+10)))\n        flags=$(u8 $((p+25))); filen=$(u8 $((p+32)))\n        local first=${BYTES[$((p+33))]}\n\n        if (( filen == 1 && first <= 1 )); then p=$(( p + len )); continue; fi\n\n        name=\\\"\\\"\n        local i c\n        for (( i=0; i<filen; i++ )); do\n            c=${BYTES[$((p+33+i))]}\n            name+=$(printf \\\"\\\\$(printf '%03o' \\\"$c\\\")\\\")\n        done\n        p=$(( p + len ))\n\n        (( flags & 2 )) && continue\n        name=\\\"${name%%;*}\\\"; name=\\\"${name%.}\\\"\n        [[ -n \\\"$name\\\" ]] || continue\n\n        dd if=\\\"$img\\\" bs=2048 skip=\\\"$lba\\\" count=$(( (size + 2047) / 2048 )) 2>/dev/null | head -c \\\"$size\\\" > \\\"$dest/$name\\\"\n    done\n}\n\necho \\\"Reading the disc image\\\"\nextract_iso \\\"$IMG\\\" \\\"$UNPACK\\\" || { rm -f \\\"$IMG\\\"; exit 1; }\n\nshopt -s nullglob nocaseglob\nfor f in \\\"$UNPACK\\\"/*_*.bin; do\n    base=\\\"${f##*/}\\\"\n    for alt in \\\"$(sed -E 's/_([0-9]+)\\.bin$/-\\1.bin/I' <<<\\\"$base\\\")\\\" \\\"${base//_/-}\\\"; do\n        [[ \\\"$alt\\\" == \\\"$base\\\" || -e \\\"$UNPACK/$alt\\\" ]] && continue\n        ln \\\"$f\\\" \\\"$UNPACK/$alt\\\" 2>/dev/null || cp \\\"$f\\\" \\\"$UNPACK/$alt\\\"\n    done\ndone\n\nSETUP=\\\"\\\"\nfor n in Setup.exe FarmingSimulator2019.exe; do\n    for cand in \\\"$UNPACK\\\"/$n; do [[ -f \\\"$cand\\\" ]] && SETUP=\\\"$cand\\\" && break 2; done\ndone\nif [[ -z \\\"$SETUP\\\" ]]; then\n    for cand in \\\"$UNPACK\\\"/*.exe; do [[ -f \\\"$cand\\\" ]] && SETUP=\\\"$cand\\\" && break; done\nfi\nshopt -u nullglob nocaseglob\n[[ -n \\\"$SETUP\\\" ]] || { echo \\\"ERROR: the installer was not found in the disc image\\\"; rm -rf \\\"$UNPACK\\\"; rm -f \\\"$IMG\\\"; exit 1; }\n\nrm -f \\\"$IMG\\\"\n\necho \\\"Fetching innoextract\\\"\nmkdir -p \\\"$TOOLS\\\"\nINNO=$(find \\\"$TOOLS\\\" -type f -name innoextract -perm -u+x 2>/dev/null | head -1)\nif [[ -z \\\"$INNO\\\" ]]; then\n    if ! curl -fsSL -o \\\"$TOOLS/ie.tar.xz\\\" \\\"$INNOEXTRACT_URL\\\"; then\n        echo \\\"ERROR: could not download innoextract\\\"; exit 1\n    fi\n    GOT=$(sha256sum \\\"$TOOLS/ie.tar.xz\\\" | cut -d' ' -f1)\n    if [[ \\\"$GOT\\\" != \\\"$INNOEXTRACT_SHA256\\\" ]]; then\n        echo \\\"ERROR: The innoextract download failed its checksum check.\\\"\n        rm -f \\\"$TOOLS/ie.tar.xz\\\"; exit 1\n    fi\n    tar -xJf \\\"$TOOLS/ie.tar.xz\\\" -C \\\"$TOOLS\\\" && rm -f \\\"$TOOLS/ie.tar.xz\\\"\n    INNO=$(find \\\"$TOOLS\\\" -maxdepth 2 -type f -name innoextract -perm -u+x | head -1)\nfi\n[[ -n \\\"$INNO\\\" ]] || { echo \\\"ERROR: innoextract was not found after downloading it\\\"; exit 1; }\n\necho \\\"Unpacking the game. This takes several minutes\\\"\nif ! \\\"$INNO\\\" --extract --output-dir \\\"$STAGING\\\" --color=off --progress=no \\\"$SETUP\\\"; then\n    echo \\\"ERROR: innoextract failed to unpack the installer\\\"\n    rm -rf \\\"$UNPACK\\\" \\\"$STAGING\\\"; exit 1\nfi\n\nif [[ ! -d \\\"$STAGING/app\\\" ]]; then\n    echo \\\"ERROR: the unpacked payload has no app directory\\\"\n    rm -rf \\\"$UNPACK\\\" \\\"$STAGING\\\"; exit 1\nfi\necho \\\"Moving the game into place\\\"\nif ! cp -a -l -f \\\"$STAGING/app\\\"/. \\\"$GAME_DIR\\\"/ 2>/dev/null; then\n    cp -a -f \\\"$STAGING/app\\\"/. \\\"$GAME_DIR\\\"/ || { echo \\\"ERROR: could not copy the game into place\\\"; exit 1; }\nfi\nrm -rf \\\"$UNPACK\\\" \\\"$STAGING\\\"\n\nif [[ ! -f \\\"$GAME_DIR/dedicatedServer.exe\\\" ]]; then\n    echo \\\"ERROR: The game was unpacked but no dedicated server was found in it.\\\"\n    exit 1\nfi\nprintf '%s' \\\"${AVAILABLE_SOURCE:-unknown}\\\" > \\\"$INSTALLED_MARKER\\\"\necho \\\"Farming Simulator 19 $(installed_version) installed from ${AVAILABLE_SOURCE:-an unrecorded download}\\\"\n\" fs-install --key \"{{ActivationKey}}\" --url \"{{DownloadURL}}\" --gamedir \"{{$FullBaseDir}}game\" --workdir \"{{$FullBaseDir}}work\"",
        "SkipOnFailure": false,
        "ProcessToolOutput": true
    }
]
