How To: Configure and Host a Hidden & Dangerous 2 Dedicated Server on FreeBSD

1 year 8 months ago - 1 year 8 months ago #1 by toadlife
UPDATE on 2021-05-23: Added pre-configured virtual machine and other downloads.
UPDATE on 2021-05-20: Added shell scripts for server automation.
How To: Configure and Host a Hidden & Dangerous 2 Dedicated Server on FreeBSD 
This guide gives a basic overview of how to set up and host a dedicated Hidden & Dangerous 2 server on FreeBSD. To save in both hardware and licensing costs, I first tried running my H&D2 server on Linux and WINE, but I was never able to get it to work. On Linux, the server will show up in the server listing, but clients cannot connect, like with modern versions of Windows. I was never able to figure out a fix for Linux, so I tried my favorite Unix-like operating system, FreeBSD and for whatever reason, clients have no problem connecting to H&D2 servers that are hosted on FreeBSD. This guide assumes that you have basic experience installing operating systems. Working experience with unix-like operating systems and experience working in and with unix shells is highly recommended.

Official Resources:

Resources: FreeBSD Home Page:  The FreeBSD Project
Download FreeBSD:  The FreeBSD Project | Download FreeBSD
Official FreeBSD documentation:  FreeBSD Handbook  

Downloads specific to this guide:

For some reason, these links don't seem to work when you click on them here. You can right-click on the link, copy the URL and paste it into a new browser window and it will work.

Virtual Machine: FreeBSD HD2 Virtual Machine created from this guide  (user and root password are both "FreeBSD" and VNC password is "1234" - CHANGE THESE IF YOU EXPOSE THESE MACHINES TO THE INTERNET!)
Shell Scripts: Shell scripts from this guide
Hex-Edited Consoles: Consoles with custom names (used in the scripts in this guide)



 Installing FreeBSD Install FreeBSD using the default options.  In addition to the defaults, make sure powerd and moused are enabled:



When the installer asks you if you want to add another user, choose yes.
 


In this guide, the scripts and commands assume the user name is “server”.  It is recommended that you name your user “server” so you don’t have to edit the commands. Create the user with default settings. When the wizard asks you if you want to invite your user into other groups, type, “wheel operator” as shown in the screenshot below.



After rebooting, log into the system as your non-root user (“server” in the case of this guide) and type “su” and the root password to elevate to root:



Initialize the pkg system by typing the command: pkg  



Now install the software needed to run the game: 
pkg install xorg xfce sddm i386-wine winetricks xrdp x11vnc xdotool bash

Optionally, you might want to install a browser, for example:
pkg install firefox
pkg install chromium

Run these commands to enable xrdp, the display manager and dbus for xfce:
sysrc xrdp_enable=YES
sysrc dbus_enable=YES
sysrc sddm_enable=YES

Now create the config file for the display manager. Replace “server” below with the username of your user: 
echo "[Autologin]" >> /usr/local/etc/sddm.conf
echo "User=server" >> /usr/local/etc/sddm.conf
echo "Session=xfce.desktop" >> /usr/local/etc/sddm.conf

Now reboot the machine:
shutdown -r now

After rebooting, log in via ssh as your regular user and elevate to root. Launch the VNC server with the following command. Replace “server” with the username of your user and “1234” with your password:
x11vnc -auth /home/server/.Xauthority -passwd "1234" -forever

Use an RDP client and connect to your server:



Once connected, change the session to “vnc-any”, the ip to “127.0.0.1” and type in the vnc password from previous command line:



If successful, you should see a fresh xfce desktop:



Now you need to configure the VNC server to automatically start when you log on. To do this, go to Settings > Session and Startup



Create a new item in “Application Autostart” with the following command. Replace "1234" with your password:
x11vnc -passwd "1234" -forever

Reboot the machine. After it boots, you should be able to log into the desktop using RDP.Open and shell and elevate to root. As root, type the following command to update winetricks to the latest version:
winetricks --self-update

Now, exit from root:
exit

Now run winetricks as your regular user:
winetricks


If winetricks asks you if you want to install components like mono and gecko, click “install”:

 

 
Attachments:
The following user(s) said Thank You: snowman, Damni

