def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "Preset": from randovania.interface_common.preset_manager import PresetManager manager: PresetManager = metadata["manager"] included_presets = [ versioned.get_preset() for versioned in manager.included_presets ] is_custom_preset = bitpacking.decode_bool(decoder) reference = decoder.decode_element(included_presets) if is_custom_preset: preset = Preset( name="{} Custom".format(reference.name), description="A customized preset.", base_preset_name=reference.name, game=reference.game, configuration=reference.configuration.bit_pack_unpack( decoder, {"reference": reference.configuration}), ) else: preset = reference included_data_hash = decoder.decode_single(256) expected_data_hash = _dictionary_byte_hash( preset.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 bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "MajorItemsConfiguration": from randovania.game_description import default_database item_database = default_database.default_prime2_item_database() progressive_suit = bitpacking.decode_bool(decoder) progressive_grapple = bitpacking.decode_bool(decoder) progressive_launcher = bitpacking.decode_bool(decoder) default = MajorItemsConfiguration.default() num_items = decoder.decode_single(len(default.items_state)) indices_with_custom = { decoder.decode_single(len(default.items_state)) for _ in range(num_items) } items_state = {} for index, item in enumerate(item_database.major_items.values()): if index in indices_with_custom: items_state[item] = MajorItemState.bit_pack_unpack( decoder, item) else: items_state[item] = default.items_state[item] minimum, maximum = decoder.decode(RANDOM_STARTING_ITEMS_LIMIT, RANDOM_STARTING_ITEMS_LIMIT) return cls(items_state, progressive_suit=progressive_suit, progressive_grapple=progressive_grapple, progressive_launcher=progressive_launcher, minimum_random_starting_items=minimum, maximum_random_starting_items=maximum)
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata): from randovania.game_description import default_database item_database = default_database.default_prime2_item_database() default = cls.default() has_value = { item_key: bool(decoder.decode_single(2)) for item_key in default.maximum_ammo.keys() } maximum_ammo = { item_key: decoder.decode_single(256) if has_value[item_key] else default.maximum_ammo[item_key] for item_key, default_value in default.maximum_ammo.items() } num_items = decoder.decode_single(len(default.items_state)) indices_with_custom = { decoder.decode_single(len(default.items_state)) for _ in range(num_items) } items_state = {} for index, item in enumerate(item_database.ammo.values()): if index in indices_with_custom: items_state[item] = AmmoState.bit_pack_unpack(decoder, {}) else: items_state[item] = default.items_state[item] return cls(maximum_ammo, items_state)
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 bit_pack_unpack(cls, decoder: BitPackDecoder, item: MajorItem) -> "MajorItemState": original = decoder.decode_single(2) # num shuffled shuffled = bitpacking.decode_int_with_limits(decoder, DEFAULT_MAXIMUM_SHUFFLED) # starting item starting = decoder.decode_single( ENERGY_TANK_MAXIMUM_COUNT if item.item_category == ItemCategory.ENERGY_TANK else 2) if item.ammo_index: included_ammo = decoder.decode(*[256 for _ in item.ammo_index]) else: included_ammo = [] # allowed_as_random_starting_item allowed_as_random_starting_item = bitpacking.decode_bool(decoder) return cls( include_copy_in_original_location=bool(original), num_shuffled_pickups=shuffled, num_included_in_starting_items=starting, included_ammo=tuple(included_ammo), allowed_as_random_starting_item=allowed_as_random_starting_item, )
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "Permalink": version, seed_number = decoder.decode(_PERMALINK_MAX_VERSION, _PERMALINK_MAX_SEED) cls._raise_if_different_version(version) spoiler = bitpacking.decode_bool(decoder) player_count = bitpacking.decode_int_with_limits( decoder, _PERMALINK_PLAYER_COUNT_LIMITS) manager = PresetManager(None) previous_unique_presets = [] presets = {} for index in range(player_count): in_previous_presets = bitpacking.decode_bool(decoder) if in_previous_presets: presets[index] = decoder.decode_element( previous_unique_presets) continue preset = _decode_preset(decoder, manager) previous_unique_presets.append(preset) presets[index] = preset return Permalink(seed_number, spoiler, presets)
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "MajorItemsConfiguration": reference: MajorItemsConfiguration = metadata["reference"] num_items = decoder.decode_single(len(reference.items_state)) indices_with_custom = { decoder.decode_single(len(reference.items_state)) for _ in range(num_items) } items_state = {} for index, item in enumerate(reference.items_state.keys()): if index in indices_with_custom: items_state[item] = MajorItemState.bit_pack_unpack( decoder, item) else: items_state[item] = reference.items_state[item] minimum, maximum = decoder.decode(RANDOM_STARTING_ITEMS_LIMIT, RANDOM_STARTING_ITEMS_LIMIT) return cls(items_state, minimum_random_starting_items=minimum, maximum_random_starting_items=maximum)
def bit_pack_unpack(cls, decoder: BitPackDecoder, item: MajorItem, reference: "MajorItemState") -> "MajorItemState": db = default_database.resource_database_for(item.game) if item.progression: main_index = item.progression[0] else: main_index = item.ammo_index[0] main_item = db.get_item(main_index) # original location original = False if item.original_index is not None: original = bitpacking.decode_bool(decoder) # num shuffled shuffled = bitpacking.decode_int_with_limits(decoder, DEFAULT_MAXIMUM_SHUFFLED) # starting item if main_item.max_capacity > 1: starting = bitpacking.decode_int_with_limits( decoder, (2, main_item.max_capacity + 1)) else: starting = decoder.decode_single(main_item.max_capacity + 1) # priority priority = bitpacking.BitPackFloat.bit_pack_unpack( decoder, PRIORITY_LIMITS) # ammo index if item.ammo_index: custom_ammo = bitpacking.decode_bool(decoder) if custom_ammo: all_equal = len( item.ammo_index) <= 1 or bitpacking.decode_bool(decoder) if all_equal: ammo = decoder.decode_single( db.get_item(item.ammo_index[0]).max_capacity + 1) included_ammo = [ammo] * len(item.ammo_index) else: included_ammo = [ decoder.decode_single( db.get_item(item).max_capacity + 1) for item in item.ammo_index ] else: included_ammo = reference.included_ammo else: included_ammo = [] return cls( include_copy_in_original_location=original, num_shuffled_pickups=shuffled, num_included_in_starting_items=starting, priority=priority, included_ammo=tuple(included_ammo), )
def bit_pack_unpack(cls, decoder: BitPackDecoder, name: str, database: ResourceDatabase) -> PickupEntry: model_index = decoder.decode_single(255) probability_offset = BitPackFloat.bit_pack_unpack( decoder, _PROBABILITY_OFFSET_META) probability_multiplier = BitPackFloat.bit_pack_unpack( decoder, _PROBABILITY_MULTIPLIER_META) item_category = ItemCategory.bit_pack_unpack(decoder, {}) broad_category = ItemCategory.bit_pack_unpack(decoder, {}) has_name = bitpacking.decode_bool(decoder) num_conditional = decoder.decode_single( MAXIMUM_PICKUP_CONDITIONAL_RESOURCES) + 1 conditional_resources = [] for i in range(num_conditional): item_name = None # TODO: get the first resource name if i > 0: item_dependency = decoder.decode_element(database.item) else: item_dependency = None resources = [] for _ in range(decoder.decode_single(MAXIMUM_PICKUP_RESOURCES + 1)): resource = decoder.decode_element(database.item) quantity = decoder.decode_single(255) resources.append((resource, quantity)) if has_name: if bitpacking.decode_bool(decoder): item_name = name else: item_name = resources[0][0].long_name conditional_resources.append( ConditionalResources( name=item_name, item=item_dependency, resources=tuple(resources), )) num_convert = decoder.decode_single(MAXIMUM_PICKUP_CONVERSION + 1) convert_resources = [] for i in range(num_convert): source = decoder.decode_element(database.item) target = decoder.decode_element(database.item) convert_resources.append(ResourceConversion(source, target)) return PickupEntry( name=name, model_index=model_index, item_category=item_category, broad_category=broad_category, resources=tuple(conditional_resources), convert_resources=tuple(convert_resources), probability_offset=probability_offset, probability_multiplier=probability_multiplier, )
def test_encode_no_tricks_are_removed(): from_json = TrickLevelConfiguration.from_json( { "minimal_logic": False, "specific_levels": { "Dash": "disabled" } }, game=RandovaniaGame.METROID_PRIME_ECHOES) encoded, byte_count = bitpacking.pack_results_and_bit_count( from_json.bit_pack_encode({})) assert encoded == b'\x00\x00\x00\x00' assert byte_count == 26 decoder = BitPackDecoder(encoded) decoded = TrickLevelConfiguration.bit_pack_unpack( decoder, { "reference": TrickLevelConfiguration(False, {}, RandovaniaGame.METROID_PRIME_ECHOES), }) assert decoded.specific_levels == {}
def test_prime_thing(default_prime_configuration): config = { "mode": "two-way", "types_state": { "door": { "can_change_from": [ "Ice Door", "Missile Blast Shield", "Normal Door", "Plasma Door", "Wave Door" ], "can_change_to": [ "Ice Door", "Ice Spreader Blast Shield", "Missile Blast Shield (randomprime)", "Normal Door", "Plasma Door", "Power Bomb Blast Shield", "Super Missile Blast Shield", "Wave Door" ] }, "morph_ball": { "can_change_from": [], "can_change_to": [] }, "other": { "can_change_from": [], "can_change_to": [] } } } ref = {"reference": default_prime_configuration.dock_rando} dc = DockRandoConfiguration.from_json(config, RandovaniaGame.METROID_PRIME) encoded = bitpacking.pack_value(dc, metadata=ref) decoder = BitPackDecoder(encoded) decoded = DockRandoConfiguration.bit_pack_unpack(decoder, ref) assert dc == decoded
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "TranslatorConfiguration": from randovania.layout import configuration_factory templates = [ configuration_factory.get_vanilla_actual_translator_configurations( ), configuration_factory.get_vanilla_colors_translator_configurations( ), cls.default().with_full_random().translator_requirement, None, ] fixed_gfmc_compound = bitpacking.decode_bool(decoder) fixed_torvus_temple = bitpacking.decode_bool(decoder) fixed_great_temple = bitpacking.decode_bool(decoder) translator_requirement = decoder.decode_element(templates) if translator_requirement is None: translator_requirement = {} for gate in templates[0].keys(): translator_requirement[ gate] = LayoutTranslatorRequirement.bit_pack_unpack( decoder, {}) return cls( translator_requirement, fixed_gfmc_compound=fixed_gfmc_compound, fixed_torvus_temple=fixed_torvus_temple, fixed_great_temple=fixed_great_temple, )
def bit_pack_unpack(cls, decoder: BitPackDecoder): disable_hud_popup, menu_mod, speed_up_credits = decoder.decode(2, 2, 2) return cls( disable_hud_popup=bool(disable_hud_popup), menu_mod=bool(menu_mod), speed_up_credits=bool(speed_up_credits), )
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "AmmoState": pickup_count = decoder.decode_single(cls.maximum_pickup_count()) requires_major_item = bitpacking.decode_bool(decoder) return cls( variance=0, pickup_count=pickup_count, requires_major_item=requires_major_item, )
def test_decode(location_with_data): # Setup data, expected = location_with_data # Run decoder = BitPackDecoder(data) result = StartingLocation.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def test_decode(translator_data): # Setup data, _, expected = translator_data # Run decoder = BitPackDecoder(data) result = TranslatorConfiguration.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def test_decode(patcher_with_data): # Setup data, expected = patcher_with_data # Run decoder = BitPackDecoder(data) result = PatcherConfiguration.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def test_decode(mock_possible_tricks, configuration_with_data): # Setup data, expected = configuration_with_data # Run decoder = BitPackDecoder(data) result = TrickLevelConfiguration.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def test_decode(state_with_data): # Setup data, expected = state_with_data # Run decoder = BitPackDecoder(data) result = AmmoState.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def test_decode(major_item_state): # Setup item, data, _, expected, reference = major_item_state # Run decoder = BitPackDecoder(data) result = MajorItemState.bit_pack_unpack(decoder, item, reference=reference) # Assert assert result == expected
def test_decode(layout_config_with_data): # Setup data, expected, _ = layout_config_with_data # Run decoder = BitPackDecoder(data) result = EchoesConfiguration.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def test_decode(state_with_data): # Setup item, data, expected = state_with_data # Run decoder = BitPackDecoder(data) result = MajorItemState.bit_pack_unpack(decoder, item) # Assert assert result == expected
def test_decode(config_with_data): # Setup data, expected = config_with_data # Run decoder = BitPackDecoder(data) result = MajorItemsConfiguration.bit_pack_unpack(decoder, {}) # Assert assert result == expected
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata) -> "GeneratorParameters": games = decode_game_list(decoder) seed_number = decoder.decode_single(_PERMALINK_MAX_SEED) spoiler = bitpacking.decode_bool(decoder) manager = PresetManager(None) presets = [ Preset.bit_pack_unpack(decoder, {"manager": manager, "game": game}) for game in games ] for game in _get_unique_games(presets): included_data_hash = decoder.decode_single(256) expected_data_hash = _game_db_hash(game) if included_data_hash != expected_data_hash: raise ValueError("Given permalink is for a Randovania {} database with hash '{}', " "but current database has hash '{}'.".format(game.long_name, included_data_hash, expected_data_hash)) return GeneratorParameters(seed_number, spoiler, presets)
def test_decode_prime2(prime2_data): # Setup data, default, expected = prime2_data # Run decoder = BitPackDecoder(data) result = MajorItemsConfiguration.bit_pack_unpack(decoder, {"reference": default}) # Assert assert result == expected
def test_decode(with_data): # Setup reference, data, _, expected = with_data # Run decoder = BitPackDecoder(data) result = TeleporterConfiguration.bit_pack_unpack(decoder, {"reference": reference}) # Assert assert result == expected
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_decode(location_with_data): # Setup data, expected = location_with_data # Run decoder = BitPackDecoder(data) result = LocationList.bit_pack_unpack( decoder, {"reference": LocationList.with_elements([], RandovaniaGame.METROID_PRIME_ECHOES)}) # Assert assert result == expected
def test_decode(config_with_data): # Setup data, expected, reference = config_with_data # Run decoder = BitPackDecoder(data) result = AmmoConfiguration.bit_pack_unpack(decoder, {"reference": reference}) # Assert assert result == expected
def bit_pack_unpack(cls, decoder: BitPackDecoder, metadata): global_level = LayoutTrickLevel.bit_pack_unpack(decoder, metadata) encodable_levels = list(LayoutTrickLevel) encodable_levels.remove(LayoutTrickLevel.MINIMAL_LOGIC) specific_levels = {} for trick in sorted(_all_trick_indices()): if bitpacking.decode_bool(decoder): specific_levels[trick] = decoder.decode_element(encodable_levels) return cls(global_level, specific_levels)