• Please make sure you are familiar with the forum rules. You can find them here: https://forums.tripwireinteractive.com/index.php?threads/forum-rules.2334636/

Server Installing KF 2 Server on Linux with WINE

So I wrote this little script to update the maps/map cycle all my servers at once.
I run 9 severs now. Adding a map/managing the playlist has become a huge hassle.

I have my Configs per server in kf2server/KFGame/Config/
So for example, for my second normar server, there is a folder kf2server/KFGame/Config/ConfigNormal2

What this script does is the following:
  • Scans my map upload folder for new maps
  • Copies the maps to BrewedPC/Maps
  • Generates the KFMapSummary for every map
  • Reads the map cycle from maplist.txt/maplist with defaults.txt
  • Updates every PCServer-KFGame.ini in every folder it finds

It supports 2 maplists. It can be configured which maplist it installs on what server.
It replaces the parts between:
GameMapCycles=(Maps=(...))
and the parts between:
[KF-Default KFMapSummary]\
MapName=KF-Default
ScreenshotPathName=UI_MapPreview_TEX.UI_MapPreview_Placeholder
...
[Survival KFGameInfoSummary]

It does require perl to do the replaces:

Code:
#!/bin/bash
# Update all Killing Floor 2 servers with new maps

# Variables
UploadFolder="/home/ragequit/public_html/kf2/"
InstallFolder="/home/steam/steamcmdwin/kf2server/"
MapListFolder="/home/steam/"

# Config folders in this array get maplist.txt, the rest gets maplist with defaults.txt
declare -a NoDefaultsArr=(ConfigNormal2 ConfigHard2 ConfigHard4 ConfigSuicidal1) 

# Config folders in this array are ignored
declare -a IgnoredArr=(ConfigSpecial)  

# Everything between these 2 strings will be replaced with the map cycle
ConfigCycleReplaceStart="GameMapCycles=\(Maps=\("
ConfigCycleReplaceEnd="\)\)"
# Everything between these 2 strings will be replaced with the map list
ConfigMapReplaceStart="\[KF-Default KFMapSummary\]\r\nMapName=KF-Default\r\nScreenshotPathName=UI_MapPreview_TEX.UI_MapPreview_Placeholder"
ConfigMapReplaceEnd="\[Survival KFGameInfoSummary\]"

# Functions
array_contains() {
    local array="$1[@]"
    local seeking=$2
    local in=1
    for element in "${!array}"; do
        if [[ $element == $seeking ]]; then
            in=0
            break
        fi
    done
    return $in
}

#Actual script

echo "Step 1: Copy new maps from $UploadFolder to $InstallFolder"
rsync -v -a "$UploadFolder" "$InstallFolder"KFGame/BrewedPC/Maps/
#chown -R steam:steam "$InstallFolder"KFGame/BrewedPC/Maps/

shopt -s nullglob

echo "Step 2: Find all server configs to be updated..."
dirArray=()
while IFS=  read -r -d $'\0'; do
	echo Found `basename "$REPLY"`
    dirArray+=("$REPLY")
done < <(find "$InstallFolder"KFGame/Config/ -maxdepth 1 -mindepth 1 -type d -name 'Config*' -print0)

echo "Step 3: Loading maplist.txt"
MapList=""
while IFS='' read -r line || [[ -n $line ]]; do
    #echo "Adding to Map Cycle: $line"
    MapList="${MapList}\"${line}\","
done < "$MapListFolder"maplist.txt
MapList=${MapList%?}
echo "New maplist for servers without defaults: $MapList" 

echo "Step 4: Loading maplist with defaults.txt"
MapListDefaults=""
while IFS='' read -r line || [[ -n $line ]]; do
    #echo "Adding to Map Cycle for defaults: $line"
    MapListDefaults="${MapListDefaults}\"${line}\","
done < "${MapListFolder}maplist with defaults.txt"
MapListDefaults=${MapListDefaults%?}
echo "New maplist for servers with defaults: $MapListDefaults"

echo "Step 5: Adding all maps to the web interface..."
MapSummary="\r\n\r\n"
for file in "$InstallFolder"KFGame/BrewedPC/Maps/*.kfm
do 
	filename=${file##*/}
	mapname=${filename%.*}
	echo "Processing map: $mapname, filename: $filename"
	MapSummary="${MapSummary}[${mapname} KFMapSummary]\r\n"
	MapSummary="${MapSummary}MapName=${mapname}\r\n"
	MapSummary="${MapSummary}ScreenshotPathName=UI_MapPreview_TEX.UI_MapPreview_Placeholder\r\n\r\n"
done

