mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-04-19 19:53:35 -07:00
Merge branch 'ArchipelagoMW:main' into Satisfactory
This commit is contained in:
@@ -49,7 +49,6 @@ def setup_multiworld(worlds: Union[List[Type[World]], Type[World]], steps: Tuple
|
||||
multiworld.game = {player: world_type.game for player, world_type in enumerate(worlds, 1)}
|
||||
multiworld.player_name = {player: f"Tester{player}" for player in multiworld.player_ids}
|
||||
multiworld.set_seed(seed)
|
||||
multiworld.state = CollectionState(multiworld)
|
||||
args = Namespace()
|
||||
for player, world_type in enumerate(worlds, 1):
|
||||
for key, option in world_type.options_dataclass.type_hints.items():
|
||||
@@ -57,6 +56,7 @@ def setup_multiworld(worlds: Union[List[Type[World]], Type[World]], steps: Tuple
|
||||
updated_options[player] = option.from_any(option.default)
|
||||
setattr(args, key, updated_options)
|
||||
multiworld.set_options(args)
|
||||
multiworld.state = CollectionState(multiworld)
|
||||
for step in steps:
|
||||
call_all(multiworld, step)
|
||||
return multiworld
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from typing import Callable
|
||||
import unittest
|
||||
from enum import IntEnum
|
||||
|
||||
@@ -34,7 +35,7 @@ def generate_entrance_pair(region: Region, name_suffix: str, group: int):
|
||||
|
||||
|
||||
def generate_disconnected_region_grid(multiworld: MultiWorld, grid_side_length: int, region_size: int = 0,
|
||||
region_type: type[Region] = Region):
|
||||
region_creator: Callable[[str, int, MultiWorld], Region] = Region):
|
||||
"""
|
||||
Generates a grid-like region structure for ER testing, where menu is connected to the top-left region, and each
|
||||
region "in vanilla" has 2 2-way exits going either down or to the right, until reaching the goal region in the
|
||||
@@ -44,7 +45,7 @@ def generate_disconnected_region_grid(multiworld: MultiWorld, grid_side_length:
|
||||
for col in range(grid_side_length):
|
||||
index = row * grid_side_length + col
|
||||
name = f"region{index}"
|
||||
region = region_type(name, 1, multiworld)
|
||||
region = region_creator(name, 1, multiworld)
|
||||
multiworld.regions.append(region)
|
||||
generate_locations(region_size, 1, region=region, tag=f"_{name}")
|
||||
|
||||
@@ -465,7 +466,7 @@ class TestRandomizeEntrances(unittest.TestCase):
|
||||
entrance_type = CustomEntrance
|
||||
|
||||
multiworld = generate_test_multiworld()
|
||||
generate_disconnected_region_grid(multiworld, 5, region_type=CustomRegion)
|
||||
generate_disconnected_region_grid(multiworld, 5, region_creator=CustomRegion)
|
||||
|
||||
self.assertRaises(EntranceRandomizationError, randomize_entrances, multiworld.worlds[1], False,
|
||||
directionally_matched_group_lookup)
|
||||
|
||||
@@ -47,7 +47,20 @@ class TestIDs(unittest.TestCase):
|
||||
"""Test that a game doesn't have item id overlap within its own datapackage"""
|
||||
for gamename, world_type in AutoWorldRegister.world_types.items():
|
||||
with self.subTest(game=gamename):
|
||||
self.assertEqual(len(world_type.item_id_to_name), len(world_type.item_name_to_id))
|
||||
len_item_id_to_name = len(world_type.item_id_to_name)
|
||||
len_item_name_to_id = len(world_type.item_name_to_id)
|
||||
|
||||
if len_item_id_to_name != len_item_name_to_id:
|
||||
self.assertCountEqual(
|
||||
world_type.item_id_to_name.values(),
|
||||
world_type.item_name_to_id.keys(),
|
||||
"\nThese items have overlapping ids with other items in its own world")
|
||||
self.assertCountEqual(
|
||||
world_type.item_id_to_name.keys(),
|
||||
world_type.item_name_to_id.values(),
|
||||
"\nThese items have overlapping names with other items in its own world")
|
||||
|
||||
self.assertEqual(len_item_id_to_name, len_item_name_to_id)
|
||||
|
||||
def test_duplicate_location_ids(self):
|
||||
"""Test that a game doesn't have location id overlap within its own datapackage"""
|
||||
|
||||
@@ -53,6 +53,22 @@ class TestImplemented(unittest.TestCase):
|
||||
if failed_world_loads:
|
||||
self.fail(f"The following worlds failed to load: {failed_world_loads}")
|
||||
|
||||
def test_prefill_items(self):
|
||||
"""Test that every world can reach every location from allstate before pre_fill."""
|
||||
for gamename, world_type in AutoWorldRegister.world_types.items():
|
||||
if gamename not in ("Archipelago", "Sudoku", "Final Fantasy", "Test Game"):
|
||||
with self.subTest(gamename):
|
||||
multiworld = setup_solo_multiworld(world_type, ("generate_early", "create_regions", "create_items",
|
||||
"set_rules", "connect_entrances", "generate_basic"))
|
||||
allstate = multiworld.get_all_state(False)
|
||||
locations = multiworld.get_locations()
|
||||
reachable = multiworld.get_reachable_locations(allstate)
|
||||
unreachable = [location for location in locations if location not in reachable]
|
||||
|
||||
self.assertTrue(not unreachable,
|
||||
f"Locations were not reachable with all state before prefill: "
|
||||
f"{unreachable}. Seed: {multiworld.seed}")
|
||||
|
||||
def test_explicit_indirect_conditions_spheres(self):
|
||||
"""Tests that worlds using explicit indirect conditions produce identical spheres as when using implicit
|
||||
indirect conditions"""
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import unittest
|
||||
from argparse import Namespace
|
||||
from typing import Type
|
||||
|
||||
from BaseClasses import CollectionState
|
||||
from worlds.AutoWorld import AutoWorldRegister, call_all
|
||||
from BaseClasses import CollectionState, MultiWorld
|
||||
from Fill import distribute_items_restrictive
|
||||
from Options import ItemLinks
|
||||
from worlds.AutoWorld import AutoWorldRegister, World, call_all
|
||||
from . import setup_solo_multiworld
|
||||
|
||||
|
||||
@@ -83,6 +87,47 @@ class TestBase(unittest.TestCase):
|
||||
multiworld = setup_solo_multiworld(world_type)
|
||||
for item in multiworld.itempool:
|
||||
self.assertIn(item.name, world_type.item_name_to_id)
|
||||
|
||||
def test_item_links(self) -> None:
|
||||
"""
|
||||
Tests item link creation by creating a multiworld of 2 worlds for every game and linking their items together.
|
||||
"""
|
||||
def setup_link_multiworld(world: Type[World], link_replace: bool) -> None:
|
||||
multiworld = MultiWorld(2)
|
||||
multiworld.game = {1: world.game, 2: world.game}
|
||||
multiworld.player_name = {1: "Linker 1", 2: "Linker 2"}
|
||||
multiworld.set_seed()
|
||||
item_link_group = [{
|
||||
"name": "ItemLinkTest",
|
||||
"item_pool": ["Everything"],
|
||||
"link_replacement": link_replace,
|
||||
"replacement_item": None,
|
||||
}]
|
||||
args = Namespace()
|
||||
for name, option in world.options_dataclass.type_hints.items():
|
||||
setattr(args, name, {1: option.from_any(option.default), 2: option.from_any(option.default)})
|
||||
setattr(args, "item_links",
|
||||
{1: ItemLinks.from_any(item_link_group), 2: ItemLinks.from_any(item_link_group)})
|
||||
multiworld.set_options(args)
|
||||
multiworld.set_item_links()
|
||||
# groups get added to state during its constructor so this has to be after item links are set
|
||||
multiworld.state = CollectionState(multiworld)
|
||||
gen_steps = ("generate_early", "create_regions", "create_items", "set_rules", "connect_entrances", "generate_basic")
|
||||
for step in gen_steps:
|
||||
call_all(multiworld, step)
|
||||
# link the items together and attempt to fill
|
||||
multiworld.link_items()
|
||||
multiworld._all_state = None
|
||||
call_all(multiworld, "pre_fill")
|
||||
distribute_items_restrictive(multiworld)
|
||||
call_all(multiworld, "post_fill")
|
||||
self.assertTrue(multiworld.can_beat_game(CollectionState(multiworld)), f"seed = {multiworld.seed}")
|
||||
|
||||
for game_name, world_type in AutoWorldRegister.world_types.items():
|
||||
with self.subTest("Can generate with link replacement", game=game_name):
|
||||
setup_link_multiworld(world_type, True)
|
||||
with self.subTest("Can generate without link replacement", game=game_name):
|
||||
setup_link_multiworld(world_type, False)
|
||||
|
||||
def test_itempool_not_modified(self):
|
||||
"""Test that worlds don't modify the itempool after `create_items`"""
|
||||
|
||||
@@ -26,4 +26,4 @@ class TestBase(unittest.TestCase):
|
||||
for step in self.test_steps:
|
||||
with self.subTest("Step", step=step):
|
||||
call_all(multiworld, step)
|
||||
self.assertTrue(multiworld.get_all_state(False, True))
|
||||
self.assertTrue(multiworld.get_all_state(False, allow_partial_entrances=True))
|
||||
|
||||
Reference in New Issue
Block a user