Compare commits

..

5 Commits

Author SHA1 Message Date
6bd74c851b Sun May 31 2020 2020-07-09 02:00:53 +03:00
bc4493d042 Wed May 27 2020 2020-07-09 01:59:33 +03:00
1f2a50b164 Mon Apr 27 2020 2020-07-09 01:58:10 +03:00
03b40427af Sat Mar 7 2020 2020-07-09 01:56:38 +03:00
cf7cbbfc85 Sat Jan 18 2020 2020-07-09 01:53:47 +03:00
9 changed files with 732 additions and 250 deletions

View File

@ -17,39 +17,31 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
declare -a DiffArray
declare -a WaveArray
declare -A ModeArray
source /etc/steamcmd/steamcmd.conf source /etc/steamcmd/steamcmd.conf
source /etc/kf2-srv/kf2-srv.conf source /etc/kf2-srv/kf2-srv.conf
ScriptFullname=$(readlink -e "$0") ScriptFullname=$(readlink -e "$0")
ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}') ScriptName=$(echo "$ScriptFullname" | awk -F '/' '{print $NF;}')
ScriptVersion="0.9.1"
AppNum="232130" # Constants. Don't change.
AppServerNum="232130"
AppClientNum="232090"
StrangeConstUID="17825793" StrangeConstUID="17825793"
InstallDir="/usr/games/kf2-srv" ServerBotLogin="srvbot"
ActiveBranch="$InstallDir/activebranch.txt"
AppBin="$InstallDir/Binaries/Win64/KFGameSteamServer.bin.x86_64"
DefaultConfigDir="$InstallDir/KFGame/Config"
CustomMapsDir="$InstallDir/KFGame/Cache"
InstanceConfigDir="/etc/kf2-srv/instances"
InstanceConfigLnk="$DefaultConfigDir/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 () function show_help ()
{ {
# echo "TODO: English description" # echo "TODO: English description"
echo "$ScriptName" echo "$ScriptName v$ScriptVersion"
echo "Централизование управление серверами Killing Floor 2" echo "Централизование управление серверами Killing Floor 2"
echo "Usage:" echo "Usage:"
echo "$ScriptName OPTIONS" echo "${ScriptName} OPTIONS stable branch"
echo "${ScriptName}-beta OPTIONS beta branch"
echo "" echo ""
echo "Mandatory arguments to long options are mandatory for short options too." echo "Mandatory arguments to long options are mandatory for short options too."
echo " -n, --new INSTANCE создает новый ЭКЗЕМПЛЯР сервера" echo " -n, --new INSTANCE создает новый ЭКЗЕМПЛЯР сервера"
@ -65,6 +57,7 @@ function show_help ()
echo " необходимости перекачивает их." echo " необходимости перекачивает их."
echo " -r, --run [OPTIONS] запускает экземпляр сервера с указанными" echo " -r, --run [OPTIONS] запускает экземпляр сервера с указанными"
echo " ПАРАМЕТРАМИ" echo " ПАРАМЕТРАМИ"
echo " -c, --chat MSG [INSTANCE] отправляет сообщение в чат указанных экземпляров"
echo " -st, --start [INSTANCE] запускает указанный ЭКЗЕМПЛЯР сервера; если" echo " -st, --start [INSTANCE] запускает указанный ЭКЗЕМПЛЯР сервера; если"
echo " ЭКЗЕМПЛЯР не указан, запускает все" echo " ЭКЗЕМПЛЯР не указан, запускает все"
echo " автозапускаемые экземпляры сервера" echo " автозапускаемые экземпляры сервера"
@ -80,14 +73,14 @@ function show_help ()
echo " -di, --disable [INSTANCE] удаляет указанный ЭКЗЕМПЛЯР сервера из" echo " -di, --disable [INSTANCE] удаляет указанный ЭКЗЕМПЛЯР сервера из"
echo " автозапуска; если ЭКЗЕМПЛЯР не указан," echo " автозапуска; если ЭКЗЕМПЛЯР не указан,"
echo " удаляет все экземпляры сервера из автозапуска" echo " удаляет все экземпляры сервера из автозапуска"
echo " -ml, --map-list отображает список карт из SteamWorkshop" echo " -wl, --workshop-list отображает список ресурсов из SteamWorkshop"
echo " -ms, --map-sync синхронизирует списки сторонних карт в" 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 " сторонних карт; синхронизирует списки карт из" echo " сторонних карт; синхронизирует списки карт из"
echo " SteamWorkshop между всеми экземплярами серверов" echo " SteamWorkshop между всеми экземплярами серверов"
echo " -ma, --map-add [MAP_ID] добавляет карту из SteamWorkshop по URL или"
echo " WorkshopID"
echo " -md, --map-del [MAP_ID] удаляет карту SteamWorkshop по URL или WorkshopID"
echo "-mrs, --map-rotate-save [INSTANCE] сохраняет текущий порядок карт для" echo "-mrs, --map-rotate-save [INSTANCE] сохраняет текущий порядок карт для"
echo " указанного ЭКЗЕМПЛЯРА сервера; если ЭКЗЕМПЛЯР" echo " указанного ЭКЗЕМПЛЯРА сервера; если ЭКЗЕМПЛЯР"
echo " не указан, сохраняет порядок для всех ЭКЗЕМПЛЯРОВ" echo " не указан, сохраняет порядок для всех ЭКЗЕМПЛЯРОВ"
@ -104,14 +97,22 @@ function show_help ()
echo " -bd, --ban-del [BAN_ID] удаляет пользователя из списка заблокированных" echo " -bd, --ban-del [BAN_ID] удаляет пользователя из списка заблокированных"
echo " допустимо использовать ID3, SteamID, а также" echo " допустимо использовать ID3, SteamID, а также"
echo " ссылку на профиль пользователя" echo " ссылку на профиль пользователя"
echo " -fp, --fix-permissions [INSTANCE] поправить права на ini файлы"
echo " -as, --admin-sync синхронизировать всех админов (заглушка)"
echo " -pg, --password-game PASSWORD [INSTANCE] установить пароль игры для экземпляров"
echo " -pa, --password-admin PASSWORD [INSTANCE] установить пароль админа для экземпляров"
echo " -h, --help display this help and exit" echo " -h, --help display this help and exit"
} }
# Use this function with non-root user only!!! # Use this function with non-root user only!!!
function run_as_root () # $*: Args function run_as_root () # $*: Args
{ {
if [[ -n "$BetaPostfix" ]]; then
BetaPostfix="beta"
fi
if [[ -n $(groups "$USER" | grep -Fo 'wheel') ]]; then if [[ -n $(groups "$USER" | grep -Fo 'wheel') ]]; then
sudo "$ScriptFullname" $* sudo "$ScriptFullname" $BetaPostfix $*
else else
echo "You must be root or sudo-user to run this command." echo "You must be root or sudo-user to run this command."
return 1 return 1
@ -123,7 +124,7 @@ function service_name () # $*: Instance[s]
local Services="" local Services=""
for Instance in $* for Instance in $*
do do
Services+=" kf2-srv@$Instance.service" Services+=" kf2-srv$BetaPostfix@$Instance.service"
done done
echo "$Services" echo "$Services"
} }
@ -156,7 +157,7 @@ function instance_exists () # $1: Instance
function server_exists () function server_exists ()
{ {
if [[ -n $(ls "$InstallDir") ]]; then if [[ -x "$AppBin" ]]; then
return 0 return 0
else else
return 1 return 1
@ -165,8 +166,22 @@ function server_exists ()
function updates_aviable () function updates_aviable ()
{ {
# TODO: implementation 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 return 0
else
return 1
fi
} }
function new_instance () # $*: InstanceName[s] function new_instance () # $*: InstanceName[s]
@ -186,9 +201,9 @@ function new_instance () # $*: InstanceName[s]
for Instance in $(show_instances) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/main.conf" local Config="$InstanceConfigDir/$Instance/main.conf"
local GamePort=$(grep -Po '"-port=([0-9]+)' "$Config" | grep -Po '[0-9]+$') local GamePort=$(multini --get "$Config" '' 'PortGame')
local WebAdminPort=$(grep -Po '"-webadminport=([0-9]+)' "$Config" | grep -Po '[0-9]+$') local WebAdminPort=$(multini --get "$Config" '' 'PortWeb')
local QueryPort=$(grep -Po '"-queryport=([0-9]+)' "$Config" | grep -Po '[0-9]+$') local QueryPort=$(multini --get "$Config" '' 'PortQuery')
if [[ "$GamePort" -gt "$MaxGamePort" ]]; then MaxGamePort="$GamePort"; fi if [[ "$GamePort" -gt "$MaxGamePort" ]]; then MaxGamePort="$GamePort"; fi
if [[ "$QueryPort" -gt "$MaxQueryPort" ]]; then MaxQueryPort="$QueryPort"; fi if [[ "$QueryPort" -gt "$MaxQueryPort" ]]; then MaxQueryPort="$QueryPort"; fi
if [[ "$WebAdminPort" -gt "$MaxWebAdminPort" ]]; then MaxWebAdminPort="$WebAdminPort"; fi if [[ "$WebAdminPort" -gt "$MaxWebAdminPort" ]]; then MaxWebAdminPort="$WebAdminPort"; fi
@ -202,28 +217,34 @@ function new_instance () # $*: InstanceName[s]
fi fi
local InstanceDir="$InstanceConfigDir/$Instance" local InstanceDir="$InstanceConfigDir/$Instance"
install -d -g "$SteamUser" -o "$SteamUser" -m 755 "$InstanceDir"
install -d -g "$SteamUser" -o "$SteamUser" -m 755 "$InstanceDir/LinuxServer"
cp -a "$MainConfigTemplate" "$InstanceDir/main.conf" local DirMode="-d -g $SteamUser -o $SteamUser -m 775"
cp -a "$DefaultConfigDir/KFAI.ini" "$InstanceDir" local FileMode=" -g $SteamUser -o $SteamUser -m 664"
cp -a "$DefaultConfigDir/KFWeb.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFEngine.ini" "$InstanceDir" install $DirMode "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFGame.ini" "$InstanceDir" install $DirMode "$InstanceDir/LinuxServer"
cp -a "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer-KFSystemSettings.ini" "$InstanceDir" install $FileMode "$MainConfigTemplate" "$InstanceDir/main.conf"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerEngine.ini" "$InstanceDir/LinuxServer" install $FileMode "$DefaultConfigDir/KFAI.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" "$InstanceDir/LinuxServer" install $FileMode "$DefaultConfigDir/KFWeb.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerInput.ini" "$InstanceDir/LinuxServer" install $FileMode "$DefaultConfigDir/KFWebAdmin.ini" "$InstanceDir"
cp -a "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer" install $FileMode "$DefaultConfigDir/KFMultiAdmin.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++)) ((MaxGamePort++)); ((MaxQueryPort++)); ((MaxWebAdminPort++))
sed -i -r --follow-symlinks "s/-port=[0-9]+/-port=$MaxGamePort/g" "$InstanceDir/main.conf" multini -s "$InstanceDir/main.conf" '' 'PortGame' "$MaxGamePort"
sed -i -r --follow-symlinks "s/-queryport=[0-9]+/-queryport=$MaxQueryPort/g" "$InstanceDir/main.conf" multini -s "$InstanceDir/main.conf" '' 'PortQuery' "$MaxQueryPort"
sed -i -r --follow-symlinks "s/-webadminport=[0-9]+/-webadminport=$MaxWebAdminPort/g" "$InstanceDir/main.conf" multini -s "$InstanceDir/main.conf" '' 'PortWeb' "$MaxWebAdminPort"
echo "Instance $Instance created. See /etc/$ScriptName/instances/$Instance for edit configuration" echo "Instance $Instance created. See /etc/$ScriptName/instances$BetaPostfix/$Instance for edit configuration"
done done
} }
@ -270,31 +291,37 @@ function show_status_implementation_body () # $*: [InstanceName[s]]
local IsRuning="stopped" local IsRuning="stopped"
fi fi
local Description=$(grep -P 'Description=' "$InstanceConfigDir/$Instance/main.conf" | sed -r 's/(Description=|")//g') local Comment=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "Comment")
local GamePort=$(grep -Po '"-port=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$') local GamePort=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "PortGame")
local WebAdminPort=$(grep -Po '"-webadminport=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$') local WebAdminPort=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "PortWeb")
local QueryPort=$(grep -Po '"-queryport=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$') local QueryPort=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "PortQuery")
local GameType=$(grep -Po 'Game=([^\?]+)' "$InstanceConfigDir/$Instance/main.conf" | sed -r 's/Game=([^?]+)/\1/g' ) local GameType=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "Game")
local GameLength=$(grep -Po 'GameLength=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$') local GameLength=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "Length")
local GameDifficulty=$(grep -Po 'Difficulty=([0-9]+)' "$InstanceConfigDir/$Instance/main.conf" | grep -Po '[0-9]+$') local GameDifficulty=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "Difficulty")
local Map=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "Map")
local Args=$( multini -g "$InstanceConfigDir/$Instance/main.conf" '' "Args")
local DisplayGameType=${ModeArray[$GameType]} local DisplayGameType=${ModeArray[$GameType]}
local DisplayGameLength=${WaveArray[$GameLength]} local DisplayGameLength=${WaveArray[$GameLength]}
local DisplayDifficulty=${DiffArray[$GameDifficulty]} local DisplayDifficulty=${DiffArray[$GameDifficulty]}
if [[ "$DisplayGameType" == 'Weekly' || \ if [[ -z "$DisplayGameType" ]]; then
"$DisplayGameType" == 'Endless' || \ DisplayGameType="$GameType"
"$DisplayGameType" == 'Versus' || \ fi
"$DisplayGameType" == 'Objective' ]]; then
if [[ "$GameType" == 'KFGameContent.KFGameInfo_WeeklySurvival' || \
"$GameType" == 'KFGameContent.KFGameInfo_Endless' || \
"$GameType" == 'KFGameContent.KFGameInfo_VersusSurvival' || \
"$GameType" == 'KFGameContent.KFGameInfo_Objective' ]]; then
DisplayGameLength='-' DisplayGameLength='-'
fi fi
if [[ "$DisplayGameType" == 'Weekly' || \ if [[ "$GameType" == 'KFGameContent.KFGameInfo_WeeklySurvival' || \
"$DisplayGameType" == 'Versus' ]]; then "$DisplayGameType" == 'KFGameContent.KFGameInfo_VersusSurvival' ]]; then
DisplayDifficulty='-' DisplayDifficulty='-'
fi fi
echo -e "$Instance:$IsEnabled:$IsRuning:$GamePort:$QueryPort:$WebAdminPort:$DisplayGameType:$DisplayGameLength:$DisplayDifficulty:$Description" echo -e "$Instance:$IsEnabled:$IsRuning:$GamePort:$QueryPort:$WebAdminPort:$DisplayGameType:$DisplayGameLength:$DisplayDifficulty:$Args:$Comment"
done done
} }
@ -312,7 +339,7 @@ function show_status_implementation_full () # $*: [InstanceName[s]]
done done
fi fi
echo -e "INSTANCE:AUTORUN:STATE:P_GAME:P_QUERY:P_WEB:TYPE:LEN:DIFF:DESCRIPTION" echo -e "INSTANCE:AUTORUN:STATE:P_GAME:P_QUERY:P_WEB:TYPE:LEN:DIFF:ARGS:COMMENT"
show_status_implementation_body "$InstanceList" | sort -t : -k 4 show_status_implementation_body "$InstanceList" | sort -t : -k 4
} }
@ -323,27 +350,26 @@ function show_status () # $*: [InstanceName[s]]
function validate () function validate ()
{ {
if [[ -n "$BranchName" ]]; then if [[ -n "$BetaPostfix" ]]; then
local BetaArg="-beta $BranchName" local BetaArg="-beta preview"
fi fi
stop_instance stop_instance
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg validate +exit steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppServerNum $BetaArg validate +exit
echo "$BranchName" > "$ActiveBranch" fix_steamclient_so
start_instance start_instance
} }
function link_default_instance () function make_default_instance () # $1: Dir
{ {
local Instance="default" local InstanceDir="$InstanceConfigDir/default"
if instance_exists "$Instance"; then
echo "Instance $Instance already exists - skip" install -d -g "$SteamUser" -o "$SteamUser" -m 775 "$InstanceDir"
else install -d -g "$SteamUser" -o "$SteamUser" -m 775 "$InstanceDir/LinuxServer"
local InstanceDir="$InstanceConfigDir/$Instance" install -g "$SteamUser" -o "$SteamUser" -m 664 "$MainConfigTemplate" "$InstanceDir/main.conf"
install -d -g "$SteamUser" -o "$SteamUser" -m 755 "$InstanceDir"
install -d -g "$SteamUser" -o "$SteamUser" -m 755 "$InstanceDir/LinuxServer"
cp -a "$MainConfigTemplate" "$InstanceDir/main.conf"
ln -s "$DefaultConfigDir/KFAI.ini" "$InstanceDir/KFAI.ini" ln -s "$DefaultConfigDir/KFAI.ini" "$InstanceDir/KFAI.ini"
ln -s "$DefaultConfigDir/KFWeb.ini" "$InstanceDir/KFWeb.ini" ln -s "$DefaultConfigDir/KFWeb.ini" "$InstanceDir/KFWeb.ini"
ln -s "$DefaultConfigDir/KFWebAdmin.ini" "$InstanceDir/KFWebAdmin.ini"
ln -s "$DefaultConfigDir/KFMultiAdmin.ini" "$InstanceDir/KFMultiAdmin.ini"
ln -s "$DefaultConfigDir/LinuxServer-KFEngine.ini" "$InstanceDir/LinuxServer-KFEngine.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-KFGame.ini" "$InstanceDir/LinuxServer-KFGame.ini"
ln -s "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir/LinuxServer-KFInput.ini" ln -s "$DefaultConfigDir/LinuxServer-KFInput.ini" "$InstanceDir/LinuxServer-KFInput.ini"
@ -352,9 +378,38 @@ function link_default_instance ()
ln -s "$DefaultConfigDir/LinuxServer/LinuxServerGame.ini" "$InstanceDir/LinuxServer/LinuxServerGame.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/LinuxServerInput.ini" "$InstanceDir/LinuxServer/LinuxServerInput.ini"
ln -s "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer/LinuxServerSystemSettings.ini" ln -s "$DefaultConfigDir/LinuxServer/LinuxServerSystemSettings.ini" "$InstanceDir/LinuxServer/LinuxServerSystemSettings.ini"
fix_ini_permissions "$InstanceDir"
fix_ini_eol "$InstanceDir"
}
function fix_permissions () # $*: Instance[s]
{
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
fix_ini_permissions "$InstanceConfigDir"
else
for Instance in $InstanceList
do
fix_ini_permissions "$InstanceConfigDir/$Instance"
done
fi fi
} }
function fix_ini_permissions () # $1: Dir
{
find "$1" \( -type l -o -type f \) -name '*.ini' | \
xargs --max-procs=$(nproc) -I {} \
sh -c "chmod 664 {}; chown $SteamUser:$SteamUser {}"
}
function fix_ini_eol () # $1: Dir
{
find "$1" \( -type l -o -type f \) -name '*.ini' | \
xargs --max-procs=$(nproc) -I {} \
sh -c "dos2unix -F {}"
}
function fix_steamclient_so () function fix_steamclient_so ()
{ {
rm -f "$InstallDir/linux64/steamclient.so" rm -f "$InstallDir/linux64/steamclient.so"
@ -365,18 +420,46 @@ function fix_steamclient_so ()
ln -s "/usr/share/steamcmd/linux64/steamclient.so" "$InstallDir/Binaries/Win64/lib64/steamclient.so" ln -s "/usr/share/steamcmd/linux64/steamclient.so" "$InstallDir/Binaries/Win64/lib64/steamclient.so"
} }
function update_kf2 () function create_map_dirs ()
{ {
if [[ -n "$BranchName" ]]; then # space saving
local BetaArg="-beta $BranchName" 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 fi
if ! server_exists; then # First install else # Beta
echo "$BranchName" > "$ActiveBranch" sudo -u "$SteamUser" install -d -m 775 "$DownloadDirBeta"
if ! steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg validate +exit; then 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 first_install ()
{
if ! steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppServerNum $BetaArg validate +exit; then
echo "Errors during installation - exit" echo "Errors during installation - exit"
exit 1 exit 1
fi fi
sudo -u "$SteamUser" $AppBin &
echo "Creating base ini files"
sudo -u "$SteamUser" $AppBin &> /dev/null &
while true while true
do do
if [[ -e "$DefaultConfigDir/KFAI.ini" ]] && if [[ -e "$DefaultConfigDir/KFAI.ini" ]] &&
@ -393,22 +476,85 @@ function update_kf2 ()
fi fi
sleep 2 sleep 2
done done
killall -KILL KFGameSteamServer.bin.x86_64 killall -KILL KFGameSteamServer.bin.x86_64; sleep 1
#$InstallDir/Binaries/Win64/steamapps/workshop/content/232090/1078911795/BrewedPC/Maps/KF-HorzineArena-B2-v6.kfm echo "Setting up WebAdmin"
#$InstallDir/KFGame/Cache/1078911795/0/BrewedPC/Maps/KF-HorzineArena-B2-v6.kfm multini -s "$DefaultConfigDir/KFWeb.ini" "IpDrv.WebServer" "bEnabled" "true"
install -d -g "$SteamUser" -o "$SteamUser" -m 755 "$CustomMapsDir" sudo -u "$SteamUser" $AppBin &> /dev/null &
while true
do
if [[ -e "$DefaultConfigDir/KFWebAdmin.ini" ]]; then
break
fi
sleep 2
done
killall -KILL KFGameSteamServer.bin.x86_64; sleep 1
multini -s "$DefaultConfigDir/KFWebAdmin.ini" "WebAdmin.WebAdmin" "AuthenticationClass" "WebAdmin.MultiWebAdminAuth"
multini -s "$DefaultConfigDir/KFWebAdmin.ini" "WebAdmin.WebAdmin" "bHttpAuth" "True"
echo "Wait while WebAdmin up"
sudo -u "$SteamUser" $AppBin &> /dev/null &
while ! curl -s -o "/dev/null" -u "Admin:Admin" "localhost:8080"
do
sleep 2
done
echo "Setting up server bot"
while ! curl -s -o "/dev/null" \
-u "Admin:Admin" \
"localhost:8080/ServerAdmin/multiadmin" \
--request POST \
--data adminid="$ServerBotLogin" \
--data action="create"
do sleep 2; done
while ! multini -gq \
"$DefaultConfigDir/KFMultiAdmin.ini" \
"$ServerBotLogin MultiAdminData" \
"Password"
do sleep 2; done
while ! curl -s -o "/dev/null" \
-u "Admin:Admin" \
"localhost:8080/ServerAdmin/multiadmin" \
--request POST \
--data adminid="$ServerBotLogin" \
--data displayname="ServerBot" \
--data enabled=1 \
--data password1="$ServerBotPassword" \
--data password2="$ServerBotPassword" \
--data order="DenyAllow" \
--data deny= \
--data allow= \
--data action="save"
do sleep 2; done
while [[ -z $(multini -g \
"$DefaultConfigDir/KFMultiAdmin.ini" \
"$ServerBotLogin MultiAdminData" \
"Password") ]]
do sleep 2; done
killall -KILL KFGameSteamServer.bin.x86_64; sleep 1
create_map_dirs
fix_steamclient_so fix_steamclient_so
ln -s "$InstanceConfigDir" "$InstanceConfigLnk" ln -s "$InstanceConfigDir" "$InstanceConfigLnk"
link_default_instance make_default_instance
echo "KF2 succesfully installed" echo "KF2 succesfully installed"
elif updates_aviable; then # Update }
if [[ "$BranchName" == $(cat "$ActiveBranch") ]]; then
function update_kf2 ()
{
if [[ -n "$BetaPostfix" ]]; then
local BetaArg="-beta preview"
fi
if ! server_exists; then
first_install
elif updates_aviable; then
stop_instance stop_instance
steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppNum $BetaArg +exit steamcmd +login $SteamLogin +force_install_dir $InstallDir +app_update $AppServerNum $BetaArg +exit
start_instance start_instance
else else
validate echo "Server is up to date"
fi
fi fi
} }
@ -548,34 +694,61 @@ function run ()
fi fi
} }
function map_list_ext () # $1: MaplistFile 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
{ {
local Num=1
echo "NUM WORKSHOP_ID WORKSHOP_URL"
while read WorkshopID while read WorkshopID
do do
local Cache="$CacheDir/$WorkshopID"
local Downl="$DownloadDir/$WorkshopID"
local Url="https://steamcommunity.com/sharedfiles/filedetails/?id=$WorkshopID" local Url="https://steamcommunity.com/sharedfiles/filedetails/?id=$WorkshopID"
echo "$Num $WorkshopID $Url" local WsName=$(name_by_workshopID "$WorkshopID")
((Num++)) 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" done < "$1"
} }
function map_list () # $1: [--human-readable] function workshop_list_full () # $1: WorkshoplistFile
{ {
# TODO: Show map names (sizes?) echo "WORKSHOP_ID NAME SIZE WORKSHOP_URL"
local MapList=$(mktemp) workshop_list_body "$1" | sort -k 2
}
function workshop_list () # $1: [--human-readable]
{
# TODO: Multiple *.kfm/*u in folder
local WsList=$(mktemp)
for Instance in $(show_instances) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini" local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini"
grep -P 'ServerSubscribedWorkshopItems=' "$Config" | sed -r 's/.+=([0-9]+)$/\1/' >> "$MapList" if multini -gq "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems"; then
done multini -g "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" >> "$WsList"
sort -u "$MapList" -o "$MapList"
if [[ -n "$1" ]]; then
map_list_ext "$MapList" | column -t
else
cat "$MapList"
fi fi
rm -f "$MapList" 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 function any_to_workshopID () # $1: WorkshopID/URL
@ -588,83 +761,85 @@ function any_to_workshopID () # $1: WorkshopID/URL
echo "$WorkshopID" echo "$WorkshopID"
} }
function map_add () # $*: WorkshopID[s] function workshop_add () # $*: WorkshopID[s]
{ {
for Instance in $(show_instances) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini" local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini"
if ! grep -qF '[OnlineSubsystemSteamworks.KFWorkshopSteamworks]' "$Config"; then multini -ar "$Config" "IpDrv.TcpNetDriver" "DownloadManagers" "OnlineSubsystemSteamworks.SteamWorkshopDownload"
echo -e '
[OnlineSubsystemSteamworks.KFWorkshopSteamworks]' >> "$Config"
fi
if ! grep -qF 'DownloadManagers=OnlineSubsystemSteamworks.SteamWorkshopDownload' "$Config"; then
sed -i --follow-symlinks -r '0,/DownloadManagers=/ s/^(DownloadManagers=.+)$/DownloadManagers=OnlineSubsystemSteamworks.SteamWorkshopDownload
\1/' "$Config"
fi
for Map in $* for Map in $*
do do
local WorkshopID=$(any_to_workshopID "$Map") local WorkshopID=$(any_to_workshopID "$Map")
local MapStr="ServerSubscribedWorkshopItems=$WorkshopID" if ! multini -gq "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" "$WorkshopID"; then
if ! grep -qF "$MapStr" "$Config"; then echo "Add workshop $WorkshopID to $Instance"
echo "Add map $WorkshopID to $Instance" multini -ar "$Config" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" "$WorkshopID"
sed -i --follow-symlinks "/^\[OnlineSubsystemSteamworks\.KFWorkshopSteamworks\]/a $MapStr" "$Config"
fi fi
done done
done done
} }
function map_del () # $*: WorkshopID[s] function workshop_del () # $*: WorkshopID[s]
{ {
# TODO: Remove lines from LinuxServer-KFGame.ini, clear cache
for Map in $* for Map in $*
do do
local WorkshopID=$(any_to_workshopID "$Map") 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) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini" local ConfigEngine="$InstanceConfigDir/$Instance/LinuxServer-KFEngine.ini"
local MapStr="ServerSubscribedWorkshopItems=$WorkshopID" multini -d "$ConfigEngine" "OnlineSubsystemSteamworks.KFWorkshopSteamworks" "ServerSubscribedWorkshopItems" "$WorkshopID"
if grep -qF "$MapStr" "$Config"; then if echo "$WsName" | grep -qP '\.kfm$' ; then
echo "Remove map $WorkshopID from $Instance" echo "Remove map $WorkshopID ($WsName) from $Instance"
sed -i --follow-symlinks "/$MapStr/d" "$Config" local WsNameShort=$(echo "$WsName" | sed 's/\.kfm$//')
local ConfigGame="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
multini -d "$ConfigGame" "$WsNameShort KFMapSummary"
fi fi
done done
done done
} }
function map_sync () function workshop_sync ()
{ {
#local InstanceList="$*" workshop_add $(workshop_list)
#if [[ -z "$InstanceList" ]] ; then
# InstanceList=$(show_instances)
#fi
map_add $(map_list)
# TODO: Make it faster
for Instance in $(show_instances) for Instance in $(show_instances)
do do
if instance_exists "$Instance"; then local Service=$(service_name "$Instance")
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini" if ! instance_exists "$Instance"; then
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" echo "Instance $Instance not exitst"
elif systemctl -q is-active $Service ; then
echo "Instance $Instance is running - skip."
else
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
fi fi
done done
} }
@ -689,6 +864,16 @@ function map_rotate_save () # $*: Instance[s]
done done
} }
function map_rotate_to_webstring () # $1: MapRotate
{
local RN='%0D%0A'
echo "$1" | \
sed -r 's/^\(Maps=\("//' | \
sed -r 's/"\)\)$//' | \
sed 's/ /+/g' | \
sed "s/\",\"/${RN}/g"
}
function map_rotate_load () # $*: Instance[s] function map_rotate_load () # $*: Instance[s]
{ {
local InstanceList="$*" local InstanceList="$*"
@ -698,17 +883,42 @@ function map_rotate_load () # $*: Instance[s]
for Instance in $InstanceList for Instance in $InstanceList
do do
if instance_exists "$Instance"; then local Service=$(service_name "$Instance")
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local MapRotate="$InstanceConfigDir/$Instance/MapRotate.ini" local MapRotate="$InstanceConfigDir/$Instance/MapRotate.ini"
if [[ -e "$MapRotate" ]]; then if ! instance_exists "$Instance"; then
sed -i --follow-symlinks -r "/(ActiveMapCycle=|GameMapCycles=)/d" "$Config" echo "Instance $Instance not exists"
sed -i --follow-symlinks "/\[KFGame\.KFGameInfo\]/ r $MapRotate" "$Config" elif ! [[ -e "$MapRotate" ]]; then
else
echo "$MapRotate not found - skip" echo "$MapRotate not found - skip"
elif systemctl -q is-active $Service ; then
# TODO: Delete other cycles
# Example: maplistidx=1&mapcycle=KF-Airship%0D%0A&delete=doit
local ActiveCycleIndex=$(multini -g "$MapRotate" '' 'ActiveMapCycle')
local ActiveCycleWeb=''
local Index=0
while read MapCycle
do
local MapCycleWeb=$(map_rotate_to_webstring "$MapCycle")
admin_curl "$Instance" "ServerAdmin/settings/maplist" \
--request POST \
--data maplistidx="$Index" \
--data mapcycle="$MapCycleWeb" \
--data action="save"
if [[ "$Index" -eq "$ActiveCycleIndex" ]]; then
ActiveCycleWeb="$MapCycleWeb"
fi
((Index++))
done < <(multini -g "$MapRotate" '' 'GameMapCycles')
if [[ -n "$ActiveCycleWeb" ]]; then
admin_curl "$Instance" "ServerAdmin/settings/maplist" \
--request POST \
--data maplistidx="$ActiveCycleIndex" \
--data mapcycle="$ActiveCycleWeb" \
--data activate="activate"
fi fi
else else
echo "Instance $Instance not exitst" local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
sed -i --follow-symlinks -r "/(ActiveMapCycle=|GameMapCycles=)/d" "$Config"
sed -i --follow-symlinks "/\[KFGame\.KFGameInfo\]/ r $MapRotate" "$Config"
fi fi
done done
} }
@ -736,12 +946,16 @@ function steamID64_to_steamID3 () # $1: ID4
function ban_list_ext () # $1: BanlistFile function ban_list_ext () # $1: BanlistFile
{ {
local Num=1 local Num=1
echo "NUM STEAM_ID3 STEAM_ID64 PROFILE_URL" echo "NUM STEAM_ID3 STEAM_ID64 URL_CONST URL_EFFECTIVE"
while read ID3 while read ID3
do do
local ID64=$(steamID3_to_steamID64 "$ID3") local ID64=$(steamID3_to_steamID64 "$ID3")
local Url=$(curl "https://steamcommunity.com/profiles/$ID64" -s -L -I -o /dev/null -w '%{url_effective}') local UrlConst="https://steamcommunity.com/profiles/$ID64"
echo "$Num $ID3 $ID64 $Url" local UrlEffective=$(curl "$UrlConst" -s -L -I -o /dev/null -w '%{url_effective}')
if [[ "$UrlConst" == "$UrlEffective" ]]; then
UrlEffective="-"
fi
echo "$Num $ID3 $ID64 $UrlConst $UrlEffective"
((Num++)) ((Num++))
done < "$1" done < "$1"
} }
@ -752,7 +966,9 @@ function ban_list () # $1: [--human-readable]
for Instance in $(show_instances) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini" local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
grep -P 'BannedIDs=' "$Config" | sed -r 's/.+A=([0-9]+),.+/\1/' >> "$BanList" if multini -gq "$Config" "Engine.AccessControl" "BannedIDs"; then
multini -g "$Config" "Engine.AccessControl" "BannedIDs" | sed -r 's/.+A=([0-9]+),.+/\1/' >> "$BanList"
fi
done done
sort -u "$BanList" -o "$BanList" sort -u "$BanList" -o "$BanList"
if [[ -n "$1" ]]; then if [[ -n "$1" ]]; then
@ -769,10 +985,19 @@ function ban_ID3 () # $1: ID3
for Instance in $(show_instances) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini" local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local BanStr="BannedIDs=(Uid=(A=$ID3,B=$StrangeConstUID))" local BanStr="(Uid=(A=$ID3,B=$StrangeConstUID))"
if ! grep -qF "$BanStr" "$Config"; then local Service=$(service_name "$Instance")
if ! multini -gq "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"; then
echo "Add ban $ID3 to $Instance" echo "Add ban $ID3 to $Instance"
sed -i --follow-symlinks "/^\[Engine\.AccessControl\]/a $BanStr" "$Config" if systemctl -q is-active $Service ; then
admin_curl "$Instance" "ServerAdmin/policy/bans" \
--request POST \
--data action="add" \
--data steamint64=$(steamID3_to_steamID64 $ID3) \
--data uniqueid=
else
multini -a "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"
fi
fi fi
done done
} }
@ -783,10 +1008,19 @@ function unban_ID3 () # $1: ID3
for Instance in $(show_instances) for Instance in $(show_instances)
do do
local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini" local Config="$InstanceConfigDir/$Instance/LinuxServer-KFGame.ini"
local BanStr="BannedIDs=(Uid=(A=$ID3,B=$StrangeConstUID))" local BanStr="(Uid=(A=$ID3,B=$StrangeConstUID))"
if grep -qF "$BanStr" "$Config"; then local Service=$(service_name "$Instance")
if systemctl -q is-active $Service ; then
echo "Instance $Instance is running - skip."
# TODO: delete ban with webadmin/curl
# POST Body example:
# banid=plainid%3A8&action=delete
# WTF is plainID?!
else
if multini -gq "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"; then
echo "Remove ban $ID3 from $Instance" echo "Remove ban $ID3 from $Instance"
sed -i --follow-symlinks "/$BanStr/d" "$Config" multini -d "$Config" "Engine.AccessControl" "BannedIDs" "$BanStr"
fi
fi fi
done done
} }
@ -842,6 +1076,129 @@ function ban_sync ()
done done
} }
function admin_sync ()
{
# TODO: Implementation
echo "Dummy"
}
function admin_curl () # $1: Instance, $2: URL, $*: Request
{
local Instance="$1"
local URL="$2"
local MainConf="$InstanceConfigDir/$Instance/main.conf"
local WebPort=$(multini --get "$MainConf" '' "PortWeb")
shift; shift
curl -s -o "/dev/null" -u "$ServerBotLogin:$ServerBotPassword" "localhost:$WebPort/$URL" $*
}
function password_game () # $1: Password (if empty, use: ''), $*: Instance[s]
{
if echo "$1" | grep -qP '\s'; then
echo "Password should not contain spaces"
return 1
fi
local Password="$1"; shift
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 Service=$(service_name "$Instance")
if systemctl -q is-active $Service ; then
admin_curl "$Instance" "ServerAdmin/policy/passwords" \
--request POST \
--data action="gamepassword" \
--data gamepw1="$Password" \
--data gamepw2="$Password"
else
multini -s "$Config" "Engine.AccessControl" "GamePassword" "$Password"
fi
else
echo "Instance $Instance not exitst"
fi
done
}
function password_admin () # $1: Password (if empty, use: ''), $*: Instance[s]
{
if echo "$1" | grep -qP '\s'; then
echo "Password should not contain spaces"
return 1
fi
local Password="$1"; shift
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 Service=$(service_name "$Instance")
if systemctl -q is-active $Service ; then
admin_curl "$Instance" "ServerAdmin/policy/passwords" \
--request POST \
--data action="adminpassword" \
--data adminpw1="$Password" \
--data adminpw2="$Password"
else
multini -s "$Config" "Engine.AccessControl" "AdminPassword" "$Password"
fi
else
echo "Instance $Instance not exitst"
fi
done
}
function chat ()
{
local Message=$(echo "$1" | sed 's/ /+/g')
shift
local InstanceList="$*"
if [[ -z "$InstanceList" ]] ; then
InstanceList=$(show_instances)
fi
for Instance in $InstanceList
do
if instance_exists "$Instance"; then
local Service=$(service_name "$Instance")
if systemctl -q is-active $Service ; then
admin_curl "$Instance" "ServerAdmin/current/chat+frame+data" \
--request POST \
--data ajax=1 \
--data message="$Message" \
--data teamsay=-1
else
echo "Instance $Instance not running - skip"
fi
else
echo "Instance $Instance not exitst"
fi
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 if [[ $# -eq 0 ]]; then show_help; exit 0; fi
case $1 in case $1 in
-h|--help ) show_help; ;; -h|--help ) show_help; ;;
@ -851,20 +1208,25 @@ case $1 in
-u|--update ) if [[ "$EUID" -eq 0 ]]; then update_kf2 ; else run_as_root $*; fi ;; -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 ;; -v|--validate ) if [[ "$EUID" -eq 0 ]]; then validate ; else run_as_root $*; fi ;;
-r|--run ) shift; run $*; ;; -r|--run ) shift; run $*; ;;
-c|--chat ) shift; Msg="$1"; shift; chat "$Msg" $*; ;;
-st|--start ) if [[ "$EUID" -eq 0 ]]; then shift; start_instance $*; else run_as_root $*; fi ;; -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 ;; -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 ;; -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 ;; -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 ;; -di|--disable ) if [[ "$EUID" -eq 0 ]]; then shift; disable_instance $*; else run_as_root $*; fi ;;
-ml|--map-list ) if [[ "$EUID" -eq 0 ]]; then shift; map_list "-h" ; else run_as_root $*; fi ;; -wl|--workshop-list ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_list "-h" ; else run_as_root $*; fi ;;
-ms|--map-sync ) if [[ "$EUID" -eq 0 ]]; then shift; map_sync ; else run_as_root $*; fi ;; -wa|--workshop-add ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_add $*; else run_as_root $*; fi ;;
-ma|--map-add ) if [[ "$EUID" -eq 0 ]]; then shift; map_add $*; else run_as_root $*; fi ;; -wd|--workshop-del ) if [[ "$EUID" -eq 0 ]]; then shift; workshop_del $*; else run_as_root $*; fi ;;
-md|--map-del ) if [[ "$EUID" -eq 0 ]]; then shift; map_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 ;; -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 ;; -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 ;; -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 ;; -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 ;; -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 ;; -bd|--ban-del ) if [[ "$EUID" -eq 0 ]]; then shift; ban_del $*; else run_as_root $*; fi ;;
-fp|--fix-permissions ) if [[ "$EUID" -eq 0 ]]; then shift; fix_permissions $*; else run_as_root $*; fi ;;
-as|--admin-sync ) if [[ "$EUID" -eq 0 ]]; then shift; admin_sync ; else run_as_root $*; fi ;;
-pg|--password-game ) if [[ "$EUID" -eq 0 ]]; then shift; Pass="$1"; shift ; password_game "$Pass" $*; else run_as_root $*; fi ;;
-pa|--password-admin ) if [[ "$EUID" -eq 0 ]]; then shift; Pass="$1"; shift ; password_admin "$Pass" $*; else run_as_root $*; fi ;;
* ) echo "Command not recognized: $1"; exit 1 ;; * ) echo "Command not recognized: $1"; exit 1 ;;
esac esac