echo "Step 6: Actually updating the config files"
MapCycle=$MapListDefaults
for i in "${dirArray[@]}"
do
	foldername=`basename "$i"`
	
	if array_contains IgnoredArr $foldername
	then
		echo "Ignoring $foldername"
		continue
	fi
	
	if array_contains NoDefaultsArr $foldername
	then
		MapCycle=$MapList
	fi
	
	echo "Updating ${i}/PCServer-KFGame.ini"
	
	#cycle
	perl -0777 -pi -e "s/${ConfigCycleReplaceStart}.*?(${ConfigCycleReplaceEnd})/${ConfigCycleReplaceStart}${MapCycle}${ConfigCycleReplaceEnd}/g" "${i}/PCServer-KFGame.ini"


	#summary
	perl -0777 -pi -e "s/${ConfigMapReplaceStart}.*?(${ConfigMapReplaceEnd})/${ConfigMapReplaceStart}${MapSummary}${ConfigMapReplaceEnd}/gs" "${i}/PCServer-KFGame.ini"
	
	
	MapCycle=$MapListDefaults
done

echo "Done!"

The maplist.txt is just the map per line:
Code:
KF-londonbetathree
KF-Defence_Thyself_v3_beta
KF-DarkZone
KF-ZedIsland_FinalBeta
KF-BioticsLabUK_B2
KF-Subterrane-v2
KF-Complexity-B4
KF-HotelZed_BetaV4-2
KF-ScrakesOnAPlane-v1-0
KF-Antize-RE2-V7
KF-BloodBank
KF-PoliceStation
KF-ZedIsland_FinalBeta
KF-HorzineDistrict
KF-PoliceStation
KF-RatsManorV2-1
 
Last edited:
Upvote 0
Thanks for that great tutorial! Laughed loudly while reading first time ;)

So I just wanted to share some of my scripts:

firstly: kill the server everyday at 4am:

Code:
~ crontab -e
0 4 * * * /home/kf2/dailyServerKill.sh > /dev/null 2>&1

Code:
~ cat ~/dailyServerKill.sh
#!/bin/bash
pkill "KFServer.exe" > /dev/null
echo "Cron Killed: " `date` >> /home/kf2/restarted_kf2.log

Also I'm running two screens for one server:

One is running an automated restart script (that starts the server if the server isn't present in my processes anymore)

Code:
~ cat ~/autoRestart.sh

#!/bin/bash

START='/home/kf2/start.sh'
SCREEN_NAME="kf2server"

while /bin/true; do

    sleep 10
    echo "checking..."
    SERVER=`ps --User kf2 | grep "KFServer.exe" | grep -v grep | wc -l`

    if [[ $SERVER -eq "0" ]]; then
        screen -S $SCREEN_NAME -X quit
        screen -dmLS $SCREEN_NAME $START
        DATE_NOW=`date`
        echo "Restarted: $DATE_NOW" >> restarted_kf2.log
        sleep 10
    fi
done

So I just run "screen autoRestart.sh" -> Press CTRL+A & CTRL+D and I'm fine. - My server restarts on unexpected errors (on hosting community alpha maps) and restarts on 4am so no memory leaks will happen - also the server-list bug is fixed, so.

And my "start.sh":
Code:
WINEDEBUG=fixme-all DISPLAY=:XXX wine /home/kf2/steamcmdwin/kf2server/Binaries/Win64/KFServer kf-bioticslab?difficulty=1?AdminName=<removed>?AdminPassword=<removed>-port=7777
 
Last edited:
Upvote 0
Hello so I'm running Cent OS 6 and this guide worked for me for the most part however, the server doesn't show up on the server list, nor in history even after I directly connect to it using 'open ip'.


Restarting doesn't help any ideas? :S

I have the exact same problem, running Ubuntu 14.04 x64.

It appears to be running, but the web admin does not come up and you can't connect to it directly in game.
 
Upvote 0
Ok, I wanted to make sure this idea worked since the latest update.

Yes, ports are open, UFW is disabled. I do get this error message:

Code:
err:winediag:SECUR32_initNTLMSP ntlm_auth was not found or is outdated. Make sure that ntlm_auth >= 3.0.25 is in your path. Usually, you can find it in the winbind package of your distribution.
Setting breakpad minidump AppID = 232090
Warning, Unknown language extension . Defaulting to INT
Warning, Failed to load 'Texture2D FX_GORE_TEX.FX_Gore_Blend_All_D': Failed to find object 'Texture2D FX_GORE_TEX.FX_Gore_Blend_All_D'
Warning, The Outer object (Package ENG_EngineResources_TEX.Dither) for 'ENG_EngineResources_TEX.Dither.dither_pattern' couldn't be loaded [while loading package ENG_EngineResources_TEX]: Invalid linker index [couldn't load Package ENG_EngineResources_TEX.Dither]?
Warning, Failed to load 'Texture2D ENG_EngineResources_TEX.Dither.dither_pattern': Failed to find object 'Texture2D ENG_EngineResources_TEX.Dither.dither_pattern'

