From 224eeb9614f21c3e466c102734dd667f84e3aea7 Mon Sep 17 00:00:00 2001 From: Price Hiller Date: Thu, 5 Aug 2021 18:01:13 -0500 Subject: [PATCH] Created Squad-Install-Mod.bash, tweaks to other Squad Scripts --- CentOS/Squad/Squad-Install-Mod.bash | 264 +++++++++++++++++++++++++ CentOS/Squad/Squad-Install-Server.bash | 10 +- CentOS/Squad/Squad-Start-Server.bash | 209 +++++++++++--------- 3 files changed, 384 insertions(+), 99 deletions(-) create mode 100755 CentOS/Squad/Squad-Install-Mod.bash diff --git a/CentOS/Squad/Squad-Install-Mod.bash b/CentOS/Squad/Squad-Install-Mod.bash new file mode 100755 index 0000000..7862c13 --- /dev/null +++ b/CentOS/Squad/Squad-Install-Mod.bash @@ -0,0 +1,264 @@ +#!/bin/bash + +echo_rgb() { + # Echo a colored string to the terminal based on rgb values + # + # Positional Arguments: + # + # message + # - The message to be printed to stdout + # red + # - The red value from 0 to 255 + # green + # - The green value from 0 to 255 + # blue + # - The blue value from 0 to 255 + # + # Usage: + # echo_rgb "Yep" 10 8 30 + # + # POSIX Compliant: + # N/A + # + + local red + local green + local blue + local input + + input="${1}" + red="${2}" + green="${3}" + blue="${4}" + + printf "\e[0;38;2;%s;%s;%sm%s\e[m\n" "${red}" "${green}" "${blue}" "${input}" +} + +log() { + # Print a message and send it to stdout or stderr depending upon log level, also configurable with debug etc. + # + # Arguments: + # level + # - The log level, defined within a case check in this function + # message + # - The info message + # line_number + # - The line number of the calling function (${LINNO}) + # + # Usage: + # log "info" "Could not find that directory" + # + # POSIX Compliant: + # Yes + # + + # Set debug status depending if a global debug variable has been set to either 1 or 0 + local debug + if [ ${DEBUG} ]; then + debug=${DEBUG} + else + debug=0 + fi + + local FORMAT + FORMAT="[$(echo_rgb "$(date +%Y-%m-%dT%H:%M:%S)" 180 140 255)]" + + # Convert the level to uppercase + local level + level=$(echo "${1}" | tr '[:lower:]' '[:upper:]') + + local message + message="${2}" + + case "${level}" in + INFO) + # Output all info log levels to stdout + printf "${FORMAT}[$(echo_rgb "INFO" 0 140 255)] %s\n" "${message}" >&1 + return 0 + ;; + WARN | WARNING) + # Output all info log levels to stdout + printf "${FORMAT}[$(echo_rgb "WARNING" 255 255 0)] %s\n" "${message}" >&1 + return 0 + ;; + DEBUG) + [[ ${debug} == 0 ]] && return + printf "${FORMAT}[$(echo_rgb "DEBUG" 0 160 110)] %s\n" "${message}" >&1 + return 0 + ;; + ERROR) + # Output all error log levels to stderr + printf "${FORMAT}[$(echo_rgb "ERROR" 255 0 0)] %s\n" "${message}" >&2 + return 0 + ;; + # Further log levels can be added by extending this switch statement with more comparisons + + *) # Default case, no matches + # Returns non-zero code as an improper log option was passed, this helps with using `set -e` + printf "${FORMAT}[ERROR] %s\n" "Invalid log level passed, received level \"${level}\" with message \"${message}\"" >&2 + return 1 + ;; + esac +} + +confirmation() { + # Receive confirmation from user as y, Y, n, or N + # returns 0 when answer is yes and 1 when answer is no + # + # Arguments: + # message + # - The confirmation prompt sent to the user, for example: + # Would you like to overwrite foobar.txt (y/N)? + # + # Usage: + # confirmation "Some prompt" + # - Sends "Some prompt" to the user and gets their input + # + # POSIX Compliant: + # Yes + # + + local message + message="${1}" + + local choice + + while true; do + read -p "${message} " -n 1 -r choice + case "$choice" in + y | Y) + echo "" + return 0 + ;; + n | N) + echo "" + return 1 + ;; + *) echo -e "\nInput must be either y, Y, n, or N" ;; + esac + done +} + +usage() { + # Print out usage instructions for the local script + # + # Arguments: + # None + # + # Usage: + # usage + # + # POSIX Compliant: + # Yes + # + printf "Usage: %s\n" \ + "$(important "$(basename "${0}") -s -w ") + -s | --server + Which Squad server to start, see the ~/Squad directory -- each number corresponds to an ID + + Example: + --server 0 + + -w | --workshop-id + Installs the given workshop ID + + Example: + --verify" +} + +important() { + echo_rgb "${1}" 145 233 255 +} + +server_id="" +workshop_id="" + +parse_args() { + # Parse input arguments + # + # Arguments: + # Consult the `usage` function + # + # Usage: + # parse_args "$@" + # - All arguments should be ingested by parse_args first for variable setting + # + # POSIX Compliant: + # Yes + # + + while :; do + case ${1} in + -h | -\? | --help) + usage # Display a usage synopsis. + exit + ;; + --) # End of all options. + break + ;; + -s | --server) + shift + server_id="${1}" + [[ -z "${server_id}" ]] && + log "error" "Server requires an argument, e.g. --server 0" && + exit 1 + [[ ! "${server_id}" =~ [0-9] ]] && + log "error" "Server ID must be a number, received: ${server_id}" && + exit 1 + ;; + -w | --workshop-id) + shift + workshop_id="${1}" + [[ -z "${workshop_id}" ]] && + log "error" "Workshop ID requires an argument, e.g. --server 0" && + exit 1 + [[ ! "${workshop_id}" =~ [0-9] ]] && + log "error" "Workshop ID must be a number, received: ${workshop_id}" && + exit 1 + ;; + -?*) + printf 'Unknown option: %s\n' "$1" >&2 + usage + ;; + *) # Default case: No more options, so break out of the loop. + break ;; + esac + shift + done +} + +parse_args "$@" + +[[ -z "${server_id}" ]] && + log "error" "A Server ID must be passed via the -s flag" && + exit 1 + +[[ -z "${workshop_id}" ]] && + log "error" "A Workshop ID must be passed via the -w flag" && + exit 1 + +[[ ! -d ~/Squad/Server-"${server_id}" ]] && + log "error" "Unable to find Squad-Server-${server_id}, has it been installed?" && + exit 1 + +# Download the mod +log "info" "Downloading mod ${workshop_id}..." +steamcmd +login anonymous +force_install_dir ~/Squad/Server-"${server_id}" +app_update 403240 validate +workshop_download_item 393380 "${workshop_id}" +quit + +[[ ! -d ~/Squad/Server-"${server_id}"/steamapps/workshop/conetent/393380/"${workshop_id}" ]] && + log "error" "Could not download ${workshop_id}, is that Workshop ID valid?" && + exit 1 + +log "info" "Finished downloading ${workshop_id}" + +log "info" "Removing old version of mod ${workshop_id} if it exists" +rm -rf ~/Squad/Server-"${server_id}"/SquadGame/Plugins/Mods/"${workshop_id}" >/dev/null 2>&1 + +[[ "${?}" == "0" ]] && + log "info" "Removed old mod ${workshop_id}" + +log "info" "Installing ${workshop_id} to Squad-Server-${server_id}..." +mv ~/Squad/Server-"${server_id}"/steamapps/workshop/conetent/393380/"${workshop_id}" \ + ~/Squad/Server-"${server_id}"/SquadGame/Plugins/Mods/"${workshop_id}" && + log "info" "Successfully installed mod ${workshop_id} to Squad-Server-${server_id}" || + log "error" "Unable to install mod ${workshop_id} to Squad-Server-${server_id}" diff --git a/CentOS/Squad/Squad-Install-Server.bash b/CentOS/Squad/Squad-Install-Server.bash index 41d2f75..d980fa8 100755 --- a/CentOS/Squad/Squad-Install-Server.bash +++ b/CentOS/Squad/Squad-Install-Server.bash @@ -175,8 +175,14 @@ important() { parse_args "$@" -mkdir -p ~/Squad/Server-"${server_id}" \ - && log "info" "Created a new Squad server directory at $(important ~/Squad/Server-"${server_id}")" +if [ -d ~/Squad/Server-"${server_id}" ]; then + log "error" "The directory for Squad-Server-${server_id} already exists, delete the directory if you mean to install a server to ~/Squad/Server-${server_id}" + exit 1 +else + mkdir -p ~/Squad/Server-"${server_id}" \ + && log "info" "Created a new Squad server directory at $(important ~/Squad/Server-"${server_id}")" +fi + steamcmd +login anonymous +force_install_dir ~/Squad/Server-"${server_id}" +app_update 403240 validate +quit log "info" "Successfully installed a Squad server to $(important ~/Squad/Server-"${server_id}")" \ No newline at end of file diff --git a/CentOS/Squad/Squad-Start-Server.bash b/CentOS/Squad/Squad-Start-Server.bash index 7a0f801..39b15ae 100755 --- a/CentOS/Squad/Squad-Start-Server.bash +++ b/CentOS/Squad/Squad-Start-Server.bash @@ -76,33 +76,33 @@ log() { message="${2}" case "${level}" in - INFO) - # Output all info log levels to stdout - printf "${FORMAT}[$(echo_rgb "INFO" 0 140 255)] %s\n" "${message}" >&1 - return 0 - ;; - WARN | WARNING) - # Output all info log levels to stdout - printf "${FORMAT}[$(echo_rgb "WARNING" 255 255 0)] %s\n" "${message}" >&1 - return 0 - ;; - DEBUG) - [[ ${debug} == 0 ]] && return - printf "${FORMAT}[$(echo_rgb "DEBUG" 0 160 110)] %s\n" "${message}" >&1 - return 0 - ;; - ERROR) - # Output all error log levels to stderr - printf "${FORMAT}[$(echo_rgb "ERROR" 255 0 0)] %s\n" "${message}" >&2 - return 0 - ;; - # Further log levels can be added by extending this switch statement with more comparisons + INFO) + # Output all info log levels to stdout + printf "${FORMAT}[$(echo_rgb "INFO" 0 140 255)] %s\n" "${message}" >&1 + return 0 + ;; + WARN | WARNING) + # Output all info log levels to stdout + printf "${FORMAT}[$(echo_rgb "WARNING" 255 255 0)] %s\n" "${message}" >&1 + return 0 + ;; + DEBUG) + [[ ${debug} == 0 ]] && return + printf "${FORMAT}[$(echo_rgb "DEBUG" 0 160 110)] %s\n" "${message}" >&1 + return 0 + ;; + ERROR) + # Output all error log levels to stderr + printf "${FORMAT}[$(echo_rgb "ERROR" 255 0 0)] %s\n" "${message}" >&2 + return 0 + ;; + # Further log levels can be added by extending this switch statement with more comparisons - *) # Default case, no matches - # Returns non-zero code as an improper log option was passed, this helps with using `set -e` - printf "${FORMAT}[ERROR] %s\n" "Invalid log level passed, received level \"${level}\" with message \"${message}\"" >&2 - return 1 - ;; + *) # Default case, no matches + # Returns non-zero code as an improper log option was passed, this helps with using `set -e` + printf "${FORMAT}[ERROR] %s\n" "Invalid log level passed, received level \"${level}\" with message \"${message}\"" >&2 + return 1 + ;; esac } @@ -131,15 +131,15 @@ confirmation() { while true; do read -p "${message} " -n 1 -r choice case "$choice" in - y | Y) + y | Y) echo "" return 0 ;; - n | N) + n | N) echo "" return 1 ;; - *) echo -e "\nInput must be either y, Y, n, or N" ;; + *) echo -e "\nInput must be either y, Y, n, or N" ;; esac done } @@ -157,15 +157,26 @@ usage() { # Yes # printf "Usage: %s\n" \ - "$(basename "${0}") -s + "$(important "$(basename "${0}") -s | $(basename "${0}") -s -v") -s | --server Which Squad server to start, see the ~/Squad directory -- each number corresponds to an ID Example: - --server 0" + --server 0 + + -v | --verify + Forces a verification check of the given Squad installation + + Example: + --verify" +} + +important() { + echo_rgb "${1}" 145 233 255 } server_id="" +verify=0 parse_args() { # Parse input arguments @@ -183,101 +194,99 @@ parse_args() { while :; do case ${1} in - -h | -\? | --help) - usage # Display a usage synopsis. - exit - ;; - --) # End of all options. - break - ;; - -s | --server) - shift - server_id="${1}" - [[ -z "${server_id}" ]] \ - && log "error" "Server requires an argument, e.g. --server 0" \ - && exit 1 - [[ ! "${server_id}" =~ [0-9] ]] \ - && log "error" "Server ID must be a number, received: ${server_id}" \ - && exit 1 - ;; - -?*) - printf 'Unknown option: %s\n' "$1" >&2 - usage - ;; - *) # Default case: No more options, so break out of the loop. - break ;; + -h | -\? | --help) + usage # Display a usage synopsis. + exit + ;; + --) # End of all options. + break + ;; + -s | --server) + shift + server_id="${1}" + [[ -z "${server_id}" ]] && \ + log "error" "Server requires an argument, e.g. --server 0" && \ + exit 1 + [[ ! "${server_id}" =~ [0-9] ]] && \ + log "error" "Server ID must be a number, received: ${server_id}" && \ + exit 1 + ;; + -v | --verify) + verify=1 + ;; + -?*) + printf 'Unknown option: %s\n' "$1" >&2 + usage + ;; + *) # Default case: No more options, so break out of the loop. + break ;; esac shift done } -important() { - echo_rgb "${1}" 145 233 255 -} - parse_args "$@" -### CONSTANTS ### -TICK_RATE="60" -### CONSTANTS ### +[[ -z "${server_id}" ]] \ + && log "error" "A server id must be passed via the -s flag" \ + && exit 1 +### CONSTANTS ### +TICK_RATE="30" +### CONSTANTS ### squad_directory=~/Squad/Server-"${server_id}" -[[ ! -d "${squad_directory}" ]] \ - && log "error" "The Squad directory does not exist at ${squad_directory}, unable to start $(important "${squad_directory}")" \ - && exit 1 +[[ ! -d "${squad_directory}" ]] && \ + log "error" "The Squad directory does not exist at ${squad_directory}, unable to start $(important "${squad_directory}")" && \ + exit 1 squad_start_script="${squad_directory}"/SquadGameServer.sh -[[ ! -f "${squad_start_script}" ]] \ - && log "error" "The given Squad server lacks a start script, could not find $(importamt "${squad_start_script}")" \ - && exit 1 - +[[ ! -f "${squad_start_script}" ]] && + log "error" "The given Squad server lacks a start script, could not find $(importamt "${squad_start_script}")" && + exit 1 + squad_rcon_config="${squad_directory}"/SquadGame/ServerConfig/Rcon.cfg -[[ ! -f "${squad_rcon_config}" ]] \ - && log "error" "The given Squad server lacks a Rcon.cfg, could not find $(important "${squad_rcon_config}")" \ - && exit 1 - +[[ ! -f "${squad_rcon_config}" ]] && \ + log "error" "The given Squad server lacks a Rcon.cfg, could not find $(important "${squad_rcon_config}")" && \ + exit 1 # If the tmux session exists then we prompt the user if they want to kill it off and start the new session -tmux has-session -t "Squad-Server-${server_id}" > /dev/null 2>&1 +tmux has-session -t "Squad-Server-${server_id}" >/dev/null 2>&1 if [ "${?}" == 0 ]; then log "warning" "Squad server $(important "Squad-Server-${server_id}") is currently running" confirmation "Would you like to kill it and then run the new one (y/N)?" if [ "${?}" == 0 ]; then log "info" "Ok, killing server $(important "Squad-Server-${server_id}")" - tmux kill-session -t "Squad-Server-${server_id}" \ - && log "info" "Successfully killed $(important "Squad-Server-${server_id}")" + tmux kill-session -t "Squad-Server-${server_id}" && + log "info" "Successfully killed $(important "Squad-Server-${server_id}")" else log "info" "Not ending current server $(important "Squad-Server-${server_id}"), exiting..." exit 0 fi fi - # Create our relevant ports -game_port=$(("13000" + "${server_id}")) -query_port=$(("13100" + "${server_id}")) +game_port=$(("13000" + $(("${server_id}" * 2)))) +query_port=$(("13100" + $(("${server_id}" * 2)))) rcon_port=$(("13200" + "${server_id}")) - # Create backups before modifying files backup_extension="$(date +%Y-%m-%dT%H:%M:%S%z)" mkdir -p "${squad_directory}"/Backups/ log "info" "Creating a backup of $(important "Rcon.cfg")" -cp "${squad_directory}"/SquadGame/ServerConfig/Rcon.cfg "${squad_directory}"/Backups/Rcon.cfg."${backup_extension}" \ - && log "info" "Successfully created a backup of $(important "Rcon.cfg")" - +cp "${squad_directory}"/SquadGame/ServerConfig/Rcon.cfg "${squad_directory}"/Backups/Rcon.cfg."${backup_extension}" && + log "info" "Successfully created a backup of $(important "Rcon.cfg")" ## RCON configuration # If we haven't created a rcon.password file go ahead and make it and generate a password for it if [ ! -f ~/Squad/rcon.password ]; then log "info" "Creating a global rcon password in $(important ~/Squad/rcon.password) as it did not exist" - openssl rand -base64 48 > ~/Squad/rcon.password + openssl rand -base64 48 >~/Squad/rcon.password fi # Get the rcon password @@ -286,8 +295,7 @@ rcon_password="$(cat ~/Squad/rcon.password)" log "info" "Updating $(important "Squad-Server-${server_id}")'s RCON config" # Update the password, since sed is PIA in regards to base64 & raw strings we fix this one up line by line -while read -r line -do +while read -r line; do if [[ "${line}" == Password=* ]]; then # Overwrites the password @@ -299,26 +307,33 @@ do else echo "${line}" fi -done < "${squad_rcon_config}" > "rcon.temp" && mv "rcon.temp" "${squad_rcon_config}" +done <"${squad_rcon_config}" >"rcon.temp" && mv "rcon.temp" "${squad_rcon_config}" log "info" "Successfully updated RCON config" +if [ "${verify}" -eq "1" ]; then + log "info" "Verification of game files requested" + log "info" "Verifying the Squad install located at $(important "${squad_directory}")" + steamcmd +login anonymous +force_install_dir "${squad_directory}" +app_update 403240 validate +quit + log "info" "Finished verifying files" +fi + log "info" \ "Starting $(important "Squad-Server-${server_id}") with the following parameters: $(important \ - "-Port=${game_port} - -QueryPort=${query_port} - -FIXEDMAXTICKRATE=${TICK_RATE} - -USEALLAVAILABLECORES - -LOG")" + "Port=${game_port} + QueryPort=${query_port} + FIXEDMAXTICKRATE=${TICK_RATE} + USEALLAVAILABLECORES + LOG")" # Kick off a new tmux session containing the Squad Server echo | tmux new-session -d -s "Squad-Server-${server_id}" \ - "${squad_start_script}" -Port="${game_port}" -QueryPort="${query_port}" -FIXEDMAXTICKRATE="${TICK_RATE}" \ - -USEALLAVILABLECORES -LOG && -log "info" \ - "Started Squad-Server-${server_id} with the following ports: + "${squad_start_script}" Port="${game_port}" QueryPort="${query_port}" FIXEDMAXTICKRATE="${TICK_RATE}" \ + USEALLAVILABLECORES LOG && + log "info" \ + "Started Squad-Server-${server_id} with the following ports: $(important \ - "Game Port: ${game_port} + "Game Port: ${game_port} Query Port: ${query_port} - RCON Port ${rcon_port}")" + RCON Port ${rcon_port}")" \ No newline at end of file