3
SOURCES/kf2-srv-beta Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
/usr/bin/kf2-srv beta $*

View File

@ -0,0 +1,14 @@
[Unit]
Description=Check and Update Killing Floor 2 server
[Service]
Type=simple
ExecStart=/usr/bin/kf2-srv-beta --update
PrivateTmp=true
PrivateDevices=true
ProtectHome=false
ProtectSystem=false
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=Check and Update killing Floor 2 beta job
[Timer]
OnCalendar=Wed, 04:00
Unit=kf2-srv-beta-update.service
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,21 @@
[Unit]
Description=Killing Floor 2 Beta Server Daemon - %i
[Service]
User=steam
Group=steam
Type=simple
StandardOutput=null
StandardError=null
EnvironmentFile=/etc/kf2-srv/instances-beta/%i/main.conf
ExecStart=/usr/games/kf2-srv-beta/Binaries/Win64/KFGameSteamServer.bin.x86_64 ${Map}?Difficulty=${Difficulty}?GameLength=${Length}?Game=${Game}${Args} configsubdir=instances/%i -webadminport=${PortWeb} -queryport=${PortQuery} -port=${PortGame}
Restart=always
NoNewPrivileges=yes
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=false
[Install]
WantedBy=multi-user.target

20
SOURCES/kf2-srv.conf Normal file → Executable file
View File

