Files
cs16-dm-server/docs/HOW-IT-WORKS.md
T

11 KiB
Raw Blame History

How it works

The stack

Part Version Why
HLDS app 90, beta steam_legacy (frozen branch) Valve's dedicated server. ReHLDS needs engine build ≤ 8684, so the legacy branch is used
ReHLDS 3.15.0.896 drop-in engine with fixes and better performance; replaces engine_i486.so, hlds_linux etc.
ReGameDLL_CS 5.30.0.814 drop-in game logic (cstrike/dlls/cs.so) with mp_freeforall, mp_forcerespawn and more
Metamod-R 1.3.0.149 plugin loader; liblist.gam points the game at it
AMX Mod X 1.10.0.5486 scripting platform for the plugins
ReAPI 5.29.0.358 AMXX module that gives plugins access to ReHLDS/ReGameDLL hooks
ReUnion 0.2.0.25 lets non-Steam clients (protocol 47/48) join
CSDM-ReAPI 1.0.8 deathmatch: respawn, gun menu, spawn points, spawn protection
YaPB 4.4.957 bots (Metamod plugin)
GunGame 2.13c GunGame mode, compiled from source by setup

tools/versions.txt pins every download by URL and sha256. If anything upstream changes a file, setup stops instead of installing it.

Install flow (setup.sh)

  1. Creates .env and asks the questions. Generates secrets/rcon-password.txt and secrets/reunion-salt.txt, which are kept forever. The salt derives non-Steam players' IDs, so a new salt would reset their stats and admin entries.
  2. Builds the image: Debian bookworm, 32-bit libs, SteamCMD, unzip/xz.
  3. Downloads the game with SteamCMD, anonymously, with up to 4 tries, because app 90 often fails the first time. It runs validate only on the very first download. Later, validate would put back Valve's version of files you edited, and it also silently removes ReHLDS and Metamod.
  4. tools/install-addons.sh runs inside the image (repo mounted read-only, only dl/ writable):
    • downloads and checks the pinned files
    • unpacks ReHLDS, then sets its exec bits, which the zip loses
    • unpacks ReGameDLL and comments out the sv_alltalk 0 that its game.cfg would force on every map
    • unpacks Metamod and points liblist.gam at it (a copy of the original is kept as liblist.gam.orig)
    • unpacks AMXX, ReAPI and ReUnion. ReUnion gets the salt and IDClientsLimit 0, so several non-Steam players with the same placeholder ID can all join.
    • unpacks CSDM-ReAPI and the spawn files. de_prodigy and de_train are in CSDM 2.1's old 6-field format and get converted to the 10 fields CSDM-ReAPI reads, because it silently skips lines with any other count. Symlinks one folder up let GunGame find the files too.
    • unpacks YaPB, with chmod 775 on its folders (the tarball's folders have no x bit, so the bots couldn't save their path caches), yb_csdm_mode 2 (FFA-aware) and yb_quota_mode fill
    • copies the GunGame source, lang file and sounds, plus the 14 announcer sounds
    • copies cstrike/ from the repo over the game
    • compiles rtv, esef_extras, esef_mode and gungame with AMXX's amxxpc
    • leaves exactly one of plugins-CSDM_ReAPI.ini / plugins-gungame.ini active. It keeps the mode that was running before, or uses CS_MODE on the first install.
    • symlinks steamclient.so into ~/.steam/sdk32. Without it you get "Unable to initialize Steam" in Docker.
    • saves and restores what people edit: users.ini, amxx.cfg, csdm/config.ini. mapcycle.txt and custom.cfg are only written on the first install.
  5. Stops the old container if it's running (the engine files are in use), starts the server, and waits until it answers an A2S query.

At every container start (tools/start.sh)

  • writes cstrike/env.cfg (hostname) and cstrike/secrets.cfg (RCON + join password, mode 600) from .env and secrets/
  • sets yb_quota / yb_difficulty in addons/yapb/conf/yapb.cfg from CS_BOTS / CS_BOT_DIFFICULTY
  • runs hlds_run -game cstrike -port $CS_PORT +maxplayers $CS_MAXPLAYERS +map $CS_MAP -pingboost 2 -norestart +log on

server.cfg runs env.cfg, then secrets.cfg, then custom.cfg, on every map.

Game modes

esef_mode (own plugin) is a server command: esef_mode, esef_mode dm or esef_mode gg. AMXX reads every configs/plugins-*.ini at each map change, so a mode is simply which plugin list is named .ini and which is named .ini.off. The plugin renames them, then reloads the map. The rename stays on disk, so the mode survives restarts.

GunGame settings (configs/gungame.cfg):

  • free for all: gg_tk_penalty -1, plus mp_freeforall 1 in gg_map_setup
  • bomb and hostages blocked
  • 30 s knife warmup, 1 s respawn, 30 min maps
  • 2 kills per level

gg_map_setup also switches off the respawn cvars CSDM leaves behind (mp_forcerespawn 0, mp_respawn_immunitytime 0). CSDM sets them again in dm mode.

Important: GunGame needs the AMXX modules cstrike, fakemeta and hamsandwich. They're listed in configs/modules.ini so they load at server start. If they load later, on the first GunGame map, they miss the game's message registration and the server crashes when a player joins (PF_MessageBegin_I: bogus message type ( 0 )). Because of this, Metamod logs Not loading plugin 'CStrike'; already loaded on every map. Those errors are harmless. Never add reapi to modules.ini: AMXX autoloads it, and listing it loads it twice.

