Пример #1
0
def merge_dungeonstatic(diffs: dict = None):
    """Merges all changes to the CDungeon Static.smubin"""
    if not diffs:
        return

    new_static = oead.byml.from_binary(
        util.decompress((util.get_aoc_dir() / "Map" / "CDungeon" /
                         "Static.smubin").read_bytes()))

    base_dungeons = [str(dungeon["Map"]) for dungeon in new_static["StartPos"]]
    for dungeon, diff in diffs.items():
        if dungeon not in base_dungeons:
            new_static["StartPos"].append(diff)
        else:
            for key, value in diff.items():
                new_static["StartPos"][base_dungeons.index(
                    dungeon)][key] = value

    output_static = (util.get_master_modpack_dir() / util.get_dlc_path() /
                     ("0010" if util.get_settings("wiiu") else "") / "Map" /
                     "CDungeon" / "Static.smubin")
    output_static.parent.mkdir(parents=True, exist_ok=True)
    output_static.write_bytes(
        util.compress(
            oead.byml.to_binary(new_static,
                                big_endian=util.get_settings("wiiu"))))
Пример #2
0
    def perform_merge(self):
        no_del = self._options.get("no_del", False)
        shutil.rmtree(
            str(util.get_master_modpack_dir() / util.get_dlc_path() /
                ("0010" if util.get_settings("wiiu") else "") / "Map" /
                "MainField"),
            ignore_errors=True,
        )
        shutil.rmtree(
            str(util.get_master_modpack_dir() / util.get_content_path() /
                "Map" / "MainField"),
            ignore_errors=True,
        )
        log_path = util.get_master_modpack_dir() / "logs" / "map.log"
        if log_path.exists():
            log_path.unlink()
        print("Loading map mods...")
        map_diffs = self.consolidate_diffs(self.get_all_diffs())
        util.vprint("All map diffs:")
        util.vprint(map_diffs)
        if not map_diffs:
            print("No map merge necessary")
            return
        aoc_pack = (util.get_master_modpack_dir() / util.get_dlc_path() /
                    ("0010" if util.get_settings("wiiu") else "") / "Pack" /
                    "AocMainField.pack")
        if not aoc_pack.exists() or aoc_pack.stat().st_size > 0:
            print("Emptying AocMainField.pack...")
            aoc_pack.parent.mkdir(parents=True, exist_ok=True)
            aoc_pack.write_bytes(b"")

        rstb_vals = {}
        rstb_calc = rstb.SizeCalculator()
        print("Merging modded map units...")

        pool = self._pool or Pool(maxtasksperchild=500)
        rstb_results = pool.map(
            partial(merge_map, rstb_calc=rstb_calc, no_del=no_del),
            map_diffs.items(),
        )
        for result in rstb_results:
            rstb_vals[result[util.get_dlc_path()][0]] = result[
                util.get_dlc_path()][1]
            rstb_vals[result["main"][0]] = result["main"][1]
        if not self._pool:
            pool.close()
            pool.join()

        print("Adjusting RSTB...")
        log_path.parent.mkdir(parents=True, exist_ok=True)
        with log_path.open("w", encoding="utf-8") as l_file:
            for canon, val in rstb_vals.items():
                l_file.write(f"{canon},{val}\n")
        print("Map merge complete")