Please Log in or Create an account to join the conversation.

1 year 8 months ago - 1 year 8 months ago #2 by toadlife
Choose “Select the default wine prefix” and click “OK”:



Select “Install a Windows DLL or component” and click “OK”:



Choose “DirectPlay” and click “OK”:



Open up a shell, elevate to root and open the hosts file:
ee /etc/hosts



Add the following lines to the hosts file and save it:

65.112.87.186    hd2.available.gamespy.com    #hidden and dangerous 2 check
65.112.87.186    hd2.master.gamespy.com        #hidden and dangerous 2 heartbeats
65.112.87.186    hd2.ms14.gamespy.com        #hidden and dangerous 2 server list


Now, install the game. The example scripts in this guide use a game path of “C:\HD2”, so you might want to use that path:

 

After the game installs, you can test to see if it works by running the Server Launcher

Automating the server using shell scripts
The following shell scripts are adapted from my coop server. The scripts can be downloaded here: 
This attachment is hidden for guests.
Please log in or register to see it.


server[1-4].sh - These scripts launch or restart a particular server.

! Note the "hdexecutable" variable. For the purposes of automation, I use hex-edited versions of the server executables that have unique console names. You don't need to have different server executable names for each server. The normal executable name is "HD2DS_SabreSquadron.exe" and it's perfectly fine if you use the same executable for multiple servers.
#!/bin/sh

# Set the variables below
##############################################
serverid='server1'
gamedir='/home/server/.wine/drive_c/HD2/'
winelocation='/usr/local/bin/wine'
hdexecutable='HD2DS_SabreSquadron1.exe'
serverhome='/home/server/'
##############################################
serverid=hd2server${serverid}

echo "Daemon Hidden and Dangerous II Server Launcher by Paul Blair/toadlife (paulwblair@live.com)"
echo Game Dir: $gamedir
echo Server ID: $serverid
echo WINE Location: $winelocation
echo HD2 Executable: $hdexecutable
echo Server Home: $serverhome
cd $gamedir
echo Changed directory to $gamedir
supervisor_pidfile=$serverhome$serverid'.pid'
echo Set supervisor pid file to $supervisor_pidfile
child_pidfile=$serverhome$serverid'server.pid'
echo Set child pid file to $child_pidfile
command="$winelocation $hdexecutable -cmd -exec ServerConfigs\\${serverid}.cfg"
echo Killing existing server
if (test -e $supervisor_pidfile)
then
kill -s TERM `cat $supervisor_pidfile`
fi
sleep 1
if (test -e $child_pidfile)
then
kill -s TERM `cat $child_pidfile`
fi
sleep 2
/usr/sbin/daemon -R 5 -t ${serverid} -P ${supervisor_pidfile} -p ${child_pidfile} ${command}&
sleep 10
echo Server has been launched!

createconfig[1-4].sh - These scripts generate server config files with random map lists. Edit the variables at the top and comment out any maps that you don't want includes. A few maps are already commented out. Each createconfig script corresponds to a server scripts. for example, "createconfig1.sh" creates the config that "server1.sh" uses.

creatconfig1.sh
#!/usr/local/bin/bash

# Set the variables below
###################################################################
serverid='server1'
sessionname='FreeBSD Test (server1)'
port='11051'
password=''
adminpass='FreeBSD'
nummaps='12'
maxclients='6'
pointlimit='0'
roundlimit='5'
roundcount='0'
allowrespawn='1'
respawntime='5'
spawnprotection='5'
friendlyfire='1'
inversedamage='0'
warmup='5'
autoteambalance='0'
thirdpersonview='1'
fallingdmg='1'
allowvehicles='1'
maxping='0'
maxfreq='0'
maxinactivity='0'
voicechat='none'
autorestart='0'
coopdifficulty='2'
cooplives='6'
allowcrosshair='1'
teamlives='0'
configdir='/usr/home/server/.wine/drive_c/HD2/ServerConfigs/'
serverhome='/home/server/'
###################################################################
serverid=hd2server${serverid}