Own plugins (plugins/)

  • esef_extras: damage numbers (DHUD; blue = dealt, red = taken, real HP lost), killstreak announcements at 3/5/7/9/11/13/15 (to everyone), multikills within 2 s (to the killer), headshot / knife / first blood sounds, +HP per kill (capped at 100), and a "K D | streak (best)" HUD line that hides itself in GunGame.
  • rtv: a minimal rock-the-vote. 60% of players (amx_rtv_ratio) starts a 15 s vote between 5 random mapcycle maps. It's blocked in the first 2 minutes (amx_rtv_delay) and in the last 3 minutes, when mapchooser's end-of-map vote runs.
  • esef_mode: the mode switch described above.

Server settings worth knowing (cstrike/server.cfg)

  • sv_lan 0: has to stay 0 even for VPN or tunnel players, because they aren't "LAN" to the engine.
  • sv_rehlds_maxclients_from_single_ip 16: a tunnel like playit delivers every player from one IP.
  • sv_rcon_banpenalty 1: a wrong RCON password bans the source IP for 1 minute instead of forever, which matters when everyone shares the tunnel's IP.
  • sv_rcon_condebug 0: RCON commands contain the password, so they aren't echoed to the console or docker logs.
  • sys_ticrate 300: plenty for DM, and it keeps CPU use low.

Crash handling

  • Crash: the container runs with init: true, so tini is PID 1, and hlds runs with -norestart. When hlds dies the container exits and Docker's restart: unless-stopped starts it again. Without -norestart, hlds_run's own restart loop can hang after a crash, with the container still showing "running". Core dumps are off (ulimits: core: 0), because a single crash writes ~170 MB.
  • Hang: scripts/watchdog.sh runs from cron and A2S-queries the server. After 3 failed checks in a row it runs docker restart.
  • Logs: Docker's json log is capped at 3 × 10 MB. scripts/backup.sh deletes game logs older than 30 days, after counting their kills.

Kill counter

./kills counts the "X<..>" killed "Y<..>" with "weapon" lines in hlds/cstrike/logs/*.log, keeping the counts per log file in kills-tally.json. Because the counts live in that file, the totals survive the 30-day log cleanup.

Windows version (setup.cmd, windows/)

The same stack, native instead of Docker: the win32 builds of every part, hlds.exe instead of hlds_linux. The Windows scripts are Windows PowerShell 5.1 (built into Windows 10 and 11) and mirror the Linux ones: windows/setup.ps1 = setup.sh, windows/install.ps1 = tools/install-addons.sh, Start-CsServer in windows/common.ps1 = tools/start.sh, windows/cs.ps1 = cs + rcon + kills. They read the same cstrike/, plugins/, defaults/ and tools/versions.txt; tools/versions-windows.txt swaps in the Windows builds of AMX Mod X and YaPB (files with -linux in the name are skipped). Settings go in settings.txt with the .env names.

Things that differ from Linux:

  • steam_appid.txt. A fresh SteamCMD install has no hlds\steam_appid.txt. hlds.exe writes it while starting, but after Steam has already failed, so the very first start ends in a "Fatal error: Unable to initialize Steam" box that blocks the desktop until it's closed. Start-CsServer writes the file (10) before every start. If the box shows up anyway, it closes the server and starts it again (up to 3 times). The server window starts minimized so it doesn't take the focus.
  • Firewall. Setup adds an allow rule for hlds\hlds.exe on all network types (admin prompt) before the first start, so Windows' own popup doesn't appear, and removes block rules Windows made if that popup was ever cancelled. Normal users often can't read firewall rules, so the result is remembered in secrets\firewall-rule.txt.
  • Install folder. Documents\cs16, or %USERPROFILE%\cs16 when Documents is synced by OneDrive, or C:\cs16 when the user folder has non-ASCII characters (SteamCMD and HLDS can't handle them). The folder is remembered in %LOCALAPPDATA%\cs16-dm-server\install-folder.txt, so running a newly downloaded setup.cmd updates the existing install.
  • Console log. -condebug writes hlds\qconsole.log; setup shows its end when the server doesn't come up.
  • No watchdog or backups. It's meant to be started and closed like a game.

Tests for the pure functions: Invoke-Pester windows\tests (Pester 3.4 ships with Windows 10).

Backup downloads

If a main download URL fails (or returns something that doesn't match the hash), setup tries the same file name under the #mirror URL in tools/versions.txt: the mods release on this repo's Gitea. Only the freely licensed files are there (ReHLDS, ReGameDLL, Metamod-R, AMX Mod X, ReAPI, ReUnion, YaPB); tools/make-mirror.sh uploads them. After bumping one of those versions, run it again.

Layout

setup.sh, cs, rcon, kills   Linux: install, menu, console, kill counter
setup.cmd, cs.cmd           Windows: install, menu (scripts in windows/)
.env.example                Linux settings template
docker-compose.yml          the container; Dockerfile = Debian + 32-bit libs + SteamCMD
cstrike/                    configs copied into the game on every setup
defaults/                   mapcycle.txt + custom.cfg, copied once, then yours
plugins/                    the own plugins (extras, rtv, mode switch), compiled by setup
tools/                      pinned downloads (versions*.txt), install-addons.sh, start.sh, hlq.py, make-mirror.sh
scripts/                    Linux watchdog, backup, install-cron
hlds/                       the game server (downloaded; maps, logs, stats)