Пример #3
0
def merge_dungeonstatic(diffs: dict = None):
    """Merges all changes to the CDungeon Static.smubin"""
    if not diffs:
        try:
            (util.get_master_modpack_dir() / "logs" /
             "dungeonstatic.smubin").unlink()
        except:
            pass
        return

    try:
        new_static = oead.byml.from_binary(
            util.decompress((util.get_aoc_dir() / "Map" / "CDungeon" /
                             "Static.smubin").read_bytes()))
    except FileNotFoundError:
        new_static = oead.byml.from_binary(
            util.get_nested_file_bytes(
                f"{util.get_game_file('Pack/Bootup.pack')}//Map/CDungeon/Static.smubin"
            ))

    base_names = [
        f"{str(spawn_point['Map'])}___{str(spawn_point['PosName'])}"
        for spawn_point in new_static["StartPos"]
    ]
    for spawn_name, diff in diffs.items():
        if "___" not in spawn_name:
            spawn_name = f"{spawn_name}___Entrance_1"
        if spawn_name not in base_names:
            new_static["StartPos"].append(diff)
        else:
            for key, value in diff.items():
                new_static["StartPos"][base_names.index(
                    spawn_name)][key] = value

    data = util.compress(
        oead.byml.to_binary(new_static, big_endian=util.get_settings("wiiu")))
    try:
        util.get_aoc_dir()
        output_static = (util.get_master_modpack_dir() / util.get_dlc_path() /
                         ("0010" if util.get_settings("wiiu") else "") /
                         "Map" / "CDungeon" / "Static.smubin")
    except FileNotFoundError:
        output_static = util.get_master_modpack_dir(
        ) / "logs" / "dungeonstatic.smubin"
        util.inject_file_into_sarc(
            "Map/CDungeon/Static.smubin",
            data,
            "Pack/Bootup.pack",
            create_sarc=True,
        )
    output_static.parent.mkdir(parents=True, exist_ok=True)
    output_static.write_bytes(data)
Пример #4
0
 def generate_diff(self, mod_dir: Path, modded_files: List[Union[str, Path]]):
     diffs = {}
     bootups = {util.get_file_language(file): file for file in modded_files
                if 'Bootup_' in str(file) and 'Graphics' not in str(file) 
                and isinstance(file, Path)}
     if not bootups:
         return {}
     mod_langs = list(bootups.keys())
     lang_map = {}
     save_langs = LANGUAGES if not self._options['user_only'] else [util.get_settings()['lang']]
     for lang in save_langs:
         if lang in mod_langs:
             lang_map[lang] = lang
         elif lang[2:4] in [l[2:4] for l in mod_langs]:
             lang_map[lang] = [l for l in mod_langs if l[2:4] == lang[2:4]][0]
         else:
             lang_map[lang] = [l for l in LANGUAGES if l in mod_langs][0]
     lang_diffs = {}
     from io import StringIO
     for lang in set(lang_map.values()):
         dict_diffs, added = get_text_mods_from_bootup(bootups[lang], lang=lang)[:2]
         str_buf = StringIO()
         yaml.dump(dict_diffs, str_buf, allow_unicode=True, encoding='utf-8')
         lang_diffs[lang] = (str_buf.getvalue(), added)
         del str_buf
     for u_lang, t_lang in lang_map.items():
         diffs[u_lang] = lang_diffs[t_lang]
     return diffs
Пример #5
0
 def perform_merge(self):
     diffs = self.consolidate_diffs(self.get_all_diffs())
     output: Path
     static_data: Path
     try:
         util.get_aoc_dir()
         output = (util.get_master_modpack_dir() / util.get_dlc_path() /
                   ("0010" if util.get_settings("wiiu") else "") /
                   STATIC_PATH)
         static_data = util.get_game_file("Map/MainField/Static.smubin",
                                          aoc=True).read_bytes()
     except FileNotFoundError:
         output = util.get_master_modpack_dir(
         ) / "logs" / "mainstatic.smubin"
         static_data = util.get_nested_file_bytes(
             (str(util.get_game_file("Pack/Bootup.pack")) +
              "//Map/MainField/Static.smubin"),
             unyaz=False,
         )
     if not diffs:
         try:
             output.unlink()
         except:
             pass
         return
     stock_static = oead.byml.from_binary(util.decompress(static_data))
     merged = Hash()
     for cat in stock_static:
         if cat in diffs:
             items = {get_id(item): item for item in stock_static[cat]}
             util.dict_merge(items, diffs[cat])
             merged[cat] = Array([
                 item for _, item in items.items() if "remove" not in item
             ])
         else:
             merged[cat] = stock_static[cat]
     data = util.compress(
         oead.byml.to_binary(merged, big_endian=util.get_settings("wiiu")))
     output.parent.mkdir(parents=True, exist_ok=True)
     output.write_bytes(data)
     if "mainstatic" in str(output):
         util.inject_file_into_sarc(
             "Map/MainField/Static.smubin",
             data,
             "Pack/Bootup.pack",
             create_sarc=True,
         )
