Пример #1
0
    def diff_objs() -> Hash:
        base_hashes = [int(obj["HashId"]) for obj in base_map["Objs"]]
        base_links = (set() if link_del else {
            int(link["DestUnitHashId"])
            for obj in base_map["Objs"]
            for link in obj.get("LinksToObj", Array()) if "LinksToObj" in obj
        })
        mod_hashes = [int(obj["HashId"]) for obj in mod_map["Objs"]]

        diffs = Hash()
        diffs["add"] = Array([
            obj for obj in mod_map["Objs"]
            if int(obj["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(obj["HashId"]): obj
            for obj in mod_map["Objs"] if int(obj["HashId"]) in base_hashes
            and obj != base_map["Objs"][base_hashes.index(int(obj["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in {
                hash_id
                for hash_id in base_hashes
                if hash_id not in {*mod_hashes, *base_links}
            }
        ] if not no_del else set())
        return diffs
Пример #2
0
    def diff_objs() -> Hash:
        base_hashes = [int(obj["HashId"]) for obj in base_map["Objs"]]
        mod_hashes = [int(obj["HashId"]) for obj in mod_map["Objs"]]

        diffs = Hash()
        diffs["add"] = Array([
            obj for obj in mod_map["Objs"]
            if int(obj["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(obj["HashId"]): obj
            for obj in mod_map["Objs"] if int(obj["HashId"]) in base_hashes
            and obj != base_map["Objs"][base_hashes.index(int(obj["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])

        if new_hashes:
            hash_map: Dict[int, int] = {}
            for obj in diffs["add"]:
                new_hash = crc32(oead.byml.to_text(obj).encode("utf8"))
                hash_map[obj["HashId"].v] = new_hash
                obj["HashId"] = oead.U32(new_hash)
            for obj in [*diffs["add"], *[v for k, v in diffs["mod"].items()]]:
                if "LinksToObj" in obj:
                    for link in obj["LinksToObj"]:
                        if link["DestUnitHashId"].v in hash_map:
                            link["DestUnitHashId"] = oead.U32(
                                hash_map[link["DestUnitHashId"].v])
        return diffs
Пример #3
0
def diff_gamedata_type(data_type: str, mod_data: dict, stock_data: dict) -> Hash:
    stock_entries = {entry["DataName"]: entry for entry in stock_data}
    del stock_data
    mod_entries = {entry["DataName"] for entry in mod_data}
    diffs = Hash(
        {
            "add": Hash(
                {
                    entry["DataName"]: entry
                    for entry in mod_data
                    if (
                        entry["DataName"] not in stock_entries
                        or entry != stock_entries[entry["DataName"]]
                    )
                }
            ),
            "del": oead.byml.Array(
                {entry for entry in stock_entries if entry not in mod_entries}
            ),
        }
    )
    del stock_entries
    del mod_entries
    del mod_data
    return Hash({data_type: diffs})
Пример #4
0
def parse_legacy_diff(text: str) -> Hash:
    diff = oead.byml.from_text(text)
    return Hash({
        unit: Hash({
            "Objs": changes,
            "Rails": Hash()
        })
        for unit, changes in diff.items()
    })
Пример #5
0
 def to_Hash(self) -> Hash:
     r = super(Vec2ArrayFlag, self).to_Hash()
     vec_array = Array()
     vec_array.append(Hash())
     vec_array[0]["Values"] = Array()
     for i in range(len(self._init_value)):
         vector = self._init_value[i]
         vec = Array()
         vec.append(F32(vector[0]))
         vec.append(F32(vector[1]))
         vec_array[0]["Values"].append(Array())
         vec_array[0]["Values"][i].append(vec)
     r["InitValue"] = vec_array
     vec_array = Array()
     vec = Array()
     vec.append(F32(self._max_value[0]))
     vec.append(F32(self._max_value[1]))
     vec_array.append(vec)
     r["MaxValue"] = vec_array
     vec_array = Array()
     vec = Array()
     vec.append(F32(self._min_value[0]))
     vec.append(F32(self._min_value[1]))
     vec_array.append(vec)
     r["MinValue"] = vec_array
     return r
Пример #6
0
def get_modded_savedata_entries(savedata: oead.Sarc) -> Hash:
    ref_savedata = get_stock_savedata().get_files()
    ref_hashes = {
        int(item["HashValue"])
        for file in sorted(ref_savedata, key=lambda f: f.name)[0:-2]
        for item in oead.byml.from_binary(file.data)["file_list"][1]
    }
    new_entries = oead.byml.Array()
    mod_hashes = set()
    for file in savedata.get_files():
        data = oead.byml.from_binary(file.data)
        if data["file_list"][0]["file_name"] != "game_data.sav":
            continue
        entries = data["file_list"][1]
        mod_hashes |= {int(item["HashValue"]) for item in entries}
        new_entries.extend(
            [item for item in entries if int(item["HashValue"]) not in ref_hashes]
        )
    del ref_savedata
    return Hash(
        {
            "add": new_entries,
            "del": oead.byml.Array(
                oead.S32(item)
                for item in {item for item in ref_hashes if item not in mod_hashes}
            ),
        }
    )
Пример #7
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
Пример #8
0
 def add_flags_from_Hash(self, name: str, data: Hash) -> None:
     is_revival = bool("revival" in name)
     for ftype, flags in data.items():
         for flag in flags:
             self._store[ftype][flag["HashValue"].v] = FLAG_MAPPING[ftype](
                 flag, revival=is_revival)
             self._orig_store[ftype][
                 flag["HashValue"].v] = FLAG_MAPPING[ftype](
                     flag, revival=is_revival)
Пример #9
0
 def to_Hash(self) -> Hash:
     r = super(F32ArrayFlag, self).to_Hash()
     array_one = Array()
     array_one.append(Hash())
     array_two = Array([F32(value) for value in self._init_value])
     array_one[0]["Values"] = array_two
     r["InitValue"] = array_one
     r["MaxValue"] = F32(self._max_value)
     r["MinValue"] = F32(self._min_value)
     return r
Пример #10
0
    def diff_objs() -> Hash:
        base_hashes = [int(obj["HashId"]) for obj in base_map["Objs"]]
        mod_hashes = [int(obj["HashId"]) for obj in mod_map["Objs"]]

        diffs = Hash()
        diffs["add"] = Array([
            obj for obj in mod_map["Objs"]
            if int(obj["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(obj["HashId"]): obj
            for obj in mod_map["Objs"] if int(obj["HashId"]) in base_hashes
            and obj != base_map["Objs"][base_hashes.index(int(obj["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])
        return diffs
Пример #11
0
def get_map_diff(map_unit: Map,
                 tmp_dir: Path,
                 no_del: bool = False,
                 link_del: bool = False) -> Hash:
    mod_map = get_modded_map(map_unit, tmp_dir)
    stock_map = True
    for obj in mod_map["Objs"]:
        str_obj = oead.byml.to_text(obj)
        if "IsHardModeActor" in str_obj or "AoC_HardMode_Enabled" in str_obj:
            stock_map = False
            break
    base_map = get_stock_map(map_unit, force_vanilla=stock_map)

    base_hashes = [int(obj["HashId"]) for obj in base_map["Objs"]]
    base_links = (set() if link_del else {
        int(link["DestUnitHashId"])
        for obj in base_map["Objs"] for link in obj.get("LinksToObj", Array())
        if "LinksToObj" in obj
    })
    mod_hashes = [int(obj["HashId"]) for obj in mod_map["Objs"]]

    diffs = Hash()
    diffs["add"] = Array({
        obj
        for obj in mod_map["Objs"] if int(obj["HashId"]) not in base_hashes
    })
    diffs["mod"] = Hash({
        str(obj["HashId"]): obj
        for obj in mod_map["Objs"] if int(obj["HashId"]) in base_hashes
        and obj != base_map["Objs"][base_hashes.index(int(obj["HashId"]))]
    })
    diffs["del"] = Array({
        oead.U32(hash_id)
        for hash_id in base_hashes
        if hash_id not in {*mod_hashes, *base_links}
    } if not no_del else set())
    del mod_map
    del base_map
    del base_links
    del mod_hashes
    return "_".join(map_unit), oead.byml.to_text(diffs)
Пример #12
0
 def to_Hash(self) -> Hash:
     r = Hash()
     r["DataName"] = self._data_name
     r["DeleteRev"] = S32(self._delete_rev)
     r["HashValue"] = S32(self._hash_value)
     r["IsEventAssociated"] = self._is_event_associated
     r["IsOneTrigger"] = self._is_one_trigger
     r["IsProgramReadable"] = self._is_program_readable
     r["IsProgramWritable"] = self._is_program_writable
     r["IsSave"] = self._is_save
     r["ResetType"] = S32(self._reset_type)
     return r
Пример #13
0
 def add_flags_from_Hash(self,
                         name: str,
                         data: Hash,
                         overwrite_ok: bool = True) -> None:
     is_revival = bool("revival" in name)
     for ftype, flags in data.items():
         for flag in flags:
             hash = flag["HashValue"].v
             if hash in self._store[ftype] and not overwrite_ok:
                 continue
             self._store[ftype][hash] = FLAG_MAPPING[ftype](
                 flag, revival=is_revival)
Пример #14
0
    def diff_rails() -> Hash:
        base_hashes = [int(rail["HashId"]) for rail in base_map["Rails"]]
        mod_hashes = [int(rail["HashId"]) for rail in mod_map["Rails"]]

        diffs = Hash()
        diffs["add"] = Array([
            rail for rail in mod_map["Rails"]
            if int(rail["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(rail["HashId"]): rail
            for rail in mod_map["Rails"]
            if int(rail["HashId"]) in base_hashes and
            rail != base_map["Rails"][base_hashes.index(int(rail["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])
        return diffs
Пример #15
0
 def to_Hash(self) -> Hash:
     r = super(String256ArrayFlag, self).to_Hash()
     array_one = Array()
     array_one.append(Hash())
     # array_two = [FixedSafeString256(value) for value in self._init_value]
     array_two = Array(self._init_value)
     array_one[0]["Values"] = array_two
     r["InitValue"] = array_one
     # r["MaxValue"] = FixedSafeString256(self._max_value)
     r["MaxValue"] = self._max_value
     # r["MinValue"] = FixedSafeString256(self._min_value)
     r["MinValue"] = self._min_value
     return r
Пример #16
0
 def consolidate_diffs(self, diffs: list):
     if not diffs:
         return {}
     all_diffs = Hash({"add": oead.byml.Array(), "del": oead.byml.Array()})
     hashes = set()
     for diff in reversed(diffs):
         for entry in diff["add"]:
             if entry["HashValue"].v not in hashes:
                 all_diffs["add"].append(entry)
             hashes.add(entry["HashValue"].v)
         for entry in diff["del"]:
             if entry not in all_diffs["del"]:
                 all_diffs["del"].append(entry)
     del hashes
     return all_diffs
Пример #17
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,
         )
Пример #18
0
def get_modded_gamedata_entries(gamedata: oead.Sarc, pool: pool.Pool = None) -> Hash:
    this_pool = pool or Pool(maxtasksperchild=500)
    stock_data = consolidate_gamedata(get_stock_gamedata())
    mod_data = consolidate_gamedata(gamedata)
    del gamedata
    results = this_pool.starmap(
        diff_gamedata_type,
        ((key, mod_data[key], stock_data[key]) for key in mod_data),
    )
    diffs = Hash({data_type: diff for d in results for data_type, diff in d.items()})
    del results
    if not pool:
        this_pool.close()
        this_pool.join()
    del stock_data
    del mod_data
    return diffs
Пример #19
0
 def get_mod_diff(self, mod: util.BcmlMod):
     diffs = Hash()
     if self.is_mod_logged(mod):
         util.dict_merge(
             diffs,
             oead.byml.from_text(
                 (mod.path / "logs" /
                  self._log_name).read_text(encoding="utf-8")),
             overwrite_lists=True,
         )
     for opt in {d for d in (mod.path / "options").glob("*") if d.is_dir()}:
         if (opt / "logs" / self._log_name).exists():
             util.dict_merge(
                 diffs,
                 oead.byml.from_text(
                     (opt / "logs" / self._log_name).read_text("utf-8")),
                 overwrite_lists=True,
             )
     return diffs
Пример #20
0
 def to_sv_Hash(self) -> Hash:
     r = Hash()
     r["DataName"] = self._data_name
     r["HashValue"] = S32(self._hash_value)
     return r
Пример #21
0
def get_map_diff(map_unit: Map,
                 tmp_dir: Path,
                 new_hashes: bool = False) -> Hash:
    mod_map = get_modded_map(map_unit, tmp_dir)
    stock_map = True
    for obj in mod_map["Objs"]:
        str_obj = oead.byml.to_text(obj)
        if "IsHardModeActor" in str_obj or "AoC_HardMode_Enabled" in str_obj:
            stock_map = False
            break
    base_map = get_stock_map(map_unit, force_vanilla=stock_map)

    def diff_objs() -> Hash:
        base_hashes = [int(obj["HashId"]) for obj in base_map["Objs"]]
        mod_hashes = [int(obj["HashId"]) for obj in mod_map["Objs"]]

        diffs = Hash()
        diffs["add"] = Array([
            obj for obj in mod_map["Objs"]
            if int(obj["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(obj["HashId"]): obj
            for obj in mod_map["Objs"] if int(obj["HashId"]) in base_hashes
            and obj != base_map["Objs"][base_hashes.index(int(obj["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])

        if new_hashes:
            hash_map: Dict[int, int] = {}
            for obj in diffs["add"]:
                new_hash = crc32(oead.byml.to_text(obj).encode("utf8"))
                hash_map[obj["HashId"].v] = new_hash
                obj["HashId"] = oead.U32(new_hash)
            for obj in [*diffs["add"], *[v for k, v in diffs["mod"].items()]]:
                if "LinksToObj" in obj:
                    for link in obj["LinksToObj"]:
                        if link["DestUnitHashId"].v in hash_map:
                            link["DestUnitHashId"] = oead.U32(
                                hash_map[link["DestUnitHashId"].v])
        return diffs

    def diff_rails() -> Hash:
        base_hashes = [int(rail["HashId"]) for rail in base_map["Rails"]]
        mod_hashes = [int(rail["HashId"]) for rail in mod_map["Rails"]]

        diffs = Hash()
        diffs["add"] = Array([
            rail for rail in mod_map["Rails"]
            if int(rail["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(rail["HashId"]): rail
            for rail in mod_map["Rails"]
            if int(rail["HashId"]) in base_hashes and
            rail != base_map["Rails"][base_hashes.index(int(rail["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])
        return diffs

    return (
        "_".join(map_unit),
        oead.byml.to_text(
            Hash({
                "Objs":
                diff_objs(),
                "Rails":
                diff_rails() if map_unit.type == "Static" else Hash(),
            })),
    )
Пример #22
0
def consolidate_gamedata(gamedata: oead.Sarc) -> Hash:
    data = Hash()
    for file in gamedata.get_files():
        util.dict_merge(data, oead.byml.from_binary(file.data))
    del gamedata
    return data
Пример #23
0
    def perform_merge(self):
        force = self._options.get("force", False)
        slog_path = util.get_master_modpack_dir() / "logs" / "savedata.log"

        new_entries = self.consolidate_diffs(self.get_all_diffs())
        if not new_entries:
            print("No savedata merging necessary.")
            if slog_path.exists():
                slog_path.unlink()
            if (util.get_master_modpack_dir() / "logs" / "savedata.sarc").exists():
                (util.get_master_modpack_dir() / "logs" / "savedata.sarc").unlink()
            return
        if slog_path.exists() and not force:
            with slog_path.open("r") as l_file:
                if xxhash.xxh64_hexdigest(str(new_entries)) == l_file.read():
                    print("No savedata merging necessary.")
                    return

        savedata = get_stock_savedata()
        save_files = sorted(savedata.get_files(), key=lambda f: f.name)[0:-2]
        del_ids = {item.v for item in new_entries["del"]}

        print("Merging changes...")
        merged_entries = oead.byml.Array(
            sorted(
                {
                    entry["HashValue"].v: entry
                    for entry in [
                        *[
                            e
                            for file in save_files
                            for e in oead.byml.from_binary(file.data)["file_list"][1]
                        ],
                        *new_entries["add"],
                    ]
                    if entry["HashValue"].v not in del_ids
                }.values(),
                key=itemgetter("HashValue"),
            )
        )
        print("Creating and injecting new savedataformat.sarc...")
        new_savedata = oead.SarcWriter(
            endian=oead.Endianness.Big
            if util.get_settings("wiiu")
            else oead.Endianness.Little
        )
        num_files = ceil(len(merged_entries) / 8192)
        for i in range(num_files):
            end_pos = (i + 1) * 8192
            if end_pos > len(merged_entries):
                end_pos = len(merged_entries)
            data = oead.byml.to_binary(
                Hash(
                    {
                        "file_list": oead.byml.Array(
                            [
                                {
                                    "IsCommon": False,
                                    "IsCommonAtSameAccount": False,
                                    "IsSaveSecureCode": True,
                                    "file_name": "game_data.sav",
                                },
                                oead.byml.Array(merged_entries[i * 8192 : end_pos]),
                            ]
                        ),
                        "save_info": oead.byml.Array(
                            [
                                {
                                    "directory_num": oead.S32(8),
                                    "is_build_machine": True,
                                    "revision": oead.S32(18203),
                                }
                            ]
                        ),
                    }
                ),
                big_endian=util.get_settings("wiiu"),
            )
            new_savedata.files[f"/saveformat_{i}.bgsvdata"] = data

        new_savedata.files[f"/saveformat_{num_files}.bgsvdata"] = oead.Bytes(
            savedata.get_file("/saveformat_6.bgsvdata").data
        )
        new_savedata.files[f"/saveformat_{num_files + 1}.bgsvdata"] = oead.Bytes(
            savedata.get_file("/saveformat_7.bgsvdata").data
        )

        del savedata
        new_save_bytes = new_savedata.write()[1]
        del new_savedata
        util.inject_file_into_sarc(
            "GameData/savedataformat.ssarc",
            util.compress(new_save_bytes),
            "Pack/Bootup.pack",
            create_sarc=True,
        )
        (util.get_master_modpack_dir() / "logs").mkdir(parents=True, exist_ok=True)
        (
            (util.get_master_modpack_dir() / "logs" / "savedata.sarc").write_bytes(
                new_save_bytes
            )
        )

        print("Updating RSTB...")
        rstable.set_size(
            "GameData/savedataformat.sarc",
            rstable.calculate_size("GameData/savedataformat.sarc", new_save_bytes),
        )
        del new_save_bytes

        slog_path.parent.mkdir(parents=True, exist_ok=True)
        with slog_path.open("w", encoding="utf-8") as l_file:
            l_file.write(xxhash.xxh64_hexdigest(str(new_entries)))
Пример #24
0
 def consolidate_diffs(self, diffs: list):
     a_diffs = Hash()
     for mod_diff in diffs:
         for file, diff in mod_diff.items():
             # a_map = Map(*file.split("_"))
             if file not in a_diffs:
                 a_diffs[file] = Array()
             a_diffs[file].append(diff)
     c_diffs = Hash()
     for file, mods in a_diffs.items():
         c_diffs[file] = Hash({
             "Objs":
             Hash({
                 "add":
                 Array(),
                 "mod":
                 Hash(),
                 "del":
                 Array([
                     oead.U32(h) for h in set([
                         hash_id.v for hashes in [
                             mod["Objs"]["del"] for mod in mods
                             if "Objs" in mod and "del" in mod["Objs"]
                         ] for hash_id in hashes
                     ])
                 ]),
             }),
             "Rails":
             Hash({
                 "add":
                 Array(),
                 "mod":
                 Hash(),
                 "del":
                 Array([
                     oead.U32(h) for h in set([
                         hash_id.v for hashes in [
                             mod["Rails"]["del"] for mod in mods
                             if "Rails" in mod and "del" in mod["Rails"]
                         ] for hash_id in hashes
                     ])
                 ]),
             }),
         })
         for mod in [m for m in mods if "Objs" in m and "mod" in m["Objs"]]:
             for hash_id, actor in mod["Objs"]["mod"].items():
                 c_diffs[file]["Objs"]["mod"][hash_id] = actor
         for mod in [
                 m for m in mods if "Rails" in m and "mod" in m["Rails"]
         ]:
             for hash_id, actor in mod["Rails"]["mod"].items():
                 c_diffs[file]["Rails"]["mod"][hash_id] = actor
         add_obj_hashes = []
         add_rail_hashes = []
         for mod in reversed(mods):
             if "add" in mod["Objs"]:
                 for actor in mod["Objs"]["add"]:
                     if actor["HashId"] not in add_obj_hashes:
                         add_obj_hashes.append(actor["HashId"])
                         c_diffs[file]["Objs"]["add"].append(actor)
             if "add" in mod["Rails"]:
                 for actor in mod["Rails"]["add"]:
                     if actor["HashId"] not in add_rail_hashes:
                         add_rail_hashes.append(actor["HashId"])
                         c_diffs[file]["Rails"]["add"].append(actor)
     return c_diffs
Пример #25
0
    def perform_merge(self):
        force = self._options.get("force", False)
        glog_path = util.get_master_modpack_dir() / "logs" / "gamedata.log"

        modded_entries = self.consolidate_diffs(self.get_all_diffs())
        if not modded_entries:
            print("No gamedata merging necessary.")
            if glog_path.exists():
                glog_path.unlink()
            if (util.get_master_modpack_dir() / "logs" / "gamedata.sarc").exists():
                (util.get_master_modpack_dir() / "logs" / "gamedata.sarc").unlink()
            return
        if glog_path.exists() and not force:
            with glog_path.open("r") as l_file:
                if xxhash.xxh64_hexdigest(str(modded_entries)) == l_file.read():
                    print("No gamedata merging necessary.")
                    return

        print("Loading stock gamedata...")
        gamedata = consolidate_gamedata(get_stock_gamedata())
        merged_entries = {
            data_type: Hash({entry["DataName"]: entry for entry in entries})
            for data_type, entries in gamedata.items()
        }
        del gamedata

        print("Merging changes...")
        for data_type in {d for d in merged_entries if d in modded_entries}:
            util.dict_merge(
                merged_entries[data_type],
                modded_entries[data_type]["add"],
                shallow=True,
            )
            for entry in modded_entries[data_type]["del"]:
                try:
                    del merged_entries[data_type][entry]
                except KeyError:
                    continue

        merged_entries = Hash(
            {
                data_type: oead.byml.Array([value for _, value in entries.items()])
                for data_type, entries in merged_entries.items()
            }
        )
        print("Creating and injecting new gamedata.sarc...")
        new_gamedata = oead.SarcWriter(
            endian=oead.Endianness.Big
            if util.get_settings("wiiu")
            else oead.Endianness.Little
        )
        for data_type in merged_entries:
            num_files = ceil(len(merged_entries[data_type]) / 4096)
            for i in range(num_files):
                end_pos = (i + 1) * 4096
                if end_pos > len(merged_entries[data_type]):
                    end_pos = len(merged_entries[data_type])
                new_gamedata.files[f"/{data_type}_{i}.bgdata"] = oead.byml.to_binary(
                    Hash({data_type: merged_entries[data_type][i * 4096 : end_pos]}),
                    big_endian=util.get_settings("wiiu"),
                )
        new_gamedata_bytes = new_gamedata.write()[1]
        del new_gamedata
        util.inject_file_into_sarc(
            "GameData/gamedata.ssarc",
            util.compress(new_gamedata_bytes),
            "Pack/Bootup.pack",
            create_sarc=True,
        )
        (util.get_master_modpack_dir() / "logs").mkdir(parents=True, exist_ok=True)
        (util.get_master_modpack_dir() / "logs" / "gamedata.sarc").write_bytes(
            new_gamedata_bytes
        )

        print("Updating RSTB...")
        rstable.set_size(
            "GameData/gamedata.sarc",
            rstable.calculate_size("GameData/gamedata.sarc", new_gamedata_bytes),
        )
        del new_gamedata_bytes

        glog_path.parent.mkdir(parents=True, exist_ok=True)
        with glog_path.open("w", encoding="utf-8") as l_file:
            l_file.write(xxhash.xxh64_hexdigest(str(modded_entries)))
Пример #26
0
 def consolidate_diffs(self, diffs: list):
     all_diffs = Hash()
     for diff in diffs:
         util.dict_merge(all_diffs, diff, overwrite_lists=True)
     return all_diffs
Пример #27
0
 def find_name(item: Hash) -> str:
     for k, v in item.items():
         if "name" in k.lower():
             return v
     else:
         return ""
Пример #28
0
def get_map_diff(map_unit: Map, tmp_dir: Path) -> Hash:
    mod_map = get_modded_map(map_unit, tmp_dir)
    stock_map = True
    for obj in mod_map["Objs"]:
        str_obj = oead.byml.to_text(obj)
        if "IsHardModeActor" in str_obj or "AoC_HardMode_Enabled" in str_obj:
            stock_map = False
            break
    base_map = get_stock_map(map_unit, force_vanilla=stock_map)

    def diff_objs() -> Hash:
        base_hashes = [int(obj["HashId"]) for obj in base_map["Objs"]]
        mod_hashes = [int(obj["HashId"]) for obj in mod_map["Objs"]]

        diffs = Hash()
        diffs["add"] = Array([
            obj for obj in mod_map["Objs"]
            if int(obj["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(obj["HashId"]): obj
            for obj in mod_map["Objs"] if int(obj["HashId"]) in base_hashes
            and obj != base_map["Objs"][base_hashes.index(int(obj["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])
        return diffs

    def diff_rails() -> Hash:
        base_hashes = [int(rail["HashId"]) for rail in base_map["Rails"]]
        mod_hashes = [int(rail["HashId"]) for rail in mod_map["Rails"]]

        diffs = Hash()
        diffs["add"] = Array([
            rail for rail in mod_map["Rails"]
            if int(rail["HashId"]) not in base_hashes
        ])
        diffs["mod"] = Hash({
            str(rail["HashId"]): rail
            for rail in mod_map["Rails"]
            if int(rail["HashId"]) in base_hashes and
            rail != base_map["Rails"][base_hashes.index(int(rail["HashId"]))]
        })
        diffs["del"] = Array([
            oead.U32(h) for h in
            {hash_id
             for hash_id in base_hashes if hash_id not in mod_hashes}
        ])
        return diffs

    return (
        "_".join(map_unit),
        oead.byml.to_text(
            Hash({
                "Objs":
                diff_objs(),
                "Rails":
                diff_rails() if map_unit.type == "Static" else Hash(),
            })),
    )