diff --git a/docs/world api.md b/docs/world api.md index fe4a6300..87eace89 100644 --- a/docs/world api.md +++ b/docs/world api.md @@ -433,7 +433,7 @@ In addition, the following methods can be implemented and attributes can be set * `required_client_version: Tuple(int, int, int)` Client version as tuple of 3 ints to make sure the client is compatible to this world (e.g. implements all required features) when connecting. -* `assert_generate(cls, world)` is a class method called at the start of +* `stage_assert_generate(cls, multiworld)` is a class method called at the start of generation to check the existence of prerequisite files, usually a ROM for games which require one. diff --git a/test/general/TestImplemented.py b/test/general/TestImplemented.py index b504470b..66a09981 100644 --- a/test/general/TestImplemented.py +++ b/test/general/TestImplemented.py @@ -22,3 +22,12 @@ class TestImplemented(unittest.TestCase): for region in multiworld.regions: for exit in region.exits: self.assertEqual(exit.parent_region, region) + + def testStageMethods(self): + """Tests that worlds don't try to implement certain steps that are only ever called as stage.""" + for game_name, world_type in AutoWorldRegister.world_types.items(): + if not world_type.hidden: + with self.subTest(game_name): + for method in ("assert_generate",): + self.assertFalse(hasattr(world_type, method), + f"{method} must be implemented as a @classmethod named stage_{method}.") diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index d7547a3a..7985d470 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -188,10 +188,11 @@ class World(metaclass=AutoWorldRegister): # can also be implemented as a classmethod and called "stage_", # in that case the MultiWorld object is passed as an argument and it gets called once for the entire multiworld. # An example of this can be found in alttp as stage_pre_fill + @classmethod - def assert_generate(cls) -> None: + def stage_assert_generate(cls, multiworld: "MultiWorld") -> None: """Checks that a game is capable of generating, usually checks for some base file like a ROM. - Not run for unittests since they don't produce output""" + This gets called once per present world type. Not run for unittests since they don't produce output""" pass def generate_early(self) -> None: @@ -213,14 +214,12 @@ class World(metaclass=AutoWorldRegister): """Optional method that is supposed to be used for special fill stages. This is run *after* plando.""" pass - @classmethod - def fill_hook(cls, + def fill_hook(self, progitempool: List["Item"], usefulitempool: List["Item"], filleritempool: List["Item"], fill_locations: List["Location"]) -> None: - """Special method that gets called as part of distribute_items_restrictive (main fill). - This gets called once per present world type.""" + """Special method that gets called as part of distribute_items_restrictive (main fill).""" pass def post_fill(self) -> None: diff --git a/worlds/bk_sudoku/__init__.py b/worlds/bk_sudoku/__init__.py index fe7fe174..4b0f0fb4 100644 --- a/worlds/bk_sudoku/__init__.py +++ b/worlds/bk_sudoku/__init__.py @@ -29,5 +29,5 @@ class Bk_SudokuWorld(World): location_name_to_id: Dict[str, int] = {} @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld): raise Exception("BK Sudoku cannot be used for generating worlds, the client can instead connect to any other world") diff --git a/worlds/dkc3/__init__.py b/worlds/dkc3/__init__.py index f877935c..4b54d67e 100644 --- a/worlds/dkc3/__init__.py +++ b/worlds/dkc3/__init__.py @@ -55,7 +55,7 @@ class DKC3World(World): super().__init__(world, player) @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld: MultiWorld): rom_file = get_base_rom_path() if not os.path.exists(rom_file): raise FileNotFoundError(rom_file) diff --git a/worlds/lufia2ac/__init__.py b/worlds/lufia2ac/__init__.py index da1516c0..e54f8428 100644 --- a/worlds/lufia2ac/__init__.py +++ b/worlds/lufia2ac/__init__.py @@ -80,7 +80,7 @@ class L2ACWorld(World): shuffle_party_members: Optional[ShufflePartyMembers] @classmethod - def stage_assert_generate(cls, _multiworld: MultiWorld) -> None: + def stage_assert_generate(cls, multiworld: MultiWorld) -> None: rom_file: str = get_base_rom_path() if not os.path.exists(rom_file): raise FileNotFoundError(f"Could not find base ROM for {cls.game}: {rom_file}") diff --git a/worlds/oot/__init__.py b/worlds/oot/__init__.py index bcf29f3a..20b3ccb0 100644 --- a/worlds/oot/__init__.py +++ b/worlds/oot/__init__.py @@ -140,7 +140,7 @@ class OOTWorld(World): super(OOTWorld, self).__init__(world, player) @classmethod - def stage_assert_generate(cls, world: MultiWorld): + def stage_assert_generate(cls, multiworld: MultiWorld): rom = Rom(file=get_options()['oot_options']['rom_file']) def generate_early(self): diff --git a/worlds/pokemon_rb/__init__.py b/worlds/pokemon_rb/__init__.py index 90c782b5..abe30922 100644 --- a/worlds/pokemon_rb/__init__.py +++ b/worlds/pokemon_rb/__init__.py @@ -65,11 +65,11 @@ class PokemonRedBlueWorld(World): self.traps = None @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld: MultiWorld): versions = set() - for player in world.player_ids: - if world.worlds[player].game == "Pokemon Red and Blue": - versions.add(world.game_version[player].current_key) + for player in multiworld.player_ids: + if multiworld.worlds[player].game == "Pokemon Red and Blue": + versions.add(multiworld.game_version[player].current_key) for version in versions: if not os.path.exists(get_base_rom_path(version)): raise FileNotFoundError(get_base_rom_path(version)) diff --git a/worlds/sm/__init__.py b/worlds/sm/__init__.py index e6324c6c..43edf35c 100644 --- a/worlds/sm/__init__.py +++ b/worlds/sm/__init__.py @@ -107,7 +107,7 @@ class SMWorld(World): super().__init__(world, player) @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld: MultiWorld): rom_file = get_base_rom_path() if not os.path.exists(rom_file): raise FileNotFoundError(rom_file) diff --git a/worlds/smw/__init__.py b/worlds/smw/__init__.py index 73d6d58d..6365bd11 100644 --- a/worlds/smw/__init__.py +++ b/worlds/smw/__init__.py @@ -55,7 +55,7 @@ class SMWWorld(World): super().__init__(world, player) @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld: MultiWorld): rom_file = get_base_rom_path() if not os.path.exists(rom_file): raise FileNotFoundError(rom_file) diff --git a/worlds/smz3/__init__.py b/worlds/smz3/__init__.py index 08a23577..93ac7fbd 100644 --- a/worlds/smz3/__init__.py +++ b/worlds/smz3/__init__.py @@ -181,7 +181,7 @@ class SMZ3World(World): return itemType in progressionTypes @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld: MultiWorld): base_combined_rom = get_base_rom_bytes() def generate_early(self): diff --git a/worlds/soe/__init__.py b/worlds/soe/__init__.py index f87e0c3e..20f18d1a 100644 --- a/worlds/soe/__init__.py +++ b/worlds/soe/__init__.py @@ -201,7 +201,7 @@ class SoEWorld(World): return SoEItem(item.name, classification, self.item_name_to_id[item.name], self.player) @classmethod - def stage_assert_generate(cls, world): + def stage_assert_generate(cls, multiworld): rom_file = get_base_rom_path() if not os.path.exists(rom_file): raise FileNotFoundError(rom_file) diff --git a/worlds/zillion/__init__.py b/worlds/zillion/__init__.py index bc3c9c03..44d80cff 100644 --- a/worlds/zillion/__init__.py +++ b/worlds/zillion/__init__.py @@ -108,7 +108,7 @@ class ZillionWorld(World): self.id_to_zz_item = id_to_zz_item @classmethod - def stage_assert_generate(cls, world: MultiWorld) -> None: + def stage_assert_generate(cls, multiworld: MultiWorld) -> None: """Checks that a game is capable of generating, usually checks for some base file like a ROM. Not run for unittests since they don't produce output""" rom_file = get_base_rom_path()