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 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__':
|
||||
|
|
Loading…
Reference in a new issue