def open_internal_data(cls, game: RandovaniaGame, edit_mode: bool) -> "DataEditorWindow": default_data.read_json_then_binary.cache_clear() path, data = default_data.read_json_then_binary(game) if path.suffix == ".bin": path = None return DataEditorWindow(data, path, True, edit_mode)
def test_create_new_dock(skip_qtbot, tmp_path, blank_game_data): db_path = Path(tmp_path.joinpath("test-game", "game")) game_data = default_data.read_json_then_binary(RandovaniaGame.BLANK)[1] window = DataEditorWindow(game_data, db_path, True, True) window.set_warning_dialogs_disabled(True) skip_qtbot.addWidget(window) window.focus_on_area_by_name("Back-Only Lock Room") current_area = window.current_area target_area = window.game_description.world_list.area_by_area_location( AreaIdentifier("Intro", "Explosive Depot")) assert current_area.node_with_name("Dock to Explosive Depot") is None assert target_area.node_with_name("Dock to Back-Only Lock Room") is None # Run window._create_new_dock(NodeLocation(0, 0, 0), target_area) # Assert new_node = current_area.node_with_name("Dock to Explosive Depot") assert new_node is not None assert window.current_node is new_node assert target_area.node_with_name( "Dock to Back-Only Lock Room") is not None
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 test_round_trip_full(game_enum: RandovaniaGame): original_data = default_data.read_json_then_binary(game_enum)[1] game = data_reader.decode_data(original_data) encoded_data = data_writer.write_game_description(game) assert list(encoded_data.keys()) == list(original_data.keys()) assert encoded_data == original_data
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 main(): package_folder = Path("dist", "randovania") if package_folder.exists(): shutil.rmtree(package_folder, ignore_errors=False) app_folder = Path("dist", "Randovania.app") if app_folder.exists(): shutil.rmtree(app_folder, ignore_errors=False) for game in iterate_enum(RandovaniaGame): database.export_as_binary( default_data.read_json_then_binary(game)[1], _ROOT_FOLDER.joinpath("randovania", "data", "binary_data", f"{game.value}.bin")) if is_production(): server_suffix = "randovania" client_id = 618134325921316864 else: server_suffix = "randovania-staging" client_id = 887825192208969828 configuration = { "discord_client_id": client_id, "server_address": f"https://randovania.metroidprime.run/{server_suffix}", "socketio_path": f"/{server_suffix}/socket.io", } with _ROOT_FOLDER.joinpath( "randovania", "data", "configuration.json").open("w") as config_release: json.dump(configuration, config_release) await download_nintendont() # HACK: pyintaller calls lipo/codesign on macOS and frequently timeout in github actions # There's also timeouts on Windows so we're expanding this to everyone print("Will patch timeout in PyInstaller compat") import PyInstaller.compat compat_path = Path(PyInstaller.compat.__file__) compat_text = compat_path.read_text().replace("timeout=60", "timeout=180") compat_path.write_text(compat_text) subprocess.run([sys.executable, "-m", "PyInstaller", "randovania.spec"], check=True) if platform.system() == "Windows": create_windows_zip(package_folder) elif platform.system() == "Darwin": create_macos_zip(app_folder) elif platform.system() == "Linux": create_linux_zip(package_folder) else: raise ValueError(f"Unknown system: {platform.system()}")
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(""))
def test_decode(patches_with_data, default_echoes_configuration): encoded, expected = patches_with_data data = default_data.read_json_then_binary( default_echoes_configuration.game)[1] game = data_reader.decode_data(data) pool = pool_creator.calculate_pool_results(default_echoes_configuration, game.resource_database) # Run decoded = game_patches_serializer.decode_single( 0, {0: pool}, game, encoded, default_echoes_configuration) # Assert assert decoded.elevator_connection == expected.elevator_connection assert decoded == expected
def refresh_all_logic(args): from randovania.game_description import pretty_print from randovania.game_description import data_reader, data_writer from randovania.game_description import integrity_check gd_per_game = {} path_per_game = {} idb_per_game = {} for game in iterate_enum(RandovaniaGame): logging.info("Reading %s", game.long_name) path, data = default_data.read_json_then_binary(game) path_per_game[game] = path gd = data_reader.decode_data(data) gd_per_game[game] = gd idb = default_database.item_database_for_game(game) idb_per_game[game] = idb should_stop = False if args.integrity_check: for game, gd in gd_per_game.items(): errors = integrity_check.find_database_errors(gd) if errors: logging.warning("Integrity errors for %s:\n%s", game.long_name, "\n".join(errors)) if game.data.development_state.is_stable: should_stop = True if should_stop: return for game, gd in gd_per_game.items(): path = path_per_game[game] logging.info("Writing %s", game.long_name) new_data = data_writer.write_game_description(gd) data_writer.write_as_split_files(new_data, path) path.with_suffix("").mkdir(parents=True, exist_ok=True) pretty_print.write_human_readable_game(gd, path.with_suffix("")) default_database.write_item_database_for_game(idb_per_game[game], game)
async def main(): package_folder = Path("dist", "randovania") if package_folder.exists(): shutil.rmtree(package_folder, ignore_errors=False) app_folder = Path("dist", "Randovania.app") if app_folder.exists(): shutil.rmtree(app_folder, ignore_errors=False) for game in iterate_enum(RandovaniaGame): prime_database.export_as_binary( default_data.read_json_then_binary(game)[1], _ROOT_FOLDER.joinpath("randovania", "data", "binary_data", f"{game.value}.bin")) if is_production(): server_suffix = "randovania" else: server_suffix = "randovania-staging" configuration = { "discord_client_id": 618134325921316864, "server_address": f"https://randovania.metroidprime.run/{server_suffix}", "socketio_path": f"/{server_suffix}/socket.io", } with _ROOT_FOLDER.joinpath( "randovania", "data", "configuration.json").open("w") as config_release: json.dump(configuration, config_release) await download_nintendont() subprocess.run([sys.executable, "-m", "PyInstaller", "randovania.spec"], check=True) if platform.system() == "Windows": create_windows_zip(package_folder) elif platform.system() == "Darwin": create_macos_zip(app_folder)
def test_on_filters_changed_view_mode(tmp_path, mocker, skip_qtbot): db_path = Path(tmp_path.joinpath("test-game", "game")) game_data = default_data.read_json_then_binary(RandovaniaGame.BLANK)[1] window = DataEditorWindow(game_data, db_path, True, False) skip_qtbot.addWidget(window) # Disable the layer found = False for (trick, trick_check), trick_combo in window.layers_editor.tricks.items(): if trick.long_name == "Combat": trick_check.setChecked(True) trick_combo.setCurrentIndex(1) found = True assert found window.layers_editor.layer_checks[1].setChecked(False) window.focus_on_world_by_name("Intro") window.focus_on_area_by_name("Boss Arena") assert window.current_area.node_with_name("Pickup (Free Loot)") is None
def collect_game_info(game: RandovaniaGame): data = default_data.read_json_then_binary(game)[1] worlds = dict() for world in data["worlds"]: areas = dict() for area_name in world["areas"]: area = world["areas"][area_name] nodes = dict() for node_name in area["nodes"]: node = area["nodes"][node_name] connections = dict() for connection_name in node["connections"]: connection = node["connections"][connection_name] yt_ids = list() get_yt_ids(connection, yt_ids, 0) if len(yt_ids) > 0: connections[connection_name] = yt_ids if len(connections) > 0: nodes[node_name] = connections if len(nodes) > 0: areas[area_name] = nodes if len(areas) > 0: worlds[world["name"]] = areas return worlds
def game_description_for(game: RandovaniaGame) -> GameDescription: result = data_reader.decode_data(default_data.read_json_then_binary(game)[1]) if result.game != game: raise ValueError(f"Game Description for {game} has game field {result.game}") return result
def _game_db_hash(game: RandovaniaGame) -> int: data = default_data.read_json_then_binary(game)[1] return bitpacking.single_byte_hash(json.dumps(data, separators=(',', ':')).encode("UTF-8"))
def resource_database_for(game: RandovaniaGame) -> ResourceDatabase: return read_resource_database( game, default_data.read_json_then_binary(game)[1]["resource_database"])
def game_description_for(game: RandovaniaGame) -> GameDescription: return data_reader.decode_data(default_data.read_json_then_binary(game)[1])
def echoes_game_data() -> dict: return default_data.read_json_then_binary(RandovaniaGame.METROID_PRIME_ECHOES)[1]
def corruption_game_data() -> dict: return default_data.read_json_then_binary(RandovaniaGame.METROID_PRIME_CORRUPTION)[1]
def corruption_game_data() -> dict: return default_data.read_json_then_binary(RandovaniaGame.PRIME3)[1]
def blank_game_data() -> dict: return default_data.read_json_then_binary(RandovaniaGame.BLANK)[1]
def game_data(self) -> dict: return default_data.read_json_then_binary(self.game)[1]
def echoes_game_data() -> dict: return default_data.read_json_then_binary(RandovaniaGame.PRIME2)[1]