ql-lg-server: Quake Live LG vampiric practice server in Docker
One-command setup (SteamCMD + minqlx build), .env settings with a listed/unlisted switch, three factories (lgvamp, lgvamp_nolag, lgvamp100), warmup-text and welcome minqlx plugins, watchdog/backup/daily-restart, docs for admins and players. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
bc5bd09c15
25 files changed
+1009
No files matched your search
@@ -0,0 +1,137 @@
|
||||
[
|
||||
{
|
||||
"id": "lgvamp",
|
||||
"title": "LG Vampiric FFA",
|
||||
"author": "ql-lg-server",
|
||||
"description": "LG only, 1:1 vampiric, no knockback, no items, antilag. Permanent warmup like the x76 LG duel servers: pair up and duel, ready-up can't start a match.",
|
||||
"basegt": "ffa",
|
||||
"tags": [
|
||||
"lg",
|
||||
"aimtraining"
|
||||
],
|
||||
"cvars": {
|
||||
"g_startingWeapons": "33",
|
||||
"g_infiniteAmmo": "1",
|
||||
"g_startingHealth": "100",
|
||||
"g_startingHealthBonus": "100",
|
||||
"g_startingArmor": "0",
|
||||
"g_vampiricDamage": "1",
|
||||
"g_knockback": "0",
|
||||
"g_weaponrespawn": "0",
|
||||
"g_spawnItemAmmo": "0",
|
||||
"g_spawnItemArmor": "0",
|
||||
"g_spawnItemHealth": "0",
|
||||
"g_spawnItemHoldable": "0",
|
||||
"g_spawnItemPowerup": "0",
|
||||
"g_spawnItemRune": "0",
|
||||
"g_spawnItemWeapons": "0",
|
||||
"g_allowKill": "0",
|
||||
"g_allowVote": "0",
|
||||
"g_allowVoteMidGame": "0",
|
||||
"g_allowSpecVote": "0",
|
||||
"g_voteFlags": "4095",
|
||||
"pmove_WeaponRaiseTime": "0",
|
||||
"pmove_WeaponDropTime": "0",
|
||||
"sv_warmupReadyPercentage": "2",
|
||||
"g_warmupReadyDelay": "0",
|
||||
"fraglimit": "50",
|
||||
"timelimit": "15",
|
||||
"g_lagHax": "1",
|
||||
"g_lagHaxMs": "240",
|
||||
"g_lagHaxMsec": "10",
|
||||
"g_lagHaxHistory": "12",
|
||||
"dmflags": "28",
|
||||
"g_overtime": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lgvamp_nolag",
|
||||
"title": "LG Vampiric FFA (no antilag)",
|
||||
"author": "ql-lg-server",
|
||||
"description": "LG only, 1:1 vampiric, no knockback, no items, no antilag. Permanent warmup like the x76 LG duel servers: pair up and duel, ready-up can't start a match.",
|
||||
"basegt": "ffa",
|
||||
"tags": [
|
||||
"lg",
|
||||
"aimtraining"
|
||||
],
|
||||
"cvars": {
|
||||
"g_startingWeapons": "33",
|
||||
"g_infiniteAmmo": "1",
|
||||
"g_startingHealth": "100",
|
||||
"g_startingHealthBonus": "100",
|
||||
"g_startingArmor": "0",
|
||||
"g_vampiricDamage": "1",
|
||||
"g_knockback": "0",
|
||||
"g_weaponrespawn": "0",
|
||||
"g_spawnItemAmmo": "0",
|
||||
"g_spawnItemArmor": "0",
|
||||
"g_spawnItemHealth": "0",
|
||||
"g_spawnItemHoldable": "0",
|
||||
"g_spawnItemPowerup": "0",
|
||||
"g_spawnItemRune": "0",
|
||||
"g_spawnItemWeapons": "0",
|
||||
"g_allowKill": "0",
|
||||
"g_allowVote": "0",
|
||||
"g_allowVoteMidGame": "0",
|
||||
"g_allowSpecVote": "0",
|
||||
"g_voteFlags": "4095",
|
||||
"pmove_WeaponRaiseTime": "0",
|
||||
"pmove_WeaponDropTime": "0",
|
||||
"sv_warmupReadyPercentage": "2",
|
||||
"g_warmupReadyDelay": "0",
|
||||
"fraglimit": "50",
|
||||
"timelimit": "15",
|
||||
"g_lagHax": "0",
|
||||
"g_lagHaxMs": "240",
|
||||
"g_lagHaxMsec": "10",
|
||||
"g_lagHaxHistory": "12",
|
||||
"dmflags": "28",
|
||||
"g_overtime": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lgvamp100",
|
||||
"title": "LG Vampiric FFA (100 HP)",
|
||||
"author": "ql-lg-server",
|
||||
"description": "LG only, 1:1 vampiric, no knockback, spawn with 100 HP (no decay), no items, antilag. Permanent warmup like the x76 LG duel servers: pair up and duel, ready-up can't start a match.",
|
||||
"basegt": "ffa",
|
||||
"tags": [
|
||||
"lg",
|
||||
"aimtraining"
|
||||
],
|
||||
"cvars": {
|
||||
"g_startingWeapons": "33",
|
||||
"g_infiniteAmmo": "1",
|
||||
"g_startingHealth": "100",
|
||||
"g_startingHealthBonus": "0",
|
||||
"g_startingArmor": "0",
|
||||
"g_vampiricDamage": "1",
|
||||
"g_knockback": "0",
|
||||
"g_weaponrespawn": "0",
|
||||
"g_spawnItemAmmo": "0",
|
||||
"g_spawnItemArmor": "0",
|
||||
"g_spawnItemHealth": "0",
|
||||
"g_spawnItemHoldable": "0",
|
||||
"g_spawnItemPowerup": "0",
|
||||
"g_spawnItemRune": "0",
|
||||
"g_spawnItemWeapons": "0",
|
||||
"g_allowKill": "0",
|
||||
"g_allowVote": "0",
|
||||
"g_allowVoteMidGame": "0",
|
||||
"g_allowSpecVote": "0",
|
||||
"g_voteFlags": "4095",
|
||||
"pmove_WeaponRaiseTime": "0",
|
||||
"pmove_WeaponDropTime": "0",
|
||||
"sv_warmupReadyPercentage": "2",
|
||||
"g_warmupReadyDelay": "0",
|
||||
"fraglimit": "50",
|
||||
"timelimit": "15",
|
||||
"g_lagHax": "1",
|
||||
"g_lagHaxMs": "240",
|
||||
"g_lagHaxMsec": "10",
|
||||
"g_lagHaxHistory": "12",
|
||||
"dmflags": "28",
|
||||
"g_overtime": "0"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
// ql-lg-server. Per-server settings come from .env (local.cfg, generated on start).
|
||||
// Gameplay lives in scripts/lgvamp.factories. See README.md and docs/HOW-IT-WORKS.md.
|
||||
set sv_serverType "2" // internet server (also right for VPN players)
|
||||
set sv_privateClients "0"
|
||||
set sv_fps "40"
|
||||
set sv_idleExit "0"
|
||||
set net_strict "1"
|
||||
set sv_floodprotect "10"
|
||||
set g_floodprot_maxcount "10"
|
||||
set g_floodprot_decay "1000"
|
||||
set g_accessFile "access.txt" // admins, mods, bans (docs/ADMIN.md)
|
||||
set sv_mapPoolFile "mappool_lg.txt"
|
||||
set g_allowVote "0"
|
||||
|
||||
// bots: none by default (permanent warmup needs none); rcon "addbot hunter 5", remove with "kick allbots"
|
||||
set bot_enable "1"
|
||||
set bot_minplayers "0"
|
||||
set bot_nochat "1"
|
||||
|
||||
// RCON over ZMQ, localhost only (port from .env, password from secrets/)
|
||||
set zmq_rcon_enable "1"
|
||||
set zmq_rcon_ip "127.0.0.1"
|
||||
set zmq_stats_enable "0"
|
||||
|
||||
// minqlx: only our plugins (the default minqlx plugin list needs a redis server)
|
||||
set qlx_plugins "nowarmuptext,welcome"
|
||||
set qlx_pluginsPath "/ql/home/minqlx-plugins"
|
||||
|
||||
exec secrets.cfg
|
||||
exec local.cfg // hostname, password, listing, max players, then: map <map> <factory>
|
||||
@@ -0,0 +1,32 @@
|
||||
# hide the client's warmup text ("The match will begin when more players join",
|
||||
# "Press F3 to ready yourself") while the server stays in permanent warmup (PRE_GAME).
|
||||
# The client draws that text only while configstring CS_WARMUP (5) carries a nonzero
|
||||
# "time" (warmup sets \time\-1), so we send clients an empty CS_WARMUP instead.
|
||||
import minqlx
|
||||
|
||||
CS_WARMUP = 5
|
||||
|
||||
|
||||
class nowarmuptext(minqlx.Plugin):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.add_hook("set_configstring", self.handle_set_configstring, priority=minqlx.PRI_HIGHEST)
|
||||
self.add_hook("map", self.handle_map)
|
||||
# The first map was set up before this plugin loaded: clear the value it stored.
|
||||
minqlx.set_configstring(CS_WARMUP, "")
|
||||
self.log_warmup("loaded")
|
||||
|
||||
def handle_set_configstring(self, index, value):
|
||||
if index == CS_WARMUP and value:
|
||||
return ""
|
||||
|
||||
def handle_map(self, mapname, factory):
|
||||
self.log_warmup_later()
|
||||
|
||||
@minqlx.delay(2)
|
||||
def log_warmup_later(self):
|
||||
self.log_warmup("map loaded")
|
||||
|
||||
def log_warmup(self, when):
|
||||
self.logger.info("nowarmuptext %s: CS_WARMUP=%r g_gameState=%s", when,
|
||||
minqlx.get_configstring(CS_WARMUP), minqlx.get_cvar("g_gameState"))
|
||||
@@ -0,0 +1,23 @@
|
||||
# Welcome message: tells each player the text of qlx_welcome (QL_WELCOME in .env) a few seconds
|
||||
# after they finish loading the map. Empty = nothing is sent.
|
||||
import minqlx
|
||||
|
||||
|
||||
class welcome(minqlx.Plugin):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.set_cvar_once("qlx_welcome", "")
|
||||
self.add_hook("player_loaded", self.handle_player_loaded)
|
||||
|
||||
def handle_player_loaded(self, player):
|
||||
self.greet(player)
|
||||
|
||||
@minqlx.delay(3)
|
||||
def greet(self, player):
|
||||
text = self.get_cvar("qlx_welcome")
|
||||
if text:
|
||||
try:
|
||||
player.tell(text)
|
||||
player.center_print(text)
|
||||
except minqlx.NonexistentPlayerError:
|
||||
pass # left before the message went out
|
||||
Reference in new issue
Block a user