KF2-SRV/SOURCES/kf2-srv
2020-07-09 01:58:10 +03:00

971 lines
35 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, 2020 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
ScriptFullname=$(readlink -e "$0")
ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}')
ScriptVersion="0.8.0"
AppServerNum="232130"
AppClientNum="232090"
StrangeConstUID="17825793"
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 "TODO: English description"
echo "$ScriptName v$ScriptVersion"
echo "Централизование управление серверами Killing Floor 2"
echo "Usage:"
echo "${ScriptName} OPTIONS stable branch"
echo "${ScriptName}-beta OPTIONS beta branch"
echo ""
echo "Mandatory arguments to long options are mandatory for short options too."
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 " -st, --start [INSTANCE] запускает указанный ЭКЗЕМПЛЯР сервера; если"
echo " ЭКЗЕМПЛЯР не указан, запускает все"
echo " автозапускаемые экземпляры сервера"
echo " -sp, --stop [INSTANCE] останавливает указанный ЭКЗЕМПЛЯР сервера;"
echo " если ЭКЗЕМПЛЯР не указан, останавливает все"
echo " экземпляры сервера"
echo " -rs, --restart [INSTANCE] перезапускает указанный ЭКЗЕМПЛЯР сервера;"
echo " если ЭКЗЕМПЛЯР не указан, перезапускает"
echo " все автозапускаемые экземпляры сервера"
echo " -en, --enable [INSTANCE] добавляет указанный ЭКЗЕМПЛЯР сервера в"
echo " автозапуск; если ЭКЗЕМПЛЯР не указан,"
echo " добавляет все экземпляры сервера в автозапуск"
echo " -di, --disable [INSTANCE] удаляет указанный ЭКЗЕМПЛЯР сервера из"
echo " автозапуска; если ЭКЗЕМПЛЯР не указан,"
echo " удаляет все экземпляры сервера из автозапуска"
echo " -wl, --workshop-list отображает список ресурсов из SteamWorkshop"
echo " -wa, --workshop-add [MAP_ID] добавляет ресурс из SteamWorkshop по URL или"
echo " WorkshopID"
echo " -wd, --workshop-del [MAP_ID] удаляет ресурс SteamWorkshop по URL или WorkshopID"
echo " -ws, --workshop-sync синхронизирует списки сторонних карт в"
echo " конфигурационных файлах с имеющимися файлами"
echo " сторонних карт; синхронизирует списки карт из"
echo " SteamWorkshop между всеми экземплярами серверов"
echo "-mrs, --map-rotate-save [INSTANCE] сохраняет текущий порядок карт для"
echo " указанного ЭКЗЕМПЛЯРА сервера; если ЭКЗЕМПЛЯР"
echo " не указан, сохраняет порядок для всех ЭКЗЕМПЛЯРОВ"
echo "-mrl, --map-rotate-load [INSTANCE] применяет ранее сохраненный порядок карт"
echo " для указанного ЭКЗЕМПЛЯРА сервера; если ЭКЗЕМПЛЯР"
echo " не указан, применяет сохраненные порядки для"
echo " всех ЭКЗЕМПЛЯРОВ сервера"
echo " -bl, --ban-list отображает список заблокированных пользователей"
echo " -bs, --ban-sync синхронизирует список заблокированных"
echo " пользователей между всеми экземплярами сервера"
echo " -ba, --ban-add [BAN_ID] добавляет пользователя в список заблокированных"
echo " допустимо использовать ID3, SteamID, а также"
echo " ссылку на профиль пользователя"
echo " -bd, --ban-del [BAN_ID] удаляет пользователя из списка заблокированных"
echo " допустимо использовать ID3, SteamID, а также"
echo " ссылку на профиль пользователя"
echo " -h, --help display this help and exit"
}
# Use this function with non-root user only!!!
function run_as_root () # $*: Args
{
if [[ -n "$BetaPostfix" ]]; then
BetaPostfix="beta"
fi
if [[ -n $(groups "$USER" | grep -Fo 'wheel') ]]; then
sudo "$ScriptFullname" $BetaPostfix $*
else
echo "You must be root or sudo-user to run this command."
return 1
fi
}
function service_name () # $*: Instance[s]
{
local Services=""
for Instance in $*
do
Services+=" kf2-srv$BetaPostfix@$Instance.service"
done
echo "$Services"
}
function show_instances ()
{
find "$InstanceConfigDir" -maxdepth 1 -mindepth 1 -type d -printf "%f\n"
}
function show_enabled_instances ()
{
local EnabledInstances=""
for Instance in $(show_instances)
do
if systemctl -q is-enabled $(service_name "$Instance") ; then
EnabledInstances+=" $Instance"
fi
done
echo "$EnabledInstances"
}
function instance_exists () # $1: Instance
{
if [[ -d "$InstanceConfigDir/$1" ]]; then
return 0
else
return 1
fi
}
function server_exists ()
{
if [[ -x "$AppBin" ]]; then
return 0
else
return 1
fi
}
function updates_aviable ()
{
return 0 # steamcmd does not show updates even if they are :(
# TODO: check updates correctly (but how?)
if [[ -n "$BetaPostfix" ]]; then
local BetaArg="-beta preview"
fi
if steamcmd +login anonymous \
+force_install_dir $InstallDir \
+app_info_update 1 \
+app_status $AppServerNum $BetaArg \
+quit | \
grep 'install state:' | \
grep -qiF 'Update Required'; then
return 0
else
return 1
fi
}
function new_instance () # $*: InstanceName[s]
{
if [[ -z "$*" ]]; then
echo "Name of instance[s] must be set"
exit 1
elif ! server_exists; then
echo "You must install server first"
echo "Run \"$ScriptName --update\" to install it"
exit 1
fi
local MaxGamePort='7777'
local MaxQueryPort='27015'
local MaxWebAdminPort='8080'
for Instance in $(show_instances)
do
local Config="$InstanceConfigDir/$Instance/main.conf"
local GamePort=$(grep -Po '"-port=([0-9]+)' "$Config" | grep -Po '[0-9]+$')
local WebAdminPort=$(grep -Po '"-webadminport=([0-9]+)' "$Config" | grep -Po '[0-9]+$')
local QueryPort=$(grep -Po '"-queryport=([0-9]+)' "$Config" | grep -Po '[0-9]+$')
if [[ "$GamePort" -gt "$MaxGamePort" ]]; then MaxGamePort="$GamePort"; fi
if [[ "$QueryPort" -gt "$MaxQueryPort" ]]; then MaxQueryPort="$QueryPort"; fi
if [[ "$WebAdminPort" -gt "$MaxWebAdminPort" ]]; then MaxWebAdminPort="$WebAdminPort"; fi
done
for Instance in $*
do
if instance_exists "$Instance"; then
echo "Instance $Instance already exists - skip"
continue
fi
local InstanceDir="$InstanceConfigDir/$Instance"
local DirMode="-d -g $SteamUser -o $SteamUser -m 775"
local FileMode=" -g $SteamUser -o $SteamUser -m 664"
install $DirMode "$InstanceDir"
install $DirMode "$InstanceDir/LinuxServer"
install $FileMode "$MainConfigTemplate" "$InstanceDir/main.conf"
install $FileMode "$DefaultConfigDir/KFAI.ini" "$InstanceDir"
install $FileMode "$DefaultConfigDir/KFWeb.ini" "$InstanceDir"
install $FileMode "$DefaultConfigDir/LinuxServer-KFEngine.ini" "$InstanceDir"
install $FileMode "$DefaultConfigDir/LinuxServer-KFGame.ini" "$InstanceDir"
install $FileMode "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir"
install $FileMode "$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" "$InstanceDir"
install $FileMode "$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" "$InstanceDir/LinuxServer"
install $FileMode "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" "$InstanceDir/LinuxServer"
install $FileMode "$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" "$InstanceDir/LinuxServer"
install $FileMode "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer"
((MaxGamePort++)); ((MaxQueryPort++)); ((MaxWebAdminPort++))
sed -i -r --follow-symlinks "s/-port=[0-9]+/-port=$MaxGamePort/g" "$InstanceDir/main.conf"
sed -i -r --follow-symlinks "s/-queryport=[0-9]+/-queryport=$MaxQueryPort/g" "$InstanceDir/main.conf"
sed -i -r --follow-symlinks "s/-webadminport=[0-9]+/-webadminport=$MaxWebAdminPort/g" "$InstanceDir/main.conf"
echo "Instance $Instance created. See /etc/$ScriptName/instances$BetaPostfix/$Instance for edit configuration"
done
}
function delete_instance () # $*: [InstanceName[s]]
{
if [[ -z "$*" ]]; 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
else
for Instance in $*
do
if 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
done
fi
}
function show_status_implementation_body () # $*: [InstanceName[s]]
{
for Instance in $InstanceList
do
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="stopped"
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"
done
}
function show_status_implementation_full () # $*: [InstanceName[s]]
{
local InstanceList=""
if [[ -z "$*" ]] ; then
InstanceList=$(show_instances)
else
for Instance in $*
do
if instance_exists "$Instance"; then
InstanceList+=" $Instance"
fi
done
fi
echo -e "INSTANCE:AUTORUN:STATE:P_GAME:P_QUERY:P_WEB:TYPE:LEN:DIFF:DESCRIPTION"
show_status_implementation_body "$InstanceList" | sort -t : -k 4
}
function show_status () # $*: [InstanceName[s]]
{
show_status_implementation_full $* | column -t -s :
}
function validate ()
{
if [[ -n "$BetaPostfix" ]]; then
local BetaArg="-beta preview"
fi
stop_instance
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppServerNum $BetaArg validate +exit
fix_steamclient_so
start_instance
}
function make_default_instance ()
{
local InstanceDir="$InstanceConfigDir/default"
chmod 664 \
"$DefaultConfigDir/KFAI.ini" \
"$DefaultConfigDir/KFWeb.ini" \
"$DefaultConfigDir/LinuxServer-KFEngine.ini" \
"$DefaultConfigDir/LinuxServer-KFGame.ini" \
"$DefaultConfigDir/LinuxServer-KFInput.ini" \
"$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini"
dos2unix \
"$DefaultConfigDir/KFAI.ini" \
"$DefaultConfigDir/KFWeb.ini" \
"$DefaultConfigDir/LinuxServer-KFEngine.ini" \
"$DefaultConfigDir/LinuxServer-KFGame.ini" \
"$DefaultConfigDir/LinuxServer-KFInput.ini" \
"$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" \
"$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini"
install -d -g "$SteamUser" -o "$SteamUser" -m 775 "$InstanceDir"
install -d -g "$SteamUser" -o "$SteamUser" -m 775 "$InstanceDir/LinuxServer"
install -g "$SteamUser" -o "$SteamUser" -m 664 "$MainConfigTemplate" "$InstanceDir/main.conf"
ln -s "$DefaultConfigDir/KFAI.ini" "$InstanceDir/KFAI.ini"
ln -s "$DefaultConfigDir/KFWeb.ini" "$InstanceDir/KFWeb.ini"
ln -s "$DefaultConfigDir/KFWebAdmin.ini" "$InstanceDir/KFWebAdmin.ini"
ln -s "$DefaultConfigDir/LinuxServer-KFEngine.ini" "$InstanceDir/LinuxServer-KFEngine.ini"
ln -s "$DefaultConfigDir/LinuxServer-KFGame.ini" "$InstanceDir/LinuxServer-KFGame.ini"
ln -s "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir/LinuxServer-KFInput.ini"
ln -s "$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" "$InstanceDir/LinuxServer-KFSystemSettings.ini"
ln -s "$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" "$InstanceDir/LinuxServer/LinuxServerEngine.ini"
ln -s "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" "$InstanceDir/LinuxServer/LinuxServerGame.ini"
ln -s "$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" "$InstanceDir/LinuxServer/LinuxServerInput.ini"
ln -s "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer/LinuxServerSystemSettings.ini"
}
function fix_steamclient_so ()
{
rm -f "$InstallDir/linux64/steamclient.so"
rm -f "$InstallDir/steamclient.so"
rm -f "$InstallDir/Binaries/Win64/lib64/steamclient.so"
ln -s "/usr/share/steamcmd/linux64/steamclient.so" "$InstallDir/linux64/steamclient.so"
ln -s "/usr/share/steamcmd/linux64/steamclient.so" "$InstallDir/steamclient.so"
ln -s "/usr/share/steamcmd/linux64/steamclient.so" "$InstallDir/Binaries/Win64/lib64/steamclient.so"
}
function create_map_dirs ()
{
# space saving
local InstallDirOrig="/usr/games/kf2-srv"
local InstallDirBeta="/usr/games/kf2-srv-beta"
local DownloadDirOrig="$InstallDirOrig/Binaries/Win64/steamapps/workshop/content/$AppClientNum"
local CacheDirOrig="$InstallDirOrig/KFGame/Cache"
local DownloadDirBeta="$InstallDirBeta/Binaries/Win64/steamapps/workshop/content/$AppClientNum"
local CacheDirBeta="$InstallDirBeta/KFGame/Cache"
if [[ -z "$BetaPostfix" ]]; then # Orig
sudo -u "$SteamUser" install -d -m 775 "$DownloadDirOrig"
if [[ -d "$CacheDirBeta" ]]; then
ln -s "$CacheDirBeta" "$CacheDirOrig"
rm -rf "$DownloadDirOrig"
ln -s "$DownloadDirBeta" "$DownloadDirOrig"
else
sudo -u "$SteamUser" install -d -m 775 "$CacheDirOrig"
fi
else # Beta
sudo -u "$SteamUser" install -d -m 775 "$DownloadDirBeta"
if [[ -d "$CacheDirOrig" ]]; then
ln -s "$CacheDirOrig" "$CacheDirBeta"
rm -rf "$DownloadDirBeta"
ln -s "$DownloadDirOrig" "$DownloadDirBeta"
else
sudo -u "$SteamUser" install -d -m 775 "$CacheDirBeta"
fi
fi
}
function update_kf2 ()
{
if [[ -n "$BetaPostfix" ]]; then
local BetaArg="-beta preview"
fi
if ! server_exists; then # First install
if ! steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppServerNum $BetaArg validate +exit; then
echo "Errors during installation - exit"
exit 1
fi
sudo -u "$SteamUser" $AppBin &
while true
do
if [[ -e "$DefaultConfigDir/KFAI.ini" ]] &&
[[ -e "$DefaultConfigDir/KFWeb.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer-KFEngine.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer-KFGame.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer-KFInput.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" ]] &&
[[ -e "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" ]]; then
break
fi
sleep 2
done
killall -KILL KFGameSteamServer.bin.x86_64
multini -s "$DefaultConfigDir/KFWeb.ini" "IpDrv.WebServer" "bEnabled" "true"
create_map_dirs
fix_steamclient_so
ln -s "$InstanceConfigDir" "$InstanceConfigLnk"
make_default_instance
echo "KF2 succesfully installed"
elif updates_aviable; then # Update
stop_instance
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppServerNum $BetaArg +exit
start_instance
fi
}
function start_instance () # $*: [InstanceName[s]]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_enabled_instances)
fi
local InactiveServiceList=""
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
local Service=$(service_name "$Instance")
if systemctl -q is-active $Service ; then
echo "Instance $Instance already running - skip"
else
InactiveServiceList+=" $Service"
fi
else
echo "Instance $Instance not exitst"
fi
done
if [[ -n "$InactiveServiceList" ]]; then
systemctl start $InactiveServiceList
else
echo "Nothing to do"
fi
}
function stop_instance () # $*: [InstanceName[s]]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_instances)
fi
local ToStopInstanceList=""
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
ToStopInstanceList+=" $Instance"
else
echo "Instance $Instance not exitst"
fi
done
if [[ -n "$ToStopInstanceList" ]]; then
systemctl stop $(service_name "$ToStopInstanceList")
else
echo "Nothing to do"
fi
}
function restart_instance () # $*: [InstanceName[s]]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_enabled_instances)
fi
local ToRestartInstancesList=""
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
ToRestartInstancesList+=" $Instance"
else
echo "Instance $Instance not exitst"
fi
done
if [[ -n "$ToRestartInstancesList" ]]; then
systemctl restart $(service_name "$ToRestartInstancesList")
else
echo "Nothing to do"
fi
}
function enable_instance () # $1*: [InstanceName[s]]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_instances)
fi
local ToEnableInstanceList=""
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
ToEnableInstanceList+=" $Instance"
else
echo "Instance $Instance not exist"
fi
done
if [[ -n "$ToEnableInstanceList" ]]; then
systemctl enable $(service_name "$ToEnableInstanceList")
else
echo "Nothing to do"
fi
}
function disable_instance () # $*: [InstanceName[s]]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_instances)
fi
local ToDisableInstanceList=""
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
ToDisableInstanceList+=" $Instance"
else
echo "Instance $Instance not exitst"
fi
done
if [[ -n "$ToDisableInstanceList" ]]; then
systemctl disable $(service_name "$ToDisableInstanceList")
else
echo "Nothing to do"
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 name_by_workshopID () # $1: WorkshopID
{
local WorkshopID="$1"
local Cache="$CacheDir/$WorkshopID"
local Result=""
if [[ -d "$Cache" ]]; then
Result=$(find "$Cache" -type f -name '*.kfm' -printf '%f\n' | head -n 1)
if [[ -z "$Result" ]]; then
Result=$(find "$Cache" -type f -name '*.u' -printf '%f\n' | head -n 1)
fi
fi
echo "$Result"
}
function workshop_list_body () # $1: WorkshopListFile
{
while read WorkshopID
do
local Cache="$CacheDir/$WorkshopID"
local Downl="$DownloadDir/$WorkshopID"
local Url="https://steamcommunity.com/sharedfiles/filedetails/?id=$WorkshopID"
local WsName=$(name_by_workshopID "$WorkshopID")
if [[ -n "$WsName" ]]; then
local WsSize=$(du -sch "$Downl" "$Cache" | tail -n 1 | grep -Po '^[^\s]+')
else
local WsSize="-"; WsName="-"
fi
echo "$WorkshopID $WsName $WsSize $Url"
done < "$1"
}
function workshop_list_full () # $1: WorkshoplistFile
{
echo "WORKSHOP_ID NAME SIZE WORKSHOP_URL"
workshop_list_body "$1" | sort -k 2
}
function workshop_list () # $1: [--human-readable]
{
local WsList=$(mktemp)
for Instance in $(show_instances)
do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini"
if multini -gq "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems"; then
multini -g "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" >> "$WsList"
fi
done
sort -u "$WsList" -o "$WsList"
if [[ -n "$1" ]]; then
workshop_list_full "$WsList" | column -t
else
cat "$WsList"
fi
rm -f "$WsList"
}
function any_to_workshopID () # $1: WorkshopID/URL
{
if echo "$1" | grep -qP '^http.+'; then
local WorkshopID=$(echo "$1" | sed -r 's/.+=([0-9]+)$/\1/')
else
local WorkshopID="$1"
fi
echo "$WorkshopID"
}
function workshop_add () # $*: WorkshopID[s]
{
for Instance in $(show_instances)
do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini"
multini -ar "$Config" "IpDrv.TcpNetDriver" "DownloadManagers" "OnlineSubsystemSteamworks.SteamWorkshopDownload"
for Map in $*
do
local WorkshopID=$(any_to_workshopID "$Map")
if ! multini -gq "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" "$WorkshopID"; then
echo "Add workshop $WorkshopID to $Instance"
multini -ar "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" "$WorkshopID"
fi
done
done
}
function workshop_del () # $*: WorkshopID[s]
{
for Map in $*
do
local WorkshopID=$(any_to_workshopID "$Map")
local WsName=$(name_by_workshopID "$WorkshopID")
local Cache="$CacheDir/$WorkshopID"
local Downl="$DownloadDir/$WorkshopID"
echo -e "Clear cache:
$Cache
$Downl"
rm -rf "$Cache" "$Downl"
for Instance in $(show_instances)
do
local ConfigEngine="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini"
multini -d "$ConfigEngine" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" "$WorkshopID"
if echo "$WsName" | grep -qP '\.kfm$' ; then
echo "Remove map $WorkshopID ($WsName) from $Instance"
local WsNameShort=$(echo "$WsName" | sed 's/\.kfm$//')
local ConfigGame="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
multini -d "$ConfigGame" "$WsNameShort KFMapSummary"
fi
done
done
}
function workshop_sync ()
{
workshop_add $(workshop_list)
for Instance in $(show_instances)
do
if instance_exists "$Instance"; then
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
for MapFile in $(find -L "$CacheDir" -type f -name '*.kfm' -printf "%f\n")
do
MapName=$(echo "$MapFile" | sed -r 's|.kfm$||')
if ! multini -gq "$Config" "$MapName KFMapSummary"; then
echo "Adding $MapName to $Instance."
multini -s "$Config" "$MapName KFMapSummary" "MapName" "$MapName"
multini -s "$Config" "$MapName KFMapSummary" "bPlayableInSurvival" "True"
multini -s "$Config" "$MapName KFMapSummary" "bPlayableInWeekly" "True"
multini -s "$Config" "$MapName KFMapSummary" "bPlayableInVsSurvival" "True"
multini -s "$Config" "$MapName KFMapSummary" "bPlayableInEndless" "True"
multini -s "$Config" "$MapName KFMapSummary" "bPlayableInObjective" "False"
fi
done
for MutFile in $(find -L "$CacheDir" -type f -name '*.u' -printf "%f\n")
do
MutName=$(echo "$MutFile" | sed -r 's|.u$||')
if ! multini -gq "$Config" "$MutName KFMutatorSummary"; then
echo "Adding $MutName to $Instance."
multini -s "$Config" "$MutName KFMutatorSummary" "ClassName" ""
fi
done
else
echo "Instance $Instance not exitst"
fi
done
}
function map_rotate_save () # $*: Instance[s]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_instances)
fi
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local MapRotate="$InstanceConfigDir/$Instance/MapRotate.ini"
grep -F 'ActiveMapCycle=' "$Config" > "$MapRotate"
grep -F 'GameMapCycles=' "$Config" >> "$MapRotate"
else
echo "Instance $Instance not exitst"
fi
done
}
function map_rotate_load () # $*: Instance[s]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_instances)
fi
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local MapRotate="$InstanceConfigDir/$Instance/MapRotate.ini"
if [[ -e "$MapRotate" ]]; then
sed -i --follow-symlinks -r "/(ActiveMapCycle=|GameMapCycles=)/d" "$Config"
sed -i --follow-symlinks "/\[KFGame\.KFGameInfo\]/ r $MapRotate" "$Config"
else
echo "$MapRotate not found - skip"
fi
else
echo "Instance $Instance not exitst"
fi
done
}
# conversion algorithm taken from here:
# https://github.com/noobient/killinuxfloor/blob/master/share/killinuxfloor
# thank bviktor for that :)
function steamID3_to_steamID64 () # $1: ID3
{
# steamID64 = "7656" + (steamID3 + 1197960265728)
ID64=$1
((ID64+=1197960265728))
ID64="7656${ID64}"
echo "$ID64"
}
function steamID64_to_steamID3 () # $1: ID4
{
# steamID3 = substr(steamID64, 4) - 1197960265728
ID3=${1:4}
((ID3-=1197960265728))
echo "$ID3"
}
function ban_list_ext () # $1: BanlistFile
{
local Num=1
echo "NUM STEAM_ID3 STEAM_ID64 PROFILE_URL"
while read ID3
do
local ID64=$(steamID3_to_steamID64 "$ID3")
local Url=$(curl "https://steamcommunity.com/profiles/$ID64" -s -L -I -o /dev/null -w '%{url_effective}')
echo "$Num $ID3 $ID64 $Url"
((Num++))
done < "$1"
}
function ban_list () # $1: [--human-readable]
{
local BanList=$(mktemp)
for Instance in $(show_instances)
do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
if multini -gq "$Config" "Engine.AccessControl" "BannedIDs"; then
multini -g "$Config" "Engine.AccessControl" "BannedIDs" | sed -r 's/.+A=([0-9]+),.+/\1/' >> "$BanList"
fi
done
sort -u "$BanList" -o "$BanList"
if [[ -n "$1" ]]; then
ban_list_ext "$BanList" | column -t
else
cat "$BanList"
fi
rm -f "$BanList"
}
function ban_ID3 () # $1: ID3
{
ID3="$1"
for Instance in $(show_instances)
do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local BanStr="(Uid=(A=$ID3,B=$StrangeConstUID))"
if ! multini -gq "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"; then
echo "Add ban $ID3 to $Instance"
multini -a "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"
fi
done
}
function unban_ID3 () # $1: ID3
{
ID3="$1"
for Instance in $(show_instances)
do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local BanStr="(Uid=(A=$ID3,B=$StrangeConstUID))"
if multini -gq "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"; then
echo "Remove ban $ID3 from $Instance"
multini -d "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"
fi
done
}
function any_to_ID3 () # $1: ID3/ID64/Url
{
if echo "$1" | grep -qP '^http.+'; then
local Xml=$(mktemp)
curl -ss "$1/?xml=1" > "$Xml"
local ID64=$(xmllint --xpath 'string(//steamID64/text())' "$Xml")
local ID3=$(steamID64_to_steamID3 "$ID64")
rm -f "$Xml"
elif [[ $(echo "$1" | wc -m) -eq 18 ]] && echo "$1" | grep -qP '^76561[0-9]+' ; then
local ID3=$(steamID64_to_steamID3 "$1")
else
local ID3="$1"
fi
echo "$ID3"
}
function ban_add () # $*: ban list
{
if [[ -z "$*" ]]; then
echo "Nothing to do"
exit 1
fi
for Ban in $*
do
ban_ID3 $(any_to_ID3 "$Ban")
done
}
function ban_del () # $*: ban list
{
if [[ -z "$*" ]]; then
echo "Nothing to do"
exit 1
fi
for Ban in $*
do
unban_ID3 $(any_to_ID3 "$Ban")
done
}
function ban_sync ()
{
ban_list | \
while read ID3
do
ban_ID3 "$ID3"
done
}
if [[ "$1" == "beta" ]]; then
BetaPostfix="-beta"; shift
fi
InstallDir="/usr/games/kf2-srv$BetaPostfix"
AppBin="$InstallDir/Binaries/Win64/KFGameSteamServer.bin.x86_64"
DefaultConfigDir="$InstallDir/KFGame/Config"
DownloadDir="$InstallDir/Binaries/Win64/steamapps/workshop/content/$AppClientNum"
CacheDir="$InstallDir/KFGame/Cache"
InstanceConfigDir="/etc/kf2-srv/instances$BetaPostfix"
InstanceConfigLnk="$DefaultConfigDir/instances"
MainConfigTemplate="/etc/kf2-srv/main.conf.template"
if [[ $# -eq 0 ]]; then show_help; exit 0; fi
case $1 in
-h|--help ) show_help; ;;
-n|--new ) if [[ "$EUID" -eq 0 ]]; then shift; new_instance $*; else run_as_root $*; fi ;;
-d|--delete ) if [[ "$EUID" -eq 0 ]]; then shift; delete_instance $*; else run_as_root $*; fi ;;
-s|--status ) shift; show_status $*; ;;
-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 ) shift; run $*; ;;
-st|--start ) if [[ "$EUID" -eq 0 ]]; then shift; start_instance $*; else run_as_root $*; fi ;;
-sp|--stop ) if [[ "$EUID" -eq 0 ]]; then shift; stop_instance $*; else run_as_root $*; fi ;;
-rs|--restart ) if [[ "$EUID" -eq 0 ]]; then shift; restart_instance $*; else run_as_root $*; fi ;;
-en|--enable ) if [[ "$EUID" -eq 0 ]]; then shift; enable_instance $*; else run_as_root $*; fi ;;
-di|--disable ) if [[ "$EUID" -eq 0 ]]; then shift; disable_instance $*; else run_as_root $*; fi ;;
-wl|--workshop-list ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_list "-h" ; else run_as_root $*; fi ;;
-wa|--workshop-add ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_add $*; else run_as_root $*; fi ;;
-wd|--workshop-del ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_del $*; else run_as_root $*; fi ;;
-ws|--workshop-sync ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_sync ; else run_as_root $*; fi ;;
-mrs|--map-rotate-save ) if [[ "$EUID" -eq 0 ]]; then shift; map_rotate_save $*; else run_as_root $*; fi ;;
-mrl|--map-rotate-load ) if [[ "$EUID" -eq 0 ]]; then shift; map_rotate_load $*; else run_as_root $*; fi ;;
-bl|--ban-list ) if [[ "$EUID" -eq 0 ]]; then shift; ban_list "-h" ; else run_as_root $*; fi ;;
-bs|--ban-sync ) if [[ "$EUID" -eq 0 ]]; then shift; ban_sync ; else run_as_root $*; fi ;;
-ba|--ban-add ) if [[ "$EUID" -eq 0 ]]; then shift; ban_add $*; else run_as_root $*; fi ;;
-bd|--ban-del ) if [[ "$EUID" -eq 0 ]]; then shift; ban_del $*; else run_as_root $*; fi ;;
* ) echo "Command not recognized: $1"; exit 1 ;;
esac