Пример #6
0
 def generate_diff(self, mod_dir: Path, modded_files: List[Union[str,
                                                                 Path]]):
     mod_data: bytes
     stock_data: bytes
     if (mod_dir / util.get_dlc_path() /
         ("0010" if util.get_settings("wiiu") else "") /
             STATIC_PATH) in modded_files:
         mod_data = (mod_dir / util.get_dlc_path() /
                     ("0010" if util.get_settings("wiiu") else "") /
                     STATIC_PATH).read_bytes()
         stock_data = util.get_game_file("Map/MainField/Static.smubin",
                                         aoc=True).read_bytes()
     elif (f"{util.get_content_path()}/Pack/Bootup.pack//Map/MainField/Static.smubin"
           ) in modded_files:
         mod_data = util.get_nested_file_bytes(
             (str(mod_dir / util.get_content_path() / "Pack" /
                  "Bootup.pack") + "//Map/MainField/Static.smubin"),
             unyaz=False,
         )
         stock_data = util.get_nested_file_bytes(
             (str(util.get_game_file("Pack/Bootup.pack")) +
              "//Map/MainField/Static.smubin"),
             unyaz=False,
         )
     else:
         return None
     stock_static: Hash = oead.byml.from_binary(util.decompress(stock_data))
     mod_static: Hash = oead.byml.from_binary(util.decompress(mod_data))
     diffs = Hash()
     for cat in stock_static:
         if cat not in stock_static:
             continue
         stock_items = {get_id(item): item for item in stock_static[cat]}
         mod_items = {get_id(item): item for item in mod_static[cat]}
         diffs[cat] = Hash({
             item_id: item
             for item_id, item in mod_items.items()
             if item_id not in stock_items or item != stock_items[item_id]
         })
         for item_id, item in [(i1, i2) for i1, i2 in stock_items.items()
                               if i1 not in mod_items]:
             item["remove"] = True
             diffs[cat][item_id] = item
         if not diffs[cat]:
             del diffs[cat]
     return diffs
Пример #7
0
def get_modded_map(map_unit: Union[Map, tuple], tmp_dir: Path) -> Hash:
    if isinstance(map_unit, tuple):
        map_unit = Map(*map_unit)
    map_bytes = None
    aoc_dir = (tmp_dir / util.get_dlc_path() /
               ("0010/content" if util.get_settings("wiiu") else ""))
    if not aoc_dir.exists():
        aoc_dir = tmp_dir / util.get_dlc_path() / "content" / "0010"
        if not aoc_dir.exists():
            aoc_dir = tmp_dir / util.get_dlc_path() / "0010"
    if (aoc_dir / "Pack" / "AocMainField.pack").exists():
        try:
            map_pack = oead.Sarc(
                (aoc_dir / "Pack" / "AocMainField.pack").read_bytes())
        except (RuntimeError, ValueError, oead.InvalidDataError):
            pass
        else:
            try:
                map_bytes = bytes(
                    map_pack.get_file(
                        f"Map/MainField/{map_unit.section}/"
                        f"{map_unit.section}_{map_unit.type}.smubin").data)
            except AttributeError:
                pass
    if not map_bytes:
        if (aoc_dir / "Map" / "MainField" / map_unit.section /
                f"{map_unit.section}_{map_unit.type}.smubin").exists():
            map_bytes = (
                aoc_dir / "Map" / "MainField" / map_unit.section /
                f"{map_unit.section}_{map_unit.type}.smubin").read_bytes()
        elif (tmp_dir / util.get_content_path() / "Map" / "MainField" /
              map_unit.section /
              f"{map_unit.section}_{map_unit.type}.smubin").exists():
            map_bytes = (
                tmp_dir / util.get_content_path() / "Map" / "MainField" /
                map_unit.section /
                f"{map_unit.section}_{map_unit.type}.smubin").read_bytes()
    if not map_bytes:
        raise FileNotFoundError(
            f"Oddly, the modded map {map_unit.section}_{map_unit.type}.smubin "
            "could not be found.")
    map_bytes = util.decompress(map_bytes)
    return oead.byml.from_binary(map_bytes)
