def test_edit_layout_trick_level(option: Options, initial_layout_configuration_params: dict, new_trick_level: LayoutTrickLevel): # Setup option._layout_configuration = LayoutConfiguration.from_params(**initial_layout_configuration_params) option._nested_autosave_level = 1 # Run initial_layout_configuration_params["trick_level"] = new_trick_level setattr(option, "layout_configuration_trick_level", new_trick_level) # Assert assert option.layout_configuration == LayoutConfiguration.from_params(**initial_layout_configuration_params)
def test_edit_layout_quantity(option: Options, initial_layout_configuration_params: dict): # Setup option._layout_configuration = LayoutConfiguration.from_params(**initial_layout_configuration_params) option._nested_autosave_level = 1 pickup = next(option._layout_configuration.pickup_quantities.pickups()) # Run initial_layout_configuration_params["pickup_quantities"] = {pickup.name: 12} option.set_quantity_for_pickup(pickup, 12) # Assert assert option.layout_configuration == LayoutConfiguration.from_params(**initial_layout_configuration_params)
def _layout_config_with_data(request): trick_config = DummyValue() starting_location = DummyValue() randomization_mode = DummyValue() major_items = DummyValue() ammo_config = DummyValue() translator_config = DummyValue() hints = DummyValue() with patch.multiple(TrickLevelConfiguration, bit_pack_unpack=MagicMock(return_value=trick_config)), \ patch.multiple(StartingLocation, bit_pack_unpack=MagicMock(return_value=starting_location)), \ patch.multiple(RandomizationMode, bit_pack_unpack=MagicMock(return_value=randomization_mode)), \ patch.multiple(MajorItemsConfiguration, bit_pack_unpack=MagicMock(return_value=major_items)), \ patch.multiple(AmmoConfiguration, bit_pack_unpack=MagicMock(return_value=ammo_config)), \ patch.multiple(TranslatorConfiguration, bit_pack_unpack=MagicMock(return_value=translator_config)), \ patch.multiple(HintConfiguration, bit_pack_unpack=MagicMock(return_value=hints)): yield request.param["encoded"], LayoutConfiguration.from_params( trick_level_configuration=trick_config, sky_temple_keys=request.param["sky_temple"], elevators=request.param["elevators"], starting_location=starting_location, randomization_mode=randomization_mode, major_items_configuration=major_items, ammo_configuration=ammo_config, translator_configuration=translator_config, hints=hints, )
def test_distribute_command_logic(mock_generate_list: MagicMock, ): # Setup args = MagicMock() args.trick_level = LayoutTrickLevel.HARD.value args.major_items_mode = False args.sky_temple_keys = LayoutSkyTempleKeyMode.ALL_BOSSES.value args.skip_item_loss = True args.seed = 15000 args.output_file = "asdfasdf/qwerqwerqwer/zxcvzxcv.json" # Run echoes.distribute_command_logic(args) # Assert mock_generate_list.assert_called_once_with(permalink=Permalink( seed_number=args.seed, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.HARD, sky_temple_keys=LayoutSkyTempleKeyMode.ALL_BOSSES, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_non_custom_configuration( StartingResourcesConfiguration.VANILLA_ITEM_LOSS_DISABLED), ), ), status_update=ANY) save_file_mock: MagicMock = mock_generate_list.return_value.save_to_file save_file_mock.assert_called_once_with(Path(args.output_file))
def test_create_permalink_logic(mock_print: MagicMock, ): # Setup args = MagicMock() args.trick_level = LayoutTrickLevel.HARD.value args.major_items_mode = False args.sky_temple_keys = LayoutSkyTempleKeyMode.ALL_BOSSES.value args.skip_item_loss = True args.seed = 15000 args.menu_mod = False args.warp_to_start = False # Run randovania.cli.commands.create_permalink.create_permalink_logic(args) # Assert permalink = Permalink( seed_number=args.seed, spoiler=True, patcher_configuration=PatcherConfiguration( menu_mod=args.menu_mod, warp_to_start=args.warp_to_start, ), layout_configuration=LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HARD), sky_temple_keys=LayoutSkyTempleKeyMode.ALL_BOSSES, elevators=LayoutElevators.VANILLA, starting_location=StartingLocation.default(), ), ) # Assert mock_print.assert_called_once_with(permalink)
def test_add_elevator_connections_to_patches_random(echoes_game_data): # Setup game = data_reader.decode_data(echoes_game_data) permalink = dataclasses.replace(Permalink.default(), layout_configuration=dataclasses.replace( LayoutConfiguration.default(), elevators=LayoutElevators.RANDOMIZED)) expected = dataclasses.replace(GamePatches.with_game(game), elevator_connection={ 589851: AreaLocation(1039999561, 1868895730), 1572998: AreaLocation(1039999561, 3479543630), 1966093: AreaLocation(2252328306, 408633584), 2097251: AreaLocation(1119434212, 3331021649), 136970379: AreaLocation(2252328306, 2068511343), 3342446: AreaLocation(1039999561, 3205424168), 3538975: AreaLocation(1119434212, 2806956034), 152: AreaLocation(1006255871, 2889020216), 393260: AreaLocation(464164546, 3145160350), 524321: AreaLocation(464164546, 900285955), 589949: AreaLocation(1006255871, 2278776548), 122: AreaLocation(464164546, 3528156989), 1245307: AreaLocation(1006255871, 1345979968), 2949235: AreaLocation(1006255871, 1287880522), 129: AreaLocation(1006255871, 2918020398), 2162826: AreaLocation(1006255871, 1660916974), 4522032: AreaLocation(1006255871, 3455543403), 38: AreaLocation(1119434212, 1473133138), 1245332: AreaLocation(2252328306, 2399252740), 1638535: AreaLocation(2252328306, 2556480432), }) # Run result = base_patches_factory.add_elevator_connections_to_patches( permalink.layout_configuration, Random(permalink.seed_number), GamePatches.with_game(game), ) # Assert assert result == expected
def test_decode(mock_dictionary_byte_hash: MagicMock): mock_dictionary_byte_hash.return_value = 120 # We're mocking the database hash to avoid breaking tests every single time we change the database # This test should break whenever we change how permalinks are created # When this happens, we must bump the permalink version and change the tests encoded = "gAAAfReLCAAC4wAAAOaANg==" expected = Permalink( seed_number=1000, spoiler=True, patcher_configuration=PatcherConfiguration( menu_mod=True, warp_to_start=False, ), layout_configuration=LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HARD), elevators=LayoutElevators.RANDOMIZED, ), ) # Uncomment this line to quickly get the new encoded permalink # assert expected.as_str == "" # print(expected.as_str) # Run link = Permalink.from_str(encoded) # Assert assert link == expected
def test_run_filler(mock_retcon_playthrough_filler: MagicMock, echoes_game_description, pickup ): # Setup configuration = LayoutConfiguration.default() rng = Random(5000) status_update = MagicMock() item_pool = [pickup] patches = GamePatches.with_game(echoes_game_description) logbook_nodes = [node for node in echoes_game_description.world_list.all_nodes if isinstance(node, LogbookNode)] mock_retcon_playthrough_filler.return_value = patches.assign_hint( logbook_nodes[0].resource(), Hint(HintType.LOCATION, None, PickupIndex(0)) ).assign_pickup_assignment({PickupIndex(1): pickup}) # Run result_patches, remaining_items = runner.run_filler(configuration, echoes_game_description, item_pool, patches, rng, status_update) # Assert assert len(result_patches.hints) == len(logbook_nodes) assert [hint for hint in patches.hints.values() if hint.item_precision is None or hint.location_precision is None] == [] assert remaining_items == [pickup]
def _decode_preset(decoder: BitPackDecoder, manager: PresetManager) -> Preset: included_presets = [versioned.get_preset() for versioned in manager.included_presets] is_custom_preset = bitpacking.decode_bool(decoder) reference_preset = decoder.decode_element(included_presets) if is_custom_preset: patcher_configuration = PatcherConfiguration.bit_pack_unpack( decoder, {"reference": reference_preset.patcher_configuration}) layout_configuration = LayoutConfiguration.bit_pack_unpack( decoder, {"reference": reference_preset.layout_configuration}) preset = Preset( name="{} Custom".format(reference_preset.name), description="A customized preset.", base_preset_name=reference_preset.name, patcher_configuration=patcher_configuration, layout_configuration=layout_configuration, ) else: preset = reference_preset included_data_hash = decoder.decode_single(256) expected_data_hash = _dictionary_byte_hash(preset.layout_configuration.game_data) if included_data_hash != expected_data_hash: raise ValueError("Given permalink is for a Randovania database with hash '{}', " "but current database has hash '{}'.".format(included_data_hash, expected_data_hash)) return preset
def test_round_trip_generated_patches(echoes_game_data): # Setup configuration = LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( global_level=LayoutTrickLevel.MINIMAL_RESTRICTIONS, specific_levels={}, )) patches = generator._create_randomized_patches( permalink=Permalink( seed_number=1000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ), game=data_reader.decode_data(echoes_game_data), status_update=lambda x: None, ) # Run encoded = game_patches_serializer.serialize(patches, echoes_game_data) decoded = game_patches_serializer.decode(encoded, configuration) # Assert assert patches == decoded
def default(cls) -> "Permalink": return Permalink( seed_number=0, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=LayoutConfiguration.default(), )
def test_edit_layout_trick_level(option: Options, initial_layout_configuration_params: dict, new_trick_level: LayoutTrickLevel): # Setup option._layout_configuration = LayoutConfiguration.from_params( **initial_layout_configuration_params) option._nested_autosave_level = 1 # Run initial_layout_configuration_params[ "trick_level_configuration"] = TrickLevelConfiguration(new_trick_level) option.set_layout_configuration_field( "trick_level_configuration", TrickLevelConfiguration(new_trick_level)) # Assert assert option.layout_configuration == LayoutConfiguration.from_params( **initial_layout_configuration_params)
def test_decode(patches_with_data): encoded, expected = patches_with_data # Run decoded = game_patches_serializer.decode(encoded, LayoutConfiguration.default()) # Assert assert decoded == expected
def from_json_dict(cls, param: dict) -> "Permalink": return Permalink( seed_number=param["seed"], spoiler=param["spoiler"], patcher_configuration=PatcherConfiguration.from_json_dict( param["patcher_configuration"]), layout_configuration=LayoutConfiguration.from_json_dict( param["layout_configuration"]), )
def get_layout_configuration_from_args(args) -> LayoutConfiguration: return LayoutConfiguration.from_params( trick_level=LayoutTrickLevel(args.trick_level), sky_temple_keys=LayoutSkyTempleKeyMode(args.sky_temple_keys), elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_item_loss( not args.skip_item_loss), )
def test_decode(layout_config_with_data): # Setup data, expected = layout_config_with_data # Run decoder = BitPackDecoder(data) result = LayoutConfiguration.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def from_json_dict(cls, value) -> "Preset": return Preset( name=value["name"], description=value["description"], base_preset_name=value["base_preset_name"], patcher_configuration=PatcherConfiguration.from_json_dict( value["patcher_configuration"]), layout_configuration=LayoutConfiguration.from_json_dict( value["layout_configuration"]), )
def test_create_patches( mock_random: MagicMock, mock_calculate_item_pool: MagicMock, mock_create_base_patches: MagicMock, mock_retcon_playthrough_filler: MagicMock, mock_indices_for_unassigned_pickups: MagicMock, ): # Setup seed_number: int = 91319 game = default_prime2_game_description() status_update: Union[MagicMock, Callable[[str], None]] = MagicMock() configuration = LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.from_item_loss(False), ) permalink = Permalink( seed_number=seed_number, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) mock_calculate_item_pool.return_value = list( sorted(game.pickup_database.original_pickup_mapping.values())) mock_create_base_patches.return_value.starting_location = game.starting_location mock_create_base_patches.return_value.custom_initial_items = None filler_patches = mock_retcon_playthrough_filler.return_value # Run result = generator._create_patches(permalink, game, status_update) # Assert mock_random.assert_called_once_with(permalink.as_str) mock_calculate_item_pool.assert_called_once_with(permalink, game) mock_create_base_patches.assert_called_once_with(mock_random.return_value, game, permalink, ANY) mock_retcon_playthrough_filler.assert_called_once_with( ANY, ANY, ANY, mock_random.return_value, status_update) mock_indices_for_unassigned_pickups.assert_called_once_with( mock_random.return_value, game, filler_patches.pickup_assignment, ANY) filler_patches.assign_new_pickups.assert_called_once_with( mock_indices_for_unassigned_pickups.return_value) assert result == filler_patches.assign_new_pickups.return_value
def get_layout_configuration_from_args(args) -> LayoutConfiguration: try: sky_temple_keys = int(args.sky_temple_keys) except ValueError: sky_temple_keys = args.sky_temple_keys # TODO: support for item loss return LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel(args.trick_level)), sky_temple_keys=LayoutSkyTempleKeyMode(sky_temple_keys), elevators=LayoutElevators.VANILLA, starting_location=StartingLocation.default(), )
def test_create_pickup_all_from_pool(echoes_resource_database, disable_hud_popup: bool ): layout_configuration = LayoutConfiguration.from_params() item_pool = pool_creator.calculate_pool_results(layout_configuration, echoes_resource_database)[0] index = PickupIndex(0) if disable_hud_popup: memo_data = None else: memo_data = default_prime2_memo_data() for item in item_pool: try: patcher_file._create_pickup(index, item, item, PickupModelStyle.ALL_VISIBLE, memo_data) except Exception as e: assert str(e) == item.name
def test_encode(mock_dictionary_byte_hash: MagicMock): # Setup mock_dictionary_byte_hash.return_value = 120 link = Permalink( seed_number=1000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=LayoutConfiguration.default(), ) # Run encoded = link.as_str # Assert mock_dictionary_byte_hash.assert_called_once_with( link.layout_configuration.game_data) assert encoded == "MAAAfReMYADv"
def _test_data(): data = default_data.decode_default_prime2() game = data_reader.decode_data(data) configuration = LayoutConfiguration.from_params() permalink = Permalink( seed_number=15000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) patches = GamePatches.with_game(game) patches = patches.assign_gate_assignment( base_patches_factory.gate_assignment_for_configuration( configuration, game.resource_database, Random(15000))) game, state = logic_bootstrap(configuration, game, patches) return game, state, permalink
def test_retcon_filler_integration(): layout_configuration = LayoutConfiguration.default() rng = Random("fixed-seed!") status_update = MagicMock() game = data_reader.decode_data(layout_configuration.game_data) patches = GamePatches.with_game(game) available_pickups = game.pickup_database.all_useful_pickups logic, state = logic_bootstrap(layout_configuration, game, patches) logic.game.simplify_connections(state.resources) filler_patches = retcon.retcon_playthrough_filler(logic, state, tuple(available_pickups), rng, status_update) assert filler_patches == patches
def validate_command_logic(args): debug._DEBUG_LEVEL = args.debug data = prime_database.decode_data_file(args) game = data_reader.decode_data(data) if args.layout_file is not None: description = LayoutDescription.from_file(Path(args.layout_file)) configuration = description.permalink.layout_configuration patches = description.patches else: configuration = LayoutConfiguration.default() patches = GamePatches.with_game(game).assign_pickup_assignment( game.pickup_database.original_pickup_mapping) final_state_by_resolve = resolver.resolve(configuration=configuration, game=game, patches=patches) print(final_state_by_resolve)
def test_output_name_for(mock_shareable_hash: PropertyMock, empty_patches): # Setup permalink_mock = MagicMock(spec=Permalink( seed_number=15000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=LayoutConfiguration.default(), )) layout = LayoutDescription(version="0.15.0", permalink=permalink_mock, patches=empty_patches, solver_path=()) mock_shareable_hash.return_value = "PermalinkStr" # Run result = simplified_patcher._output_name_for(layout) # Assert assert result == "Echoes Randomizer - PermalinkStr"
def _load_previous_state(persistence_path: Path, layout_configuration: LayoutConfiguration, ) -> Optional[dict]: previous_layout_path = persistence_path.joinpath("layout_configuration.json") try: with previous_layout_path.open() as previous_layout_file: previous_layout = LayoutConfiguration.from_json_dict(json.load(previous_layout_file)) except (FileNotFoundError, TypeError, KeyError, json.JSONDecodeError): return None if previous_layout != layout_configuration: return None previous_state_path = persistence_path.joinpath("state.json") try: with previous_state_path.open() as previous_state_file: return json.load(previous_state_file) except (FileNotFoundError, json.JSONDecodeError): return None
def test_calculate_reach_with_all_pickups(test_data): game, state, _ = test_data item_pool = calculate_item_pool(LayoutConfiguration.from_params(), game.resource_database, state.patches) add_resources_into_another(state.resources, item_pool[0].starting_items) for pickup in item_pool[1]: add_pickup_to_state(state, pickup) first_reach, second_reach = _create_reaches_and_compare(game, state) first_actions, second_actions = _compare_actions(first_reach, second_reach) found_pickups = set( filter_pickup_nodes(filter_reachable(second_reach.nodes, first_reach))) all_pickups = set(filter_pickup_nodes(game.world_list.all_nodes)) # assert (len(list(first_reach.nodes)), len(first_actions)) == (898, 9) # assert (len(list(second_reach.nodes)), len(second_actions)) == (898, 9) pprint.pprint(first_actions) assert all_pickups == found_pickups
def test_reach_size_from_start(echoes_game_description): # Setup configuration = LayoutConfiguration.from_params( trick_level_configuration=TrickLevelConfiguration( LayoutTrickLevel.HYPERMODE), ) patches = GamePatches.with_game(echoes_game_description) patches = patches.assign_gate_assignment( base_patches_factory.gate_assignment_for_configuration( configuration, echoes_game_description.resource_database, Random(15000))) game, state = logic_bootstrap(configuration, echoes_game_description, patches) # Run reach = GeneratorReach.reach_from_state(game, state) # Assert assert len(list(reach.nodes)) == 26 assert len(list(reach.safe_nodes)) == 4
def bit_pack_unpack(cls, decoder: BitPackDecoder) -> "Permalink": version, seed, spoiler = decoder.decode(_PERMALINK_MAX_VERSION, _PERMALINK_MAX_SEED, 2) cls._raise_if_different_version(version) included_data_hash = decoder.decode(256)[0] patcher_configuration = PatcherConfiguration.bit_pack_unpack(decoder) layout_configuration = LayoutConfiguration.bit_pack_unpack(decoder) expected_data_hash = _dictionary_byte_hash( layout_configuration.game_data) if included_data_hash != expected_data_hash: raise ValueError( "Given permalink is for a Randovania database with hash '{}', " "but current database has hash '{}'.".format( included_data_hash, expected_data_hash)) return Permalink(seed, bool(spoiler), patcher_configuration, layout_configuration)
def _test_data(): data = default_data.decode_default_prime2() game = data_reader.decode_data(data, False) configuration = LayoutConfiguration.from_params( trick_level=LayoutTrickLevel.NO_TRICKS, sky_temple_keys=LayoutSkyTempleKeyMode.FULLY_RANDOM, elevators=LayoutRandomizedFlag.VANILLA, pickup_quantities={}, starting_location=StartingLocation.default(), starting_resources=StartingResources.default(), ) permalink = Permalink( seed_number=15000, spoiler=True, patcher_configuration=PatcherConfiguration.default(), layout_configuration=configuration, ) logic, state = logic_bootstrap(configuration, game, GamePatches.with_game(game)) return logic, state, permalink