mirror of
https://github.com/MinecraftServerControl/mscs.git
synced 2024-11-15 14:58:18 -07:00
2449 lines
80 KiB
Bash
Executable File
2449 lines
80 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Copyright (c) 2011-2016, Jason M. Wood <sandain@hotmail.com>
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Minecraft Server Control Script
|
|
#
|
|
# A powerful command-line control script for Linux-powered Minecraft servers.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Get executable name
|
|
# ---------------------------------------------------------------------------
|
|
PROG=$(basename $0)
|
|
|
|
# Script Usage
|
|
# ---------------------------------------------------------------------------
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $PROG [<options>] <action>
|
|
|
|
Actions:
|
|
|
|
start <world>
|
|
Start the Minecraft world server. Start all world servers by default.
|
|
|
|
stop <world>
|
|
Stop the Minecraft world server. Stop all world servers by default.
|
|
|
|
force-stop <world>
|
|
Forcibly stop the Minecraft world server. Forcibly stop all world
|
|
servers by default.
|
|
|
|
restart <world>
|
|
Restart the Minecraft world server. Restart all world servers by default.
|
|
|
|
force-restart <world>
|
|
Forcibly restart the Minecraft world server. Forcibly restart all world
|
|
servers by default.
|
|
|
|
create <world> <port> [<ip>]
|
|
Create a Minecraft world server. The world name and port must be
|
|
provided, the IP address is usually blank. Without arguments, create a
|
|
a default world at the default port.
|
|
|
|
delete <world>
|
|
Delete a Minecraft world server.
|
|
|
|
disable <world>
|
|
Temporarily disable a world server.
|
|
|
|
enable <world>
|
|
Enable a disabled world server.
|
|
|
|
ls <option>
|
|
Display a list of worlds.
|
|
Options:
|
|
enabled Display a list of enabled worlds, default.
|
|
disabled Display a list of disabled worlds.
|
|
running Display a list of running worlds.
|
|
stopped Display a list of stopped worlds.
|
|
If no option, all available worlds are listed.
|
|
|
|
list <option>
|
|
Same as 'ls' but more detailed.
|
|
|
|
status <world>
|
|
Display the status of the Minecraft world server. Display the status of
|
|
all world servers by default.
|
|
|
|
sync <world>
|
|
Synchronize the data stored in the mirror images of the Minecraft world
|
|
server. Synchronizes all of the world servers by default. This option
|
|
is only available when the mirror image option is enabled.
|
|
|
|
broadcast <command>
|
|
Broadcast a command to all running Minecraft world servers.
|
|
|
|
send <world> <command>
|
|
Send a command to a Minecraft world server.
|
|
|
|
console <world>
|
|
Connect to the Minecraft world server's console. Hit <Ctrl-D> to detach.
|
|
|
|
watch <world>
|
|
Watch the log file for the Minecraft world server.
|
|
|
|
logrotate <world>
|
|
Rotate the log file for the Minecraft world. Rotate the log file for
|
|
all worlds by default.
|
|
|
|
backup <world>
|
|
Backup the Minecraft world. Backup all worlds by default.
|
|
|
|
list-backups <world>
|
|
List the datetime of the backups for the world.
|
|
|
|
restore-backup <world> <datetime>
|
|
Restore a backup for a world that was taken at the datetime.
|
|
|
|
map <world>
|
|
Run the Minecraft Overviewer mapping software on the Minecraft world.
|
|
Map all worlds by default.
|
|
|
|
update <world>
|
|
Update the server software for the Minecraft world server. Update
|
|
server software for all worlds by default.
|
|
|
|
query <world>
|
|
Run a detailed Query on the Minecraft world server.
|
|
|
|
Options:
|
|
|
|
-c <config_file>
|
|
Read configuration from <config_files> instead of default locations.
|
|
|
|
-l <location>
|
|
Uses <location> as the base path for data. Overrides configuration file
|
|
options.
|
|
EOF
|
|
}
|
|
|
|
# Parse command-line options
|
|
# ---------------------------------------------------------------------------
|
|
while [ "$1" != "${1#-}" ]; do
|
|
case "$1" in
|
|
-p)
|
|
if [ -n "$2" ]; then
|
|
PROG="$2"
|
|
shift
|
|
else
|
|
echo "$PROG: '-p' needs a program name argument."
|
|
exit 1
|
|
fi
|
|
;;
|
|
-c)
|
|
if [ -n "$2" ]; then
|
|
MSCS_DEFAULTS_CL="$2"
|
|
shift
|
|
else
|
|
echo "$PROG: '-c' needs a config file argument."
|
|
exit 1
|
|
fi
|
|
;;
|
|
-l)
|
|
if [ -n "$2" ]; then
|
|
LOCATION_CL="$2"
|
|
shift
|
|
else
|
|
echo "$PROG: '-l' needs a location path argument."
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "$PROG: unknown option '$1'."
|
|
echo "Execute '$PROG' without arguments for usage instructions."
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Override Global Variables
|
|
# ---------------------------------------------------------------------------
|
|
# Override global variables below by adding them to the specified file. If
|
|
# the file does not exist, the default values below will be used.
|
|
# Configuration files are checked in the following order. First file found is
|
|
# sourced and the rest are discarded:
|
|
# command line option "-c".
|
|
# $HOME/mscs.conf
|
|
# $HOME/.config/mscs/mscs.conf
|
|
if [ -r "$MSCS_DEFAULTS_CL" ]; then
|
|
MSCS_DEFAULTS="$MSCS_DEFAULTS_CL"
|
|
elif [ -r "$HOME/mscs.conf" ]; then
|
|
MSCS_DEFAULTS="$HOME/mscs.conf"
|
|
elif [ -r "$HOME/.config/mscs/mscs.conf" ]; then
|
|
MSCS_DEFAULTS="$HOME/.config/mscs/mscs.conf"
|
|
fi
|
|
|
|
# Server Location
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# The default location of server software and data.
|
|
LOCATION="$HOME/mscs"
|
|
|
|
# Override the default values if the default file exists.
|
|
[ -r "$MSCS_DEFAULTS" ] && . "$MSCS_DEFAULTS"
|
|
|
|
# Override with command-line location option.
|
|
[ -n "$LOCATION_CL" ] && LOCATION="$LOCATION_CL"
|
|
|
|
# Required Software
|
|
# ---------------------------------------------------------------------------
|
|
# Detect its presence and location for later.
|
|
|
|
JAVA=$(which java)
|
|
PERL=$(which perl)
|
|
PYTHON=$(which python)
|
|
WGET=$(which wget)
|
|
RDIFF_BACKUP=$(which rdiff-backup)
|
|
SOCAT=$(which socat)
|
|
|
|
|
|
# Global Server Configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Minecraft Versions information
|
|
# ---------------------------------------------------------------------------
|
|
MINECRAFT_VERSIONS_URL=https://s3.amazonaws.com/Minecraft.Download/versions/versions.json
|
|
|
|
|
|
# Minecraft Server Settings
|
|
# ---------------------------------------------------------------------------
|
|
# Default settings if not provided in the world's mscs.properties file.
|
|
|
|
DEFAULT_WORLD='world'
|
|
DEFAULT_PORT='25565'
|
|
DEFAULT_IP=''
|
|
DEFAULT_VERSION_TYPE='release'
|
|
DEFAULT_CLIENT_VERSION='$CURRENT_VERSION'
|
|
DEFAULT_CLIENT_JAR='$CLIENT_VERSION.jar'
|
|
DEFAULT_CLIENT_URL='https://s3.amazonaws.com/Minecraft.Download/versions/$CLIENT_VERSION/$CLIENT_VERSION.jar'
|
|
DEFAULT_CLIENT_LOCATION=$HOME'/.minecraft/versions/$CLIENT_VERSION'
|
|
DEFAULT_SERVER_VERSION='$CURRENT_VERSION'
|
|
DEFAULT_SERVER_JAR='minecraft_server.$SERVER_VERSION.jar'
|
|
DEFAULT_SERVER_URL='https://s3.amazonaws.com/Minecraft.Download/versions/$SERVER_VERSION/minecraft_server.$SERVER_VERSION.jar'
|
|
DEFAULT_SERVER_ARGS='nogui'
|
|
DEFAULT_INITIAL_MEMORY='128M'
|
|
DEFAULT_MAXIMUM_MEMORY='2048M'
|
|
DEFAULT_SERVER_LOCATION=$LOCATION'/server'
|
|
DEFAULT_SERVER_COMMAND='$JAVA -Xms$INITIAL_MEMORY -Xmx$MAXIMUM_MEMORY -jar $SERVER_LOCATION/$SERVER_JAR $SERVER_ARGS'
|
|
|
|
# The server settings for each world can be customized by adding certain
|
|
# key/value pairs to the world's mscs.properties file.
|
|
#
|
|
# The following keys are available:
|
|
# mscs-enabled - Enable or disable the world server.
|
|
# mscs-version-type - Assign the version type (release or snapshot).
|
|
# mscs-client-version - Assign the version of the client software.
|
|
# mscs-client-jar - Assign the .jar file for the client software.
|
|
# mscs-client-url - Assign the download URL for the client software.
|
|
# mscs-client-location - Assign the location of the client .jar file.
|
|
# mscs-server-version - Assign the version of the server software.
|
|
# mscs-server-jar - Assign the .jar file for the server software.
|
|
# mscs-server-url - Assign the download URL for the server software.
|
|
# mscs-server-args - Assign the arguments to the server.
|
|
# mscs-initial-memory - Assign the initial amount of memory for the server.
|
|
# mscs-maximum-memory - Assign the maximum amount of memory for the server.
|
|
# mscs-server-location - Assign the location of the server .jar file.
|
|
# mscs-server-command - Assign the command to run for the server.
|
|
#
|
|
# The following variables may be used in some of the values of the above
|
|
# keys:
|
|
# $JAVA - The Java virtual machine.
|
|
# $CURRENT_VERSION - The current Mojang Minecraft release version.
|
|
# $CLIENT_VERSION - The version of the client software.
|
|
# $SERVER_VERSION - The version of the server software.
|
|
# $SERVER_JAR - The .jar file to run for the server.
|
|
# $SERVER_ARGS - The arguments to the server.
|
|
# $INITIAL_MEMORY - The initial amount of memory for the server.
|
|
# $MAXIMUM_MEMORY - The maximum amount of memory for the server.
|
|
# $SERVER_LOCATION - The location of the server .jar file.
|
|
#
|
|
# The following example key/value pairs are equivalent to the default values:
|
|
# mscs-enabled=true
|
|
# mscs-version-type=release
|
|
# mscs-client-version=$CURRENT_VERSION
|
|
# mscs-client-jar=$CLIENT_VERSION.jar
|
|
# mscs-client-url=https://s3.amazonaws.com/Minecraft.Download/versions/$CLIENT_VERSION/$CLIENT_VERSION.jar
|
|
# mscs-client-location=/opt/mscs/.minecraft/versions/$CLIENT_VERSION
|
|
# mscs-server-version=$CURRENT_VERSION
|
|
# mscs-server-jar=minecraft_server.$SERVER_VERSION.jar
|
|
# mscs-server-url=https://s3.amazonaws.com/Minecraft.Download/versions/$SERVER_VERSION/minecraft_server.$SERVER_VERSION.jar
|
|
# mscs-server-args=nogui
|
|
# mscs-initial-memory=128M
|
|
# mscs-maximum-memory=2048M
|
|
# mscs-server-location=/opt/mscs/server
|
|
# mscs-server-command=$JAVA -Xms$INITIAL_MEMORY -Xmx$MAXIMUM_MEMORY -jar $SERVER_LOCATION/$SERVER_JAR $SERVER_ARGS
|
|
|
|
|
|
# World (Server Instance) Configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# The location to store files for each world server.
|
|
WORLDS_LOCATION="$LOCATION/worlds"
|
|
|
|
# The location old disabled worlds were stored in previous versions
|
|
OLD_DISABLED_WORLDS_LOCATION="$LOCATION/worlds-disabled"
|
|
|
|
# The location to store the versions.json file.
|
|
VERSIONS_JSON="$DEFAULT_SERVER_LOCATION/versions.json"
|
|
|
|
# The duration (in minutes) to keep the versions.json file before updating.
|
|
VERSIONS_DURATION=1440
|
|
|
|
|
|
# Backup Configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Location to store backups.
|
|
BACKUP_LOCATION="$LOCATION/backups"
|
|
|
|
# Location of the backup log file.
|
|
BACKUP_LOG="$BACKUP_LOCATION/backup.log"
|
|
|
|
# Length in days that backups survive.
|
|
BACKUP_DURATION=15
|
|
|
|
|
|
# Server Log Configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Length in days that logs survive.
|
|
LOG_DURATION=15
|
|
|
|
|
|
# Listing options
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Server properties for detailed listing (list).
|
|
DETAILED_LISTING_PROPERTIES="motd server-ip server-port max-players level-type online-mode"
|
|
|
|
|
|
# Mirror Image Options
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Create a mirror image of the world data on system startup, and
|
|
# update that mirror image on system shutdown.
|
|
#
|
|
# IMPORTANT: If using this option, the admin should schedule
|
|
# periodic synchronizations of the mirror image using cron
|
|
# to avoid data loss. To do this, add a cron task to call
|
|
# the "sync" option on a VERY regular basis (e.g.,
|
|
# every 5-10 minutes).
|
|
#
|
|
# 0 - Do not use a mirror image, default.
|
|
# 1 - Use a mirror image.
|
|
ENABLE_MIRROR=0
|
|
|
|
# The location to store the mirror image.
|
|
#
|
|
# NOTE: This is usually a ramdisk, e.g. /dev/shm on Debian/Ubuntu.
|
|
MIRROR_PATH="/dev/shm/mscs"
|
|
|
|
|
|
# Minecraft Overviewer Mapping Software Options
|
|
# ---------------------------------------------------------------------------
|
|
|
|
OVERVIEWER_BIN=$(which overviewer.py)
|
|
OVERVIEWER_URL="http://overviewer.org"
|
|
MAPS_URL="http://minecraft.server.com/maps"
|
|
MAPS_LOCATION="$LOCATION/maps"
|
|
|
|
# Do additional overrides if the default file exists.
|
|
# Override the default values if the default file exists.
|
|
[ -r "$MSCS_DEFAULTS" ] && . "$MSCS_DEFAULTS"
|
|
|
|
# Override with command-line location option.
|
|
[ -n "$LOCATION_CL" ] && LOCATION="$LOCATION_CL"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Internal Methods
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# NOTE: Nothing below this point should need to be edited directly.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the PID of the Java process for the world server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return The Java PID.
|
|
# ---------------------------------------------------------------------------
|
|
getJavaPID() {
|
|
local PID MCUSER
|
|
MCUSER=$(whoami)
|
|
PID=$(
|
|
ps -a -U $MCUSER -o pid,comm,args -ww |
|
|
$PERL -ne 'if ($_ =~ /^\s*(\d+)\s+java.+mscs-world='$1'$/) { print $1; }'
|
|
)
|
|
printf "%d\n" $PID
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check to see if the world server is running.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return A 0 if the server is thought to be running, a 1 otherwise.
|
|
# ---------------------------------------------------------------------------
|
|
serverRunning() {
|
|
# Try to determine if the world is running.
|
|
if [ $(getJavaPID "$1") -gt 0 ]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Send a command to the world server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The command to send.
|
|
# ---------------------------------------------------------------------------
|
|
sendCommand() {
|
|
echo "$2" | $PERL -e '
|
|
while (<>) { $_ =~ s/[\r\n]+//g; $cmd .= $_; } print "$cmd\r";
|
|
' >> $WORLDS_LOCATION/$1/console.in
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check whether the item is in the list.
|
|
#
|
|
# @param 1 The item being searched for.
|
|
# @param 2 The list being searched.
|
|
# @return A 0 if the list contains the item, a 1 otherwise.
|
|
# ---------------------------------------------------------------------------
|
|
listContains() {
|
|
local MATCH ITEM
|
|
MATCH=1
|
|
for ITEM in $2; do
|
|
if [ "$ITEM" = "$1" ]; then
|
|
MATCH=0
|
|
fi
|
|
done
|
|
return $MATCH
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Compare two datetime strings.
|
|
#
|
|
# @param 1 The first datetime string.
|
|
# @param 2 The second datetime string.
|
|
# @return The result of the comparison: -1, 0, 1.
|
|
# ---------------------------------------------------------------------------
|
|
compareTime() {
|
|
local T1 T2
|
|
T1=$(date --date="$1" +%s)
|
|
T2=$(date --date="$2" +%s)
|
|
echo $(($T1 < $T2 ? -1 : $T1 > $T2 ? 1 : 0))
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Compare two Minecraft version numbers.
|
|
#
|
|
# @param 1 The first Minecraft version number.
|
|
# @param 2 The second Minecraft version number.
|
|
# @return The result of the comparison: -1, 0, 1.
|
|
# ---------------------------------------------------------------------------
|
|
compareMinecraftVersions() {
|
|
local T1 T2
|
|
T1=$(getMinecraftVersionReleaseTime "$1")
|
|
T2=$(getMinecraftVersionReleaseTime "$2")
|
|
compareTime "$T1" "$T2"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Create a world.
|
|
#
|
|
# @param 1 The world server to create.
|
|
# @param 2 The port of the world server.
|
|
# @param 3 The IP address of the world server.
|
|
# ---------------------------------------------------------------------------
|
|
createWorld() {
|
|
# Create a basic server.properties file. Values not supplied here
|
|
# will use default values when the world server is first started.
|
|
mkdir -p "$WORLDS_LOCATION/$1"
|
|
setServerPropertiesValue "$1" "level-name" "$1"
|
|
setServerPropertiesValue "$1" "server-port" "$2"
|
|
setServerPropertiesValue "$1" "server-ip" "$3"
|
|
setServerPropertiesValue "$1" "enable-query" "true"
|
|
setServerPropertiesValue "$1" "query.port" "$2"
|
|
setMSCSValue "$1" "mscs-enabled" "true"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Delete a world.
|
|
#
|
|
# @param 1 The world server to delete.
|
|
# ---------------------------------------------------------------------------
|
|
deleteWorld() {
|
|
# Delete the world directory.
|
|
rm -Rf "$WORLDS_LOCATION/$1"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Disable a world.
|
|
#
|
|
# @param 1 The world server to disable.
|
|
# ---------------------------------------------------------------------------
|
|
disableWorld() {
|
|
# Disable the world.
|
|
setMSCSValue "$1" "mscs-enabled" "false"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Enable a world.
|
|
#
|
|
# @param 1 The world server to enable.
|
|
# ---------------------------------------------------------------------------
|
|
enableWorld() {
|
|
# Enable the world.
|
|
setMSCSValue "$1" "mscs-enabled" "true"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Grab the list of enabled worlds.
|
|
#
|
|
# @return The list of enabled worlds.
|
|
# ---------------------------------------------------------------------------
|
|
getEnabledWorlds() {
|
|
local WORLD WORLDS
|
|
mkdir -p "$WORLDS_LOCATION"
|
|
WORLDS=""
|
|
for WORLD in $(ls $WORLDS_LOCATION); do
|
|
if [ -d $WORLDS_LOCATION/$WORLD ]; then
|
|
if [ "$(getMSCSValue $WORLD 'mscs-enabled' 'true')" = "true" ]; then
|
|
WORLDS="$WORLDS $WORLD"
|
|
fi
|
|
fi
|
|
done
|
|
echo $WORLDS
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Grab the list of disabled worlds.
|
|
#
|
|
# @return The list of disabled worlds.
|
|
# ---------------------------------------------------------------------------
|
|
getDisabledWorlds() {
|
|
local WORLD WORLDS
|
|
WORLDS=""
|
|
for WORLD in $(ls $WORLDS_LOCATION); do
|
|
if [ -d $WORLDS_LOCATION/$WORLD ]; then
|
|
if [ "$(getMSCSValue $WORLD 'mscs-enabled' 'true')" != "true" ]; then
|
|
WORLDS="$WORLDS $WORLD"
|
|
fi
|
|
fi
|
|
done
|
|
echo $WORLDS
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Grab the list of all available worlds.
|
|
#
|
|
# @return The list of all available worlds.
|
|
# ---------------------------------------------------------------------------
|
|
getAvailableWorlds() {
|
|
echo $(getEnabledWorlds) $(getDisabledWorlds)
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check to see if the world is enabled.
|
|
#
|
|
# @param 1 The world of interest.
|
|
# @return A 0 if the world is enabled, a 1 otherwise.
|
|
# ---------------------------------------------------------------------------
|
|
isWorldEnabled() {
|
|
local WORLDS
|
|
WORLDS=$(getEnabledWorlds)
|
|
if [ -n "$1" ] && listContains "$1" "$WORLDS"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check to see if the world is available (exists).
|
|
#
|
|
# @param 1 The world of interest.
|
|
# @return A 0 if the world is available, a 1 otherwise.
|
|
# ---------------------------------------------------------------------------
|
|
isWorldAvailable() {
|
|
local WORLDS
|
|
WORLDS=$(getAvailableWorlds)
|
|
if [ -n "$1" ] && listContains "$1" "$WORLDS"; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the value of a key from the provided file.
|
|
#
|
|
# @param 1 The file containing the key/value combo.
|
|
# @param 2 The key to get.
|
|
# @param 3 The default value.
|
|
# ---------------------------------------------------------------------------
|
|
getValue() {
|
|
local KEY VALUE
|
|
# Make sure the file exists.
|
|
if [ -e "$1" ]; then
|
|
# Find the key/value combo.
|
|
KEY=$($PERL -ne '
|
|
$_ =~ s/[\r]//;
|
|
if ($_ =~ /^('$2')=.*$/i) { print lc $1; }
|
|
' $1)
|
|
VALUE=$($PERL -ne '
|
|
$_ =~ s/[\r]//;
|
|
if ($_ =~ /^'$2'=(.*)$/i) { print $1; }
|
|
' $1)
|
|
fi
|
|
# Return the value if found, the default value if not.
|
|
if [ -n "$KEY" ] && [ -n "$VALUE" ]; then
|
|
echo "$VALUE"
|
|
else
|
|
echo "$3"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Modify the value of a key/value combo in the provided file.
|
|
#
|
|
# @param 1 The file containing the key/value combo.
|
|
# @param 2 The key to modify.
|
|
# @param 3 The value to assign to the key.
|
|
# ---------------------------------------------------------------------------
|
|
setValue() {
|
|
local KEY_VALUE
|
|
# Make sure that the file exists.
|
|
touch "$1"
|
|
# Replace the key/value combo if it already exists, otherwise just
|
|
# append it to the end of the file.
|
|
KEY_VALUE=$($PERL -ne '
|
|
$_ =~ s/[\r]//;
|
|
if ($_ =~ /^('$2'=.*)$/) { print "$1"; }
|
|
' $1)
|
|
if [ -n "$KEY_VALUE" ]; then
|
|
$PERL -i -ne '
|
|
$_ =~ s/[\r]//;
|
|
if ($_ =~ /^'$2'=.*$/) { print "'$2'='$3'\n"; } else { print; }
|
|
' $1
|
|
else
|
|
printf "$2=$3\n" >> "$1"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the value of the EULA boolean.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# ---------------------------------------------------------------------------
|
|
getEULAValue() {
|
|
local EULA_FILE
|
|
EULA_FILE=$WORLDS_LOCATION/$1/eula.txt
|
|
getValue "$EULA_FILE" "eula" "true" | $PERL -ne 'print lc'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the value of a key in a mscs.properties file.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The key to get.
|
|
# @param 3 The default value.
|
|
# ---------------------------------------------------------------------------
|
|
getMSCSValue() {
|
|
local PROPERTY_FILE
|
|
PROPERTY_FILE=$WORLDS_LOCATION/$1/mscs.properties
|
|
getValue "$PROPERTY_FILE" "$2" "$3"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Modify the value of a key/value combo in a mscs.properties file.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The key to modify.
|
|
# @param 3 The value to assign to the key.
|
|
# ---------------------------------------------------------------------------
|
|
setMSCSValue() {
|
|
local PROPERTY_FILE
|
|
PROPERTY_FILE=$WORLDS_LOCATION/$1/mscs.properties
|
|
setValue "$PROPERTY_FILE" "$2" "$3"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the value of a key in a server.properties file.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The key to get.
|
|
# @param 3 The default value.
|
|
# ---------------------------------------------------------------------------
|
|
getServerPropertiesValue() {
|
|
local PROPERTY_FILE
|
|
PROPERTY_FILE="$WORLDS_LOCATION/$1/server.properties"
|
|
getValue "$PROPERTY_FILE" "$2" "$3"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Modify the value of a key/value combo in a server.properties file.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The key to modify.
|
|
# @param 3 The value to assign to the key.
|
|
# ---------------------------------------------------------------------------
|
|
setServerPropertiesValue() {
|
|
local PROPERTY_FILE
|
|
PROPERTY_FILE=$WORLDS_LOCATION/$1/server.properties
|
|
setValue "$PROPERTY_FILE" "$2" "$3"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the current Minecraft version number.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return The current Minecraft version number.
|
|
# ---------------------------------------------------------------------------
|
|
getCurrentMinecraftVersion() {
|
|
local VERSION TYPE
|
|
# Make sure the server software directory exists.
|
|
mkdir -p "$DEFAULT_SERVER_LOCATION"
|
|
# Determine the version type for the current world.
|
|
TYPE=$(getMSCSValue "$1" "mscs-version-type" "$DEFAULT_VERSION_TYPE")
|
|
if [ -s $VERSIONS_JSON ]; then
|
|
# Make a backup copy of the versions.json file.
|
|
cp -p "$VERSIONS_JSON" "$VERSIONS_JSON.bak"
|
|
# Delete the versions.json file if it is old.
|
|
find "$VERSIONS_JSON" -mmin +"$VERSIONS_DURATION" -delete
|
|
fi
|
|
# Download the versions.json file if it does not exist.
|
|
if [ ! -s $VERSIONS_JSON ]; then
|
|
$WGET --no-use-server-timestamps -qO "$VERSIONS_JSON" "$MINECRAFT_VERSIONS_URL"
|
|
if [ $? -ne 0 ]; then
|
|
if [ -s $VERSIONS_JSON.bak ]; then
|
|
printf "Error downloading the Minecraft versions.json file, using an old copy.\n"
|
|
cp -p "$VERSIONS_JSON.bak" "$VERSIONS_JSON"
|
|
else
|
|
printf "Error downloading the Minecraft versions.json file.\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
# Extract the current version information.
|
|
VERSION=$(
|
|
$PERL -ne 'if ($_ =~ /^\s+\"'$TYPE'\": \"([\w\.-]+)\"/) { print $1; }' $VERSIONS_JSON
|
|
)
|
|
# Print an error and exit if the version string is empty.
|
|
if [ -z "$VERSION" ]; then
|
|
printf "Error detecting the current Minecraft version.\n"
|
|
exit 1
|
|
fi
|
|
echo "$VERSION"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Get the release time of the Minecraft version number.
|
|
#
|
|
# @param 1 The Minecraft version number.
|
|
# @return The release time of the Minecraft version number.
|
|
# ---------------------------------------------------------------------------
|
|
getMinecraftVersionReleaseTime() {
|
|
cat $VERSIONS_JSON | $PERL -e '
|
|
$id = null;
|
|
while (<>) {
|
|
if ($_ =~ /\"id\":\s+\"('$1')\"/) {
|
|
$id = $1;
|
|
}
|
|
elsif ($id != null && $_ =~ /\"releaseTime\":\s+\"([\w:+-]+)\"/) {
|
|
print $1;
|
|
last;
|
|
}
|
|
}
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the version of the client for the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return CLIENT_VERSION
|
|
# ---------------------------------------------------------------------------
|
|
getClientVersion() {
|
|
local CURRENT_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the client version, use the default version if not provided.
|
|
getMSCSValue "$1" "mscs-client-version" "$DEFAULT_CLIENT_VERSION" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the .jar file name for the client for the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return CLIENT_JAR
|
|
# ---------------------------------------------------------------------------
|
|
getClientJar() {
|
|
local CURRENT_VERSION CLIENT_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
CLIENT_VERSION=$(getClientVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CLIENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the client jar, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-client-jar" "$DEFAULT_CLIENT_JAR" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$client_version="'$CLIENT_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$CLIENT_VERSION/$client_version/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the location of the client files for the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return CLIENT_LOCATION
|
|
# ---------------------------------------------------------------------------
|
|
getClientLocation() {
|
|
local CURRENT_VERSION CLIENT_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
CLIENT_VERSION=$(getClientVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CLIENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the client location, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-client-location" "$DEFAULT_CLIENT_LOCATION" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$client_version="'$CLIENT_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$CLIENT_VERSION/$client_version/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the URL to download the client for the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return CLIENT_URL
|
|
# ---------------------------------------------------------------------------
|
|
getClientURL() {
|
|
local CURRENT_VERSION CLIENT_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
CLIENT_VERSION=$(getClientVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CLIENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the client download URL, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-client-url" "$DEFAULT_CLIENT_URL" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$client_version="'$CLIENT_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$CLIENT_VERSION/$client_version/g;
|
|
$_ =~ s/\\\:/\:/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the version of the server running the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return SERVER_VERSION
|
|
# ---------------------------------------------------------------------------
|
|
getServerVersion() {
|
|
local CURRENT_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the server version, use the default version if not provided.
|
|
getMSCSValue "$1" "mscs-server-version" "$DEFAULT_SERVER_VERSION" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the .jar file name for the server running the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return SERVER_JAR
|
|
# ---------------------------------------------------------------------------
|
|
getServerJar() {
|
|
local CURRENT_VERSION SERVER_VERSION SERVER_JAR
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
SERVER_VERSION=$(getServerVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the server jar, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-server-jar" "$DEFAULT_SERVER_JAR" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$server_version="'$SERVER_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$SERVER_VERSION/$server_version/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the location of the server files for the server running the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return SERVER_LOCATION
|
|
# ---------------------------------------------------------------------------
|
|
getServerLocation() {
|
|
local CURRENT_VERSION SERVER_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
SERVER_VERSION=$(getServerVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the server location, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-server-location" "$DEFAULT_SERVER_LOCATION" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$server_version="'$SERVER_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$SERVER_VERSION/$server_version/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the URL to download the server running the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return SERVER_URL
|
|
# ---------------------------------------------------------------------------
|
|
getServerURL() {
|
|
local CURRENT_VERSION SERVER_VERSION
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
SERVER_VERSION=$(getServerVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_VERSION\n"
|
|
exit 1
|
|
fi
|
|
# Get the server download URL, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-server-url" "$DEFAULT_SERVER_URL" |
|
|
$PERL -ne '
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$server_version="'$SERVER_VERSION'";
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$SERVER_VERSION/$server_version/g;
|
|
$_ =~ s/\\\:/\:/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Retrieve the command to start the server running the world.
|
|
#
|
|
# @param 1 The world server.
|
|
# @return SERVER_COMMAND
|
|
# ---------------------------------------------------------------------------
|
|
getServerCommand() {
|
|
local CURRENT_VERSION SERVER_VERSION SERVER_JAR SERVER_LOCATION
|
|
local SERVER_ARGS INITIAL_MEMORY MAXIMUM_MEMORY
|
|
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CURRENT_VERSION\n"
|
|
exit 1
|
|
fi
|
|
SERVER_VERSION=$(getServerVersion "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_VERSION\n"
|
|
exit 1
|
|
fi
|
|
SERVER_JAR=$(getServerJar "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_JAR\n"
|
|
exit 1
|
|
fi
|
|
SERVER_LOCATION=$(getServerLocation "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_LOCATION\n"
|
|
exit 1
|
|
fi
|
|
# Get the server arguments, use the default value if not provided.
|
|
SERVER_ARGS=$(
|
|
getMSCSValue "$1" "mscs-server-args" "$DEFAULT_SERVER_ARGS"
|
|
)
|
|
# Get the initial memory, use the default value if not provided.
|
|
INITIAL_MEMORY=$(
|
|
getMSCSValue "$1" "mscs-initial-memory" "$DEFAULT_INITIAL_MEMORY"
|
|
)
|
|
# Get the maximum memory, use the default value if not provided.
|
|
MAXIMUM_MEMORY=$(
|
|
getMSCSValue "$1" "mscs-maximum-memory" "$DEFAULT_MAXIMUM_MEMORY"
|
|
)
|
|
# Get the server command, use the default value if not provided.
|
|
getMSCSValue "$1" "mscs-server-command" "$DEFAULT_SERVER_COMMAND" |
|
|
$PERL -ne '
|
|
$java = "'$JAVA'";
|
|
$current_version="'$CURRENT_VERSION'";
|
|
$server_version="'$SERVER_VERSION'";
|
|
$server_jar = "'$SERVER_JAR'";
|
|
$server_location = "'$SERVER_LOCATION'";
|
|
$server_args = "'$SERVER_ARGS'";
|
|
$initial_memory = "'$INITIAL_MEMORY'";
|
|
$maximum_memory = "'$MAXIMUM_MEMORY'";
|
|
$_ =~ s/\$JAVA/$java/g;
|
|
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
|
|
$_ =~ s/\$SERVER_VERSION/$server_version/g;
|
|
$_ =~ s/\$SERVER_JAR/$server_jar/g;
|
|
$_ =~ s/\$SERVER_LOCATION/$server_location/g;
|
|
$_ =~ s/\$SERVER_ARGS/$server_args/g;
|
|
$_ =~ s/\$INITIAL_MEMORY/$initial_memory/g;
|
|
$_ =~ s/\$MAXIMUM_MEMORY/$maximum_memory/g;
|
|
print;
|
|
'
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Remove old world log files and rotate log files from old servers (v < 1.7).
|
|
#
|
|
# @param 1 The world server generating the log to rotate.
|
|
# ---------------------------------------------------------------------------
|
|
rotateLog() {
|
|
local WORLD_DIR DATE LOG NUMBER
|
|
WORLD_DIR="$WORLDS_LOCATION/$1"
|
|
# Make sure the log directory exists.
|
|
mkdir -p "$WORLD_DIR/logs"
|
|
# Delete old log files.
|
|
find "$WORLD_DIR/logs" -type f -mtime +"$LOG_DURATION" -delete
|
|
# Archive and rotate the log files for old Minecraft servers (Versions 1.7
|
|
# and greater do this automatically).
|
|
if [ -e "$WORLD_DIR/server.log" ] &&
|
|
[ $(wc -l < $WORLD_DIR/server.log) -ge 1 ]; then
|
|
# Make a copy of the log file in the world's logs directory.
|
|
DATE=$(date +%F)
|
|
cp "$WORLD_DIR/server.log" "$WORLD_DIR/logs/$DATE-0.log"
|
|
gzip "$WORLD_DIR/logs/$DATE-0.log"
|
|
# Empty the contents of the worlds log file.
|
|
cp /dev/null "$WORLD_DIR/server.log"
|
|
# Rotate the files in the world's logs directory.
|
|
for LOG in $(ls -r $WORLD_DIR/logs/$DATE-*.log.gz); do
|
|
NUMBER=$(echo $LOG | cut -d "." -f 1 | cut -d "-" -f 4)
|
|
NUMBER=$(($NUMBER+1))
|
|
mv -f $LOG "$WORLD_DIR/logs/$DATE-$NUMBER.log.gz"
|
|
done
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Watch the world latest.log file.
|
|
#
|
|
# @param 1 The world server generating the log to watch.
|
|
# ---------------------------------------------------------------------------
|
|
watchLog() {
|
|
local WORLD_DIR
|
|
WORLD_DIR="$WORLDS_LOCATION/$1"
|
|
# Make sure that the latest.log file exists.
|
|
if [ -e "$WORLD_DIR/logs/latest.log" ]; then
|
|
# Watch the log file of worlds running Minecraft 1.7 +.
|
|
tail -n0 -f --pid=$(getJavaPID "$1") $WORLD_DIR/logs/latest.log
|
|
elif [ -e "$WORLD_DIR/server.log" ]; then
|
|
# Watch the log file of worlds running older Minecraft servers.
|
|
tail -n0 -f --pid=$(getJavaPID "$1") $WORLD_DIR/server.log
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Synchronizes the data stored in the mirror images.
|
|
#
|
|
# @param 1 The world server to sync.
|
|
# ---------------------------------------------------------------------------
|
|
syncMirrorImage() {
|
|
# Sync the world server.
|
|
cp -Ru "$WORLDS_LOCATION/$1/$1/*" "$WORLDS_LOCATION/$1/$1-original"
|
|
if [ $? -ne 0 ]; then
|
|
printf "Error synchronizing mirror images for world $1.\n"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Display the server console.
|
|
#
|
|
# @param 1 The world server to connect to.
|
|
# ---------------------------------------------------------------------------
|
|
serverConsole() {
|
|
local LINE WORLD_DIR
|
|
# Make sure that the world's directory exists.
|
|
WORLD_DIR="$WORLDS_LOCATION/$1"
|
|
# Follow the console output buffer file.
|
|
sh -c "tail --pid=\$$ -f '$WORLD_DIR/console.out'" &
|
|
# Copy user input to the console input buffer file.
|
|
while read LINE; do
|
|
echo "$LINE" >> $WORLD_DIR/console.in
|
|
done
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Start the world server. Generate the appropriate environment for the
|
|
# server if it doesn't already exist.
|
|
#
|
|
# @param 1 The world server to start.
|
|
# ---------------------------------------------------------------------------
|
|
start() {
|
|
local EULA PID SERVER_COMMAND WORLD_DIR
|
|
# Make sure that the server software exists.
|
|
updateServerSoftware "$1"
|
|
# Make sure that the world's directory exists.
|
|
WORLD_DIR="$WORLDS_LOCATION/$1"
|
|
mkdir -p "$WORLD_DIR"
|
|
# Make sure the EULA has been set to true.
|
|
EULA=$(getEULAValue "$1")
|
|
if [ $EULA != "true" ]; then
|
|
printf "\nError, the EULA has not been accepted for world %s.\n" "$1"
|
|
printf "To accept the EULA, modify %s/eula.txt file.\n" "$WORLD_DIR"
|
|
exit 1
|
|
fi
|
|
# Rotate the world's log files.
|
|
rotateLog "$1"
|
|
# Make a mirror image of the world directory if requested.
|
|
if [ $ENABLE_MIRROR -eq 1 ]; then
|
|
mkdir -p "$MIRROR_PATH/$1"
|
|
if [ $? -ne 0 ]; then
|
|
printf "Error copying world data, path %s not found.\n" $MIRROR_PATH/$1
|
|
exit 1
|
|
fi
|
|
# Check for a clean dismount from the previous server run. If we have a
|
|
# <world>-original directory within <world> we didn't stop cleanly.
|
|
if [ -d "WORLDS_LOCATION/$1/$1-original" ]; then
|
|
# Remove the symlink to the world-file mirror image.
|
|
rm -r "$WORLDS_LOCATION/$1/$1"
|
|
# Move the world files back to their original path name.
|
|
mv "$WORLDS_LOCATION/$1/$1-original" "$WORLDS_LOCATION/$1/$1"
|
|
fi
|
|
# Copy the world files over to the mirror.
|
|
cp -R "$WORLDS_LOCATION/$1/$1/*" "$MIRROR_PATH/$1"
|
|
# Rename the original world file directory.
|
|
mv "$WORLDS_LOCATION/$1/$1" "$WORLDS_LOCATION/$1/$1-original"
|
|
# Create a symlink from the world file directory's original name to the mirrored files.
|
|
ln -s "$MIRROR_PATH/$1" "$WORLDS_LOCATION/$1/$1"
|
|
fi
|
|
# Change to the world's directory.
|
|
cd $WORLD_DIR
|
|
# Delete any old console.in or console.out buffer files.
|
|
rm -f "$WORLD_DIR/console.in" "$WORLD_DIR/console.out"
|
|
# Initialize the console.in buffer file.
|
|
printf '' > $WORLD_DIR/console.in
|
|
# Get the server command for this world.
|
|
SERVER_COMMAND=$(getServerCommand "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_COMMAND\n"
|
|
exit 1
|
|
fi
|
|
# Start the server.
|
|
sh -c "tail -f --pid=\$$ '$WORLD_DIR/console.in' | {
|
|
$SERVER_COMMAND mscs-world='$1' > '$WORLD_DIR/console.out' 2>&1; kill \$$;
|
|
}" &
|
|
# Verify the server is running.
|
|
if [ $? -ne 0 ]; then
|
|
printf "Error starting the server.\n"
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
PID=$(getJavaPID "$1")
|
|
if [ $PID -eq 0 ]; then
|
|
printf "Error starting the server: couldn't retrieve the server's process ID.\n"
|
|
exit 1
|
|
fi
|
|
# Start the Query handler if enabled.
|
|
if [ "$(getServerPropertiesValue $1 'enable-query')" = "true" ]; then
|
|
queryStart "$1" &
|
|
fi
|
|
# Create a PID file for the world server.
|
|
echo $PID > "$WORLDS_LOCATION/$1.pid"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stop the world server.
|
|
#
|
|
# @param 1 The world server to stop.
|
|
# ---------------------------------------------------------------------------
|
|
stop() {
|
|
local WORLD NUM
|
|
sendCommand $1 "stop"
|
|
sendCommand $1 "end"
|
|
# Synchronize the mirror image of the world prior to closing, if
|
|
# required.
|
|
if [ $ENABLE_MIRROR -eq 1 ] && [ -d $MIRROR_PATH ]; then
|
|
syncMirrorImage $1
|
|
# Remove the symlink to the world-file mirror image.
|
|
rm -r "$WORLDS_LOCATION/$1/$1"
|
|
# Move the world files back to their original path name.
|
|
mv "$WORLDS_LOCATION/$1/$1-original" "$WORLDS_LOCATION/$1/$1"
|
|
fi
|
|
# Remove the PID file for the world server.
|
|
rm -f "$WORLDS_LOCATION/$1.pid"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Forcibly stop the world server.
|
|
#
|
|
# @param 1 The world server to forcibly stop.
|
|
# ---------------------------------------------------------------------------
|
|
forceStop() {
|
|
# Try to stop the server cleanly first.
|
|
stop "$1"
|
|
sleep 5
|
|
# Kill the process id of the world server.
|
|
kill -9 $(getJavaPID "$1") > /dev/null 2>&1
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Backup the world server.
|
|
#
|
|
# @param 1 The world server to backup.
|
|
# @return A 0 if backup successful, a 1 otherwise
|
|
# ---------------------------------------------------------------------------
|
|
worldBackup() {
|
|
# Make sure that the backup location exists.
|
|
if ! mkdir -p "$BACKUP_LOCATION"; then
|
|
echo "Error creating backup dir $BACKUP_LOCATION"
|
|
return 1
|
|
fi
|
|
# Create the backup.
|
|
if ! $RDIFF_BACKUP -v5 --print-statistics "$WORLDS_LOCATION/$1" "$BACKUP_LOCATION/$1" >> "$BACKUP_LOG"; then
|
|
echo "Error doing backup of world $1"
|
|
return 1
|
|
fi
|
|
# Cleanup old backups.
|
|
if [ $BACKUP_DURATION -gt 0 ]; then
|
|
if ! $RDIFF_BACKUP --remove-older-than ${BACKUP_DURATION}D --force "$BACKUP_LOCATION/$1" >> "$BACKUP_LOG"; then
|
|
echo "Error cleaning old backups of world $1"
|
|
return 1
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# List the backups for the world server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# ---------------------------------------------------------------------------
|
|
worldBackupList() {
|
|
local SEC TYPE
|
|
if [ -d $BACKUP_LOCATION/$1 ]; then
|
|
# Grab the list of backups for the world server.
|
|
$RDIFF_BACKUP --parsable-output -l $BACKUP_LOCATION/$1 |
|
|
while read SEC TYPE; do
|
|
date --date=\@$SEC --rfc-3339=seconds | tr ' ' T
|
|
done
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Restore a backup for the world server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The datetime of the backup to restore.
|
|
# @return A 0 on success, a 1 otherwise.
|
|
# ---------------------------------------------------------------------------
|
|
worldBackupRestore() {
|
|
local TARGET TARGET_TMP
|
|
TARGET="$WORLDS_LOCATION/$1"
|
|
TARGET_TMP="${TARGET}_bktmp"
|
|
rm -rf "$TARGET_TMP"
|
|
if [ -d $BACKUP_LOCATION/$1 ]; then
|
|
if $RDIFF_BACKUP -r $2 "$BACKUP_LOCATION/$1" "$TARGET_TMP"; then
|
|
rm -r "$TARGET"
|
|
mv "$TARGET_TMP" "$TARGET"
|
|
else
|
|
echo "Restoring backup failed: $1 $2"
|
|
rm -rf "$TARGET_TMP"
|
|
return 1
|
|
fi
|
|
else
|
|
echo "No backups found for world $1"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Update the Minecraft client software.
|
|
#
|
|
# @param 1 The world to update.
|
|
# ---------------------------------------------------------------------------
|
|
updateClientSoftware() {
|
|
local CLIENT_JAR CLIENT_LOCATION CLIENT_URL
|
|
CLIENT_JAR=$(getClientJar "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CLIENT_JAR\n"
|
|
exit 1
|
|
fi
|
|
CLIENT_LOCATION=$(getClientLocation "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CLIENT_LOCATION\n"
|
|
exit 1
|
|
fi
|
|
CLIENT_URL=$(getClientURL "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$CLIENT_URL\n"
|
|
exit 1
|
|
fi
|
|
# Make sure the client software directory exists.
|
|
mkdir -p "$CLIENT_LOCATION"
|
|
# Download the client jar if it is missing.
|
|
if [ ! -s "$CLIENT_LOCATION/$CLIENT_JAR" ]; then
|
|
# Download the Minecraft client software.
|
|
$WGET -qO "$CLIENT_LOCATION/$CLIENT_JAR" "$CLIENT_URL"
|
|
# Report any errors.
|
|
if [ $? -ne 0 ]; then
|
|
printf "Error updating the Minecraft client software.\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Update the Minecraft server software.
|
|
#
|
|
# @param 1 The world server to update.
|
|
# ---------------------------------------------------------------------------
|
|
updateServerSoftware() {
|
|
local SERVER_JAR SERVER_LOCATION SERVER_URL
|
|
SERVER_JAR=$(getServerJar "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_JAR\n"
|
|
exit 1
|
|
fi
|
|
SERVER_LOCATION=$(getServerLocation "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_LOCATION\n"
|
|
exit 1
|
|
fi
|
|
SERVER_URL=$(getServerURL "$1")
|
|
if [ $? -ne 0 ]; then
|
|
printf "$SERVER_URL\n"
|
|
exit 1
|
|
fi
|
|
# Make sure the server software directory exists.
|
|
mkdir -p "$SERVER_LOCATION"
|
|
# Download the server jar if it is missing.
|
|
if [ ! -s "$SERVER_LOCATION/$SERVER_JAR" ]; then
|
|
# Download the Minecraft server software.
|
|
$WGET -qO "$SERVER_LOCATION/$SERVER_JAR" "$SERVER_URL"
|
|
# Report any errors.
|
|
if [ $? -ne 0 ]; then
|
|
printf "Error updating the Minecraft server software.\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Run Minecraft Overviewer mapping software on the world. Generates an
|
|
# index.html file using the Google Maps API.
|
|
#
|
|
# @param 1 The world server to map with Overviewer.
|
|
# ---------------------------------------------------------------------------
|
|
overviewer() {
|
|
local CLIENT_JAR CLIENT_LOCATION SERVER_RUNNING
|
|
if serverRunning $1; then
|
|
SERVER_RUNNING=1
|
|
else
|
|
SERVER_RUNNING=0
|
|
fi
|
|
# Announce the mapping of the world to players.
|
|
if [ $SERVER_RUNNING -eq 1 ]; then
|
|
if [ $(compareMinecraftVersions $(getServerVersion $1) 1.7.2) -ge 0 ]; then
|
|
sendCommand $WORLD 'tellraw @a {
|
|
"text" : "",
|
|
"extra" : [
|
|
{
|
|
"text" : "[Server] The world is about to be mapped with "
|
|
},
|
|
{
|
|
"text" : "Overviewer",
|
|
"color" : "aqua",
|
|
"clickEvent" : {
|
|
"action" : "open_url",
|
|
"value" : "'$OVERVIEWER_URL'"
|
|
}
|
|
},
|
|
{
|
|
"text" : "."
|
|
}
|
|
]
|
|
}'
|
|
else
|
|
sendCommand $1 "say The world is about to be mapped with Overviewer."
|
|
fi
|
|
sendCommand $1 "save-all"
|
|
sendCommand $1 "save-off"
|
|
sleep 20
|
|
# Run a backup of the world.
|
|
worldBackup $1
|
|
sendCommand $1 "save-on"
|
|
fi
|
|
# Make sure the maps directory exists.
|
|
mkdir -p "$MAPS_LOCATION/$1"
|
|
# Make sure the Minecraft client is available.
|
|
updateClientSoftware "$1"
|
|
# Make sure that the world files are actually there before mapping.
|
|
if [ -e "$WORLDS_LOCATION/$1/server.properties" ]; then
|
|
# Check for Overviewer settings file.
|
|
if [ ! -e "$WORLDS_LOCATION/$1/overviewer-settings.py" ]; then
|
|
touch "$WORLDS_LOCATION/$1/overviewer-settings.py"
|
|
#Use the backup location so we minimize the time the server don't save data.
|
|
printf "worlds['$1'] = \"$BACKUP_LOCATION/$1/$1\"\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "renders['normalrender'] = {\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'world': '$1',\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'title': 'Normal',\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'dimension': 'overworld',\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'rendermode': 'normal'\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "}\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "renders['caverender'] = {\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'world': '$1',\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'title': 'Caves',\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'dimension': 'overworld',\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf " 'rendermode': 'cave'\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "}\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
printf "outputdir = \"$MAPS_LOCATION/$1\"\n" >> $WORLDS_LOCATION/$1/overviewer-settings.py
|
|
fi
|
|
# Generate the map and POI.
|
|
$OVERVIEWER_BIN --config="$WORLDS_LOCATION/$1/overviewer-settings.py" >> "$WORLDS_LOCATION/$1/logs/overviewer.log" 2>&1
|
|
$OVERVIEWER_BIN --config="$WORLDS_LOCATION/$1/overviewer-settings.py" --genpoi >> "$WORLDS_LOCATION/$1/logs/overviewer.log" 2>&1
|
|
fi
|
|
# Announce the location to access the world map to players.
|
|
if [ $SERVER_RUNNING -eq 1 ]; then
|
|
if [ $(compareMinecraftVersions $(getServerVersion $1) 1.7.2) -ge 0 ]; then
|
|
sendCommand $WORLD 'tellraw @a {
|
|
"text" : "",
|
|
"extra" : [
|
|
{
|
|
"text" : "[Server] Mapping is complete. You can access the maps "
|
|
},
|
|
{
|
|
"text" : "here",
|
|
"color" : "aqua",
|
|
"clickEvent" : {
|
|
"action" : "open_url",
|
|
"value" : "'$MAPS_URL'/'$WORLD'"
|
|
}
|
|
},
|
|
{
|
|
"text" : "."
|
|
}
|
|
]
|
|
}'
|
|
else
|
|
sendCommand $1 "say Mapping is complete. You can access the maps at:"
|
|
sendCommand $1 "say $MAPS_URL/$WORLD"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Start a Query handler for a world server.
|
|
#
|
|
# @param 1 The world server to start a Query handler for.
|
|
# ---------------------------------------------------------------------------
|
|
queryStart() {
|
|
local WORLD_DIR SERVER_IP QUERY_PORT
|
|
# Grab the location of the world's directory.
|
|
WORLD_DIR="$WORLDS_LOCATION/$1"
|
|
# Determine the IP address and port used by the query server.
|
|
SERVER_IP=$(getServerPropertiesValue $1 'server-ip' '127.0.0.1')
|
|
QUERY_PORT=$(getServerPropertiesValue $1 'query.port')
|
|
# Delete any old query.in or query.out buffer files.
|
|
rm -Rf "$WORLD_DIR/query.in" "$WORLD_DIR/query.out"
|
|
# Give the server a moment to start before initializing the
|
|
# Query handler.
|
|
sleep 20
|
|
# Initialize the query.in and query.out buffer files.
|
|
printf '' > "$WORLD_DIR/query.in"
|
|
printf '' > "$WORLD_DIR/query.out"
|
|
# Start a tail process to watch for changes to the query.in file to pipe
|
|
# to the Minecraft query server via socat. The response from the query
|
|
# server is piped into the query.out file.
|
|
tail -f --pid=$(getJavaPID $1) "$WORLD_DIR/query.in" | \
|
|
$SOCAT - UDP:$SERVER_IP:$QUERY_PORT > "$WORLD_DIR/query.out"
|
|
# Verify the connection to the query server worked.
|
|
if [ $? -ne 0 ]; then
|
|
printf "Error connecting to the query server.\n"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Pack a hex string into a buffer file that is piped to the Minecraft query
|
|
# server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @param 2 The packet type.
|
|
# @param 3 The packet payload.
|
|
# @param 4 The response format.
|
|
# @return The response from the Query server in the requested format.
|
|
# ---------------------------------------------------------------------------
|
|
querySendPacket() {
|
|
local ID PACKET RESPONSE WORLD_DIR
|
|
# The packet identifier.
|
|
ID="00000001"
|
|
# The world's directory.
|
|
WORLD_DIR="$WORLDS_LOCATION/$1"
|
|
# Make sure the query.in and query.out buffer files exist before
|
|
# preparing and sending the packet to the Query server.
|
|
if [ -e "$WORLD_DIR/query.in" ] && [ -e "$WORLD_DIR/query.out" ]; then
|
|
# Add the magic bytes and create the hex string packet.
|
|
PACKET=$(printf "FEFD%s%s%s" "$2" "$ID" "$3")
|
|
# Remove any old responses from the query.out buffer file.
|
|
printf '' > "$WORLD_DIR/query.out"
|
|
# Pack the hex string packet and write it to the query.in buffer file.
|
|
$PERL -e "
|
|
print map { pack (\"C\", hex(\$_)) } (\"$PACKET\" =~ /(..)/g);
|
|
" >> "$WORLD_DIR/query.in"
|
|
# Give the Query server a moment to respond.
|
|
sleep 1
|
|
# Unpack the response packet from the query.out buffer file. There are a
|
|
# variable amount of null bytes at the start of the response packet, so
|
|
# find the start of the response by searching for the packet type and ID.
|
|
RESPONSE=$($PERL -0777 -ne '
|
|
foreach (unpack "C*", $_) {
|
|
$char = sprintf ("%.2x", $_);
|
|
$char =~ s/0a/5c6e/;
|
|
$hex .= $char;
|
|
}
|
|
$hex =~ s/^0*'$2$ID'/'$2$ID'/;
|
|
print $hex;
|
|
' $WORLD_DIR/query.out)
|
|
fi
|
|
if [ -n "$RESPONSE" ]; then
|
|
# Return the response in the format requested.
|
|
$PERL -e '
|
|
$packed = join "", map { pack ("C", hex($_)) } ("'$RESPONSE'" =~ /(..)/g);
|
|
printf "%s\n", join "\t", unpack ("'$4'", $packed);
|
|
'
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Send a challenge packet to the Minecraft query server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return Tab separated values:
|
|
# type - The packet type.
|
|
# id - The packet identifier.
|
|
# token - The token.
|
|
# ---------------------------------------------------------------------------
|
|
querySendChallengePacket() {
|
|
local PACKET
|
|
# Use an empty packet.
|
|
PACKET="00000000"
|
|
# Send the challenge packet to the Minecraft query server.
|
|
querySendPacket "$1" "09" "$PACKET" "Cl>Z*"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Send a status query to the Minecraft query server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return Tab separated values:
|
|
# type - The packet type.
|
|
# id - The packet identifier.
|
|
# MOTD - The world's message of the day.
|
|
# gametype - The world's game type.
|
|
# map - The name of the world.
|
|
# numplayers - The current number of players.
|
|
# maxplayers - The maximum number of players.
|
|
# hostport - The host's port
|
|
# hostip - The host's IP address.
|
|
# ---------------------------------------------------------------------------
|
|
queryStatus() {
|
|
local PACKET TOKEN
|
|
if [ "$(getServerPropertiesValue $1 'enable-query')" = "true" ]; then
|
|
# Send a challenge packet to the Minecraft query server.
|
|
TOKEN=$(querySendChallengePacket $1 | cut -f 3)
|
|
if [ -n "$TOKEN" ]; then
|
|
# Use the challenge token for the packet.
|
|
PACKET=$(printf "%08x" $TOKEN)
|
|
# Send the information request packet to the Minecraft query server.
|
|
querySendPacket "$1" "00" "$PACKET" "Cl>Z*Z*Z*Z*Z*s<Z*"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Send a detailed status query to the Minecraft query server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return Tab separated values:
|
|
# type - The packet type.
|
|
# id - The packet identifier.
|
|
# * - The string 'splitnum'.
|
|
# * - The value 128.
|
|
# * - The value 0.
|
|
# * - The string 'hostname'.
|
|
# MOTD - The world's message of the day.
|
|
# * - The string 'gametype'.
|
|
# gametype - The world's game type, hardcoded to 'SMP'.
|
|
# * - The string 'game_id'.
|
|
# gameid - The world's game ID, hardcoded to 'MINECRAFT'.
|
|
# * - The string 'version'.
|
|
# version - The world's Minecraft version.
|
|
# * - The string 'plugins'.
|
|
# plugins - The world's plugins.
|
|
# * - The string 'map'.
|
|
# map - The world's name.
|
|
# * - The string 'numplayers'.
|
|
# numplayers - The world's current number of players.
|
|
# * - The string 'maxplayers'.
|
|
# maxplayers - The world's maximum number of players.
|
|
# * - The string 'hostport'.
|
|
# hostport - The world's host port.
|
|
# * - The string 'hostip'.
|
|
# hostip - The world's host IP address.
|
|
# * - The value 0.
|
|
# * - The value 1.
|
|
# * - The string 'player_'.
|
|
# * - The value 0.
|
|
# players - The players currently logged onto the world.
|
|
# ---------------------------------------------------------------------------
|
|
queryDetailedStatus() {
|
|
local CHALLENGE ID PACKET TOKEN
|
|
if [ "$(getServerPropertiesValue $1 'enable-query')" = "true" ]; then
|
|
# Send a challenge packet to the Minecraft query server.
|
|
CHALLENGE=$(querySendChallengePacket $1)
|
|
ID=$(echo "$CHALLENGE" | cut -f 2)
|
|
TOKEN=$(echo "$CHALLENGE" | cut -f 3)
|
|
if [ -n "$ID" ] && [ -n "$TOKEN" ]; then
|
|
# Use the challenge token for the packet, with the ID on the end.
|
|
PACKET=$(printf "%08x%08x" $TOKEN $ID)
|
|
# Send the information request packet to the Minecraft query server.
|
|
querySendPacket "$1" "00" "$PACKET" \
|
|
"Cl>Z*CCZ*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*Z*CCZ*C(Z*)*"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Send a detailed status query to the Minecraft query server and return the
|
|
# data in JSON format.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return Query values in JSON format.
|
|
queryDetailedStatusJSON() {
|
|
local STATUS JSON PLAYERS COUNTER
|
|
STATUS=$(queryDetailedStatus $1)
|
|
if [ -n "$STATUS" ]; then
|
|
NUMPLAYERS=$(printf "%s" "$STATUS" | cut -f 19)
|
|
if [ $NUMPLAYERS -gt 0 ]; then
|
|
PLAYERS=$(printf "\"%s\"" "$STATUS" | cut -f 30)
|
|
COUNTER=1
|
|
while [ $COUNTER -lt $NUMPLAYERS ]; do
|
|
PLAYERS=$(printf "%s, \"%s\"" "$PLAYERS" $(printf "%s" "$STATUS" | cut -f $((30+$COUNTER))))
|
|
COUNTER=$(($COUNTER+1))
|
|
done
|
|
fi
|
|
JSON='{
|
|
"motd": "'$(printf "%s" "$STATUS" | cut -f 7)'",
|
|
"gametype": "'$(printf "%s" "$STATUS" | cut -f 9)'",
|
|
"gameid": "'$(printf "%s" "$STATUS" | cut -f 11)'",
|
|
"version": "'$(printf "%s" "$STATUS" | cut -f 13)'",
|
|
"plugins": "'$(printf "%s" "$STATUS" | cut -f 15)'",
|
|
"map": "'$(printf "%s" "$STATUS" | cut -f 17)'",
|
|
"numplayers": '$NUMPLAYERS',
|
|
"maxplayers": '$(printf "%s" "$STATUS" | cut -f 21)',
|
|
"hostport": "'$(printf "%s" "$STATUS" | cut -f 23)'",
|
|
"hostip": "'$(printf "%s" "$STATUS" | cut -f 25)'",
|
|
"players": ['$PLAYERS']
|
|
}'
|
|
else
|
|
JSON="{}"
|
|
fi
|
|
printf "%s" $JSON
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Query the number of active users from the query server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# @return Number of active users.
|
|
# ---------------------------------------------------------------------------
|
|
queryNumUsers() {
|
|
local NUM_USERS
|
|
NUM_USERS=$(queryStatus $1 | cut -f6)
|
|
# Return 0 if query server not available
|
|
[ -z "$NUM_USERS" ] && NUM_USERS=0
|
|
echo "$NUM_USERS"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Display the status of a Minecraft world server.
|
|
#
|
|
# @param 1 The world server of interest.
|
|
# ---------------------------------------------------------------------------
|
|
worldStatus() {
|
|
local STATUS NUM MAX PLAYERS COUNTER VERSION
|
|
if serverRunning $1; then
|
|
STATUS=$(queryDetailedStatus $1)
|
|
if [ -n "$STATUS" ]; then
|
|
NUM=$(printf "%s" "$STATUS" | cut -f 19)
|
|
MAX=$(printf "%s" "$STATUS" | cut -f 21)
|
|
VERSION=$(printf "%s" "$STATUS" | cut -f 13)
|
|
printf "running version %s (%d of %d users online).\n" $VERSION $NUM $MAX
|
|
if [ $NUM -gt 0 ]; then
|
|
PLAYERS=$(printf "%s" "$STATUS" | cut -f 30)
|
|
COUNTER=1
|
|
while [ $COUNTER -lt $NUM ]; do
|
|
PLAYERS=$(printf "%s, %s" "$PLAYERS" $(printf "%s" "$STATUS" | cut -f $((30+$COUNTER))))
|
|
COUNTER=$(($COUNTER+1))
|
|
done
|
|
printf " Players: %s.\n" "$PLAYERS"
|
|
fi
|
|
elif [ "$(getServerPropertiesValue $1 'enable-query')" = "true" ]; then
|
|
printf "running (query server offline).\n"
|
|
else
|
|
printf "running.\n"
|
|
fi
|
|
printf " Process ID: %d.\n" $(getJavaPID "$1")
|
|
elif [ "$(getMSCSValue $1 'mscs-enabled')" = "false" ]; then
|
|
printf "disabled.\n"
|
|
else
|
|
printf "not running.\n"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Migrate world from old-style MSCS configuration if necessary.
|
|
#
|
|
# @param 1 The world to be migrated.
|
|
# ---------------------------------------------------------------------------
|
|
migrateOldMSCSConfig() {
|
|
local SERVER_PROPERTY_FILE MSCS_PROPERTY_FILE TMP_PROPERTY_FILE
|
|
if isWorldAvailable "$1"; then
|
|
SERVER_PROPERTY_FILE="$WORLDS_LOCATION/$1/server.properties"
|
|
MSCS_PROPERTY_FILE="$WORLDS_LOCATION/$1/mscs.properties"
|
|
TMP_PROPERTY_FILE="$WORLDS_LOCATION/$1/tmp.properties"
|
|
if [ ! -f "$MSCS_PROPERTY_FILE" ]; then
|
|
grep ^mscs "$SERVER_PROPERTY_FILE" > "$MSCS_PROPERTY_FILE"
|
|
grep -v ^mscs "$SERVER_PROPERTY_FILE" > "$TMP_PROPERTY_FILE"
|
|
mv "$TMP_PROPERTY_FILE" "$SERVER_PROPERTY_FILE"
|
|
fi
|
|
else
|
|
echo "World $1 not found."
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Migrate all worlds from old-style MSCS configuration if necessary.
|
|
# ---------------------------------------------------------------------------
|
|
migrateWorldsConfig() {
|
|
if [ ! -f "$WORLDS_LOCATION/mscs-worlds-config-migrated" ]; then
|
|
echo "Migrating worlds to new mscs.properties config file if needed"
|
|
for WORLD in $(getAvailableWorlds); do
|
|
migrateOldMSCSConfig "$WORLD"
|
|
done
|
|
touch "$WORLDS_LOCATION/mscs-worlds-config-migrated"
|
|
echo "Remove file '$WORLDS_LOCATION/mscs-worlds-config-migrated' to repeat"
|
|
echo "the migration process in the next execution."
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Migrate old disabled worlds if any.
|
|
# ---------------------------------------------------------------------------
|
|
migrateOldDisabledWorlds() {
|
|
local WORLD WORLDS
|
|
if [ -d "$OLD_DISABLED_WORLDS_LOCATION" ]; then
|
|
# Be sure worlds directory exists
|
|
mkdir -p "$WORLDS_LOCATION"
|
|
for WORLD in $(ls "$OLD_DISABLED_WORLDS_LOCATION"); do
|
|
if [ -d "$OLD_DISABLED_WORLDS_LOCATION/$WORLD" ]; then
|
|
echo "Migrating old version's disabled world: $WORLD"
|
|
mv "$OLD_DISABLED_WORLDS_LOCATION/$WORLD" "$WORLDS_LOCATION"
|
|
migrateOldMSCSConfig "$WORLD"
|
|
setMSCSValue "$WORLD" mscs-enabled false
|
|
fi
|
|
done
|
|
# Try to remove old disabled worlds dir if empty
|
|
if ! rmdir "$OLD_DISABLED_WORLDS_LOCATION" > /dev/null 2>&1; then
|
|
echo "Warning: old version's disabled world dir not emty after migration"
|
|
echo " Dir: $OLD_DISABLED_WORLDS_LOCATION"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Begin.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Migrate old config.
|
|
# Migrate config of not already migrated worlds
|
|
migrateWorldsConfig
|
|
# Migrate old version's disabled worlds if any
|
|
migrateOldDisabledWorlds
|
|
|
|
# Make sure that Java, Perl, Python, Wget, Rdiff-backup, and Socat are installed.
|
|
if [ ! -e "$JAVA" ]; then
|
|
printf "ERROR: Java not found!\n"
|
|
printf "Try installing this with:\n"
|
|
printf "sudo apt-get install default-jre"
|
|
exit 1
|
|
fi
|
|
if [ ! -e "$PERL" ]; then
|
|
printf "ERROR: Perl not found!\n"
|
|
printf "Try installing this with:\n"
|
|
printf "sudo apt-get install perl\n"
|
|
exit 1
|
|
fi
|
|
if [ ! -e "$PYTHON" ]; then
|
|
printf "ERROR: Python not found!\n"
|
|
printf "Try installing this with:\n"
|
|
printf "sudo apt-get install python\n"
|
|
exit 1
|
|
fi
|
|
if [ ! -e "$WGET" ]; then
|
|
printf "ERROR: GNU Wget not found!\n"
|
|
printf "Try installing this with:\n"
|
|
printf "sudo apt-get install wget\n"
|
|
exit 1
|
|
fi
|
|
if [ ! -e "$RDIFF_BACKUP" ]; then
|
|
printf "ERROR: rdiff-backup not found!\n"
|
|
printf "Try installing this with:\n"
|
|
printf "sudo apt-get install rdiff-backup\n"
|
|
exit 1
|
|
fi
|
|
if [ ! -e "$SOCAT" ]; then
|
|
printf "ERROR: socat not found!\n"
|
|
printf "Try installing this with:\n"
|
|
printf "sudo apt-get install socat\n"
|
|
exit 1
|
|
fi
|
|
|
|
|
|
# Respond to the command line arguments.
|
|
case "$1" in
|
|
start)
|
|
# Figure out which worlds to start.
|
|
WORLDS=$(getEnabledWorlds)
|
|
if [ -z "$WORLDS" ]; then
|
|
echo "There are no worlds to start."
|
|
echo "You may want to enable a world:"
|
|
echo " $PROG enable <world>"
|
|
echo "Or create a new world:"
|
|
echo " $PROG create <world> <port>"
|
|
echo "Or create the default world at the default port:"
|
|
echo " $PROG create"
|
|
exit 1
|
|
elif [ -n "$2" ]; then
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' not recognized.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
# Start each world requested, if not already running.
|
|
printf "Starting Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
if ! serverRunning $WORLD; then
|
|
printf " $WORLD"
|
|
start $WORLD
|
|
fi
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
stop|force-stop)
|
|
# Figure out which worlds to stop.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' not recognized.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Stop each world requested, if running.
|
|
printf "Stopping Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
# Try to stop the world cleanly.
|
|
if serverRunning $WORLD; then
|
|
printf " $WORLD"
|
|
if [ $(queryNumUsers $WORLD) -gt 0 ]; then
|
|
sendCommand $WORLD "say The server admin has initiated a server shut down."
|
|
sendCommand $WORLD "say The server will shut down in 1 minute..."
|
|
sleep 60
|
|
sendCommand $WORLD "say The server is now shutting down."
|
|
fi
|
|
sendCommand $WORLD "save-all"
|
|
sendCommand $WORLD "save-off"
|
|
if [ "$1" = "force-stop" ]; then
|
|
forceStop $WORLD
|
|
else
|
|
stop $WORLD
|
|
fi
|
|
elif [ "$1" = "force-stop" ]; then
|
|
printf " $WORLD"
|
|
forceStop $WORLD
|
|
fi
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
restart|reload|force-restart|force-reload)
|
|
# Figure out which worlds to restart.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' not recognized.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Restart each world requested, start those not already
|
|
# running.
|
|
printf "Restarting Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD"
|
|
if serverRunning $WORLD; then
|
|
if [ $(queryNumUsers $WORLD) -gt 0 ]; then
|
|
sendCommand $WORLD "say The server admin has initiated a server restart."
|
|
sendCommand $WORLD "say The server will restart in 1 minute..."
|
|
sleep 60
|
|
sendCommand $WORLD "say The server is now restarting."
|
|
fi
|
|
sendCommand $WORLD "save-all"
|
|
sendCommand $WORLD "save-off"
|
|
if [ "$(echo \"$1\" | cut -d '-' -f1)" = "force" ]; then
|
|
forceStop $WORLD
|
|
else
|
|
stop $WORLD
|
|
fi
|
|
sleep 5
|
|
fi
|
|
start $WORLD
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
create|new)
|
|
if [ -n "$2" ]; then
|
|
if [ -z "$3" ]; then
|
|
printf "A name and port for the new world must be supplied.\n"
|
|
printf "An IP address is optional and usually not needed.\n"
|
|
printf " Usage: $PROG create <world> <port> [<ip>]\n"
|
|
exit 1
|
|
else
|
|
printf "Creating Minecraft world: $2"
|
|
createWorld "$2" "$3" "$4"
|
|
printf ".\n"
|
|
fi
|
|
elif [ -z "$(getAvailableWorlds)" ]; then
|
|
printf 'Creating default world "%s" at default port %s' \
|
|
$DEFAULT_WORLD $DEFAULT_PORT
|
|
createWorld "$DEFAULT_WORLD" "$DEFAULT_PORT"
|
|
printf ".\n"
|
|
fi
|
|
;;
|
|
delete|remove)
|
|
# Get list of enabled worlds.
|
|
if ! isWorldAvailable "$2"; then
|
|
printf "World not found, unable to delete world '$2'.\n"
|
|
exit 1
|
|
fi
|
|
printf "Deleting Minecraft world: $2"
|
|
if serverRunning "$2"; then
|
|
# If the world server has users logged in, announce that the world is
|
|
# being deleted.
|
|
if [ $(queryNumUsers "$2") -gt 0 ]; then
|
|
sendCommand "$2" "say The server admin is deleting this world."
|
|
sendCommand "$2" "say The server will be deleted in 1 minute..."
|
|
sleep 60
|
|
sendCommand "$2" "say The server is now shutting down."
|
|
fi
|
|
# Stop the world server.
|
|
stop "$2"
|
|
sleep 5
|
|
fi
|
|
# Delete the world.
|
|
deleteWorld "$2"
|
|
printf ".\n"
|
|
;;
|
|
disable)
|
|
# Get list of enabled worlds.
|
|
if ! isWorldEnabled "$2"; then
|
|
printf "World not found, unable to disable world '$2'.\n"
|
|
exit 1
|
|
fi
|
|
printf "Disabling Minecraft world: $2"
|
|
if serverRunning "$2"; then
|
|
# If the world server has users logged in, announce that the world is
|
|
# being disabled.
|
|
if [ $(queryNumUsers "$2") -gt 0 ]; then
|
|
sendCommand "$2" "say The server admin is disabling this world."
|
|
sendCommand "$2" "say The server will be disabled in 1 minute..."
|
|
sleep 60
|
|
sendCommand "$2" "say The server is now shutting down."
|
|
fi
|
|
# Stop the world server.
|
|
stop "$2"
|
|
sleep 5
|
|
fi
|
|
# Disable the world.
|
|
disableWorld "$2"
|
|
printf ".\n"
|
|
;;
|
|
enable)
|
|
# Get list of disabled worlds.
|
|
if ! isWorldAvailable "$2"; then
|
|
printf "World not found, unable to enable world '$2'.\n"
|
|
exit 1
|
|
elif isWorldEnabled "$2"; then
|
|
printf "Unable to enable already enabled world '$2'.\n"
|
|
exit 1
|
|
fi
|
|
printf "Enabling Minecraft world: $2"
|
|
# Enable the world.
|
|
enableWorld "$2"
|
|
# Start the world.
|
|
start "$2"
|
|
printf ".\n"
|
|
;;
|
|
ls|list)
|
|
# Grab the desired list of worlds.
|
|
WORLDS=""
|
|
case "$2" in
|
|
enabled)
|
|
WORLDS=$(getEnabledWorlds)
|
|
;;
|
|
disabled)
|
|
WORLDS=$(getDisabledWorlds)
|
|
;;
|
|
running)
|
|
for WORLD in $(getEnabledWorlds); do
|
|
if serverRunning $WORLD; then
|
|
WORLDS="$WORLDS $WORLD"
|
|
fi
|
|
done
|
|
;;
|
|
stopped)
|
|
for WORLD in $(getEnabledWorlds); do
|
|
if ! serverRunning $WORLD; then
|
|
WORLDS="$WORLDS $WORLD"
|
|
fi
|
|
done
|
|
;;
|
|
"")
|
|
WORLDS=$(getAvailableWorlds)
|
|
;;
|
|
*)
|
|
echo "Unknown list option: $2."
|
|
echo " Try '$PROG help' for help."
|
|
exit 1
|
|
;;
|
|
esac
|
|
case "$1" in
|
|
ls)
|
|
# Simple list
|
|
for WORLD in $WORLDS; do
|
|
WPORT=$(getServerPropertiesValue "$WORLD" server-port "")
|
|
printf " $WORLD: $WPORT"
|
|
if isWorldEnabled "$WORLD"; then
|
|
printf '\n'
|
|
else
|
|
printf ' (disabled)\n'
|
|
fi
|
|
done
|
|
;;
|
|
list)
|
|
# Detailed list
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD:"
|
|
if isWorldEnabled "$WORLD"; then
|
|
printf '\n'
|
|
else
|
|
printf ' (disabled)\n'
|
|
fi
|
|
for PROP in $DETAILED_LISTING_PROPERTIES; do
|
|
printf " $PROP="
|
|
getServerPropertiesValue "$WORLD" "$PROP" ""
|
|
done
|
|
done
|
|
;;
|
|
esac
|
|
;;
|
|
status|show)
|
|
# Figure out which worlds to show the status for.
|
|
if isWorldAvailable "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' not recognized.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getAvailableWorlds)
|
|
fi
|
|
# Show the status of each world requested.
|
|
printf "Minecraft Server Status:\n"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD: "
|
|
worldStatus $WORLD
|
|
done
|
|
;;
|
|
sync|synchronize)
|
|
# Figure out which worlds to synchronize.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' not recognized.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Synchronize the images for each world.
|
|
printf "Synchronizing Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
if serverRunning $WORLD; then
|
|
printf " $WORLD"
|
|
sendCommand $WORLD "save-all"
|
|
if [ $ENABLE_MIRROR -eq 1 ]; then
|
|
sendCommand $WORLD "save-off"
|
|
sleep 20
|
|
syncMirrorImage $WORLD
|
|
sendCommand $WORLD "save-on"
|
|
fi
|
|
fi
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
broadcast)
|
|
# Get list of enabled worlds.
|
|
WORLDS=$(getEnabledWorlds)
|
|
if [ -n "$2" ]; then
|
|
# Remove broadcast from the command line arguments.
|
|
shift 1
|
|
# Broadcast the message to all of the enabled worlds.
|
|
printf "Broadcasting command to world:"
|
|
for WORLD in $WORLDS; do
|
|
if serverRunning $WORLD; then
|
|
printf " $WORLD"
|
|
sendCommand $WORLD "$*"
|
|
fi
|
|
done
|
|
printf ".\n"
|
|
else
|
|
printf "Usage: $PROG $1 <command>\n"
|
|
printf " ie: $PROG $1 say Hello World!\n"
|
|
exit 1
|
|
fi
|
|
;;
|
|
send)
|
|
# Check for the world command line argument.
|
|
if isWorldEnabled "$2" && [ -n "$3" ]; then
|
|
WORLD=$2
|
|
shift 2
|
|
printf "Sending command to world: $WORLD - '$*'.\n"
|
|
sendCommand $WORLD "$*"
|
|
else
|
|
printf "Usage: $PROG $1 <world> <command>\n"
|
|
printf " ie: $PROG $1 world say Hello World!\n"
|
|
exit 1
|
|
fi
|
|
;;
|
|
console)
|
|
# Check for the world command line argument.
|
|
if isWorldEnabled "$2"; then
|
|
printf "Connecting to server console: $2.\n"
|
|
printf " Hit <Ctrl-D> to detach.\n"
|
|
sleep 3
|
|
serverConsole $2
|
|
else
|
|
if [ -n "$2" ]; then
|
|
printf "Minecraft world $2 not found!\n"
|
|
else
|
|
printf "Minecraft world not provided!\n"
|
|
fi
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
fi
|
|
;;
|
|
watch)
|
|
# Check for the world command line argument.
|
|
if isWorldEnabled "$2"; then
|
|
printf "Monitoring Minecraft Server: $2.\n"
|
|
watchLog $2
|
|
else
|
|
if [ -n "$2" ]; then
|
|
printf "Minecraft world $2 not found!\n"
|
|
else
|
|
printf "Minecraft world not provided!\n"
|
|
fi
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
fi
|
|
;;
|
|
logrotate)
|
|
# Figure out which worlds to rotate the log.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' does not exist or not enabled.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Backup each world requested.
|
|
printf "Rotating Minecraft Server Log:"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD"
|
|
rotateLog $WORLD
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
backup)
|
|
# Figure out which worlds to backup.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' does not exist or not enabled.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Backup each world requested.
|
|
printf "Backing up Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD"
|
|
if serverRunning $WORLD; then
|
|
sendCommand $WORLD "say Backing up the world."
|
|
sendCommand $WORLD "save-all"
|
|
sendCommand $WORLD "save-off"
|
|
sleep 20
|
|
worldBackup $WORLD
|
|
sendCommand $WORLD "save-on"
|
|
sendCommand $WORLD "say Backup complete."
|
|
else
|
|
worldBackup $WORLD
|
|
fi
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
list-backups)
|
|
if isWorldEnabled "$2"; then
|
|
worldBackupList "$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' does not exist or not enabled.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
printf "World not supplied.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
fi
|
|
;;
|
|
restore-backup)
|
|
if [ -z $2 ]; then
|
|
printf "World not supplied.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
elif ! isWorldAvailable "$2"; then
|
|
printf "World '$2' not recognized.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
elif serverRunning "$2"; then
|
|
printf "World '$2' is running. Stop it first\n"
|
|
printf " $PROG stop $2\n"
|
|
exit 1
|
|
elif worldBackup "$2"; then
|
|
worldBackupRestore "$2" "$3"
|
|
else
|
|
echo "Current world's state backup failed. Restore cancelled."
|
|
exit 1
|
|
fi
|
|
;;
|
|
update)
|
|
# Figure out which worlds to update.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' does not exist or not enabled.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Stop all of the world servers and backup the worlds.
|
|
RUNNING=
|
|
printf "Stopping Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
if serverRunning $WORLD; then
|
|
RUNNING="$RUNNING $WORLD"
|
|
printf " $WORLD"
|
|
if [ $(queryNumUsers $WORLD) -gt 0 ]; then
|
|
sendCommand $WORLD "say The server admin has initiated a software update."
|
|
sendCommand $WORLD "say The server will restart and update in 1 minute..."
|
|
sleep 60
|
|
sendCommand $WORLD "say The server is now restarting."
|
|
fi
|
|
sendCommand $WORLD "save-all"
|
|
sendCommand $WORLD "save-off"
|
|
stop $WORLD
|
|
fi
|
|
done
|
|
printf ".\n"
|
|
printf "Backing up Minecraft Server:"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD"
|
|
worldBackup $WORLD
|
|
done
|
|
printf ".\n"
|
|
# Update the server software.
|
|
printf "Updating Server Software:"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD"
|
|
updateServerSoftware "$WORLD"
|
|
done
|
|
printf ".\n"
|
|
printf "Restarting Minecraft Server:"
|
|
for WORLD in $RUNNING; do
|
|
printf " $WORLD"
|
|
start $WORLD
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
map|overviewer)
|
|
# Make sure that the Minecraft Overviewer software exists.
|
|
if [ ! -e "$OVERVIEWER_BIN" ]; then
|
|
printf "Minecraft Overviewer software not found.\n"
|
|
exit 1
|
|
fi
|
|
# Figure out which worlds to map.
|
|
if isWorldEnabled "$2"; then
|
|
WORLDS="$2"
|
|
elif [ -n "$2" ]; then
|
|
printf "World '$2' does not exist or not enabled.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
else
|
|
WORLDS=$(getEnabledWorlds)
|
|
fi
|
|
# Run Minecraft Overviewer on each world requested.
|
|
printf "Running Minecraft Overviewer mapping:"
|
|
for WORLD in $WORLDS; do
|
|
printf " $WORLD"
|
|
overviewer "$WORLD"
|
|
done
|
|
printf ".\n"
|
|
;;
|
|
query|query-raw|query-json)
|
|
# Make sure there is a world to query.
|
|
if [ ! -n "$2" ]; then
|
|
printf "World not provided.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
fi
|
|
if ! isWorldEnabled "$2"; then
|
|
printf "World '$2' does not exist or not enabled.\n"
|
|
printf " Usage: $PROG $1 <world>\n"
|
|
exit 1
|
|
fi
|
|
case "$1" in
|
|
query|query-raw)
|
|
queryDetailedStatus "$2"
|
|
;;
|
|
query-json)
|
|
queryDetailedStatusJSON "$2"
|
|
;;
|
|
esac
|
|
;;
|
|
usage|help)
|
|
printf "Minecraft Server Control Script\n"
|
|
printf "\n"
|
|
usage
|
|
;;
|
|
*)
|
|
printf "Error in command line usage.\n"
|
|
printf "\n"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
exit 0
|