diff --git a/scripts/auto_reboot.sh b/scripts/auto_reboot.sh index 13f1de424..fac6ee1a1 100644 --- a/scripts/auto_reboot.sh +++ b/scripts/auto_reboot.sh @@ -2,32 +2,30 @@ # shellcheck source=/dev/null source "/home/steam/server/helper_functions.sh" -if [ "${RCON_ENABLED,,}" != true ]; then - LogWarn "Unable to reboot. RCON is required." - exit 0 -fi +if [ "${RCON_ENABLED,,}" = true ]; then + if [ "${AUTO_REBOOT_EVEN_IF_PLAYERS_ONLINE,,}" != true ]; then + players_count=$(get_player_count) -if [ -z "${AUTO_REBOOT_WARN_MINUTES}" ]; then - LogError "Unable to auto reboot, AUTO_REBOOT_WARN_MINUTES is empty." - exit 0 -fi + if [ "$players_count" -gt 0 ]; then + LogWarn "There are ${players_count} players online. Skipping auto reboot." + exit 0 + fi + fi -if [ "${AUTO_REBOOT_EVEN_IF_PLAYERS_ONLINE,,}" != true ]; then - players_count=$(get_player_count) - if [ "$players_count" -gt 0 ]; then - LogWarn "There are ${players_count} players online. Skipping auto reboot." - exit 0 - fi -fi - -if [[ "${AUTO_REBOOT_WARN_MINUTES}" =~ ^[0-9]+$ ]]; then - for ((i = "${AUTO_REBOOT_WARN_MINUTES}" ; i > 0 ; i--)); do - RCON "broadcast The_Server_will_reboot_in_${i}_Minutes" - sleep "1m" - done - RCON save - RCON "shutdown 1" - exit 0 + case "$(countdown_message "${AUTO_REBOOT_WARN_MINUTES}" "The_Server_will_reboot"; echo $?)" in + 0 ) + shutdown_server + ;; + 1 ) + LogError "Unable to auto reboot, the server is not empty and AUTO_REBOOT_WARN_MINUTES is empty" + exit 1 + ;; + 2 ) + LogError "Unable to auto reboot, the server is not empty and AUTO_REBOOT_WARN_MINUTES is not an integer: ${AUTO_REBOOT_WARN_MINUTES}" + exit 1 + ;; + esac +else + LogWarn "Unable to reboot. RCON is required." + exit 1 fi - -LogError "Unable to auto reboot, AUTO_REBOOT_WARN_MINUTES is not an integer: ${AUTO_REBOOT_WARN_MINUTES}" \ No newline at end of file diff --git a/scripts/backup.sh b/scripts/backup.sh index 119ffa126..0fe3c5ad0 100644 --- a/scripts/backup.sh +++ b/scripts/backup.sh @@ -3,9 +3,7 @@ source "/home/steam/server/helper_functions.sh" DiscordMessage "Creating backup..." "in-progress" -if [ "${RCON_ENABLED,,}" = true ]; then - RCON save -fi +save_server DATE=$(date +"%Y-%m-%d_%H-%M-%S") FILE_PATH="/palworld/backups/palworld-save-${DATE}.tar.gz" @@ -21,23 +19,20 @@ LogInfo "Backup created at ${FILE_PATH}" DiscordMessage "Backup created at ${FILE_PATH}" "success" if [ "${DELETE_OLD_BACKUPS,,}" != true ]; then - exit 0 -fi - -if [ -z "${OLD_BACKUP_DAYS}" ]; then - LogWarn "Unable to delete old backups, OLD_BACKUP_DAYS is empty." - DiscordMessage "Unable to delete old backups, OLD_BACKUP_DAYS is empty." "warn" - exit 0 + if [ -z "${OLD_BACKUP_DAYS}" ]; then + LogWarn "Unable to delete old backups, OLD_BACKUP_DAYS is empty." + DiscordMessage "Unable to delete old backups, OLD_BACKUP_DAYS is empty." "warn" + exit 1 + fi + + if [[ "${OLD_BACKUP_DAYS}" =~ ^[0-9]+$ ]]; then + LogAction "Removing Old Backups" + LogInfo "Removing backups older than ${OLD_BACKUP_DAYS} days" + DiscordMessage "Removing backups older than ${OLD_BACKUP_DAYS} days..." "in-progress" + find /palworld/backups/ -mindepth 1 -maxdepth 1 -mtime "+${OLD_BACKUP_DAYS}" -type f -name 'palworld-save-*.tar.gz' -print -delete + DiscordMessage "Removed backups older than ${OLD_BACKUP_DAYS} days" "success" + else + LogError "Unable to delete old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" + DiscordMessage "Unable to delete old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" "failure" + fi fi - -if [[ "${OLD_BACKUP_DAYS}" =~ ^[0-9]+$ ]]; then - LogAction "Removing Old Backups" - LogInfo "Removing backups older than ${OLD_BACKUP_DAYS} days" - DiscordMessage "Removing backups older than ${OLD_BACKUP_DAYS} days..." "in-progress" - find /palworld/backups/ -mindepth 1 -maxdepth 1 -mtime "+${OLD_BACKUP_DAYS}" -type f -name 'palworld-save-*.tar.gz' -print -delete - DiscordMessage "Removed backups older than ${OLD_BACKUP_DAYS} days" "success" - exit 0 -fi - -LogError "Unable to delete old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" -DiscordMessage "Unable to delete old backups, OLD_BACKUP_DAYS is not an integer. OLD_BACKUP_DAYS=${OLD_BACKUP_DAYS}" "failure" \ No newline at end of file diff --git a/scripts/helper_functions.sh b/scripts/helper_functions.sh index 41921f1c7..96db82ad2 100644 --- a/scripts/helper_functions.sh +++ b/scripts/helper_functions.sh @@ -71,12 +71,15 @@ isExecutable() { # Outputs the player count if rcon is enabled get_player_count() { local player_list - if [ "${RCON_ENABLED,,}" != true ]; then + local return_val=0 + if player_list=$(RCON "ShowPlayers"); then + echo -n "${player_list}" | wc -l + else echo 0 - return 0 + return_val=1 fi - player_list=$(RCON "ShowPlayers") - echo -n "${player_list}" | wc -l + + return "$return_val" } # @@ -130,10 +133,111 @@ DiscordMessage() { # RCON Call RCON() { - local args="$1" - rcon-cli -c /home/steam/server/rcon.yaml "$args" + local return_val=0 + local args="$1" + if [ "${RCON_ENABLED,,}" = true ]; then + rcon-cli -c /home/steam/server/rcon.yaml "$args" + else + return_val=1 + fi + return "$return_val" +} + +# Saves the server +# Returns 0 if it saves +# Returns 1 if it is not able to save +save_server() { + local return_val=0 + if ! RCON save; then + return_val=1 + fi + return "$return_val" +} + +# Saves then shutdowns the server +# Returns 0 if it is shutdown +# Returns 1 if it is not able to be shutdown +shutdown_server() { + local return_val=0 + # Do not shutdown if not able to save + if save_server; then + if ! RCON "DoExit"; then + return_val=1 + fi + else + return_val=1 + fi + return "$return_val" +} + +# Given a message this will broadcast in game +# Since RCON does not support spaces this will replace all spaces with underscores +# Returns 0 on success +# Returns 1 if not able to broadcast +broadcast_command() { + local return_val=0 + # Replaces spaces with underscore + local message="${1// /_}" + if [[ $TEXT = *[![:ascii:]]* ]]; then + LogWarn "Unable to broadcast since the message contains non-ascii characters: \"${message}\"" + return_val=1 + elif ! RCON "broadcast ${message}"; then + return_val=1 + fi + return "$return_val" } -# Helper Functions for installation & updates -# shellcheck source=/dev/null -source "/home/steam/server/helper_install.sh" \ No newline at end of file +# Given an amount of time in minutes and a message prefix +# Will skip countdown if no players are in the server, Will only check the mtime if there are players in the server +# Returns 0 on success +# Returns 1 if mtime is empty +# Returns 2 if mtime is not an integer +countdown_message() { + local mtime="$1" + local message_prefix="$2" + local return_val=0 + + # Only do countdown if there are players + if [ "$(get_player_count)" -gt 0 ]; then + if [[ "${mtime}" =~ ^[0-9]+$ ]]; then + for ((i = "${mtime}" ; i > 0 ; i--)); do + case "$i" in + 1 ) + broadcast_command "${message_prefix}_in_${i}_minute" + sleep 30s + broadcast_command "${message_prefix}_in_30_seconds" + sleep 20s + broadcast_command "${message_prefix}_in_10_seconds" + sleep 10s + ;; + 2 ) + ;& + 3 ) + ;& + 10 ) + ;& + 15 ) + ;& + "$mtime" ) + broadcast_command "${message_prefix}_in_${i}_minutes" + ;& + * ) + sleep 1m + # Checking for players every minute + # Checking after sleep since it is ran in the beginning of the function + if [ "$(get_player_count)" -eq 0 ]; then + break + fi + ;; + esac + done + # If there are players but mtime is empty + elif [ -z "${mtime}" ]; then + return_val=1 + # If there are players but mtime is not an integer + else + return_val=2 + fi + fi + return "$return_val" +} diff --git a/scripts/helper_install.sh b/scripts/helper_install.sh index a75c923e1..3b9743a23 100644 --- a/scripts/helper_install.sh +++ b/scripts/helper_install.sh @@ -1,6 +1,9 @@ #!/bin/bash # This file contains functions which can be used in multiple scripts +# shellcheck source=/dev/null +source "/home/steam/server/helper_functions.sh" + # Returns 0 if game is installed # Returns 1 if game is not installed IsInstalled() { diff --git a/scripts/init.sh b/scripts/init.sh index 0c03448e9..af0c862a0 100644 --- a/scripts/init.sh +++ b/scripts/init.sh @@ -26,12 +26,10 @@ mkdir -p /palworld/backups # shellcheck disable=SC2317 term_handler() { - DiscordMessage "${DISCORD_PRE_SHUTDOWN_MESSAGE}" "in-progress" + DiscordMessage "${DISCORD_PRE_SHUTDOWN_MESSAGE}" "in-progress" - if [ "${RCON_ENABLED,,}" = true ]; then - RCON save - RCON "shutdown 1" - else # Does not save + if ! shutdown_server; then + # If it fails then kill the server kill -SIGTERM "$(pidof PalServer-Linux-Test)" fi diff --git a/scripts/restore.sh b/scripts/restore.sh index 9f4bac15b..3b432e6ec 100644 --- a/scripts/restore.sh +++ b/scripts/restore.sh @@ -63,8 +63,7 @@ if [ -f "$BACKUP_FILE" ]; then if [ "${RCON_ENABLED}" = true ]; then LogAction "Shutting Down Server" - RCON save - RCON "shutdown 1" + shutdown_server else LogWarn "RCON is not enabled. Please enable RCON to use this feature. Unable to restore backup." exit 1 diff --git a/scripts/start.sh b/scripts/start.sh index e15b47b0f..2d6d05c0e 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -2,6 +2,10 @@ # shellcheck source=/dev/null source "/home/steam/server/helper_functions.sh" +# Helper Functions for installation & updates +# shellcheck source=/dev/null +source "/home/steam/server/helper_install.sh" + dirExists "/palworld" || exit isWritable "/palworld" || exit isExecutable "/palworld" || exit @@ -20,23 +24,18 @@ if [ "$architecture" == "arm64" ] && [ "$kernel_page_size" != "4096" ]; then exit 1 fi -IsInstalled -ServerInstalled=$? -if [ "$ServerInstalled" == 1 ]; then +if IsInstalled; then + # Update Only If Already Installed + if [ "${UPDATE_ON_BOOT,,}" == true ] && UpdateRequired; then + LogAction "Starting Update" + InstallServer + fi +else LogInfo "Server installation not detected." LogAction "Starting Installation" InstallServer fi -# Update Only If Already Installed -if [ "$ServerInstalled" == 0 ] && [ "${UPDATE_ON_BOOT,,}" == true ]; then - UpdateRequired - IsUpdateRequired=$? - if [ "$IsUpdateRequired" == 0 ]; then - LogAction "Starting Update" - InstallServer - fi -fi # Check if the architecture is arm64 if [ "$architecture" == "arm64" ]; then @@ -79,7 +78,7 @@ fi if [ "${DISABLE_GENERATE_SETTINGS,,}" = true ]; then LogAction "GENERATING CONFIG" - LogWarn "Env vars will not be applied due to DISABLE_GENERATE_SETTINGS being set to TRUE!" + LogWarn "Environment variables will not be applied due to DISABLE_GENERATE_SETTINGS being set to TRUE!" # shellcheck disable=SC2143 if [ ! "$(grep -s '[^[:space:]]' /palworld/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini)" ]; then @@ -146,4 +145,4 @@ echo "${STARTCOMMAND[*]}" "${STARTCOMMAND[@]}" DiscordMessage "${DISCORD_POST_SHUTDOWN_MESSAGE}" "failure" -exit 0 \ No newline at end of file +exit 0 diff --git a/scripts/update.sh b/scripts/update.sh index 5489bf5c9..2a2e4650c 100644 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -2,32 +2,43 @@ # shellcheck source=/dev/null source "/home/steam/server/helper_functions.sh" -UpdateRequired -updateRequired=$? +# Helper Functions for installation & updates +# shellcheck source=/dev/null +source "/home/steam/server/helper_install.sh" + # Check if Update was actually required -if [ "$updateRequired" != 0 ]; then - exit 0 -fi +if UpdateRequired; then + if [ "${UPDATE_ON_BOOT}" = false ]; then + LogWarn "An update is available however, UPDATE_ON_BOOT needs to be enabled for auto updating" + DiscordMessage "An update is available however, UPDATE_ON_BOOT needs to be enabled for auto updating" "warn" + exit 1 + fi -if [ "${UPDATE_ON_BOOT}" = false ]; then - LogWarn "An update is available however, UPDATE_ON_BOOT needs to be enabled for auto updating" - DiscordMessage "An update is available however, UPDATE_ON_BOOT needs to be enabled for auto updating" "warn" - exit 1 -fi + if [ "${RCON_ENABLED,,}" = false ]; then + LogWarn "An update is available however auto updating without rcon is not supported" + DiscordMessage "An update is available however auto updating without rcon is not supported" "warn" + exit 1 + fi -if [ "${RCON_ENABLED,,}" = false ]; then - LogWarn "An update is available however auto updating without rcon is not supported" - DiscordMessage "An update is available however auto updating without rcon is not supported" "warn" - exit 1 -fi + if [[ "${AUTO_UPDATE_WARN_MINUTES}" =~ ^[0-9]+$ ]]; then + DiscordMessage "Server will update in ${AUTO_UPDATE_WARN_MINUTES} minutes" + fi -if [ "$(get_player_count)" -gt 0 ]; then - LogAction "Updating the server from $CURRENT_MANIFEST to $TARGET_MANIFEST." - DiscordMessage "Server will update in ${AUTO_UPDATE_WARN_MINUTES} minutes" - RCON "broadcast The_Server_will_update_in_${AUTO_UPDATE_WARN_MINUTES}_Minutes" - sleep "${AUTO_UPDATE_WARN_MINUTES}m" -fi + case "$(countdown_message "${AUTO_UPDATE_WARN_MINUTES}" "Server_will_update"; echo $?)" in + 0 ) + LogAction "Updating the server from $CURRENT_MANIFEST to $TARGET_MANIFEST." + rm /palworld/steamapps/appmanifest_2394010.acf -rm /palworld/steamapps/appmanifest_2394010.acf -backup -RCON "shutdown 1" \ No newline at end of file + backup + shutdown_server + ;; + 1 ) + LogWarn "Unable to auto update, the server is not empty and AUTO_UPDATE_WARN_MINUTES is empty." + exit 1 + ;; + 2 ) + LogWarn "Unable to auto update, the server is not empty and AUTO_UPDATE_WARN_MINUTES is not an integer: ${AUTO_UPDATE_WARN_MINUTES}" + exit 1 + ;; + esac +fi