def _migrate_v1(data: dict) -> dict: game = RandovaniaGame(data["game"]) for item in data["items"].values(): item["progression"] = [ migration_data.get_resource_name_from_index( game, progression, ResourceType.ITEM) for progression in item["progression"] ] ammo = item.get("ammo") if ammo is not None: item["ammo"] = [ migration_data.get_resource_name_from_index( game, ammo, ResourceType.ITEM) for ammo in item["ammo"] ] for ammo in data["ammo"].values(): ammo["items"] = [ migration_data.get_resource_name_from_index( game, item, ResourceType.ITEM) for item in ammo["items"] ] unlock = ammo.get("unlocked_by") if unlock is not None: ammo["unlocked_by"] = migration_data.get_resource_name_from_index( game, ammo["unlocked_by"], ResourceType.ITEM) temporary = ammo.get("temporary") if temporary is not None: ammo["temporary"] = migration_data.get_resource_name_from_index( game, ammo["temporary"], ResourceType.ITEM) return data
def allowed_games(self) -> List[RandovaniaGame]: dev_features = self.dev_features or "" return [ game for game in RandovaniaGame.sorted_all_games() if game.data.defaults_available_in_game_sessions or game.value in dev_features ]
def from_json_dict(cls, json_dict: dict) -> "LayoutConfiguration": return LayoutConfiguration( game=RandovaniaGame(json_dict["game"]), trick_level_configuration=TrickLevelConfiguration.from_json(json_dict["trick_level"]), damage_strictness=LayoutDamageStrictness(json_dict["damage_strictness"]), sky_temple_keys=LayoutSkyTempleKeyMode(json_dict["sky_temple_keys"]), elevators=LayoutElevators(json_dict["elevators"]), starting_location=StartingLocation.from_json(json_dict["starting_location"]), available_locations=AvailableLocationsConfiguration.from_json(json_dict["available_locations"]), major_items_configuration=MajorItemsConfiguration.from_json( json_dict["major_items_configuration"], default_prime2_item_database(), ), ammo_configuration=AmmoConfiguration.from_json( json_dict["ammo_configuration"], default_prime2_item_database(), ), translator_configuration=TranslatorConfiguration.from_json(json_dict["translator_configuration"]), hints=HintConfiguration.from_json(json_dict["hints"]), beam_configuration=BeamConfiguration.from_json(json_dict["beam_configuration"]), skip_final_bosses=json_dict["skip_final_bosses"], energy_per_tank=json_dict["energy_per_tank"], safe_zone=LayoutSafeZone.from_json(json_dict["safe_zone"]), split_beam_ammo=json_dict["split_beam_ammo"], )
def from_json(cls, data) -> "GameSessionEntry": player_entries = [ PlayerSessionEntry.from_json(player_json) for player_json in data["players"] ] return GameSessionEntry( id=data["id"], name=data["name"], presets=[ VersionedPreset(preset_json) for preset_json in data["presets"] ], players={ player_entry.id: player_entry for player_entry in player_entries }, actions=[ GameSessionAction.from_json(item) for item in data["actions"] ], seed_hash=data["seed_hash"], word_hash=data["word_hash"], spoiler=data["spoiler"], permalink=data["permalink"], state=GameSessionState(data["state"]), generation_in_progress=data["generation_in_progress"], allowed_games=[ RandovaniaGame(game) for game in data["allowed_games"] ], )
def decode_data_file(args) -> Dict: json_database: Optional[Path] = args.json_database if json_database is not None: with json_database.open() as data_file: return json.load(data_file) else: return default_data.read_json_then_binary(RandovaniaGame(args.game))[1]
def bit_pack_unpack(cls, decoder: BitPackDecoder, database: ResourceDatabase) -> PickupEntry: helper = DatabaseBitPackHelper(database) name = bitpacking.decode_string(decoder) model = PickupModel( game=RandovaniaGame.bit_pack_unpack(decoder, {}), name=bitpacking.decode_string(decoder), ) item_category = ItemCategory.bit_pack_unpack(decoder, {}) broad_category = ItemCategory.bit_pack_unpack(decoder, {}) progression = bitpacking.decode_tuple(decoder, helper.decode_resource_quantity) extra_resources = bitpacking.decode_tuple(decoder, helper.decode_resource_quantity) unlocks_resource = bitpacking.decode_bool(decoder) resource_lock = None if bitpacking.decode_bool(decoder): resource_lock = helper.decode_resource_lock(decoder) respects_lock = bitpacking.decode_bool(decoder) probability_offset = BitPackFloat.bit_pack_unpack(decoder, _PROBABILITY_OFFSET_META) probability_multiplier = BitPackFloat.bit_pack_unpack(decoder, _PROBABILITY_MULTIPLIER_META) return PickupEntry( name=name, model=model, item_category=item_category, broad_category=broad_category, progression=progression, extra_resources=extra_resources, unlocks_resource=unlocks_resource, resource_lock=resource_lock, respects_lock=respects_lock, probability_offset=probability_offset, probability_multiplier=probability_multiplier, )
def decode_data_with_world_reader( data: Dict) -> Tuple[WorldReader, GameDescription]: game = RandovaniaGame(data["game"]) resource_database = read_resource_database(data["resource_database"]) dock_weakness_database = read_dock_weakness_database( data["dock_weakness_database"], resource_database) if game == RandovaniaGame.PRIME2: game_specific = read_game_specific(data["game_specific"], resource_database) else: game_specific = None world_reader = WorldReader(resource_database, dock_weakness_database) world_list = world_reader.read_world_list(data["worlds"]) victory_condition = read_requirement(data["victory_condition"], resource_database) starting_location = AreaLocation.from_json(data["starting_location"]) initial_states = read_initial_states(data["initial_states"], resource_database) return world_reader, GameDescription( game=game, resource_database=resource_database, game_specific=game_specific, dock_weakness_database=dock_weakness_database, world_list=world_list, victory_condition=victory_condition, starting_location=starting_location, initial_states=initial_states, )
def from_json(cls, data) -> "GameSessionEntry": data = convert_to_raw_python(BinaryGameSessionEntry.parse(data)) player_entries = [ PlayerSessionEntry.from_json(player_json) for player_json in data["players"] ] return GameSessionEntry( id=data["id"], name=data["name"], presets=[ VersionedPreset(json.loads(preset_json)) for preset_json in data["presets"] ], players={ player_entry.id: player_entry for player_entry in player_entries }, game_details=GameDetails.from_json(data["game_details"]) if data["game_details"] is not None else None, state=GameSessionState(data["state"]), generation_in_progress=data["generation_in_progress"], allowed_games=[ RandovaniaGame(game) for game in data["allowed_games"] ], )
def update_items(self): self.clear() tree_item: dict[Any, QtWidgets.QTreeWidgetItem] = {} for game in RandovaniaGame.sorted_all_games(): if not game.data.development_state.can_view( self.show_experimental): continue root = QtWidgets.QTreeWidgetItem(self) root.setText(0, game.long_name) root.setExpanded(True) tree_item[game] = root self.preset_to_item = {} # Included presets for preset in self.window_manager.preset_manager.included_presets.values( ): if not preset.game.data.development_state.can_view( self.show_experimental): continue item = QtWidgets.QTreeWidgetItem(tree_item[preset.game]) item.setText(0, preset.name) item.setExpanded(True) item.setData(0, Qt.UserRole, preset.uuid) self.preset_to_item[preset.uuid] = item # Custom Presets for preset in self.window_manager.preset_manager.custom_presets.values( ): if not preset.game.data.development_state.can_view( self.show_experimental): continue item = QtWidgets.QTreeWidgetItem(tree_item[preset.game]) item.setText(0, preset.name) item.setData(0, Qt.UserRole, preset.uuid) self.preset_to_item[preset.uuid] = item # Set parents after, so don't have issues with order for preset in sorted( self.window_manager.preset_manager.custom_presets.values(), key=lambda it: it.name): if preset.base_preset_uuid in self.preset_to_item: root_item = tree_item[preset.game] self_item = self.preset_to_item[preset.uuid] target_parent = parent_item = self.preset_to_item[ preset.base_preset_uuid] while parent_item != root_item: if parent_item == self_item: # LOOP DETECTED! target_parent = root_item break parent_item = parent_item.parent() root_item.removeChild(self_item) target_parent.addChild(self_item)
def decode_data_with_world_reader( data: Dict) -> Tuple[WorldReader, GameDescription]: data = game_migration.migrate_to_current(copy.deepcopy(data)) game = RandovaniaGame(data["game"]) resource_database = read_resource_database(game, data["resource_database"]) dock_weakness_database = read_dock_weakness_database( data["dock_weakness_database"], resource_database) layers = frozen_lib.wrap(data["layers"]) world_reader = WorldReader(resource_database, dock_weakness_database) world_list = world_reader.read_world_list(data["worlds"]) victory_condition = read_requirement(data["victory_condition"], resource_database) starting_location = AreaIdentifier.from_json(data["starting_location"]) initial_states = read_initial_states(data["initial_states"], resource_database) minimal_logic = read_minimal_logic_db(data["minimal_logic"]) return world_reader, GameDescription( game=game, resource_database=resource_database, layers=layers, dock_weakness_database=dock_weakness_database, world_list=world_list, victory_condition=victory_condition, starting_location=starting_location, initial_states=initial_states, minimal_logic=minimal_logic, )
def _all_hash_words() -> Dict[RandovaniaGame, typing.List[str]]: with (get_data_path() / "hash_words" / "hash_words.json").open() as hash_words_file: return { RandovaniaGame(key): words for key, words in json.load(hash_words_file).items() }
def __init__(self, data_dir: Path, user_dir: Optional[Path] = None): self._data_dir = data_dir self._user_dir = user_dir or data_dir self._last_changelog_displayed = str(update_checker.strict_current_version()) for game in RandovaniaGame.all_games(): self._set_field(f"game_{game.value}", None)
def create_permalink(args): from randovania.layout.permalink import Permalink from randovania.layout.generator_parameters import GeneratorParameters from randovania.interface_common.preset_manager import PresetManager game: RandovaniaGame = RandovaniaGame(args.game) preset_manager = PresetManager(None) presets = [] for preset_name in args.preset_name: versioned = preset_manager.included_preset_with(game, preset_name) if versioned is None: raise ValueError( "Unknown included preset '{}' for game {}. Valid options are: {}" .format(preset_name, game.long_name, [ preset.name for preset in preset_manager.included_presets.values() if preset.game == game ])) presets.append(versioned.get_preset()) seed = args.seed_number if seed is None: seed = random.randint(0, 2**31) return Permalink.from_parameters( GeneratorParameters( seed, spoiler=not args.race, presets=presets, ), )
def game(self) -> RandovaniaGame: if self._preset is not None: return self._preset.configuration.game if self.data["schema_version"] < 6: return RandovaniaGame.METROID_PRIME_ECHOES return RandovaniaGame(self.data["game"])
def game(self) -> RandovaniaGame: if self.data is None: return self._preset.configuration.game if self.data["schema_version"] < 6: return RandovaniaGame.PRIME2 return RandovaniaGame(self.data["game"])
def add_per_game_serializer(): def make_decoder(g): return lambda it: g.options.from_json(it) for game in RandovaniaGame.all_games(): _SERIALIZER_FOR_FIELD[f"game_{game.value}"] = Serializer( lambda it: it.as_json, make_decoder(game), )
def from_json_dict(cls, value) -> "Preset": game = RandovaniaGame(value["game"]) return Preset( name=value["name"], description=value["description"], base_preset_name=value["base_preset_name"], game=game, configuration=_game_to_config[game].from_json( value["configuration"]), )
def update_human_readable_logic(args): from randovania.game_description import pretty_print from randovania.game_description import data_reader game = RandovaniaGame(args.game) path, data = default_data.read_json_then_binary(game) gd = data_reader.decode_data(data) path.with_suffix("").mkdir(parents=True, exist_ok=True) pretty_print.write_human_readable_game(gd, path.with_suffix(""))
async def _create_permalink(args_) -> Permalink: from randovania.interface_common.preset_manager import PresetManager preset_manager = PresetManager(None) preset = preset_manager.included_preset_with(RandovaniaGame(args_.game), args_.preset_name).get_preset() return Permalink( args_.seed_number, spoiler=True, presets={i: preset for i in range(args_.player_count)}, )
async def game_session_request_pickups( self) -> Tuple[RandovaniaGame, List[Tuple[str, bytes]]]: data = await self._emit_with_result("game_session_request_pickups", self._current_game_session.id) if data is None: return RandovaniaGame.PRIME2, [] return RandovaniaGame(data["game"]), [ (item["provider_name"], base64.b85decode(item["pickup"])) for item in data["pickups"] if item is not None ]
def export_videos_command_logic(args): from randovania.cli.commands.export_db_videos import export_videos games = list() if args.game is not None: games.append(RandovaniaGame(args.game)) else: games = [g for g in RandovaniaGame] for game in games: export_videos(game, args.output_dir)
def from_json_dict(cls, value) -> "Preset": game = RandovaniaGame(value["game"]) return Preset( name=value["name"], uuid=uuid.UUID(value["uuid"]), description=value["description"], base_preset_uuid=uuid.UUID(value["base_preset_uuid"]) if value["base_preset_uuid"] is not None else None, game=game, configuration=game.data.layout.configuration.from_json( value["configuration"]), )
async def _on_game_session_pickups_update_raw(self, data): game = RandovaniaGame(data["game"]) resource_database = default_database.resource_database_for(game) await self.on_game_session_pickups_update( GameSessionPickups( game=game, pickups=tuple( (item["provider_name"], _decode_pickup(item["pickup"], resource_database)) for item in data["pickups"]), ))
def _on_first_show(self): self._index_for_game = {} for game in RandovaniaGame.sorted_all_games(): if game.gui.help_widget is None: continue index = self.addTab(game.gui.help_widget(), game.long_name) self.setTabVisible( index, game.data.development_state.can_view( self._experimental_visible)) self._index_for_game[game] = index
async def display_window_for(app, options, command: str, args): if command == "tracker": await show_tracker(app) elif command == "main": await show_main_window(app, options, args.preview) elif command == "data_editor": show_data_editor(app, options, RandovaniaGame(args.game)) elif command == "game": show_game_details(app, options, args.rdvgame) elif command == "session": await show_game_session(app, options, args.session_id) else: raise RuntimeError(f"Unknown command: {command}")
def from_json(cls, value: dict) -> "EchoesPerGameOptions": game = RandovaniaGame.METROID_PRIME_ECHOES cosmetic_patches = game.data.layout.cosmetic_patches.from_json( value["cosmetic_patches"]) return cls( cosmetic_patches=cosmetic_patches, input_path=decode_if_not_none(value["input_path"], Path), output_directory=decode_if_not_none(value["output_directory"], Path), use_external_models={ RandovaniaGame(g) for g in value["use_external_models"] }, )
def __getattr__(self, item): if isinstance(item, str) and item.startswith("game_"): game_name = item[len("game_"):] try: game: RandovaniaGame = RandovaniaGame(game_name) except ValueError: raise AttributeError(item) result = getattr(self, f"_{item}", None) if result is None: result = game.options.default_for_game(game) return result raise AttributeError(item)
def _migrate_v32(preset: dict) -> dict: game = RandovaniaGame(preset["game"]) weakness_database = default_database.game_description_for( game).dock_weakness_database preset["configuration"]["dock_rando"] = { "mode": DockRandoMode.VANILLA.value, "types_state": { dock_type.short_name: DockTypeState.default_state(game, dock_type.short_name).as_json for dock_type in weakness_database.dock_types } } return preset
def rename_docks_logic(args): from randovania.game_description import data_reader from randovania.game_description import data_writer from randovania.game_description import pretty_print from randovania.game_description.editor import Editor from randovania.game_description.world.dock_node import DockNode from randovania.game_description import integrity_check game = RandovaniaGame(args.game) path, data = default_data.read_json_then_binary(game) gd = data_reader.decode_data(data) # Make the changes editor = Editor(gd) for world in gd.world_list.worlds: for area in world.areas: for i in range(len(area.nodes)): node = area.nodes[i] if not isinstance(node, DockNode): continue valid_name, suffix = integrity_check.dock_has_correct_name( area, node) if not valid_name: expected_name = integrity_check.base_dock_name(node) docks_to_same_target = integrity_check.docks_with_same_base_name( area, expected_name) if suffix is None: suffix = f" ({docks_to_same_target.index(node) + 1})" print( f"In {area.name}, renaming '{node.name}' to '{expected_name}{suffix}'" ) editor.replace_node( area, node, dataclasses.replace(node, name=f"{expected_name}{suffix}")) # Write it back logging.info("Writing database files") new_data = data_writer.write_game_description(gd) data_writer.write_as_split_files(new_data, path) logging.info("Writing human readable") path.with_suffix("").mkdir(parents=True, exist_ok=True) pretty_print.write_human_readable_game(gd, path.with_suffix(""))
def bulk_move_node_logic(args): game = RandovaniaGame(args.game) path, data = default_data.read_json_then_binary(game) gd = data_reader.decode_data(data) # Make the changes editor = Editor(gd) world = gd.world_list.world_with_name(args.world) source_area = world.area_by_name(args.source_area) target_area = world.area_by_name(args.target_area) node_names = args.node_names requirements: dict[str, dict[str, Requirement]] = { node_name: { target.name: req for target, req in source_area.connections[ source_area.node_with_name(node_name)].items() } for node_name in node_names } for node_name in node_names: logging.info("Moving node %s", node_name) editor.move_node_from_area_to_area( source_area, target_area, source_area.node_with_name(node_name)) for name, connections in requirements.items(): source_node = target_area.node_with_name(name) for target, req in connections.items(): editor.edit_connections( target_area, source_node, target_area.node_with_name(target), req, ) # Write it back logging.info("Writing database files") new_data = data_writer.write_game_description(gd) data_writer.write_as_split_files(new_data, path) logging.info("Writing human readable") path.with_suffix("").mkdir(parents=True, exist_ok=True) pretty_print.write_human_readable_game(gd, path.with_suffix(""))