def gen_game(gen_options, race=False, owner=None, sid=None): try: target = tempfile.TemporaryDirectory() playercount = len(gen_options) seed = get_seed() random.seed(seed) if race: random.seed() # reset to time-based random source seedname = "M" + ( f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)) erargs = parse_arguments(['--multi', str(playercount)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, playercount + 1) } # only so it can be overwrittin in mystery erargs.create_spoiler = not race erargs.race = race erargs.skip_playthrough = race erargs.outputname = seedname erargs.outputpath = target.name erargs.teams = 1 erargs.progression_balancing = {} erargs.create_diff = True name_counter = Counter() for player, (playerfile, settings) in enumerate(gen_options.items(), 1): for k, v in settings.items(): if v is not None: getattr(erargs, k)[player] = v if not erargs.name[player]: erargs.name[player] = os.path.splitext( os.path.split(playerfile)[-1])[0] erargs.name[player] = handle_name(erargs.name[player], player, name_counter) erargs.names = ",".join(erargs.name[i] for i in range(1, playercount + 1)) del (erargs.name) erargs.skip_progression_balancing = { player: not balanced for player, balanced in erargs.progression_balancing.items() } del (erargs.progression_balancing) ERmain(erargs, seed) return upload_to_db(target.name, owner, sid, race) except BaseException as e: if sid: with db_session: gen = Generation.get(id=sid) if gen is not None: gen.state = STATE_ERROR gen.meta = (e.__class__.__name__ + ": " + str(e)).encode() raise
def gen(gen_options, race=False): target = tempfile.TemporaryDirectory() with target: playercount = len(gen_options) seed = get_seed() random.seed(seed) if race: random.seed() # reset to time-based random source seedname = "M" + ( f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)) erargs = parse_arguments(['--multi', str(playercount)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, playercount + 1) } # only so it can be overwrittin in mystery erargs.create_spoiler = not race erargs.race = race erargs.skip_playthrough = race erargs.outputname = seedname erargs.outputpath = target.name erargs.teams = 1 erargs.progression_balancing = {} erargs.create_diff = True for player, (playerfile, settings) in enumerate(gen_options.items(), 1): for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v if not erargs.name[player]: erargs.name[player] = os.path.split(playerfile)[-1].split( ".")[0] erargs.names = ",".join(erargs.name[i] for i in range(1, playercount + 1)) del (erargs.name) erargs.skip_progression_balancing = { player: not balanced for player, balanced in erargs.progression_balancing.items() } del (erargs.progression_balancing) ERmain(erargs, seed) return upload_to_db(target.name)
def main(args=None, callback=ERmain): if not args: args = mystery_argparse() seed = get_seed(args.seed) random.seed(seed) seedname = "M" + ( f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits)) print( f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}" ) if args.race: random.seed() # reset to time-based random source weights_cache = {} if args.weights: try: weights_cache[args.weights] = get_weights(args.weights) except Exception as e: raise ValueError( f"File {args.weights} is destroyed. Please fix your yaml." ) from e print( f"Weights: {args.weights} >> " f"{get_choice('description', weights_cache[args.weights], 'No description specified')}" ) if args.meta: try: weights_cache[args.meta] = get_weights(args.meta) except Exception as e: raise ValueError( f"File {args.meta} is destroyed. Please fix your yaml.") from e meta_weights = weights_cache[args.meta] print( f"Meta: {args.meta} >> {get_choice('meta_description', meta_weights, 'No description specified')}" ) if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: try: if path not in weights_cache: weights_cache[path] = get_weights(path) print( f"P{player} Weights: {path} >> " f"{get_choice('description', weights_cache[path], 'No description specified')}" ) except Exception as e: raise ValueError( f"File {path} is destroyed. Please fix your yaml.") from e erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, args.multi + 1) } # only so it can be overwrittin in mystery erargs.create_spoiler = args.create_spoiler erargs.create_diff = args.create_diff erargs.glitch_triforce = args.glitch_triforce erargs.race = args.race erargs.skip_playthrough = args.skip_playthrough erargs.outputname = seedname erargs.outputpath = args.outputpath erargs.teams = args.teams erargs.progression_balancing = {} # set up logger if args.loglevel: erargs.loglevel = args.loglevel loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[erargs.loglevel] if args.log_output_path: import sys class LoggerWriter(object): def __init__(self, writer): self._writer = writer self._msg = '' def write(self, message): self._msg = self._msg + message while '\n' in self._msg: pos = self._msg.find('\n') self._writer(self._msg[:pos]) self._msg = self._msg[pos + 1:] def flush(self): if self._msg != '': self._writer(self._msg) self._msg = '' log = logging.getLogger("stderr") log.addHandler(logging.StreamHandler()) sys.stderr = LoggerWriter(log.error) os.makedirs(args.log_output_path, exist_ok=True) logging.basicConfig(format='%(message)s', level=loglevel, filename=os.path.join(args.log_output_path, f"{seed}.log")) else: logging.basicConfig(format='%(message)s', level=loglevel) if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = { k: (roll_settings(v, args.plando) if args.samesettings else None) for k, v in weights_cache.items() } player_path_cache = {} for player in range(1, args.multi + 1): player_path_cache[player] = getattr(args, f'p{player}') if getattr( args, f'p{player}') else args.weights if args.meta: for player, path in player_path_cache.items(): weights_cache[path].setdefault("meta_ignore", []) meta_weights = weights_cache[args.meta] for key in meta_weights: option = get_choice(key, meta_weights) if option is not None: for player, path in player_path_cache.items(): players_meta = weights_cache[path].get("meta_ignore", []) if key not in players_meta: weights_cache[path][key] = option elif type(players_meta) == dict and players_meta[ key] and option not in players_meta[key]: weights_cache[path][key] = option name_counter = Counter() for player in range(1, args.multi + 1): path = player_path_cache[player] if path: try: settings = settings_cache[path] if settings_cache[path] else \ roll_settings(weights_cache[path], args.plando) if settings.sprite and not os.path.isfile( settings.sprite) and not Sprite.get_sprite_from_name( settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist." ) if args.pre_roll: import yaml if path == args.weights: settings.name = f"Player{player}" elif not settings.name: settings.name = os.path.splitext( os.path.split(path)[-1])[0] if "-" not in settings.shuffle and settings.shuffle != "vanilla": settings.shuffle += f"-{random.randint(0, 2 ** 64)}" pre_rolled = dict() pre_rolled["original_seed_number"] = seed pre_rolled["original_seed_name"] = seedname pre_rolled["pre_rolled"] = vars(settings).copy() if "plando_items" in pre_rolled["pre_rolled"]: pre_rolled["pre_rolled"]["plando_items"] = [ item.to_dict() for item in pre_rolled["pre_rolled"] ["plando_items"] ] if "plando_connections" in pre_rolled["pre_rolled"]: pre_rolled["pre_rolled"]["plando_connections"] = [ connection.to_dict() for connection in pre_rolled["pre_rolled"]["plando_connections"] ] with open( os.path.join( args.outputpath if args.outputpath else ".", f"{os.path.split(path)[-1].split('.')[0]}_pre_rolled.yaml" ), "wt") as f: yaml.dump(pre_rolled, f) for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v except Exception as e: raise ValueError( f"File {path} is destroyed. Please fix your yaml.") from e else: raise RuntimeError(f'No weights specified for player {player}') if path == args.weights: # if name came from the weights file, just use base player name erargs.name[player] = f"Player{player}" elif not erargs.name[ player]: # if name was not specified, generate it from filename erargs.name[player] = os.path.splitext(os.path.split(path)[-1])[0] erargs.name[player] = handle_name(erargs.name[player], player, name_counter) logging.info(erargs.name[player]) erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) del (erargs.name) if args.yaml_output: import yaml important = {} for option, player_settings in vars(erargs).items(): if type(player_settings) == dict: if all( type(value) != list for value in player_settings.values()): if len(player_settings.values()) > 1: important[option] = { player: value for player, value in player_settings.items() if player <= args.yaml_output } elif len(player_settings.values()) > 0: important[option] = player_settings[1] else: logging.debug( f"No player settings defined for option '{option}'" ) else: if player_settings != "": # is not empty name important[option] = player_settings else: logging.debug( f"No player settings defined for option '{option}'") if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) with open( os.path.join(args.outputpath if args.outputpath else ".", f"mystery_result_{seed}.yaml"), "wt") as f: yaml.dump(important, f) erargs.skip_progression_balancing = { player: not balanced for player, balanced in erargs.progression_balancing.items() } del (erargs.progression_balancing) callback(erargs, seed)
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) multiargs, _ = parser.parse_known_args() parser = argparse.ArgumentParser() parser.add_argument( '--weights', help= 'Path to the weights file to use for rolling game settings, urls are also valid' ) parser.add_argument( '--samesettings', help='Rolls settings per weights file rather than per player', action='store_true') parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) parser.add_argument('--create_spoiler', action='store_true') parser.add_argument('--skip_playthrough', action='store_true') parser.add_argument('--rom') parser.add_argument('--enemizercli') parser.add_argument('--outputpath') parser.add_argument('--race', action='store_true') parser.add_argument('--meta', default=None) parser.add_argument('--log_output_path', help='Path to store output log') parser.add_argument('--loglevel', default='info', help='Sets log level') parser.add_argument( '--yaml_output', default=0, type=lambda value: min(max(int(value), 0), 255), help= 'Output rolled mystery results to yaml up to specified number (made for async multiworld)' ) for player in range(1, multiargs.multi + 1): parser.add_argument(f'--p{player}', help=argparse.SUPPRESS) args = parser.parse_args() if args.seed is None: random.seed(None) seed = random.randint(0, 999999999) else: seed = args.seed random.seed(seed) seedname = "M" + (f"{random.randint(0, 999999999)}".zfill(9)) print( f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}" ) weights_cache = {} if args.weights: try: weights_cache[args.weights] = get_weights(args.weights) except Exception as e: raise ValueError( f"File {args.weights} is destroyed. Please fix your yaml." ) from e print( f"Weights: {args.weights} >> {weights_cache[args.weights]['description']}" ) if args.meta: try: weights_cache[args.meta] = get_weights(args.meta) except Exception as e: raise ValueError( f"File {args.meta} is destroyed. Please fix your yaml.") from e meta_weights = weights_cache[args.meta] print(f"Meta: {args.meta} >> {meta_weights['meta_description']}") if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: try: if path not in weights_cache: weights_cache[path] = get_weights(path) print( f"P{player} Weights: {path} >> {weights_cache[path]['description']}" ) except Exception as e: raise ValueError( f"File {path} is destroyed. Please fix your yaml.") from e erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, args.multi + 1) } # only so it can be overwrittin in mystery erargs.create_spoiler = args.create_spoiler erargs.race = args.race erargs.skip_playthrough = args.skip_playthrough erargs.outputname = seedname erargs.outputpath = args.outputpath erargs.teams = args.teams erargs.progression_balancing = {} # set up logger if args.loglevel: erargs.loglevel = args.loglevel loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[erargs.loglevel] import sys class LoggerWriter(object): def __init__(self, writer): self._writer = writer self._msg = '' def write(self, message): self._msg = self._msg + message while '\n' in self._msg: pos = self._msg.find('\n') self._writer(self._msg[:pos]) self._msg = self._msg[pos + 1:] def flush(self): if self._msg != '': self._writer(self._msg) self._msg = '' if args.log_output_path: log = logging.getLogger("stderr") log.addHandler(logging.StreamHandler()) sys.stderr = LoggerWriter(log.error) os.makedirs(args.log_output_path, exist_ok=True) logging.basicConfig(format='%(message)s', level=loglevel, filename=os.path.join(args.log_output_path, f"{seed}.log")) else: logging.basicConfig(format='%(message)s', level=loglevel) if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = { k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items() } player_path_cache = {} for player in range(1, args.multi + 1): player_path_cache[player] = getattr(args, f'p{player}') if getattr( args, f'p{player}') else args.weights if args.meta: for player, path in player_path_cache.items(): weights_cache[path].setdefault("meta_ignore", []) meta_weights = weights_cache[args.meta] for key in meta_weights: option = get_choice(key, meta_weights) if option is not None: for player, path in player_path_cache.items(): players_meta = weights_cache[path].get("meta_ignore", []) if key not in players_meta: weights_cache[path][key] = option elif type(players_meta) == dict and players_meta[ key] and option not in players_meta[key]: weights_cache[path][key] = option for player in range(1, args.multi + 1): path = player_path_cache[player] if path: try: settings = settings_cache[path] if settings_cache[ path] else roll_settings(weights_cache[path]) if settings.sprite is not None and not os.path.isfile( settings.sprite) and not get_sprite_from_name( settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist." ) for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v except Exception as e: raise ValueError( f"File {path} is destroyed. Please fix your yaml.") from e else: raise RuntimeError(f'No weights specified for player {player}') if not erargs.name[player]: erargs.name[player] = os.path.split(path)[-1].split(".")[0] if args.weights: erargs.names = "" else: erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) del (erargs.name) if args.yaml_output: import yaml important = {} for option, player_settings in vars(erargs).items(): if type(player_settings) == dict: if len(set(player_settings.values())) > 1: important[option] = { player: value for player, value in player_settings.items() if player <= args.yaml_output } elif len(set(player_settings.values())) > 0: important[option] = player_settings[1] else: logging.debug( f"No player settings defined for option '{option}'") else: if player_settings != "": # is not empty name important[option] = player_settings else: logging.debug( f"No player settings defined for option '{option}'") if args.outputpath: os.makedirs(args.outputpath, exist_ok=True) with open( os.path.join(args.outputpath if args.outputpath else ".", f"mystery_result_{seed}.yaml"), "wt") as f: yaml.dump(important, f) erargs.skip_progression_balancing = { player: not balanced for player, balanced in erargs.progression_balancing.items() } del (erargs.progression_balancing) ERmain(erargs, seed)
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) multiargs, _ = parser.parse_known_args() parser = argparse.ArgumentParser() parser.add_argument('--weights', help='Path to the weights file to use for rolling game settings, urls are also valid') parser.add_argument('--samesettings', help='Rolls settings per weights file rather than per player', action='store_true') parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) parser.add_argument('--create_spoiler', action='store_true') parser.add_argument('--rom') parser.add_argument('--enemizercli') parser.add_argument('--outputpath') parser.add_argument('--race', action='store_true') parser.add_argument('--meta', default=None) for player in range(1, multiargs.multi + 1): parser.add_argument(f'--p{player}', help=argparse.SUPPRESS) args = parser.parse_args() if args.seed is None: random.seed(None) seed = random.randint(0, 999999999) else: seed = args.seed random.seed(seed) seedname = "M"+(f"{random.randint(0, 999999999)}".zfill(9)) print(f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}") weights_cache = {} if args.weights: try: weights_cache[args.weights] = get_weights(args.weights) except Exception as e: raise ValueError(f"File {args.weights} is destroyed. Please fix your yaml.") from e print(f"Weights: {args.weights} >> {weights_cache[args.weights]['description']}") if args.meta: try: weights_cache[args.meta] = get_weights(args.meta) except Exception as e: raise ValueError(f"File {args.meta} is destroyed. Please fix your yaml.") from e print(f"Meta: {args.meta} >> {weights_cache[args.meta]['meta_description']}") if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: try: if path not in weights_cache: weights_cache[path] = get_weights(path) print(f"P{player} Weights: {path} >> {weights_cache[path]['description']}") except Exception as e: raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.name = {x: "" for x in range(1, args.multi + 1)} # only so it can be overwrittin in mystery erargs.create_spoiler = args.create_spoiler erargs.race = args.race erargs.outputname = seedname erargs.outputpath = args.outputpath erargs.teams = args.teams # set up logger loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = {k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items()} player_path_cache = {} for player in range(1, args.multi + 1): player_path_cache[player] = getattr(args, f'p{player}') if getattr(args, f'p{player}') else args.weights if args.meta: for player, path in player_path_cache.items(): weights_cache[path].setdefault("meta_ignore", []) meta_weights = weights_cache[args.meta] for key in meta_weights: option = get_choice(key, meta_weights) if option is not None: for player, path in player_path_cache.items(): players_meta = weights_cache[path]["meta_ignore"] if key not in players_meta: weights_cache[path][key] = option elif type(players_meta) == dict and option not in players_meta[key]: weights_cache[path][key] = option for player in range(1, args.multi + 1): path = player_path_cache[player] if path: try: settings = settings_cache[path] if settings_cache[path] else roll_settings(weights_cache[path]) if settings.sprite is not None and not os.path.isfile(settings.sprite) and not get_sprite_from_name(settings.sprite): logging.warning( f"Warning: The chosen sprite, \"{settings.sprite}\", for yaml \"{path}\", does not exist.") for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v except Exception as e: raise ValueError(f"File {path} is destroyed. Please fix your yaml.") from e else: raise RuntimeError(f'No weights specified for player {player}') if not erargs.name[player]: erargs.name[player] = os.path.split(path)[-1].split(".")[0] if args.samesettings: erargs.names = "" else: erargs.names = ",".join(erargs.name[i] for i in range(1, args.multi + 1)) del (erargs.name) ERmain(erargs, seed)
def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) multiargs, _ = parser.parse_known_args() parser = argparse.ArgumentParser() parser.add_argument( '--weights', help= 'Path to the weights file to use for rolling game settings, urls are also valid' ) parser.add_argument( '--samesettings', help='Rolls settings per weights file rather than per player', action='store_true') parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--multi', default=1, type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--names', default='') parser.add_argument('--teams', default=1, type=lambda value: max(int(value), 1)) parser.add_argument('--create_spoiler', action='store_true') parser.add_argument('--rom') parser.add_argument('--enemizercli') parser.add_argument('--outputpath') for player in range(1, multiargs.multi + 1): parser.add_argument(f'--p{player}', help=argparse.SUPPRESS) args = parser.parse_args() if args.seed is None: random.seed(None) seed = random.randint(0, 999999999) else: seed = args.seed random.seed(seed) seedname = f'M{random.randint(0, 999999999)}' print( f"Generating mystery for {args.multi} player{'s' if args.multi > 1 else ''}, {seedname} Seed {seed}" ) weights_cache = {} if args.weights: weights_cache[args.weights] = get_weights(args.weights) print( f"Weights: {args.weights} >> {weights_cache[args.weights]['description']}" ) for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if path: if path not in weights_cache: weights_cache[path] = get_weights(path) print( f"P{player} Weights: {path} >> {weights_cache[path]['description']}" ) erargs = parse_arguments(['--multi', str(args.multi)]) erargs.seed = seed erargs.names = args.names erargs.create_spoiler = args.create_spoiler erargs.race = True erargs.outputname = seedname erargs.outputpath = args.outputpath if args.rom: erargs.rom = args.rom if args.enemizercli: erargs.enemizercli = args.enemizercli settings_cache = { k: (roll_settings(v) if args.samesettings else None) for k, v in weights_cache.items() } for player in range(1, args.multi + 1): path = getattr(args, f'p{player}') if getattr( args, f'p{player}') else args.weights if path: settings = settings_cache[path] if settings_cache[ path] else roll_settings(weights_cache[path]) for k, v in vars(settings).items(): if v is not None: getattr(erargs, k)[player] = v else: raise RuntimeError(f'No weights specified for player {player}') # set up logger loglevel = { 'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG }[erargs.loglevel] logging.basicConfig(format='%(message)s', level=loglevel) ERmain(erargs, seed)