@ -1 +1,19 @@
#BranchName="preview" # Displays game difficulty
# You can rename them as you like
DiffArray=('Normal' 'Hard' 'Suicide' 'Hell')
# Displays the number of waves
# You can rename them as you like
WaveArray=('4' '7' '10')
# Add custom gamemodes to the end of the list, similar to what is already there:
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'
# Bot default password
# To change the password for the bot, you must do this here and in WebAdmin.
# Otherwise, the bot will stop working and some actions cannot be done on running servers
ServerBotPassword=VerySecretBotPassword

View File

@ -8,7 +8,7 @@ Type=simple
StandardOutput=null StandardOutput=null
StandardError=null StandardError=null
EnvironmentFile=/etc/kf2-srv/instances/%i/main.conf EnvironmentFile=/etc/kf2-srv/instances/%i/main.conf
ExecStart=/usr/games/kf2-srv/Binaries/Win64/KFGameSteamServer.bin.x86_64 $Args configsubdir=instances/%i $PortW $PortQ $PortG ExecStart=/usr/games/kf2-srv/Binaries/Win64/KFGameSteamServer.bin.x86_64 ${Map}?Difficulty=${Difficulty}?GameLength=${Length}?Game=${Game}${Args} configsubdir=instances/%i -webadminport=${PortWeb} -queryport=${PortQuery} -port=${PortGame}
Restart=always Restart=always
NoNewPrivileges=yes NoNewPrivileges=yes

