diff --git a/CentOS/Minecraft/Minecraft-Start-Server.bash b/CentOS/Minecraft/Minecraft-Start-Server.bash index f4aa58c..3c2c9de 100755 --- a/CentOS/Minecraft/Minecraft-Start-Server.bash +++ b/CentOS/Minecraft/Minecraft-Start-Server.bash @@ -3,11 +3,47 @@ ### CONSTANTS ### #gigabytes -MAX_RAM=8 +MAX_MEM=8 #gigabytes INITIAL_MEM=2 +#rcon password +DEFAULT_RCON_PASSWORD="" + +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 10 80 3 "Yep" + # + # 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. @@ -36,7 +72,7 @@ log() { fi local FORMAT - FORMAT="[$(date +%Y-%m-%dT%H:%M:%S%z)]" + FORMAT="[$(echo_rgb "$(date +%Y-%m-%dT%H:%M:%S%z)" 180 140 255)]" # Convert the level to uppercase local level @@ -48,28 +84,74 @@ log() { case "${level}" in INFO) # Output all info log levels to stdout - printf "${FORMAT}[INFO] %s\n" "${message}" >&1 + 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 0 - printf "${FORMAT}[DEBUG] %s\n" "${message}" >&1 + printf "${FORMAT}[$(echo_rgb "DEBUG" 0 160 110)] %s\n" "${message}" >&1 return 0 ;; ERROR) # Output all error log levels to stderr - printf "${FORMAT}[ERROR] %s\n" "${message}" >&2 + 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` - log "ERROR" "Invalid log level passed, received level \"${level}\" with message \"${message}\"" + 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 # @@ -97,6 +179,7 @@ usage() { server_id="" minecraft_jar="" +rcon_ignore=0 parse_args() { # Parse input arguments @@ -129,6 +212,9 @@ parse_args() { shift minecraft_jar="${1}" ;; + -r | --rcon-ignore) + rcon_ignore=1 + ;; -?*) printf 'Unknown option: %s\n' "$1" >&2 usage @@ -150,13 +236,23 @@ parse_args "$@" minecraft_directory=~/Minecraft/Server-"${server_id}" mkdir -p "${minecraft_directory}" +mkdir -p "${minecraft_directory}/backups" + cd "${minecraft_directory}" || (log "error" "Unable to change directory to ${minecraft_directory}" && exit 1) -if [ ! -z "${minecraft_jar}" ]; then - [[ -d "${minecraft_jar}" ]] || (log "error" "Could not find a minecraft server jar at \"${minecraft_jar}\"" && exit 1) - minecraft_jar_name="$(basename ${minecraft_jar})" - mv "${minecraft_jar}" "${minecraft_directory}/server.jar" - java -jar "${minecraft_directory}/${minecraft_jar_name}" +if [ -n "${minecraft_jar}" ]; then + if [ ! -f "${minecraft_jar}" ]; then + log "error" "Could not find a minecraft server jar \"${minecraft_jar}\"" + exit 1 + fi + minecraft_jar_name="$(basename "${minecraft_jar}")" + log "info" "Copying minecraft server files..." + cp "${minecraft_jar}" "${minecraft_directory}" \ + && log "info" "Finished copying files" + mv "${minecraft_directory}/${minecraft_jar_name}" "${minecraft_directory}/server.jar" + log "info" "Installed a minecraft server.jar to Minecraft-Server-${server_id}" + java -jar "${minecraft_directory}"/server.jar > /dev/null 2>&1 + log "info" "Successfully installed the minecraft server.jar to Minecraft-Server-${server_id}, continuing with setup" elif [ ! -d "${minecraft_directory}" ]; then log "error" "The minecraft server \"${minecraft_directory}\" did not exist, to create it please pass the \"--jar\" flag..." exit 1 @@ -167,23 +263,67 @@ query_port=$(("12100" + "${server_id}")) rcon_port=$(("12200" + "${server_id}")) -## Set the correct ports -sed -i "s/server-port=.+/server-port=${server_port}/g" server.properties \ - && log "info" "Set the server port to ${server_port}" -sed -i "s/query.port=.+/query.port=${query_port}/g" server.properties \ +## Create a backup of the config file +backup_extension="$(date +%Y-%m-%dT%H:%M:%S%z)" + +log "info" "Making a backup of the server.properties file in ${minecraft_directory}/backups/server.properties.${backup_extension}" +rm -f +cp "${minecraft_directory}/server.properties" "${minecraft_directory}/backups/server.properties.${backup_extension}" \ + && log "info" "Successfully created backup" + +## Set the correct ports +sed -i "s/server-port=.*/server-port=${server_port}/g" server.properties \ + && log "info" "Set the server port to ${server_port}" || exit 1 + +sed -i "s/query.port=.*/query.port=${query_port}/g" server.properties \ + && log "info" "Set the query port to ${query_port}" || exit 1 + +sed -i "s/rcon.port=.*/rcon.port=${rcon_port}/g" server.properties \ + && log "info" "Set the RCON port to ${rcon_port}" || exit 1 -sed -i "s/rcon.port=.+/rcon.port=${rcon_port}/g" server.properties ## Turn RCON On -# set the rcon password to the default -log "info" "Setting the RCON password..." +# set the rcon password to the default if rcon-ignore is not set +if [[ "${rcon_ignore}" == 0 ]]; then + log "info" "Setting the RCON password..." -default_rcon_password="" -[[ -z "${default_rcon_password}" ]] \ - && log "error" "No RCON password has been defined within $(basename "${0}") -- exiting!" \ - && exit 1 + [[ -z "${DEFAULT_RCON_PASSWORD}" ]] \ + && log "warning" "No RCON password has been defined within $(basename "${0}"), consider generating one with \"openssl rand -base64 36\"" -sed -i "s/rcon.password=.+/rcon.password=${default_rcon_password}/g" server.properties \ - && log "info" "RCON password set" + sed -i "s/rcon.password=.+/rcon.password=${DEFAULT_RCON_PASSWORD}/g" server.properties \ + && log "info" "RCON password set" +fi +## Accept the eula +sed -i "s/eula=false/eula=true/g" eula.txt \ + && log "info" "Minecraft eula accepted" +## Go ahead and start 'er on up + +tmux has-session -t "Minecraft-Server-${server_id}" > /dev/null 2>&1 + +if [ "${?}" == 0 ]; then + log "warning" "That minecraft server 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..." + tmux kill-session -t "Minecraft-Server-${server_id}" \ + && log "info" "Successfully killed the server" + else + log "info" "Not ending current Minecraft-Server-${server_id}, exiting..." + exit 0 + fi +fi + +log "info" \ +"Startup Arguments: + -Xms${INITIAL_MEM}G + -Xmx${MAX_MEM}G + -jar" + +log "info" "Starting Minecraft-Server-${server_id}" + +tmux new-session -d -s \ + "Minecraft-Server-${server_id}" \ + java -Xms"${INITIAL_MEM}G" -Xmx"${MAX_MEM}G" -jar server.jar --nogui \ + && log "info" "Server Minecraft-Server-${server_id} started successfully!"