cs16-dm-server: CS 1.6 deathmatch server in Docker

One-command setup (SteamCMD + pinned, checksum-verified ReHLDS / ReGameDLL /
Metamod-R / AMXX / ReAPI / ReUnion / CSDM-ReAPI / YaPB / GunGame), .env
settings, ./cs menu (map, DM/GunGame mode, bots, kill counter, restart,
update), own plugins (extras, rtv, mode switch), all-time kill counter,
watchdog + nightly backup, docs for admins and players.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
esefandClaude Opus 5.5 committed 2026-10-11 05:03:07 +03:00
commit 7e9cbee14d
33 files changed
+1890

No files matched your search

Executable
+88
View File
@@ -0,0 +1,88 @@
#!/bin/sh
# Control menu: ./cs (pick a number)
# or directly: ./cs status | map <name> | mode dm|gg | bots <n> | kills | say <text>
# ./cs restart | stop | start | logs | console | apply | update
D=$(cd "$(dirname "$0")" && pwd)
cd "$D" || exit 1
[ -f .env ] || { echo "no .env yet: run ./setup.sh first"; exit 1; }
getenv() { sed -n "s/^$1=//p" .env | tr -d '\r'; }
setenv() { sed -i "s|^$1=.*|$1=$2|" .env; }
NAME=$(getenv CS_NAME); NAME=${NAME:-cs16}
PORT=$(getenv CS_PORT); PORT=${PORT:-27015}
C=hlds/cstrike
status() {
st=$(docker inspect -f '{{.State.Status}}' "$NAME" 2>/dev/null || echo "not created")
if [ "$st" = running ]; then
if out=$(python3 tools/hlq.py info 127.0.0.1 "$PORT" 2>/dev/null); then echo " ${out#A2S_INFO ok: }"
else echo " container running, server not answering yet (starting or changing map?)"; fi
if [ -f $C/addons/amxmodx/configs/plugins-gungame.ini ]; then echo " mode: GunGame"; else echo " mode: deathmatch"; fi
else
echo " server is $st (start it: ./cs start)"
fi
}
players() { ./rcon status | grep -a -E '^#|^map|^players' ; }
setmap() {
m=$1
if [ -z "$m" ]; then
echo "Maps on this server:"
ls $C/maps/*.bsp 2>/dev/null | sed 's|.*/||; s|\.bsp$||' | nl -w3 -s') ' | pr -3 -t -w 90
printf 'map name or number: '; read -r m
case "$m" in ''|*[!0-9]*) ;; *) m=$(ls $C/maps/*.bsp | sed 's|.*/||; s|\.bsp$||' | sed -n "${m}p") ;; esac
fi
[ -n "$m" ] || return
[ -f "$C/maps/$m.bsp" ] || { echo "no map called '$m' in $C/maps"; return; }
r=$(./rcon changelevel "$m"); case "$r" in "(no answer"*) echo "$r" ;; *) echo "changing to $m" ;; esac
}
setmode() {
m=$1
[ -n "$m" ] || { printf 'mode: dm = deathmatch, gg = GunGame: '; read -r m; }
case "$m" in dm|gg) ./rcon esef_mode "$m" | grep -a esef_mode ;; *) echo "use dm or gg" ;; esac
}
setbots() {
n=$1
[ -n "$n" ] || { printf 'fill the server up to how many players with bots? (0 = no bots, now %s): ' "$(getenv CS_BOTS)"; read -r n; }
case "$n" in ''|*[!0-9]*) echo "give a number"; return ;; esac
setenv CS_BOTS "$n" # remembered for restarts
r=$(./rcon yb_quota "$n"); case "$r" in "(no answer"*) echo "saved in .env, applies when the server is back: $r" ;; *) echo "bots: up to $n players (saved in .env)" ;; esac
}
run() {
case "$1" in
status|1) status; players ;;
map|2) shift; setmap "$1" ;;
mode|3) shift; setmode "$1" ;;
bots|4) shift; setbots "$1" ;;
kills|5) python3 kills ;;
say|6) shift; t="$*"; [ -n "$t" ] || { printf 'message: '; read -r t; }; [ -n "$t" ] && ./rcon say "$t" > /dev/null && echo sent ;;
restart|7) docker restart "$NAME" > /dev/null && echo "restarted (back in ~10 s)" ;;
stop|8) docker compose stop && echo "stopped (./cs start to start again)" ;;
start|9) docker compose up -d ;;
logs|10) echo "live server output, Ctrl+C to leave"; docker logs -f --tail 30 "$NAME" 2>&1 | grep --line-buffered -v -E 'rcon_password|sv_password|Rcon:' ;;
console|11) ./rcon ;;
apply|12) docker compose up -d && echo "applied .env (server restarted if anything changed)" ;;
update|13) ./setup.sh --yes --update ;;
*) echo "unknown: $1 (try ./cs with no arguments)"; return 1 ;;
esac
}
if [ $# -gt 0 ]; then run "$@"; exit $?; fi
while true; do
echo
echo "== $(getenv CS_HOSTNAME) == (container $NAME, UDP $PORT)"
status
cat <<'EOF'
1) who's playing 8) stop server
2) change map 9) start server
3) game mode (DM / GG) 10) live log
4) bots 11) console (type server commands)
5) kill counter 12) apply .env changes
6) message to players 13) update game + mods
7) restart server 0) quit
EOF
printf '> '; read -r c || break
case "$c" in 0|q|quit|exit|'') break ;; esac
run "$c"
done