But from what I've seen, it's normal?
 
Upvote 0
The log isn't giving a lot of info. But here is what I have

Code:
Log: Log file open, 09/16/15 20:43:19
Init: WinSock: version 1.1 (2.2), MaxSocks=128, MaxUdp=1024
DevConfig: GConfig::LoadFile associated file:  ..\..\KFGame\Config\KFLightmass.ini
DevConfig: GConfig::LoadFile associated file:  ..\..\KFGame\Config\PCServer-KFUI.ini
DevConfig: GConfig::LoadFile associated file:  ..\..\KFGame\Config\PCServer-KFGameStats.ini
DevConfig: GConfig::LoadFile associated file:  ..\..\KFGame\Config\PCServer-KFBenchmarking.ini
DevConfig: GConfig::Find has loaded file:  ..\..\Engine\Config\ConsoleVariables.ini
Init: Version: 10897
Init: Epic Internal: 0
Init: Compiled (64-bit): Sep  9 2015 21:44:12
Init: Changelist: 1532151
Init: Command line: SERVER kf-bioticslab?difficulty=1 -port=7777
Init: Base directory: Z:\root\steamgames\kf2server\Binaries\Win64\
[0000.14] Init: Computer: server101
[0000.14] Init: User: root
[0000.14] Init: CPU Page size=4096, Processors=1
[0000.14] Init: High frequency timer resolution =10.000000 MHz
[0000.14] Init: Memory total: Physical=0.5GB (0GB approx) Pagefile=0.5GB Virtual=131072.0GB
[0000.14] Log: Steam Client API not initialized (not required for servers)
[0000.14] Log: Automatically setting Steam query port to 27015 (server port is 7777)
[0000.14] Log: Automatically setting Steam port to 20560 (server port is 7777)
[0000.35] Log: Steam Game Server API initialized 1
[0000.35] DevOnline: appSteamInit: Steam Game Server UID: 0
[0000.35] Init: Presizing for 0 objects not considered by GC, pre-allocating 0 bytes.
[0000.35] Init: Object subsystem initialized
[0000.36] Warning: Warning, Unknown language extension . Defaulting to INT
[0000.80] Log: CachePaths() took 0.44 Seconds
[0000.81] Log: Shader platform (RHI): PC-D3D-SM5
[0001.04] Log: PhysXLevel : 0
 
Upvote 0
Memory leak

Memory leak

It seems the most recent patch has brought back the memory leak problem for me. I still don't actually why but after each game it seems to be using about 50MB more of RAM and it never seems to touch it again so since I only run a 1GB server and it seems to use about 800MB on average when in use. I just made a 4GB swap space and since KF2 never uses that data again it just sits in the swap space forever and i can't restart less often.
 
Upvote 0
I figured out how to put my own redirect server up using webfs, which should be available cross-platform and is also very easy to set up and run. Might be worthwhile adding this to the guide.

Having said that -- this thread needs to be pinned. This plus the KF2 Dedicated Server page on the official wiki made setting up on Linux a breeze. To the OP: Thank you for your service.

And the server itself performs excellently. My friends and I haven't experienced any server lag or instability you might expect from something running under wine.
 
Upvote 0
Well, got it running, but seems only locally. Tried to invite a friend, no luck.

Other wierd thing is the fact whatever changes I make on webadmin, the game follows the command line at terminal when I start the server, for exemple, map, difficulty and gamelength - "wine /home/thomas/steamcmdwin/kf2server/Binaries/Win64/KFServer kf-outpost?difficulty=1?gamelength=2 -port=7777". Even after a map, changes made at webadmin dont get apply.

Any ideas?
 
Upvote 0
Well, got it running, but seems only locally. Tried to invite a friend, no luck.

Other wierd thing is the fact whatever changes I make on webadmin, the game follows the command line at terminal when I start the server, for exemple, map, difficulty and gamelength - "wine /home/thomas/steamcmdwin/kf2server/Binaries/Win64/KFServer kf-outpost?difficulty=1?gamelength=2 -port=7777". Even after a map, changes made at webadmin dont get apply.

Any ideas?

I'm confused as to what you are trying to say? The command line overrides any settings on launch. The server will start up exactly as your command line.

What changes are you trying to do in web admin that don't apply? How are you changing maps, through webadmin or in game?
 
Upvote 0
I'm confused as to what you are trying to say? The command line overrides any settings on launch. The server will start up exactly as your command line.

What changes are you trying to do in web admin that don't apply? How are you changing maps, through webadmin or in game?

For example, if I boot the server with 10 waves at hard difficulty, and after change to normal and 7 waves through webadmin, those last settings dont apply.. Only thing I can change through webadmin is the map.

But this is not a real problem.