Пример #8
0
    def perform_merge(self):
        shutil.rmtree(
            str(util.get_master_modpack_dir() / util.get_dlc_path() /
                ("0010" if util.get_settings("wiiu") else "") / "Map" /
                "MainField"),
            ignore_errors=True,
        )
        shutil.rmtree(
            str(util.get_master_modpack_dir() / util.get_content_path() /
                "Map" / "MainField"),
            ignore_errors=True,
        )
        log_path = util.get_master_modpack_dir() / "logs" / "map.log"
        if log_path.exists():
            log_path.unlink()
        print("Loading map mods...")
        map_diffs = self.consolidate_diffs(self.get_all_diffs())
        util.vprint("All map diffs:")
        util.vprint(map_diffs)
        if not map_diffs:
            print("No map merge necessary")
            return
        aoc_pack = (util.get_master_modpack_dir() / util.get_dlc_path() /
                    ("0010" if util.get_settings("wiiu") else "") / "Pack" /
                    "AocMainField.pack")
        if not aoc_pack.exists() or aoc_pack.stat().st_size > 0:
            print("Emptying AocMainField.pack...")
            aoc_pack.parent.mkdir(parents=True, exist_ok=True)
            aoc_pack.write_bytes(b"")

        rstb_vals = {}
        rstb_calc = rstb.SizeCalculator()
        print("Merging modded map units...")

        pool = self._pool or Pool(maxtasksperchild=500)
        rstb_results = pool.map(
            partial(merge_map, rstb_calc=rstb_calc),
            map_diffs.items(),
        )
        for result in rstb_results:
            rstb_vals[result[util.get_dlc_path()][0]] = result[
                util.get_dlc_path()][1]
            rstb_vals[result["main"][0]] = result["main"][1]
        if not self._pool:
            pool.close()
            pool.join()

        stock_static = [m for m in map_diffs if m[1] == "Static"]
        if stock_static:
            title_path = (util.get_master_modpack_dir() /
                          util.get_content_path() / "Pack" / "TitleBG.pack")
            if not title_path.exists():
                title_path.parent.mkdir(parents=True, exist_ok=True)
                shutil.copyfile(util.get_game_file("Pack/TitleBG.pack"),
                                title_path)
            title_bg: oead.SarcWriter = oead.SarcWriter.from_sarc(
                oead.Sarc(title_path.read_bytes()))
            for static in stock_static:
                del title_bg.files[
                    f"Map/MainField/{static[0]}/{static[0]}_Static.smubin"]
            title_path.write_bytes(title_bg.write()[1])
        print("Adjusting RSTB...")
        log_path.parent.mkdir(parents=True, exist_ok=True)
        with log_path.open("w", encoding="utf-8") as l_file:
            for canon, val in rstb_vals.items():
                l_file.write(f"{canon},{val}\n")
        print("Map merge complete")
