mscs/minecraft_server

1884 lines
65 KiB
Plaintext
Raw Normal View History

2013-06-25 21:04:02 -07:00
#!/bin/sh
2013-06-24 11:26:09 -07:00
### BEGIN INIT INFO
# Provides: minecraft_server
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
2013-06-24 11:26:09 -07:00
# chkconfig: 345 50 50
2013-06-24 13:20:10 -07:00
# Description: Minecraft Server Control Script
2013-06-24 11:26:09 -07:00
### END INIT INFO
2013-06-24 14:30:46 -07:00
# ---------------------------------------------------------------------------
# Copyright (c) 2011-2014, 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.
# ---------------------------------------------------------------------------
2013-06-24 13:20:10 -07:00
# Script Usage
# ---------------------------------------------------------------------------
2013-06-24 13:11:34 -07:00
USAGE=$(cat <<EOF
2013-12-02 21:50:29 -07:00
Usage: $0 <option>
2013-06-24 13:11:34 -07:00
Options:
start <world>
Start the Minecraft world server. Start all world servers by default.
stop <world>
Stop the Minecraft world server. Stop all world servers by default.
force-stop <world>
Forcibly stop the Minecraft world server. Forcibly stop all world
servers by default.
restart <world>
Restart the Minecraft world server. Restart all world servers by default.
force-restart <world>
Forcibly restart the Minecraft world server. Forcibly restart all world
servers by default.
create <world> <port> <ip>
Create a Minecraft world server. The world name and port must be
provided, the IP addressis usually blank.
delete <world>
Delete a Minecraft world server.
disable <world>
Temporarily disable a world server.
enable <world>
Enable a disabled world server.
2013-12-03 14:55:54 -07:00
list <option>
Display a list of worlds.
Options:
enabled Display a list of enabled worlds, default.
disabled Display a list of disabled worlds.
running Display a list of running worlds.
stopped Display a list of stopped worlds.
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.
send <world> <command>
Send a command to a Minecraft world server.
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.
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.
2013-06-24 13:11:34 -07:00
EOF
)
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# User Account & Server Location
# ---------------------------------------------------------------------------
# Who we run as and where we run from.
2013-06-24 11:26:09 -07:00
# User name used to run all commands. Be sure to create this user if it
# doesn't already exist (sudo adduser minecraft).
2013-06-24 11:26:09 -07:00
USER_NAME="minecraft"
# The location of server software and data.
LOCATION="/home/$USER_NAME"
2013-06-24 13:20:10 -07:00
# Required Software
# ---------------------------------------------------------------------------
# Detect its presence and location for later.
2013-06-24 11:26:09 -07:00
JAVA=$(which java)
PERL=$(which perl)
PYTHON=$(which python)
RSYNC=$(which rsync)
WGET=$(which wget)
RDIFF_BACKUP=$(which rdiff-backup)
SOCAT=$(which socat)
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# Global Server Configuration
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Mojang Versions information
# ---------------------------------------------------------------------------
# Detect the latest version.
CURRENT_VERSION=$(
wget -q -O - https://s3.amazonaws.com/Minecraft.Download/versions/versions.json |
$PERL -ne 'if ($_ =~ /^\s+\"release\": \"([0-9\.]+)\"/) { print $1; }'
)
2013-06-24 13:20:10 -07:00
# Minecraft Server Settings
# ---------------------------------------------------------------------------
# Default settings if not provided in the world's server.properties file.
2013-06-24 11:26:09 -07:00
DEFAULT_WORLD='world'
DEFAULT_PORT='25565'
DEFAULT_IP=''
DEFAULT_CLIENT_VERSION=$CURRENT_VERSION
DEFAULT_CLIENT_JAR='$CLIENT_VERSION.jar'
DEFAULT_CLIENT_URL='https://s3.amazonaws.com/Minecraft.Download/versions/$CLIENT_VERSION/$CLIENT_VERSION.jar'
DEFAULT_CLIENT_LOCATION=$LOCATION'/.minecraft/versions/$CLIENT_VERSION'
DEFAULT_SERVER_VERSION=$CURRENT_VERSION
DEFAULT_SERVER_JAR='minecraft_server.$SERVER_VERSION.jar'
DEFAULT_SERVER_URL='https://s3.amazonaws.com/Minecraft.Download/versions/$SERVER_VERSION/minecraft_server.$SERVER_VERSION.jar'
DEFAULT_SERVER_ARGS='nogui'
DEFAULT_INITIAL_MEMORY='128M'
DEFAULT_MAXIMUM_MEMORY='2048M'
DEFAULT_SERVER_LOCATION=$LOCATION'/minecraft_server'
DEFAULT_SERVER_COMMAND='$JAVA -Xms$INITIAL_MEMORY -Xmx$MAXIMUM_MEMORY -jar $SERVER_LOCATION/$SERVER_JAR $SERVER_ARGS'
2013-06-24 11:26:09 -07:00
# The server settings for each world can be customized by adding certain
# key/value pairs to the world's server.properties file.
#
# The following keys are available:
# mscs-client-version - Assign the version of the client software.
# mscs-client-jar - Assign the .jar file for the client software.
# mscs-client-url - Assign the download URL for the client software.
# mscs-client-location - Assign the location of the client .jar file.
# mscs-server-version - Assign the version of the server software.
# mscs-server-jar - Assign the .jar file for the server software.
# mscs-server-url - Assign the download URL for the server software.
# mscs-server-args - Assign the arguments to the server.
# mscs-initial-memory - Assign the initial amount of memory for the server.
# mscs-maximum-memory - Assign the maximum amount of memory for the server.
# mscs-server-location - Assign the location of the server .jar file.
# mscs-server-command - Assign the command to run for the server.
#
# The following variables may be used in some of the values of the above
# keys:
# $JAVA - The Java virtual machine.
# $CURRENT_VERSION - The current Mojang Minecraft release version.
# $CLIENT_VERSION - The version of the client software.
# $SERVER_VERSION - The version of the server software.
# $SERVER_JAR - The .jar file to run for the server.
# $SERVER_ARGS - The arguments to the server.
# $INITIAL_MEMORY - The initial amount of memory for the server.
# $MAXIMUM_MEMORY - The maximum amount of memory for the server.
# $SERVER_LOCATION - The location of the server .jar file.
#
# The following example key/value pairs are equivalent to the default values:
# mscs-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=/home/minecraft/.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=/home/minecraft/minecraft_server
# mscs-server-command=$JAVA -Xms$INITIAL_MEMORY -Xmx$MAXIMUM_MEMORY -jar $SERVER_LOCATION/$SERVER_JAR $SERVER_ARGS
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# World (Server Instance) Configuration
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# The location to store files for each world server.
WORLDS_LOCATION="$LOCATION/worlds"
2013-10-19 10:47:23 -07:00
# The location to store disabled world server files.
DISABLED_WORLDS_LOCATION="$LOCATION/worlds-disabled"
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# Global Message Of The Day file (MOTD)
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Location of the file to display to users on login. Nothing will be done if
# this file does not exist.
MOTD="$LOCATION/motd.txt"
# NOTE: MOTD can contain color codes as follows:
2013-06-24 11:26:09 -07:00
# §0 - black
# §1 - blue
# §2 - dark green
# §3 - aqua
# §4 - dark red
# §5 - purple
# §6 - gold
# §7 - gray
# §8 - dark gray
# §9 - light blue
# §a - green
# §b - teal
# §c - red
# §d - magenta
# §e - yellow
# §f - white
2013-06-24 13:20:10 -07:00
# Backup Configuration
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Location to store backups.
BACKUP_LOCATION="$LOCATION/backups"
# Location of the backup log file.
BACKUP_LOG="$BACKUP_LOCATION/backup.log"
# Length in days that backups survive.
BACKUP_DURATION=15
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# Server Log Configuration
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Length in days that logs survive.
LOG_DURATION=15
2013-06-24 11:26:09 -07:00
# Mirror Image Options
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# 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).
2013-06-24 11:26:09 -07:00
#
# 0 - Do not use a mirror image, default.
# 1 - Use a mirror image.
ENABLE_MIRROR=0
# The location to store the mirror image.
#
# NOTE: This is usually a ramdisk, e.g. /dev/shm on Debian/Ubuntu.
2013-06-24 11:26:09 -07:00
MIRROR_PATH="/dev/shm/minecraft"
2013-06-24 13:20:10 -07:00
# Mincecraft Overviewer Mapping Software Options
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
OVERVIEWER_BIN=$(which overviewer.py)
MAPS_URL="http://minecraft.server.com/maps"
MAPS_LOCATION="$LOCATION/maps"
2013-06-24 13:20:10 -07:00
# Lib-Notify Configuration
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Use lib-notify to print a message on your desktop of important server
# events.
2013-06-24 11:26:09 -07:00
# 0 - Do not use lib-notify.
# 1 - Display server events using lib-notify.
USE_LIBNOTIFY=0
# The username and display that messages will be routed to.
LIBNOTIFY_USER_NAME=$USER_NAME
LIBNOTIFY_DISPLAY=":0.0"
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Internal Methods
# ---------------------------------------------------------------------------
#
# NOTE: Nothing below this point should need to be edited directly.
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Execute the given command.
#
# @param 1 The command to execute.
# @param 2 The user name to execute the command with.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
execute() {
2013-08-04 09:09:40 -07:00
if [ $(id -u) -eq 0 ]; then
# Script is running as root, switch user and execute
# the command.
su -c "$1" $2
else
# Script is running as a user, just execute the command.
sh -c "$1"
fi
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# 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
PID=$(
ps -a -u $USER_NAME -o pid,comm,args |
$PERL -ne 'if ($_ =~ /^\s*(\d+)\s+java.+mscs-world='$1'$/) { print $1; }'
)
2013-12-04 21:20:24 -07:00
printf "%d\n" $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
# Check to see if the world server is running.
#
# @param 1 The world server of interest.
# @return A 1 if the server is thought to be running, a 0 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
2013-08-04 09:09:40 -07:00
echo 1
else
echo 0
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() {
local COMMAND
2013-08-04 09:09:40 -07:00
COMMAND=$(printf "$2\r")
echo "$COMMAND" >> $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 1 if the list contains the item, a 0 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=0
for ITEM in $2; do
if [ "$ITEM" = "$1" ]; then
MATCH=1
fi
done
echo $MATCH
2013-06-24 11:26:09 -07:00
}
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.
execute "mkdir -p $WORLDS_LOCATION/$1" $USER_NAME
setPropertiesValue "$1" "level-name" "$1"
setPropertiesValue "$1" "server-port" "$2"
setPropertiesValue "$1" "server-ip" "$3"
setPropertiesValue "$1" "enable-query" "true"
setPropertiesValue "$1" "query.port" "$2"
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.
execute "rm -Rf $WORLDS_LOCATION/$1" $USER_NAME
}
2013-10-19 10:47:23 -07:00
# ---------------------------------------------------------------------------
# Disable a world.
#
# @param 1 The world server to disable.
# ---------------------------------------------------------------------------
disableWorld() {
# Make sure the disabled world location exists.
execute "mkdir -p $DISABLED_WORLDS_LOCATION" $USER_NAME
2013-10-19 10:47:23 -07:00
# Disable the world.
execute "mv $WORLDS_LOCATION/$1 $DISABLED_WORLDS_LOCATION/$1" $USER_NAME
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.
execute "mv $DISABLED_WORLDS_LOCATION/$1 $WORLDS_LOCATION/$1" $USER_NAME
2013-10-19 10:57:04 -07:00
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Grab the first line of the Message of the Day file as a summary, and strip
# any color codes from it.
#
# @param 1 The world server of interest.
# @return The global message of the day or the specifued world
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
getMOTD() {
2013-08-04 09:09:40 -07:00
local MOTD_SUMMARY WORLD_MOTD
MOTD_SUMMARY=""
WORLD_MOTD="$WORLDS_LOCATION/$1.motd"
if [ -e $WORLD_MOTD ]; then
MOTD_SUMMARY=$(head -n 1 $WORLD_MOTD | $PERL -ne '$_ =~ s/§[0-9a-fA-F]//g; print;')
2013-08-04 09:09:40 -07:00
elif [ -e $MOTD ]; then
MOTD_SUMMARY=$(head -n 1 $MOTD | $PERL -ne '$_ =~ s/§[0-9a-fA-F]//g; print;')
2013-08-04 09:09:40 -07:00
fi
echo $MOTD_SUMMARY
2013-06-24 11:26:09 -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
#
2013-12-03 14:49:45 -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
WORLDS=""
for WORLD in $(ls $WORLDS_LOCATION); do
if [ -f $WORLDS_LOCATION/$WORLD/server.properties ]; then
WORLDS="$WORLDS $WORLD"
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.
# ---------------------------------------------------------------------------
getDisabledWorlds() {
local WORLD WORLDS
WORLDS=""
for WORLD in $(ls $DISABLED_WORLDS_LOCATION); do
if [ -f $DISABLED_WORLDS_LOCATION/$WORLD/server.properties ]; then
WORLDS="$WORLDS $WORLD"
fi
done
echo $WORLDS
}
# ---------------------------------------------------------------------------
2013-10-07 20:04:37 -07:00
# Get the value of a key in a world properties file.
#
# @param 1 The world server of interest.
# @param 2 The key to get.
# @param 3 The default value.
# ---------------------------------------------------------------------------
getPropertiesValue() {
local PROPERTY_FILE KEY VALUE
2013-08-04 09:09:40 -07:00
PROPERTY_FILE=$WORLDS_LOCATION/$1/server.properties
# Make sure the properties file exists
if [ -e "$PROPERTY_FILE" ]; then
# Find the key/value combo.
KEY=$($PERL -ne 'if ($_ =~ /^('$2')=.*$/i) { print lc $1; }' $PROPERTY_FILE)
VALUE=$($PERL -ne 'if ($_ =~ /^'$2'=(.*)$/i) { print $1; }' $PROPERTY_FILE)
2013-08-04 09:09:40 -07:00
if [ -n "$KEY" ] && [ -n "$VALUE" ]; then
echo "$VALUE"
else
echo "$3"
2013-08-04 09:09:40 -07:00
fi
fi
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
# Modify the value of a key/value combo in a world 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
# ---------------------------------------------------------------------------
setPropertiesValue() {
local PROPERTY_FILE KEY_VALUE
PROPERTY_FILE=$WORLDS_LOCATION/$1/server.properties
2013-08-04 09:09:40 -07:00
# Make sure that the properties file exists.
execute "touch $PROPERTY_FILE" $USER_NAME
2013-08-04 09:09:40 -07:00
# Replace the key/value combo if it already exists, otherwise just
# append it to the end of the file.
KEY_VALUE=$($PERL -ne 'if ($_ =~ /^('$2'=.*)$/) { print "$1"; }' $PROPERTY_FILE)
2013-08-04 09:09:40 -07:00
if [ -n "$KEY_VALUE" ]; then
execute "$PERL -i -ne 'if (\$_ =~ /^$2=.*$/) { print \"$2=$3\\n\"; } else { print; }' $PROPERTY_FILE" $USER_NAME
2013-08-04 09:09:40 -07:00
else
execute "printf \"$2=$3\\n\" >> $PROPERTY_FILE" $USER_NAME
2013-08-04 09:09:40 -07:00
fi
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# Retrieve the version of the client for the world.
#
# @param 1 The world server.
# @return CLIENT_VERSION
# ---------------------------------------------------------------------------
getClientVersion() {
local CLIENT_VERSION
# Get the client version, use the default version if not provided.
CLIENT_VERSION=$(
getPropertiesValue "$1" "mscs-client-version" "$DEFAULT_CLIENT_VERSION" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
print;
'
)
echo "$CLIENT_VERSION"
}
# ---------------------------------------------------------------------------
# Retrieve the .jar file name for the client for the world.
#
# @param 1 The world server.
# @return CLIENT_JAR
# ---------------------------------------------------------------------------
getClientJar() {
local CLIENT_JAR
# Get the client jar, use the default value if not provided.
CLIENT_JAR=$(
getPropertiesValue "$1" "mscs-client-jar" "$DEFAULT_CLIENT_JAR" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$client_version="'$(getClientVersion "$1")'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
$_ =~ s/\$CLIENT_VERSION/$client_version/g;
print;
'
)
echo "$CLIENT_JAR"
}
# ---------------------------------------------------------------------------
# Retrieve the location of the client files for the world.
#
# @param 1 The world server.
# @return CLIENT_LOCATION
# ---------------------------------------------------------------------------
getClientLocation() {
local CLIENT_LOCATION
# Get the client location, use the default value if not provided.
CLIENT_LOCATION=$(
getPropertiesValue "$1" "mscs-client-location" "$DEFAULT_CLIENT_LOCATION" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$client_version="'$(getClientVersion "$1")'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
$_ =~ s/\$CLIENT_VERSION/$client_version/g;
print;
'
)
echo "$CLIENT_LOCATION"
}
# ---------------------------------------------------------------------------
# Retrieve the URL to download the client for the world.
#
# @param 1 The world server.
# @return CLIENT_URL
# ---------------------------------------------------------------------------
getClientURL() {
local CLIENT_URL
# Get the client download URL, use the default value if not provided.
CLIENT_URL=$(
getPropertiesValue "$1" "mscs-client-url" "$DEFAULT_CLIENT_URL" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$client_version="'$(getClientVersion "$1")'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
$_ =~ s/\$CLIENT_VERSION/$client_version/g;
$_ =~ s/\\\:/\:/g;
print;
'
)
echo "$CLIENT_URL"
}
# ---------------------------------------------------------------------------
# Retrieve the version of the server running the world.
#
# @param 1 The world server.
# @return SERVER_VERSION
# ---------------------------------------------------------------------------
getServerVersion() {
local SERVER_VERSION
# Get the server version, use the default version if not provided.
SERVER_VERSION=$(
getPropertiesValue "$1" "mscs-server-version" "$DEFAULT_SERVER_VERSION" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
print;
'
)
echo "$SERVER_VERSION"
}
# ---------------------------------------------------------------------------
# Retrieve the .jar file name for the server running the world.
#
# @param 1 The world server.
# @return SERVER_JAR
# ---------------------------------------------------------------------------
getServerJar() {
local SERVER_JAR
# Get the server jar, use the default value if not provided.
SERVER_JAR=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-server-jar" "$DEFAULT_SERVER_JAR" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$server_version="'$(getServerVersion "$1")'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
$_ =~ s/\$SERVER_VERSION/$server_version/g;
print;
'
)
echo "$SERVER_JAR"
}
# ---------------------------------------------------------------------------
# Retrieve the location of the server files for the server running the world.
#
# @param 1 The world server.
# @return SERVER_LOCATION
# ---------------------------------------------------------------------------
getServerLocation() {
local SERVER_LOCATION
# Get the server location, use the default value if not provided.
SERVER_LOCATION=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-server-location" "$DEFAULT_SERVER_LOCATION" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$server_version="'$(getServerVersion "$1")'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
$_ =~ s/\$SERVER_VERSION/$server_version/g;
print;
'
)
echo "$SERVER_LOCATION"
}
# ---------------------------------------------------------------------------
# Retrieve the URL to download the server running the world.
#
# @param 1 The world server.
# @return SERVER_URL
# ---------------------------------------------------------------------------
getServerURL() {
local SERVER_URL
# Get the server download URL, use the default value if not provided.
SERVER_URL=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-server-url" "$DEFAULT_SERVER_URL" |
$PERL -ne '
$current_version="'$CURRENT_VERSION'";
$server_version="'$(getServerVersion "$1")'";
$_ =~ s/\$CURRENT_VERSION/$current_version/g;
$_ =~ s/\$SERVER_VERSION/$server_version/g;
2013-11-01 19:44:57 -07:00
$_ =~ s/\\\:/\:/g;
print;
'
)
echo "$SERVER_URL"
}
# ---------------------------------------------------------------------------
# Retrieve the command to start the server running the world.
#
# @param 1 The world server.
# @return SERVER_COMMAND
# ---------------------------------------------------------------------------
getServerCommand() {
local SERVER_ARGS INITIAL_MEMORY MAXIMUM_MEMORY SERVER_COMMAND
2013-11-03 19:11:49 -07:00
# Get the server arguments, use the default value if not provided.
SERVER_ARGS=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-server-args" "$DEFAULT_SERVER_ARGS"
)
# Get the initial memory, use the default value if not provided.
INITIAL_MEMORY=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-initial-memory" "$DEFAULT_INITIAL_MEMORY"
)
# Get the maximum memory, use the default value if not provided.
MAXIMUM_MEMORY=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-maximum-memory" "$DEFAULT_MAXIMUM_MEMORY"
)
# Get the server command, use the default value if not provided.
SERVER_COMMAND=$(
2013-11-01 20:35:17 -07:00
getPropertiesValue "$1" "mscs-server-command" "$DEFAULT_SERVER_COMMAND" |
$PERL -ne '
$java = "'$JAVA'";
$current_version = "'$CURRENT_VERSION'";
$server_version = "'$(getServerVersion "$1")'";
$server_jar = "'$(getServerJar "$1")'";
$server_location = "'$(getServerLocation "$1")'";
$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;
'
)
echo "$SERVER_COMMAND"
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Send a message to the desktop using lib-notify, if it is available.
#
# @param 1 The summary of the message to send.
# @param 2 The body of the message to send.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
libNotify() {
2013-08-04 09:09:40 -07:00
local NOTIFY
NOTIFY=$(which notify-send)
if [ -e "$NOTIFY" ]; then
execute "DISPLAY=$LIBNOTIFY_DISPLAY $NOTIFY \"$1\" \"$2\"" $LIBNOTIFY_USER_NAME > /dev/null 2>&1
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 the contents of the Message Of The Day (MOTD) to the user.
#
# @param 1 The world server of interest.
# @param 2 The user being told the contents of the motd file.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
tellMOTD() {
2013-08-04 09:09:40 -07:00
local LINE WORLD_MOTD
WORLD_MOTD="$WORLDS_LOCATION/$1.motd"
if [ -e $WORLD_MOTD ]; then
while read LINE; do
sendCommand $1 "tell $2 $LINE"
done < $WORLD_MOTD
elif [ -e $MOTD ]; then
while read LINE; do
sendCommand $1 "tell $2 $LINE"
done < $MOTD
fi
2013-06-24 11:26:09 -07:00
}
# ---------------------------------------------------------------------------
# Check to see if the user running this script has the correct permissions.
# ---------------------------------------------------------------------------
checkPermission() {
# Make sure that the minecraft user exists.
if [ ! -n "$(grep $USER_NAME /etc/passwd)" ]; then
printf "ERROR: This script requires that a user account named "
printf "$USER_NAME exist on this system.\nEither modify the "
printf "USER_NAME variable in this script, or try adding this "
printf "user:\n"
printf "sudo adduser $USER_NAME\n"
exit 1
fi
# Check to see if the user is root or is the minecraft user.
if [ $(id -u) -gt 0 ] && [ "$(whoami)" != "$USER_NAME" ]; then
# Script is running with the wrong user.
printf "WARNING: This script appears to have been started by the "
printf "wrong user.\n"
printf "Expected to find the user: $USER_NAME. You can try to log "
printf "on to this user:\n"
printf "su $USER_NAME\n"
exit 1
fi
}
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
# Check to see if the user is in the ops.txt file of the specified world.
#
# @param 1 The world server of interest.
# @param 2 The user being checked.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
checkUserIsAdmin() {
2013-08-04 09:09:40 -07:00
local IS_ADMIN
IS_ADMIN=$(cat $WORLDS_LOCATION/$1/ops.txt | $PERL -ne 'if ($_ =~ /^'$2'$/i) { print "1"; }')
echo $IS_ADMIN
2013-06-24 11:26:09 -07:00
}
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.
execute "mkdir -p $WORLD_DIR/logs" $USER_NAME
# Delete old log files.
execute "
find $WORLD_DIR/logs -type f -mtime +$LOG_DURATION -delete
" $USER_NAME
# Archive and rotate the log files for old Minecraft servers (Versions 1.7
# and greater do this automatically).
if [ -e $WORLD_DIR/server.log ] &&
[ $(wc -l < $WORLD_DIR/server.log) -ge 1 ]; then
# Make a copy of the log file in the world's logs directory.
DATE=$(date +%F)
execute "cp $WORLD_DIR/server.log $WORLD_DIR/logs/$DATE-0.log" $USER_NAME
execute "gzip $WORLD_DIR/logs/$DATE-0.log" $USER_NAME
# Empty the contents of the worlds log file.
execute "cp /dev/null $WORLD_DIR/server.log" $USER_NAME
# 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))
execute "mv -f $LOG $WORLD_DIR/logs/$DATE-$NUMBER.log.gz" $USER_NAME
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
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.
2013-08-04 10:33:58 -07:00
execute "cp -Ru $WORLDS_LOCATION/$1/$1/* $WORLDS_LOCATION/$1/$1-original" $USER_NAME
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
}
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 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"
execute "mkdir -p $WORLD_DIR" $USER_NAME
# 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
2013-08-04 09:09:40 -07:00
execute "mkdir -p $MIRROR_PATH/$1" $USER_NAME
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
# Remove the symlink to the world-file mirror image.
execute "rm -r $WORLDS_LOCATION/$1/$1" $USER_NAME
# Move the world files back to their original path name.
execute "mv $WORLDS_LOCATION/$1/$1-original $WORLDS_LOCATION/$1/$1" $USER_NAME
fi
# Copy the world files over to the mirror.
execute "cp -R $WORLDS_LOCATION/$1/$1/* $MIRROR_PATH/$1" $USER_NAME
# Rename the original world file directory.
execute "mv $WORLDS_LOCATION/$1/$1 $WORLDS_LOCATION/$1/$1-original" $USER_NAME
# Create a symlink from the world file directory's original name to the mirrored files.
execute "ln -s $MIRROR_PATH/$1 $WORLDS_LOCATION/$1/$1" $USER_NAME
2013-08-04 09:09:40 -07:00
fi
# Change to the world's directory.
cd $WORLD_DIR
# Delete any old console.in buffer file.
execute "rm -f $WORLD_DIR/console.in" $USER_NAME
# Initialize the console.in buffer file.
execute "printf '' > $WORLD_DIR/console.in" $USER_NAME
2013-08-04 09:09:40 -07:00
# Start the server.
execute "
tail -f --pid=\$$ $WORLD_DIR/console.in | {
$(getServerCommand $1) mscs-world=$1 > /dev/null 2>&1 && kill \$$;
}
" $USER_NAME &
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
if [ $(getJavaPID "$1") -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.
if [ "$(getPropertiesValue $1 'enable-query')" = "true" ]; then
queryStart "$1" &
fi
2013-08-04 09:09:40 -07:00
# Create a lock file on RedHat and derivatives.
if [ -d "/var/lock/subsys" ]; then
touch /var/lock/subsys/minecraft_server
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
# 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"
# 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.
execute "rm -r $WORLDS_LOCATION/$1/$1" $USER_NAME
# Move the world files back to their original path name.
execute "mv $WORLDS_LOCATION/$1/$1-original $WORLDS_LOCATION/$1/$1" $USER_NAME
2013-08-04 09:09:40 -07:00
fi
# Remove the lock file on Redhat and derivatives if all world servers
# are stopped.
if [ -e "/var/lock/subsys/minecraft_server" ]; then
NUM=0
2013-12-27 12:59:13 -07:00
for WORLD in $(getEnabledWorlds); do
2013-08-04 09:09:40 -07:00
if [ "$1" != "$WORLD" ] && [ $(serverRunning $WORLD) -eq 1 ]; then
NUM=$(($NUM + 1))
fi
done
if [ $NUM -eq 0 ]; then
rm -f /var/lock/subsys/minecraft_server
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
# 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-08-04 09:09:40 -07:00
# Remove the lock file on Redhat and derivatives if it is still
# around.
rm -f /var/lock/subsys/minecraft_server
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.
2013-06-24 13:20:10 -07:00
# ---------------------------------------------------------------------------
2013-06-24 11:26:09 -07:00
worldBackup() {
2013-08-04 09:09:40 -07:00
# Make sure that the backup location exists.
execute "mkdir -p $BACKUP_LOCATION" $USER_NAME
# Create the backup.
execute "$RDIFF_BACKUP -v5 --print-statistics $WORLDS_LOCATION/$1 $BACKUP_LOCATION/$1 >> $BACKUP_LOG" $USER_NAME
# Cleanup old backups.
if [ $BACKUP_DURATION -gt 0 ]; then
execute "$RDIFF_BACKUP --remove-older-than ${BACKUP_DURATION}D --force $BACKUP_LOCATION/$1 >> $BACKUP_LOG" $USER_NAME
fi
2013-06-24 11:26:09 -07:00
}
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")
CLIENT_LOCATION=$(getClientLocation "$1")
CLIENT_URL=$(getClientURL "$1")
2013-08-04 09:09:40 -07:00
# Make sure the client software directory exists.
execute "mkdir -p $CLIENT_LOCATION" $USER_NAME
if [ ! -e "$CLIENT_LOCATION/$CLIENT_JAR" ]; then
# Download the Minecraft client software.
execute "$WGET -qO \"$CLIENT_LOCATION/$CLIENT_JAR\" \"$CLIENT_URL\"" $USER_NAME
# Report any errors.
if [ $? -ne 0 ]; then
printf "\nError 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")
SERVER_LOCATION=$(getServerLocation "$1")
SERVER_URL=$(getServerURL "$1")
# Make sure the server software directory exists.
2013-08-04 09:09:40 -07:00
execute "mkdir -p $SERVER_LOCATION" $USER_NAME
if [ ! -e "$SERVER_LOCATION/$SERVER_JAR" ]; then
# Download the Minecraft server software.
execute "$WGET -qO \"$SERVER_LOCATION/$SERVER_JAR\" \"$SERVER_URL\"" $USER_NAME
# Report any errors.
if [ $? -ne 0 ]; then
printf "\nError 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() {
2013-08-04 09:09:40 -07:00
# Make sure the maps directory exists.
execute "mkdir -p $MAPS_LOCATION/$1" $USER_NAME
# Make sure the Minecraft client is available.
updateClientSoftware "$1"
2013-08-04 09:09:40 -07:00
# Make sure that the world files are actually there before mapping.
if [ -e "$WORLDS_LOCATION/$1/server.properties" ]; then
# Check for Overviewer settings file.
if [ -e "$WORLDS_LOCATION/$1/overviewer-settings.py" ]; then
# Generate map and POI with custom settings.
execute "$OVERVIEWER_BIN --config=$WORLDS_LOCATION/$1/overviewer-settings.py" $USER_NAME
execute "$OVERVIEWER_BIN --config=$WORLDS_LOCATION/$1/overviewer-settings.py --genpoi" $USER_NAME
else
# Generate map with default settings.
execute "$OVERVIEWER_BIN --rendermodes=normal,lighting,cave --processes 1 $WORLDS_LOCATION/$1/$1 $MAPS_LOCATION/$1" $USER_NAME > /dev/null 2>&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() {
2013-12-07 12:09:36 -07:00
local WORLD_DIR
2013-12-03 12:00:37 -07:00
# Grab the location of the world's directory.
WORLD_DIR="$WORLDS_LOCATION/$1"
# Delete any old query.in or query.out buffer files.
execute "rm -Rf $WORLD_DIR/query.in $WORLD_DIR/query.out" $USER_NAME
# Give the server a moment to start before initializing the
# Query handler.
sleep 10
# Initialize the query.in and query.out buffer files.
execute "printf '' > $WORLD_DIR/query.in" $USER_NAME
execute "printf '' > $WORLD_DIR/query.out" $USER_NAME
# 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.
execute "
2013-12-07 12:09:36 -07:00
tail -f --pid=$(getJavaPID $1) $WORLD_DIR/query.in | \
$SOCAT - UDP:127.0.0.1:$(getPropertiesValue $1 'server-port') > \
$WORLD_DIR/query.out
" $USER_NAME
}
# ---------------------------------------------------------------------------
# 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 ID.
# @param 4 The packet payload.
# @param 5 The response format.
# @return The response from the Query server in the requested format.
# ---------------------------------------------------------------------------
querySendPacket() {
2013-11-14 14:44:57 -07:00
local PACKET RESPONSE WORLD_DIR
# The world's directory.
WORLD_DIR="$WORLDS_LOCATION/$1"
# Make sure the query.in and query.out buffer files exist before
# preparing and sending the packet to the Query server.
if [ -e $WORLD_DIR/query.in ] && [ -e $WORLD_DIR/query.out ]; then
# Add the magic bytes to the incoming packet.
PACKET=$(printf "FEFD%s%s%s" "$2" "$3" "$4")
# Remove any old responses from the query.out buffer file.
execute "printf '' > $WORLD_DIR/query.out" $USER_NAME
# Pack the hex string packet and write it to the query.in buffer file.
execute "$PERL -e '
print map { pack (\"C\", hex(\$_)) } (\"'$PACKET'\" =~ /(..)/g);
' >> $WORLD_DIR/query.in" $USER_NAME
# Give the Query server a moment to respond.
sleep 1
# Unpack the token from the query.out buffer file. There are a
# variable amount of null bytes at the start of the response string, so
# find the start of the packet by searching for the packet type and ID.
RESPONSE=$($PERL -ne '
$hex .= sprintf "%.2x", $_ foreach (unpack "C*", $_);
$hex =~ s/^0*'$2$3'/'$2$3'/;
print $hex;
' $WORLD_DIR/query.out)
fi
# Return the response in the format requested.
$PERL -e '
$packed = join "", map { pack ("C", hex($_)) } ("'$RESPONSE'" =~ /(..)/g);
printf "%s\n", join "\t", unpack ("'$5'", $packed);
'
}
# ---------------------------------------------------------------------------
# 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 ID PACKET RESPONSE
# The packet identifier.
ID="00000001"
# Use an empty packet.
PACKET="00000000"
# Send the challenge packet to the Minecraft query server.
RESPONSE=$(querySendPacket "$1" "09" "$ID" "$PACKET" "Cl>Z*")
# Return the response.
printf "$RESPONSE\n"
}
# ---------------------------------------------------------------------------
# Send an information request packet to the Minecraft query server.
#
# @param 1 The world server of interest.
# @param 2 The challenge token.
# @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, hardcoded to 'SMP'.
# map - The world's name.
# numplayers - The world's current number of players.
# maxplayers - The world's maximum number of players.
# hostport - The world's host port.
# hostip - The world's host IP address.
# ---------------------------------------------------------------------------
querySendInformationPacket() {
local ID PACKET RESPONSE
# The packet identifier.
ID="00000001"
# Use the challenge token for the packet.
PACKET=$(printf "%.8x" $2)
# Send the information request packet to the Minecraft query server.
RESPONSE=$(querySendPacket "$1" "00" "$ID" "$PACKET" "Cl>Z*Z*Z*Z*Z*s<Z*")
# Return the response.
printf "$RESPONSE\n"
}
2013-08-08 09:06:16 -07:00
# ---------------------------------------------------------------------------
# Send a detailed information request packet to the Minecraft query server.
#
# @param 1 The world server of interest.
# @param 2 The challenge token.
# @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
# ---------------------------------------------------------------------------
querySendDetailedInformationPacket() {
local ID PACKET RESPONSE
# The packet identifier.
ID="00000001"
# Use the challenge token for the packet, with the ID on the end.
PACKET=$(printf "%.8x%s" $2 $ID)
# Send the information request packet to the Minecraft query server.
RESPONSE=$(querySendPacket "$1" "00" "$ID" "$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*)*")
# Return the response.
printf "$RESPONSE\n"
}
# ---------------------------------------------------------------------------
# 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 TOKEN RESPONSE
if [ "$(getPropertiesValue $1 'enable-query')" = "true" ]; then
# Send a challenge packet to the Minecraft query server.
TOKEN=$(querySendChallengePacket $1 | cut -f 3)
if [ -n "$TOKEN" ]; then
# Send an information request packet to the Minecraft query server.
RESPONSE=$(querySendInformationPacket $1 $TOKEN)
fi
fi
# Return the response.
printf "$RESPONSE\n"
}
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 TOKEN RESPONSE
if [ "$(getPropertiesValue $1 'enable-query')" = "true" ]; then
# Send a challenge packet to the Minecraft query server.
TOKEN=$(querySendChallengePacket $1 | cut -f 3)
if [ -n "$TOKEN" ]; then
# Send an information request packet to the Minecraft query server.
RESPONSE=$(querySendDetailedInformationPacket $1 $TOKEN)
fi
fi
2013-08-08 09:06:16 -07:00
# Return the response.
printf "$RESPONSE\n"
}
# ---------------------------------------------------------------------------
# Display the status of a Minecraft world server.
#
# @param 1 The world server of interest.
# ---------------------------------------------------------------------------
worldStatus() {
local STATUS NUM MAX PLAYERS COUNTER
if [ $(serverRunning $1) -eq 1 ]; then
STATUS=$(queryDetailedStatus $1)
if [ -n "$STATUS" ]; then
NUM=$(echo "$STATUS" | cut -f 19)
MAX=$(echo "$STATUS" | cut -f 21)
printf "running (%d of %d users online).\n" $NUM $MAX
if [ $NUM -gt 0 ]; then
2014-01-06 13:52:35 -07:00
PLAYERS=$(echo "$STATUS" | cut -f 30)
COUNTER=1
while [ $COUNTER -lt $NUM ]; do
PLAYERS=$(printf "%s, %s" "$PLAYERS" $(echo "$STATUS" | cut -f $((30+$COUNTER))))
COUNTER=$(($COUNTER+1))
done
printf " Players: %s.\n" "$PLAYERS"
fi
else
printf "running (query server offline).\n"
fi
printf " Process ID: %d.\n" $(getJavaPID "$1")
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
# Make sure that Java, Perl, Python, Rsync, and GNU Wget are installed.
2013-06-24 11:26:09 -07:00
if [ ! -e "$JAVA" ]; then
2013-08-04 09:09:40 -07:00
printf "ERROR: Java not found!\n"
printf "Try installing this with:\n"
printf "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
2013-08-04 09:09:40 -07:00
printf "ERROR: Perl not found!\n"
printf "Try installing this with:\n"
printf "sudo apt-get install perl\n"
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$PYTHON" ]; then
2013-08-04 09:09:40 -07:00
printf "ERROR: Python not found!\n"
printf "Try installing this with:\n"
printf "sudo apt-get install python\n"
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$RSYNC" ] && [ $ENABLE_MIRROR -eq 1 ]; then
2013-08-04 09:09:40 -07:00
printf "ERROR: Rsync not found!\n"
printf "Try installing this with:\n"
printf "sudo apt-get install rsync\n"
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$WGET" ]; then
2013-08-04 09:09:40 -07:00
printf "ERROR: GNU Wget not found!\n"
printf "Try installing this with:\n"
printf "sudo apt-get install wget\n"
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$RDIFF_BACKUP" ]; then
2013-08-04 09:09:40 -07:00
printf "ERROR: rdiff-backup not found!\n"
printf "Try installing this with:\n"
printf "sudo apt-get install rdiff-backup\n"
exit 1
2013-06-24 11:26:09 -07:00
fi
if [ ! -e "$SOCAT" ]; then
printf "ERROR: socat not found!\n"
printf "Try installing this with:\n"
printf "sudo apt-get install socat\n"
exit 1
fi
2013-06-24 11:26:09 -07:00
# Respond to the command line arguments.
case "$1" in
2013-08-04 09:09:40 -07:00
start)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to start.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
# If there are no worlds in the list, then use the default world.
if [ ! -n "$WORLDS" ]; then
WORLDS="$DEFAULT_WORLD"
createWorld "$DEFAULT_WORLD" "$DEFAULT_PORT" "$DEFAULT_IP"
fi
# If an optional argument was supplied, verify it is a valid world.
2013-12-27 12:59:13 -07:00
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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) -eq 0 ]; then
printf " $WORLD"
start $WORLD
fi
done
printf ".\n"
;;
stop|force-stop)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to stop.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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) -eq 1 ]; then
printf " $WORLD"
2013-10-19 11:50:50 -07:00
if [ $(printf "%d" $(queryStatus $WORLD | cut -f6)) -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)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to restart.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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) -eq 1 ]; then
2013-10-19 11:50:50 -07:00
if [ $(printf "%d" $(queryStatus $WORLD | cut -f6)) -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)
checkPermission
2013-10-19 09:57:29 -07:00
if [ ! -n "$2" ]; then
printf "A name for the new world must be supplied.\n"
exit 1
fi
if [ ! -n "$3" ]; then
printf "A port for the new world must be supplied.\n"
exit 1
fi
printf "Creating Minecraft world: $2"
2013-10-19 09:57:29 -07:00
createWorld "$2" "$3" "$4"
printf ".\n"
2013-10-19 09:57:29 -07:00
;;
2013-10-19 10:15:16 -07:00
delete|remove)
checkPermission
2013-12-27 12:59:13 -07:00
# Get list of enabled worlds.
WORLDS=$(getEnabledWorlds)
if [ ! -n "$2" ] || [ $(listContains "$2" "$WORLDS") -eq 0 ]; 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") -eq 1 ]; then
# If the world server has users logged in, announce that the world is
# being deleted.
if [ $(printf "%d" $(queryStatus $2 | cut -f6)) -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)
checkPermission
2013-12-27 12:59:13 -07:00
# Get list of enabled worlds.
WORLDS=$(getEnabledWorlds)
if [ ! -n "$2" ] || [ $(listContains "$2" "$WORLDS") -eq 0 ]; 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"
2013-10-19 10:47:23 -07:00
if [ $(serverRunning "$2") -eq 1 ]; then
# If the world server has users logged in, announce that the world is
# being disabled.
if [ $(printf "%d" $(queryStatus $2 | cut -f6)) -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)
checkPermission
2013-10-19 10:57:04 -07:00
if [ ! -n "$2" ] || [ ! -f "$DISABLED_WORLDS_LOCATION/$2/server.properties" ]; then
printf "World not found, unable to enable world '$2'.\n"
exit 1
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
2013-12-03 14:55:54 -07:00
if [ $(serverRunning $WORLD) -eq 1 ]; then
WORLDS="$WORLDS $WORLD"
fi
done
;;
stopped)
2013-12-27 12:59:13 -07:00
for WORLD in $(getEnabledWorlds); do
2013-12-03 14:55:54 -07:00
if [ $(serverRunning $WORLD) -eq 0 ]; then
WORLDS="$WORLDS $WORLD"
fi
done
;;
*)
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
2013-12-03 14:55:54 -07:00
;;
esac
echo $WORLDS
;;
2013-08-04 09:09:40 -07:00
status|show)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to show the status for.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to synchronize.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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) -eq 1 ]; then
printf " $WORLD"
sendCommand $WORLD "save-all"
if [ $ENABLE_MIRROR -eq 1 ]; then
sendCommand $WORLD "save-off"
sleep 20
syncMirrorImage $WORLD
sendCommand $WORLD "save-on"
fi
fi
done
printf ".\n"
;;
send)
checkPermission
2013-12-27 12:59:13 -07:00
# Get list of enabled worlds.
WORLDS=$(getEnabledWorlds)
2013-08-04 09:09:40 -07:00
# Check for the world command line argument.
2013-12-27 12:59:13 -07:00
if [ -n "$2" ] && [ $(listContains $2 "$WORLDS") -eq 1 ] && [ -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
printf "Usage: $0 $1 <world> <command>\n"
printf " ie: $0 $1 world say Hello World!\n"
exit 1
fi
;;
watch)
checkPermission
2013-12-27 12:59:13 -07:00
# Get list of enabled worlds.
WORLDS=$(getEnabledWorlds)
2013-08-04 09:09:40 -07:00
# Check for the world command line argument.
2013-12-27 12:59:13 -07:00
if [ -n "$2" ] && [ $(listContains $2 "$WORLDS") -eq 1 ]; 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
printf " Usage: $0 $1 <world>\n"
exit 1
fi
;;
logrotate)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to rotate the log.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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)
checkPermission
2013-08-04 09:09:40 -07:00
# Figure out which worlds to backup.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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"
if [ $(serverRunning $WORLD) -eq 1 ]; then
sendCommand $WORLD "say Backing up the world."
sendCommand $WORLD "save-all"
sendCommand $WORLD "save-off"
sleep 20
worldBackup $WORLD
sendCommand $WORLD "save-on"
sendCommand $WORLD "say Backup complete."
else
worldBackup $WORLD
fi
done
printf ".\n"
;;
update)
checkPermission
# Figure out which worlds to update.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
fi
2013-08-04 09:09:40 -07:00
# Stop all of the world servers and backup the worlds.
printf "Stopping Minecraft Server:"
for WORLD in $WORLDS; do
2013-08-04 09:09:40 -07:00
if [ $(serverRunning $WORLD) -eq 1 ]; then
printf " $WORLD"
2013-10-19 11:50:50 -07:00
if [ $(printf "%d" $(queryStatus $WORLD | cut -f6)) -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:"
for WORLD in $WORLDS; do
2013-08-04 09:09:40 -07:00
printf " $WORLD"
start $WORLD
done
printf ".\n"
;;
map|overviewer)
checkPermission
2013-08-04 09:09:40 -07:00
# Make sure that the Minecraft Overviewer software exists.
if [ ! -e "$OVERVIEWER_BIN" ]; then
printf "Mincraft Overviewer software not found.\n"
exit 1
fi
# Figure out which worlds to map.
2013-12-27 12:59:13 -07:00
WORLDS=$(getEnabledWorlds)
if [ -n "$2" ] && [ $(listContains "$2" "$WORLDS") -eq 1 ]; then
WORLDS="$2"
elif [ -n "$2" ]; then
printf "World '$2' not recognized.\n"
printf " Usage: $0 $1 <world>\n"
exit 1
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"
if [ $(serverRunning $WORLD) -eq 1 ]; then
sendCommand $WORLD "say The world is about to be mapped with Minecraft Overviewer."
sendCommand $WORLD "save-all"
sendCommand $WORLD "save-off"
sleep 20
worldBackup $WORLD
overviewer $WORLD
sendCommand $WORLD "save-on"
sendCommand $WORLD "say Mapping is complete. You can access the maps at:"
sendCommand $WORLD "say $MAPS_URL/$WORLD"
else
worldBackup $WORLD
overviewer $WORLD
fi
done
printf ".\n"
;;
*)
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"
printf "$USAGE\n"
exit 1
;;
2013-06-24 11:26:09 -07:00
esac
exit 0