The thing is the server does not show up in the server list, only on my lan.. And does not work if I invite someone to join..

Here's what I get after booting up..

Code:
thomas@server:~$ ./Setting breakpad minidump AppID = 232090
Warning, Unknown language extension . Defaulting to INT
Warning, Failed to load 'Texture2D FX_GORE_TEX.FX_Gore_Blend_All_D': Failed to find object 'Texture2D FX_GORE_TEX.FX_Gore_Blend_All_D'
Warning, The Outer object (Package ENG_EngineResources_TEX.Dither) for 'ENG_EngineResources_TEX.Dither.dither_pattern' couldn't be loaded [while loading package ENG_EngineResources_TEX]: Invalid linker index [couldn't load Package ENG_EngineResources_TEX.Dither]?
Warning, Failed to load 'Texture2D ENG_EngineResources_TEX.Dither.dither_pattern': Failed to find object 'Texture2D ENG_EngineResources_TEX.Dither.dither_pattern'
Warning, Failed to load 'AUD_RO2_Impacts': Can't find file for package 'AUD_RO2_Impacts' while loading ..\..\KFGame\BrewedPC\Packages\Gameplay\LD_Toolbox.upk
Warning, Failed to load 'AUD_RO2_Impacts': Can't find file for package 'AUD_RO2_Impacts' while loading ..\..\KFGame\BrewedPC\Packages\Gameplay\LD_Toolbox.upk
Warning, Failed to load 'AUD_RO2_Impacts': Can't find file for package 'AUD_RO2_Impacts' while loading ..\..\KFGame\BrewedPC\Packages\Gameplay\LD_Toolbox.upk
Warning, Failed to load 'LD_Toolbox.Prefabs.Windows:PrefabSequence_5'! Referenced by 'LD_Toolbox.Prefabs.Windows:PrefabSequence_1.SeqAct_PlaySound_0' ('Engine.SeqAct_PlaySound:PlaySound').
Warning, Failed to load 'AUD_RO2_Impacts': Can't find file for package 'AUD_RO2_Impacts' while loading NULL
Warning, Failed to load 'Texture2D None.None': Failed to find object 'Texture2D None.None'
Warning, Failed to load 'Texture2D None.None': Failed to find object 'Texture2D None.None'
 
Upvote 0
Nevermind, solved.
Was a port forwarding thing.

Thanks,

Thomas

EDIT

Does anyone managed to run more than 1 server using only one installation folder?

I'm running like this,

#server 1 // wine /home/thomas/steamcmdwin/kf2server/Binaries/Win64/KFServer kf-outpost?difficulty=1?gamelength=2? -port=7777 QueryPort=27015 -WebadminPort=8080

#server 2 // wine /home/thomas/steamcmdwin/kf2server/Binaries/Win64/KFServer kf-outpost?difficulty=1?gamelength=2? -port=7787 QueryPort=27025 -WebadminPort=8081

#server 3 // wine /home/thomas/steamcmdwin/kf2server/Binaries/Win64/KFServer kf-outpost?difficulty=1?gamelength=2? -port=7797 QueryPort=27035 -WebadminPort=8082


Frist server goes ok, but when I boot the second it does now show up in Lan, or any other list in game.. I'm able to go into webadmin.. All needed ports are open..

Any tips?
 
Last edited:
Upvote 0
I found out why an X server and the DISPLAY environment variable is needed: Apparently the server checks if it's connected to a TTY on startup. If it is not, it starts its own graphical console window, which requires a usable X server. If it fails to open the console, it crashes. I suppose it makes sense in the Windows world, because then people get a console when they double-click the EXE.

You can work around this by running wine using unbuffer (from expect, see also Ubuntu packages), which creates a fake TTY. Like this:

Code:
/usr/bin/unbuffer /usr/bin/wine "C:/steamcmd/kf2server/Binaries/Win64/KFServer.exe"
 
Last edited:
Upvote 0
Thanks
awkward-4c0d6f5.png
adding the info to the first post
360fx360f-4da16a9.png
 
Last edited:
Upvote 0
By the way, I did not need the extra DLL's in your zip file. They were bundled with the wine installation out of the box:

Code:
    $ find .wine-kf2server -iname 'msvcr10*'
    .wine-kf2server/drive_c/windows/system32/msvcr100.dll
    .wine-kf2server/drive_c/windows/syswow64/msvcr100.dll
    $ find .wine-kf2server -iname 'X3DAudio1_7*'
    .wine-kf2server/drive_c/windows/system32/x3daudio1_7.dll
    .wine-kf2server/drive_c/windows/syswow64/x3daudio1_7.dll

Tried this in a fresh WINEPREFIX just now.

You can also remove ?difficulty=0 -port=7777 from the command line. They are the default values, so no need to specify them.
 
Upvote 0