Пример #9
0
def get_stock_map(map_unit: Union[Map, tuple],
                  force_vanilla: bool = False) -> Hash:
    if isinstance(map_unit, tuple):
        map_unit = Map(*map_unit)
    try:
        aoc_dir = util.get_aoc_dir()
    except FileNotFoundError:
        force_vanilla = True
    map_bytes = None
    map_path: Union[str, Path]
    if force_vanilla:
        try:
            if util.get_settings("wiiu"):
                update = util.get_update_dir()
            else:
                update = util.get_game_dir()
            map_path = (
                update / "Map/MainField/"
                f"{map_unit.section}/{map_unit.section}_{map_unit.type}.smubin"
            )
            if not map_path.exists():
                map_path = (
                    util.get_game_dir() / "Map/MainField/"
                    f"{map_unit.section}/{map_unit.section}_{map_unit.type}.smubin"
                )
            map_bytes = map_path.read_bytes()
        except FileNotFoundError:
            try:
                title_pack = oead.Sarc(
                    util.get_game_file("Pack/TitleBG.pack").read_bytes())
                map_bytes = title_pack.get_file(
                    f"Map/MainField/{map_unit.section}/{map_unit.section}_{map_unit.type}"
                    ".smubin").data
            except (KeyError, RuntimeError, AttributeError):
                map_bytes = None
    else:
        if (aoc_dir / "Pack" / "AocMainField.pack").exists():
            try:
                map_pack = oead.Sarc(
                    (aoc_dir / "Pack" / "AocMainField.pack").read_bytes())
                map_bytes = map_pack.get_file(
                    f"Map/MainField/{map_unit.section}/{map_unit.section}_{map_unit.type}"
                    ".smubin").data
            except (KeyError, RuntimeError, AttributeError):
                map_bytes = None
        if not map_bytes:
            map_path = f"Map/MainField/{map_unit.section}/{map_unit.section}_{map_unit.type}.smubin"
            try:
                map_bytes = util.get_game_file(map_path, aoc=True).read_bytes()
            except FileNotFoundError:
                try:
                    map_bytes = util.get_game_file(map_path).read_bytes()
                except FileNotFoundError:
                    try:
                        title_pack = oead.Sarc(
                            util.get_game_file(
                                "Pack/TitleBG.pack").read_bytes())
                        map_bytes = bytes(
                            title_pack.get_file(
                                f"Map/MainField/{map_unit.section}/"
                                f"{map_unit.section}_{map_unit.type}.smubin").
                            data)
                    except (KeyError, RuntimeError, AttributeError):
                        map_bytes = None
    if not map_bytes:
        raise FileNotFoundError(
            f"The stock map file {map_unit.section}_{map_unit.type}.smubin could not be found."
        )
    map_bytes = util.decompress(map_bytes)
    return oead.byml.from_binary(map_bytes)
