mscs/msctl

2560 lines
88 KiB
Plaintext
Raw Normal View History

2013-06-25 21:04:02 -07:00
#!/bin/sh
2013-06-24 14:30:46 -07:00
# ---------------------------------------------------------------------------
2016-02-09 23:35:10 -07:00
# Copyright (c) 2011-2016, Jason M. Wood <sandain@hotmail.com>
2013-06-24 14:30:46 -07:00
#
# 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.
# ---------------------------------------------------------------------------
2013-06-24 13:11:34 -07:00
# ---------------------------------------------------------------------------
# Minecraft Server Control Script
2013-06-24 11:26:09 -07:00
#
2013-06-24 13:11:34 -07:00
# A powerful command-line control script for Linux-powered Minecraft servers.
# ---------------------------------------------------------------------------
2015-08-11 05:55:59 -07:00
# Get executable name
# ---------------------------------------------------------------------------
PROG=$(basename $0)
2013-06-24 13:20:10 -07:00
2016-05-29 18:01:41 -07:00
# 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)
2013-06-24 13:20:10 -07:00
# Script Usage
# ---------------------------------------------------------------------------
usage() {
cat <<EOF
2015-08-11 16:47:13 -07:00
Usage: $PROG [<options>] <action>
2013-06-24 13:11:34 -07:00
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.
2015-08-11 06:41:09 -07:00
create <world> <port> [<ip>]
Create a Minecraft world server. The world name and port must be
2015-08-11 06:41:09 -07:00
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>
2013-12-03 14:55:54 -07:00
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.
2015-07-10 02:09:49 -07:00
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.
2014-12-20 23:21:58 -07:00
broadcast <command>
Broadcast a command to all running Minecraft world servers.
send <world> <command>
Send a command to a Minecraft world server.
2014-02-06 15:47:52 -07:00
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>
2014-01-03 20:45:41 -07:00
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.
2016-03-05 11:23:41 -07:00
query <world>
Run a detailed Query on the Minecraft world server.
Options:
-c <config_file>
Read configuration from <config_files> instead of default locations.
2015-08-11 09:41:15 -07:00
-l <location>
Uses <location> as the base path for data. Overrides configuration file
options.
2013-06-24 13:11:34 -07:00
EOF
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# 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
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# Get the amount of memory used by the Java process for the world server.
#
# @param 1 The world server of interest.
# @return The amount of memory used.
# ---------------------------------------------------------------------------
getJavaMemory() {
local PID
PID=$(getJavaPID "$1")
ps -h -p $PID -o rss
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# 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.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
serverRunning() {
2013-08-04 09:09:40 -07:00
# Try to determine if the world is running.
2013-12-07 12:09:36 -07:00
if [ $(getJavaPID "$1") -gt 0 ]; then
return 0
2013-08-04 09:09:40 -07:00
else
return 1
2013-08-04 09:09:40 -07:00
fi
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Send a command to the world server.
#
# @param 1 The world server of interest.
# @param 2 The command to send.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
sendCommand() {
2014-09-16 12:53:16 -07:00
echo "$2" | $PERL -e '
2014-09-16 11:47:36 -07:00
while (<>) { $_ =~ s/[\r\n]+//g; $cmd .= $_; } print "$cmd\r";
2014-09-16 12:53:16 -07:00
' >> $WORLDS_LOCATION/$1/console.in
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# 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.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
listContains() {
2013-08-04 09:09:40 -07:00
local MATCH ITEM
MATCH=1
2013-08-04 09:09:40 -07:00
for ITEM in $2; do
if [ "$ITEM" = "$1" ]; then
MATCH=0
2013-08-04 09:09:40 -07:00
fi
done
return $MATCH
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# 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"
}
2013-10-19 09:57:29 -07:00
# ---------------------------------------------------------------------------
# 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.
2015-08-10 04:09:38 -07:00
mkdir -p "$WORLDS_LOCATION/$1"
2015-07-09 14:39:03 -07:00
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"
2013-10-19 09:57:29 -07:00
}
2013-10-19 10:15:16 -07:00
# ---------------------------------------------------------------------------
# Delete a world.
#
# @param 1 The world server to delete.
# ---------------------------------------------------------------------------
deleteWorld() {
# Delete the world directory.
2015-08-10 04:09:38 -07:00
rm -Rf "$WORLDS_LOCATION/$1"
2013-10-19 10:15:16 -07:00
}
2013-10-19 10:47:23 -07:00
# ---------------------------------------------------------------------------
# Disable a world.
#
# @param 1 The world server to disable.
# ---------------------------------------------------------------------------
disableWorld() {
# Disable the world.
2015-07-09 14:39:03 -07:00
setMSCSValue "$1" "mscs-enabled" "false"
2013-10-19 10:47:23 -07:00
}
2013-10-19 10:57:04 -07:00
# ---------------------------------------------------------------------------
# Enable a world.
#
# @param 1 The world server to enable.
# ---------------------------------------------------------------------------
enableWorld() {
# Enable the world.
2015-07-09 14:39:03 -07:00
setMSCSValue "$1" "mscs-enabled" "true"
2013-10-19 10:57:04 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-12-03 14:49:45 -07:00
# Grab the list of enabled worlds.
2013-06-24 11:26:09 -07:00
#
# @return The list of enabled worlds.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-12-03 14:49:45 -07:00
getEnabledWorlds() {
local WORLD WORLDS
2015-08-10 04:09:38 -07:00
mkdir -p "$WORLDS_LOCATION"
WORLDS=""
for WORLD in $(ls $WORLDS_LOCATION); do
2015-07-09 14:35:29 -07:00
if [ -d $WORLDS_LOCATION/$WORLD ]; then
2015-07-09 14:39:03 -07:00
if [ "$(getMSCSValue $WORLD 'mscs-enabled' 'true')" = "true" ]; then
2015-07-09 14:35:29 -07:00
WORLDS="$WORLDS $WORLD"
fi
fi
done
2013-08-04 09:09:40 -07:00
echo $WORLDS
2013-06-24 11:26:09 -07:00
}
2013-12-03 14:51:57 -07:00
# ---------------------------------------------------------------------------
# Grab the list of disabled worlds.
#
# @return The list of disabled worlds.
2013-12-03 14:51:57 -07:00
# ---------------------------------------------------------------------------
getDisabledWorlds() {
local WORLD WORLDS
WORLDS=""
2015-07-09 14:35:29 -07:00
for WORLD in $(ls $WORLDS_LOCATION); do
if [ -d $WORLDS_LOCATION/$WORLD ]; then
if [ "$(getMSCSValue $WORLD 'mscs-enabled' 'true')" != "true" ]; then
2015-07-09 14:35:29 -07:00
WORLDS="$WORLDS $WORLD"
fi
2013-12-03 14:51:57 -07:00
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 '
2016-06-19 13:03:51 -07:00
# Remove single and double quotes plus CR and LF.
$_ =~ s/[\x22\x27\r\n]//g;
# Remove comments.
$_ =~ s/^\s*\x23.*//;
# Extract the key.
if ($_ =~ /^\s*('$2')\s*=\s*.*$/i) { print lc $1; }
' $1)
VALUE=$($PERL -ne '
2016-06-19 13:03:51 -07:00
# Remove single and double quotes plus CR and LF.
$_ =~ s/[\x22\x27\r\n]//g;
# Remove comments.
$_ =~ s/^\s*\x23.*//;
# Extract the value.
if ($_ =~ /^\s*'$2'\s*=\s*(.*)$/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"
2013-08-04 09:09:40 -07:00
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.
2015-08-10 04:09:38 -07:00
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
2015-08-10 04:09:38 -07:00
printf "$2=$3\n" >> "$1"
fi
}
2016-05-30 19:15:55 -07:00
# ---------------------------------------------------------------------------
# Get the value of a key in the mscs.defaults file.
#
# @param 1 The key to get.
# @param 2 The default value.
# ---------------------------------------------------------------------------
getDefaultsValue() {
getValue "$MSCS_DEFAULTS" "$1" "$2"
}
# ---------------------------------------------------------------------------
# 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
2015-08-27 16:45:27 -07:00
getValue "$EULA_FILE" "eula" "true" | $PERL -ne 'print lc'
}
# ---------------------------------------------------------------------------
2015-07-09 14:39:03 -07:00
# 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.
# ---------------------------------------------------------------------------
2015-07-09 14:39:03 -07:00
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
2015-07-10 00:34:41 -07:00
PROPERTY_FILE="$WORLDS_LOCATION/$1/server.properties"
getValue "$PROPERTY_FILE" "$2" "$3"
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2015-07-09 14:39:03 -07:00
# Modify the value of a key/value combo in a server.properties file.
2013-06-24 11:26:09 -07:00
#
# @param 1 The world server of interest.
2013-06-24 11:26:09 -07:00
# @param 2 The key to modify.
# @param 3 The value to assign to the key.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2015-07-09 14:39:03 -07:00
setServerPropertiesValue() {
local PROPERTY_FILE
PROPERTY_FILE=$WORLDS_LOCATION/$1/server.properties
setValue "$PROPERTY_FILE" "$2" "$3"
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# 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.
2015-08-10 04:09:38 -07:00
mkdir -p "$DEFAULT_SERVER_LOCATION"
# Determine the version type for the current world.
2015-07-09 14:39:03 -07:00
TYPE=$(getMSCSValue "$1" "mscs-version-type" "$DEFAULT_VERSION_TYPE")
if [ -s $VERSIONS_JSON ]; then
# Make a backup copy of the version_manifest.json file.
2015-08-10 04:09:38 -07:00
cp -p "$VERSIONS_JSON" "$VERSIONS_JSON.bak"
# Delete the version_manifest.json file if it is old.
2015-08-10 04:09:38 -07:00
find "$VERSIONS_JSON" -mmin +"$VERSIONS_DURATION" -delete
fi
# Download the version_manifest.json file if it does not exist.
if [ ! -s $VERSIONS_JSON ]; then
2015-08-10 04:09:38 -07:00
$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 version_manifest.json file, using an old copy.\n"
2015-08-10 04:09:38 -07:00
cp -p "$VERSIONS_JSON.bak" "$VERSIONS_JSON"
else
printf "Error downloading the Minecraft version_manifest.json file.\n"
exit 1
fi
fi
fi
# Extract the current version information.
VERSION=$($PERL -0777ne '
use JSON;
$json = decode_json ($_);
print $json->{latest}{'$TYPE'};
' $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() {
$PERL -0777ne '
use JSON;
$json = decode_json ($_);
foreach $ver (@{$json->{versions}}) {
print $ver->{releaseTime} if ($ver->{id} eq "'$1'");
}
' $VERSIONS_JSON
}
# ---------------------------------------------------------------------------
# Retrieve the version of the client for the world.
#
# @param 1 The world server.
# @return CLIENT_VERSION
# ---------------------------------------------------------------------------
getClientVersion() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the client version, use the default version if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-client-version" "$DEFAULT_CLIENT_VERSION" |
2014-11-06 14:49:59 -07:00
$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() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION CLIENT_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
CLIENT_VERSION=$(getClientVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CLIENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the client jar, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-client-jar" "$DEFAULT_CLIENT_JAR" |
2014-11-06 14:49:59 -07:00
$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() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION CLIENT_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
CLIENT_VERSION=$(getClientVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CLIENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the client location, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-client-location" "$DEFAULT_CLIENT_LOCATION" |
2014-11-06 14:49:59 -07:00
$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() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION CLIENT_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
CLIENT_VERSION=$(getClientVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CLIENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the client download URL, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-client-url" "$DEFAULT_CLIENT_URL" |
2014-11-06 14:49:59 -07:00
$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() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the server version, use the default version if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-server-version" "$DEFAULT_SERVER_VERSION" |
2014-11-06 14:49:59 -07:00
$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() {
2014-06-19 11:35:46 -07:00
local CURRENT_VERSION SERVER_VERSION SERVER_JAR
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_VERSION=$(getServerVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the server jar, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-server-jar" "$DEFAULT_SERVER_JAR" |
2014-11-06 14:49:59 -07:00
$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() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION SERVER_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_VERSION=$(getServerVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the server location, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-server-location" "$DEFAULT_SERVER_LOCATION" |
2014-11-06 14:49:59 -07:00
$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() {
2014-11-06 14:49:59 -07:00
local CURRENT_VERSION SERVER_VERSION
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_VERSION=$(getServerVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Get the server download URL, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-server-url" "$DEFAULT_SERVER_URL" |
2014-11-06 14:49:59 -07:00
$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() {
2014-06-19 11:35:46 -07:00
local CURRENT_VERSION SERVER_VERSION SERVER_JAR SERVER_LOCATION
2014-11-06 14:49:59 -07:00
local SERVER_ARGS INITIAL_MEMORY MAXIMUM_MEMORY
2014-06-19 11:35:46 -07:00
CURRENT_VERSION=$(getCurrentMinecraftVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CURRENT_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_VERSION=$(getServerVersion "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_VERSION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_JAR=$(getServerJar "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_JAR\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_LOCATION=$(getServerLocation "$1")
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_LOCATION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
2013-11-03 19:11:49 -07:00
# Get the server arguments, use the default value if not provided.
SERVER_ARGS=$(
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-server-args" "$DEFAULT_SERVER_ARGS"
)
# Get the initial memory, use the default value if not provided.
INITIAL_MEMORY=$(
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-initial-memory" "$DEFAULT_INITIAL_MEMORY"
)
# Get the maximum memory, use the default value if not provided.
MAXIMUM_MEMORY=$(
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-maximum-memory" "$DEFAULT_MAXIMUM_MEMORY"
)
# Get the server command, use the default value if not provided.
2015-07-09 14:39:03 -07:00
getMSCSValue "$1" "mscs-server-command" "$DEFAULT_SERVER_COMMAND" |
2014-11-06 14:49:59 -07:00
$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;
'
}
# ---------------------------------------------------------------------------
# Create a lock file for a world. This will help avoid having multiple long
# running processes running at the same time. This code was inspired by
# http://bencane.com/2015/09/22/preventing-duplicate-cron-job-executions/
#
# @param 1 The world server.
# @param 2 The type of lock file.
# @return TRUE if lock file created, FALSE otherwise.
# ---------------------------------------------------------------------------
createLockFile() {
local PID LOCKFILE
LOCKFILE=$WORLDS_LOCATION/$1/lock-$2.pid
# Delete the old LOCKFILE.
find $LOCKFILE -mmin +"$LOCKFILE_DURATION" -delete > /dev/null 2>&1
# Check to see if the LOCKFILE exists.
if [ -s $LOCKFILE ]; then
PID=$(cat $LOCKFILE)
# LOCKFILE exists, check to see if its process is running.
ps -p $PID > /dev/null 2>&1
if [ $? -eq 0 ]; then
# LOCKFILE exists and the process is running, return FALSE.
return 1
else
# Process not found assume it is not running.
echo $$ > $LOCKFILE
if [ $? -ne 0 ]; then
# Error creating LOCKFILE, return FALSE.
return 1
fi
fi
else
# LOCKFILE does not exists.
echo $$ > $LOCKFILE
if [ $? -ne 0 ]; then
# Error creating LOCKFILE, return FALSE.
return 1
fi
fi
# Success creating LOCKFILE, return TRUE.
return 0
}
# ---------------------------------------------------------------------------
# Remove a lock file for a world.
#
# @param 1 The world server.
# @param 2 The type of lock file.
# ---------------------------------------------------------------------------
removeLockFile() {
rm -f $WORLDS_LOCATION/$1/lock-$2.pid
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Remove old world log files and rotate log files from old servers (v < 1.7).
2013-06-24 11:26:09 -07:00
#
# @param 1 The world server generating the log to rotate.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
rotateLog() {
local WORLD_DIR DATE LOG NUMBER
2013-08-04 09:09:40 -07:00
WORLD_DIR="$WORLDS_LOCATION/$1"
# Make sure the log directory exists.
2015-08-10 04:09:38 -07:00
mkdir -p "$WORLD_DIR/logs"
# Delete old log files.
2015-08-10 04:09:38 -07:00
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).
2015-08-10 04:09:38 -07:00
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)
2015-08-10 04:09:38 -07:00
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.
2015-08-10 04:09:38 -07:00
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))
2015-08-10 04:09:38 -07:00
mv -f $LOG "$WORLD_DIR/logs/$DATE-$NUMBER.log.gz"
done
2013-08-04 09:09:40 -07:00
fi
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Watch the world latest.log file.
2013-06-24 11:26:09 -07:00
#
# @param 1 The world server generating the log to watch.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
watchLog() {
2013-12-07 12:09:36 -07:00
local WORLD_DIR
2013-08-04 09:09:40 -07:00
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 +.
2013-12-07 12:09:36 -07:00
tail -n0 -f --pid=$(getJavaPID "$1") $WORLD_DIR/logs/latest.log
2015-12-29 17:23:55 -07:00
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
2013-08-04 09:09:40 -07:00
fi
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Synchronizes the data stored in the mirror images.
#
# @param 1 The world server to sync.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
syncMirrorImage() {
2013-08-04 09:09:40 -07:00
# Sync the world server.
cp -Ru "$WORLDS_LOCATION/$1/$1/"* "$WORLDS_LOCATION/$1/$1-original"
2013-08-04 09:09:40 -07:00
if [ $? -ne 0 ]; then
printf "Error synchronizing mirror images for world $1.\n"
exit 1
fi
2013-06-24 11:26:09 -07:00
}
2014-02-06 15:47:52 -07:00
# ---------------------------------------------------------------------------
# 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.
tail -f --pid=$$ $WORLD_DIR/console.out &
2014-02-06 15:47:52 -07:00
# Copy user input to the console input buffer file.
while read LINE; do
echo "$LINE" >> $WORLD_DIR/console.in
done
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Start the world server. Generate the appropriate environment for the
# server if it doesn't already exist.
2013-06-24 11:26:09 -07:00
#
# @param 1 The world server to start.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
start() {
local EULA PID SERVER_COMMAND WORLD_DIR
# Make sure that the server software exists.
updateServerSoftware "$1"
2013-08-04 09:09:40 -07:00
# Make sure that the world's directory exists.
WORLD_DIR="$WORLDS_LOCATION/$1"
2015-08-10 04:09:38 -07:00
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"
2013-08-04 09:09:40 -07:00
# Make a mirror image of the world directory if requested.
2013-08-04 10:33:58 -07:00
if [ $ENABLE_MIRROR -eq 1 ]; then
2015-08-10 04:09:38 -07:00
mkdir -p "$MIRROR_PATH/$1"
2013-08-04 10:33:58 -07:00
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
2013-08-04 10:33:58 -07:00
# Remove the symlink to the world-file mirror image.
# if recently restored from backup, this symlink may or may not exist
if [ -L "$WORLDS_LOCATION/$1/$1" ]; then
rm -r "$WORLDS_LOCATION/$1/$1"
fi
2013-08-04 10:33:58 -07:00
# Move the world files back to their original path name.
2015-08-10 04:09:38 -07:00
mv "$WORLDS_LOCATION/$1/$1-original" "$WORLDS_LOCATION/$1/$1"
2013-08-04 10:33:58 -07:00
fi
# Copy the world files over to the mirror.
cp -R "$WORLDS_LOCATION/$1/$1/"* "$MIRROR_PATH/$1"
2013-08-04 10:33:58 -07:00
# Rename the original world file directory.
2015-08-10 04:09:38 -07:00
mv "$WORLDS_LOCATION/$1/$1" "$WORLDS_LOCATION/$1/$1-original"
2013-08-04 10:33:58 -07:00
# Create a symlink from the world file directory's original name to the mirrored files.
ln -s "$MIRROR_PATH/$1/" "$WORLDS_LOCATION/$1/$1"
2013-08-04 09:09:40 -07:00
fi
# Change to the world's directory.
cd $WORLD_DIR
2014-02-06 15:47:52 -07:00
# Delete any old console.in or console.out buffer files.
2015-08-10 04:09:38 -07:00
rm -f "$WORLD_DIR/console.in" "$WORLD_DIR/console.out"
# Initialize the console.in buffer file.
2015-08-10 04:09:38 -07:00
printf '' > $WORLD_DIR/console.in
# Get the server command for this world.
SERVER_COMMAND=$(getServerCommand "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_COMMAND\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
2013-08-04 09:09:40 -07:00
# Start the server.
sh -c "tail -f --pid=\$$ $WORLD_DIR/console.in | {
$SERVER_COMMAND mscs-world=$1 > $WORLD_DIR/console.out 2>&1; kill \$$;
}" &
2013-12-07 10:53:59 -07:00
# Verify the server is running.
2013-08-04 09:09:40 -07:00
if [ $? -ne 0 ]; then
printf "Error starting the server.\n"
exit 1
fi
sleep 1
PID=$(getJavaPID "$1")
if [ $PID -eq 0 ]; then
2013-08-04 09:09:40 -07:00
printf "Error starting the server: couldn't retrieve the server's process ID.\n"
exit 1
fi
# Start the Query handler if enabled.
2015-07-09 14:39:03 -07:00
if [ "$(getServerPropertiesValue $1 'enable-query')" = "true" ]; then
queryStart "$1" &
fi
# Create a PID file for the world server.
2015-08-10 04:09:38 -07:00
echo $PID > "$WORLDS_LOCATION/$1.pid"
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Stop the world server.
#
# @param 1 The world server to stop.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
stop() {
2013-08-04 09:09:40 -07:00
local WORLD NUM
sendCommand $1 "stop"
sendCommand $1 "end"
2013-08-04 09:09:40 -07:00
# Synchronize the mirror image of the world prior to closing, if
# required.
if [ $ENABLE_MIRROR -eq 1 ] && [ -d $MIRROR_PATH ]; then
syncMirrorImage $1
2013-08-04 10:33:58 -07:00
# Remove the symlink to the world-file mirror image.
2015-08-10 04:09:38 -07:00
rm -r "$WORLDS_LOCATION/$1/$1"
2013-08-04 10:33:58 -07:00
# Move the world files back to their original path name.
2015-08-10 04:09:38 -07:00
mv "$WORLDS_LOCATION/$1/$1-original" "$WORLDS_LOCATION/$1/$1"
2013-08-04 09:09:40 -07:00
fi
# Remove the PID file for the world server.
2015-08-10 04:09:38 -07:00
rm -f "$WORLDS_LOCATION/$1.pid"
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Forcibly stop the world server.
#
# @param 1 The world server to forcibly stop.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
forceStop() {
2013-08-04 09:09:40 -07:00
# Try to stop the server cleanly first.
stop "$1"
2013-08-04 09:09:40 -07:00
sleep 5
# Kill the process id of the world server.
kill -9 $(getJavaPID "$1") > /dev/null 2>&1
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Backup the world server.
#
# @param 1 The world server to backup.
2015-08-01 14:36:55 -07:00
# @return A 0 if backup successful, a 1 otherwise
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
worldBackup() {
local EXCLUDE_OPTION
2013-08-04 09:09:40 -07:00
# Make sure that the backup location exists.
2015-08-10 04:09:38 -07:00
if ! mkdir -p "$BACKUP_LOCATION"; then
2015-08-01 14:36:55 -07:00
echo "Error creating backup dir $BACKUP_LOCATION"
return 1
fi
# Synchronize the mirror image of the world prior to closing, if
# required.
if [ $ENABLE_MIRROR -eq 1 ] && [ -d $MIRROR_PATH ]; then
syncMirrorImage $1
fi
# Determine if we need to exclude the mirrored symlink or not
if [ -L "$WORLDS_LOCATION/$1/$1" ]; then
EXCLUDE_OPTION="--exclude $WORLDS_LOCATION/$1/$1"
fi
2013-08-04 09:09:40 -07:00
# Create the backup.
if ! $RDIFF_BACKUP -v5 --print-statistics $EXCLUDE_OPTION "$WORLDS_LOCATION/$1" "$BACKUP_LOCATION/$1" >> "$BACKUP_LOG"; then
2015-08-01 14:36:55 -07:00
echo "Error doing backup of world $1"
return 1
fi
2013-08-04 09:09:40 -07:00
# Cleanup old backups.
if [ $BACKUP_DURATION -gt 0 ]; then
2015-08-10 04:09:38 -07:00
if ! $RDIFF_BACKUP --remove-older-than ${BACKUP_DURATION}D --force "$BACKUP_LOCATION/$1" >> "$BACKUP_LOG"; then
2015-08-01 14:36:55 -07:00
echo "Error cleaning old backups of world $1"
return 1
fi
2013-08-04 09:09:40 -07:00
fi
2015-08-01 14:36:55 -07:00
return 0
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# 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"
2015-08-10 04:09:38 -07:00
rm -rf "$TARGET_TMP"
if [ -d $BACKUP_LOCATION/$1 ]; then
2015-08-10 04:09:38 -07:00
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"
2015-08-10 04:09:38 -07:00
rm -rf "$TARGET_TMP"
return 1
fi
else
echo "No backups found for world $1"
return 1
fi
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Update the Minecraft client software.
#
# @param 1 The world to update.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
updateClientSoftware() {
local CLIENT_JAR CLIENT_LOCATION CLIENT_URL
CLIENT_JAR=$(getClientJar "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CLIENT_JAR\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
CLIENT_LOCATION=$(getClientLocation "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CLIENT_LOCATION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
CLIENT_URL=$(getClientURL "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$CLIENT_URL\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
2013-08-04 09:09:40 -07:00
# Make sure the client software directory exists.
2015-08-10 04:09:38 -07:00
mkdir -p "$CLIENT_LOCATION"
# Download the client jar if it is missing.
if [ ! -s "$CLIENT_LOCATION/$CLIENT_JAR" ]; then
# Download the Minecraft client software.
2015-08-10 04:09:38 -07:00
$WGET -qO "$CLIENT_LOCATION/$CLIENT_JAR" "$CLIENT_URL"
# Report any errors.
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "Error updating the Minecraft client software.\n"
exit 1
2013-08-04 09:09:40 -07:00
fi
fi
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Update the Minecraft server software.
#
# @param 1 The world server to update.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
updateServerSoftware() {
local SERVER_JAR SERVER_LOCATION SERVER_URL
SERVER_JAR=$(getServerJar "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_JAR\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_LOCATION=$(getServerLocation "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_LOCATION\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
SERVER_URL=$(getServerURL "$1")
2014-06-19 11:35:46 -07:00
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "$SERVER_URL\n"
2014-06-19 11:35:46 -07:00
exit 1
fi
# Make sure the server software directory exists.
2015-08-10 04:09:38 -07:00
mkdir -p "$SERVER_LOCATION"
# Download the server jar if it is missing.
if [ ! -s "$SERVER_LOCATION/$SERVER_JAR" ]; then
# Download the Minecraft server software.
2015-08-10 04:09:38 -07:00
$WGET -qO "$SERVER_LOCATION/$SERVER_JAR" "$SERVER_URL"
# Report any errors.
if [ $? -ne 0 ]; then
2014-06-19 12:06:18 -07:00
printf "Error updating the Minecraft server software.\n"
exit 1
2013-08-04 09:09:40 -07:00
fi
fi
2013-06-24 11:26:09 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# 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.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
overviewer() {
2016-05-28 12:58:30 -07:00
local SETTINGS_FILE LOG_FILE VERSION_TEST
SETTINGS_FILE="$WORLDS_LOCATION/$1/overviewer-settings.py"
LOG_FILE="$WORLDS_LOCATION/$1/logs/overviewer.log"
VERSION_TEST=$(compareMinecraftVersions $(getServerVersion $1) 1.7.2)
# Make sure this world has a server.properties file before mapping.
if [ ! -e "$WORLDS_LOCATION/$1/server.properties" ]; then
return
fi
# Make sure that the backup of the world files are there before mapping.
if [ ! -e "$BACKUP_LOCATION/$1/server.properties" ]; then
printf "\nError finding the backup for world $1. To save server "
printf "down time, mapping is run from the backup location.\n"
printf "Run '$PROG backup $1' before mapping.\n"
return
fi
2013-08-04 09:09:40 -07:00
# Make sure the maps directory exists.
2015-08-10 04:09:38 -07:00
mkdir -p "$MAPS_LOCATION/$1"
2013-08-04 09:09:40 -07:00
# Make sure the Minecraft client is available.
updateClientSoftware "$1"
2016-05-28 12:58:30 -07:00
# Create a default Overviewer settings file if it is missing.
if [ ! -e $SETTINGS_FILE ]; then
# Use the backup location so we minimize the time the server isn't saving
# data.
printf "worlds['$1'] = '$BACKUP_LOCATION/$1/$1'\n\n" > $SETTINGS_FILE
printf "renders['overworld-render'] = {\n" >> $SETTINGS_FILE
printf " 'world': '$1',\n" >> $SETTINGS_FILE
printf " 'title': 'Overworld',\n" >> $SETTINGS_FILE
printf " 'dimension': 'overworld',\n" >> $SETTINGS_FILE
printf " 'rendermode': 'normal'\n" >> $SETTINGS_FILE
printf "}\n\n" >> $SETTINGS_FILE
printf "renders['overworld-caves-render'] = {\n" >> $SETTINGS_FILE
printf " 'world': '$1',\n" >> $SETTINGS_FILE
printf " 'title': 'Caves',\n" >> $SETTINGS_FILE
printf " 'dimension': 'overworld',\n" >> $SETTINGS_FILE
printf " 'rendermode': 'cave'\n" >> $SETTINGS_FILE
printf "}\n\n" >> $SETTINGS_FILE
printf "renders['nether-render'] = {\n" >> $SETTINGS_FILE
printf " 'world': '$1',\n" >> $SETTINGS_FILE
printf " 'title': 'Nether',\n" >> $SETTINGS_FILE
printf " 'dimension': 'nether',\n" >> $SETTINGS_FILE
printf " 'rendermode': 'nether'\n" >> $SETTINGS_FILE
printf "}\n\n" >> $SETTINGS_FILE
printf "renders['end-render'] = {\n" >> $SETTINGS_FILE
printf " 'world': '$1',\n" >> $SETTINGS_FILE
printf " 'title': 'End',\n" >> $SETTINGS_FILE
printf " 'dimension': 'end',\n" >> $SETTINGS_FILE
printf " 'rendermode': 'normal'\n" >> $SETTINGS_FILE
printf "}\n\n" >> $SETTINGS_FILE
printf "processes = 2\n" >> $SETTINGS_FILE
printf "outputdir = '$MAPS_LOCATION/$1'\n" >> $SETTINGS_FILE
fi
# Announce the mapping of the world to players if the world is running.
if serverRunning $1; then
if [ $VERSION_TEST -ge 0 ]; then
sendCommand $1 '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."
2013-08-04 09:09:40 -07:00
fi
fi
2016-05-28 12:58:30 -07:00
# Generate the map and POI.
$OVERVIEWER_BIN --config=$SETTINGS_FILE >> $LOG_FILE 2>&1
$OVERVIEWER_BIN --config=$SETTINGS_FILE --genpoi >> $LOG_FILE 2>&1
# Announce the location to access the world map to players.
2016-05-28 12:58:30 -07:00
if serverRunning $1; then
if [ $VERSION_TEST -ge 0 ]; then
sendCommand $1 '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'/'$1'"
}
2016-05-28 12:58:30 -07:00
},
{
"text" : "."
}
]
}'
else
2016-05-28 12:58:30 -07:00
sendCommand $1 "say Mapping is complete. You can access the maps at:"
sendCommand $1 "say $MAPS_URL/$1"
fi
fi
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# Start a Query handler for a world server.
#
2013-12-03 12:00:37 -07:00
# @param 1 The world server to start a Query handler for.
# ---------------------------------------------------------------------------
queryStart() {
local WORLD_DIR SERVER_IP QUERY_PORT
2013-12-03 12:00:37 -07:00
# Grab the location of the world's directory.
WORLD_DIR="$WORLDS_LOCATION/$1"
# Determine the IP address and port used by the query server.
2015-07-09 14:39:03 -07:00
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.
2015-08-10 04:09:38 -07:00
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.
2015-08-10 04:09:38 -07:00
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.
2015-08-10 04:09:38 -07:00
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.
2015-12-29 17:23:55 -07:00
if [ -e "$WORLD_DIR/query.in" ] && [ -e "$WORLD_DIR/query.out" ]; then
2016-02-10 08:55:09 -07:00
# 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.
2015-08-10 04:09:38 -07:00
printf '' > "$WORLD_DIR/query.out"
# Pack the hex string packet and write it to the query.in buffer file.
2015-08-10 04:09:38 -07:00
$PERL -e "
print map { pack (\"C\", hex(\$_)) } (\"$PACKET\" =~ /(..)/g);
" >> "$WORLD_DIR/query.in"
# Give the Query server a moment to respond.
sleep 1
2016-02-10 09:08:19 -07:00
# 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
2015-07-09 14:39:03 -07:00
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.
2015-08-05 02:22:37 -07:00
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
}
2013-08-08 09:06:16 -07:00
# ---------------------------------------------------------------------------
# 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.
2013-08-08 09:06:16 -07:00
# ---------------------------------------------------------------------------
queryDetailedStatus() {
local CHALLENGE ID PACKET TOKEN
2015-07-09 14:39:03 -07:00
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.
2015-08-05 02:22:37 -07:00
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
2013-08-08 09:06:16 -07:00
}
2016-05-28 12:37:50 -07:00
# ---------------------------------------------------------------------------
2016-03-07 21:24:41 -07:00
# 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.
2016-05-28 12:37:50 -07:00
# ---------------------------------------------------------------------------
2016-03-07 21:24:41 -07:00
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)
2016-03-07 21:24:41 -07:00
COUNTER=1
while [ $COUNTER -lt $NUMPLAYERS ]; do
PLAYERS=$(printf "%s, \"%s\"" "$PLAYERS" $(printf "%s" "$STATUS" | cut -f $((30+$COUNTER))))
2016-03-07 21:24:41 -07:00
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
2015-07-09 14:39:03 -07:00
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")
printf " Memory used: %d kB.\n" $(getJavaMemory "$1")
elif [ "$(getMSCSValue $1 'mscs-enabled')" = "false" ]; then
printf "disabled.\n"
else
printf "not running.\n"
fi
}
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Begin.
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
2016-12-19 10:20:00 -07:00
# Make sure that Java, Perl, libjson-perl, Python, Wget, Rdiff-backup, and
# Socat are installed.
2016-05-28 12:56:38 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
if [ ! -e "$JAVA" ]; then
echo "ERROR: Java not found!"
echo "Try installing this with:"
echo "sudo apt-get install default-jre"
2013-08-04 09:09:40 -07:00
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$PERL" ]; then
echo "ERROR: Perl not found!"
echo "Try installing this with:"
echo "sudo apt-get install perl"
2013-08-04 09:09:40 -07:00
exit 1
2013-06-24 11:26:09 -07:00
fi
2016-12-19 10:20:00 -07:00
perl -e 'use JSON;' > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "ERROR: libjson-perl not found!"
echo "Try installing this with:"
echo "sudo apt-get install libjson-perl"
exit 1
fi
2013-06-24 11:26:09 -07:00
if [ ! -e "$PYTHON" ]; then
echo "ERROR: Python not found!"
echo "Try installing this with:"
echo "sudo apt-get install python"
2013-08-04 09:09:40 -07:00
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$WGET" ]; then
echo "ERROR: GNU Wget not found!"
echo "Try installing this with:"
echo "sudo apt-get install wget"
2013-08-04 09:09:40 -07:00
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$RDIFF_BACKUP" ]; then
echo "ERROR: rdiff-backup not found!"
echo "Try installing this with:"
echo "sudo apt-get install rdiff-backup"
2013-08-04 09:09:40 -07:00
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$SOCAT" ]; then
echo "ERROR: socat not found!"
echo "Try installing this with:"
echo "sudo apt-get install socat"
exit 1
fi
2013-06-24 11:26:09 -07:00
2016-05-29 18:14:53 -07:00
# 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
2016-05-30 19:15:55 -07:00
# Override Default Values
2016-05-29 18:14:53 -07:00
# ---------------------------------------------------------------------------
2016-05-30 19:15:55 -07:00
# Override the default values by adding them to one of the following files. If
# none of the files exist, the default values in the script will be used (see
# below). Possible files are checked in the following order:
2016-05-29 18:14:53 -07:00
# command line option "-c".
2016-05-30 19:15:55 -07:00
# $HOME/mscs.defaults
# $HOME/.config/mscs/mscs.defaults
if [ -n "$MSCS_DEFAULTS_CL" ]; then
2016-05-29 18:14:53 -07:00
MSCS_DEFAULTS="$MSCS_DEFAULTS_CL"
2016-05-30 19:15:55 -07:00
elif [ -r "$HOME/mscs.defaults" ]; then
MSCS_DEFAULTS="$HOME/mscs.defaults"
elif [ -r "$HOME/.config/mscs/mscs.defaults" ]; then
MSCS_DEFAULTS="$HOME/.config/mscs/mscs.defaults"
2016-05-29 18:14:53 -07:00
fi
2016-05-30 19:15:55 -07:00
# Default values in the script can be overridden by adding certain key/value
# pairs to one of the mscs.defaults files mentioned above. Default values in
# the script will be used unless overridden in one these files.
#
# The following keys are available:
# mscs-location - Location of the mscs files.
# mscs-worlds-location - Location of world files.
# mscs-versions-url - URL to download the version_manifest.json file.
# mscs-versions-json - Location of the version_manifest.json file.
# mscs-versions-duration - Duration (in minutes) to keep the version_manifest.json file before updating.
# mscs-lockfile-duration - Duration (in minutes) to keep lock files before removing.
2016-05-30 19:15:55 -07:00
# mscs-detailed-listing - Properties to return for detailed listings.
# mscs-default-world - Default world name.
# mscs-default-port - Default Port.
# mscs-default-ip - Default IP address.
# mscs-default-version-type - Default version type (release or snapshot).
# mscs-default-client-version - Default version of the client software.
# mscs-default-client-jar - Default .jar file for the client software.
# mscs-default-client-url - Default download URL for the client software.
# mscs-default-client-location - Default location of the client .jar file.
# mscs-default-server-version - Default version of the server software.
# mscs-default-server-jar - Default .jar file for the server software.
# mscs-default-server-url - Default download URL for the server software.
# mscs-default-server-args - Default arguments to for a world server.
# mscs-default-initial-memory - Default initial amount of memory for a world server.
# mscs-default-maximum-memory - Default maximum amount of memory for a world server.
# mscs-default-server-location - Default location of the server .jar file.
# mscs-default-server-command - Default command to run for a world server.
# mscs-backup-location - Location to store backup files.
# mscs-backup-log - Lcation of the backup log file.
# mscs-backup-duration - Length in days that backups survive.
# mscs-log-duration - Length in days that logs survive.
# mscs-enable-mirror - Enable the mirror option by default for worlds (default disabled).
# mscs-mirror-path - Default path for the mirror files.
# mscs-overviewer-bin - Location of Overviewer.
# mscs-overviewer-url - URL for Overviewer.
# mscs-maps-location - Location of Overviewer generated map files.
# mscs-maps-url - URL for accessing Overviewer generated maps.
#
# The following variables may be used in some of the key values:
# $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-location=/opt/mscs
# mscs-worlds-location=/opt/mscs/worlds
# mscs-versions-url=https://launchermeta.mojang.com/mc/game/version_manifest.json
# mscs-versions-json=/opt/mscs/version_manifest.json
# mscs-versions-duration=1440
# mscs-lockfile-duration=1440
2016-05-30 19:15:55 -07:00
# mscs-default-world=world
# mscs-default-port=25565
# mscs-default-ip=
# mscs-default-version-type=release
# mscs-default-client-version=$CURRENT_VERSION
# mscs-default-client-jar=$CLIENT_VERSION.jar
# mscs-default-client-url=https://s3.amazonaws.com/Minecraft.Download/versions/$CLIENT_VERSION/$CLIENT_VERSION.jar
# mscs-default-client-location=/opt/mscs/.minecraft/versions/$CLIENT_VERSION
# mscs-default-server-version=$CURRENT_VERSION
# mscs-default-server-jar=minecraft_server.$SERVER_VERSION.jar
# mscs-default-server-url=https://s3.amazonaws.com/Minecraft.Download/versions/$SERVER_VERSION/minecraft_server.$SERVER_VERSION.jar
# mscs-default-server-args=nogui
# mscs-default-initial-memory=128M
# mscs-default-maximum-memory=2048M
# mscs-default-server-location=/opt/mscs/server
# mscs-default-server-command=$JAVA -Xms$INITIAL_MEMORY -Xmx$MAXIMUM_MEMORY -jar $SERVER_LOCATION/$SERVER_JAR $SERVER_ARGS
# mscs-backup-location=/opt/mscs/backups
# mscs-backup-log=/opt/mscs/backups/backup.log
# mscs-backup-duration=15
# mscs-log-duration=15
# mscs-detailed-listing=motd server-ip server-port max-players level-type online-mode
# mscs-enable-mirror=0
# mscs-mirror-path=/dev/shm/mscs
# mscs-overviewer-bin=/usr/bin/overviewer.py
# mscs-overviewer-url=http://overviewer.org
# mscs-maps-location=/opt/mscs/maps
# mscs-maps-url=http://minecraft.server.com/maps
2016-05-29 18:14:53 -07:00
# Server Location
# ---------------------------------------------------------------------------
# The default location of server software and data.
2016-05-30 19:15:55 -07:00
LOCATION=$(getDefaultsValue 'mscs-location' $HOME'/mscs')
2016-05-29 18:14:53 -07:00
# Override with command-line location option.
[ -n "$LOCATION_CL" ] && LOCATION="$LOCATION_CL"
# Global Server Configuration
# ---------------------------------------------------------------------------
# Minecraft Versions information
# ---------------------------------------------------------------------------
2016-05-30 19:15:55 -07:00
MINECRAFT_VERSIONS_URL=$(getDefaultsValue 'mscs-versions-url' 'https://launchermeta.mojang.com/mc/game/version_manifest.json')
2016-05-29 18:14:53 -07:00
# Minecraft Server Settings
# ---------------------------------------------------------------------------
2016-05-30 19:15:55 -07:00
# Settings used if not provided in the world's mscs.properties file.
DEFAULT_WORLD=$(getDefaultsValue 'mscs-default-world' 'world')
DEFAULT_PORT=$(getDefaultsValue 'mscs-default-port' '25565')
DEFAULT_IP=$(getDefaultsValue 'mscs-default-ip' '')
DEFAULT_VERSION_TYPE=$(getDefaultsValue 'mscs-default-version-type' 'release')
DEFAULT_CLIENT_VERSION=$(getDefaultsValue 'mscs-default-client-version' '$CURRENT_VERSION')
DEFAULT_CLIENT_JAR=$(getDefaultsValue 'mscs-default-client-jar' '$CLIENT_VERSION.jar')
DEFAULT_CLIENT_URL=$(getDefaultsValue 'mscs-default-client-url' 'https://s3.amazonaws.com/Minecraft.Download/versions/$CLIENT_VERSION/$CLIENT_VERSION.jar')
DEFAULT_CLIENT_LOCATION=$(getDefaultsValue 'mscs-default-client-location' $HOME'/.minecraft/versions/$CLIENT_VERSION')
DEFAULT_SERVER_VERSION=$(getDefaultsValue 'mscs-default-server-version' '$CURRENT_VERSION')
DEFAULT_SERVER_JAR=$(getDefaultsValue 'mscs-default-server-jar' 'minecraft_server.$SERVER_VERSION.jar')
DEFAULT_SERVER_URL=$(getDefaultsValue 'mscs-default-server-url' 'https://s3.amazonaws.com/Minecraft.Download/versions/$SERVER_VERSION/minecraft_server.$SERVER_VERSION.jar')
DEFAULT_SERVER_ARGS=$(getDefaultsValue 'mscs-default-server-args' 'nogui')
DEFAULT_INITIAL_MEMORY=$(getDefaultsValue 'mscs-default-initial-memory' '128M')
DEFAULT_MAXIMUM_MEMORY=$(getDefaultsValue 'mscs-default-maximum-memory' '2048M')
DEFAULT_SERVER_LOCATION=$(getDefaultsValue 'mscs-default-server-location' $LOCATION'/server')
DEFAULT_SERVER_COMMAND=$(getDefaultsValue 'mscs-default-server-command' '$JAVA -Xms$INITIAL_MEMORY -Xmx$MAXIMUM_MEMORY -jar $SERVER_LOCATION/$SERVER_JAR $SERVER_ARGS')
# Each world server can override the default values in a similar manner by
# adding certain key/value pairs to the world's mscs.properties file.
2016-05-29 18:14:53 -07:00
#
# 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.
#
2016-05-30 19:15:55 -07:00
# Like above, the following variables may be used in some of the key values:
2016-05-29 18:14:53 -07:00
# $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.
2016-05-30 19:15:55 -07:00
WORLDS_LOCATION=$(getDefaultsValue 'mscs-worlds-location' $LOCATION'/worlds')
2016-05-29 18:14:53 -07:00
# The location to store the version_manifest.json file.
2016-05-30 19:15:55 -07:00
VERSIONS_JSON=$(getDefaultsValue 'mscs-versions-json' $LOCATION'/version_manifest.json')
2016-05-29 18:14:53 -07:00
# The duration (in minutes) to keep the version_manifest.json file before updating.
2016-05-30 19:15:55 -07:00
VERSIONS_DURATION=$(getDefaultsValue 'mscs-versions-duration' '1440')
# The duration (in minutes) to keep lock files before removing.
LOCKFILE_DURATION=$(getDefaultsValue 'mscs-lockfile-duration' '1440')
2016-05-29 18:14:53 -07:00
# Backup Configuration
# ---------------------------------------------------------------------------
# Location to store backups.
2016-05-30 19:15:55 -07:00
BACKUP_LOCATION=$(getDefaultsValue 'mscs-backup-location' $LOCATION'/backups')
2016-05-29 18:14:53 -07:00
# Location of the backup log file.
2016-05-30 19:15:55 -07:00
BACKUP_LOG=$(getDefaultsValue 'mscs-backup-log' $BACKUP_LOCATION'/backup.log')
2016-05-29 18:14:53 -07:00
# Length in days that backups survive.
2016-05-30 19:15:55 -07:00
BACKUP_DURATION=$(getDefaultsValue 'mscs-backup-duration' '15')
2016-05-29 18:14:53 -07:00
# Server Log Configuration
# ---------------------------------------------------------------------------
# Length in days that logs survive.
2016-05-30 19:15:55 -07:00
LOG_DURATION=$(getDefaultsValue 'mscs-log-duration' '15')
2016-05-29 18:14:53 -07:00
# Listing options
# ---------------------------------------------------------------------------
# Server properties for detailed listing (list).
2016-05-30 19:15:55 -07:00
DETAILED_LISTING_PROPERTIES=$(getDefaultsValue 'mscs-detailed-listing' 'motd server-ip server-port max-players level-type online-mode')
2016-05-29 18:14:53 -07:00
# 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.
2016-05-30 19:15:55 -07:00
ENABLE_MIRROR=$(getDefaultsValue 'mscs-enable-mirror' '0')
2016-05-29 18:14:53 -07:00
# The location to store the mirror image.
#
# NOTE: This is usually a ramdisk, e.g. /dev/shm on Debian/Ubuntu.
2016-05-30 19:15:55 -07:00
MIRROR_PATH=$(getDefaultsValue 'mscs-mirror-path' '/dev/shm/mscs')
2016-05-29 18:14:53 -07:00
# Minecraft Overviewer Mapping Software Options
# ---------------------------------------------------------------------------
2016-05-30 19:15:55 -07:00
OVERVIEWER_BIN=$(getDefaultsValue 'mscs-overviewer-bin' $(which overviewer.py))
OVERVIEWER_URL=$(getDefaultsValue 'mscs-overviewer-url' 'http://overviewer.org')
MAPS_LOCATION=$(getDefaultsValue 'mscs-maps-location' $LOCATION'/maps')
MAPS_URL=$(getDefaultsValue 'mscs-maps-url' 'http://minecraft.server.com/maps')
2013-06-24 11:26:09 -07:00
# Respond to the command line arguments.
2016-05-28 12:56:38 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
case "$1" in
2013-08-04 09:09:40 -07:00
start)
# Figure out which worlds to start.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -z "$WORLDS" ]; then
echo "There are no worlds to start."
2015-08-11 06:41:09 -07:00
echo "You may want to enable a world:"
echo " $PROG enable <world>"
2015-08-11 06:41:09 -07:00
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
2013-08-04 09:09:40 -07:00
# Start each world requested, if not already running.
printf "Starting Minecraft Server:"
for WORLD in $WORLDS; do
if ! serverRunning $WORLD; then
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# 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
2013-08-04 09:09:40 -07:00
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
2013-08-04 09:09:40 -07:00
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
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# 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
2013-08-04 09:09:40 -07:00
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"
;;
2013-10-19 09:57:29 -07:00
create|new)
2015-08-11 06:41:09 -07:00
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"
2015-08-12 02:16:40 -07:00
printf " Usage: $PROG create <world> <port> [<ip>]\n"
2015-08-11 06:41:09 -07:00
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"
2013-10-19 09:57:29 -07:00
fi
;;
2013-10-19 10:15:16 -07:00
delete|remove)
2013-12-27 12:59:13 -07:00
# Get list of enabled worlds.
if ! isWorldAvailable "$2"; then
2013-10-19 10:15:16 -07:00
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
2013-10-19 10:15:16 -07:00
# Delete the world.
deleteWorld "$2"
printf ".\n"
2013-10-19 10:15:16 -07:00
;;
2013-10-19 10:47:23 -07:00
disable)
2013-12-27 12:59:13 -07:00
# Get list of enabled worlds.
if ! isWorldEnabled "$2"; then
2013-10-19 10:47:23 -07:00
printf "World not found, unable to disable world '$2'.\n"
exit 1
fi
printf "Disabling Minecraft world: $2"
if serverRunning "$2"; then
2013-10-19 10:47:23 -07:00
# If the world server has users logged in, announce that the world is
# being disabled.
if [ $(queryNumUsers "$2") -gt 0 ]; then
2013-10-19 10:47:23 -07:00
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"
2013-10-19 10:47:23 -07:00
;;
2013-10-19 10:57:04 -07:00
enable)
2015-07-09 14:35:29 -07:00
# Get list of disabled worlds.
if ! isWorldAvailable "$2"; then
2013-10-19 10:57:04 -07:00
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
2013-10-19 10:57:04 -07:00
fi
printf "Enabling Minecraft world: $2"
2013-10-19 10:57:04 -07:00
# Enable the world.
enableWorld "$2"
# Start the world.
start "$2"
printf ".\n"
2013-10-19 10:57:04 -07:00
;;
ls|list)
2013-12-03 14:55:54 -07:00
# Grab the desired list of worlds.
WORLDS=""
case "$2" in
enabled)
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
2013-12-03 14:55:54 -07:00
;;
disabled)
WORLDS=$(getDisabledWorlds)
;;
running)
2013-12-27 12:59:13 -07:00
for WORLD in $(getEnabledWorlds); do
if serverRunning $WORLD; then
2013-12-03 14:55:54 -07:00
WORLDS="$WORLDS $WORLD"
fi
done
;;
stopped)
2013-12-27 12:59:13 -07:00
for WORLD in $(getEnabledWorlds); do
if ! serverRunning $WORLD; then
2013-12-03 14:55:54 -07:00
WORLDS="$WORLDS $WORLD"
fi
done
;;
"")
WORLDS=$(getAvailableWorlds)
2013-12-03 14:55:54 -07:00
;;
*)
echo "Unknown list option: $2."
2015-08-11 05:55:59 -07:00
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
;;
2013-12-03 14:55:54 -07:00
esac
;;
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getAvailableWorlds)
fi
2013-08-04 09:09:40 -07:00
# Show the status of each world requested.
printf "Minecraft Server Status:\n"
for WORLD in $WORLDS; do
printf " $WORLD: "
worldStatus $WORLD
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# Synchronize the images for each world.
printf "Synchronizing Minecraft Server:"
for WORLD in $WORLDS; do
if serverRunning $WORLD; then
2013-08-04 09:09:40 -07:00
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"
;;
2014-12-20 23:21:58 -07:00
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
2014-12-20 23:21:58 -07:00
printf " $WORLD"
sendCommand $WORLD "$*"
fi
2015-07-02 22:11:19 -07:00
done
2014-12-20 23:21:58 -07:00
printf ".\n"
else
2015-08-11 05:55:59 -07:00
printf "Usage: $PROG $1 <command>\n"
printf " ie: $PROG $1 say Hello World!\n"
2014-12-20 23:21:58 -07:00
exit 1
fi
;;
2013-08-04 09:09:40 -07:00
send)
# Check for the world command line argument.
if isWorldEnabled "$2" && [ -n "$3" ]; then
2013-08-04 09:09:40 -07:00
WORLD=$2
shift 2
printf "Sending command to world: $WORLD - '$*'.\n"
sendCommand $WORLD "$*"
else
2015-08-11 05:55:59 -07:00
printf "Usage: $PROG $1 <world> <command>\n"
printf " ie: $PROG $1 world say Hello World!\n"
2013-08-04 09:09:40 -07:00
exit 1
fi
;;
2014-02-06 15:47:52 -07:00
console)
# Check for the world command line argument.
if isWorldEnabled "$2"; then
2014-02-06 15:47:52 -07:00
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
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
2014-02-06 15:47:52 -07:00
exit 1
fi
;;
2013-08-04 09:09:40 -07:00
watch)
# Check for the world command line argument.
if isWorldEnabled "$2"; then
2013-08-04 09:09:40 -07:00
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
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# 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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# Backup each world requested.
printf "Backing up Minecraft Server:"
for WORLD in $WORLDS; do
printf " $WORLD"
2016-08-05 18:28:13 -07:00
# Create a lock file so that we don't create duplicate processes.
if $(createLockFile $WORLD "backup"); then
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
# Remove the lock file.
removeLockFile $WORLD "backup"
2013-08-04 09:09:40 -07:00
else
2016-08-05 18:28:13 -07:00
printf "\nError lock file for world $WORLD could not be created."
printf " Is the world already running a backup?\n"
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
2015-07-02 22:11:19 -07:00
else
printf "World not supplied.\n"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
fi
;;
restore-backup)
if [ -z $2 ]; then
printf "World not supplied.\n"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
elif ! isWorldAvailable "$2"; then
printf "World '$2' not recognized.\n"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
elif serverRunning "$2"; then
printf "World '$2' is running. Stop it first\n"
2015-08-11 05:55:59 -07:00
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
;;
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# Stop all of the world servers and backup the worlds.
2015-06-05 18:13:38 -07:00
RUNNING=
2013-08-04 09:09:40 -07:00
printf "Stopping Minecraft Server:"
for WORLD in $WORLDS; do
if serverRunning $WORLD; then
2015-06-05 18:13:38 -07:00
RUNNING="$RUNNING $WORLD"
2013-08-04 09:09:40 -07:00
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
2013-08-04 09:09:40 -07:00
sendCommand $WORLD "save-all"
sendCommand $WORLD "save-off"
stop $WORLD
fi
done
printf ".\n"
printf "Backing up Minecraft Server:"
for WORLD in $WORLDS; do
2013-08-04 09:09:40 -07:00
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
2013-08-04 09:09:40 -07:00
printf ".\n"
printf "Restarting Minecraft Server:"
2015-06-05 18:13:38 -07:00
for WORLD in $RUNNING; do
2013-08-04 09:09:40 -07:00
printf " $WORLD"
start $WORLD
done
printf ".\n"
;;
map|overviewer)
# Make sure that the Minecraft Overviewer software exists.
if [ ! -e "$OVERVIEWER_BIN" ]; then
2014-05-06 06:53:55 -07:00
printf "Minecraft Overviewer software not found.\n"
2013-08-04 09:09:40 -07:00
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"
2015-08-11 05:55:59 -07:00
printf " Usage: $PROG $1 <world>\n"
exit 1
else
WORLDS=$(getEnabledWorlds)
fi
2013-08-04 09:09:40 -07:00
# Run Minecraft Overviewer on each world requested.
printf "Running Minecraft Overviewer mapping:"
for WORLD in $WORLDS; do
printf " $WORLD"
2016-08-05 18:27:16 -07:00
# Create a lock file so that we don't create duplicate processes.
if $(createLockFile $WORLD "overviewer"); then
overviewer "$WORLD"
# Remove the lock file.
removeLockFile $WORLD "overviewer"
else
printf "\nError lock file for world $WORLD could not be created."
printf " Is the world already running Overviewer?\n"
fi
2013-08-04 09:09:40 -07:00
done
printf ".\n"
;;
2016-03-07 21:24:41 -07:00
query|query-raw|query-json)
2016-03-05 11:23:41 -07:00
# 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
2016-03-07 21:24:41 -07:00
case "$1" in
query|query-raw)
queryDetailedStatus "$2"
;;
query-json)
queryDetailedStatusJSON "$2"
;;
esac
2016-03-05 11:23:41 -07:00
;;
2015-03-03 19:27:43 -07:00
usage|help)
printf "Minecraft Server Control Script\n"
printf "\n"
usage
2015-03-03 19:27:43 -07:00
;;
2013-08-04 09:09:40 -07:00
*)
2014-01-04 19:41:24 -07:00
printf "Error in command line usage.\n"
2013-08-04 09:09:40 -07:00
printf "\n"
usage
2013-08-04 09:09:40 -07:00
exit 1
;;
2013-06-24 11:26:09 -07:00
esac
exit 0