Esempio n. 1
0
 def upgrade_bnp(self, params=None):
     path = self.window.create_file_dialog(
         file_types=tuple(["BOTW Nano Patch (*.bnp)"]))
     if not path:
         return
     path = Path(path if isinstance(path, str) else path[0])
     if not path.exists():
         return
     tmp_dir = install.open_mod(path)
     output = self.window.create_file_dialog(
         webviewb.SAVE_DIALOG,
         file_types=tuple(["BOTW Nano Patch (*.bnp)"]))
     if not output:
         return
     output = Path(output if isinstance(output, str) else output[0])
     print(f"Saving output file to {str(output)}...")
     x_args = [install.ZPATH, "a", str(output), f'{str(tmp_dir / "*")}']
     if SYSTEM == "Windows":
         run(
             x_args,
             stdout=PIPE,
             stderr=PIPE,
             creationflags=util.CREATE_NO_WINDOW,
             check=True,
         )
     else:
         run(x_args, stdout=PIPE, stderr=PIPE, check=True)
Esempio n. 2
0
 def convert_bnp(self, params) -> List[str]:
     bnp = Path(params["mod"])
     mod = install.open_mod(bnp)
     warnings = dev.convert_mod(mod, params["wiiu"], params["warn"])
     out = self.window.create_file_dialog(
         webviewb.SAVE_DIALOG,
         file_types=("BOTW Nano Patch (*.bnp)", "All files (*.*)"),
         save_filename=bnp.stem +
         f"_{'wiiu' if params['wiiu'] else 'switch'}.bnp",
     )
     if not out:
         raise Exception("canceled")
     x_args = [
         util.get_7z_path(),
         "a",
         out if isinstance(out, str) else out[0],
         f'{str(mod / "*")}',
     ]
     if system() == "Windows":
         result = run(
             x_args,
             capture_output=True,
             universal_newlines=True,
             creationflags=util.CREATE_NO_WINDOW,
             check=False,
         )
     else:
         result = run(x_args,
                      capture_output=True,
                      universal_newlines=True,
                      check=False)
     if result.stderr:
         raise RuntimeError(result.stderr)
     rmtree(mod, ignore_errors=True)
     return warnings
Esempio n. 3
0
def create_bnp_mod(mod: Path,
                   output: Path,
                   meta: dict,
                   options: Optional[dict] = None):
    if isinstance(mod, str):
        mod = Path(mod)
    if not options:
        options = {"options": {}, "disable": []}

    if mod.is_file():
        print("Extracting mod...")
        tmp_dir: Path = install.open_mod(mod)
    elif mod.is_dir():
        print(f"Loading mod from {str(mod)}...")
        tmp_dir = Path(TemporaryDirectory().name)
        shutil.copytree(mod, tmp_dir)
    else:
        print(f"Error: {str(mod)} is neither a valid file nor a directory")
        return

    if not ((tmp_dir / util.get_content_path()).exists() or
            (tmp_dir / util.get_dlc_path()).exists()):
        if (tmp_dir.parent / util.get_content_path()).exists():
            tmp_dir = tmp_dir.parent
        elif util.get_settings("wiiu") and (tmp_dir / "Content").exists():
            (tmp_dir / "Content").rename(tmp_dir / "content")
        else:
            raise FileNotFoundError(
                "This mod does not appear to have a valid folder structure")

    if (tmp_dir / "rules.txt").exists():
        (tmp_dir / "rules.txt").unlink()

    if "showDepends" in meta:
        del meta["showDepends"]
    depend_string = f"{meta['name']}=={meta['version']}"
    meta["id"] = urlsafe_b64encode(depend_string.encode("utf8")).decode("utf8")
    any_platform = (options.get("options",
                                dict()).get("general",
                                            dict()).get("agnostic", False))
    meta["platform"] = ("any" if any_platform else
                        "wiiu" if util.get_settings("wiiu") else "switch")
    (tmp_dir / "info.json").write_text(dumps(meta,
                                             ensure_ascii=False,
                                             indent=2),
                                       encoding="utf-8")

    with Pool(maxtasksperchild=500) as pool:
        yml_files = set(tmp_dir.glob("**/*.yml"))
        if yml_files:
            print("Compiling YAML documents...")
            pool.map(_do_yml, yml_files)

        hashes = util.get_hash_table(util.get_settings("wiiu"))
        print("Packing SARCs...")
        _pack_sarcs(tmp_dir, hashes, pool)
        for folder in {d for d in tmp_dir.glob("options/*") if d.is_dir()}:
            _pack_sarcs(folder, hashes, pool)

        for option_dir in tmp_dir.glob("options/*"):
            for file in {
                    f
                    for f in option_dir.rglob("**/*")
                    if (f.is_file() and (tmp_dir /
                                         f.relative_to(option_dir)).exists())
            }:
                data1 = (tmp_dir / file.relative_to(option_dir)).read_bytes()
                data2 = file.read_bytes()
                if data1 == data2:
                    util.vprint(
                        f"Removing {file} from option {option_dir.name}, "
                        "identical to base mod")
                    file.unlink()
                del data1
                del data2

        if not options:
            options = {"disable": [], "options": {}}
        options["options"]["texts"] = {"all_langs": True}

        try:
            _make_bnp_logs(tmp_dir, options)
            for option_dir in {
                    d
                    for d in tmp_dir.glob("options/*") if d.is_dir()
            }:
                _make_bnp_logs(option_dir, options)
        except Exception as err:  # pylint: disable=broad-except
            pool.terminate()
            raise Exception(
                f"There was an error generating change logs for your mod. {str(err)}"
            )

        _clean_sarcs(tmp_dir, hashes, pool)
        for folder in {d for d in tmp_dir.glob("options/*") if d.is_dir()}:
            _clean_sarcs(folder, hashes, pool)

    print("Cleaning any junk files...")
    for file in {f for f in tmp_dir.rglob("**/*") if f.is_file()}:
        if "logs" in file.parts:
            continue
        if (file.suffix in {".yml", ".json", ".bak", ".tmp", ".old"}
                and file.stem != "info"):
            file.unlink()

    print("Removing blank folders...")
    for folder in reversed(list(tmp_dir.rglob("**/*"))):
        if folder.is_dir() and not list(folder.glob("*")):
            shutil.rmtree(folder)

    print(f"Saving output file to {str(output)}...")
    x_args = [util.get_7z_path(), "a", str(output), f'{str(tmp_dir / "*")}']
    if system() == "Windows":
        subprocess.run(
            x_args,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            creationflags=util.CREATE_NO_WINDOW,
            check=True,
        )
    else:
        subprocess.run(x_args,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE,
                       check=True)
    shutil.rmtree(tmp_dir, ignore_errors=True)
    print("Conversion complete.")