setup.cmd installs the same DM/GunGame server natively on Windows 10/11 (no Docker or Python) into Documents\cs16, then helps set up how friends join (LAN, playit.gg, port forwarding, VPN). cs.cmd is the menu. Also: setup falls back to backup copies of the freely licensed mod downloads on this Gitea when a main site is down (tools/make-mirror.sh fills them), and the README is rewritten as a plain guide. Co-Authored-By: Claude Opus 5.5 <[email protected]>
11 KiB
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)
- Creates
.envand asks the questions. Generatessecrets/rcon-password.txtandsecrets/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. - Builds the image: Debian bookworm, 32-bit libs, SteamCMD, unzip/xz.
- Downloads the game with SteamCMD, anonymously, with up to 4 tries, because app 90 often fails the first time. It runs
validateonly 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. tools/install-addons.shruns inside the image (repo mounted read-only, onlydl/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 0that itsgame.cfgwould force on every map - unpacks Metamod and points
liblist.gamat it (a copy of the original is kept asliblist.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 775on 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) andyb_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_modeandgungamewith AMXX'samxxpc - leaves exactly one of
plugins-CSDM_ReAPI.ini/plugins-gungame.iniactive. It keeps the mode that was running before, or usesCS_MODEon the first install. - symlinks
steamclient.sointo~/.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.txtandcustom.cfgare only written on the first install.
- 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) andcstrike/secrets.cfg(RCON + join password, mode 600) from.envandsecrets/ - sets
yb_quota/yb_difficultyinaddons/yapb/conf/yapb.cfgfromCS_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, plusmp_freeforall 1ingg_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 ordocker 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'srestart: unless-stoppedstarts 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.shruns from cron and A2S-queries the server. After 3 failed checks in a row it runsdocker restart. - Logs: Docker's json log is capped at 3 × 10 MB.
scripts/backup.shdeletes 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 installed on the same PC. The server's
steam_api.dllfinds the Steam client'ssteamclient.dllthroughHKCU\Software\Valve\Steam\ActiveProcess\SteamClientDlland loads that instead of its own, which ends in "Unable to initialize Steam".Start-CsServerrenames that value until the server answers queries (a few seconds), then puts it back. Steam rewrites it at every start anyway, and every script repairs it on load if a start was interrupted. - Firewall. Setup adds an allow rule for
hlds\hlds.exeon 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 insecrets\firewall-rule.txt. - Install folder.
Documents\cs16, or%USERPROFILE%\cs16when Documents is synced by OneDrive, orC:\cs16when 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 downloadedsetup.cmdupdates the existing install. - Console log.
-condebugwriteshlds\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)