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:
commit
7e9cbee14d
33 files changed
+1890
No files matched your search
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Server console from the terminal (the RCON password never leaves this machine).
|
||||
./rcon status one command
|
||||
./rcon interactive prompt (Ctrl+D or 'exit' to quit)
|
||||
Reads the port from .env and the password from secrets/rcon-password.txt."""
|
||||
import os, socket, sys
|
||||
|
||||
D = os.path.dirname(os.path.abspath(__file__))
|
||||
env = {}
|
||||
for line in open(os.path.join(D, ".env"), encoding="utf-8"):
|
||||
k, _, v = line.strip().partition("=")
|
||||
env[k] = v
|
||||
PW = open(os.path.join(D, "secrets", "rcon-password.txt")).read().strip()
|
||||
ADDR = ("127.0.0.1", int(env.get("CS_PORT") or 27015))
|
||||
H = b"\xff\xff\xff\xff"
|
||||
|
||||
|
||||
def rcon(cmd):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.settimeout(3)
|
||||
try:
|
||||
s.sendto(H + b"challenge rcon\n", ADDR)
|
||||
ch = s.recvfrom(4096)[0].split()[2]
|
||||
except (OSError, IndexError):
|
||||
return "(no answer: server down or changing map?)"
|
||||
s.sendto(H + b"rcon " + ch + b' "' + PW.encode() + b'" ' + cmd.encode(), ADDR)
|
||||
out = []
|
||||
while True: # long replies (status, cvarlist) come in several packets
|
||||
try:
|
||||
data = s.recvfrom(65535)[0]
|
||||
except OSError:
|
||||
break
|
||||
out.append(data[5:].decode(errors="replace") if data[:4] == H else data.decode(errors="replace"))
|
||||
s.settimeout(0.4)
|
||||
text = "".join(out)
|
||||
# never show passwords (a map change prints the whole cvar list)
|
||||
return "\n".join(l for l in text.splitlines()
|
||||
if "rcon_password" not in l and "sv_password" not in l) or "(ok, no output)"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
print(rcon(" ".join(sys.argv[1:])))
|
||||
sys.exit()
|
||||
print("CS 1.6 console: status, changelevel de_nuke, yb_quota 6, esef_mode gg, say hi. Ctrl+D to quit.")
|
||||
while True:
|
||||
try:
|
||||
line = input("cs16> ").strip()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print()
|
||||
break
|
||||
if line in ("exit", "quit"):
|
||||
break
|
||||
if line:
|
||||
print(rcon(line))
|
||||
Reference in new issue
Block a user