diff --git a/Generate.py b/Generate.py index aa43b106..aa826a64 100644 --- a/Generate.py +++ b/Generate.py @@ -426,17 +426,8 @@ def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str, except Exception as e: raise Exception(f"Error generating option {option_key} in {ret.game}") from e else: - # verify item names existing - if getattr(player_option, "verify_item_name", False): - for item_name in player_option.value: - if item_name not in AutoWorldRegister.world_types[ret.game].item_names: - raise Exception(f"Item {item_name} from option {player_option} " - f"is not a valid item name from {ret.game}") - elif getattr(player_option, "verify_location_name", False): - for location_name in player_option.value: - if location_name not in AutoWorldRegister.world_types[ret.game].location_names: - raise Exception(f"Location {location_name} from option {player_option} " - f"is not a valid location name from {ret.game}") + if hasattr(player_option, "verify"): + player_option.verify(AutoWorldRegister.world_types[ret.game]) else: setattr(ret, option_key, option(option.default)) @@ -513,6 +504,7 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b raise Exception(f"Unsupported game {ret.game}") return ret + def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options): if "dungeon_items" in weights and get_choice_legacy('dungeon_items', weights, "none") != "none": raise Exception(f"dungeon_items key in A Link to the Past was removed, but is present in these weights as {get_choice_legacy('dungeon_items', weights, False)}.") diff --git a/Main.py b/Main.py index ac8d1edd..39f98ee8 100644 --- a/Main.py +++ b/Main.py @@ -158,9 +158,6 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No pool = set() for item in item_link["item_pool"]: pool |= current_item_name_groups.get(item, {item}) - unknown_items = pool - AutoWorld.AutoWorldRegister.world_types[item_link["game"]].item_names - if unknown_items: - raise Exception(f"Unknown item in ItemLink({name}): {''.join(unknown_items)}") item_link["item_pool"] = pool for group_name, item_link in item_links.items(): diff --git a/Options.py b/Options.py index fbcf5eea..086428f6 100644 --- a/Options.py +++ b/Options.py @@ -262,26 +262,12 @@ class Range(Option, int): return str(self.value) -class OptionNameSet(Option): - default = frozenset() - - def __init__(self, value: typing.Set[str]): - self.value: typing.Set[str] = value - - @classmethod - def from_text(cls, text: str) -> OptionNameSet: - return cls({option.strip() for option in text.split(",")}) - - @classmethod - def from_any(cls, data: typing.Any) -> OptionNameSet: - if type(data) == set: - return cls(data) - return cls.from_text(str(data)) - - class VerifyKeys: valid_keys = frozenset() valid_keys_casefold: bool = False + verify_item_name = False + verify_location_name = False + value: typing.Any @classmethod def verify_keys(cls, data): @@ -293,6 +279,18 @@ class VerifyKeys: raise Exception(f"Found unexpected key {', '.join(extra)} in {cls}. " f"Allowed keys: {cls.valid_keys}.") + def verify(self, world): + if self.verify_item_name: + for item_name in self.value: + if item_name not in world.item_names: + raise Exception(f"Item {item_name} from option {self} " + f"is not a valid item name from {world.game}") + elif self.verify_location_name: + for location_name in self.value: + if location_name not in world.world_types[world.game].location_names: + raise Exception(f"Location {location_name} from option {self} " + f"is not a valid location name from {world.game}") + class OptionDict(Option, VerifyKeys): default = {} @@ -354,7 +352,7 @@ class OptionList(Option, VerifyKeys): return item in self.value -class OptionSet(Option): +class OptionSet(Option, VerifyKeys): default = frozenset() supports_weighting = False value: set @@ -370,8 +368,10 @@ class OptionSet(Option): @classmethod def from_any(cls, data: typing.Any): if type(data) == list: + cls.verify_keys(data) return cls(data) elif type(data) == set: + cls.verify_keys(data) return cls(data) return cls.from_text(str(data)) @@ -468,6 +468,17 @@ class ItemLinks(OptionList): } ]) + def verify(self, world): + super(ItemLinks, self).verify(world) + for link in self.value: + for item_name in link["item_pool"]: + if item_name not in world.item_names and item_name not in world.item_name_groups: + raise Exception(f"Item {item_name} from option {self} " + f"is not a valid item name from {world.game}") + if link["replacement_item"] not in world.item_names: + raise Exception(f"Item {link['replacement_item']} from option {self} " + f"is not a valid item name from {world.game}") + per_game_common_options = { **common_options, # can be overwritten per-game