#!/usr/bin/env python3 from argparse import ArgumentParser from os import system from os.path import basename from random import shuffle from sys import exit from yaml import safe_load GDEFAULTS = { 'bots': { 'level': 3, 'names': ['anarki', 'angel', 'crash', 'doom', 'hunter', 'klesk', 'major', 'mynx', 'orbb', 'slash', 'xaero'] } } MDEFAULTS = { 'randomize': True, 'vars': { 'fraglimit': 30, 'timelimit': 15 } } def parse_arguments(): desc = 'host a q3 server' parser = ArgumentParser(description=desc) parser.add_argument('-m', '--gamemode', default='default') parser.add_argument('-b', '--bots', type=int, default=0) parser.add_argument('-c', '--config', default='config.yml') parser.add_argument('-B', '--bootstrap') parser.add_argument('-d', '--debug', action="store_true") return parser.parse_args() 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, randomize=True): num = 1 stmpl = 'set d{} "map {} ; set nextmap vstr d{}"\n' script = str() if randomize: shuffle(maplist) 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, names): btmpl = 'addbot {} {}\n' script = str() shuffle(names) for bot in names[:count]: script += btmpl.format(bot, level) return script def gen_exec(gcfg, mcfg, bvars=dict(), bot_count=0, debug=False): cfg_data = str() for param in bvars: cfg_data += gen_confline(param, bvars[param], archive=True) cfg_data += gen_maplist(mcfg['maps'], mcfg.get('randomize', MDEFAULTS['randomize'])) if bot_count: bot_level = gcfg.\ get('bots', GDEFAULTS['bots']).\ get('level', GDEFAULTS['bots']['level']) bot_names = gcfg.\ get('bots', GDEFAULTS['bots']).\ get('names', GDEFAULTS['bots']['names']) cfg_data += gen_addbots(bot_count, bot_level, bot_names) if debug: print('Debug {} contents:\n{}'.format(gcfg['exec'], cfg_data)) return try: with open(gcfg['exec'], 'w+') as config: config.write(cfg_data) except FileNotFoundError as error: exit('Config `{}` not found!'.format(error.filename)) def main(): args = parse_arguments() cfg_data, cmd_list, bvars = str(), list(), dict() try: with open(args.config, 'r') as config_file: gcfg = safe_load(config_file) assert {'user', 'exec', 'cmd'} <= gcfg.keys() mcfg = gcfg['gamemodes'][args.gamemode] assert 'maps' in mcfg if args.bootstrap: with open(args.bootstrap, 'r') as bootstrap_file: bvars = safe_load(bootstrap_file) except FileNotFoundError as error: exit('Config `{}` not found!'.format(error.filename)) except (AssertionError, KeyError): exit('Missing required settings in {}!'.format(args.config)) svars = mcfg.get('vars', MDEFAULTS['vars']) exec_filename = basename(gcfg['exec']) for param in svars: cmd_list.append('+set {} {}'.format(param, svars[param])) cmd_list.append('+exec {}'.format(exec_filename)) cmd_opts = ' '.join(cmd_list) action = print if args.debug else system gen_exec(gcfg, mcfg, bvars, args.bots, args.debug) action('sudo -u {} {} {}'.format(gcfg['user'], gcfg['cmd'], cmd_opts)) if __name__ == '__main__': main()