View File

@ -1,29 +1,36 @@
LANG=en_US.UTF-8 LANG=en_US.UTF-8
PortW="-webadminport=8080" PortWeb=8080
PortQ="-queryport=27015" PortQuery=27015
PortG="-port=7777" PortGame=7777
# Default Map
Map=KF-Nuked
# First arg: map name
#
# Difficulty: # Difficulty:
# Normal: 0 # Normal: 0
# Hard: 1 # Hard: 1
# Suicide: 2 # Suicide: 2
# Hell: 3 # Hell: 3
# Difficulty=2
# Game: # Game:
# Survival: KFGameContent.KFGameInfo_Survival # Survival: KFGameContent.KFGameInfo_Survival
# WeeklyOutbreak: KFGameContent.KFGameInfo_WeeklySurvival # WeeklyOutbreak: KFGameContent.KFGameInfo_WeeklySurvival
# Endless: KFGameContent.KFGameInfo_Endless # Endless: KFGameContent.KFGameInfo_Endless
# Objective: KFGameContent.KFGameInfo_Objective # Objective: KFGameContent.KFGameInfo_Objective
# Versus: KFGameContent.KFGameInfo_VersusSurvival # Versus: KFGameContent.KFGameInfo_VersusSurvival
# Game=KFGameContent.KFGameInfo_Endless
# GameLength: # GameLength:
# 4 waves: 0 # 4 waves: 0
# 7 waves: 1 # 7 waves: 1
# 10 waves: 2 # 10 waves: 2
Args=kf-bioticslab?Difficulty=0?Game=KFGameContent.KFGameInfo_Survival?GameLength=2 Length=2
# Additional parameters
# If the parameter is used, it must necessarily begin with a character '?'
Args=
# Notes for yourself # Notes for yourself
Description="Default description" Comment=