Пример #10
0
def merge_map(map_pair: tuple,
              rstb_calc: rstb.SizeCalculator) -> Dict[str, Tuple[str, int]]:
    map_unit, changes = map_pair[0], map_pair[1]
    util.vprint(f'Merging {len(changes)} versions of {"_".join(map_unit)}...')
    new_map = get_stock_map(map_unit)
    stock_obj_hashes = [int(obj["HashId"]) for obj in new_map["Objs"]]
    for hash_id, actor in changes["Objs"]["mod"].items():
        try:
            new_map["Objs"][stock_obj_hashes.index(int(hash_id))] = actor
        except ValueError:
            changes["Objs"]["add"].append(actor)
    for map_del in sorted(
            changes["Objs"]["del"],
            key=lambda change: stock_obj_hashes.index(change)
            if change in stock_obj_hashes else -1,
            reverse=True,
    ):
        if int(map_del) in stock_obj_hashes:
            try:
                new_map["Objs"].pop(stock_obj_hashes.index(map_del))
            except IndexError:
                try:
                    obj_to_delete = next(
                        iter([
                            actor for actor in new_map["Objs"]
                            if actor["HashId"] == map_del
                        ]))
                    new_map["Objs"].remove(obj_to_delete)
                except (StopIteration, ValueError):
                    util.vprint(
                        f"Could not delete actor with HashId {map_del}")
    new_map["Objs"].extend([
        change for change in changes["Objs"]["add"]
        if int(change["HashId"]) not in stock_obj_hashes
    ])
    new_map["Objs"] = sorted(new_map["Objs"],
                             key=lambda actor: int(actor["HashId"]))

    if len(new_map["Rails"]):
        stock_rail_hashes = [int(rail["HashId"]) for rail in new_map["Rails"]]
        for hash_id, rail in changes["Rails"]["mod"].items():
            try:
                new_map["Rails"][stock_rail_hashes.index(int(hash_id))] = rail
            except ValueError:
                changes["Rails"]["add"].append(rail)
        for map_del in sorted(
                changes["Rails"]["del"],
                key=lambda change: stock_rail_hashes.index(int(change))
                if int(change) in stock_rail_hashes else -1,
                reverse=True,
        ):
            if int(map_del) in stock_rail_hashes:
                try:
                    new_map["Rails"].pop(stock_rail_hashes.index(int(map_del)))
                except IndexError:
                    try:
                        obj_to_delete = next(
                            iter([
                                rail for rail in new_map["Rails"]
                                if rail["HashId"] == map_del
                            ]))
                        new_map["Rails"].remove(obj_to_delete)
                    except (StopIteration, ValueError):
                        util.vprint(
                            f"Could not delete rail with HashId {map_del}")
        new_map["Rails"].extend([
            change for change in changes["Rails"]["add"]
            if int(change["HashId"]) not in stock_rail_hashes
        ])
        new_map["Rails"] = sorted(new_map["Rails"],
                                  key=lambda rail: int(rail["HashId"]))

    aoc_out: Path = (util.get_master_modpack_dir() / util.get_dlc_path() /
                     ("0010" if util.get_settings("wiiu") else "") / "Map" /
                     "MainField" / map_unit.section /
                     f"{map_unit.section}_{map_unit.type}.smubin")
    aoc_out.parent.mkdir(parents=True, exist_ok=True)
    aoc_bytes = oead.byml.to_binary(new_map,
                                    big_endian=util.get_settings("wiiu"))
    aoc_out.write_bytes(util.compress(aoc_bytes))
    new_map["Objs"] = [
        obj for obj in new_map["Objs"]
        if not str(obj["UnitConfigName"]).startswith("DLC")
    ]
    (util.get_master_modpack_dir() / util.get_content_path() / "Map" /
     "MainField" / map_unit.section).mkdir(parents=True, exist_ok=True)
    base_out = (util.get_master_modpack_dir() / util.get_content_path() /
                "Map" / "MainField" / map_unit.section /
                f"{map_unit.section}_{map_unit.type}.smubin")
    base_out.parent.mkdir(parents=True, exist_ok=True)
    base_bytes = oead.byml.to_binary(new_map,
                                     big_endian=util.get_settings("wiiu"))
    base_out.write_bytes(util.compress(base_bytes))
    return {
        util.get_dlc_path(): (
            f"Aoc/0010/Map/MainField/{map_unit.section}/{map_unit.section}_{map_unit.type}.mubin",
            rstb_calc.calculate_file_size_with_ext(bytes(aoc_bytes),
                                                   util.get_settings("wiiu"),
                                                   ".mubin"),
        ),
        "main": (
            f"Map/MainField/{map_unit.section}/{map_unit.section}_{map_unit.type}.mubin",
            rstb_calc.calculate_file_size_with_ext(bytes(base_bytes),
                                                   util.get_settings("wiiu"),
                                                   ".mubin"),
        ),
    }
Пример #11
0
 def perform_merge(self):
     merge_texts(util.get_settings()['lang'], original_pool=self._pool)
Пример #12
0
 def perform_merge(self):
     merge_texts(util.get_settings()['lang'])