From b01091f3012ae699afccf579627e171cc492c6a6 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Sun, 15 Jan 2023 15:04:23 -0600 Subject: [PATCH 1/9] throw an error for unknown options --- Generate.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Generate.py b/Generate.py index d7fe965dfe20..28362b50b9ff 100644 --- a/Generate.py +++ b/Generate.py @@ -473,7 +473,9 @@ def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings handle_option(ret, game_weights, option_key, option, plando_options) if PlandoSettings.items in plando_options: ret.plando_items = game_weights.get("plando_items", []) - if ret.game == "Minecraft" or ret.game == "Ocarina of Time": + if ret.game == "A Link to the Past": + roll_alttp_settings(ret, game_weights, plando_options) + else: # bad hardcoded behavior to make this work for now ret.plando_connections = [] if PlandoSettings.connections in plando_options: @@ -485,8 +487,11 @@ def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings get_choice("exit", placement), get_choice("direction", placement) )) - elif ret.game == "A Link to the Past": - roll_alttp_settings(ret, game_weights, plando_options) + for option_key in game_weights: + if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, + world_type.option_definitions)\ + and option_key not in {"plando_connections", "plando_items", "plando_texts"}: + raise Exception(f"Unsupported option {option_key} for game {ret.game}") else: raise Exception(f"Unsupported game {ret.game}") From 61f0e09b78ed42dea264de50fa25350675ae8bf8 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Sun, 15 Jan 2023 15:24:58 -0600 Subject: [PATCH 2/9] move the error to the end of trigger resolution and make trigger names valid --- Generate.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Generate.py b/Generate.py index 28362b50b9ff..437de24f665b 100644 --- a/Generate.py +++ b/Generate.py @@ -11,6 +11,7 @@ from typing import Dict, Tuple, Callable, Any, Union import ModuleUpdate +import worlds.AutoWorld ModuleUpdate.update() @@ -381,6 +382,7 @@ def roll_linked_options(weights: dict) -> dict: def roll_triggers(weights: dict, triggers: list) -> dict: weights = copy.deepcopy(weights) # make sure we don't write back to other weights sets in same_settings weights["_Generator_Version"] = Utils.__version__ + valid_keys = set() for i, option_set in enumerate(triggers): try: currently_targeted_weights = weights @@ -401,10 +403,26 @@ def roll_triggers(weights: dict, triggers: list) -> dict: if category_name: currently_targeted_weights = currently_targeted_weights[category_name] update_weights(currently_targeted_weights, category_options, "Triggered", option_set["option_name"]) - + valid_keys.add(key) except Exception as e: raise ValueError(f"Your trigger number {i + 1} is destroyed. " f"Please fix your triggers.") from e + if isinstance(weights["game"], dict): + for game in weights["game"]: + game_weights = weights[game] + for option_key in game_weights: + if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, + AutoWorldRegister.world_types[game].option_definitions)\ + and option_key not in {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}: + raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") + pass + else: + game = weights["game"] + for option_key in weights[game]: + if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, + AutoWorldRegister.world_types[game].option_definitions)\ + and option_key not in {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}: + raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") return weights @@ -487,11 +505,6 @@ def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings get_choice("exit", placement), get_choice("direction", placement) )) - for option_key in game_weights: - if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, - world_type.option_definitions)\ - and option_key not in {"plando_connections", "plando_items", "plando_texts"}: - raise Exception(f"Unsupported option {option_key} for game {ret.game}") else: raise Exception(f"Unsupported game {ret.game}") From 04df591d5a061e6fff9dfb49f36a6022eee5f166 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Sun, 15 Jan 2023 15:30:33 -0600 Subject: [PATCH 3/9] add bad hardcoded stuff for LTTP --- Generate.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Generate.py b/Generate.py index 437de24f665b..da2225a22a70 100644 --- a/Generate.py +++ b/Generate.py @@ -409,6 +409,8 @@ def roll_triggers(weights: dict, triggers: list) -> dict: f"Please fix your triggers.") from e if isinstance(weights["game"], dict): for game in weights["game"]: + if game == "A Link to the Past": # TODO remove when LTTP doesn't have to be coded around + continue game_weights = weights[game] for option_key in game_weights: if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, @@ -418,11 +420,12 @@ def roll_triggers(weights: dict, triggers: list) -> dict: pass else: game = weights["game"] - for option_key in weights[game]: - if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, - AutoWorldRegister.world_types[game].option_definitions)\ - and option_key not in {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}: - raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") + if game != "A Link to the Past": # TODO remove when LTTP doesn't have to be coded around + for option_key in weights[game]: + if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, + AutoWorldRegister.world_types[game].option_definitions)\ + and option_key not in {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}: + raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") return weights From b15bdb4530b102b7fa15021f5dd8226ab56ca8d0 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Mon, 16 Jan 2023 16:30:24 -0600 Subject: [PATCH 4/9] use itertools.chain instead of a ChainMap --- Generate.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Generate.py b/Generate.py index da2225a22a70..f56ec1e7f672 100644 --- a/Generate.py +++ b/Generate.py @@ -8,6 +8,7 @@ import urllib.parse import urllib.request from collections import Counter, ChainMap +from itertools import chain from typing import Dict, Tuple, Callable, Any, Union import ModuleUpdate @@ -413,18 +414,19 @@ def roll_triggers(weights: dict, triggers: list) -> dict: continue game_weights = weights[game] for option_key in game_weights: - if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, - AutoWorldRegister.world_types[game].option_definitions)\ - and option_key not in {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}: + if option_key not in chain(Options.common_options, Options.per_game_common_options, + AutoWorldRegister.world_types[game].option_definitions, + {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}): raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") pass else: game = weights["game"] if game != "A Link to the Past": # TODO remove when LTTP doesn't have to be coded around for option_key in weights[game]: - if option_key not in ChainMap(Options.common_options, Options.per_game_common_options, - AutoWorldRegister.world_types[game].option_definitions)\ - and option_key not in {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}: + if option_key not in chain(Options.common_options, Options.per_game_common_options, + AutoWorldRegister.world_types[game].option_definitions, + {*valid_keys, "plando_connections", "plando_items", "plando_texts", + "triggers"}): raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") return weights From 740a96edcf190539e24767e678f334210288d150 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Thu, 26 Jan 2023 20:42:43 -0600 Subject: [PATCH 5/9] remove accidental unused import --- Generate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Generate.py b/Generate.py index f56ec1e7f672..31ed95466ef0 100644 --- a/Generate.py +++ b/Generate.py @@ -12,7 +12,6 @@ from typing import Dict, Tuple, Callable, Any, Union import ModuleUpdate -import worlds.AutoWorld ModuleUpdate.update() From ebc1c224bc40401e85dec0e14a1c5a4fdbb557b0 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Mon, 30 Jan 2023 19:11:39 -0600 Subject: [PATCH 6/9] make the check after both trigger resolutions so no valid keys are missed, and only check relevant game. --- Generate.py | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/Generate.py b/Generate.py index a5dd8f9dc27f..82e25a1ed09e 100644 --- a/Generate.py +++ b/Generate.py @@ -379,10 +379,9 @@ def roll_linked_options(weights: dict) -> dict: return weights -def roll_triggers(weights: dict, triggers: list) -> dict: +def roll_triggers(weights: dict, triggers: list, valid_keys: set) -> dict: weights = copy.deepcopy(weights) # make sure we don't write back to other weights sets in same_settings weights["_Generator_Version"] = Utils.__version__ - valid_keys = set() for i, option_set in enumerate(triggers): try: currently_targeted_weights = weights @@ -407,26 +406,6 @@ def roll_triggers(weights: dict, triggers: list) -> dict: except Exception as e: raise ValueError(f"Your trigger number {i + 1} is destroyed. " f"Please fix your triggers.") from e - if isinstance(weights["game"], dict): - for game in weights["game"]: - if game == "A Link to the Past": # TODO remove when LTTP doesn't have to be coded around - continue - game_weights = weights[game] - for option_key in game_weights: - if option_key not in chain(Options.common_options, Options.per_game_common_options, - AutoWorldRegister.world_types[game].option_definitions, - {*valid_keys, "plando_connections", "plando_items", "plando_texts", "triggers"}): - raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") - pass - else: - game = weights["game"] - if game != "A Link to the Past": # TODO remove when LTTP doesn't have to be coded around - for option_key in weights[game]: - if option_key not in chain(Options.common_options, Options.per_game_common_options, - AutoWorldRegister.world_types[game].option_definitions, - {*valid_keys, "plando_connections", "plando_items", "plando_texts", - "triggers"}): - raise ValueError(f"{option_key} not a valid option name for {game} and not present in triggers") return weights @@ -450,8 +429,9 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b if "linked_options" in weights: weights = roll_linked_options(weights) + valid_trigger_names = set() if "triggers" in weights: - weights = roll_triggers(weights, weights["triggers"]) + weights = roll_triggers(weights, weights["triggers"], valid_trigger_names) requirements = weights.get("requires", {}) if requirements: @@ -478,9 +458,16 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b game_weights = weights[ret.game] if "triggers" in game_weights: - weights = roll_triggers(weights, game_weights["triggers"]) + weights = roll_triggers(weights, game_weights["triggers"], valid_trigger_names) game_weights = weights[ret.game] + if ret.game != "A Link to the Past": # TODO rip out LTTP behavior + for option_key in weights[ret.game]: + if option_key not in chain(Options.common_options, Options.per_game_common_options, + AutoWorldRegister.world_types[ret.game].option_definitions, + {*valid_trigger_names, "plando_connections", "plando_items", "plando_texts", "triggers"}): + raise ValueError(f"{option_key} not a valid option name for {ret.game} and not present in triggers") + ret.name = get_choice('name', weights) for option_key, option in Options.common_options.items(): setattr(ret, option_key, option.from_any(get_choice(option_key, weights, option.default))) From 8ff1123221d49937b302542cd5e5090185713e81 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Sun, 5 Mar 2023 11:54:01 -0600 Subject: [PATCH 7/9] log a warning instead of crashing --- Generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generate.py b/Generate.py index e87be250da38..181e41226c51 100644 --- a/Generate.py +++ b/Generate.py @@ -466,7 +466,7 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b if option_key not in chain(Options.common_options, Options.per_game_common_options, AutoWorldRegister.world_types[ret.game].option_definitions, {*valid_trigger_names, "plando_connections", "plando_items", "plando_texts", "triggers"}): - raise ValueError(f"{option_key} not a valid option name for {ret.game} and not present in triggers") + logging.warning(f"{option_key} not a valid option name for {ret.game} and not present in triggers") ret.name = get_choice('name', weights) for option_key, option in Options.common_options.items(): From d0b0688f274c26f6abb8eb485a751b435a4305c7 Mon Sep 17 00:00:00 2001 From: alwaysintreble Date: Tue, 2 Apr 2024 11:12:02 -0500 Subject: [PATCH 8/9] delete options from the weights once it gets registered for cleaner erroring --- Generate.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Generate.py b/Generate.py index 36e24c226608..0299be455403 100644 --- a/Generate.py +++ b/Generate.py @@ -429,6 +429,7 @@ def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str, raise Exception(f"Error generating option {option_key} in {ret.game}") from e else: player_option.verify(AutoWorldRegister.world_types[ret.game], ret.name, plando_options) + del game_weights[option_key] else: setattr(ret, option_key, option.from_any(option.default)) # call the from_any here to support default "random" @@ -488,6 +489,10 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b for option_key, option in world_type.options_dataclass.type_hints.items(): handle_option(ret, game_weights, option_key, option, plando_options) + for option_key in game_weights: + if option_key in {"triggers", *valid_trigger_names}: + continue + logging.warning(f"{option_key} not a valid option name for {ret.game} and not present in triggers.") if PlandoOptions.items in plando_options: ret.plando_items = game_weights.get("plando_items", []) if ret.game == "A Link to the Past": From ae21745f672bd0c558c259889f317b6f26e78ae9 Mon Sep 17 00:00:00 2001 From: Aaron Wagener Date: Fri, 26 Apr 2024 14:29:07 -0500 Subject: [PATCH 9/9] grammar hard Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --- Generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generate.py b/Generate.py index 0299be455403..146e5e399836 100644 --- a/Generate.py +++ b/Generate.py @@ -492,7 +492,7 @@ def roll_settings(weights: dict, plando_options: PlandoOptions = PlandoOptions.b for option_key in game_weights: if option_key in {"triggers", *valid_trigger_names}: continue - logging.warning(f"{option_key} not a valid option name for {ret.game} and not present in triggers.") + logging.warning(f"{option_key} is not a valid option name for {ret.game} and is not present in triggers.") if PlandoOptions.items in plando_options: ret.plando_items = game_weights.get("plando_items", []) if ret.game == "A Link to the Past":