def find_modded_files( tmp_dir: Path, pool: Optional[multiprocessing.pool.Pool] = None ) -> List[Union[Path, str]]: modded_files = [] if isinstance(tmp_dir, str): tmp_dir = Path(tmp_dir) if (tmp_dir / util.get_dlc_path()).exists(): try: util.get_aoc_dir() except FileNotFoundError: raise FileNotFoundError( "This mod uses DLC files, but BCML cannot locate the DLC folder in " "your game dump.") aoc_field = (tmp_dir / util.get_dlc_path() / ("0010" if util.get_settings("wiiu") else "") / "Pack" / "AocMainField.pack") if aoc_field.exists() and aoc_field.stat().st_size > 0: if not list((tmp_dir / util.get_dlc_path() / ("0010" if util.get_settings("wiiu") else "") ).rglob("Map/**/?-?_*.smubin")): aoc_pack = oead.Sarc(aoc_field.read_bytes()) for file in aoc_pack.get_files(): ex_out = (tmp_dir / util.get_dlc_path() / ("0010" if util.get_settings("wiiu") else "") / file.name) ex_out.parent.mkdir(parents=True, exist_ok=True) ex_out.write_bytes(file.data) aoc_field.write_bytes(b"") this_pool = pool or Pool(maxtasksperchild=500) results = this_pool.map( partial(_check_modded, tmp_dir=tmp_dir), { f for f in tmp_dir.rglob("**/*") if f.is_file() and "options" not in f.relative_to(tmp_dir).parts }, ) for result in results: if result: modded_files.append(result) total = len(modded_files) print(f'Found {total} modified file{"s" if total > 1 else ""}') total = 0 sarc_files = {f for f in modded_files if f.suffix in util.SARC_EXTS} if sarc_files: print("Scanning files packed in SARCs...") for files in this_pool.imap_unordered( partial(find_modded_sarc_files, tmp_dir=tmp_dir), sarc_files): total += len(files) modded_files.extend(files) print(f'Found {total} modified packed file{"s" if total > 1 else ""}') if not pool: this_pool.close() this_pool.join() return modded_files
def find_modded_files( tmp_dir: Path, pool: Optional[multiprocessing.pool.Pool] = None ) -> List[Union[Path, str]]: modded_files = [] if isinstance(tmp_dir, str): tmp_dir = Path(tmp_dir) if (tmp_dir / util.get_dlc_path()).exists(): try: util.get_aoc_dir() except FileNotFoundError: raise FileNotFoundError( "This mod uses DLC files, but BCML cannot locate the DLC folder in " "your game dump.") aoc_field = (tmp_dir / util.get_dlc_path() / ("0010" if util.get_settings("wiiu") else "") / "Pack" / "AocMainField.pack") if aoc_field.exists() and aoc_field.stat().st_size > 0: if not list((tmp_dir / util.get_dlc_path() / ("0010" if util.get_settings("wiiu") else "") ).rglob("Map/**/?-?_*.smubin")): aoc_pack = oead.Sarc(aoc_field.read_bytes()) for file in aoc_pack.get_files(): ex_out = (tmp_dir / util.get_dlc_path() / ("0010" if util.get_settings("wiiu") else "") / file.name) ex_out.parent.mkdir(parents=True, exist_ok=True) ex_out.write_bytes(file.data) aoc_field.write_bytes(b"") modded_files = [ f if "//" in f else Path(f) for f in rsext.find_modified_files( str(tmp_dir), util.get_settings("wiiu")) ] return modded_files
def find_modded_files(tmp_dir: Path, verbose: bool = False, original_pool: Pool = None) -> List[Union[Path, str]]: """ Detects all of the modified files in an extracted mod :param tmp_dir: The path to the base directory of the mod. :type tmp_dir: class:`pathlib.Path` :param deep_merge: Whether to log diffs for individual AAMP and BYML files, defaults to False :type deep_merge: bool, optional :param verbose: Specifies whether to return more detailed output :type verbose: bool, optional :returns: Returns a tuple with a dict of modified files and the RSTB entries, a list of changes, and (if deep merge) diffs of modded BYML and AAMP files :rtype: (dict of class:`pathlib.Path`: int, list of str, dict of str: str) """ modded_files = [] if isinstance(tmp_dir, str): tmp_dir = Path(tmp_dir) rstb_path = tmp_dir / 'content' / 'System' / 'Resource' /\ 'ResourceSizeTable.product.srsizetable' if rstb_path.exists(): rstb_path.unlink() if (tmp_dir / 'aoc').exists: try: util.get_aoc_dir() except FileNotFoundError as err: err.error_text = ( 'This mod uses DLC files, but you do not appear to have the DLC ' 'installed. If you still want to use this mod, unpack it and ' 'remove the "aoc" folder.') raise err aoc_field = tmp_dir / 'aoc' / '0010' / 'Pack' / 'AocMainField.pack' if aoc_field.exists() and aoc_field.stat().st_size > 0: with aoc_field.open('rb') as a_file: sarc.read_file_and_make_sarc(a_file).extract_to_dir( str(tmp_dir / 'aoc' / '0010')) aoc_field.write_bytes(b'') for file in tmp_dir.rglob('**/*'): if file.is_file(): canon = util.get_canon_name(file.relative_to(tmp_dir).as_posix()) if canon is None: if verbose: print( f'Ignored unknown file {file.relative_to(tmp_dir).as_posix()}' ) continue if util.is_file_modded(canon, file, True): modded_files.append(file) if verbose: print(f'Found modded file {canon}') else: if 'Aoc/0010/Map/MainField' in canon: file.unlink() if verbose: print(f'Ignored unmodded file {canon}') continue total = len(modded_files) print(f'Found {total} modified file{"s" if total > 1 else ""}') total = 0 sarc_files = [ file for file in modded_files if file.suffix in util.SARC_EXTS ] if sarc_files: print(f'Scanning files packed in SARCs...') num_threads = min(len(sarc_files), cpu_count() - 1) pool = original_pool or Pool(processes=num_threads) modded_sarc_files = pool.map( partial(find_modded_sarc_files, tmp_dir=tmp_dir, verbose=verbose), sarc_files) for files in modded_sarc_files: total += len(files) modded_files.extend(files) if not original_pool: pool.close() pool.join() print(f'Found {total} modified packed file{"s" if total > 1 else ""}') return modded_files