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

119 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](https://github.com/rehlds/ReHLDS) | 3.15.0.896 | drop-in engine with fixes and better performance; replaces `engine_i486.so`, `hlds_linux` etc. |
| [ReGameDLL_CS](https://github.com/rehlds/ReGameDLL_CS) | 5.30.0.814 | drop-in game logic (`cstrike/dlls/cs.so`) with `mp_freeforall`, `mp_forcerespawn` and more |
| [Metamod-R](https://github.com/rehlds/Metamod-R) | 1.3.0.149 | plugin loader; `liblist.gam` points the game at it |
| [AMX Mod X](https://www.amxmodx.org) | 1.10.0.5486 | scripting platform for the plugins |
| [ReAPI](https://github.com/rehlds/ReAPI) | 5.29.0.358 | AMXX module that gives plugins access to ReHLDS/ReGameDLL hooks |
| [ReUnion](https://github.com/rehlds/ReUnion) | 0.2.0.25 | lets non-Steam clients (protocol 47/48) join |
| [CSDM-ReAPI](https://github.com/wopox1337/CSDM-ReAPI) | 1.0.8 | deathmatch: respawn, gun menu, spawn points, spawn protection |
| [YaPB](https://github.com/yapb/yapb) | 4.4.957 | bots (Metamod plugin) |
| [GunGame](https://github.com/fysiks1/amxx-gungame_cstrike) | 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)
```