KF2-SRV/SOURCES/kf2-srv
2020-07-09 01:50:08 +03:00

451 lines
16 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# kf2-srv is a command line tool for managing a set of Killing Floor 2 servers.
# Copyright (C) 2019 GenZmeY
# mailto: genzmey@gmail.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
source /etc/steamcmd/steamcmd.conf
source /etc/kf2-srv/kf2-srv.conf
ScriptFullname=$(readlink -e "$0")
ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}')
AppNum="232130"
InstallDir="/usr/games/kf2-srv"
ActiveBranch="$InstallDir/activebranch.txt"
AppBin="$InstallDir/Binaries/Win64/KFGameSteamServer.bin.x86_64"
DefaultConfigDir="$InstallDir/KFGame/Config"
CustomMapsDir="$InstallDir/KFGame/Cache"
InstanceConfigDir="$DefaultConfigDir/instances"
InstanceConfigLnk="/etc/kf2-srv/instances"
MainConfigTemplate="/etc/kf2-srv/main.conf.template"
DiffArray=('Normal' 'Hard' 'Suicide' 'Hell')
WaveArray=('4' '7' '10')
declare -A ModeArray
ModeArray['KFGameContent.KFGameInfo_Survival']='Survival'
ModeArray['KFGameContent.KFGameInfo_WeeklySurvival']='Weekly'
ModeArray['KFGameContent.KFGameInfo_Endless']='Endless'
ModeArray['KFGameContent.KFGameInfo_Objective']='Objective'
ModeArray['KFGameContent.KFGameInfo_VersusSurvival']='Versus'
function show_help ()
{
echo "$ScriptName"
echo "Централизование управление серверами Killing Floor 2"
echo "Usage:"
echo "$ScriptName OPTION [INSTANCE]"
echo ""
echo "Mandatory arguments to long options are mandatory for short options too."
echo "TODO: English description"
echo " -n, --new INSTANCE создает новый ЭКЗЕМПЛЯР сервера"
echo " -d, --delete [INSTANCE] удаляет указанный ЭКЗМПЛЯР сервера; если"
echo " ЭКЗЕМПЛЯР не указан, удаляет все сервера"
echo " -s, --status [INSTANCE] отображает состояние указанного ЭКЗЕМПЛЯРА"
echo " сервера; если ЭКЗЕМПЛЯР не указан,"
echo " отображает состояние всех экземпляров сервера"
echo " -u, --update при первом запуске производит установку KF2;"
echo " в дальнейшем устанавливает обновления при их"
echo " наличии"
echo " -v, --validate проверяет целостность файлов, при"
echo " необходимости перекачивает их."
echo " -r, --run [OPTIONS] запускает экземпляр сервера с указанными"
echo " ПАРАМЕТРАМИ"
echo " --start [INSTANCE] запускает указанный ЭКЗЕМПЛЯР сервера; если"
echo " ЭКЗЕМПЛЯР не указан, запускает все"
echo " автозапускаемые экземпляры сервера"
echo " --stop [INSTANCE] останавливает указанный ЭКЗЕМПЛЯР сервера;"
echo " если ЭКЗЕМПЛЯР не указан, останавливает все"
echo " экземпляры сервера"
echo " --restart [INSTANCE] перезапускает указанный ЭКЗЕМПЛЯР сервера;"
echo " если ЭКЗЕМПЛЯР не указан, перезапускает"
echo " все автозапускаемые экземпляры сервера"
echo " --enable [INSTANCE] добавляет указанный ЭКЗЕМПЛЯР сервера в"
echo " автозапуск; если ЭКЗЕМПЛЯР не указан,"
echo " добавляет все экземпляры сервера в автозапуск"
echo " --disable [INSTANCE] удаляет указанный ЭКЗЕМПЛЯР сервера из"
echo " автозапуска; если ЭКЗЕМПЛЯР не указан,"
echo " удаляет все экземпляры сервера из автозапуска"
echo " --map-sync [INSTANCE] синхронизирует список сторонних карт в"
echo " конфигурационном файле ЭКЗЕМПЛЯРА с"
echo " имеющимися файлами сторонних карт; если"
echo " ЭКЗЕМПЛЯР не указан, синхронизирует все"
echo " экземпляры серверов"
echo " -h, --help display this help and exit"
}
# Use this function with non-root user only!!!
function run_as_root () # $@: Args
{
if [[ -n $(groups "$USER" | grep -Fo 'wheel') ]]; then
sudo "$ScriptFullname" $@
else
echo "You must be root or sudo-user to run this command."
return 1
fi
}
function service_name () # $1: Instance
{
echo "kf2-srv@$1.service"
}
function show_instances ()
{
find "$InstanceConfigDir" -maxdepth 1 -mindepth 1 -type d -printf "%f\n"
}
function instance_exists () # $1: Instance
{
if show_instances | grep -qP "^.*[ ]*$1[ ]*.*$" ; then
return 0
else
return 1
fi
}
function server_exists ()
{
if [[ -n $(ls "$InstallDir") ]]; then
return 0
else
return 1
fi
}
function updates_aviable ()
{
# TODO: implementation
return 0
}
function new_instance () # $1: InstanceName
{
local Instance="$1"
if [[ -z "$Instance" ]]; then
echo "Name of instance must be set"
exit 1
elif ! server_exists; then
echo "You must install server first"
echo "Run \"$ScriptName --update\" to install it"
exit 1
elif instance_exists "$Instance"; then
echo "Instance $Instance already exists"
exit 1
fi
local InstanceDir="$InstanceConfigDir/$Instance"
if [[ -d "$InstanceDir" ]]; then
echo "$InstanceDir already exists"
exit 1
fi
mkdir -p "$InstanceDir/LinuxServer" && chown -R "$SteamUser:$SteamUser" "$InstanceDir"
cp -a "$MainConfigTemplate" "$InstanceDir/main.conf"
cp -a "$DefaultConfigDir/KFAI.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/KFWeb.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFEngine.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFGame.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" "$InstanceDir/LinuxServer"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" "$InstanceDir/LinuxServer"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" "$InstanceDir/LinuxServer"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer"
echo "Instance $Instance created. See /etc/$ScriptName/instances/$Instance for edit configuration"
}
function delete_instance () # $1: [InstanceName]
{
local Instance="$1"
if [[ -z "$Instance" ]]; then
echo "Are you sure you want to delete all instances? [y/N]"
local Answ="N"
read Answ
if [[ "$Answ" == "y" || "$Answ" == "Y" ]]; then
for Instance in $(show_instances)
do
stop_instance "$Instance"
delete_instance "$Instance"
done
fi
elif instance_exists "$Instance"; then
local InstanceDir="$InstanceConfigDir/$Instance"
stop_instance "$Instance"
rm -rf "$InstanceDir"
echo "Instance $Instance removed"
else
echo "Instance $Instance not exists"
fi
}
function show_status_implementation () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]]; then
if systemctl -q is-enabled $(service_name "$Instance"); then
local IsEnabled="enabled"
else
local IsEnabled="disabled"
fi
if systemctl | grep $(service_name "$Instance") | grep -q 'running' ; then
local IsRuning="running"
else
local IsRuning="dead"
fi
local Description=$(grep -P 'Description=' "$InstanceConfigDir/$Instance/main.conf" | sed -r 's/(Description=|")//g')
local GamePort=$(grep -Po '"-port=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$')
local WebAdminPort=$(grep -Po '"-webadminport=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$')
local QueryPort=$(grep -Po '"-queryport=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$')
local GameType=$(grep -Po 'Game=([^\?]+)' "$InstanceConfigDir/$Instance/main.conf" | sed -r 's/Game=([^?]+)/\1/g' )
local GameLength=$(grep -Po 'GameLength=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$')
local GameDifficulty=$(grep -Po 'Difficulty=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$')
local DisplayGameType=${ModeArray[$GameType]}
local DisplayGameLength=${WaveArray[$GameLength]}
local DisplayDifficulty=${DiffArray[$GameDifficulty]}
if [[ "$DisplayGameType" == 'Weekly' || \
"$DisplayGameType" == 'Endless' || \
"$DisplayGameType" == 'Versus' || \
"$DisplayGameType" == 'Objective' ]]; then
DisplayGameLength='-'
fi
if [[ "$DisplayGameType" == 'Weekly' || \
"$DisplayGameType" == 'Versus' ]]; then
DisplayDifficulty='-'
fi
echo -e "$Instance:$IsEnabled:$IsRuning:$GamePort:$QueryPort:$WebAdminPort:$DisplayGameType:$DisplayGameLength:$DisplayDifficulty:$Description"
else
echo -e "INSTANCE:AUTORUN:STATE:P_GAME:P_QUERY:P_WEB:TYPE:LEN:DIFF:DESCRIPTION"
for Instance in $(show_instances)
do
show_status_implementation "$Instance"
done
fi
}
function show_status () # $1: [InstanceName]
{
show_status_implementation "$1" | column -t -s :
}
function validate ()
{
if [[ -n "$BranchName" ]]; then
local BetaArg="-beta $BranchName"
fi
stop_instance
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg validate +exit
echo "$BranchName" > "$ActiveBranch"
start_instance
}
function update_kf2 ()
{
if [[ -n "$BranchName" ]]; then
local BetaArg="-beta $BranchName"
fi
if ! server_exists; then # First install
mkdir -p "$InstanceConfigDir" "$CustomMapsDir" && chown -R "$SteamUser:$SteamUser" "$InstallDir/KFGame"
ln -s "$InstanceConfigDir" "$InstanceConfigLnk"
echo "$BranchName" > "$ActiveBranch"
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg validate +exit
elif updates_aviable; then # Update
if [[ "$BranchName" == $(cat "$ActiveBranch") ]]; then
stop_instance
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg +exit
start_instance
else
validate
fi
fi
}
function start_instance () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]] ; then
if instance_exists "$Instance"; then
systemctl start $(service_name "$Instance")
else
echo "Instance $Instance not exitst"
fi
else
for Instance in $(show_instances)
do
if systemctl -q is-enabled $(service_name "$Instance") ; then
start_instance "$Instance"
fi
done
fi
}
function stop_instance () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]]; then
if instance_exists "$Instance"; then
systemctl stop $(service_name "$Instance")
else
echo "Instance $Instance not exitst"
fi
else
for Instance in $(show_instances)
do
stop_instance "$Instance"
done
fi
}
function restart_instance () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]] ; then
if instance_exists "$Instance"; then
systemctl restart $(service_name "$Instance")
else
echo "Instance $Instance not exitst"
fi
else
for Instance in $(show_instances)
do
if systemctl -q is-enabled $(service_name "$Instance") ; then
restart_instance "$Instance"
fi
done
fi
}
function enable_instance () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]]; then
if instance_exists "$Instance"; then
systemctl enable $(service_name "$Instance")
else
echo "Instance $Instance not exitst"
fi
else
for Instance in $(show_instances)
do
enable_instance "$Instance"
done
fi
}
function disable_instance () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]]; then
if instance_exists "$Instance"; then
systemctl disable $(service_name "$Instance")
else
echo "Instance $Instance not exitst"
fi
else
for Instance in $(show_instances)
do
disable_instance "$Instance"
done
fi
}
function run ()
{
if [[ "$USER" == "$SteamUser" ]]; then
"$AppBin" "$@"
elif [[ -n $(groups "$USER" | grep -Fo 'wheel') ]] || [[ "$EUID" -eq 0 ]]; then
sudo -u "$SteamUser" "$AppBin" "$@"
else
echo "You must be a $SteamUser, root or sudo-user to run this command."
fi
}
function map_sync () # $1: [InstanceName]
{
local Instance="$1"
if [[ -n "$Instance" ]]; then
if instance_exists "$Instance"; then
stop_instance "$Instance"
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
for MapFile in $(find "$CustomMapsDir" -type f -name '*.kfm' -printf "%f\n")
do
MapName=$(echo "$MapFile" | sed -r 's|.kfm$||g')
if [[ ! -f "$Config" ]]; then
echo "$Config does not exist!"
elif grep -qP "MapName=$MapName[ $]" "$Config"; then
echo "$MapName is already in $Config."
else
echo "Adding $MapName to $Config."
echo -e "
[$MapName KFMapSummary]
MapName=$MapName
bPlayableInSurvival=True
bPlayableInWeekly=True
bPlayableInVsSurvival=True
bPlayableInEndless=True
bPlayableInObjective=False" >> "$Config"
fi
done
else
echo "Instance $Instance not exitst"
fi
else
for Instance in $(show_instances)
do
map_sync "$Instance"
done
fi
}
function map_rotate_save ()
{
# TODO: implementation
echo "Dummy..."
}
function map_rotate_load ()
{
# TODO: implementation
echo "Dummy..."
}
if [[ $# -eq 0 ]]; then show_help; exit 0; fi
case $1 in
-h|--help ) show_help; ;;
-n|--new ) if [[ "$EUID" -eq 0 ]]; then new_instance "$2"; else run_as_root $@; fi;;
-d|--delete ) if [[ "$EUID" -eq 0 ]]; then delete_instance "$2"; else run_as_root $@; fi;;
-s|--status ) show_status "$2"; ;;
-u|--update ) if [[ "$EUID" -eq 0 ]]; then update_kf2 ; else run_as_root $@; fi;;
-v|--validate ) if [[ "$EUID" -eq 0 ]]; then validate ; else run_as_root $@; fi;;
-r|--run ) run $@ ; ;;
--start ) if [[ "$EUID" -eq 0 ]]; then start_instance "$2"; else run_as_root $@; fi;;
--stop ) if [[ "$EUID" -eq 0 ]]; then stop_instance "$2"; else run_as_root $@; fi;;
--restart ) if [[ "$EUID" -eq 0 ]]; then restart_instance "$2"; else run_as_root $@; fi;;
--enable ) if [[ "$EUID" -eq 0 ]]; then enable_instance "$2"; else run_as_root $@; fi;;
--disable ) if [[ "$EUID" -eq 0 ]]; then disable_instance "$2"; else run_as_root $@; fi;;
--map-sync ) if [[ "$EUID" -eq 0 ]]; then map_sync "$2"; else run_as_root $@; fi;;
--map-rotate-save ) map_rotate_save; ;;
--map-rotate-load ) map_rotate_load; ;;
* ) echo "Command not recognized: $1"; exit 1 ;;
esac