Esempio n. 1
0
def load_rstb(be: bool, file: Path = None) -> ResourceSizeTable:
    table = ResourceSizeTable(b"", be=be)
    if not file:
        ver = "wiiu" if be else "switch"
        file = EXEC_DIR / "data" / ver / "rstb.json"
    ref_contents = json.loads(file.read_text(), encoding="utf-8")

    def parse_hash(file: str) -> int:
        try:
            return int(file)
        except ValueError:
            return crc32(file.encode("utf8"))

    table.crc32_map = {parse_hash(k): v for k, v in ref_contents["hash_map"].items()}
    table.name_map = {k: v for k, v in ref_contents["name_map"].items()}
    return table
Esempio n. 2
0
def load_rstb(be: bool, file: Path = None) -> ResourceSizeTable:
    table = ResourceSizeTable(b'', be=be)
    if not file:
        ver = 'wiiu' if be else 'switch'
        file = EXEC_DIR / 'data' / ver / 'rstb.json'
    ref_contents = json.loads(file.read_text(), encoding='utf-8')

    def parse_hash(file: str) -> int:
        try:
            return int(file)
        except ValueError:
            return crc32(file.encode('utf8'))

    table.crc32_map = {
        parse_hash(k): v
        for k, v in ref_contents['hash_map'].items()
    }
    table.name_map = {k: v for k, v in ref_contents['name_map'].items()}
    return table
Esempio n. 3
0
def open_rstb(file: Path) -> ResourceSizeTable:
    data = file.read_bytes()
    if data[0:4] == b"Yaz0":
        data = decompress(data)
    be = True
    rstb = ResourceSizeTable(data, be=True)
    random_tests = {
        "EventFlow/PictureMemory.bfevfl",
        "Camera/Demo648_0/C04-0.bcamanim",
        "Effect/FldObj_ScaffoldIronParts_A_01.esetlist",
        "Physics/TeraMeshRigidBody/MainField/9-8.hktmrb",
    }
    if not any(rstb.is_in_table(f) for f in random_tests):
        del rstb
        rstb = ResourceSizeTable(data, be=False)
        be = False
        if not any(rstb.is_in_table(f) for f in random_tests):
            raise ValueError("File does not appeat to be a valid BOTW RSTB")
    return rstb, be
Esempio n. 4
0
def _fix_rstb_resource_size(path: Path, rel_path: Path,
                            table: rstb.ResourceSizeTable, wiiu: bool,
                            is_aoc: bool):
    resource_path = _get_resource_path_for_rstb(rel_path, is_aoc)
    if not _should_be_listed_in_rstb(Path(resource_path), rel_path=rel_path):
        sys.stderr.write(
            f'{Fore.WHITE}{rel_path}{Style.RESET_ALL} ({resource_path})\n')
        return
    resource_size = size_calculator.calculate_file_size(str(path), wiiu=wiiu)
    if resource_size == 0:
        sys.stderr.write(
            f'{Fore.WHITE}{rel_path}{Style.RESET_ALL} ({resource_path}) {Style.BRIGHT}{Fore.YELLOW}*** complex ***{Style.RESET_ALL}\n'
        )
        table.delete_entry(resource_path)
        return

    notes = []
    prev_resource_size = 0
    if not table.is_in_table(resource_path):
        notes.append(f'{Style.BRIGHT}{Fore.RED}*** NEW ***{Style.RESET_ALL}')
    else:
        prev_resource_size = table.get_size(resource_path)

    sys.stderr.write(
        f'{Fore.WHITE}{rel_path}{Style.RESET_ALL} ({resource_path}) [0x%x -> 0x%x bytes] %s\n'
        % (prev_resource_size, resource_size, ' '.join(notes)))
    table.set_size(resource_path, resource_size)
Esempio n. 5
0
def merge_rstb(table: ResourceSizeTable, changes: dict) -> (ResourceSizeTable, List[str]):
    """
    Merges changes from a list of RSTB mods into a single RSTB

    :param table: The base RSTB to merge into. This will be directly modified.
    :type table: class:`rstb.ResourceSizeTable`
    :param changes: A dict of resources and their RSTB sizes.
    :type changes: dict of str: int
    :param verbose: Whether to log changes in full detail. Defaults to false.
    :type verbose: bool, optional
    :returns: Returns a list of strings recording RSTB changes made.
    :rtype: list of str
    """
    change_list = []
    spaces = '  '
    change_count = {
        'updated': 0,
        'deleted': 0,
        'added': 0,
        'warning': 0
    }
    for change in changes:
        if zlib.crc32(change.encode()) in table.crc32_map:
            newsize = int(changes[change]['size'])
            if newsize == 0:
                if not changes[change]['leave']:
                    if change.endswith('.bas') or change.endswith('.baslist'):
                        change_list.append((
                            f'{spaces}WARNING: Could not calculate or safely remove RSTB size for'
                            f'{change}. This may need to be corrected manually, or the game could '
                            'become unstable',
                            False
                        ))
                        change_count['warning'] += 1
                        continue
                    else:
                        table.delete_entry(change)
                        change_list.append(
                            (f'{spaces}Deleted RSTB entry for {change}', True))
                        change_count['deleted'] += 1
                        continue
                else:
                    change_list.append(
                        (f'{spaces}Skipped deleting RSTB entry for {change}', True))
                    continue
            oldsize = table.get_size(change)
            if newsize <= oldsize:
                if changes[change]['shrink']:
                    table.set_size(change, newsize)
                    change_list.append((
                        f'{spaces}Updated RSTB entry for {change} from {oldsize} to {newsize}',
                        True
                    ))
                    change_count['updated'] += 1
                    continue
                else:
                    change_list.append(
                        (f'{spaces}Skipped updating RSTB entry for {change}', True))
                    continue
            elif newsize > oldsize:
                table.set_size(change, newsize)
                change_list.append(
                    (f'{spaces}Updated RSTB entry for {change} from {oldsize} to {newsize}', True))
                change_count['updated'] += 1
        else:
            newsize = int(changes[change]['size'])
            if newsize == 0:
                change_list.append(
                    (f'{spaces}Could not calculate size for new entry {change}, skipped', True))
                continue
            table.set_size(change, newsize)
            change_list.append(
                (f'{spaces}Added new RSTB entry for {change} with value {newsize}', True))
            change_count['added'] += 1
    change_list.append((
        f'RSTB merge complete: updated {change_count["updated"]} entries, deleted'
        f' {change_count["deleted"]} entries, added {change_count["added"]} entries',
        False
    ))
    return table, change_list