diff --git a/Generate.py b/Generate.py index 7cfe7a50..70a8eaf6 100644 --- a/Generate.py +++ b/Generate.py @@ -7,7 +7,7 @@ import urllib.request import urllib.parse from typing import Set, Dict, Tuple, Callable, Any, Union import os -from collections import Counter +from collections import Counter, ChainMap import string import enum @@ -133,12 +133,14 @@ def main(args=None, callback=ERmain): if args.meta_file_path and os.path.exists(args.meta_file_path): try: - weights_cache[args.meta_file_path] = read_weights_yamls(args.meta_file_path) + meta_weights = read_weights_yamls(args.meta_file_path)[-1] except Exception as e: raise ValueError(f"File {args.meta_file_path} is destroyed. Please fix your yaml.") from e - meta_weights = weights_cache[args.meta_file_path][-1] print(f"Meta: {args.meta_file_path} >> {get_choice('meta_description', meta_weights)}") - del(meta_weights["meta_description"]) + try: # meta description allows us to verify that the file named meta.yaml is intentionally a meta file + del(meta_weights["meta_description"]) + except Exception as e: + raise ValueError("No meta description found for meta.yaml. Unable to verify.") from e if args.samesettings: raise Exception("Cannot mix --samesettings with --meta") else: @@ -164,7 +166,7 @@ def main(args=None, callback=ERmain): player_files[player_id] = filename player_id += 1 - args.multi = max(player_id-1, args.multi) + args.multi = max(player_id - 1, args.multi) print(f"Generating for {args.multi} player{'s' if args.multi > 1 else ''}, {seed_name} Seed {seed} with plando: " f"{args.plando}") @@ -186,26 +188,28 @@ def main(args=None, callback=ERmain): erargs.enemizercli = args.enemizercli settings_cache: Dict[str, Tuple[argparse.Namespace, ...]] = \ - {fname: ( tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.samesettings else None) - for fname, yamls in weights_cache.items()} - player_path_cache = {} - for player in range(1, args.multi + 1): - player_path_cache[player] = player_files.get(player, args.weights_file_path) + {fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.samesettings else None) + for fname, yamls in weights_cache.items()} if meta_weights: for category_name, category_dict in meta_weights.items(): for key in category_dict: - option = get_choice(key, category_dict) + option = roll_meta_option(key, category_name, category_dict) if option is not None: - for player, path in player_path_cache.items(): + for path in weights_cache: for yaml in weights_cache[path]: if category_name is None: - yaml[key] = option + for category in yaml: + if category in AutoWorldRegister.world_types and key in Options.common_options: + yaml[category][key] = option elif category_name not in yaml: logging.warning(f"Meta: Category {category_name} is not present in {path}.") else: - yaml[category_name][key] = option + yaml[category_name][key] = option + player_path_cache = {} + for player in range(1, args.multi + 1): + player_path_cache[player] = player_files.get(player, args.weights_file_path) name_counter = Counter() erargs.player_settings = {} @@ -387,6 +391,28 @@ def update_weights(weights: dict, new_weights: dict, type: str, name: str) -> di return weights +def roll_meta_option(option_key, game: str, category_dict: Dict) -> Any: + if not game: + return get_choice(option_key, category_dict) + if game in AutoWorldRegister.world_types: + game_world = AutoWorldRegister.world_types[game] + options = ChainMap(game_world.options, Options.per_game_common_options) + if option_key in options: + if options[option_key].supports_weighting: + return get_choice(option_key, category_dict) + return options[option_key] + if game == "A Link to the Past": # TODO wow i hate this + if option_key in {"glitches_required", "dark_room_logic", "entrance_shuffle", "goals", "triforce_pieces_mode", + "triforce_pieces_percentage", "triforce_pieces_available", "triforce_pieces_extra", + "triforce_pieces_required", "shop_shuffle", "mode", "item_pool", "item_functionality", + "boss_shuffle", "enemy_damage", "enemy_health", "timer", "countdown_start_time", + "red_clock_time", "blue_clock_time", "green_clock_time", "dungeon_counters", "shuffle_prizes", + "misery_mire_medallion", "turtle_rock_medallion", "sprite_pool", "sprite", + "random_sprite_on_event"}: + return get_choice(option_key, category_dict) + raise Exception(f"Error generating meta option {option_key} for {game}.") + + def roll_linked_options(weights: dict) -> dict: weights = copy.deepcopy(weights) # make sure we don't write back to other weights sets in same_settings for option_set in weights["linked_options"]: