vq3srv: remade to support a config; other: initial commt, some housekeeping

This commit is contained in:
Von Random 2021-02-07 18:37:53 +03:00
parent 28b5bebc40
commit 3e8932a4f2
4 changed files with 82 additions and 60 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.vscode
config.yml
bootstrap.yml

14
bootstrap.example.yml Normal file
View file

@ -0,0 +1,14 @@
# these are saved to the q3config_server.cfg, so -B should only be used once really
# add any config variable with value here as needed,
# defaults are mostly sensible, so here is a rather small list
sv_pure: '0'
sv_maxclients: '8'
sv_hostname: 'myhost.tld'
# this will let your server send maps to clients
# the downloads are attempted from http://%sv_dlURL%/baseq3/mapname.pk3
# note the protocol - no support for https,
# as well as the need to have baseq3 as a part of the path
# note that clients have to seta cl_allowDownload 1 for that to work
sv_dlURL: 'anyhost.tld/q3'
sv_allowDownloads: '1'

31
config.example.yml Normal file
View file

@ -0,0 +1,31 @@
user: quake3
cmd: /opt/ioquake3/ioq3ded.x86_64 +exec autoexec.cfg
autoexec: /home/quake3/.q3a/baseq3/autoexec.cfg
gamemodes:
any:
vars:
fraglimit: 100
timelimit: 10
ffa:
maps: [
q3dm2, q3dm3, q3dm4, q3dm5, q3dm6,
q3dm7, q3dm8, q3dm9, q3dm10, q3dm11
]
vars:
fraglimit: 30
timelimit: 15
duel:
maps: [
q3dm1, q3dm2, pro-q3dm6, pro-q3dm13,
q3tourney1, q3tourney3, q3tourney5, q3tourney6,
pro-q3tourney2, pro-q3tourney4
]
vars:
fraglimit: 15
timelimit: 5
bots:
level: '3'
names: [
anarki, angel, crash, doom, hunter,
klesk, major, mynx, orbb, slash, xaero
]

94
vq3srv
View file

@ -3,64 +3,24 @@ from argparse import ArgumentParser
from os import system
from random import shuffle
from sys import exit
# TODO: move this shit to a yaml config somewhere in /etc
USER = 'quake3' # linux user, for sudo -u
BIN = '/usr/bin/q3ded'
CONF = '/srv/q3/.q3a/baseq3/autoexec.cfg'
PARAM = '+exec autoexec.cfg'
MAPLISTS = {
'ffa': [
'q3dm2', 'q3dm3', 'q3dm4', 'q3dm5', 'q3dm6',
'q3dm7', 'q3dm8', 'q3dm9', 'q3dm10', 'q3dm11'
],
'duel': [
'q3dm1', 'q3dm2', 'pro-q3dm6', 'pro-q3dm13',
'q3tourney1', 'q3tourney3', 'q3tourney5', 'q3tourney6',
'pro-q3tourney2', 'pro-q3tourney4'
],
'ctf': list()
}
BOTS = {
'level': '3',
'names': [
'Anarki', 'Angel', 'Crash', 'Doom', 'Hunter',
'Klesk', 'Major', 'Mynx', 'Orbb', 'Slash', 'Xaero'
]
}
# these are saved to the q3config_server.cfg on the first run
# no point in keeping them here afterwards
BOOTSTRAP_OPTS = dict()
# BOOTSTRAP_OPTS = {
# 'sv_pure': '0', # enable client side mods, like better fonts or graphics
# 'sv_maxclients': '8',
# 'sv_hostname': 'myhost.tld'
#
# # this will let your server send maps to clients
# # the downloads are attempted from http://%sv_dlURL%/baseq3/mapname.pk3
# # note the protocol - no support for https,
# # as well as the need to have baseq3 as a part of the path
# # note that clients have to seta cl_allowDownload 1 for that to work
# 'sv_dlURL': 'anyhost.tld/q3',
# 'sv_allowDownloads': '1'
# }
from yaml import safe_load
def parse_arguments():
desc = 'host a q3 server'
parser = ArgumentParser(description=desc)
parser.add_argument('-m', '--gamemode', default='ffa')
parser.add_argument('-f', '--fraglimit', type=int, default=15)
parser.add_argument('-t', '--timelimit', type=int, default=10)
parser.add_argument('-f', '--fraglimit', type=int)
parser.add_argument('-t', '--timelimit', type=int)
parser.add_argument('-b', '--bots', type=int, default=0)
parser.add_argument('-c', '--config', default='config.yml')
parser.add_argument('-B', '--bootstrap')
return parser.parse_args()
def gen_confline(param, value):
return 'seta {} "{}"\n'.format(param, value)
def gen_confline(param, value, archive=False):
set_cmd = 'seta' if archive else 'set'
return '{} {} "{}"\n'.format(set_cmd, param, value)
def gen_maplist(maplist):
@ -87,24 +47,38 @@ def gen_addbots(count, level='3', names=list()):
def main():
args = parse_arguments()
cfg_data = str()
cfg_data, bvars, svars = str(), dict(), dict()
try:
assert args.gamemode in MAPLISTS
with open(args.config, 'r') as config_file:
cfg = safe_load(config_file)
if args.bootstrap:
with open(args.bootstrap, 'r') as bootstrap_file:
bvars.update(safe_load(bootstrap_file))
assert args.gamemode != 'any' and args.gamemode in cfg['gamemodes']
except FileNotFoundError as error:
exit('Config `{}` not found!'.format(error.filename))
except AssertionError:
exit('Wrong game mode specified!')
exit('Wrong game mode `{}` specified!'.format(args.gamemode))
for param in BOOTSTRAP_OPTS:
cfg_data += gen_confline(param, BOOTSTRAP_OPTS[param])
cfg_data += gen_confline('fraglimit', args.fraglimit)
cfg_data += gen_confline('timelimit', args.timelimit)
# this should be last since it launches the actual maplist
cfg_data += gen_maplist(MAPLISTS[args.gamemode])
smaps = cfg['gamemodes'][args.gamemode]['maps']
svars.update(cfg['gamemodes']['any']['vars'])
svars.update(cfg['gamemodes'][args.gamemode]['vars'])
if args.fraglimit:
svars.update({'fraglimit': args.fraglimit})
if args.timelimit:
svars.update({'timelimit': args.timelimit})
for param in bvars:
cfg_data += gen_confline(param, bvars[param], archive=True)
for param in svars:
cfg_data += gen_confline(param, svars[param])
cfg_data += gen_maplist(smaps)
if args.bots:
cfg_data += gen_addbots(args.bots, **BOTS)
cfg_data += gen_addbots(args.bots, **cfg['bots'])
with open(CONF, 'w+') as config:
with open(cfg['autoexec'], 'w+') as config:
config.write(cfg_data)
system('sudo -u {} {} {}'.format(USER, BIN, PARAM))
system('sudo -u {} {}'.format(cfg['user'], cfg['cmd']))
if __name__ == '__main__':