Auto Update Steamcmd Servers

Idee

Mit Steamcmd können verschiedene Spieleserver heruntergeladen werden.
Die lokal installierte Version hat eine buildid, die mit der öffentlich verfügbaren Version verglichen wird.
Unterscheiden sich die beiden IDs, werden die Dateien mittels Docker und des Steamcmd Images aktualisiert.
Läuft der Container des Servers noch, wird dieser gestoppt und im anschluss neugestartet.

Genauere Infos zum Verhalten wird noch weiter unten beleuchtet.

Skript

Grundsätzlich ist dieses Skript für Docker basierte Server gedacht. Es kann auch andere Systeme updaten, allerdings sind Prüfungen und Funktionen für Docker eingebaut. Einfach unter /usr/local/sbin/update_steam_game.sh ablegen.

#!/bin/bash

set -e

: "${APP_ID:=}"
: "${APP_DIR:=}"
: "${APP_UID:=1000}"
: "${APP_GID:=1000}"
: "${APP_DIR_INIT:=0}"
: "${CONTAINER_NAME:=}"
: "${UPDATE_SCRIPT:=}"


[[ ! -d "${APP_DIR}" && "${APP_DIR_INIT}" != "1" ]] && echo "APP_DIR [${APP_DIR}] does not exist" && exit 1

# get state of game
TEMP_FILE=$(mktemp)
URL="https://api.steamcmd.net/v1/info/${APP_ID}"
curl -X GET "${URL}" -o ${TEMP_FILE} > /dev/null 2>&1


local_buildid=$(grep -oP 'buildid.+"\K[0-9]+' ${APP_DIR}/appmanifest_${APP_ID}.acf 2>/dev/null|| echo 0)
remote_buildid=$(jq -r  '.data.[].depots.branches.public.buildid' "${TEMP_FILE}")
rm "${TEMP_FILE}"

if [[ "${local_buildid}" == "${remote_buildid}" ]]; then
    echo "no update needed - buildid local[${local_buildid}] remote[${remote_buildid}]"
    exit 0
fi

# stop container if existing and not stopped
state=$(docker ps -a -f name="^${CONTAINER_NAME}$" --format json | jq -r '.State')

if [[ ${state} == "" ]];then
    echo "Container [${CONTAINER_NAME}] does not exist (check ENV CONTAINER_NAME variable)"
elif [[ ! ${state} =~ exited ]];then
    echo "stopping container [${CONTAINER_NAME}]"
    docker stop "${CONTAINER_NAME}"
    stopped=1
fi

# update by script / default cmd
if [[ -x "${UPDATE_SCRIPT}" ]];then
    echo "UPDATE BY SCRIPT [${UPDATE_SCRIPT}]"
    ${UPDATE_SCRIPT}
else
    # create directory and fix permissions
    if [[ ! -d "${APP_DIR}" ]];then
        mkdir -p "${APP_DIR}"
    fi
    ts=$(date +'%s')

    chown -R 1000:1000 "${APP_DIR}"
    cmd="docker run --network host --rm -it --name=${CONTAINER_NAME:-steam_$ts}_updater -v ${APP_DIR}:/home/steam/Steam/steamapps:rw cm2network/steamcmd /home/steam/steamcmd/steamcmd.sh +login anonymous +app_update ${APP_ID} validate +quit"
    echo "UPDATE BY COMMAND [${cmd}]"
    $cmd
    chown -R ${APP_UID}:${APP_GID} "${APP_DIR}"
fi

[[ ${stopped} -eq 1 ]] && echo "starting docker container [${CONTAINER_NAME}]" && docker start "${CONTAINER_NAME}"

Berechtigung fixen:

chmod 700 /usr/local/sbin/update_steam_game.sh

Benutzung

Zu Beginn des Skripts werden folgende Variablen gesetzt:

Variable Verwendung
APP_ID ID des Spiels, Palworld z.B. hat die ID 2394010
APP_DIR Pfad zu steamapps (Installation), im Dockercontainer wäre dies der Pfad zu /home/steam/Steam/steamapps
APP_DIR_INIT Existiert der Ordner noch nicht, wird dieser angelegt und das Spiel erstmalig heruntergeladen
CONTAINER_NAME Name des Server-Containers der geprüft und ggf. neugestartet werden soll
UPDATE_SCRIPT Pfad zu einem eigenen Update Skript, welches Anstelle des docker run Befehls mit Standard Steamcmd Parametern ausgeführt wird (z.B. wenn Login nötig ist, oder anderer Branch)
OPTIONALE VARIABLEN
APP_UID Nach dem Update wird der Owner von APP_DIR auf diese ID gesetzt
APP_GID Nach dem Update wird die Owner Group von APP_DIR auf diese GID gesetzt

Beispiel:

Auto Update für Palworld, kann so auch als Cronjob / Systemd Timer laufen…

APP_ID="2394010" APP_DIR_INIT="1" APP_DIR="/srv/docker/containers/steam/palworld.testing2/" CONTAINER_NAME="steam_palworld_test" /usr/local/sbin/update_steam_game.sh