diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 63975f73..c1163385 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -61,7 +61,7 @@ namespace Components Loader::Register(new Network()); Loader::Register(new Session()); Loader::Register(new Theatre()); - //Loader::Register(new ClanTags()); + Loader::Register(new ClanTags()); Loader::Register(new Download()); Loader::Register(new Playlist()); Loader::Register(new RawFiles()); diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 3278611c..72c3836b 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -366,7 +366,7 @@ namespace Components // In case a loaded mod didn't call "BotStop" before the VM shutdown Events::OnVMShutdown([] { - for (std::size_t i = 0; i < std::extent_v; i++) + for (std::size_t i = 0; i < std::extent_v; ++i) { g_botai[i].active = false; } diff --git a/src/Components/Modules/CardTitles.cpp b/src/Components/Modules/CardTitles.cpp index 78e7a2f9..7f5d6164 100644 --- a/src/Components/Modules/CardTitles.cpp +++ b/src/Components/Modules/CardTitles.cpp @@ -3,14 +3,14 @@ namespace Components { std::string CardTitles::CustomTitles[18]; - Dvar::Var CardTitles::CustomTitleDvar; + Dvar::Var CardTitles::CustomTitle; CClient* CardTitles::GetClientByIndex(std::uint32_t index) { return &reinterpret_cast(0x8E77B0)[index]; } - std::int32_t CardTitles::GetPlayerCardClientInfo(std::int32_t lookupResult, playercarddata_s* data) + std::int32_t CardTitles::GetPlayerCardClientInfo(std::int32_t lookupResult, Game::PlayerCardData* data) { std::int32_t returnResult = lookupResult; @@ -22,12 +22,12 @@ namespace Components } else { - for (auto clientNum = 0; clientNum < 18; clientNum++) + for (std::size_t clientNum = 0; clientNum < Game::MAX_CLIENTS; ++clientNum) { CClient* c = GetClientByIndex(clientNum); if (c != nullptr) { - if (!strcmp(data->name, c->Name)) + if (!std::strcmp(data->name, c->Name)) { // Since a 4 byte integer is overkill for a row num: We can use it to store the customprefix + clientNum and use a 2 byte integer for the row number returnResult += 0xFF000000; @@ -62,7 +62,6 @@ namespace Components mov [ebx + 4], eax pop ebx - push 62EB2Ch retn } } @@ -83,10 +82,10 @@ namespace Components { if (prefix == 0xFE) { - if (!CardTitles::CustomTitleDvar.get().empty()) + if (!CardTitles::CustomTitle.get().empty()) { // 0xFF in front of the title to skip localization. Or else it will wait for a couple of seconds for the asset of type localize - const char* title = Utils::String::VA("\x15%s", CardTitles::CustomTitleDvar.get()); + const char* title = Utils::String::VA("\x15%s", CardTitles::CustomTitle.get()); // prepare return value operand->internals.stringVal.string = title; @@ -157,20 +156,20 @@ namespace Components { std::string list; - for (int i = 0; i < 18; i++) + for (std::size_t i = 0; i < Game::MAX_CLIENTS; i++) { char playerTitle[18]; - if (Game::svs_clients[i].state >= 3) + if (Game::svs_clients[i].state >= Game::CS_CONNECTED) { - strncpy_s(playerTitle, Game::Info_ValueForKey(Game::svs_clients[i].connectInfoString, "customTitle"), 17); + strncpy_s(playerTitle, Game::Info_ValueForKey(Game::svs_clients[i].userinfo, "customTitle"), _TRUNCATE); } else { - memset(playerTitle, 0, 18); + playerTitle[0] = '\0'; } - list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).c_str(), playerTitle)); + list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).data(), playerTitle)); } const auto* command = Utils::String::VA("%c customTitles \"%s\"", 21, list.data()); @@ -179,7 +178,7 @@ namespace Components void CardTitles::ParseCustomTitles(const char* msg) { - for (int i = 0; i < 18; ++i) + for (std::size_t i = 0; i < Game::MAX_CLIENTS; ++i) { const char* playerTitle = Game::Info_ValueForKey(msg, std::to_string(i).c_str()); @@ -192,7 +191,7 @@ namespace Components { Scheduler::Once([] { - CardTitles::CustomTitleDvar = Dvar::Register("customtitle", "", Game::DVAR_USERINFO | Game::DVAR_ARCHIVE, "Custom card title"); + CardTitles::CustomTitle = Dvar::Register("customTitle", "", Game::DVAR_USERINFO | Game::DVAR_ARCHIVE, "Custom card title"); }, Scheduler::Pipeline::MAIN); ServerCommands::OnCommand(21, [](Command::Params* params) @@ -215,8 +214,5 @@ namespace Components // Table lookup stuff Utils::Hook(0x62DCC1, CardTitles::TableLookupByRowHookStub).install()->quick(); Utils::Hook::Nop(0x62DCC6, 1); - - // This is placed here in case the anticheat has been disabled! - // This checks specifically for launching the process suspended to inject a dll } } diff --git a/src/Components/Modules/CardTitles.hpp b/src/Components/Modules/CardTitles.hpp index 6f02b47a..7dcf5ce8 100644 --- a/src/Components/Modules/CardTitles.hpp +++ b/src/Components/Modules/CardTitles.hpp @@ -12,18 +12,6 @@ namespace Components std::int32_t tableColumn; }; - struct playercarddata_s - { - std::uint32_t padding; - std::uint32_t playercardNumber; - std::uint32_t unknown; - std::uint32_t unknown2; - std::uint32_t level; //Level is counted from 0 -> Value 69 is Level 70 - std::uint32_t prestige; - std::uint32_t padding2; - char name[40]; - }; - struct CClient { std::uint32_t IsValid; // 0x0000 @@ -54,21 +42,21 @@ namespace Components class CardTitles : public Component { public: - static Dvar::Var CustomTitleDvar; + AssertOffset(Game::PlayerCardData, Game::PlayerCardData::name, 0x1C); + + static Dvar::Var CustomTitle; static std::string CustomTitles[18]; static void SendCustomTitlesToClients(); - static void ParseCustomTitles(const char * msg); + static void ParseCustomTitles(const char* msg); CardTitles(); private: - static CClient * GetClientByIndex(std::uint32_t index); - static std::int32_t GetPlayerCardClientInfo(std::int32_t lookupResult, playercarddata_s * data); + static CClient* GetClientByIndex(std::uint32_t index); + static std::int32_t GetPlayerCardClientInfo(std::int32_t lookupResult, Game::PlayerCardData* data); static void GetPlayerCardClientInfoStub(); - static const char* TableLookupByRowHook(Game::Operand * operand, tablelookuprequest_s * request); + static const char* TableLookupByRowHook(Game::Operand* operand, tablelookuprequest_s* request); static void TableLookupByRowHookStub(); - - }; } diff --git a/src/Components/Modules/ClanTags.cpp b/src/Components/Modules/ClanTags.cpp new file mode 100644 index 00000000..89086c11 --- /dev/null +++ b/src/Components/Modules/ClanTags.cpp @@ -0,0 +1,295 @@ +#include + +namespace Components +{ + Game::dvar_t* ClanTags::ClanName; + + // bgs_t and clientState_s do not have this + char ClanTags::ClientState[Game::MAX_CLIENTS][5]; + + const char* ClanTags::GetClanTagWithName(int clientNum, const char* playerName) + { + assert(static_cast(clientNum) < Game::MAX_CLIENTS); + + if (ClientState[clientNum][0] == '\0') + { + return playerName; + } + + return Utils::String::VA("[%s]%s", ClientState[clientNum], playerName); + } + + void ClanTags::SendClanTagsToClients() + { + std::string list; + + for (std::size_t i = 0; i < Game::MAX_CLIENTS; ++i) + { + list.append(std::format("\\{}\\{}", std::to_string(i), ClientState[i])); + } + + const auto* command = Utils::String::VA("%c clanNames \"%s\"", 22, list.data()); + Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, command); + } + + void ClanTags::ParseClanTags(const char* infoString) + { + for (std::size_t i = 0; i < Game::MAX_CLIENTS; ++i) + { + const auto* clanTag = Game::Info_ValueForKey(infoString, std::to_string(i).data()); + + if (clanTag[0] == '\0') + { + ClientState[i][0] = '\0'; + } + else + { + strncpy_s(ClientState[i], clanTag, _TRUNCATE); + } + } + } + + int ClanTags::CL_FilterChar(unsigned char input) + { + if (input == '^') + { + return ' '; + } + if (input < ' ') + { + return -1; + } + + if (input == 188 || input == 189) + { + return -1; + } + + return input; + } + + void ClanTags::CL_SanitizeClanName() + { + char saneNameBuf[5]; + std::memset(saneNameBuf, 0, sizeof(saneNameBuf)); + + auto* saneName = saneNameBuf; + const auto* currentName = Game::Dvar_GetString("clanName"); + if (currentName) + { + auto nameLen = std::strlen(currentName); + for (std::size_t i = 0; i < nameLen; ++i) + { + auto curChar = CL_FilterChar(static_cast(currentName[i])); + if (curChar > 0) + { + *saneName++ = curChar & 0xFF; + } + } + + Game::Dvar_SetStringByName("clanName", saneNameBuf); + } + } + + char* ClanTags::GamerProfile_GetClanName(int controllerIndex) + { + assert(static_cast(controllerIndex) < Game::MAX_LOCAL_CLIENTS); + + CL_SanitizeClanName(); + strncpy_s(Game::gamerSettings[0].exeConfig.clanPrefix, Game::Dvar_GetString("clanName"), _TRUNCATE); + + return Game::gamerSettings[controllerIndex].exeConfig.clanPrefix; + } + + void ClanTags::Dvar_InfoString_Stub(char* s, const char* key, const char* value) + { + Utils::Hook::Call(0x4AE560)(s, key, value); // Info_SetValueForKey + + // Set 'clanAbbrev' in the info string + Utils::Hook::Call(0x4AE560)(s, "clanAbbrev", GamerProfile_GetClanName(0)); // Info_SetValueForKey + } + + void ClanTags::ClientUserinfoChanged(const char* s, int clientNum) + { + assert(static_cast(clientNum) < Game::MAX_CLIENTS); + + auto* clanAbbrev = Game::Info_ValueForKey(s, "clanAbbrev"); + + if (clanAbbrev[0] == '\0') + { + ClientState[clientNum][0] = '\0'; + } + else + { + strncpy_s(ClientState[clientNum], clanAbbrev, _TRUNCATE); + } + + SendClanTagsToClients(); + } + + void __declspec(naked) ClanTags::ClientUserinfoChanged_Stub() + { + __asm + { + pushad + + push [esp + 0x20 + 0x824] // clientNum + push ecx // s + call ClientUserinfoChanged + add esp, 0x8 + + popad + + push 0x445334 // Return address + push 0x47C820 // Info_ValueForKey + // Jump to Info_ValueForKey & add return address + retn + } + } + + void __declspec(naked) ClanTags::DrawPlayerNameOnScoreboard() + { + __asm + { + push eax + pushad + + push edi + push [ebp] + + call GetClanTagWithName + add esp, 0x8 + + mov [esp + 0x20], eax + + popad + pop edi + + push 0x591247 // Return address + push 0x5909E0 // DrawListString + retn + } + } + + // s1 is always an empty string + int ClanTags::PartyClient_Frame_Stub(const char* s0, [[maybe_unused]] const char* s1) + { + return Utils::Hook::Call(0x4B0100)(s0, GamerProfile_GetClanName(0)); // I_strcmp + } + + // clanAbbrev is always an empty string + void ClanTags::Party_UpdateClanName_Stub(Game::PartyData* party, [[maybe_unused]] const char* clanAbbrev) + { + Utils::Hook::Call(0x4B3B10)(party, GamerProfile_GetClanName(0)); // Party_UpdateClanName + } + + void ClanTags::PlayerCards_SetCachedPlayerData(Game::PlayerCardData* data, const int clientNum) + { + strncpy_s(data->clanAbbrev, ClientState[clientNum], _TRUNCATE); + } + + void __declspec(naked) ClanTags::PlayerCards_SetCachedPlayerData_Stub() + { + static DWORD func = 0x4D6F80; // I_strncpyz + + __asm + { + call func + add esp, 0xC + + mov byte ptr [esi + 0x3C], 0x0 + + // Copy the clanName + push [esp + 0xC] // clientNum + push esi // g_PlayerCardCache + call PlayerCards_SetCachedPlayerData + add esp, 0x8 + + // Exit function + pop esi + ret + } + } + + Game::PlayerCardData* ClanTags::PlayerCards_GetLiveProfileDataForClient_Stub(const unsigned int clientIndex) + { + auto* result = Utils::Hook::Call(0x46C0F0)(clientIndex); + strncpy_s(result->clanAbbrev, ClientState[clientIndex], _TRUNCATE); + + return result; + } + + Game::PlayerCardData* ClanTags::PlayerCards_GetLiveProfileDataForController_Stub(const unsigned int controllerIndex) + { + auto* result = Utils::Hook::Call(0x463B90)(controllerIndex); + strncpy_s(result->clanAbbrev, GamerProfile_GetClanName(static_cast(controllerIndex)), _TRUNCATE); // controllerIndex should always be 0 + + return result; + } + + Game::PlayerCardData* ClanTags::PlayerCards_GetPartyMemberData(const int localClientNum, const Game::PlayerCardClientLookupType lookupType, const unsigned int memberIndex) + { + auto* result = Utils::Hook::Call(0x4A4A90)(localClientNum, lookupType, memberIndex); + strncpy_s(result->clanAbbrev, ClientState[memberIndex], _TRUNCATE); // controllerIndex should always be 0 + + return result; + } + + ClanTags::ClanTags() + { + Scheduler::Once([] + { + ClanName = Game::Dvar_RegisterString("clanName", "", Game::DVAR_ARCHIVE, + "Your clan abbreviation"); + }, Scheduler::Pipeline::MAIN); + + std::memset(&ClientState, 0, sizeof(char[Game::MAX_CLIENTS][5])); + + ServerCommands::OnCommand(22, [](Command::Params* params) + { + if (std::strcmp(params->get(1), "clanNames") == 0) + { + if (params->size() == 3) + { + ParseClanTags(params->get(2)); + return true; + } + } + + return false; + }); + + Utils::Hook(0x430B00, Dvar_InfoString_Stub, HOOK_CALL).install()->quick(); + + Utils::Hook(0x44532F, ClientUserinfoChanged_Stub, HOOK_JUMP).install()->quick(); + + // clanName before playerName + Utils::Hook(0x591242, DrawPlayerNameOnScoreboard, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x49765B, PartyClient_Frame_Stub, HOOK_CALL).install()->quick(); + Utils::Hook(0x49767E, Party_UpdateClanName_Stub, HOOK_CALL).install()->quick(); + + // clanName in the PlayerCard (GetPlayerCardClientData) + Utils::Hook(0x458DF4, PlayerCards_SetCachedPlayerData_Stub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x62EAB6, PlayerCards_GetLiveProfileDataForClient_Stub, HOOK_CALL).install()->quick(); + Utils::Hook(0x62EAC3, PlayerCards_GetLiveProfileDataForController_Stub, HOOK_CALL).install()->quick(); + Utils::Hook(0x62EAE8, PlayerCards_GetPartyMemberData, HOOK_CALL).install()->quick(); + + // clanName in CG_Obituary + Utils::Hook(0x586DD6, PlayerName::GetClientName, HOOK_CALL).install()->quick(); + Utils::Hook(0x586E2A, PlayerName::GetClientName, HOOK_CALL).install()->quick(); + + Command::Add("statGet", [](Command::Params* params) + { + if (params->size() < 2) + { + Logger::PrintError(Game::CON_CHANNEL_SERVER, "statget usage: statget \n"); + return; + } + + const auto index = std::atoi(params->get(1)); + const auto stat = Game::LiveStorage_GetStat(0, index); + Logger::Print(Game::CON_CHANNEL_SYSTEM, "Stat {}: {}\n", index, stat); + }); + } +} diff --git a/src/Components/Modules/ClanTags.hpp b/src/Components/Modules/ClanTags.hpp new file mode 100644 index 00000000..dc1c7952 --- /dev/null +++ b/src/Components/Modules/ClanTags.hpp @@ -0,0 +1,48 @@ +#pragma once + +namespace Components +{ + class ClanTags : public Component + { + public: + ClanTags(); + + static const char* GetClanTagWithName(int clientNum, const char* playerName); + + static void SendClanTagsToClients(); + + static void CL_SanitizeClanName(); + + private: + static Game::dvar_t* ClanName; + + static const char* dvarNameList[]; + + static char ClientState[Game::MAX_CLIENTS][5]; + + static void ParseClanTags(const char* infoString); + + static int CL_FilterChar(unsigned char input); + + static char* GamerProfile_GetClanName(int controllerIndex); + + static void Dvar_InfoString_Stub(char* s, const char* key, const char* value); + + static void SetCachedPlayerData(int clientNum); + + static void ClientUserinfoChanged(const char* s, int clientNum); + static void ClientUserinfoChanged_Stub(); + + static void DrawPlayerNameOnScoreboard(); + + static int PartyClient_Frame_Stub(const char* s0, const char* s1); + static void Party_UpdateClanName_Stub(Game::PartyData* party, const char* clanAbbrev); + + static void PlayerCards_SetCachedPlayerData(Game::PlayerCardData* data, int clientNum); + static void PlayerCards_SetCachedPlayerData_Stub(); + + static Game::PlayerCardData* PlayerCards_GetLiveProfileDataForClient_Stub(unsigned int clientIndex); + static Game::PlayerCardData* PlayerCards_GetLiveProfileDataForController_Stub(unsigned int controllerIndex); + static Game::PlayerCardData* PlayerCards_GetPartyMemberData(int localClientNum, Game::PlayerCardClientLookupType lookupType, unsigned int memberIndex); + }; +} diff --git a/src/Components/Modules/Clantags.cpp b/src/Components/Modules/Clantags.cpp deleted file mode 100644 index eac6a916..00000000 --- a/src/Components/Modules/Clantags.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include - -namespace Components -{ - std::string ClanTags::Tags[18]; - - void ClanTags::ParseClantags(const char* infoString) - { - for (int i = 0; i < 18; i++) - { - const char* clantag = Game::Info_ValueForKey(infoString, std::to_string(i).data()); - - if (clantag) ClanTags::Tags[i] = clantag; - else ClanTags::Tags[i].clear(); - } - } - - void ClanTags::SendClantagsToClients() - { - std::string list; - - for (int i = 0; i < 18; ++i) - { - char clantag[5] = { 0 }; - - if (Game::svs_clients[i].state >= 3) - { - strncpy_s(clantag, Game::Info_ValueForKey(Game::svs_clients[i].connectInfoString, "clantag"), 4); - } - - list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).data(), clantag)); - } - - std::string command = Utils::String::VA("%c clantags \"%s\"", 22, list.data()); - Game::SV_GameSendServerCommand(-1, Game::SV_CMD_CAN_IGNORE, command.data()); - } - - const char* ClanTags::GetUserClantag(std::uint32_t /*clientnum*/, const char* playername) - { -#if 0 - if (ClanTags::Tags[clientnum].empty()) return playername; - return Utils::String::VA("[%s] %s", ClanTags::Tags[clientnum].data(), playername); -#else - return playername; -#endif - - } - - __declspec(naked) void ClanTags::DrawPlayerNameOnScoreboard() - { - __asm - { - push eax - pushad - - push edi - push [ebp] - - call ClanTags::GetUserClantag - add esp, 8 - - mov [esp + 20h], eax - - popad - pop edi - - push 591247h // Return address - push 5909E0h // Draw string func - retn - } - } - - ClanTags::ClanTags() - { - // Create clantag dvar - Scheduler::Once([] - { - Dvar::Register("clantag", "", Game::DVAR_USERINFO | Game::DVAR_ARCHIVE, - "If set, your clantag will be shown on the scoreboard."); - }, Scheduler::Pipeline::MAIN); - - // Servercommand hook - ServerCommands::OnCommand(22, [](Command::Params* params) - { - if (params->get(1) == "clantags"s && !Dedicated::IsEnabled()) - { - if (params->size() == 3) - { - ClanTags::ParseClantags(params->get(2)); - return true; - } - } - - return false; - }); - - // Draw clantag before playername - Utils::Hook(0x591242, ClanTags::DrawPlayerNameOnScoreboard).install()->quick(); - } -} diff --git a/src/Components/Modules/Clantags.hpp b/src/Components/Modules/Clantags.hpp deleted file mode 100644 index ea7bca39..00000000 --- a/src/Components/Modules/Clantags.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -namespace Components -{ - class ClanTags : public Component - { - public: - static void ParseClantags(const char * infoString); - static void SendClantagsToClients(); - static const char* GetUserClantag(std::uint32_t clientnum, const char * playername); - - ClanTags(); - - private: - static std::string Tags[18]; - - static void DrawPlayerNameOnScoreboard(); - - }; -} diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index b0e410e9..19057580 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -334,17 +334,17 @@ namespace Components ClientCommand::Add("kill", []([[maybe_unused]] Game::gentity_s* ent, [[maybe_unused]] Command::ServerParams* params) { assert(ent->client != nullptr); - assert(ent->client->connected != Game::clientConnected_t::CON_DISCONNECTED); + assert(ent->client->sess.connected != Game::CON_DISCONNECTED); - if (ent->client->sessionState != Game::sessionState_t::SESS_STATE_PLAYING || !ClientCommand::CheatsOk(ent)) + if (ent->client->sess.sessionState != Game::SESS_STATE_PLAYING || !ClientCommand::CheatsOk(ent)) return; Scheduler::Once([ent] { - ent->flags &= ~(Game::entityFlag::FL_GODMODE | Game::entityFlag::FL_DEMI_GODMODE); + ent->flags &= ~(Game::FL_GODMODE | Game::FL_DEMI_GODMODE); ent->health = 0; ent->client->ps.stats[0] = 0; - Game::player_die(ent, ent, ent, 100000, 12, 0, nullptr, Game::hitLocation_t::HITLOC_NONE, 0); + Game::player_die(ent, ent, ent, 100000, 12, 0, nullptr, Game::HITLOC_NONE, 0); }, Scheduler::Pipeline::SERVER); }); } diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 349feb90..d7d18992 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -68,7 +68,7 @@ namespace Components { maxclientCount = Dvar::Var("party_maxplayers").get(); //maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); - clientCount = Game::PartyHost_CountMembers(reinterpret_cast(0x1081C00)); + clientCount = Game::PartyHost_CountMembers(reinterpret_cast(0x1081C00)); } wclear(Console::InfoWindow); diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index 5e475633..436a13a4 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -87,7 +87,7 @@ namespace Components { list.append(Utils::String::VA(" %llX", Game::svs_clients[i].steamID)); - Utils::InfoString info(Game::svs_clients[i].connectInfoString); + Utils::InfoString info(Game::svs_clients[i].userinfo); list.append(Utils::String::VA(" %llX", strtoull(info.get("realsteamId").data(), nullptr, 16))); } else @@ -294,7 +294,6 @@ namespace Components Scheduler::Loop([] { CardTitles::SendCustomTitlesToClients(); - //Clantags::SendClantagsToClients(); }, Scheduler::Pipeline::SERVER, 10s); // Heartbeats diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 21e4444c..9e3b1d5b 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -760,7 +760,7 @@ namespace Components else { // Score and ping are irrelevant - const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); + const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); if (!namePtr || !namePtr[0]) continue; playerInfo["name"] = namePtr; diff --git a/src/Components/Modules/Events.cpp b/src/Components/Modules/Events.cpp index b73ef3a1..e03522ec 100644 --- a/src/Components/Modules/Events.cpp +++ b/src/Components/Modules/Events.cpp @@ -5,6 +5,7 @@ namespace Components Utils::Signal Events::ClientDisconnectSignal; Utils::Signal Events::SteamDisconnectSignal; Utils::Signal Events::ShutdownSystemSignal; + Utils::Signal Events::ClientInitSignal; Utils::Signal Events::ServerInitSignal; void Events::OnClientDisconnect(const Utils::Slot& callback) @@ -22,6 +23,11 @@ namespace Components ShutdownSystemSignal.connect(callback); } + void Events::OnClientInit(const Utils::Slot& callback) + { + ClientInitSignal.connect(callback); + } + void Events::OnSVInit(const Utils::Slot& callback) { ServerInitSignal.connect(callback); @@ -52,6 +58,14 @@ namespace Components Utils::Hook::Call(0x421EE0)(sys); // Scr_ShutdownSystem } + void Events::CL_InitOnceForAllClients_HK() + { + ClientInitSignal(); + ClientInitSignal.clear(); + + Utils::Hook::Call(0x404CA0)(); // CL_InitOnceForAllClients + } + void Events::SV_Init_Hk() { ServerInitSignal(); @@ -69,6 +83,8 @@ namespace Components Utils::Hook(0x47548B, Scr_ShutdownSystem_Hk, HOOK_CALL).install()->quick(); // G_LoadGame Utils::Hook(0x4D06BA, Scr_ShutdownSystem_Hk, HOOK_CALL).install()->quick(); // G_ShutdownGame + Utils::Hook(0x60BE5B, CL_InitOnceForAllClients_HK, HOOK_CALL).install()->quick(); // Com_Init_Try_Block_Function + Utils::Hook(0x4D3665, SV_Init_Hk, HOOK_CALL).install()->quick(); // SV_Init } } diff --git a/src/Components/Modules/Events.hpp b/src/Components/Modules/Events.hpp index 08a3675a..a47f6794 100644 --- a/src/Components/Modules/Events.hpp +++ b/src/Components/Modules/Events.hpp @@ -18,6 +18,8 @@ namespace Components static void OnVMShutdown(const Utils::Slot& callback); + static void OnClientInit(const Utils::Slot& callback); + // Client & Server (triggered once) static void OnSVInit(const Utils::Slot& callback); @@ -25,11 +27,13 @@ namespace Components static Utils::Signal ClientDisconnectSignal; static Utils::Signal SteamDisconnectSignal; static Utils::Signal ShutdownSystemSignal; + static Utils::Signal ClientInitSignal; static Utils::Signal ServerInitSignal; static void ClientDisconnect_Hk(int clientNum); static void SteamDisconnect_Hk(); static void Scr_ShutdownSystem_Hk(unsigned char sys); + static void CL_InitOnceForAllClients_HK(); static void SV_Init_Hk(); }; } diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 2d316acf..89b9c89f 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -859,6 +859,7 @@ namespace Components Menus::Add("ui_mp/iw4x_credits.menu"); Menus::Add("ui_mp/resetclass.menu"); Menus::Add("ui_mp/popup_customtitle.menu"); + Menus::Add("ui_mp/popup_customclan.menu"); } Menus::~Menus() diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 4a0a5524..d7b7f2cc 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -332,7 +332,7 @@ namespace Components else { maxclientCount = Dvar::Var("party_maxplayers").get(); - clientCount = Game::PartyHost_CountMembers(reinterpret_cast(0x1081C00)); + clientCount = Game::PartyHost_CountMembers(reinterpret_cast(0x1081C00)); } Utils::InfoString info; diff --git a/src/Components/Modules/PlayerName.cpp b/src/Components/Modules/PlayerName.cpp index 74d02168..11ca774d 100644 --- a/src/Components/Modules/PlayerName.cpp +++ b/src/Components/Modules/PlayerName.cpp @@ -44,14 +44,14 @@ namespace Components } } - char* PlayerName::GetClientName(int localClientNum, int index, char* buf, size_t size) + int PlayerName::GetClientName(int localClientNum, int index, char* buf, int size) { - Game::CL_GetClientName(localClientNum, index, buf, size); + const auto result = Game::CL_GetClientName(localClientNum, index, buf, size); - // Append clantag to username & remove the colors - strncpy_s(buf, size, TextRenderer::StripColors(ClanTags::GetUserClantag(index, buf)).data(), size); + // Prepend clanName to username & remove the colors + strncpy_s(buf, size, TextRenderer::StripColors(ClanTags::GetClanTagWithName(index, buf)).data(), size); - return buf; + return result; } char* PlayerName::CleanStrStub(char* string) diff --git a/src/Components/Modules/PlayerName.hpp b/src/Components/Modules/PlayerName.hpp index b1beaaa7..ccf61ff4 100644 --- a/src/Components/Modules/PlayerName.hpp +++ b/src/Components/Modules/PlayerName.hpp @@ -9,6 +9,8 @@ namespace Components static void UserInfoCopy(char* buffer, const char* name, size_t size); + static int GetClientName(int localClientNum, int index, char* buf, int size); + private: static Dvar::Var sv_allowColoredNames; // Message used when kicking players @@ -16,7 +18,6 @@ namespace Components static char* CleanStrStub(char* string); static void ClientCleanName(); - static char* GetClientName(int localClientNum, int index, char* buf, size_t size); static bool CopyClientNameCheck(char* dest, const char* source, int size); static void SV_UserinfoChangedStub(); diff --git a/src/Components/Modules/ServerCommands.cpp b/src/Components/Modules/ServerCommands.cpp index 8c67c49b..352e0154 100644 --- a/src/Components/Modules/ServerCommands.cpp +++ b/src/Components/Modules/ServerCommands.cpp @@ -64,5 +64,6 @@ namespace Components { // Server command receive hook Utils::Hook(0x59449F, ServerCommands::CG_DeployServerCommand_Stub).install()->quick(); + Utils::Hook::Nop(0x5944A4, 6); } } diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 685ca7cd..45f11e40 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -217,7 +217,7 @@ namespace Components else { // Score and ping are irrelevant - const auto* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); + const auto* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); if (!namePtr || !namePtr[0]) continue; name = namePtr; diff --git a/src/Components/Modules/UserInfo.cpp b/src/Components/Modules/UserInfo.cpp index d4dda49c..87a15245 100644 --- a/src/Components/Modules/UserInfo.cpp +++ b/src/Components/Modules/UserInfo.cpp @@ -63,10 +63,34 @@ namespace Components { const auto* ent = Game::GetPlayerEntity(entref); - Logger::Debug("Resetting name of {} ", ent->s.number); + Logger::Debug("Resetting name of {}", ent->s.number); UserInfoOverrides[ent->s.number].erase("name"); Game::ClientUserinfoChanged(ent->s.number); }); + + Script::AddMethod("SetClanTag", [](Game::scr_entref_t entref) // gsc: self setClanTag() + { + const auto* ent = Game::GetPlayerEntity(entref); + const auto* clanName = Game::Scr_GetString(0); + + if (clanName == nullptr) + { + Game::Scr_ParamError(0, "^1SetClanTag: Illegal parameter!\n"); + } + + Logger::Debug("Setting clanName of {} to {}", ent->s.number, clanName); + UserInfoOverrides[ent->s.number]["clanAbbrev"] = clanName; + Game::ClientUserinfoChanged(ent->s.number); + }); + + Script::AddMethod("ResetClanTag", [](Game::scr_entref_t entref) // gsc: self ResetClanTag() + { + const auto* ent = Game::GetPlayerEntity(entref); + + Logger::Debug("Resetting clanName of {}", ent->s.number); + UserInfoOverrides[ent->s.number].erase("clanAbbrev"); + Game::ClientUserinfoChanged(ent->s.number); + }); } UserInfo::UserInfo() diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index aff54283..5e4b2893 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -66,6 +66,8 @@ namespace Game CL_SelectStringTableEntryInDvar_f_t CL_SelectStringTableEntryInDvar_f = CL_SelectStringTableEntryInDvar_f_t(0x4A4560); CL_DrawStretchPic_t CL_DrawStretchPic = CL_DrawStretchPic_t(0x412490); CL_ConsoleFixPosition_t CL_ConsoleFixPosition = CL_ConsoleFixPosition_t(0x44A430); + CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount = CL_GetLocalClientActiveCount_t(0x5BAD90); + CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum = CL_ControllerIndexFromClientNum_t(0x449E30); Cmd_AddCommand_t Cmd_AddCommand = Cmd_AddCommand_t(0x470090); Cmd_AddServerCommand_t Cmd_AddServerCommand = Cmd_AddServerCommand_t(0x4DCE00); @@ -128,6 +130,8 @@ namespace Game Dvar_RegisterVec3Color_t Dvar_RegisterVec3Color = Dvar_RegisterVec3Color_t(0x4918B0); Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName = Dvar_GetUnpackedColorByName_t(0x406530); + Dvar_GetString_t Dvar_GetString = Dvar_GetString_t(0x4EC6B0); + Dvar_GetVariantString_t Dvar_GetVariantString = Dvar_GetVariantString_t(0x4C47E0); Dvar_FindVar_t Dvar_FindVar = Dvar_FindVar_t(0x4D5390); Dvar_InfoString_Big_t Dvar_InfoString_Big = Dvar_InfoString_Big_t(0x4D98A0); Dvar_SetCommand_t Dvar_SetCommand = Dvar_SetCommand_t(0x4EE430); @@ -253,6 +257,8 @@ namespace Game Live_GetPrestige_t Live_GetPrestige = Live_GetPrestige_t(0x430F90); Live_GetXp_t Live_GetXp = Live_GetXp_t(0x404C60); + LiveStorage_GetStat_t LiveStorage_GetStat = LiveStorage_GetStat_t(0x471F60); + Scr_AddSourceBuffer_t Scr_AddSourceBuffer = Scr_AddSourceBuffer_t(0x61ABC0); PC_ReadToken_t PC_ReadToken = PC_ReadToken_t(0x4ACCD0); @@ -498,8 +504,8 @@ namespace Game int* g_streamPosIndex = reinterpret_cast(0x16E5578); bool* g_lobbyCreateInProgress = reinterpret_cast(0x66C9BC2); - party_t** partyIngame = reinterpret_cast(0x1081C00); - PartyData_s** partyData = reinterpret_cast(0x107E500); + PartyData* g_lobbyData = reinterpret_cast(0x1081C00); + PartyData* g_partyData = reinterpret_cast(0x107E500); int* numIP = reinterpret_cast(0x64A1E68); netIP_t* localIP = reinterpret_cast(0x64A1E28); @@ -552,7 +558,7 @@ namespace Game scrVmPub_t* scrVmPub = reinterpret_cast(0x2040CF0); scrVarPub_t* scrVarPub = reinterpret_cast(0x201A408); - clientstate_t* clcState = reinterpret_cast(0xB2C540); + clientState_t* clcState = reinterpret_cast(0xB2C540); GfxScene* scene = reinterpret_cast(0x6944914); @@ -616,6 +622,11 @@ namespace Game clientConnection_t* clientConnections = reinterpret_cast(0xA1E878); + unsigned int* playerCardUIStringIndex = reinterpret_cast(0x62CD7A8); + char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast(0x62CB4F8); + + GamerSettingState* gamerSettings = reinterpret_cast(0x107D3E8); + void Sys_LockRead(FastCriticalSection* critSect) { InterlockedIncrement(&critSect->readCount); @@ -836,8 +847,8 @@ namespace Game { for (auto i = 0; i < *svs_clientCount; ++i) { - if (svs_clients[i].state != clientstate_t::CS_FREE - && svs_clients[i].netchan.remoteAddress.type == netadrtype_t::NA_BOT) + if (svs_clients[i].state != CS_FREE + && svs_clients[i].netchan.remoteAddress.type == NA_BOT) { SV_GameDropClient(i, "GAME_GET_TO_COVER"); } @@ -1746,6 +1757,5 @@ namespace Game ret } } - #pragma optimize("", on) } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 2b0d352b..f7828d12 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -97,7 +97,7 @@ namespace Game typedef void(__cdecl * CG_SetupWeaponDef_t)(int localClientNum, unsigned int weapIndex); extern CG_SetupWeaponDef_t CG_SetupWeaponDef; - typedef char*(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, size_t size); + typedef int(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, int size); extern CL_GetClientName_t CL_GetClientName; typedef int(__cdecl * CL_IsCgameInitialized_t)(); @@ -139,6 +139,12 @@ namespace Game typedef void(__cdecl * CL_ConsoleFixPosition_t)(); extern CL_ConsoleFixPosition_t CL_ConsoleFixPosition; + typedef int(__cdecl * CL_GetLocalClientActiveCount_t)(); + extern CL_GetLocalClientActiveCount_t CL_GetLocalClientActiveCount; + + typedef int(__cdecl * CL_ControllerIndexFromClientNum_t)(int localActiveClientNum); + extern CL_ControllerIndexFromClientNum_t CL_ControllerIndexFromClientNum; + typedef void(__cdecl * Cmd_AddCommand_t)(const char* cmdName, void(*function), cmd_function_t* allocedCmd, bool isKey); extern Cmd_AddCommand_t Cmd_AddCommand; @@ -325,6 +331,12 @@ namespace Game typedef void(__cdecl * Dvar_GetUnpackedColorByName_t)(const char* dvarName, float* expandedColor); extern Dvar_GetUnpackedColorByName_t Dvar_GetUnpackedColorByName; + typedef char*(__cdecl* Dvar_GetString_t)(const char* dvarName); + extern Dvar_GetString_t Dvar_GetString; + + typedef char*(__cdecl * Dvar_GetVariantString_t)(const char* dvarName); + extern Dvar_GetVariantString_t Dvar_GetVariantString; + typedef dvar_t*(__cdecl * Dvar_FindVar_t)(const char* dvarName); extern Dvar_FindVar_t Dvar_FindVar; @@ -456,7 +468,7 @@ namespace Game typedef void(__cdecl * Image_Release_t)(GfxImage* image); extern Image_Release_t Image_Release; - typedef char*(__cdecl * Info_ValueForKey_t)(const char* infoString, const char* key); + typedef char*(__cdecl * Info_ValueForKey_t)(const char* s, const char* key); extern Info_ValueForKey_t Info_ValueForKey; typedef void(__cdecl * Key_SetCatcher_t)(int localClientNum, int catcher); @@ -651,6 +663,9 @@ namespace Game typedef int(__cdecl * Live_GetXp_t)(int controllerIndex); extern Live_GetXp_t Live_GetXp; + typedef int(__cdecl * LiveStorage_GetStat_t)(int controllerIndex, int index); + extern LiveStorage_GetStat_t LiveStorage_GetStat; + typedef char*(__cdecl * Scr_AddSourceBuffer_t)(const char* filename, const char* extFilename, const char* codePos, bool archive); extern Scr_AddSourceBuffer_t Scr_AddSourceBuffer; @@ -663,16 +678,16 @@ namespace Game typedef void(__cdecl * PC_SourceError_t)(int, const char*, ...); extern PC_SourceError_t PC_SourceError; - typedef int(__cdecl * Party_GetMaxPlayers_t)(party_s* party); + typedef int(__cdecl * Party_GetMaxPlayers_t)(PartyData* party); extern Party_GetMaxPlayers_t Party_GetMaxPlayers; - typedef int(__cdecl * PartyHost_CountMembers_t)(PartyData_s* party); + typedef int(__cdecl * PartyHost_CountMembers_t)(PartyData* party); extern PartyHost_CountMembers_t PartyHost_CountMembers; typedef netadr_t *(__cdecl * PartyHost_GetMemberAddressBySlot_t)(int unk, void *party, const int slot); extern PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot; - typedef const char *(__cdecl * PartyHost_GetMemberName_t)(PartyData_s* party, const int clientNum); + typedef const char *(__cdecl * PartyHost_GetMemberName_t)(PartyData* party, const int clientNum); extern PartyHost_GetMemberName_t PartyHost_GetMemberName; typedef void(__cdecl * Playlist_ParsePlaylists_t)(const char* data); @@ -1116,6 +1131,10 @@ namespace Game typedef void*(__cdecl * Z_VirtualAlloc_t)(int size); extern Z_VirtualAlloc_t Z_VirtualAlloc; + constexpr std::size_t STATIC_MAX_LOCAL_CLIENTS = 1; + constexpr std::size_t MAX_LOCAL_CLIENTS = 1; + constexpr std::size_t MAX_CLIENTS = 18; + extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; @@ -1150,8 +1169,8 @@ namespace Game extern int* g_streamPosIndex; extern bool* g_lobbyCreateInProgress; - extern party_t** partyIngame; - extern PartyData_s** partyData; + extern PartyData* g_lobbyData; + extern PartyData* g_partyData; extern int* numIP; extern netIP_t* localIP; @@ -1205,7 +1224,7 @@ namespace Game extern scrVmPub_t* scrVmPub; extern scrVarPub_t* scrVarPub; - extern clientstate_t* clcState; + extern clientState_t* clcState; extern GfxScene* scene; @@ -1273,6 +1292,12 @@ namespace Game extern clientConnection_t* clientConnections; + constexpr std::size_t PLAYER_CARD_UI_STRING_COUNT = 18; + extern unsigned int* playerCardUIStringIndex; + extern char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38]; + + extern GamerSettingState* gamerSettings; + void Sys_LockRead(FastCriticalSection* critSect); void Sys_UnlockRead(FastCriticalSection* critSect); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index aaa59f7a..0801b417 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -232,7 +232,7 @@ namespace Game CS_CONNECTED = 0x3, CS_CLIENTLOADING = 0x4, CS_ACTIVE = 0x5, - } clientstate_t; + } clientState_t; enum serverState_t { @@ -1611,6 +1611,32 @@ namespace Game unsigned int playerCardNameplate; }; + enum PlayerCardClientLookupType + { + PLAYERCARD_LOOKUP_SCRIPTSLOT = 0x0, + PLAYERCARD_LOOKUP_LIVEPROFILE_CLIENT = 0x1, + PLAYERCARD_LOOKUP_LIVEPROFILE_CONTROLLER = 0x2, + PLAYERCARD_LOOKUP_LOBBY = 0x3, + PLAYERCARD_LOOKUP_MYTEAM = 0x4, + PLAYERCARD_LOOKUP_ENEMYTEAM = 0x5, + PLAYERCARD_LOOKUP_COUNT = 0x6, + }; + + struct PlayerCardData + { + unsigned int lastUpdateTime; + unsigned int titleIndex; + unsigned int iconIndex; + unsigned int nameplateIndex; + int rank; + int prestige; + team_t team; + char name[32]; + char clanAbbrev[5]; + }; + + static_assert(sizeof(PlayerCardData) == 0x44); + enum usercmdButtonBits { CMD_BUTTON_ATTACK = 0x1, @@ -5082,18 +5108,6 @@ namespace Game char uiName[32]; }; - typedef struct party_s - { - unsigned char pad1[544]; - int privateSlots; - int publicSlots; - } party_t; - - typedef struct PartyData_s - { - DWORD unk; - } PartyData_t; - struct fileInIwd_s { unsigned int pos; @@ -6046,15 +6060,66 @@ namespace Game VISIONSETCOUNT } visionSetMode_t; + enum hintType_t + { + HINT_NONE = 0x0, + HINT_NOICON = 0x1, + HINT_ACTIVATE = 0x2, + HINT_HEALTH = 0x3, + HINT_FRIENDLY = 0x4, + FIRST_WEAPON_HINT = 0x5, + LAST_WEAPON_HINT = 0x57C, + HINT_NUM_HINTS = 0x57D, + }; + + struct playerTeamState_t + { + int location; + }; + + struct clientSession_t + { + sessionState_t sessionState; + int forceSpectatorClient; + int killCamEntity; + int killCamLookAtEntity; + int status_icon; + int archiveTime; + int score; + int deaths; + int kills; + int assists; + unsigned __int16 scriptPersId; + clientConnected_t connected; + usercmd_s cmd; + usercmd_s oldcmd; + int localClient; + int predictItemPickup; + char newnetname[16]; + int maxHealth; + int enterTime; + playerTeamState_t teamState; + int voteCount; + int teamVoteCount; + float moveSpeedScaleMultiplier; + int viewmodelIndex; + int noSpectate; + int teamInfo; + clientState_s cs; + int psOffsetTime; + int hasRadar; + int isRadarBlocked; + int radarMode; + int weaponHudIconOverrides[6]; + unsigned int unusableEntFlags[64]; + float spectateDefaultPos[3]; + float spectateDefaultAngles[3]; + }; + typedef struct gclient_s { playerState_s ps; - sessionState_t sessionState; // 12572 - unsigned char __pad0[40]; - clientConnected_t connected; // 12616 - unsigned char __pad1[144]; - team_t team; // 12764 - unsigned char __pad2[436]; + clientSession_t sess; int flags; // 13204 int spectatorClient; int lastCmdTime; @@ -6065,7 +6130,13 @@ namespace Game unsigned char __pad3[324]; // 13232 int visionDuration[5]; char visionName[5][64]; - unsigned char __pad4[36]; + int lastStand; + int lastStandTime; + int hudElemLastAssignedSoundID; + float lockedTargetOffset[3]; + unsigned __int16 attachShieldTagName; + hintType_t hintForcedType; + int hintForcedString; } gclient_t; static_assert(sizeof(gclient_t) == 13932); @@ -6224,14 +6295,14 @@ namespace Game typedef struct client_s { - clientstate_t state; // 0 - char __pad0[4]; // 4 + clientState_t state; // 0 + int sendAsActive; // 4 int deltaMessage; // 8 char __pad1[12]; // 12 netchan_t netchan; // 24 char __pad2[20]; // 1604 const char* delayDropReason; // 1624 - char connectInfoString[1024]; // 1628 + char userinfo[1024]; // 1628 char __pad3[132096]; // 2652 int reliableSequence; // 134748 int reliableAcknowledge; // 134752 @@ -6244,7 +6315,7 @@ namespace Game char lastClientCommandString[1024]; // 134816 gentity_t* gentity; // 135840 char name[16]; // 135844 - char __pad4[4]; // 135860 + int nextReliableTime; // 135860 int lastPacketTime; // 135864 int lastConnectTime; // 135868 int snapNum; // 135872 @@ -7875,6 +7946,8 @@ namespace Game unsigned int playerCardNameplate; }; + static_assert(sizeof(clientInfo_t) == 0x52C); + struct cgs_t { int viewX; @@ -8181,6 +8254,375 @@ namespace Game static_assert(sizeof(DeferredQueue) == 0x5908); + struct GamerSettingCommonConfig + { + float viewSensitivity; + float snd_volume; + float blacklevel; + float gpadButtonLStickDeflect; + float gpadButtonRStickDeflect; + float safearea_adjusted_horizontal; + float safearea_adjusted_vertical; + int playTimeSP; + int playTimeMP; + int playTimeSO; + int percentCompleteSP; + int percentCompleteMP; + int percentCompleteSO; + float gamma; + bool hasEverPlayed_MainMenu; + bool hasEverPlayed_SP; + bool hasEverPlayed_SO; + bool hasEverPlayed_MP; + bool invertPitch; + bool autoAim; + bool delicateFlower; + char gpadButtonsConfig[32]; + char gpadSticksConfig[32]; + }; + + struct KeyPairStringData + { + short index; + short maxSize; + }; + + union KeyPairDataUnion + { + char byteVal; + bool boolVal; + short shortVal; + int intVal; + float floatVal; + KeyPairStringData stringData; + }; + + struct GamerSettingKeyPair + { + char type; + char unused[3]; + KeyPairDataUnion u; + }; + + struct GamerSettingExeConfig + { + int playlist; + bool mapPrefs[16]; + char clanPrefix[5]; + }; + + struct GamerSettingState + { + bool isProfileLoggedIn; + bool errorOnRead; + GamerSettingCommonConfig commonConfig; + GamerSettingKeyPair commonKeyPairs[50]; + char commonKeyPairsStringPool[512]; + GamerSettingExeConfig exeConfig; + GamerSettingKeyPair exeKeyPairs[50]; + char exeKeyPairsStringPool[512]; + }; + + static_assert(sizeof(GamerSettingState) == 0x7C0); + + struct SessionStaticData + { + char* sessionName; + bool registerUsersWithVoice; + }; + + enum IWNetServerSessionStatus + { + SESSION_ONCLIENTONLY = 0x0, + SESSION_BEINGCREATED = 0x1, + SESSION_CREATED = 0x2, + SESSION_BEINGDELETED = 0x3, + }; + + struct IWNetServerInfoAboutPlayer + { + bool active; + __int64 uid; + char skill; + char teamIndex; + int mapPackFlags; + }; + + struct IWNetSessionStatus + { + IWNetServerSessionStatus status; + int sessionId; + int lastHeartbeatSent; + bool needsUpdate; + bool updatingPlayers; + int newPlayerCount; + IWNetServerInfoAboutPlayer pendingServerInfoForPlayers[18]; + }; + + struct XSESSION_INFO + { + XNKID sessionID; + XNADDR hostAddress; + XNKEY keyExchangeKey; + }; + + struct ClientInfo + { + bool registered; + bool voiceRegistered; + unsigned __int64 xuid; + int natType; + netadr_t addr; + int voiceConnectivityBits; + int lastConnectivityTestTime; + bool muted; + bool privateSlot; + }; + + struct NomineeInfo + { + int upload; + int NAT; + bool onLSP; + int connectivity; + int cpuSpeed; + int avgPing; + }; + + struct RegisteredUser + { + bool active; + unsigned __int64 xuid; + }; + + struct SessionDynamicData + { + bool sessionHandle; + IWNetSessionStatus iwnetServerSessionStatus; + XSESSION_INFO sessionInfo; + bool keysGenerated; + bool sessionStartCalled; + unsigned __int64 sessionNonce; + int privateSlots; + int publicSlots; + int flags; + bool qosListenEnabled; + ClientInfo users[18]; + int voiceConnectivityBits; + int sessionCreateController; + int sessionDeleteTime; + RegisteredUser internalRegisteredUsers[18]; + }; + + struct SessionData + { + SessionStaticData staticData; + SessionDynamicData dyn; + }; + + struct BestHostData + { + int nominee; + NomineeInfo info; + int lastHeardFrom; + int lastSentTo; + }; + + struct BandwidthTestPerClientData + { + int bytesReceived; + }; + + struct BandwidthTestData + { + int testIndex; + int testClientNum; + int startTimeArbitrator; + int announceTime; + int winnerClientNum; + BandwidthTestPerClientData clientData[18]; + char testClientName[32]; + bool inProgress; + int startTime; + int roundsComplete; + bool receiving; + int receiveIndex; + int receiveStartTime; + int receiveBytes; + int resultsSendTime; + }; + + struct MigrateData + { + bool migrateActive; + bool weAreArbitrating; + int arbitratorClientNum; + int indexBits; + int startTime; + int timeoutDuration; + int lastBroadcastTime; + bool decidedOurNominee; + BestHostData bestHost; + int expectedNewHost; + BandwidthTestData bandwidthTestData; + }; + + struct QoSData + { + float percent; + }; + + struct PartyInfo + { + bool active; + XSESSION_INFO info; + int occupiedPublicSlots; + int occupiedPrivateSlots; + int numPublicSlots; + int numPrivateSlots; + int pingBias; + int ping; + int upload; + int desirability; + }; + + struct PartyMember + { + char status; + bool headsetPresent; + char gamertag[32]; + char clanAbbrev[5]; + int qport; + char challenge[6]; + int lastPacketTime; + int lastHeartbeatTime; + int lastPartyStateAck; + XNADDR xnaddr; + int availableMapPackFlags; + int ackedMembers; + XNKID privatePartyId; + int subpartyIndex; + int trueSkill; + int rank; + int prestige; + int team; + unsigned __int16 score; + int deaths; + bool vetoedMap; + unsigned int playerCardIcon; + unsigned int playerCardTitle; + unsigned int playerCardNameplate; + int voiceConnectivityBits; + bool invited; + int natType; + unsigned __int64 player; + bool migrateHeardFrom; + int migratePingTime; + int migratePing; + bool migrateNominated; + NomineeInfo migrateNomineeInfo; + }; + + struct SubpartyInfo + { + int members[18]; + int count; + int skill; + int score; + int team; + }; + + struct PartyHostDetails + { + int partyListSlot; + netadr_t addr; + XSESSION_INFO sessionInfo; + int lastPacketTime; + int lastPacketSentTime; + int numPrivateSlots; + int numPublicSlots; + int hostNum; + bool accepted; + char challenge[6]; + }; + + struct PartyHostData + { + int partyStateChangeTime; + int partyStateLastSendTime; + int expectedPlayers; + int vetoPassTime; + bool vetoPossible; + bool preloadingMap; + bool firstLobby; + bool migrateAfterRound; + bool stopAfterRound; + int partyCreationTime; + }; + + struct PartyData + { + SessionData* session; + SessionData* presenceSession; + SessionData* searchSession; + MigrateData migrateData; + QoSData qosData; + PartyInfo* partyList; + int partyListSize; + PartyMember partyMembers[18]; + SubpartyInfo subparties[18]; + int subpartyCount; + PartyHostDetails currentHost; + PartyHostDetails potentialHost; + PartyHostData hostData; + unsigned __int64 lobbySteamID; + int areWeHost; + int joiningAnotherParty; + int searchingForGames; + int inParty; + int party_systemActive; + bool veto; + int vetoTime; + int headsetPresent; + int headsetTime; + int clanAbbrevTime; + int rankTime; + int playerCardTime; + int uploadSentTime; + int voiceBitsTime; + int idTime; + int availableMapPackFlagsTime; + int searchStartTime; + int searchEndTime; + int joinAttemptForUI; + int lastMergeTime; + int mergeAttemptStartTime; + int originalPartiesInList; + int partyId; + int nextSessionSearchTime; + int mapPackFlags; + int lastPartyStateTime; + int gameStartTime; + int interEndTime; + int inactiveKeepaliveTime; + int hostTimeouts; + char lobbyFlags; + PartyData* partyToNotify; + bool registeredWithArbitration; + bool rejoining; + int partyStatePacketCount; + int partyStateLastMemberIndex; + int unfinishedPartServerTimes[2]; + msg_t partyStatePartMsgs[2]; + char partyStatePartMsgBufs[2][1400]; + char lastEntries[8]; + int currentEntry; + char axisWins; + char alliesWins; + }; + + static_assert(sizeof(PartyData) == 0x23D8); + #pragma endregion #ifndef IDA