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]>
89 lines
3.8 KiB
Bash
Executable File
89 lines
3.8 KiB
Bash
Executable File
#!/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
|