from typing import Sequence from lib.archive import * def decode( reader: FArchiveReader, type_name: str, size: int, path: str ) -> dict[str, Any]: if type_name != "MapProperty": raise Exception(f"Expected MapProperty, got {type_name}") value = reader.property(type_name, size, path, allow_custom=False) # Decode the raw bytes and replace the raw data group_map = value["value"] for group in group_map: group_type = group["value"]["GroupType"]["value"]["value"] group_bytes = group["value"]["RawData"]["value"]["values"] group["value"]["RawData"]["value"] = decode_bytes(group_bytes, group_type) return value def decode_bytes(group_bytes: Sequence[int], group_type: str) -> dict[str, Any]: reader = FArchiveReader(bytes(group_bytes)) group_data = { "group_type": group_type, "group_id": reader.guid(), "group_name": reader.fstring(), "individual_character_handle_ids": reader.tarray(instance_id_reader), } if group_type in [ "EPalGroupType::Guild", "EPalGroupType::IndependentGuild", "EPalGroupType::Organization", ]: org = { "org_type": reader.byte(), "base_ids": reader.tarray(uuid_reader), } group_data |= org if group_type in ["EPalGroupType::Guild", "EPalGroupType::IndependentGuild"]: guild = { "base_camp_level": reader.i32(), "map_object_instance_ids_base_camp_points": reader.tarray(uuid_reader), "guild_name": reader.fstring(), } group_data |= guild if group_type == "EPalGroupType::IndependentGuild": indie = { "player_uid": reader.guid(), "guild_name_2": reader.fstring(), "player_info": { "last_online_real_time": reader.i64(), "player_name": reader.fstring(), }, } group_data |= indie if group_type == "EPalGroupType::Guild": guild = {"admin_player_uid": reader.guid(), "players": []} player_count = reader.i32() for _ in range(player_count): player = { "player_uid": reader.guid(), "player_info": { "last_online_real_time": reader.i64(), "player_name": reader.fstring(), }, } guild["players"].append(player) group_data |= guild #if not reader.eof(): #raise Exception("Warning: EOF not reached") return group_data def encode( writer: FArchiveWriter, property_type: str, properties: dict[str, Any] ) -> int: if property_type != "MapProperty": raise Exception(f"Expected MapProperty, got {property_type}") del properties["custom_type"] group_map = properties["value"] for group in group_map: if "values" in group["value"]["RawData"]["value"]: continue p = group["value"]["RawData"]["value"] encoded_bytes = encode_bytes(p) group["value"]["RawData"]["value"] = {"values": [b for b in encoded_bytes]} return writer.property_inner(property_type, properties) def encode_bytes(p: dict[str, Any]) -> bytes: writer = FArchiveWriter() writer.guid(p["group_id"]) writer.fstring(p["group_name"]) writer.tarray(instance_id_writer, p["individual_character_handle_ids"]) if p["group_type"] in [ "EPalGroupType::Guild", "EPalGroupType::IndependentGuild", "EPalGroupType::Organization", ]: writer.byte(p["org_type"]) writer.tarray(uuid_writer, p["base_ids"]) if p["group_type"] in ["EPalGroupType::Guild", "EPalGroupType::IndependentGuild"]: writer.i32(p["base_camp_level"]) writer.tarray(uuid_writer, p["map_object_instance_ids_base_camp_points"]) writer.fstring(p["guild_name"]) if p["group_type"] == "EPalGroupType::IndependentGuild": writer.guid(p["player_uid"]) writer.fstring(p["guild_name_2"]) writer.i64(p["player_info"]["last_online_real_time"]) writer.fstring(p["player_info"]["player_name"]) if p["group_type"] == "EPalGroupType::Guild": writer.guid(p["admin_player_uid"]) writer.i32(len(p["players"])) for i in range(len(p["players"])): writer.guid(p["players"][i]["player_uid"]) writer.i64(p["players"][i]["player_info"]["last_online_real_time"]) writer.fstring(p["players"][i]["player_info"]["player_name"]) encoded_bytes = writer.bytes() return encoded_bytes