vq3srv: remade to support a config; other: initial commt, some housekeeping
This commit is contained in:
parent
28b5bebc40
commit
3e8932a4f2
4 changed files with 82 additions and 60 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.vscode
|
||||||
|
config.yml
|
||||||
|
bootstrap.yml
|
14
bootstrap.example.yml
Normal file
14
bootstrap.example.yml
Normal 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
31
config.example.yml
Normal 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
94
vq3srv
|
@ -3,64 +3,24 @@ from argparse import ArgumentParser
|
||||||
from os import system
|
from os import system
|
||||||
from random import shuffle
|
from random import shuffle
|
||||||
from sys import exit
|
from sys import exit
|
||||||
|
from yaml import safe_load
|
||||||
# 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'
|
|
||||||
# }
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
desc = 'host a q3 server'
|
desc = 'host a q3 server'
|
||||||
parser = ArgumentParser(description=desc)
|
parser = ArgumentParser(description=desc)
|
||||||
parser.add_argument('-m', '--gamemode', default='ffa')
|
parser.add_argument('-m', '--gamemode', default='ffa')
|
||||||
parser.add_argument('-f', '--fraglimit', type=int, default=15)
|
parser.add_argument('-f', '--fraglimit', type=int)
|
||||||
parser.add_argument('-t', '--timelimit', type=int, default=10)
|
parser.add_argument('-t', '--timelimit', type=int)
|
||||||
parser.add_argument('-b', '--bots', type=int, default=0)
|
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()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def gen_confline(param, value):
|
def gen_confline(param, value, archive=False):
|
||||||
return 'seta {} "{}"\n'.format(param, value)
|
set_cmd = 'seta' if archive else 'set'
|
||||||
|
return '{} {} "{}"\n'.format(set_cmd, param, value)
|
||||||
|
|
||||||
|
|
||||||
def gen_maplist(maplist):
|
def gen_maplist(maplist):
|
||||||
|
@ -87,24 +47,38 @@ def gen_addbots(count, level='3', names=list()):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
cfg_data = str()
|
cfg_data, bvars, svars = str(), dict(), dict()
|
||||||
try:
|
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:
|
except AssertionError:
|
||||||
exit('Wrong game mode specified!')
|
exit('Wrong game mode `{}` specified!'.format(args.gamemode))
|
||||||
|
|
||||||
for param in BOOTSTRAP_OPTS:
|
smaps = cfg['gamemodes'][args.gamemode]['maps']
|
||||||
cfg_data += gen_confline(param, BOOTSTRAP_OPTS[param])
|
svars.update(cfg['gamemodes']['any']['vars'])
|
||||||
cfg_data += gen_confline('fraglimit', args.fraglimit)
|
svars.update(cfg['gamemodes'][args.gamemode]['vars'])
|
||||||
cfg_data += gen_confline('timelimit', args.timelimit)
|
if args.fraglimit:
|
||||||
# this should be last since it launches the actual maplist
|
svars.update({'fraglimit': args.fraglimit})
|
||||||
cfg_data += gen_maplist(MAPLISTS[args.gamemode])
|
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:
|
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)
|
config.write(cfg_data)
|
||||||
system('sudo -u {} {} {}'.format(USER, BIN, PARAM))
|
system('sudo -u {} {}'.format(cfg['user'], cfg['cmd']))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in a new issue