echo "sessionname \"$sessionname\"">${configdir}${serverid}.cfg
echo "domain internet">>${configdir}${serverid}.cfg
echo "dedicated 1">>${configdir}${serverid}.cfg
echo "port $port">>${configdir}${serverid}.cfg
echo "password \"$password\"">>${configdir}${serverid}.cfg
echo "adminpass \"$adminpass\"">>${configdir}${serverid}.cfg
echo "style Cooperative">>${configdir}${serverid}.cfg
echo "maxclients $maxclients">>${configdir}${serverid}.cfg
echo "pointlimit $pointlimit">>${configdir}${serverid}.cfg
echo "roundlimit $roundlimit">>${configdir}${serverid}.cfg
echo "roundcount $roundcount">>${configdir}${serverid}.cfg
echo "allowrespawn $allowrespawn">>${configdir}${serverid}.cfg
echo "respawntime $respawntime">>${configdir}${serverid}.cfg
echo "spawnprotection $spawnprotection">>${configdir}${serverid}.cfg
echo "friendlyfire $friendlyfire">>${configdir}${serverid}.cfg
echo "inversedamage $inversedamage">>${configdir}${serverid}.cfg
echo "warmup $warmup">>${configdir}${serverid}.cfg
echo "autoteambalance $autoteambalance">>${configdir}${serverid}.cfg
echo "3rdpersonview $thirdpersonview">>${configdir}${serverid}.cfg
echo "fallingdmg $fallingdmg">>${configdir}${serverid}.cfg
echo "allowvehicles $allowvehicles">>${configdir}${serverid}.cfg
echo "maxping $maxping">>${configdir}${serverid}.cfg
echo "maxfreq $maxfreq">>${configdir}${serverid}.cfg
echo "maxinactivity $maxinactivity">>${configdir}${serverid}.cfg
echo "voicechat $voicechat">>${configdir}${serverid}.cfg
echo "autorestart $autorestart">>${configdir}${serverid}.cfg
echo "coopdifficulty $coopdifficulty">>${configdir}${serverid}.cfg
echo "cooplives $cooplives">>${configdir}${serverid}.cfg
echo "allowcrosshair $allowcrosshair">>${configdir}${serverid}.cfg
echo "teamlives $teamlives">>${configdir}${serverid}.cfg
coopmaps=("Ac(Complex)D")
coopmaps+=("Ac(Complex)N")
coopmaps+=("Ac(Complex)N")
coopmaps+=("Ac1(Ext)Day")
#coopmaps+=("Ac1(Ext)Night")
coopmaps+=("Ac1(First_Strike)")
#coopmaps+=("Ac1(Race)")
coopmaps+=("Ac3(The_Factory)")
coopmaps+=("Ac4(Convoy)")
coopmaps+=("Ac4(Radiocamp)")
coopmaps+=("Ad1(Last_Assault)")
coopmaps+=("Ad1(Snowcamp)")
coopmaps+=("Ad1(Tanks)")
coopmaps+=("Ad2(Liege)")
coopmaps+=("Af1(Airfield)")
coopmaps+=("Af1(Battlefield)")
coopmaps+=("Af1(Defence)")
coopmaps+=("Af1(Delivery)")
coopmaps+=("Af1(Grant)")
coopmaps+=("Af1(Tankbattle)B")
coopmaps+=("Af2(Rommels_Road)")
#coopmaps+=("Af3(Bot-Race)")
coopmaps+=("Af3(Oasis)")
coopmaps+=("Af3(Turnover)")
#coopmaps+=("Af4(Oasis)")
#coopmaps+=("Af4(Turnover)")
coopmaps+=("Af5(Art_Of_Sand)")
coopmaps+=("Af5(Stealth_of_Sand)")
coopmaps+=("Africa1")
coopmaps+=("Africa2")
coopmaps+=("Africa3")
#coopmaps+=("Africa4")
coopmaps+=("Africa5")
coopmaps+=("Al1(Fatal_Airdrop)")
coopmaps+=("Al1(Rendezvous)1")
coopmaps+=("Al1(Rendezvous)1E")
coopmaps+=("Al1(Rendezvous)2")
coopmaps+=("Al1(Rendezvous)3")
coopmaps+=("Al2(Hunedoara)")
coopmaps+=("Al3(Oddball)")
coopmaps+=("Alps1")
coopmaps+=("Alps2")
coopmaps+=("Arctic1")
coopmaps+=("Arctic2")
coopmaps+=("Arctic3")
coopmaps+=("Arctic4")
coopmaps+=("Ardennes1")
coopmaps+=("Bg1(Broken_Arrow_TLC)")
coopmaps+=("Bg1(Broken_Arrow)")
coopmaps+=("Bg2(Farmstead)")
coopmaps+=("Bg3(Escape_from_Hell)")
coopmaps+=("Bg3(Rescue_from_Hell)")
coopmaps+=("Bm1(Keyguard)")
coopmaps+=("Bm1(Night-Attack)")
coopmaps+=("Bm1(Nightwing)")
coopmaps+=("Bm2(Kingslayer)")
coopmaps+=("Br(Blitz)")
coopmaps+=("Br(Extended)")
coopmaps+=("Br(Gestopo)")
coopmaps+=("Br(Silent-Op)")
coopmaps+=("Brest")
coopmaps+=("Burgundy1")
coopmaps+=("Burgundy2")
coopmaps+=("Burgundy3")
coopmaps+=("Burma1")
coopmaps+=("Burma2")
coopmaps+=("Cz1(Train)")
coopmaps+=("Cz1(Trebissky)")
coopmaps+=("Cz3(Lumbermill)")
coopmaps+=("Cz3(Lumbermill)2")
coopmaps+=("Cz3(Ostwind)")
coopmaps+=("Cz4(Ambush)")
coopmaps+=("Cz4(Hart's_War)")
coopmaps+=("Cz4(Marketplace)")
coopmaps+=("Cz4(Resistance)")
coopmaps+=("Cz4(Trapped)")
coopmaps+=("Cz4(Village)")
#coopmaps+=("Cz5(Resistance)")
#coopmaps+=("Cz5(Trapped)")
#coopmaps+=("Cz5(Village)")
coopmaps+=("Cz6(Bunker)")
coopmaps+=("Cz6(Defence)")
coopmaps+=("Cz6(Final_Assault)")
coopmaps+=("Cz6(Iron_Swarm)")
coopmaps+=("Czech1")
coopmaps+=("Czech2")
coopmaps+=("Czech3")
coopmaps+=("Czech4")
#coopmaps+=("Czech5")
coopmaps+=("Czech6")
coopmaps+=("Li1(Day)")
coopmaps+=("Li1(Dherna)")
coopmaps+=("Li1(Hells_Gate)")
coopmaps+=("Li1(PrisonBreak)")
coopmaps+=("Li1(Sidi_Badullah)")
coopmaps+=("Li1(Supercharge)")
coopmaps+=("Li2(Tankbite)")
coopmaps+=("Li2(Tiger_Tomb)")
coopmaps+=("Li3(Blowout)")
coopmaps+=("Li3(Jailbreak)")
coopmaps+=("Li3(Littorio)")
coopmaps+=("Li3(Scorpio)")
coopmaps+=("Libya1")
coopmaps+=("Libya2")
coopmaps+=("Libya2b")
coopmaps+=("Libya3")
coopmaps+=("Nm2(Bait)")
coopmaps+=("Nm2(Firefly)")
coopmaps+=("Nm2(Frontline)")
#coopmaps+=("Nm2(Marolles)")
coopmaps+=("Nm2(Resistance)")
coopmaps+=("Nm2(Saving_Private_Smith)")
coopmaps+=("Nm3(Bridge)")
coopmaps+=("Nm4(HantaYo)")
coopmaps+=("Normandy1")
coopmaps+=("Normandy2")
coopmaps+=("Norway")
coopmaps+=("Pl(EnemyHQ)")
#coopmaps+=("Si1(NightAttack)")
coopmaps+=("Si2_A2")
coopmaps+=("Si2(Boom)")
coopmaps+=("Si2(Boom2)")
coopmaps+=("Si2(Delivery2)")
coopmaps+=("Si2(Mafia_Deal)")
coopmaps+=("Si2(Stormbridge)")
coopmaps+=("Sicily1")
coopmaps+=("Sicily2")
coopmaps+=("Tu(Great-Battle)")
# create maplist array
maplist=()
i=0
while [ $i -lt $nummaps ]; do
# pick a random number between 1 and the length of the indices array
rand=$(( RANDOM % ${#coopmaps[@]} ))
echo "mapname ${coopmaps[$rand]}" >> ${configdir}${serverid}.cfg
unset "coopmaps[$rand]"
coopmaps=(${coopmaps[@]})
i=$((i+1))
done
echo "server">>${configdir}${serverid}.cfg


launch_servers.sh - This script launches all of the servers. It launches the servers twice because, for some unknown reason, the first intance of the daemon process fails to monitor the process properly.

#!/bin/sh
/bin/sh ~/server1.sh
sleep 5
/bin/sh ~/server2.sh
sleep 5
/bin/sh ~/server3.sh
sleep 5
/bin/sh ~/server4.sh
#launch the servers twice because fomr unknown reason (bug?) the first instance of /usr/sbin/daemon doesn't monitor the process properly
sleep 5
/bin/sh ~/server1.sh
sleep 5
/bin/sh ~/server2.sh
sleep 5
/bin/sh ~/server3.sh
sleep 5
/bin/sh ~/server4.sh
exit 0

killservers.sh - This script will stop all of your servers launched by the server[x].sh scripts
#!/bin/sh
kill -s TERM `pgrep -f daemon.*hd2server.*[[]`
exit 0

creatconfigs.sh - runs all of the createconfig[x].sh scripts to regenerate all server configs.
#!/usr/local/bin/bash
/usr/local/bin/bash ~/createconfig1.sh
/usr/local/bin/bash ~/createconfig2.sh
/usr/local/bin/bash ~/createconfig3.sh
/usr/local/bin/bash ~/createconfig4.sh


To completely automate your server, schedule the script "launch_servers.sh" to run at startup in xfce in the same place that you launch the VNC server:

 

Adding another server:

If you want to add a fifth server, create a copy of server1.sh and createconfig1.sh and rename them server5.sh and createconfig5.sh. Edit the server5.sh with the new "serverid" variable and edit createconfig5.sh with the new "serverid" variable and other settings for your new server. Make sure the change the port numbers so that the server doesn't conflict with the other servers! Each server uses the base port plus three more after that (example: 11001-11004). After creating the new server and creatconfig scripts, modify launch_servers.sh to include your new server5.sh script.











 
Attachments:
The following user(s) said Thank You: snowman, Damni, Stern, Matro, British Bulldog

Please Log in or Create an account to join the conversation.

1 year 8 months ago #3 by toadlife
Reserved2 (12 picture limit)

Please Log in or Create an account to join the conversation.

1 year 8 months ago - 1 year 8 months ago #4 by snowman
Thank you for the detailed installation guide, Paul! I also saw your laptop photo with the running servers on FreeBSD posted on Discord

Maybe British Bulldog can follow this and successfully host on his machine.

Afaik, our current host, Contabo, offers both FreeBSD and Arch. We could easily change the operating system and slash ~70 Euro per year from the total costs. My dilemma is if we should remain on VPS or find another solution. I still want to try to make it work on Arch Linux, but things keep getting postponed on my side, so this will take a while. I wonder if it will work with Wine Staging and disabling IPv6 from the kernel as you previously recommended

Not to mention the array of possibilities Thomas Tailor already offered to =RpR= as far as servers and hosting goes. Waiting for Steff 

"Straight and narrow is the path."
The following user(s) said Thank You: toadlife

Please Log in or Create an account to join the conversation.

1 year 8 months ago #5 by toadlife
I added example shell scripts that I use to automate my server. 
The following user(s) said Thank You: snowman, Damni

Please Log in or Create an account to join the conversation.

1 year 8 months ago #6 by snowman
Thank you for the update, Paul

"Straight and narrow is the path."
The following user(s) said Thank You: toadlife

Please Log in or Create an account to join the conversation.

  • JackH[CZ] birthday is in 1 day (24)
  • Stern birthday is in 2 days (39)
  • Zdenda birthday is in 2 days (32)
  • ShayoX birthday is in 3 days (21)
  • JonnySniper birthday is in 8 days (32)
Powered by Kunena Forum