### IMPORTS ### # "Import" our needed functions from our library LIBRARY_PATH="/usr/local/lib/Custom-Scripts" # shellcheck source=/usr/local/lib/ if ! source "${LIBRARY_PATH}/Logging-RGB.bash"; then echo "Unable to source Logging-RGB.bash at ${LIBRARY_PATH}" exit 1 fi # shellcheck source=/usr/local/lib/ if ! source "${LIBRARY_PATH}/Confirmation.bash"; then log "error" "Unable to source Confirmation.bash at ${LIBRARY_PATH}" fi ### IMPORTS ### ### CONSTANTS ### START_PORT_RANGE=50000 BASE_DIR="${HOME}/7-Days-To-Die" ### CONSTANTS ### important() { echo_rgb "${1}" 135 195 255 } start_server() { local server_id local can_kill server_id="" can_kill=1 while :; do case ${1} in -h | -\? | --help) printf "Usage: %s\n" \ "start [options] --server | -s Starts the given server id Example: --server 3 --can-kill | -c Automatically kills the server if it is running without prompting Example: --can-kill" exit ;; --) # End of all options. break ;; --server | -s) shift server_id="${1}" [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 ;; --can-kill | -c) can_kill=0 ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 local server_directory local server_config local server_name local prefix local server_session_name server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" server_config="${server_directory}/serverconfig.xml" prefix="7D2D" server_session_name="${prefix}-${server_name}" [[ ! -d "${server_directory}" ]] && log "error" "Unable to find the server directory for $(important "${server_name}")" && return 1 local server_port server_port="$(( START_PORT_RANGE + server_id ))" log "info" "Starting $(important "${server_name}") located at $(important "${server_directory}") on port $(important "${server_port}")" # Overwrite values that we want to control, e.g. server port while IFS='' read -r; do if [[ "${REPLY}" = *"ServerPort"* ]]; then printf "\t%s\n" "" else printf "%s\n" "${REPLY}" fi done < "${server_config}" > "temp-serverconfig.xml" if [[ ! "$(tail "temp-serverconfig.xml" -n 1 )" = *"ServerSettings"* ]]; then printf "\n" >> "temp-serverconfig.xml" fi local backups_dir local backup_file backups_dir="${server_directory}/Config-Backups" backup_file="${backups_dir}/serverconfig.xml-$(date +%s)" mkdir -p "${backups_dir}" cp "${server_config}" "${backup_file}" mv "temp-serverconfig.xml" "${server_config}" if tmux has-session -t "${server_session_name}" >/dev/null 2>&1; then log "warning" "$(important "${server_name}") is currently running" if (( can_kill == 0 )); then log "info" "Been explicitly permitted to kill, bypassing confirmation" kill_server -s "${server_id}" else if confirmation "Would you like to kill $(important "${server_name}")? (Y/n)" ; then log "info" "Given answer $(important "yes") to kill the server, killing $(important "${server_name}")" kill_server -s "${server_id}" else log "info" "Given answer $(important "no") to kill the server, exiting" exit 0 fi fi fi log "info" "Creating new session for $(important "${server_name}") as session $(important "${server_session_name}")" tmux new-session -d -s "${server_session_name}" tmux send-keys \ "until ${server_directory}/startserver.sh -configfile=${server_directory}/serverconfig.xml; do echo 'Server died with code $?, restarting in 60 seconds...' >&2 sleep 60; done" C-m log "info" "Finished starting $(important "${server_name}") on port $(important "${server_port}") as tmux session $(important "${server_session_name}")" } kill_server() { local prefix local tmux_response local server_id server_id="" prefix="7D2D" while :; do case ${1} in -h | -\? | --help) printf "Usage: %s\n" \ "kill [options] --server | -s Forcefully kills the server with the given id Example: --server 3" exit ;; --) # End of all options. break ;; --server | -s) shift server_id="${1}" [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 if tmux kill-session -t "${prefix}-Server-${server_id}" >/dev/null 2>&1; then log "info" "Stopped $(important "${prefix}-Server-${server_id}")" return 0 else log "error" "$(important "${prefix}-Server-${server_id}") is not running" return 1 fi } install() { local server_id server_id="" while :; do case ${1} in -h | -\? | --help) printf "Usage: %s\n" \ "install [OPTIONS] --server | -s Installs the server to the given id if it doesn't exist Example: --server 3" exit ;; --) # End of all options. break ;; --server | -s) shift server_id="${1}" [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 local prefix prefix="7D2D" local server_name local server_directory server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" # Ensure that the global mods directory exists [[ -d "${server_directory}" ]] && log "error" "A server already exists at $(important "${server_directory}"), delete it and try again" && exit 1 log "info" "Installing $(important "${server_name}") to $(important "${server_directory}")" steamcmd +force_install_dir "${server_directory}" +login anonymous +app_update 294420 validate +quit mkdir -p "${server_directory}/Mods" log "info" "Successfully installed $(important "${server_name}") to $(important "${server_directory}")" } update() { local server_id server_id="" while :; do case ${1} in -h | -\? | --help) printf "Usage: %s\n" \ "update [OPTIONS] --server | -s Updates the given server id Example: --server 3" exit ;; --) # End of all options. break ;; --server | -s) shift server_id="${1}" [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 # Kill the server to ensure a smooth update kill_server -s "${server_id}" >/dev/null 2>&1 local server_directory local server_name server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" backup -s "${server_id}" log "info" "Updating server $(important "${server_name}") located at $(important "${server_directory}")..." steamcmd +force_install_dir "${server_directory}" +login anonymous +app_update 294420 validate +quit log "info" "Finished updating $(important "${server_name}") located at $(important "${server_directory}")" } backup() { local server_id server_id="" while :; do case ${1} in -h | -\? | --help) printf "Usage: %s\n" \ "backup [OPTIONS] --server | -s Backups the given server id Example: --server 3" exit ;; --) # End of all options. break ;; --server | -s) shift server_id="${1}" [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done [[ -z "${server_id}" ]] && log "error" "No server id passed" && exit 1 # Kill the server to ensure a smooth backup kill_server -s "${server_id}" >/dev/null 2>&1 local backup_dir local backup_full_path local server_directory local server_name server_name="Server-${server_id}" server_directory="${BASE_DIR}/${server_name}" backup_dir="${HOME}/Server-Backups/${server_name}" backup_full_path="${backup_dir}/$(date +%s).tar.gz" [[ ! -d "${server_directory}" ]] && log "info" "The server $(important "${server_name}") had no directory located at $(important "${server_directory}")" && exit 1 log "info" "Backing up server $(important "${server_name}") to $(important "${backup_full_path}"), this may take a while" mkdir -p "${backup_dir}" tar cf - "${server_directory}" -P | pv -s "$(du -sb "${server_directory}" | awk '{print $1}')" | \ gzip > "${backup_full_path}" tar -czf "${server_directory}" "${backup_dir}"/ } list_servers() { local picked_option picked_option="" while :; do case ${1} in -h | -\? | --help) printf "Usage: %s\n" \ "list [OPTIONS] --running | -r Lists the currently running 7 Days To Die Servers Example: --running --installed | -i Lists the currently installed 7 Days To Die Servers Example: --installed" exit ;; --) # End of all options. break ;; --running | -r) picked_option=0 ;; --installed | -i) picked_option=1 ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 return 1 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done [[ -z "${picked_option}" ]] && log "error" "An option must be passed for list, check list -h" && return 1 if (( picked_option == 0 )); then log "debug" "Listing running servers" local tmux_sessions tmux_sessions="$(tmux list-sessions)" >/dev/null 2>&1 if [[ ! "${?}" -eq "0" ]]; then important "No servers currently running." fi while read -r; do if [[ "${REPLY}" = *"-Server-"* ]]; then local running_server running_server="$(echo "${REPLY}" | cut -d ":" -f1)" important "${running_server}" fi done <<< "${tmux_sessions}" elif (( picked_option == 1 )); then log "debug" "Listing installed servers" while read -r; do important "${BASE_DIR}/${REPLY}" done <<< "$(find "${BASE_DIR}" -name "startserver.sh" | cut -d "/" -f5)" fi } usage() { # Print out usage instructions for the local script # # Arguments: # None # # Usage: # usage # # POSIX Compliant: # Yes # printf "Usage: %s\n" \ "$(basename "${0}") -h start Exposes options to start 7 Days To Die Servers, pass -h to it for details kill Exposes options to kill 7 Days To Die Servers, pass -h to it for details install Exposes options to install 7 Days To Die Servers, pass -h to it for details update Exposes options to update 7 Days To Die Servers, pass -h to it for details list Exposes options to list 7 Days To Die Servers, pass -h to it for details backup Exposes options to backup 7 Days To Die Servers, pass -h to it for details" } main() { # 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 ;; start | s) shift start_server "$@" break ;; kill | k) shift kill_server "$@" break ;; install | i) shift install "$@" break ;; update | u) shift update "$@" break ;; list | l) shift list_servers "$@" break ;; backup | b) shift backup "$@" break ;; -?*) printf "Unknown option: %s\n" "$1" >&2 usage exit 1 ;; *) # Default case: No more options, so break out of the loop. break ;; esac shift done } main "$@"