I just updated it to v3, thought I'd share this rather than keep it to myself.
Don't expect support for this.
Don't expect support for this.
Code:
#!/usr/bin/env bash
#
# A simple jar updater script you can run on every startup.
# By default, it only attempts an update if the server jar is missing or
# more than half a day has passed since the last update.
#
# Requirements: curl, jq, bash, sha256sum, stat
#
# Usage: -h
#
# Author: Tau ([email protected], [email protected])
#
# Check we have all dependencies
for cmd in curl jq sha256sum stat; do
command -v $cmd >/dev/null 2>&1 || { echo "$cmd is required but not installed."; exit 1; }
done
PROJECT="paper"
# Defaults
MINECRAFT_VERSION_DEF="1.21.6"
STABLE_ONLY_DEF="false"
SERVER_JAR_PATH_DEF="server.jar"
JAR_AGE_DEF=43200 # Half a day
# Do not change
MINECRAFT_VERSION="$MINECRAFT_VERSION_DEF"
STABLE_ONLY="$STABLE_ONLY_DEF"
SERVER_JAR_PATH="$SERVER_JAR_PATH_DEF"
JAR_AGE="$JAR_AGE_DEF"
USER_AGENT="User-Agent: taucu-jar-updater/1.0.0"
while getopts "v:s:j:a:h" opt; do
case $opt in
v) MINECRAFT_VERSION="$OPTARG" ;;
s) STABLE_ONLY="$OPTARG" ;;
j) SERVER_JAR_PATH="$OPTARG" ;;
a) JAR_AGE="$OPTARG" ;;
h)
echo "Usage: $0 [-v version] [-s true|false] [-j path] [-a seconds]"
echo " -v <version> Target Minecraft version def: $MINECRAFT_VERSION_DEF"
echo " -s <true|false> Only update to stable releases def: $STABLE_ONLY_DEF"
echo " -j <path> Path of the jar to update def: $SERVER_JAR_PATH_DEF"
echo " -a <seconds|-1> Only update if jar is older than -a def: $JAR_AGE_DEF"
exit 0
;;
\?)
echo "Invalid option: -$OPTARG"
exit 1
;;
esac
done
# Parse/check variables
if ! [[ "$JAR_AGE" =~ ^-?[0-9]+$ ]]; then
echo "Error: -a must be a number. Got: $JAR_AGE"
exit 1
fi
STABLE_ONLY="${STABLE_ONLY,,}"
if [[ "$STABLE_ONLY" != "true" && "$STABLE_ONLY" != "false" ]]; then
echo "Error: -s must be a true or false. Got: $STABLE_ONLY"
exit 1
fi
# Only update if the jar doesn't exist or is older than JAR_AGE
if (( JAR_AGE > -1 )); then
CURTIME=$(date +%s)
if [ -f "$SERVER_JAR_PATH" ]; then
FILETIME=$(stat -c %Y "$SERVER_JAR_PATH")
TIMEDIFF=$((CURTIME - FILETIME))
if (( TIMEDIFF < JAR_AGE )); then
echo "Server jar updated recently: $TIMEDIFF seconds ago; Skipping update."
exit 0
fi
fi
fi
# Get available builds
AVAILABLE_BUILDS=$(curl -sSf --retry 3 --retry-delay 5 -H "${USER_AGENT}" "https://fill.papermc.io/v3/projects/${PROJECT}/versions/${MINECRAFT_VERSION}/builds") || {
echo "Error: Failed to fetch builds from PaperMC API"
exit 1
}
# Parse/check response
if ! echo "$AVAILABLE_BUILDS" | jq empty 2>/dev/null; then
echo "Error: Received invalid JSON"
echo "Got: $AVAILABLE_BUILDS"
exit 1
fi
# Get latest build
if [ "$STABLE_ONLY" = "true" ]; then
echo "Checking for updates... (stable only)"
LATEST_BUILD=$(echo "$AVAILABLE_BUILDS" | jq 'first(.[] | map(select(.channel == "STABLE")))')
else
echo "Checking for updates..."
LATEST_BUILD=$(echo "$AVAILABLE_BUILDS" | jq 'first(.[])')
fi
# Parse/check response
if [ "$LATEST_BUILD" = "null" ] || [ -z "$LATEST_BUILD" ]; then
echo "Couldn't find a build for: [$MINECRAFT_VERSION, stable: $STABLE_ONLY]"
exit 1
fi
# Resolve build number, hash and download url
LATEST_BUILD_NUM=$(echo "$LATEST_BUILD" | jq -r '.id')
EXPECTED_HASH=$(echo "$LATEST_BUILD" | jq -r '.downloads."server:default".checksums.sha256')
LATEST_BUILD_DL_URL=$(echo "$LATEST_BUILD" | jq -r '.downloads."server:default".url')
# Download jar
echo "Downloading: $LATEST_BUILD_DL_URL"
curl -Sf --retry 3 --retry-delay 5 -H "${USER_AGENT}" -o "$SERVER_JAR_PATH.tmp" "$LATEST_BUILD_DL_URL"
# Compute the hash
FILE_HASH=$(sha256sum "$SERVER_JAR_PATH.tmp" | awk '{print $1}')
# Verify the hash and move the jar
if [ "$EXPECTED_HASH" = "$FILE_HASH" ]; then
if [ -f "$SERVER_JAR_PATH" ]; then
mv -f "$SERVER_JAR_PATH" "$SERVER_JAR_PATH.old"
fi
mv -f "$SERVER_JAR_PATH.tmp" "$SERVER_JAR_PATH"
echo "Server jar updated to: ${MINECRAFT_VERSION}-$LATEST_BUILD_NUM"
else
echo "Hash mismatch! Update failed."
echo "Expected: $EXPECTED_HASH"
echo "Actual: $FILE_HASH"
exit 1
fi
exit 0