diff --git a/src/cli/tools/gsc.hpp b/src/cli/tools/gsc.hpp index 5d2f5d1..784d5c0 100644 --- a/src/cli/tools/gsc.hpp +++ b/src/cli/tools/gsc.hpp @@ -736,30 +736,30 @@ namespace tool::gsc { }; enum T9GSCExportFlags : UINT8 { - AUTOEXEC = 0x01, - LINKED = 0x02, - PRIVATE = 0x04, - CLASS_MEMBER = 0x08, - CLASS_DESTRUCTOR = 0x10, - VE = 0x20, - EVENT = 0x40, - CLASS_LINKED = 0x80, - CLASS_VTABLE = 0x86 + T9_EF_AUTOEXEC = 0x01, + T9_EF_LINKED = 0x02, + T9_EF_PRIVATE = 0x04, + T9_EF_CLASS_MEMBER = 0x08, + T9_EF_CLASS_DESTRUCTOR = 0x10, + T9_EF_VE = 0x20, + T9_EF_EVENT = 0x40, + T9_EF_CLASS_LINKED = 0x80, + T9_EF_CLASS_VTABLE = 0x86 }; enum T9GSCImportFlags : UINT8 { - METHOD_CHILDTHREAD = 0x1, - METHOD_THREAD = 0x2, - FUNCTION_CHILDTHREAD = 0x3, - FUNCTION = 0x4, - FUNC_METHOD = 0x5, - FUNCTION_THREAD = 0x6, - METHOD = 0x7, - CALLTYPE_MASK = 0xF, - DEV_CALL = 0x10, - GET_CALL = 0x20, - UKN40 = 0x40, - UKN80 = 0x80 + T9_IF_METHOD_CHILDTHREAD = 0x1, + T9_IF_METHOD_THREAD = 0x2, + T9_IF_FUNCTION_CHILDTHREAD = 0x3, + T9_IF_FUNCTION = 0x4, + T9_IF_FUNC_METHOD = 0x5, + T9_IF_FUNCTION_THREAD = 0x6, + T9_IF_METHOD = 0x7, + T9_IF_CALLTYPE_MASK = 0xF, + T9_IF_DEV_CALL = 0x10, + T9_IF_GET_CALL = 0x20, + T9_IF_UKN40 = 0x40, + T9_IF_UKN80 = 0x80 }; struct T8GSCString { diff --git a/src/cli/tools/pool.cpp b/src/cli/tools/pool.cpp index f4d9b78..ef115eb 100644 --- a/src/cli/tools/pool.cpp +++ b/src/cli/tools/pool.cpp @@ -149,6 +149,71 @@ struct ScriptBundle { SB_ObjectsArray sbObjectsArray; }; +enum eModes : INT32 { + MODE_ZOMBIES = 0x0, + MODE_MULTIPLAYER = 0x1, + MODE_CAMPAIGN = 0x2, + MODE_WARZONE = 0x3, + MODE_COUNT = 0x4, + MODE_INVALID = 0x4, + MODE_FIRST = 0x0, +}; + +const char* EModeName(eModes mode) { + switch (mode) { + case MODE_ZOMBIES: return "zombies"; + case MODE_MULTIPLAYER: return "multiplayer"; + case MODE_CAMPAIGN: return "campaign"; + case MODE_WARZONE: return "warzone"; + default: return ""; + } + +} + +struct Hash { + uint64_t name; + uint64_t nullpad; +}; + +struct GameTypeTableEntry { + Hash name; + Hash baseGameType; + uint64_t unk20; + Hash nameRef; + Hash nameRefCaps; + Hash descriptionRef; + Hash unk58; + bool isHardcoreAvailable; + Hash hardcoreNameRef; + bool isTeamBased; + bool hideHudScore; + uint64_t groupName; + uintptr_t image; // GfxImage* + Hash presenceString; + uint64_t unkA8; + uint64_t scoreInfoFile; + uint64_t unkB8; + uint64_t unkC0; + uint64_t unkC8; + uint64_t unkD0; + uint64_t unkD8; + uint64_t unkE0; + uint64_t unkE8; + uint64_t unkF0; + int uniqueID; + uint64_t unk100; + uint64_t unk108; +}; + +struct GameTypeTable { + UINT64 name; + UINT64 namepad; + UINT32 gameTypeCount; + uintptr_t gameTypes; // GameTypeTableEntry* + eModes sessionMode; +}; + + struct GametypeEntry { uintptr_t v1; // 0x8 uintptr_t pad0; // 0x10 @@ -479,6 +544,15 @@ bool ReadSBObject(const Process& proc, std::ostream& defout, int depth, const SB return true; } +const char* ReadTmpStr(const Process& proc, uintptr_t location) { + static CHAR tmp_buff[0x1000]; + + if (proc.ReadString(tmp_buff, location, sizeof(tmp_buff)) < 0) { + sprintf_s(tmp_buff, "", location); + } + return tmp_buff; +} + int pooltool(const Process& proc, int argc, const char* argv[]) { using namespace pool; if (argc < 3) { @@ -883,6 +957,114 @@ int pooltool(const Process& proc, int argc, const char* argv[]) { std::cout << "Dump " << readFile << " new file(s)\n"; } break; + case ASSET_TYPE_GAMETYPETABLE: + { + hashutils::ReadDefaultFile(); + size_t readFile = 0; + + + auto pool = std::make_unique(entry.itemAllocCount); + + if (!proc.ReadMemory(&pool[0], entry.pool, sizeof(pool[0]) * entry.itemAllocCount)) { + std::cerr << "Can't read pool data\n"; + return tool::BASIC_ERROR; + } + CHAR dumpbuff[MAX_PATH + 10]; + + for (size_t i = 0; i < entry.itemAllocCount; i++) { + auto& p = pool[i]; + + auto n = hashutils::ExtractPtr(p.name); + + std::cout << std::dec << i << ": "; + + if (n) { + std::cout << n; + sprintf_s(dumpbuff, "%s/gametypetable/%s.json", opt.m_output, n); + } + else { + std::cout << "file_" << std::hex << p.name << std::dec; + sprintf_s(dumpbuff, "%s/gametypetable/file_%llx.json", opt.m_output, p.name); + } + + if (!p.gameTypes || !proc.ReadMemory(p.gameTypes)) { + std::cerr << "error when reading buffer at " << p.gameTypes << "\n"; + continue; + } + + std::filesystem::path file(dumpbuff); + std::filesystem::create_directories(file.parent_path(), ec); + + std::cout << "->" << file; + + if (!std::filesystem::exists(file, ec)) { + readFile++; + std::cout << " (new)"; + } + + auto entries = std::make_unique(p.gameTypeCount); + + + if (!proc.ReadMemory(&entries[0], p.gameTypes, sizeof(entries[0]) * p.gameTypeCount)) { + std::cerr << "Can't read entries data\n"; + break; + } + + std::ofstream out{ file }; + + if (!out) { + std::cerr << "Can't open output file\n"; + break; + } + + out + << "{\n" + << " \"name\": \"" << hashutils::ExtractTmp("hash", p.name) << std::flush << "\",\n" + << " \"sessionMode\": \"" << EModeName(p.sessionMode) << "\",\n" + << " \"gametypes\": [" + ; + + for (size_t j = 0; j < p.gameTypeCount; j++) { + auto& e = entries[j]; + + if (j) { + out << ","; + } + out + << "\n" + << " {\n" + << " \"uniqueID\": " << std::dec << e.uniqueID << ",\n" + << " \"name\": \"" << ReadTmpStr(proc, e.name.name) << std::flush << "\",\n" + << " \"baseGameType\": \"" << ReadTmpStr(proc, e.baseGameType.name) << std::flush << "\",\n" + << " \"nameRef\": \"#" << hashutils::ExtractTmp("hash", e.nameRef.name) << std::flush << "\",\n" + << " \"nameRefCaps\": \"#" << hashutils::ExtractTmp("hash", e.nameRefCaps.name) << std::flush << "\",\n" + << " \"descriptionRef\": \"#" << hashutils::ExtractTmp("hash", e.descriptionRef.name) << std::flush << "\",\n" + << " \"isHardcoreAvailable\": " << (e.isHardcoreAvailable ? "true" : "false") << ",\n" + << " \"hardcoreNameRef\": \"#" << hashutils::ExtractTmp("hash", e.hardcoreNameRef.name) << std::flush << "\",\n" + << " \"isTeamBased\": " << (e.isTeamBased ? "true" : "false") << ",\n" + << " \"hideHudScore\": " << (e.hideHudScore ? "true" : "false") << ",\n" + << " \"groupname\": \"" << ReadTmpStr(proc, e.groupName) << "\",\n" + << " \"presenceString\": \"#" << hashutils::ExtractTmp("hash", e.presenceString.name) << std::flush << "\"\n" + << " }" + ; + } + + out + << "\n" + << " ]\n" + << "}" + ; + + out.close(); + + std::cout << "\n"; + + } + std::cout << "Dump " << readFile << " new file(s)\n"; + + + break; + } case ASSET_TYPE_DDL: {