2015-12-12 07:02:48 +10:00

1674 lines
48 KiB
Bash
Executable File

#!/bin/bash
# ARK: survival evolved manager
#
# Original author: LeXaT
# Maintainer: FezVrasta
# Contributors: Sispheor, Atriusftw, klightspeed, lexat, puseidr
# Script version
arkstVersion="1.5"
arkstCommit=''
doUpgradeTools() {
local sudo=sudo
if [ "$UID" == 0 -o "$steamcmd_user" == "--me" ]; then
sudo=
fi
echo "arkmanager v${arkstVersion}: Checking for updates..."
arkstLatestVersion=`curl -s https://raw.githubusercontent.com/FezVrasta/ark-server-tools/${arkstChannel}/.version`
arkstLatestCommit=`curl -s https://api.github.com/repos/FezVrasta/ark-server-tools/git/refs/heads/${arkstChannel} | sed -n 's/^ *"sha": "\(.*\)",.*/\1/p'`
if [ "$arkstLatestVersion" == "Not Found" ]; then
echo "Channel ${arkstChannel} does not exist"
echo
echo "Available channels:"
curl -s https://api.github.com/repos/FezVrasta/ark-server-tools/git/refs/heads | sed -n 's|^ *"ref": "refs/heads/\(.*\)",|\1|p'
echo
return
fi
reinstall_args=()
if [ -n "$install_bindir" ]; then
reinstall_args=( "${reinstall_args[@]}" "--bindir" "$install_bindir" )
fi
if [ -n "$install_libexecdir" ]; then
reinstall_args=( "${reinstall_args[@]}" "--libexecdir" "$install_libexecdir" )
fi
if [ -n "$install_datadir" ]; then
reinstall_args=( "${reinstall_args[@]}" "--datadir" "$install_datadir" )
fi
if [[ $arkstLatestVersion > $arkstVersion ]]; then
read -p "A new version was found! Do you want to upgrade ARK Server Tools to v${arkstLatestVersion}?" -n 1 -r
echo -en "\n"
if [[ $REPLY =~ ^[Yy]$ ]]; then
curl -s https://raw.githubusercontent.com/FezVrasta/ark-server-tools/${arkstChannel}/netinstall.sh | $sudo bash -s -- ${steamcmd_user} ${arkstChannel} "${reinstall_args[@]}"
exit 0
fi
elif [[ $arkstLatestVersion == $arkstVersion && "$arkstLatestCommit" != "$arkstCommit" ]]; then
read -p "A hotfix is available for v${arkstLatestVersion}. Do you wish to install it?" -n 1 -r
echo -en "\n"
if [[ $REPLY =~ ^[Yy]$ ]]; then
curl -s https://raw.githubusercontent.com/FezVrasta/ark-server-tools/${arkstChannel}/netinstall.sh | $sudo bash -s -- ${steamcmd_user} ${arkstChannel} "${reinstall_args[@]}"
exit 0
fi
else
echo "Your ARK server tools are already up to date"
fi
}
doUninstallTools() {
local sudo=sudo
if [ "$UID" == 0 -o "$steamcmd_user" == "--me" ]; then
sudo=
fi
read -p "Are you sure you want to uninstall the ARK Server Tools?" -n 1 -r
if [[ "$REPLY" =~ ^[Yy]$ ]]; then
if [ -n "${install_datadir}" -a -x "${install_datadir}/arkmanager-uninstall.sh" ]; then
$sudo "${install_datadir}/arkmanager-uninstall.sh"
exit 0
elif [ -n "${install_libexecdir}" -a -x "${install_libexecdir}/arkmanager-uninstall.sh" ]; then
$sudo "${install_libexecdir}/arkmanager-uninstall.sh"
exit 0
fi
fi
}
runAsRoot(){
getConfigVar(){
val="$(echo -ne "$(sed -n "/^$1=/{s|^[^=]*=||;s|[[:space:]]*\\(#.*\\)*\$||;s|^\"\\(.*\\)\"\$|\\1|;s|^'\\(.*\\)'\$|\\1|;p}" <"/etc/arkmanager/arkmanager.cfg" | tail -n1)")"
if [ -n "$val" ]; then
echo "$val"
else
echo "$2"
fi
}
arkstChannel="$(getConfigVar arkstChannel "master")"
install_bindir="$(getConfigVar install_bindir "${0%/*}")"
install_libexecdir="$(getConfigVar install_libexecdir "${install_bindir%/*}/libexec/arkmanager")"
install_datadir="$(getConfigVar install_datadir "${install_bindir%/*}/share/arkmanager")"
steamcmd_user="$(getConfigVar steamcmd_user "steam")"
if ! getent passwd "$steamcmd_user" >/dev/null 2>&1; then
echo "Invalid steamcmd_user in config file"
exit 1
fi
if [ "$1" == "upgrade-tools" ]; then
doUpgradeTools
elif [ "$1" == "uninstall-tools" ]; then
doUninstallTools
else
su "$steamcmd_user" -c "$(printf "%q" "$0")$(printf " %q" "$@")"
exit 1
fi
}
# Check the user is not currently running this script as root
if [ "$(id -u)" == "0" ]; then
runAsRoot "$@"
exit 0
fi
#---------------------
# Variables
#---------------------
# Global variables
if [ -f "/etc/arkmanager/arkmanager.cfg" ]; then
source /etc/arkmanager/arkmanager.cfg
fi
if [ -f "${HOME}/.arkmanager.cfg" ]; then
source "${HOME}/.arkmanager.cfg"
fi
lsof=lsof
if [ -x /usr/sbin/lsof ]; then
lsof=/usr/sbin/lsof
fi
# Local variables
instver=""
bnumber=""
GREEN="\\033[1;32m"
RED="\\033[1;31m"
YELLOW="\\e[0;33m"
NORMAL="\\033[0;39m"
maxOpenFiles=100000
# Set TERM to "dumb" if TERM is not set
export TERM=${TERM:-dumb}
arkmanagerLog="arkmanager.log" # here are logged the actions performed by arkmanager
arkserverLog="arkserver.log" # here is logged the output of ShooterGameServer
appid="${appid:-376030}"
mod_appid="${mod_appid:-346110}"
arkautorestartfile="${arkautorestartfile:-ShooterGame/Saved/.autorestart}"
install_bindir="${install_bindir:-${0%/*}}"
install_libexecdir="${install_libexecdir:-${install_bindir%/*}/libexec/arkmanager}"
if [ "$steamcmd_user" == "--me" ]; then
install_datadir="${install_datadir:-${HOME}/.share/local/arkmanager}"
else
install_datadir="${install_datadir:-${install_bindir%/*}/share/arkmanager}"
fi
#---------------------
# functions
#---------------------
#
# timestamp
#
timestamp() {
date +%T
}
#
# check configuration and report errors
#
checkConfig() {
# SteamCMD configuration
# steamcmdroot
if [ ! -d "$steamcmdroot" ] ; then
echo -e "[" "$RED" "ERROR" "$NORMAL" "]" "\tYour SteamCMD root seems not valid."
fi
# steamcmdexec
if [ ! -f "$steamcmdroot/$steamcmdexec" ] ; then
echo -e "[" "$RED" "ERROR" "$NORMAL" "]" "\tYour SteamCMD exec could not be found."
fi
# steamcmd_user
if [ "$steamcmd_user" != "--me" ]; then
if ! getent passwd $steamcmd_user > /dev/null 2>&1 ; then
echo -e "[" "$RED" "ERROR" "$NORMAL" "]" "\tYour SteamCMD user is not valid."
fi
fi
# Environment configuration
# arkserverexec
if [ ! -f "$arkserverroot/$arkserverexec" ] ; then
echo -e "[" "$YELLOW" "WARN" "$NORMAL" "]" "\tYour ARK server exec could not be found."
fi
# Service configuration
# logdir
if [ ! -w "$logdir" ] ; then
echo -e "[" "$RED" "ERROR" "$NORMAL" "]" "\tYou have not rights to write in the log directory."
fi
}
#
# Get setting from config or from ini file
# $1 is the setting name
# $2 is the default
#
getArkServerSetting() {
local varname="ark_$1"
if [ -n "${!varname}" ]; then
echo "${!varname}"
else
local val="$(tr -d '\0\376\377' <"${arkserverroot}/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini" | sed -n '/^\[ServerSettings\]/,/^\[.*\]/{s/^'"$1"'[[:space:]]*=[[:space:]]*//p;}' )"
if [ -n "$val" ]; then
echo "$val"
else
echo "$2"
fi
fi
}
#
# Get server admin password
#
getAdminPassword() {
getArkServerSetting "ServerAdminPassword" ""
}
#
# Get server RCON Port
#
getRconPort() {
getArkServerSetting "RCONPort" "32330"
}
#
# Get server Game Port
#
getGamePort() {
echo "${ark_Port:-7778}"
}
#
# Get server Query Port
#
getQueryPort(){
echo "${ark_QueryPort:-27015}"
}
#
# Execute RCON command
#
rconcmd() {
perl -MSocket -e '
sub sendpkt {
my ($sock, $reqid, $reqtype, $body) = @_;
my $packet = pack("VVV", length($body) + 10, $reqid, $reqtype) . $body . "\0\0";
send($sock, $packet, 0) or die "Error sending command to server";
}
sub recvpkt {
my ($sock) = @_;
my $data = "";
recv($sock, $data, 12, 0);
my ($pktlen, $resid, $restype) = unpack("VVV", $data);
recv($sock, $data, $pktlen - 8, 0);
return ($resid, $restype, substr($data, 0, $pktlen - 10));
}
sub auth {
my ($sock, $password) = @_;
my $reqid = 1;
sendpkt($sock, $reqid, 3, $password);
my ($resid, $restype, $rcvbody) = recvpkt($sock);
die "Authentication failed" if $resid == -1;
}
my $port = $ARGV[0];
my $ipaddr = $ARGV[1];
my $password = $ARGV[2];
my $command = $ARGV[3];
socket(my $socket, PF_INET, SOCK_STREAM, 0);
setsockopt($socket, SOL_SOCKET, SO_RCVTIMEO, pack("i4", 30, 0, 0, 0));
my $sockaddr = pack_sockaddr_in($port, inet_aton($ipaddr));
connect($socket, $sockaddr) or die "Error connecting to server";
auth($socket, $password);
sendpkt($socket, 2, 2, $command);
my ($resid, $restype, $rcvbody) = recvpkt($socket);
print $rcvbody, "\n";
' "$(getRconPort)" "${ark_MultiHome:-127.0.0.1}" "$(getAdminPassword)" "$1"
}
#
# Save world
#
doSaveWorld() {
rconcmd saveworld
}
#
# Exit cleanly
#
doExitServer() {
rconcmd doexit
}
#
# Broadcast message
#
doBroadcast(){
rconcmd "broadcast $1" >/dev/null
}
#
# Broadcast message with echo
#
doBroadcastWithEcho(){
echo "$1"
doBroadcast "$1"
}
#
# SteamCMD helper function
#
function runSteamCMD(){
"$steamcmdroot/$steamcmdexec" +@NoPromptForPassword 1 +login ${steamlogin:-anonymous} "$@" +quit
}
#
# Check if a new version is available but not apply it
#
function checkForUpdate(){
tput sc
echo "Querying Steam database for latest version..."
if isUpdateNeeded; then
tput rc; tput ed;
echo -e "Current version:" "$RED" $instver "$NORMAL"
echo -e "Available version:" "$GREEN" $bnumber "$NORMAL"
echo -e "Your server needs to be restarted in order to receive the latest update."
echo -e "Run \"arkmanager update\" to do so"
return 1
else
tput rc; tput ed;
echo -e "Current version:" "$GREEN" $instver "$NORMAL"
echo -e "Available version:" "$GREEN" $bnumber "$NORMAL"
echo "Your server is up to date!"
return 0
fi
}
#
# Check if the server need to be updated
# Return 0 if update is needed, else return 1
#
function isUpdateNeeded(){
getCurrentVersion
getAvailableVersion
if [[ "$bnumber" == "Unknown" || "$bnumber" -eq "$instver" ]]; then
return 1 # no update needed
else
return 0 # update needed
fi
}
#
# Parse an ACF structure
# $1 is the desired path
# $2 is the desired property
# $3 is the current path
#
function parseSteamACF(){
local sname
while read name val; do
name="${name#\"}"
name="${name%\"}"
val="${val#\"}"
val="${val%\"}"
if [ "$name" = "}" ]; then
break
elif [ "$name" == "{" ]; then
parseSteamACF "$1" "$2" "${3}.${sname}"
else
if [ "$3" == "$1" -a "$name" == "$2" ]; then
echo "$val"
break
fi
sname="${name}"
fi
done
}
#
# Return the current version number
#
function getCurrentVersion(){
if [ -f "${arkserverroot}/steamapps/appmanifest_${appid}.acf" ]; then
instver=`while read name val; do if [ "${name}" == "{" ]; then parseSteamACF "" "buildid"; break; fi; done <"${arkserverroot}/steamapps/appmanifest_${appid}.acf"`
echo $instver > "$arkserverroot/arkversion"
else
instver=""
fi
}
#
# Get the current available server version on steamdb
#
function getAvailableVersion(){
rm -f "$steamcmd_appinfocache"
bnumber=`runSteamCMD +app_info_update 1 +app_info_print "$appid" +quit | while read name val; do if [ "${name}" == "{" ]; then parseSteamACF ".depots.branches.public" "buildid"; break; fi; done`
if [ -z "$bnumber" ]; then
bnumber="Unknown"
fi
}
#
# Get the PID of the server process
#
function getServerPID(){
ps -ef | grep "$arkserverroot/$arkserverexec" | grep -v grep | awk '{print $2}'
}
#
# Check id the server process is alive
#
function isTheServerRunning(){
if [ -n "`getServerPID`" ]; then
return 0
else
return 1
fi
}
#
# Check if the server is up
#
#
function isTheServerUp(){
$lsof -i "${ark_MultiHome:+udp@}${ark_MultiHome}:$(getGamePort)" > /dev/null
result=$?
if [ $result -ne 0 ]; then
perl -MSocket -MFcntl -e '
my $port = int($ARGV[0]);
socket(my $socket, PF_INET, SOCK_DGRAM, 0);
setsockopt($socket, SOL_SOCKET, SO_RCVTIMEO, pack("i4", 1, 0, 0, 0));
my $sockaddr = pack_sockaddr_in($port, inet_aton($ARGV[1]));
send($socket, "\xff\xff\xff\xffTSource Engine Query\x00", 0, $sockaddr);
my $flags = fcntl($socket, F_GETFL, 0) or exit(1);
fcntl($socket, F_SETFL, $flags | O_NONBLOCK) or exit(1);
my $data = "";
my $rin = "";
vec($rin, fileno($socket), 1) = 1;
if (select($rin, undef, undef, 0.25) >= 0) {
recv($socket, $data, 1400, 0) or exit(1);
my ($servername, $mapname, $game, $fullname, $rest) = split(/\x00/, substr($data, 6), 5);
my $maxplayers = ord(substr($rest, 3, 1));
if ($maxplayers == 0) { exit(1); }
exit(0);
} else {
exit(1);
}
' "$(getQueryPort)" "${ark_MultiHome:-127.0.0.1}"
result=$?
fi
# In this case, the result is:
# 1 if the command fail. The port is not listenning
# 0 if the command succeed. The port is listenning
if [ $result -eq 0 ];then
return 1
else
return 0
fi
}
#
# Check if the server is visible in the steam server list
#
function isTheServerOnline(){
if [ -n "$ark_MultiHome" ]; then
publicip="$(curl --interface "${ark_MultiHome}" -s https://api.ipify.org/)"
else
publicip="$(curl -s https://api.ipify.org/)"
fi
local serverresp
if [[ "$publicip" =~ [1-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]* ]]; then
serverresp="$(curl -s "http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=${publicip}:$(getQueryPort)")"
fi
# If the Steam server response contains "addr": "$ip:$port",
# then the server has registered with the Steam master server
if [[ "$serverresp" =~ \"addr\":\ \"([^\"]*):([0-9]*)\" ]]; then
return 0
else
return 1
fi
}
#
# Check if anybody is connected to the server
#
function numPlayersConnected(){
perl -MSocket -e '
my $port = int($ARGV[0]);
socket(my $socket, PF_INET, SOCK_DGRAM, 0);
setsockopt($socket, SOL_SOCKET, SO_RCVTIMEO, pack("i4", 1, 0, 0, 0));
my $sockaddr = pack_sockaddr_in($port, inet_aton($ARGV[1]));
send($socket, "\xff\xff\xff\xffTSource Engine Query\x00", 0, $sockaddr);
my $data = "";
recv($socket, $data, 1400, 0) or (print "0" and exit(1));
my ($servername, $mapname, $game, $fullname, $rest) = split(/\x00/, substr($data, 6), 5);
my $players = ord(substr($rest, 2, 1));
print "$players\n";
' "${ark_QueryPort}" "${ark_MultiHome:-127.0.0.1}"
}
#
# run function
#
doRun() {
cd "$arkserverroot"
arkserveropts="$serverMap"
if [ -n "$serverMapModId" ]; then
arkserveropts="-MapModID=$serverMapModId"
fi
if [ -z "$arkserveropts" ]; then
arkserveropts="TheIsland"
fi
arkextraopts=( )
# bring in ark_... options
for varname in "${!ark_@}"; do
name="${varname#ark_}"
val="${!varname}"
# Port is actually one higher than specified
# i.e. specifying port 7777 will have the server
# use port 7778
if [ "$name" == "Port" ]; then
(( val = val - 1 ))
fi
if [ -n "$val" ]; then
arkserveropts="${arkserveropts}?${name}=${val}"
else
arkserveropts="${arkserveropts}?${name}"
fi
done
# bring in arkflag_... flags
for varname in "${!arkflag_@}"; do
name="${varname#arkflag_}"
arkextraopts=( "${arkextraopts[@]}" "-${name}" )
done
# bring in arkopt_... options
for varname in "${!arkopt_@}"; do
name="${varname#arkopt_}"
val="${!varname}"
if [ -n "$val" ]; then
arkextraopts=( "${arkextraopts[@]}" "-${name}=${val}" )
fi
done
arkserveropts="${arkserveropts}?listen"
# run the server in background
echo "`timestamp`: start"
# set max open files limit before we start the server
ulimit -n $maxOpenFiles
serverpid=0
restartserver=1
# Shutdown the server when we are terminated
shutdown_server(){
restartserver=0
rm "$arkserverroot/$arkautorestartfile"
if [ "$serverpid" -ne 0 ]; then
kill -INT $serverpid
fi
}
trap shutdown_server INT TERM
# Auto-restart loop
while [ $restartserver -ne 0 ]; do
echo -n "`timestamp`: Running"
printf " %q" "$arkserverroot/$arkserverexec" "$arkserveropts" "${arkextraopts[@]}"
echo
# Put the server process into the background so we can monitor it
"$arkserverroot/$arkserverexec" "$arkserveropts" "${arkextraopts[@]}" &
# Grab the server PID
serverpid=$!
echo "`timestamp`: Server PID: $serverpid"
# Disable auto-restart so we don't get caught in a restart loop
rm -f "$arkserverroot/$arkautorestartfile"
restartserver=0
sleep 5
while true; do
# Grab the current server PID
local pid="`getServerPID`"
if [ "$pid" == "$serverpid" ]; then
if [ "$restartserver" -eq 0 ]; then
# Check if the server has fully started
if ! isTheServerUp; then
# Enable auto-restart if the server is up
echo "`timestamp`: server is up"
touch "$arkserverroot/$arkautorestartfile"
restartserver=1
fi
fi
else
echo "`timestamp`: Bad PID '$pid'; expected '$serverpid'"
if [ "$pid" != "" ]; then
# Another instance must be running - disable autorestart
restartserver=0
fi
break
fi
sleep 5
done
# Wait on the now-dead process to reap it and get its return status
wait $serverpid
echo "`timestamp`: exited with status $?"
# doStop will remove the autorestart file
if [ ! -f "$arkserverroot/$arkautorestartfile" ]; then
restartserver=0
fi
if [ "$restartserver" -ne 0 ]; then
echo "`timestamp`: restarting server"
fi
done
}
#
# start function
#
doStart() {
if isTheServerRunning; then
echo "The server is already running"
else
tput sc
echo "The server is starting..."
doRun </dev/null >>"$logdir/$arkserverLog" 2>&1 & # output of this command is logged
echo "`timestamp`: start" >> "$logdir/$arkmanagerLog"
tput rc; tput ed;
echo "The server is now up"
fi
}
#
# starts all servers specified by configfile_xxxxx in config file
#
doStartAll(){
doStart
for cfg in "${!configfile_@}"; do
if [ -f "${!cfg}" ]; then
(
source "${!cfg}"
doStart
)
fi
done
}
#
# stop the ARK server
#
doStop() {
if isTheServerRunning; then
if [ " $* " =~ " --warn " ]; then
doWarn "$1"
fi
if [ " $* " =~ " --saveworld " ]; then
doSaveWorld
fi
tput sc
echo "Stopping server..."
echo "`timestamp`: stopping" >> "$logdir/$arkmanagerLog"
rm -f "$arkserverroot/$arkautorestartfile"
# kill the server with the PID
PID=`getServerPID`
kill -INT $PID
for (( i = 0; i < 20; i++ )); do
sleep 1
if ! isTheServerRunning; then
break
fi
done
if isTheServerRunning; then
tput rc
echo "Killing server..."
kill -KILL $PID
fi
tput rc; tput ed;
echo "The server has been stopped"
echo "`timestamp`: stopped" >> "$logdir/$arkmanagerLog"
else
echo "The server is already stopped"
fi
}
#
# stops all servers specified by configfile_xxxxx in config file
#
doStopAll(){
doStop
for cfg in "${!configfile_@}"; do
if [ -f "${!cfg}" ]; then
(
source "${!cfg}"
doStop
)
fi
done
}
#
# install / update / download update
#
runSteamCMDAppUpdate(){
runSteamCMD +force_install_dir "$1" +app_update $appid $2
}
#
# install of ARK server
#
doInstall() {
# Check if arkserverroot already exists
if [ ! -d "$arkserverroot" ]; then
# If it does not exist, try create it
echo -e "Creating the ARK server root directory ($arkserverroot)"
mkdir -p "$arkserverroot"
if [ ! $? ] ; then
echo -e "[" "$RED" "ERROR" "$NORMAL" "]" "\tFailed to create the defined ARK server root directory ($arkserverroot)"
exit 1
fi
fi
cd "$steamcmdroot"
# install the server
runSteamCMDAppUpdate "$arkserverroot" validate
# the current version should be the last version. We set our version
getCurrentVersion
}
#
# Waits for a configurable number of minutes before updating the server
#
doWarn(){
cd "$arkserverroot"
local warnmsgmin
local warnmsgsec
if [ "$1" == "update" ]; then
if [ -n "$msgWarnUpdateMinutes" ]; then
warnmsgmin="$msgWarnUpdateMinutes"
else
warnmsgmin="This ARK server will shutdown for an update in %d minutes"
fi
if [ -n "$msgWarnUpdateSeconds" ]; then
warnmsgsec="$msgWarnUpdateSeconds"
else
warnmsgsec="This ARK server will shutdown for an update in %d seconds"
fi
elif [ "$1" == "restart" ]; then
if [ -n "$msgWarnRestartMinutes" ]; then
warnmsgmin="$msgWarnRestartMinutes"
else
warnmsgmin="This ARK server will shutdown for a restart in %d minutes"
fi
if [ -n "$msgWarnRestartSeconds" ]; then
warnmsgsec="$msgWarnRestartSeconds"
else
warnmsgsec="This ARK server will shutdown for a restart in %d seconds"
fi
else
if [ -n "$msgWarnShutdownMinutes" ]; then
warnmsgmin="$msgWarnShutdownMinutes"
else
warnmsgmin="This ARK server will shutdown in %d minutes"
fi
if [ -n "$msgWarnShutdownSeconds" ]; then
warnmsgsec="$msgWarnShutdownSeconds"
else
warnmsgsec="This ARK server will shutdown in %d seconds"
fi
fi
local pid=`getServerPID`
local sleeppid
if [ -n "$pid" ]; then
local warnmsg
local warnminutes=$(( arkwarnminutes ))
if (( warnminutes == 0 )); then
warnminutes=60
fi
local warnintervals=( 90 60 45 30 20 15 10 5 4 3 2 )
for warninterval in "${warnintervals[@]}"; do
if [ "`getServerPID`" != "$pid" ]; then
echo "Server has stopped. Aborting $1"
return 1
fi
if (( warnminutes > warninterval )); then
sleep 1m &
sleeppid=$!
warnmsg="$(printf "$warnmsgmin" "$warnminutes")"
doBroadcastWithEcho "$warnmsg"
for (( min = warnminutes - 1; min >= warninterval; min-- )); do
numplayers=$(numPlayersConnected)
if (( numplayers + 0 == 0 )); then
echo "Nobody is connected. Shutting down immediately"
return 0
fi
wait $sleeppid
if (( $min > $warninterval )); then
sleep 1m &
sleeppid=$!
fi
done
warnminutes=$warninterval
fi
done
local warnseconds=120
warnintervals=( 90 60 45 30 20 15 10 5 0 )
for warninterval in "${warnintervals[@]}"; do
sleep $(( warnseconds - warninterval ))s &
sleeppid=$!
if [ "`getServerPID`" != "$pid" ]; then
echo "Server has stopped. Aborting update"
return 1
fi
warnmsg="$(printf "$warnmsgsec" "$warnseconds")"
doBroadcastWithEcho "$warnmsg"
if (( warnseconds >= 20 )); then
numplayers=$(numPlayersConnected)
if (( numplayers + 0 == 0 )); then
echo "Nobody is connected. Shutting down immediately"
return 0
fi
fi
wait $sleeppid
warnseconds=$warninterval
done
fi
if [ "`getServerPID`" != "$pid" ]; then
echo "Server has stopped. Aborting $1"
return 1
fi
return 0
}
#
# Stop the server, update it and then start it back.
#
doUpdate() {
local appupdate=
local updatetype=normal
local validate=
local modupdate=
local saveworld=
local downloadonly=
for arg in "$@"; do
if [ "$arg" == "--force" ]; then
appupdate=1
elif [ "$arg" == "--safe" ]; then
updatetype=safe
elif [ "$arg" == "--warn" ]; then
updatetype=warn
elif [ "$arg" == "--ifempty" ]; then
updatetype=ifempty
elif [ "$arg" == "--validate" ]; then
validate=validate
appupdate=1
elif [ "$arg" == "--saveworld" ]; then
saveworld=1
elif [ "$arg" == "--update-mods" ]; then
modupdate=1
elif [ "$arg" == "--backup" ]; then
arkBackupPreUpdate=true
elif [[ "$arg" =~ "^--stagingdir=" ]]; then
arkStagingDir="${ark#--stagingdir=}"
elif [ "$arg" == "--downloadonly" ]; then
downloadonly=1
else
echo "Unrecognized option $arg"
echo "Try 'arkmanager -h' or 'arkmanager --help' for more information."
exit 1
fi
done
echo "$$" >"${arkserverroot}/.ark-update.lock.$$"
while true; do
if ! ln "${arkserverroot}/.ark-update.lock.$$" "${arkserverroot}/.ark-update.lock"; then
local lockpid="$(<"${arkserverroot}/.ark-update.lock")"
if [ -n "$lockpid" ] && [ "$lockpid" != "$$" ] && kill -0 "$lockpid"; then
echo "Update already in progress (PID: $lockpid)"
rm -f "${arkserverroot}/.ark-update.lock.$$"
return 1
fi
rm -f "${arkserverroot}/.ark-update.lock"
else
break
fi
done
rm -f "${arkserverroot}/.ark-update.lock.$$"
if [ -n "$modupdate" ]; then
if ! doDownloadAllMods; then
modupdate=
fi
if ! isAnyModUpdateNeeded; then
modupdate=
fi
fi
cd "$arkserverroot"
if isUpdateNeeded; then
appupdate=1
if [ -n "${arkStagingDir}" -a "${arkStagingDir}" != "${arkserverroot}" ]; then
if [ ! -d "$arkStagingDir/ShooterGame" ]; then
echo "Copying to staging directory"
mkdir -p "$arkStagingDir"
if [ "$(stat -c "%d" "$arkserverroot")" == "$(stat -c "%d" "$arkStagingDir")" ]; then
cp -al "$arkserverroot/ShooterGame/." "$arkStagingDir/ShooterGame"
cp -al "$arkserverroot/Engine/." "$arkStagingDir/Engine"
cp -al "$arkserverroot/linux64/." "$arkStagingDir/linux64"
cp -al "$arkserverroot/PackageInfo.bin" "$arkStagingDir/PackageInfo.bin"
cp -al "$arkserverroot/steamclient.so" "$arkStagingDir/steamclient.so"
cp -a "$arkserverroot/steamapps/." "$arkStagingDir/steamapps"
else
rsync -a "$arkserverroot/." "$arkStagingDir/."
fi
rm -rf "$arkStagingDir/ShooterGame/Content/Mods/"*
rm -rf "$arkStagingDir/ShooterGame/Saved/"*
fi
echo "Downloading ARK update"
cd "$steamcmdroot"
runSteamCMDAppUpdate "$arkStagingDir" $validate
if [ -d "${arkStagingDir}/steamapps/downloading/${appid}" ]; then
echo "Update download interrupted"
return 1
fi
fi
fi
if [ -n "$downloadonly" ]; then
if [ -n "$appupdate" -a -n "$arkStagingDir" -a "$arkStagingDir" != "$arkserverroot" ]; then
echo "Server update downloaded"
fi
if [ -n "$modupdate" ]; then
echo "Mod update downloaded"
fi
echo "Not applying update - download-only enabled"
elif [ -n "$appupdate" -o -n "$modupdate" ]; then
if isTheServerRunning; then
if [ "$updatetype" == "safe" ]; then
while [ ! `find $arkserverroot/ShooterGame/Saved/SavedArks -mmin -1 -name ${serverMap##*/}.ark` ]; do
echo "`timestamp`: Save file older than 1 minute. Delaying update." >> "$logdir/update.log"
sleep 30s
done
echo "`timestamp`: Save file newer than 1 minute. Performing an update." >> "$logdir/update.log"
elif [ "$updatetype" == "warn" ]; then
if ! doWarn update; then
return 1
fi
elif [ "$updatetype" == "ifempty" ]; then
numplayers=$(( $(numPlayersConnected) + 0 ))
if (( numplayers == 0 )); then
echo "${numplayers} players are still connected"
return 1
fi
fi
fi
# check if the server was alive before the update so we can launch it back after the update
serverWasAlive=0
if isTheServerRunning ;then
serverWasAlive=1
fi
if [ -n "$saveworld" ]; then
echo "Saving world"
doSaveWorld
fi
doStop
# If user wants to back-up, we do it here.
if [ "$arkBackupPreUpdate" == "true" ]; then
doBackup
fi
if [ -n "$appupdate" ]; then
if [ -d "${arkStagingDir}" -a "${arkStagingDir}" != "${arkserverroot}" ]; then
echo "Applying update from staging directory"
if [ "$(stat -c "%d" "$arkserverroot")" == "$(stat -c "%d" "$arkStagingDir")" ]; then
cp -alu --remove-destination "$arkStagingDir/ShooterGame/." "$arkserverroot/ShooterGame"
cp -alu --remove-destination "$arkStagingDir/Engine/." "$arkserverroot/Engine"
cp -alu --remove-destination "$arkStagingDir/linux64/." "$arkserverroot/linux64"
cp -alu --remove-destination "$arkStagingDir/PackageInfo.bin" "$arkserverroot/PackageInfo.bin"
cp -alu --remove-destination "$arkStagingDir/steamclient.so" "$arkserverroot/steamclient.so"
cp -au --remove-destination "$arkStagingDir/steamapps/." "$arkserverroot/steamapps"
else
rsync -a "$arkStagingDir/." "$arkserverroot"
fi
cd "$arkserverroot"
find Engine ShooterGame linux64 -depth -print |
grep -v '^ShooterGame/\(Saved\|Content/Mods\)' |
while read f; do
if [ ! -e "staging/${f}" ]; then
if [ -f "$f" ]; then
rm "${f}"
else
rmdir "${f}"
fi
fi
done
else
echo "Performing ARK update"
cd "$steamcmdroot"
runSteamCMDAppUpdate "$arkserverroot" $validate
fi
# the current version should be the last version. We set our version
getCurrentVersion
echo "`timestamp`: update to $instver complete" >> "$logdir/update.log"
fi
if [ -n "$modupdate" ]; then
for modid in $(getModIds); do
if isModUpdateNeeded $modid; then
echo "Updating mod $modid"
doExtractMod $modid
echo "`timestamp`: Mod $modid updated" >> "$logdir/update.log"
fi
done
fi
# we restart the server only if it was started before the update
if [ $serverWasAlive -eq 1 ]; then
doStart
fi
else
echo "Your server is already up to date! The most recent version is ${bnumber}."
echo "`timestamp`: No update needed." >> "$logdir/update.log"
fi;
rm -f "${arkserverroot}/.ark-update.lock"
}
#
# Get the Mod IDs of the installed mods and the requested mods
#
getModIds(){
(
echo "${serverMapModId}"
echo "${ark_TotalConversionMod}"
echo "${ark_GameModIds}" | tr ',' '\n'
find "${arkserverroot}/ShooterGame/Content/Mods" -maxdepth 1 -type d -printf "%P\n"
) | sort | uniq | grep '^[1-9][0-9]*$'
}
#
# Downloads a mod from the Steam workshop
#
doDownloadMod(){
local modid=$1
local modsrcdir="$steamcmdroot/steamapps/workshop/content/$mod_appid/$modid"
local moddldir="$steamcmdroot/steamapps/workshop/downloads/$mod_appid/$modid"
local dlsize=0
cd "$steamcmdroot"
while true; do
echo "Downloading mod $modid"
runSteamCMD +workshop_download_item $mod_appid $modid
echo
echo "Checking mod $modid"
if [ ! -d "$moddldir" ]; then break; fi
local newsize="`du -s "$moddldir/.." | cut -f1`"
if [ $newsize -eq $dlsize ]; then break; fi
dlsize=$newsize
echo "Mod $modid not fully downloaded - retrying"
done
if [ -f "$modsrcdir/mod.info" ]; then
echo "Mod $modid downloaded"
return 0
else
echo "Mod $modid was not successfully downloaded"
return 1
fi
}
#
# Downloads all installed and requested mods from the Steam workshop
#
doDownloadAllMods(){
for modid in $(getModIds); do
doDownloadMod $modid || return 1
done
}
#
# Checks if the files a mod owns need to be updated
#
isModUpdateNeeded(){
local modid=$1
local modsrcdir="$steamcmdroot/steamapps/workshop/content/$mod_appid/$modid"
local moddestdir="$arkserverroot/ShooterGame/Content/Mods/$modid"
local modbranch="${mod_branch:-Linux}"
for varname in "${!mod_branch_@}"; do
if [ "mod_branch_$modid" == "$varname" ]; then
modbranch="${!varname}"
fi
done
if [ \( ! -f "$moddestdir/.modbranch" \) ] || [ "$(<"$moddestdir/.modbranch")" != "$modbranch" ]; then
return 0
fi
if [ -f "$modsrcdir/mod.info" ]; then
if [ -f "$modsrcdir/${modbranch}NoEditor/mod.info" ]; then
modsrcdir="$modsrcdir/${modbranch}NoEditor"
fi
while read f; do
if [ \( ! -f "$moddestdir/${f%.z}" \) -o "$modsrcdir/$f" -nt "$moddestdir/${f%.z}" ]; then
return 0
fi
done < <(find "$modsrcdir" -type f ! -name "*.z.uncompressed_size" -printf "%P\n")
fi
return 1
}
#
# Checks if any installed or requested mods need to be updated
#
isAnyModUpdateNeeded(){
for modid in $(getModIds); do
if isModUpdateNeeded $modid; then
return 0
fi
done
return 1
}
#
# Extracts a mod into the ARK Mods directory
#
doExtractMod(){
local modid=$1
local modsrcdir="$steamcmdroot/steamapps/workshop/content/$mod_appid/$modid"
local moddestdir="$arkserverroot/ShooterGame/Content/Mods/$modid"
local modbranch="${mod_branch:-Windows}"
for varname in "${!mod_branch_@}"; do
if [ "mod_branch_$modid" == "$varname" ]; then
modbranch="${!varname}"
fi
done
if [ \( ! -f "$moddestdir/.modbranch" \) ] || [ "$(<"$moddestdir/.modbranch")" != "$modbranch" ]; then
rm -rf "$moddestdir"
fi
if [ -f "$modsrcdir/mod.info" ]; then
echo "Copying files to $moddestdir"
if [ -f "$modsrcdir/${modbranch}NoEditor/mod.info" ]; then
modsrcdir="$modsrcdir/${modbranch}NoEditor"
fi
find "$modsrcdir" -type d -printf "$moddestdir/%P\0" | xargs -0 -r mkdir -p
find "$modsrcdir" -type f ! \( -name '*.z' -or -name '*.z.uncompressed_size' \) -printf "%P\n" | while read f; do
if [ \( ! -f "$moddestdir/$f" \) -o "$modsrcdir/$f" -nt "$moddestdir/$f" ]; then
printf "%10d %s " "`stat -c '%s' "$modsrcdir/$f"`" "$f"
cp "$modsrcdir/$f" "$moddestdir/$f"
echo -ne "\r\\033[K"
fi
done
find "$modsrcdir" -type f -name '*.z' -printf "%P\n" | while read f; do
if [ \( ! -f "$moddestdir/${f%.z}" \) -o "$modsrcdir/$f" -nt "$moddestdir/${f%.z}" ]; then
printf "%10d %s " "`stat -c '%s' "$modsrcdir/$f"`" "${f%.z}"
perl -M'Compress::Raw::Zlib' -e '
my $sig;
read(STDIN, $sig, 8) or die "Unable to read compressed file";
if ($sig != "\xC1\x83\x2A\x9E\x00\x00\x00\x00"){
die "Bad file magic";
}
my $data;
read(STDIN, $data, 24) or die "Unable to read compressed file";
my ($chunksizelo, $chunksizehi,
$comprtotlo, $comprtothi,
$uncomtotlo, $uncomtothi) = unpack("(LLLLLL)<", $data);
my @chunks = ();
my $comprused = 0;
while ($comprused < $comprtotlo) {
read(STDIN, $data, 16) or die "Unable to read compressed file";
my ($comprsizelo, $comprsizehi,
$uncomsizelo, $uncomsizehi) = unpack("(LLLL)<", $data);
push @chunks, $comprsizelo;
$comprused += $comprsizelo;
}
foreach my $comprsize (@chunks) {
read(STDIN, $data, $comprsize) or die "File read failed";
my ($inflate, $status) = new Compress::Raw::Zlib::Inflate();
my $output;
$status = $inflate->inflate($data, $output, 1);
if ($status != Z_STREAM_END) {
die "Bad compressed stream; status: " . ($status);
}
if (length($data) != 0) {
die "Unconsumed data in input"
}
print $output;
}
' <"$modsrcdir/$f" >"$moddestdir/${f%.z}"
touch -c -r "$modsrcdir/$f" "$moddestdir/${f%.z}"
echo -ne "\r\\033[K"
fi
done
perl -e '
my $data;
{ local $/; $data = <STDIN>; }
my $mapnamelen = unpack("@0 L<", $data);
my $mapname = substr($data, 4, $mapnamelen - 1);
$mapnamelen += 4;
my $mapfilelen = unpack("@" . ($mapnamelen + 4) . " L<", $data);
my $mapfile = substr($data, $mapnamelen + 8, $mapfilelen);
print pack("L< L< L< Z8 L< C L< L<", $ARGV[0], 0, 8, "ModName", 1, 0, 1, $mapfilelen);
print $mapfile;
print "\x33\xFF\x22\xFF\x02\x00\x00\x00\x01";
' $modid <"$moddestdir/mod.info" >"$moddestdir/.mod"
if [ -f "$moddestdir/modmeta.info" ]; then
cat "$moddestdir/modmeta.info" >>"$moddestdir/.mod"
else
echo -ne '\x01\x00\x00\x00\x08\x00\x00\x00ModType\x00\x02\x00\x00\x001\x00' >>"$moddestdir/.mod"
fi
echo "$modbranch" >"$moddestdir/.modbranch"
fi
}
#
# Downloads mod and installs it into mods directory
#
doInstallMod(){
local modid=$1
if [ -f "$steamcmdroot/steamapps/workshop/appworkshop_${mod_appid}.acf" ]; then
sed -i "/^\\t\\t\"${modid}\"/,/^\\t\\t}/d" "$steamcmdroot/steamapps/workshop/appworkshop_${mod_appid}.acf"
fi
if doDownloadMod $modid; then
doExtractMod $modid
echo "Mod $modid installed"
fi
}
#
# Copies server state to a backup directory
#
doBackup(){
local datestamp=`date +"%Y-%m-%d_%H.%M.%S"`
local daystamp=`date +"%Y-%m-%d"`
local backupdir="${arkbackupdir}/${datestamp}"
local backupdirdaily="${arkbackupdir}/${daystamp}"
local savedir="SavedArks"
mkdir -p "$backupdir"
mkdir -p "$backupdirdaily"
# extract the map name from the active map mod
if [ -n "$serverMapModId" ]; then
serverMap="$(perl -e '
my $data;
{ local $/; $data = <>; }
my $mapnamelen = unpack("@0 L<", $data);
my $mapname = substr($data, 4, $mapnamelen - 1);
$mapnamelen += 4;
my $mapfilelen = unpack("@" . ($mapnamelen + 4) . " L<", $data);
my $mapfile = substr($data, $mapnamelen + 8, $mapfilelen - 1);
print $mapfile;
' <"${arkserverroot}/ShooterGame/Content/Mods/${serverMapModId}/mod.info")"
fi
# Get save directory name
if [ -n "${ark_AltSaveDirectoryName}" ]; then
savedir="${ark_AltSaveDirectoryName}"
fi
# ARK server uses Write-Unlink-Rename
echo -ne "${NORMAL} Copying ARK world file "
cp -p "${arkserverroot}/ShooterGame/Saved/${savedir}/${serverMap##*/}.ark" "${backupdir}/${serverMap##*/}.ark"
if [ ! -f "${backupdir}/${serverMap##*/}.ark" ]; then
sleep 2
cp -p "${arkserverroot}/ShooterGame/Saved/${savedir}/${serverMap##*/}.ark" "${backupdir}/${serverMap##*/}.ark"
fi
# If both attempts fail, server may have
# crashed between unlink and rename
if [ ! -f "${backupdir}/${serverMap##*/}.ark" ]; then
cp -p "${arkserverroot}/ShooterGame/Saved/${savedir}/${serverMap##*/}.tmp" "${backupdir##*/}/${serverMap##*/}.ark"
fi
if [ -f "${backupdir}/${serverMap##*/}.ark" ]; then
echo -e "${NORMAL}\e[68G[ ${GREEN}OK${NORMAL} ]"
else
echo -e "${NORMAL}\e[68G[ ${RED}FAILED${NORMAL} ]"
fi
# ARK server uses Lock-Truncate-Write-Unlock
# Unfortunately we can't lock the file, as
# ARK server uses a non-blocking lock and will
# fail to update the file if the lock fails.
echo -e "${NORMAL} Copying ARK profile files"
for f in "${arkserverroot}/ShooterGame/Saved/${savedir}/"*.arkprofile; do
echo -ne "${NORMAL} ${f##*/} "
cp -p "${f}" "${backupdir}/${f##*/}"
if [ ! -s "${backupdir}/${f##*/}" ]; then
sleep 2
cp -p "${f}" "${backupdir}/${f##*/}"
fi
# If both attempts fail, server may have
# crashed between truncate and write
if [ ! -s "${backupdir}/${f##*/}" ]; then
cp -p "${f%.arkprofile}.tmpprofile" "${backupdir}/${f##*/}"
fi
if [ -s "${backupdir}/${f##*/}" ]; then
echo -e "${NORMAL}\e[68G[ ${GREEN}OK${NORMAL} ]"
else
echo -e "${NORMAL}\e[68G[ ${RED}FAILED${NORMAL} ]"
fi
done
# ARK server uses Lock-Truncate-Write-Unlock
echo -e "${NORMAL} Copying ARK tribe files "
for f in "${arkserverroot}/ShooterGame/Saved/${savedir}/"*.arktribe; do
echo -ne "${NORMAL} ${f##*/} "
cp -p "${f}" "${backupdir}/${f##*/}"
if [ ! -s "${backupdir}/${f##*/}" ]; then
sleep 2
cp -p "${f}" "${backupdir}/${f##*/}"
fi
# If both attempts fail, server may have
# crashed between truncate and write
if [ ! -s "${backupdir}/${f##*/}" ]; then
cp -p "${f%.arktribe}.tmptribe" "${backupdir}/${f##*/}"
fi
if [ -s "${backupdir}/${f##*/}" ]; then
echo -e "${NORMAL}\e[68G[ ${GREEN}OK${NORMAL} ]"
else
echo -e "${NORMAL}\e[68G[ ${RED}FAILED${NORMAL} ]"
fi
done
# ARK server uses Lock-Truncate-Write-Unlock
echo -ne "${NORMAL} Copying GameUserSettings.ini "
cp -p "${arkserverroot}/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini" "${backupdir}/GameUserSettings.ini"
if [ ! -s "${backupdir}/GameUserSettings.ini" ]; then
sleep 2
cp -p "${f}" "${backupdir}/${f##*/}"
fi
if [ -f "${backupdir}/GameUserSettings.ini" ]; then
echo -e "${NORMAL}\e[68G[ ${GREEN}OK${NORMAL} ]"
else
echo -e "${NORMAL}\e[68G[ ${RED}FAILED${NORMAL} ]"
fi
echo -ne "${NORMAL} Copying Game.ini "
cp -p "${arkserverroot}/ShooterGame/Saved/Config/LinuxServer/Game.ini" "${backupdir}/Game.ini"
if [ ! -s "${backupdir}/Game.ini" ]; then
sleep 2
cp -p "${f}" "${backupdir}/${f##*/}"
fi
if [ -f "${backupdir}/Game.ini" ]; then
echo -e "${NORMAL}\e[68G[ ${GREEN}OK${NORMAL} ]"
else
echo -e "${NORMAL}\e[68G[ ${RED}FAILED${NORMAL} ]"
fi
#Tar the files and remove the original Backup Directory. Saves about 50MB of disk space per backup
echo -ne "${NORMAL} Compressing Backup "
tar -jcf "${arkbackupdir}/${daystamp}/${datestamp}.tar.bz2" -C "${arkbackupdir}" "${datestamp}"
rm -rf ${backupdir}
if [ -f "${arkbackupdir}/${daystamp}/${datestamp}.tar.bz2" ]; then
echo -e "${NORMAL}\e[68G[ ${GREEN}OK${NORMAL} ]"
else
echo -e "${NORMAL}\e[68G[ ${RED}FAILED${NORMAL} ]"
fi
echo -e "${NORMAL} Created Backup: ${GREEN} ${datestamp}.tar.bz2${NORMAL}"
}
#
# Print the status of the server (running? online? version?)
#
printStatus(){
if isTheServerRunning ;then
echo -e "$NORMAL" "Server running: " "$GREEN" "Yes" "$NORMAL"
else
echo -e "$NORMAL" "Server running: " "$RED" "No" "$NORMAL"
fi
if isTheServerUp ;then
echo -e "$NORMAL" "Server listening: " "$RED" "No" "$NORMAL"
else
echo -e "$NORMAL" "Server listening: " "$GREEN" "Yes" "$NORMAL"
perl -MSocket -e '
my $port = int($ARGV[0]);
socket(my $socket, PF_INET, SOCK_DGRAM, 0);
setsockopt($socket, SOL_SOCKET, SO_RCVTIMEO, pack("i4", 1, 0, 0, 0));
my $sockaddr = pack_sockaddr_in($port, inet_aton($ARGV[1]));
send($socket, "\xff\xff\xff\xffTSource Engine Query\x00", 0, $sockaddr);
my $data = "";
recv($socket, $data, 1400, 0) or (print "Unable to query server\n" and exit(1));
my ($servername, $mapname, $game, $fullname, $rest) = split(/\x00/, substr($data, 6), 5);
my $players = ord(substr($rest, 2, 1));
my $maxplayers = ord(substr($rest, 3, 1));
print "Server Name: $servername\n";
print "Players: $players / $maxplayers\n";
' "$(getQueryPort)" "${ark_MultiHome:-127.0.0.1}"
if isTheServerOnline; then
echo -e "$NORMAL" "Server online: " "$GREEN" "Yes" "$NORMAL"
echo -e "$NORMAL" "ARKServers link: " "$GREEN" "http://arkservers.net/server/${publicip}:$(getQueryPort)" "$NORMAL"
else
echo -e "$NORMAL" "Server online: " "$RED" "No" "$NORMAL"
fi
fi
getCurrentVersion
echo -e "$NORMAL" "Server version: " "$GREEN" $instver "$NORMAL"
}
useConfig() {
if [ "$1" == "main" ]; then
return
fi
for varname in "${!configfile_@}"; do
if [ "configfile_$1" == "$varname" ]; then
source "${!varname}"
return
fi
done
source "$1"
}
#---------------------
# Main program
#---------------------
# check the configuration and throw errors or warnings if needed
checkConfig
while true; do
options=( )
args=( )
command="$1"
shift
nrarg=0
# get the number of arguments for commands that take arguments
case "$command" in
installmod) nrarg=1; ;;
broadcast) nrarg=1; ;;
rconcmd) nrarg=1; ;;
useconfig) nrarg=1; ;;
esac
# Enumerate the options and arguments
while [ $# -ne 0 ]; do
case "$1" in
--)
shift
break
;;
--args)
nrarg=$#
;;
--*)
options+=( "$1" )
;;
*)
if [ $nrarg -gt 0 ]; then
args+=( "$1" )
(( nrarg-- ))
else
break
fi
;;
esac
shift
done
case "$command" in
run)
doRun
;;
start)
if [ " ${options[*]} " =~ " --all " ]; then
doStartAll
shift
else
doStart
fi
;;
stop)
if [ " ${options[*]} " =~ " --all " ]; then
doStopAll
shift
else
doStop stop "${options[@]}"
fi
;;
restart)
if [ " ${options[*]} " =~ " --all " ]; then
doStopAll
else
doStop restart "${options[@]}"
fi
echo "`timestamp`: stop" >> "$logdir/$arkmanagerLog"
sleep 1
if [ " ${options[*]} " =~ " --all " ]; then
doStartAll
shift
else
doStart
fi
echo "`timestamp`: start" >> "$logdir/$arkmanagerLog"
echo "`timestamp`: restart" >> "$logdir/$arkmanagerLog"
;;
install)
doInstall
;;
update)
doUpdate "${options[@]}"
;;
checkupdate)
checkForUpdate
;;
installmod)
doInstallMod "${args[@]}"
shift
;;
backup)
doBackup
;;
broadcast)
doBroadcast "${args[@]}"
shift
;;
saveworld)
doSaveWorld
;;
rconcmd)
rconcmd "${args[@]}"
shift
;;
status)
printStatus
;;
upgrade-tools)
doUpgradeTools
;;
uninstall-tools)
doUninstallTools
;;
useconfig)
useConfig "${args[0]}"
shift
;;
--version)
echo "Version: ${arkstVersion}"
echo "Channel: ${arkstChannel}"
if [ -n "${arkstCommit}" ]; then
echo "Commit: ${arkstCommit:0:7}"
fi
exit 1
;;
-h|--help)
echo -e "Usage: arkmanager [OPTION]\n"
echo "Option Description"
echo "backup Saves a backup of your server inside the backup directory"
echo "broadcast <msg> Sends a message to all users connected to server"
echo "saveworld Saves the game world to disk"
echo "rconcmd <cmd> Execute RCON command on server"
echo "checkupdate Check for a new ARK server version"
echo "install Install the ARK server files from steamcmd"
echo "installmod <modid> Installs a mod from the Steam workshop"
echo "restart Stops the server and then starts it"
echo "restart --all Restarts all servers specified in configfile_xxxxx"
echo "run Runs the server without daemonizing"
echo "start Starts the server"
echo "start --all Starts all servers specified in configfile_xxxxx"
echo "stop Stops the server"
echo "stop --all Stops all servers specified in configfile_xxxxx"
echo "status Returns the status of the current ARK server instance"
echo "update [OPTION ...] Check for a new ARK server version, if needed, stops the server, updates it, and starts it again"
echo "upgrade-tools Check for a new ARK Server Tools version and upgrades it if needed"
echo "uninstall-tools Uninstall the ARK Server Tools"
echo "useconfig <name> Use the configuration overrides in the specified config name or file"
echo "--help Show this help"
echo "--version Show the version info of ARK Server Tools"
echo
echo "Update command takes the below options:"
echo " --force Apply update without checking the current version"
echo " --safe Wait for server to perform world save and update."
echo " --warn Warn players before updating server"
echo " --validate Validates all ARK server files"
echo " --saveworld Saves world before update"
echo " --update-mods Updates installed and requested mods"
echo " --backup Takes a backup of the save files before updating"
echo " --downloadonly Download the mod and/or server update without applying it"
echo " Requires arkStagingDir be set to a staging directory on the same filesystem as the server"
exit 1
;;
*)
echo -n "arkmanager v${arkstVersion}: "
if [ $# -eq 0 ]; then
echo "no command specified"
else
echo "unknown command '$1' specified"
fi
echo "Try 'arkmanager -h' or 'arkmanager --help' for more information."
exit 1
;;
esac
status=$?
if [ $# -eq 0 ]; then
break
fi
done
exit $status