View File

@ -1,7 +1,7 @@
%global steamuser steam %global steamuser steam
Name: kf2-srv Name: kf2-srv
Version: 0.5.0 Version: 0.9.1
Release: 1%{dist} Release: 1%{dist}
Summary: Killing Floor 2 server Summary: Killing Floor 2 server
Group: Amusements/Games Group: Amusements/Games
@ -9,16 +9,30 @@ License: GNU GPLv3
BuildArch: noarch BuildArch: noarch
Source1: %{name} Source1: %{name}
Source2: %{name}.conf Source2: %{name}-beta
Source3: %{name}.xml Source3: %{name}.xml
Source4: %{name}@.service Source4: %{name}@.service
Source5: %{name}-update.service Source5: %{name}-update.service
Source6: %{name}-update.timer Source6: %{name}-update.timer
Source7: main.conf.template Source7: main.conf.template
Source8: %{name}-beta@.service
Source9: %{name}-beta-update.service
Source10: %{name}-beta-update.timer
Source11: %{name}.conf
Requires: systemd >= 219 Requires: systemd >= 219
Requires: steamcmd Requires: steamcmd
Requires: libxml2 Requires: libxml2
Requires: dos2unix
Requires: curl
Requires: grep
Requires: coreutils
Requires: sed
Requires: util-linux
Requires: sudo
Requires: psmisc
Requires: gawk
Requires: multini >= 0.2.3
Provides: %{name} Provides: %{name}
@ -36,47 +50,81 @@ install -m 755 -d %{buildroot}/%{_bindir}
install -m 755 -d %{buildroot}/%{_prefix}/lib/systemd/system install -m 755 -d %{buildroot}/%{_prefix}/lib/systemd/system
install -m 755 -d %{buildroot}/%{_prefix}/lib/firewalld/services install -m 755 -d %{buildroot}/%{_prefix}/lib/firewalld/services
install -m 755 -d %{buildroot}/%{_sysconfdir}/%{name}/instances install -m 755 -d %{buildroot}/%{_sysconfdir}/%{name}/instances
install -m 755 -d %{buildroot}/%{_sysconfdir}/%{name}/instances-beta
install -m 755 -d %{buildroot}/%{_sysconfdir}/%{name}/mapcycles
install -m 644 -d %{buildroot}/%{_prefix}/games/%{name} install -m 644 -d %{buildroot}/%{_prefix}/games/%{name}
install -m 644 -d %{buildroot}/%{_prefix}/games/%{name}-beta
install -m 755 %{SOURCE1} %{buildroot}/%{_bindir} install -m 755 %{SOURCE1} %{buildroot}/%{_bindir}
install -m 644 %{SOURCE2} %{buildroot}/%{_sysconfdir}/%{name} install -m 644 %{SOURCE2} %{buildroot}/%{_bindir}
install -m 644 %{SOURCE3} %{buildroot}/%{_prefix}/lib/firewalld/services install -m 644 %{SOURCE3} %{buildroot}/%{_prefix}/lib/firewalld/services
install -m 644 %{SOURCE4} %{buildroot}/%{_prefix}/lib/systemd/system install -m 644 %{SOURCE4} %{buildroot}/%{_prefix}/lib/systemd/system
install -m 644 %{SOURCE5} %{buildroot}/%{_prefix}/lib/systemd/system install -m 644 %{SOURCE5} %{buildroot}/%{_prefix}/lib/systemd/system
install -m 644 %{SOURCE6} %{buildroot}/%{_prefix}/lib/systemd/system install -m 644 %{SOURCE6} %{buildroot}/%{_prefix}/lib/systemd/system
install -m 644 %{SOURCE7} %{buildroot}/%{_sysconfdir}/%{name} install -m 644 %{SOURCE7} %{buildroot}/%{_sysconfdir}/%{name}
install -m 644 %{SOURCE8} %{buildroot}/%{_prefix}/lib/systemd/system
sed -i -r "s|^(InstallDir=).*$|\1\"%{_prefix}/games/%{name}\"|g" %{buildroot}/%{_bindir}/%{name} install -m 644 %{SOURCE9} %{buildroot}/%{_prefix}/lib/systemd/system
install -m 644 %{SOURCE10} %{buildroot}/%{_prefix}/lib/systemd/system
install -m 644 %{SOURCE11} %{buildroot}/%{_sysconfdir}/%{name}
%clean %clean
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
%files %files
%attr(775,root,%{steamuser}) %dir %{_prefix}/games/%{name} %attr(775,root,%{steamuser}) %dir %{_prefix}/games/%{name}
%attr(775,root,%{steamuser}) %dir %{_prefix}/games/%{name}-beta
%attr(775,root,%{steamuser}) %dir %{_sysconfdir}/%{name} %attr(775,root,%{steamuser}) %dir %{_sysconfdir}/%{name}
%attr(775,root,%{steamuser}) %dir %{_sysconfdir}/%{name}/instances %attr(775,root,%{steamuser}) %dir %{_sysconfdir}/%{name}/instances
%attr(644,root,root) %{_sysconfdir}/%{name}/main.conf.template %attr(775,root,%{steamuser}) %dir %{_sysconfdir}/%{name}/instances-beta
%attr(644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf %attr(775,root,%{steamuser}) %dir %{_sysconfdir}/%{name}/mapcycles
%attr(644,root,%{steamuser}) %config(noreplace) %{_sysconfdir}/%{name}/main.conf.template
%attr(640,root,%{steamuser}) %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf
%attr(644,root,root) %config(noreplace) %{_prefix}/lib/firewalld/services/%{name}.xml %attr(644,root,root) %config(noreplace) %{_prefix}/lib/firewalld/services/%{name}.xml
%attr(755,root,root) %{_bindir}/%{name} %attr(755,root,root) %{_bindir}/%{name}
%attr(755,root,root) %{_bindir}/%{name}-beta
%attr(644,root,root) %{_prefix}/lib/systemd/system/* %attr(644,root,root) %{_prefix}/lib/systemd/system/*
%post
#/bin/env bash
#if [[ $1 -eq 1 ]]; then # First installation
#
#fi
#exit 0
%preun %preun
#/bin/env bash
if [[ $1 -eq 0 ]] ; then # Uninstall if [[ $1 -eq 0 ]] ; then # Uninstall
%{_bindir}/%{name} --stop %{_bindir}/%{name} --stop
%{_bindir}/%{name} --disable %{_bindir}/%{name} --disable
rm -rf %{_prefix}/games/%{name}/* rm -rf %{_prefix}/games/%{name}/*
rm -rf %{_prefix}/games/%{name}-beta/*
rm -rf %{_sysconfdir}/%{name}/instances/default
rm -rf %{_sysconfdir}/%{name}/instances-beta/default
fi fi
%changelog %changelog
* Sun May 31 2020 GenZmeY <genzmey@gmail.com> - 0.9.1-1
- fix realtime -mrl with spaces;
- mapcycles directory.
* Wed May 27 2020 GenZmeY <genzmey@gmail.com> - 0.9.0-1
- new main.conf format;
- multiple WebAdmin and http auth by default;
- online actions;
- chat-bot;
- set password;
- refactoring.
* Mon Apr 27 2020 GenZmeY <genzmey@gmail.com> - 0.8.0-1
- use multini for ini edit;
- add mutators support;
- refactoring;
- returned "reboot-updates".
* Sat Mar 7 2020 GenZmeY <genzmey@gmail.com> - 0.7.0-1
- dual versions support;
- check updates;
- bugfixes.
* Sat Jan 18 2020 GenZmeY <genzmey@gmail.com> - 0.6.0-1
- versions;
- instance conf tweaks;
- extended map list;
- clear cache on delete map;
- removed useless messages.
* Sun Jan 12 2020 GenZmeY <genzmey@gmail.com> - 0.5.0-1 * Sun Jan 12 2020 GenZmeY <genzmey@gmail.com> - 0.5.0-1
- ban admin; - ban admin;
- map admin; - map admin;