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)
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)
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)))
def find_name(item: Hash) -> str: for k, v in item.items(): if "name" in k.lower(): return v else: return ""
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