From 1a5a192f71fbe16f4a88f9dac0f590f544b62524 Mon Sep 17 00:00:00 2001 From: Marcus Whybrow Date: Mon, 11 Jun 2012 19:15:04 +0100 Subject: [PATCH] WIP commit on refactoring command registration. Removes the repetitive and gigantic case statement, and adds a register_command function. This function generates a regex for matching that command and a handler function to call. The entry point into the script now matches the user input against a regex and calls the handler function. --- init/msm | 1547 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 813 insertions(+), 734 deletions(-) diff --git a/init/msm b/init/msm index 6b9becc..e00d891 100755 --- a/init/msm +++ b/init/msm @@ -285,6 +285,7 @@ server_get_id() { # $1: The ID of the server # $2: The name of the world server_world_get_id() { + debug "server_world_get_id($1, $2)" if [ -d "${server_world_storage[$1]}/$2" ] || [ -d "${server_world_storage_inactive[$1]}/$2" ]; then # If the directory exists @@ -300,7 +301,7 @@ server_world_get_id() { done fi - error_exit NAME_NOT_FOUND "Could not find id for world \"$2\" for server \"$1\"." + error_exit NAME_NOT_FOUND "Could not find id for world \"$2\" for server \"${server_name[$1]}\"." } # Returns 0 if the server $1 is running and 1 if not @@ -1180,6 +1181,576 @@ manager_stop_all_servers_now() { } +### Command Functions + +command_start() { + # Required start option, for debian init.d scripts + for ((server=0; server<${num_servers}; server++)); do + # Only starts active servers + if "${server_active[$server]}"; then + if server_is_running "$server"; then + echo "[ACTIVE] Server \"${server_name[$server]}\" already started." + else + echo "[ACTIVE] Server \"${server_name[$server]}\" starting:" + server_start "$server" + fi + else + if server_is_running "$server"; then + echo "[INACTIVE] Server \"${server_name[$server]}\" already started. It should not be running! Use \"$0 ${server_name[$server]} stop\" to stop this server." + else + echo "[INACTIVE] Server \"${server_name[$server]}\" leaving stopped, as this server is inactive." + fi + fi + done +} + +command_stop() { + manager_stop_all_servers "stop" +} + +command_stop_now() { + manager_stop_all_servers_now +} + +command_restart() { + echo "Stopping servers:" + command_stop + + echo "Starting servers:" + command_start +} + +command_restart_now() { + echo "Stopping servers:" + command_stop_now + + echo "Starting servers:" + command_start +} + +command_version() { + echo "Minecraft Server Manager $VERSION" +} + +command_server_list() { + server_list +} + +command_server_create() { + server_create "$3" +} + +command_server_delete() { + server_delete "$3" +} + +command_server_rename() { + server_rename "$3" "$4" +} + +command_jargroup_list() { + jargroup_list +} + +command_jargroup_create() { + jargroup_create "$3" "$4" +} + +command_jargroup_delete() { + jargroup_delete "$3" +} + +command_jargroup_rename() { + jargroup_rename "$3" "$4" +} + +command_jargroup_changetarget() { + jargroup_settarget "$3" "$4" +} + +command_jargroup_getlatest() { + jargroup_getlatest "$3" +} + +command_help() { + # Outputs a list of all commands + echo -e "Usage: $0 command:" + echo -e + echo -e "--Setup Commands------------------------------------------------" + echo -e " server list List servers" + echo -e " server create Creates a new Minecraft server" + echo -e " server delete Deletes an existing Minecraft server" + echo -e " server rename Renames an existing Minecraft server" + echo -e + echo -e "--Server Mangement Commands-------------------------------------" + echo -e " start Starts a server" + echo -e " stop [now] Stops a server after warning players, or right now" + echo -e " restart [now] Restarts a server after warning players, or right now" + echo -e " status Show the running/stopped status of a server" + echo -e " connected List a servers connected players" + echo -e " worlds list Lists the worlds a server has" + echo -e " worlds load Creates links to worlds in storage for a server" + echo -e " worlds ram Toggles a world's \"in RAM\" status" + echo -e " worlds todisk Synchronises any \"in RAM\" worlds to disk a server has" + echo -e " worlds backup Makes a backup of all worlds a server has" + echo -e " worlds on|off Activate or deactivate a world, inactive worlds are not backed up" + echo -e " logroll Move a server log to a gziped archive, to reduce lag" + echo -e " backup Makes a backup of an entire server directory" + echo -e " jar [] Sets a server's jar file" + echo -e + echo -e "--Server Pass Through Commands----------------------------------" + echo -e " wl on|off Enables/disables server whitelist checking" + echo -e " wl add|remove Add/remove a player to/from a server's whitelist" + echo -e " wl list List the players whitelisted for a server" + echo -e " bl player add|remove Ban/pardon a player from/for a server" + echo -e " bl ip add|remove Ban/pardon an IP address from/for a server" + echo -e " bl list Lists the banned players and IP address for a server" + echo -e " op add|remove Add/remove operator status for a player on a server" + echo -e " op list Lists the operator players for a server" + echo -e " gm survival|creative Change the game mode for a player on a server" + echo -e " kick Forcibly disconnect a player from a server" + echo -e " say Broadcast a (pink) message to all players on a server" + echo -e " time set|add Set/increment time on a server (0-24000)" + echo -e " toggledownfall Toggles rain and snow on a server" + echo -e " save on|off Enable/disable writing world changes to file" + echo -e " save all Force the writing of all non-saved world changes to file" + echo -e " cmd Send a command string to the server and return" + echo -e " cmdlog Same as 'cmd' but shows log output afterwards (Ctrl+C to exit)" + echo -e + echo -e "--Jar Commands--------------------------------------------------" + echo -e " jargroup list List the stored jar files." + echo -e " jargroup create Create a new jar group, with a URL for new downloads" + echo -e " jargroup delete Delete a jar group" + echo -e " jargroup rename Rename a jar group" + echo -e " jargroup changeurl Change the download URL for a jar group" + echo -e " jargroup getlatest Download the latest jar file for a jar group" + echo -e + echo -e "--Global Commands-----------------------------------------------" + echo -e " start Starts all active servers" + echo -e " stop [now] Stops all running servers" + echo -e " restart [now] Restarts all active servers" + echo -e " version Prints the Minecraft Server Manager version installed8" +} + +command_server_start() { + server_set_active "$id" "active" + server_start "$id" +} + +command_server_stop() { + server_set_active "$id" "inactive" + server_stop "$id" +} + +command_server_stop_now() { + server_set_active "$id" "inactive" + server_stop_now "$id" +} + +command_server_restart() { + server_set_active "$1" "active" + server_restart "$id" +} + +command_server_restart_now() { + server_set_active "$1" "active" + server_restart_now "$id" +} + +command_server_status() { + if server_is_running "$1"; then + echo "Server \"${server_name[$1]}\" is running." + else + echo "Server \"${server_name[$1]}\" is stopped." + fi +} + +command_server_connected() { + server_connected "$id" +} + +command_server_worlds_list() { + server_worlds_list "$id" +} + +command_server_worlds_load() { + server_ensure_links "$id" +} + +command_server_worlds_ram() { + debug "command_server_worlds_ram($1, $2, $3, $4)" + world_toggle_ramdisk_state "$4" +} + +command_server_worlds_todisk() { + server_save_off "$id" + server_save_all "$id" + server_worlds_to_disk "$id" + server_save_on "$id" +} + +command_server_worlds_backup() { + if server_is_running "$id"; then + server_eval "$id" "say ${server_world_backup_started[$id]}" + server_save_off "$id" + server_save_all "$id" + fi + + server_worlds_to_disk "$id" + server_worlds_backup "$id" + + if server_is_running "$id"; then + server_save_on "$id" + server_eval "$id" "say ${server_world_backup_finished[$id]}" + fi + + echo "Backup took $SECONDS seconds". +} + +command_server_worlds_on() { + world_activate "$(server_world_get_id "$id" "$4")" +} + +command_server_worlds_off() { + world_deactivate "$(server_world_get_id "$id" "$4")" +} + +command_server_logroll() { + server_log_roll "$id" +} + +command_server_backup() { + if server_is_running "$id"; then + server_eval "$id" "say ${server_complete_backup_started[$id]}" + server_save_off "$id" + server_save_all "$id" + fi + + server_worlds_to_disk "$id" + server_backup "$id" + + if server_is_running "$id"; then + server_save_on "$id" + server_eval "$id" "say ${server_complete_backup_finished[$id]}" + fi + + echo "Backup took $SECONDS seconds". +} + +command_server_jar() { + server_set_jar "$id" "$3" "$4" +} + +command_server_whitelist_on() { + if server_is_running "$id"; then + server_eval "$id" "whitelist on" + echo "Whitelist enabled" + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_whitelist_off() { + if server_is_running "$id"; then + server_eval "$id" "whitelist off" + echo "Whitelist disabled" + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_whitelist_add() { + if server_is_running "$id"; then + server_eval "$id" "whitelist add $4" + echo "Added \"$4\" to the whitelist." + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_whitelist_remove() { + if server_is_running "$id"; then + server_eval "$id" "whitelist remove $4" + echo "Removed \"$4\" from the whitelist." + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_whitelist_list() { + local players="$(cat "${server_whitelist[$id]}")" + + if [ -z "$players" ]; then + echo "No players are whitelisted." + else + echo "$players" + fi +} + +command_server_blacklist_player_add() { + for player in ${*:5}; do + server_eval "$id" "ban $player" + done + + if [[ $# -gt 5 ]]; then + echo -n "Blacklisted the following players: " + echo -n "$5" + for player in ${*:6}; do + echo -n ", $player" + done + echo "." + else + echo "Blacklisted \"$5\"." + fi +} + +command_server_blacklist_player_remove() { + for player in ${*:5}; do + server_eval "$id" "pardon $player" + done + + if [[ $# -gt 5 ]]; then + echo -n "Removed the following players from the blacklist: " + echo -n "$5" + for player in ${*:6}; do + echo -n ", $player" + done + echo "." + else + echo "Removed \"$5\" from the blacklist." + fi +} + +command_server_blacklist_ip_add() { + for address in ${*:5}; do + server_eval "$id" "ban-ip $address" + done + + if [[ $# > 5 ]]; then + echo -n "Blacklisted the following ip addresses: " + echo -n "$5" + for player in ${*:6}; do + echo -n ", $address" + done + echo "." + else + echo "Blacklisted \"$5\"." + fi +} + +command_server_blacklist_ip_remove() { + for address in ${*:5}; do + server_eval "$id" "pardon-ip $address" + done + + if [[ $# > 5 ]]; then + echo -n "Removed the following ip addresses from the blacklist: " + echo -n "$5" + for player in ${*:6}; do + echo -n ", $address" + done + echo "." + else + echo "Removed \"$5\" from the ip blacklist." + fi +} + +command_server_blacklist_list() { + local players="$(cat "${server_banned_players[$id]}")" + + local ips="$(cat "${server_banned_ips[$id]}")" + + if [[ -z "$players" && -z "$ips" ]]; then + echo "The blacklist is empty." + else + if [[ ! -z "$players" ]]; then + echo "Players:" + for name in $players; do + echo " $name" + done + fi + + if [[ ! -z "$ips" ]]; then + echo "IP Addresses:" + for address in $ips; do + echo " $address" + done + fi + fi +} + +command_server_operator_add() { + if server_is_running "$1"; then + server_eval "$1" "op $2" + echo "The player \"$2\" is now an operator for the server." + else + error_exit SERVER_STOPPED "Server \"${server_name[$1]}\" is not running." + fi +} + +command_server_operator_remove() { + if server_is_running "$id"; then + server_eval "$id" "deop $4" + echo "The player \"$4\" is no longer an operator for the server." + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_operator_list() { + local players="$(cat "${server_ops[$id]}")" + + if [ -z "$players" ]; then + echo "No players are operators." + else + echo "$players" + fi +} + +command_server_gamemode() { + if server_is_running "$id"; then + case "$3" in + creative|1) local mode=1;; + survival|0) local mode=0;; + *) error_exit INVALID_ARGUMENT "Invalid gamemode type \"$3\" options are \"survival\", \"creative\", \"0\" or \"1\".";; + esac + + local line="$(server_eval_and_get_line "$id" "gamemode $4 $mode" "${server_confirm_gamemode[$id]}" "${server_confirm_gamemode_fail_no_user[$id]}" "${server_confirm_gamemode_fail_no_change[$id]}")" + + local regex="${LOG_REGEX} ${server_confirm_gamemode[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "Changed game mode of \"$4\" to \"$3\"." + fi + local regex="${LOG_REGEX} ${server_confirm_gamemode_fail_no_user[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "The player \"$4\" was not found to be logged on." + fi + local regex="${LOG_REGEX} ${server_confirm_gamemode_fail_no_change[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "The player \"$4\" was already in mode \"$3\"." + fi + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_kick() { + if server_is_running "$id"; then + local line="$(server_eval_and_get_line "$id" "kick $3" "${server_confirm_kick[$id]}" "${server_confirm_kick_fail[$id]}")" + + local regex="${LOG_REGEX} ${server_confirm_kick[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "Kicked \"$3\" from game." + fi + local regex="${LOG_REGEX} ${server_confirm_kick_fail[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "The player \"$3\" is not connected." + fi + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_say() { + if server_is_running "$id"; then + server_eval "$id" "say ${*:3}" + echo "Message sent to players." + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_time_set() { + if server_is_running "$id"; then + local line="$(server_eval_and_get_line "$id" "time set $4" "${server_confirm_time_set[$id]}" "${server_confirm_time_set_fail[$id]}")" + + local regex="${LOG_REGEX} ${server_confirm_time_set[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "Set time to \"$4\"." + fi + local regex="${LOG_REGEX} ${server_confirm_time_set_fail[$id]}" + if [[ "$line" =~ $regex ]]; then + error_exit INVALID_ARGUMENT "Unable to convert \"$4\" to a time." + fi + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_time_add() { + if server_is_running "$id"; then + local line="$(server_eval_and_get_line "$id" "time add $4" "${server_confirm_time_add[$id]}" "${server_confirm_time_add_fail[$id]}")" + + local regex="${LOG_REGEX} ${server_confirm_time_add[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "Added \"$4\" to time." + fi + local regex="${LOG_REGEX} ${server_confirm_time_add_fail[$id]}" + if [[ "$line" =~ $regex ]]; then + error_exit INVALID_ARGUMENT "Unable to convert \"$4\" to a time." + fi + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_toggledownfall() { + if server_is_running "$id"; then + local line="$(server_eval_and_get_line "$id" "toggledownfall $3" "${server_confirm_toggledownfall[$id]}" "${server_confirm_toggledownfall_fail[$id]}")" + + local regex="${LOG_REGEX} ${server_confirm_toggledownfall[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "${line:36:(-3)}" + fi + local regex="${LOG_REGEX} ${server_confirm_toggledownfall_fail[$id]}" + if [[ "$line" =~ $regex ]]; then + echo "${line:34:(-3)}" + fi + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_save_on() { + server_save_on "$id" +} + +command_server_save_off() { + server_save_off "$id" +} + +command_server_save_all() { + server_save_all "$id" +} + +command_server_cmd() { + if server_is_running "$id"; then + server_eval "$id" "${*:3}" + echo "Command sent." + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_cmdlog() { + if server_is_running "$id"; then + server_eval "$id" "${*:3}" + echo "Now watching logs (press Ctrl+C to exit):" + as_user "${server_user_name[$id]}" "tail --pid=$$ --follow --lines=0 --sleep-interval=0.1 ${server_log[$id]}" + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + +command_server_console() { + if server_is_running "$id"; then + as_user "${server_user_name[$1]}" "screen -r ${server_screen_name[$1]}" + else + error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." + fi +} + + ### Main Functions # Initialises a server's world @@ -1526,6 +2097,186 @@ interrupt() { exit } +COMMAND_COUNT=0 + +# Adds a command to the list, allowing it to be called from the command line. +# $1: The command signature, a coded string describing the structure of the +# command. +# $2: The handler function to call, if this command is identified. +register_command() { + local regex="^" + for word in $1; do + # Required argument + if [[ "$word" =~ ^\<.*\>$ ]]; then + local contents="${word:1:(-1)}" + regex="${regex}.+ " + continue + fi + + # Optional argument + if [[ "$word" =~ ^\[.*\]$ ]]; then + local contents="${word:1:(-1)}" + regex="${regex}.+ " + continue + fi + + if [[ "$word" =~ \| ]]; then + regex="${regex}($word) " + continue + fi + + # Constant string + regex="${regex}$word " + done + + regex="${regex:0:(-1)}$" + + COMMAND_SIGNATURE[$COMMAND_COUNT]="$1" + COMMAND_REGEX[$COMMAND_COUNT]="$regex" + COMMAND_HANDLER[$COMMAND_COUNT]="$2" + + COMMAND_COUNT=$(( $COMMAND_COUNT + 1 )) +} + +# Match and call a command from user input +# $*: User input +call_command() { + for ((i=0; i<$COMMAND_COUNT; i++)); do + if [[ "$*" =~ ${COMMAND_REGEX[$i]} ]]; then + local word_offset=1 + local args + local arg_offset=0 + local sid=-1 + local wid=-1 + + push_arg() { + args[$arg_offset]="$1" + arg_offset="$(( $arg_offset + 1 ))" + } + + for word in ${COMMAND_SIGNATURE[$i]}; do + case "$word" in + "") + local specified_name="${!word_offset}" + if [[ "$specified_name" == "all" ]]; then + # Do for all servers + sid="server:all" + else + if is_valid_name "$specified_name"; then + if [ -d "$SERVER_STORAGE_PATH/$1" ]; then + sid="$(server_get_id "$1")" + fi + fi + + if [ -z "$sid" ]; then + error_exit NAME_NOT_FOUND "There is no server with the name \"$specified_name\"." + fi + fi + + push_arg "$sid" + ;; + "") + local specified_name="${!word_offset}" + + if [[ "$sid" -eq "-1" ]]; then + # Server id not set yet + exit_error 1 "Ill-defined command $*. Please file an issue by opening the following link: https://github.com/marcuswhybrow/minecraft-server-manager/issues" + fi + + if [[ "$sid" -eq "-2" ]]; then + if [[ "$specified_name" == "all" ]]; then + wid="world:all" + else + exit_error INVALID_ARGUMENT "When specifying \"all\" servers, \"all\" worlds must be specified also." + fi + fi + + if [[ "$sid" -ge "0" ]]; then + if is_valid_name "$specified_name"; then + if [ -d "${server_world_active_path[$sid]}/$specified_name" ] || [ -d "${server_world_inactive_path[$sid]}/$specified_name" ]; then + wid="$(server_world_get_id "$sid" "$specified_name")" + fi + fi + + if [ -z "$wid" ]; then + error_exit NAME_NOT_FOUND "There is no world with the name \"$specified_name\"." + fi + + push_arg "$wid" + fi + ;; + "") + # Check the argument is a valid name and then add push it onto the argument stack + local specified_name="${!word_offset}" + + if is_valid_name "$specified_name"; then + push_arg "$specified_name" + fi + ;; + "") + # Do no checks, just push the argument onto the stack + push_arg "${!word_offset}" + ;; + esac + + word_offset=$(( $word_offset + 1 )) + done + + ### Special Cases + + # Perform command for all worlds on all servers + if [[ "$sid" == "server:all" ]] && [[ "$wid" == "world:all" ]]; then + for ((j=0; j<$num_worlds; j++)); do + # Replace server and world id placeholders with actual id's + local replaced_args + for k in ${!args[@]}; do + replaced_args[$k]="${args[$k]//server:all/${world_server_id[$j]}}" + replaced_args[$k]="${args[$k]//world:all/$j}" + done + + # Call the function with the specific replaced args + ${COMMAND_HANDLER[$i]} "${replaced_args[@]}" + done + + # Prevent the default singular call later on. + return + fi + + # Perform command for all servers + if [[ "$sid" == "server:all" ]]; then + for ((j=0; j<$num_servers; j++)); do + local replaced_args + for k in ${!args[@]}; do + replaced_args[$k]="${args[$k]//server\:all/$j}" + done + + ${COMMAND_HANDLER[$i]} "${replaced_args[@]}" + done + + return + fi + + # Perform command for all worlds on a single server + if [[ "$sid" != "server:all" ]] && [[ "$wid" == "world:all" ]]; then + for ((j=${server_world_offset[$sid]}; j<${server_num_worlds[$sid]}; j++)); do + local replaced_args + for k in ${!args[@]}; do + replaced_args[$k]="${args[$k]//world:all/$j}" + done + + ${COMMAND_HANDLER[$i]} "${replaced_args[@]}" + done + fi + + # Otherwise execute the command for the specific id's + ${COMMAND_HANDLER[$i]} "${args[@]}" + return + fi + done + + echo "No such command. See $0 help" +} + # The main function which starts the script main() { # Initialise variables that represent system state @@ -1534,739 +2285,67 @@ main() { # Trap interrupts to the script by calling the interrupt function trap interrupt EXIT - case "$1" in - start) - # Required start option, for debian init.d scripts - for ((server=0; server<${num_servers}; server++)); do - # Only starts active servers - if "${server_active[$server]}"; then - if server_is_running "$server"; then - echo "[ACTIVE] Server \"${server_name[$server]}\" already started." - else - echo "[ACTIVE] Server \"${server_name[$server]}\" starting:" - server_start "$server" - fi - else - if server_is_running "$server"; then - echo "[INACTIVE] Server \"${server_name[$server]}\" already started. It should not be running! Use \"$0 ${server_name[$server]} stop\" to stop this server." - else - echo "[INACTIVE] Server \"${server_name[$server]}\" leaving stopped, as this server is inactive." - fi - fi - done - ;; - stop) - if [ "$2" != "now" ]; then - # If the the now flag is not specified - manager_stop_all_servers "stop" - else - # If the now flag is specified - manager_stop_all_servers_now - fi - ;; - restart) - # Required restart option, for debian init.d scripts - - # Stop any running servers, now if specified - echo "Stopping servers:" - main "stop" "$2" - - echo "Starting servers:" - main "start" - ;; - version) - echo "Minecraft Server Manager $VERSION" - ;; - server) - case "$2" in - list) - # Lists the existing servers - server_list - ;; - create) - if [ -z "$3" ]; then - # If a server name is not provided - error_exit INVALID_COMMAND "Usage: $0 server create " - else - # Create a new server - server_create "$3" - fi - ;; - delete) - if [ -z "$3" ]; then - # If a server name is not provided - error_exit INVALID_COMMAND "Usage: $0 server delete " - else - # Delete an existing server, with confirmation - server_delete "$3" - fi - ;; - rename) - if [ -z "$3" ] || [ -z "$4" ]; then - # If a server name is not provided - error_exit INVALID_COMMAND "Usage: $0 server rename " - else - # Rename an existing server - server_rename "$3" "$4" - fi - ;; - *) - # "server" is not a valid command - error_exit INVALID_COMMAND "Usage: $0 server list|create|delete|rename" - ;; - esac - ;; - jargroup) - case "$2" in - list) - # Lists the jars grouped by jargroup - jargroup_list - ;; - create) - if [ -z "$3" ] || [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 jargroup create " - else - jargroup_create "$3" "$4" - fi - ;; - delete) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 jargroup delete " - else - jargroup_delete "$3" - fi - - ;; - rename) - if [ -z "$3" ] || [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 jargroup rename " - else - jargroup_rename "$3" "$4" - fi - ;; - changetarget) - if [ -z "$3" ] || [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 jargroup changetarget " - else - jargroup_settarget "$3" "$4" - fi - ;; - getlatest) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 jargroup getlatest " - else - jargroup_getlatest "$3" - fi - ;; - *) - # "jargroup" is not a valid command - error_exit INVALID_COMMAND "Usage: $0 jargroup list|create|delete|rename|changetarget|getlatest" - ;; - esac - ;; - help) - # Outputs a list of all commands - echo -e "Usage: $0 command:" - echo -e - echo -e "--Setup Commands------------------------------------------------" - echo -e " server list List servers" - echo -e " server create Creates a new Minecraft server" - echo -e " server delete Deletes an existing Minecraft server" - echo -e " server rename Renames an existing Minecraft server" - echo -e - echo -e "--Server Mangement Commands-------------------------------------" - echo -e " start Starts a server" - echo -e " stop [now] Stops a server after warning players, or right now" - echo -e " restart [now] Restarts a server after warning players, or right now" - echo -e " status Show the running/stopped status of a server" - echo -e " connected List a servers connected players" - echo -e " worlds list Lists the worlds a server has" - echo -e " worlds load Creates links to worlds in storage for a server" - echo -e " worlds ram Toggles a world's \"in RAM\" status" - echo -e " worlds todisk Synchronises any \"in RAM\" worlds to disk a server has" - echo -e " worlds backup Makes a backup of all worlds a server has" - echo -e " worlds on|off Activate or deactivate a world, inactive worlds are not backed up" - echo -e " logroll Move a server log to a gziped archive, to reduce lag" - echo -e " backup Makes a backup of an entire server directory" - echo -e " jar [] Sets a server's jar file" - echo -e - echo -e "--Server Pass Through Commands----------------------------------" - echo -e " wl on|off Enables/disables server whitelist checking" - echo -e " wl add|remove Add/remove a player to/from a server's whitelist" - echo -e " wl list List the players whitelisted for a server" - echo -e " bl player add|remove Ban/pardon a player from/for a server" - echo -e " bl ip add|remove Ban/pardon an IP address from/for a server" - echo -e " bl list Lists the banned players and IP address for a server" - echo -e " op add|remove Add/remove operator status for a player on a server" - echo -e " op list Lists the operator players for a server" - echo -e " gm survival|creative Change the game mode for a player on a server" - echo -e " kick Forcibly disconnect a player from a server" - echo -e " say Broadcast a (pink) message to all players on a server" - echo -e " time set|add Set/increment time on a server (0-24000)" - echo -e " toggledownfall Toggles rain and snow on a server" - echo -e " save on|off Enable/disable writing world changes to file" - echo -e " save all Force the writing of all non-saved world changes to file" - echo -e " cmd Send a command string to the server and return" - echo -e " cmdlog Same as 'cmd' but shows log output afterwards (Ctrl+C to exit)" - echo -e - echo -e "--Jar Commands--------------------------------------------------" - echo -e " jargroup list List the stored jar files." - echo -e " jargroup create Create a new jar group, with a URL for new downloads" - echo -e " jargroup delete Delete a jar group" - echo -e " jargroup rename Rename a jar group" - echo -e " jargroup changeurl Change the download URL for a jar group" - echo -e " jargroup getlatest Download the latest jar file for a jar group" - echo -e - echo -e "--Global Commands-----------------------------------------------" - echo -e " start Starts all active servers" - echo -e " stop [now] Stops all running servers" - echo -e " restart [now] Restarts all active servers" - echo -e " version Prints the Minecraft Server Manager version installed8" - ;; - "") - error_exit INVALID_COMMAND "No such command see: $0 help" - ;; - *) - if [[ "$1" == "all" ]] || [[ -d "$SERVER_STORAGE_PATH/$1" ]]; then - command_server() { - if [ -d "$SERVER_STORAGE_PATH/$1" ]; then - local id="$(server_get_id "$1")" - else - error_exit NAME_NOT_FOUND "There is no server with the name \"$1\"." - fi - - case "$2" in - start) - server_set_active "$id" "active" - server_start "$id" - ;; - stop) - server_set_active "$id" "inactive" - if [[ "$3" != "now" ]]; then - server_stop "$id" - else - server_stop_now "$id" - fi - ;; - restart) - server_set_active "$1" "active" - if [[ "$3" != "now" ]]; then - server_restart "$id" - else - server_restart_now "$id" - fi - ;; - status) - if server_is_running "$id"; then - echo "Server \"${server_name[$id]}\" is running." - else - echo "Server \"${server_name[$id]}\" is stopped." - fi - ;; - connected) - server_connected "$id" - ;; - worlds) - case "$3" in - list) - server_worlds_list "$id" - ;; - load) - server_ensure_links "$id" - ;; - ram) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 worlds ram " - else - world_id="$(server_world_get_id "$id" "$4")" - - if [ ! -z "$world_id" ]; then - world_toggle_ramdisk_state "$world_id" - else - error_exit NAME_NOT_FOUND "Server \"${server_name[$id]}\" has no world with that name." - fi - fi - ;; - todisk) - server_save_off "$id" - server_save_all "$id" - server_worlds_to_disk "$id" - server_save_on "$id" - ;; - backup) - if server_is_running "$id"; then - server_eval "$id" "say ${server_world_backup_started[$id]}" - server_save_off "$id" - server_save_all "$id" - fi - - server_worlds_to_disk "$id" - server_worlds_backup "$id" - - if server_is_running "$id"; then - server_save_on "$id" - server_eval "$id" "say ${server_world_backup_finished[$id]}" - fi - - echo "Backup took $SECONDS seconds". - ;; - on) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 worlds on " - else - world_activate "$(server_world_get_id "$id" "$4")" - fi - ;; - off) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 worlds off " - else - world_deactivate "$(server_world_get_id "$id" "$4")" - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 worlds list|load|ram|todisk|backup|on|off" - ;; - esac - ;; - logroll) - server_log_roll "$id" - ;; - backup) - if server_is_running "$id"; then - server_eval "$id" "say ${server_complete_backup_started[$id]}" - server_save_off "$id" - server_save_all "$id" - fi - - server_worlds_to_disk "$id" - server_backup "$id" - - if server_is_running "$id"; then - server_save_on "$id" - server_eval "$id" "say ${server_complete_backup_finished[$id]}" - fi - - echo "Backup took $SECONDS seconds". - ;; - jar) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 jar [jar-file-name]" - else - server_set_jar "$id" "$3" "$4" - fi - ;; - whitelist|wl) - case "$3" in - on) - if server_is_running "$id"; then - server_eval "$id" "whitelist on" - echo "Whitelist enabled" - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - ;; - off) - if server_is_running "$id"; then - server_eval "$id" "whitelist off" - echo "Whitelist disabled" - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - ;; - add) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 whitelist add " - else - if server_is_running "$id"; then - server_eval "$id" "whitelist add $4" - echo "Added \"$4\" to the whitelist." - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - remove) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 whitelist remove " - else - if server_is_running "$id"; then - server_eval "$id" "whitelist remove $4" - echo "Removed \"$4\" from the whitelist." - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - list) - local players="$(cat "${server_whitelist[$id]}")" - - if [ -z "$players" ]; then - echo "No players are whitelisted." - else - echo "$players" - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 whitelist on|off|add|remove|list" - ;; - esac - ;; - blacklist|bl) - case "$3" in - player) - case "$4" in - add) - if [ -z "$5" ]; then - error_exit INVALID_COMMAND "Usage: $0 blacklist player add " - else - for player in ${*:5}; do - server_eval "$id" "ban $player" - done - if [[ $# -gt 5 ]]; then - echo -n "Blacklisted the following players: " - echo -n "$5" - for player in ${*:6}; do - echo -n ", $player" - done - echo "." - else - echo "Blacklisted \"$5\"." - fi - fi - ;; - remove) - if [ -z "$5" ]; then - error_exit INVALID_COMMAND "Usage: $0 blacklist player remove " - else - for player in ${*:5}; do - server_eval "$id" "pardon $player" - done - if [[ $# -gt 5 ]]; then - echo -n "Removed the following players from the blacklist: " - echo -n "$5" - for player in ${*:6}; do - echo -n ", $player" - done - echo "." - else - echo "Removed \"$5\" from the blacklist." - fi - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 blacklist player add|remove" - ;; - esac - ;; - ip) - case "$4" in - add) - if [ -z "$5" ]; then - error_exit INVALID_COMMAND "Usage: $0 blacklist ip add " - else - for address in ${*:5}; do - server_eval "$id" "ban-ip $address" - done - if [[ $# > 5 ]]; then - echo -n "Blacklisted the following ip addresses: " - echo -n "$5" - for player in ${*:6}; do - echo -n ", $address" - done - echo "." - else - echo "Blacklisted \"$5\"." - fi - fi - ;; - remove) - if [ -z "$5" ]; then - error_exit INVALID_COMMAND "Usage: $0 blacklist ip remove " - else - for address in ${*:5}; do - server_eval "$id" "pardon-ip $address" - done - if [[ $# > 5 ]]; then - echo -n "Removed the following ip addresses from the blacklist: " - echo -n "$5" - for player in ${*:6}; do - echo -n ", $address" - done - echo "." - else - echo "Removed \"$5\" from the ip blacklist." - fi - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 blacklist ip add|remove" - ;; - esac - ;; - list) - local players="$(cat "${server_banned_players[$id]}")" - - local ips="$(cat "${server_banned_ips[$id]}")" - - if [[ -z "$players" && -z "$ips" ]]; then - echo "The blacklist is empty." - else - if [[ ! -z "$players" ]]; then - echo "Players:" - for name in $players; do - echo " $name" - done - fi - - if [[ ! -z "$ips" ]]; then - echo "IP Addresses:" - for address in $ips; do - echo " $address" - done - fi - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 blacklist ip player|ip|list" - ;; - esac - ;; - operator|op) - case "$3" in - add) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 operator add " - else - if server_is_running "$id"; then - server_eval "$id" "op $4" - echo "The player \"$4\" is now an operator for the server." - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - remove) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 operator remove " - else - if server_is_running "$id"; then - server_eval "$id" "deop $4" - echo "The player \"$4\" is no longer an operator for the server." - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - list) - local players="$(cat "${server_ops[$id]}")" - - if [ -z "$players" ]; then - echo "No players are operators." - else - echo "$players" - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 operator add|remove|list" - ;; - esac - ;; - gamemode|gm) - case "$3" in - survival|creative|0|1) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 gamemode survival|creative " - else - if server_is_running "$id"; then - case "$3" in - creative|1) local mode=1;; - survival|0) local mode=0;; - *) error_exit INVALID_ARGUMENT "Invalid gamemode type \"$3\" options are \"survival\", \"creative\", \"0\" or \"1\".";; - esac - - local line="$(server_eval_and_get_line "$id" "gamemode $4 $mode" "${server_confirm_gamemode[$id]}" "${server_confirm_gamemode_fail_no_user[$id]}" "${server_confirm_gamemode_fail_no_change[$id]}")" - - local regex="${LOG_REGEX} ${server_confirm_gamemode[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "Changed game mode of \"$4\" to \"$3\"." - fi - local regex="${LOG_REGEX} ${server_confirm_gamemode_fail_no_user[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "The player \"$4\" was not found to be logged on." - fi - local regex="${LOG_REGEX} ${server_confirm_gamemode_fail_no_change[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "The player \"$4\" was already in mode \"$3\"." - fi - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 gamemode survival|creative" - ;; - esac - ;; - kick) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 kick " - else - if server_is_running "$id"; then - local line="$(server_eval_and_get_line "$id" "kick $3" "${server_confirm_kick[$id]}" "${server_confirm_kick_fail[$id]}")" - - local regex="${LOG_REGEX} ${server_confirm_kick[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "Kicked \"$3\" from game." - fi - local regex="${LOG_REGEX} ${server_confirm_kick_fail[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "The player \"$3\" is not connected." - fi - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - say) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 say " - else - if server_is_running "$id"; then - server_eval "$id" "say ${*:3}" - echo "Message sent to players." - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - time) - case "$3" in - set) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 time set " - else - if server_is_running "$id"; then - local line="$(server_eval_and_get_line "$id" "time set $4" "${server_confirm_time_set[$id]}" "${server_confirm_time_set_fail[$id]}")" - - local regex="${LOG_REGEX} ${server_confirm_time_set[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "Set time to \"$4\"." - fi - local regex="${LOG_REGEX} ${server_confirm_time_set_fail[$id]}" - if [[ "$line" =~ $regex ]]; then - error_exit INVALID_ARGUMENT "Unable to convert \"$4\" to a time." - fi - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - add) - if [ -z "$4" ]; then - error_exit INVALID_COMMAND "Usage: $0 time add " - else - if server_is_running "$id"; then - local line="$(server_eval_and_get_line "$id" "time add $4" "${server_confirm_time_add[$id]}" "${server_confirm_time_add_fail[$id]}")" - - local regex="${LOG_REGEX} ${server_confirm_time_add[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "Added \"$4\" to time." - fi - local regex="${LOG_REGEX} ${server_confirm_time_add_fail[$id]}" - if [[ "$line" =~ $regex ]]; then - error_exit INVALID_ARGUMENT "Unable to convert \"$4\" to a time." - fi - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - *) - error_exit INVALID_COMMAND "Usage: $0 time set|add" - ;; - esac - ;; - toggledownfall|tdf) - if server_is_running "$id"; then - local line="$(server_eval_and_get_line "$id" "toggledownfall $3" "${server_confirm_toggledownfall[$id]}" "${server_confirm_toggledownfall_fail[$id]}")" - - local regex="${LOG_REGEX} ${server_confirm_toggledownfall[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "${line:36:(-3)}" - fi - local regex="${LOG_REGEX} ${server_confirm_toggledownfall_fail[$id]}" - if [[ "$line" =~ $regex ]]; then - echo "${line:34:(-3)}" - fi - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - ;; - save) - case "$3" in - on) server_save_on "$id";; - off) server_save_off "$id";; - all) server_save_all "$id";; - *) error_exit INVALID_COMMAND "Usage: $0 save on|off|all";; - esac - ;; - cmd) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 cmd " - else - if server_is_running "$id"; then - server_eval "$id" "${*:3}" - echo "Command sent." - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - cmdlog) - if [ -z "$3" ]; then - error_exit INVALID_COMMAND "Usage: $0 cmdlog " - else - if server_is_running "$id"; then - server_eval "$id" "${*:3}" - echo "Now watching logs (press Ctrl+C to exit):" - as_user "${server_user_name[$id]}" "tail --pid=$$ --follow --lines=0 --sleep-interval=0.1 ${server_log[$id]}" - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - fi - ;; - console) - if server_is_running "$id"; then - as_user "${server_user_name[$1]}" "screen -r ${server_screen_name[$1]}" - else - error_exit SERVER_STOPPED "Server \"${server_name[$id]}\" is not running." - fi - ;; - *) - error_exit INVALID_COMMAND "Invalid command. See \"$0 help\" for more information." - ;; - esac - } - - if [[ "$1" == "all" ]]; then - # Execute the command for all server names - while IFS= read -r -d $'\0' path; do - local name="$(basename "$path")" - args="${@:2}" - echo "Calling $0 \"$name\" \"$args\"" - command_server "$name" $args - done < <(find "$SERVER_STORAGE_PATH" -mindepth 1 -maxdepth 1 -type d -print0) - else - # Execute the command for a single server - command_server "$@" - fi - else - error_exit NAME_NOT_FOUND "No server with that name." - fi - ;; - esac + register_command "start" "command_start" + register_command "stop" "command_stop" + register_command "stop now" "command_stop_now" + register_command "restart" "command_restart" + register_command "restart now" "command_restart_now" + register_command "version" "command_version" + register_command "server list" "command_server_list" + register_command "server create " "command_server_create" + register_command "server delete " "command_server_delete" + register_command "server rename " "command_server_rename" + register_command "jargroup list" "command_jargroup_list" + register_command "jargroup create " "command_jargroup_create" + register_command "jargroup delete " "command_jargorup_delete" + register_command "jargroup rename " "command_jargroup_rename" + register_command "jargroup changetarget " "command_jargroup_changetarget" + register_command "jargroup getlatest " "command_jargroup_getlatest" + register_command "help" "command_help" + register_command " start" "command_server_start" + register_command " stop" "command_server_stop" + register_command " stop now" "command_server_stop_now" + register_command " restart" "command_server_restart" + register_command " restart now" "command_server_restart_now" + register_command " status" "command_server_status" + register_command " connected" "command_server_connected" + register_command " worlds list" "command_server_worlds_list" + register_command " worlds load" "command_server_worlds_load" + register_command " worlds ram " "command_server_worlds_ram" + register_command " worlds todisk" "command_server_worlds_todisk" + register_command " worlds backup" "command_server_worlds_backup" + register_command " worlds on " "command_server_worlds_on" + register_command " worlds off " "command_server_worlds_off" + register_command " logroll" "command_server_logroll" + register_command " backup" "command_server_backup" + register_command " jar [name]" "command_server_jar" + register_command " whitelist|wl on" "command_server_whitelist_on" + register_command " whitelist|wl off" "command_server_whitelist_off" + register_command " whitelist|wl add " "command_server_whitelist_add" + register_command " whitelist|wl remove " "command_server_whitelist_remove" + register_command " whitelist|wl list" "command_server_whitelist_list" + register_command " blacklist|bl player add " "command_server_blacklist_player_add" + register_command " blacklist|bl player remove " "command_server_blacklist_player_remove" + register_command " blacklist|bl ip add " "command_server_blacklist_ip_add" + register_command " blacklist|bl ip remove " "command_server_blacklist_ip_remove" + register_command " blacklist|bl list" "command_server_blacklist_list" + register_command " operator|op add " "command_server_operator_add" + register_command " operator|op remove " "command_server_operator_remove" + register_command " operator|op list" "command_server_operator_list" + register_command " gamemode|gm survival|creative|0|1 " "command_server_gamemode" + register_command " kick " "command_server_kick" + register_command " say " "command_server_say" + register_command " time set " "command_server_time_set" + register_command " time add " "command_server_time_add" + register_command " toggledownfall|tdf" "command_server_toggledownfall" + register_command " save on" "command_server_save_on" + register_command " save off" "command_server_save_off" + register_command " save all" "command_server_save_all" + register_command " cmd" "command_server_cmd" + register_command " cmdlog" "command_server_cmdlog" + register_command " console" "command_server_console" + + call_command "$@" }