vq3srv: initial commit
This commit is contained in:
parent
62ff5d45c7
commit
28b5bebc40
2 changed files with 112 additions and 1 deletions
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
MIT License Copyright (c) <year> <copyright holders>
|
MIT License Copyright (c) 2021 Von Random
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
111
vq3srv
Executable file
111
vq3srv
Executable file
|
@ -0,0 +1,111 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
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'
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
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('-b', '--bots', type=int, default=0)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def gen_confline(param, value):
|
||||||
|
return 'seta {} "{}"\n'.format(param, value)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_maplist(maplist):
|
||||||
|
shuffle(maplist)
|
||||||
|
num = 1
|
||||||
|
stmpl = 'set d{} "map {} ; set nextmap vstr d{}"\n'
|
||||||
|
script = str()
|
||||||
|
while maplist:
|
||||||
|
nextnum = 1 if len(maplist) == 1 else num + 1
|
||||||
|
script += stmpl.format(num, maplist.pop(), nextnum)
|
||||||
|
num += 1
|
||||||
|
script += 'vstr d1\n'
|
||||||
|
return script
|
||||||
|
|
||||||
|
|
||||||
|
def gen_addbots(count, level='3', names=list()):
|
||||||
|
shuffle(names)
|
||||||
|
btmpl = 'addbot {} {}\n'
|
||||||
|
script = str()
|
||||||
|
for bot in names[:count]:
|
||||||
|
script += btmpl.format(bot, level)
|
||||||
|
return script
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_arguments()
|
||||||
|
cfg_data = str()
|
||||||
|
try:
|
||||||
|
assert args.gamemode in MAPLISTS
|
||||||
|
except AssertionError:
|
||||||
|
exit('Wrong game mode specified!')
|
||||||
|
|
||||||
|
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])
|
||||||
|
if args.bots:
|
||||||
|
cfg_data += gen_addbots(args.bots, **BOTS)
|
||||||
|
|
||||||
|
with open(CONF, 'w+') as config:
|
||||||
|
config.write(cfg_data)
|
||||||
|
system('sudo -u {} {} {}'.format(USER, BIN, PARAM))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in a new issue