示例#1
0
 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)
示例#2
0
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
示例#3
0
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]
示例#4
0
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
示例#5
0
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(""))
示例#6
0
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()}")
示例#7
0
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(""))
示例#8
0
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(""))
示例#9
0
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
示例#10
0
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)
示例#11
0
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)
示例#12
0
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
示例#13
0
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
示例#14
0
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
示例#15
0
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"))
示例#16
0
def resource_database_for(game: RandovaniaGame) -> ResourceDatabase:
    return read_resource_database(
        game,
        default_data.read_json_then_binary(game)[1]["resource_database"])
示例#17
0
def game_description_for(game: RandovaniaGame) -> GameDescription:
    return data_reader.decode_data(default_data.read_json_then_binary(game)[1])
示例#18
0
def echoes_game_data() -> dict:
    return default_data.read_json_then_binary(RandovaniaGame.METROID_PRIME_ECHOES)[1]
示例#19
0
def corruption_game_data() -> dict:
    return default_data.read_json_then_binary(RandovaniaGame.METROID_PRIME_CORRUPTION)[1]
示例#20
0
def corruption_game_data() -> dict:
    return default_data.read_json_then_binary(RandovaniaGame.PRIME3)[1]
示例#21
0
def blank_game_data() -> dict:
    return default_data.read_json_then_binary(RandovaniaGame.BLANK)[1]
示例#22
0
 def game_data(self) -> dict:
     return default_data.read_json_then_binary(self.game)[1]
示例#23
0
def echoes_game_data() -> dict:
    return default_data.read_json_then_binary(RandovaniaGame.PRIME2)[1]