From ceff61930b70ee47f00210e64f0f8a9d0e740028 Mon Sep 17 00:00:00 2001 From: NinjaCheetah <58050615+NinjaCheetah@users.noreply.github.com> Date: Thu, 12 Dec 2024 20:07:51 -0500 Subject: [PATCH] Added command to get info about an EmuNAND --- commands/nand/emunand.py | 120 +++++++++++++++++++++++++++++++++++++++ wiipy.py | 8 ++- 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/commands/nand/emunand.py b/commands/nand/emunand.py index 798960d..bb6a365 100644 --- a/commands/nand/emunand.py +++ b/commands/nand/emunand.py @@ -1,11 +1,131 @@ # "commands/nand/emunand.py" from WiiPy by NinjaCheetah # https://github.com/NinjaCheetah/WiiPy +import math import pathlib import libWiiPy from modules.core import fatal_error +def handle_emunand_info(args): + emunand = libWiiPy.nand.EmuNAND(args.emunand) + # Basic info. + print(f"EmuNAND Info") + print(f" Path: {str(emunand.emunand_root.absolute())}") + is_vwii = False + try: + tmd = emunand.get_title_tmd("0000000100000002") + is_vwii = bool(tmd.vwii) + print(f" System Menu Version: {libWiiPy.title.title_ver_dec_to_standard(tmd.title_version, '0000000100000002', + vwii=is_vwii)}") + except FileNotFoundError: + print(f" System Menu Version: None") + settings_path = emunand.title_dir.joinpath("00000001", "00000002", "data", "setting.txt") + if settings_path.exists(): + settings = libWiiPy.nand.SettingTxt() + settings.load(settings_path.read_bytes()) + print(f" System Region: {settings.area}") + else: + print(f" System Region: N/A") + if is_vwii: + print(f" Type: vWii") + else: + print(f" Type: Wii") + categories = emunand.get_installed_titles() + installed_count = 0 + for category in categories: + if category.type != "00010000": + for _ in category.titles: + installed_count += 1 + print(f" Installed Titles: {installed_count}") + total_size = sum(file.stat().st_size for file in emunand.emunand_root.rglob('*')) + total_size_blocks = math.ceil(total_size / 131072) + print(f" Space Used: {total_size_blocks} blocks ({round(total_size / 1048576, 2)} MB)") + print("") + + installed_ioses = [] + installed_titles = [] + disc_titles = [] + for category in categories: + if category.type == "00000001": + ioses = [] + for title in category.titles: + if title != "00000002": + ioses.append(int(title, 16)) + ioses.sort() + installed_ioses = [f"00000001{i:08X}".upper() for i in ioses] + elif category.type != "00010000": + for title in category.titles: + installed_titles.append(f"{category.type}{title}".upper()) + elif category.type == "00010000": + for title in category.titles: + if title != "48415A41": + disc_titles.append(f"{category.type}{title}".upper()) + + print(f"System Titles:") + for ios in installed_ioses: + if ios[8:] in ["00000100", "00000101", "00000200", "00000201"]: + if ios[8:] == "00000100": + print(f" BC ({ios.upper()})") + elif ios[8:] == "00000101": + print(f" MIOS ({ios.upper()})") + elif ios[8:] == "00000200": + print(f" BC-NAND ({ios.upper()})") + elif ios[8:] == "00000201": + print(f" BC-WFS ({ios.upper()})") + tmd = emunand.get_title_tmd(f"{ios}") + print(f" Version: {tmd.title_version}") + else: + print(f" IOS{int(ios[-2:], 16)} ({ios.upper()})") + tmd = emunand.get_title_tmd(f"{ios}") + print(f" Version: {tmd.title_version} ({tmd.title_version_converted})") + print("") + + print(f"Installed Titles:") + missing_ioses = [] + for title in installed_titles: + ascii_tid = "" + try: + ascii_tid = (bytes.fromhex(title[8:].replace("00", "30"))).decode("ascii") + except UnicodeDecodeError: + pass + if ascii_tid.isalnum(): + print(f" {title.upper()} ({ascii_tid})") + else: + print(f" {title.upper()}") + tmd = emunand.get_title_tmd(f"{title}") + print(f" Version: {tmd.title_version}") + print(f" Required IOS: IOS{int(tmd.ios_tid[-2:], 16)} ({tmd.ios_tid.upper()})", end="", flush=True) + if tmd.ios_tid.upper() not in installed_ioses: + print(" *") + if tmd.ios_tid not in missing_ioses: + missing_ioses.append(tmd.ios_tid) + else: + print("") + print("") + + if disc_titles: + print(f"Save data was found for the following disc titles:") + for disc in disc_titles: + ascii_tid = "" + try: + ascii_tid = (bytes.fromhex(disc[8:].replace("00", "30"))).decode("ascii") + except UnicodeDecodeError: + pass + if ascii_tid.isalnum(): + print(f" {disc.upper()} ({ascii_tid})") + else: + print(f" {disc.upper()}") + print("") + if missing_ioses: + print(f"Some titles installed are missing their required IOS. These missing IOSes are marked with a * in the " + f"title list above. If these IOSes are not installed, the titles requiring them will not launch. The " + f"IOSes required but not installed are:") + for missing in missing_ioses: + print(f" IOS{int(missing[-2:], 16)} ({missing.upper()})") + print("") + + def handle_emunand_title(args): emunand = libWiiPy.nand.EmuNAND(args.emunand) if args.skip_hash: diff --git a/wiipy.py b/wiipy.py index f76c3fb..a416a74 100644 --- a/wiipy.py +++ b/wiipy.py @@ -76,12 +76,18 @@ if __name__ == "__main__": emunand_parser = subparsers.add_parser("emunand", help="manage Wii EmuNAND directories", description="manage Wii EmuNAND directories") emunand_subparsers = emunand_parser.add_subparsers(title="emunand", dest="emunand", required=True) + # Info EmuNAND subcommand. + emunand_info_parser = emunand_subparsers.add_parser("info", help="show info about an EmuNAND", + description="show info about an EmuNAND") + emunand_info_parser.set_defaults(func=handle_emunand_info) + emunand_info_parser.add_argument("emunand", metavar="EMUNAND", type=str, + help="path of the EmuNAND directory") # Title EmuNAND subcommand. emunand_title_parser = emunand_subparsers.add_parser("title", help="manage titles on an EmuNAND", description="manage titles on an EmuNAND") emunand_title_parser.set_defaults(func=handle_emunand_title) emunand_title_parser.add_argument("emunand", metavar="EMUNAND", type=str, - help="path to the target EmuNAND directory") + help="path of the target EmuNAND directory") emunand_title_install_group = emunand_title_parser.add_mutually_exclusive_group(required=True) emunand_title_install_group.add_argument("--install", metavar="WAD", type=str, help="install the target WAD(s) to an EmuNAND (can be a single file or a "