diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 67398577..896f00a7 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -95,7 +95,7 @@ namespace bots num_bots = atoi(params.get(1)); } - num_bots = std::min(num_bots, *game::mp::svs_numclients);; + num_bots = std::min(num_bots, *game::mp::svs_numclients); for (auto i = 0; i < num_bots; i++) { diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 3871a764..08222477 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -126,12 +126,16 @@ namespace dedicated void kill_server() { - for (auto i = 0; i < *game::mp::svs_numclients; ++i) + const auto* svs_clients = *game::mp::svs_clients; + if (svs_clients != nullptr) { - if (game::mp::svs_clients[i].header.state >= 3) + for (auto i = 0; i < *game::mp::svs_numclients; ++i) { - game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE, - utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); + if (svs_clients[i].header.state >= 3) + { + game::SV_GameSendServerCommand(i, game::SV_CMD_CAN_IGNORE, + utils::string::va("r \"%s\"", "EXE_ENDOFGAME")); + } } } @@ -156,6 +160,34 @@ namespace dedicated game::Com_Error(game::ERR_DROP, "%s", buffer); } + + utils::hook::detour ui_set_active_menu_hook; + void ui_set_active_menu_stub(void* a1, int a2) + { + static auto done = false; + if (done && (a2 == 6 || a2 == 7)) + { + return; + } + + if (a2 == 6 || a2 == 7) + { + done = true; + } + + ui_set_active_menu_hook.invoke(a1, a2); + } + + utils::hook::detour sub_552830_hook; + void* sub_552830_stub() + { + // sub_554D00 svs_clients along with other svs stuff + // Upon loading a 2nd map (ex. doing map mp_bog; map mp_crash) sub_552830 is called instead of sub_554D00 + // But svs stuff is already deallocated so it will read bad memory -> crash + // Calling sub_554D00 makes sure it reallocates that stuff first + utils::hook::invoke(0x554D00_b); + return sub_552830_hook.invoke(); + } } void initialize() @@ -292,6 +324,11 @@ namespace dedicated utils::hook::set(0x1D48B0_b, 0xC3); // related to shader caching / techsets / fastfilesc utils::hook::set(0x3A1940_b, 0xC3); // DB_ReadPackedLoadedSounds + // Workaround for server spamming 'exec default_xboxlive.cfg' when not running + ui_set_active_menu_hook.create(0x1E4D80_b, ui_set_active_menu_stub); + + sub_552830_hook.create(0x552830_b, sub_552830_stub); + // initialize the game after onlinedataflags is 32 (workaround) scheduler::schedule([=]() { diff --git a/src/client/component/dedicated_info.cpp b/src/client/component/dedicated_info.cpp index f2b02b8b..fa5c9a34 100644 --- a/src/client/component/dedicated_info.cpp +++ b/src/client/component/dedicated_info.cpp @@ -19,7 +19,7 @@ namespace dedicated_info scheduler::loop([]() { auto* sv_running = game::Dvar_FindVar("sv_running"); - if (!sv_running || !sv_running->current.enabled) + if (!sv_running || !sv_running->current.enabled || (*game::mp::svs_clients) == nullptr) { SetConsoleTitle("H1-Mod Dedicated Server"); return; @@ -32,12 +32,14 @@ namespace dedicated_info auto bot_count = 0; auto client_count = 0; - for (auto i = 0; i < sv_maxclients->current.integer; i++) + const auto svs_clients = *game::mp::svs_clients; + + for (auto i = 0; i < *game::mp::svs_numclients; i++) { - auto* client = &game::mp::svs_clients[i]; + const auto client = svs_clients[i]; auto* self = &game::mp::g_entities[i]; - if (client->header.state >= 1 && self && self->client) + if (client.header.state >= 1 && self && self->client) { client_count++; if (game::SV_BotIsBot(i)) @@ -54,8 +56,9 @@ namespace dedicated_info static_cast(strlen(sv_hostname->current.string)) + 1); SetConsoleTitle(utils::string::va("%s on %s [%d/%d] (%d)", cleaned_hostname.data(), - mapname->current.string, client_count, - sv_maxclients->current.integer, bot_count)); + mapname->current.string, client_count, + sv_maxclients->current.integer, bot_count) + ); }, scheduler::pipeline::main, 1s); } }; diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 298eade2..4a851012 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -122,28 +122,28 @@ namespace party utils::hook::invoke(0x1404FB210, dvar_name, string); } - void disconnect_stub() + void disconnect() { if (!game::VirtualLobby_Loaded()) { if (game::CL_IsCgameInitialized()) { - // CL_ForwardCommandToServer - // utils::hook::invoke(0x140253480, 0, "disconnect"); + // CL_AddReliableCommand + utils::hook::invoke(0x12B810_b, 0, "disconnect"); // CL_WritePacket - // utils::hook::invoke(0x14024DB10, 0); + utils::hook::invoke(0x13D490_b, 0); } // CL_Disconnect - // utils::hook::invoke(0x140252060, 0); + utils::hook::invoke(0x12F080_b, 0); } } - utils::hook::detour cldisconnect_hook; + utils::hook::detour cl_disconnect_hook; void cl_disconnect_stub(int a1) { party::clear_sv_motd(); - cldisconnect_hook.invoke(a1); + cl_disconnect_hook.invoke(a1); } const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a) @@ -192,9 +192,15 @@ namespace party int get_client_count() { auto count = 0; + const auto* svs_clients = *game::mp::svs_clients; + if (svs_clients == nullptr) + { + return count; + } + for (auto i = 0; i < *game::mp::svs_numclients; ++i) { - if (game::mp::svs_clients[i].header.state >= 1) + if (svs_clients[i].header.state >= 1) { ++count; } @@ -206,9 +212,15 @@ namespace party int get_bot_count() { auto count = 0; + const auto* svs_clients = *game::mp::svs_clients; + if (svs_clients == nullptr) + { + return count; + } + for (auto i = 0; i < *game::mp::svs_numclients; ++i) { - if (game::mp::svs_clients[i].header.state >= 1 && + if (svs_clients[i].header.state >= 1 && game::SV_BotIsBot(i)) { ++count; @@ -316,21 +328,20 @@ namespace party return; } - // hook disconnect command function - // utils::hook::jump(0x1402521C7, disconnect_stub); - // detour CL_Disconnect to clear motd - // cldisconnect_hook.create(0x140252060, cl_disconnect_stub); + cl_disconnect_hook.create(0x12F080_b, cl_disconnect_stub); if (game::environment::is_mp()) { // show custom drop reason // utils::hook::nop(0x12EF4E_b, 13); // utils::hook::jump(0x12EF4E_b, drop_reason_stub, true); + + command::add("disconnect", disconnect); } // enable custom kick reason in GScr_KickPlayer - // utils::hook::set(0xE423D_b, 0xEB); + utils::hook::set(0xE423D_b, 0xEB); command::add("map", [](const command::params& argument) { diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index ddf8190d..65bc2af9 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -115,12 +115,19 @@ namespace patches utils::hook::detour cmd_lui_notify_server_hook; void cmd_lui_notify_server_stub(game::mp::gentity_s* ent) { + const auto svs_clients = *game::mp::svs_clients; + if (svs_clients == nullptr) + { + return; + } + + command::params_sv params{}; const auto menu_id = atoi(params.get(1)); - const auto client = &game::mp::svs_clients[ent->s.entityNum]; + const auto client = svs_clients[ent->s.entityNum]; // 22 => "end_game" - if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK) + if (menu_id == 22 && client.header.remoteAddress.type != game::NA_LOOPBACK) { return; } @@ -217,10 +224,10 @@ namespace patches dvars::override::register_int("data_validation_allow_drop", 0, 0, 0, game::DVAR_FLAG_NONE); // Patch SV_KickClientNum - /*sv_kick_client_num_hook.create(0x14047ED00, &sv_kick_client_num); + sv_kick_client_num_hook.create(game::SV_KickClientNum, &sv_kick_client_num); // block changing name in-game - utils::hook::set(0x14047FC90, 0xC3); + /*utils::hook::set(0x14047FC90, 0xC3); // patch "Couldn't find the bsp for this map." error to not be fatal in mp utils::hook::call(0x1402BA26B, bsp_sys_error_stub); diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index f7c4a2ba..47d3bc00 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -36,15 +36,21 @@ namespace game return !game::environment::is_sp() && *mp::virtualLobby_loaded == 1; } - void SV_GameSendServerCommand(int clientNum, svscmd_type type, const char* text) + void SV_GameSendServerCommand(int client_num, svscmd_type type, const char* text) { - if (clientNum == -1) + if (*mp::svs_clients == nullptr) + { + return; + } + + if (client_num == -1) { SV_SendServerCommand(0, type, "%s", text); } else { - SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text); + printf("%s\n", mp::svs_clients[client_num]->name); + SV_SendServerCommand(mp::svs_clients[client_num], type, "%s", text); } } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index e8570bbc..c8bf2469 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1522,19 +1522,13 @@ namespace game char __pad0[265164]; int reliableSequence; int reliableAcknowledge; - char __pad1[265832]; - gentity_s* gentity; // 268976 - char name[32]; // 268984 - char __pad2[8]; - int nextSnapshotTime; // 269024 - char __pad3[544]; - LiveClientDropType liveDropRequest; //269572 - char __pad4[24]; - TestClientType testClient; // 269600 - char __pad5[347912]; - }; // size = 879616 + char __pad1[397928]; + gentity_s* gentity; + char name[32]; + char __pad5[348752]; + }; // size = 1011960 - static_assert(sizeof(client_t) == 879616); + static_assert(sizeof(client_t) == 1011960); } namespace sp diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index dd1d750a..9f2719c8 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -71,24 +71,24 @@ namespace game WEAK symbol Dvar_RegisterVec4{0x0, 0x183010}; - WEAK symbol FS_ReadFile{0x0, 0x0}; + WEAK symbol FS_ReadFile{0x0, 0x1EC690}; WEAK symbol FS_FreeFile{0x0, 0x0}; WEAK symbol FS_Startup{0x0, 0x0}; - WEAK symbol FS_AddLocalizedGameDirectory{0x0, 0x0}; + WEAK symbol FS_AddLocalizedGameDirectory{0x0, 0x1878F0}; - WEAK symbol GetVariable{0x0, 0x0}; - WEAK symbol GetNewVariable{0x0, 0x0}; - WEAK symbol GetNewArrayVariable{0x0, 0x0}; - WEAK symbol GScr_LoadConsts{0x0, 0x0}; - WEAK symbol FindVariable{0x0, 0x0}; - WEAK symbol FindEntityId{0x0, 0x0}; - WEAK symbol RemoveVariableValue{0x0, 0x0}; + WEAK symbol GetVariable{0x0, 0x50A8D0}; + WEAK symbol GetNewVariable{0x0, 0x50A4F0}; + WEAK symbol GetNewArrayVariable{0x0, 0x50A370}; + WEAK symbol GScr_LoadConsts{0x0, 0x468F40}; + WEAK symbol FindVariable{0x0, 0x509F90}; + WEAK symbol FindEntityId{0x0, 0x509E90}; + WEAK symbol RemoveVariableValue{0x0, 0x50AC90}; WEAK symbol GetEntityFieldValue{0x0, 0x0}; + int entnum, int offset)> GetEntityFieldValue{0x0, 0x50E2E0}; WEAK symbol generateHashValue{0x0, 0x183F80}; - WEAK symbol G_Glass_Update{0x0, 0x0}; + WEAK symbol G_Glass_Update{0x0, 0x417940}; WEAK symbol G_GetClientScore{0x0, 0x0}; WEAK symbol G_GetWeaponForName{0x0, 0x0}; WEAK symbol G_SelectWeapon{0x0, 0x0}; WEAK symbol G_TakePlayerWeapon{0x0, 0x0}; - WEAK symbol I_CleanStr{0x0, 0x0}; + WEAK symbol I_CleanStr{0x0, 0x5AF2E0}; - WEAK symbol Key_KeynumToString{0x0, 0x199990}; + WEAK symbol Key_KeynumToString{0x0, 0x199990}; WEAK symbol Live_SyncOnlineDataFlags{0x0, 0x1A5C10}; - WEAK symbol Material_RegisterHandle{0x0, 0x692360}; + WEAK symbol Material_RegisterHandle{0x0, 0x692360}; WEAK symbol NetadrToSockadr{0x0, 0x59E580}; WEAK symbol NET_OutOfBandPrint{0x0, 0x4F1EB0}; @@ -112,12 +112,12 @@ namespace game WEAK symbol R_AddCmdDrawStretchPic{0x0, 0x33B2B0}; - WEAK symbol R_RegisterFont{0x0, 0x67F630}; + WEAK symbol R_RegisterFont{0x0, 0x67F630}; WEAK symbol R_TextWidth{0x0, 0x67F8F0}; WEAK symbol R_GetFontHeight{0x0, 0x67F710}; - WEAK symbol R_DrawSomething{0x0, 0x67ECE0}; + WEAK symbol R_DrawSomething{0x0, 0x67ECE0}; WEAK symbol R_SyncRenderThread{0x0, 0x0}; - WEAK symbol H1_AddBaseDrawTextCmd{0x0, 0x6A3080}; @@ -131,23 +131,23 @@ namespace game uint32_t imageFlags, DXGI_FORMAT imageFormat, const char* name, const D3D11_SUBRESOURCE_DATA* initData)> Image_Setup{0x0, 0x0}; WEAK symbol VM_Execute{0x0, 0x0}; + unsigned int paramcount)> VM_Execute{0x0, 0x510EB0}; WEAK symbol Scr_NotifyId{0x0, 0x510340}; - WEAK symbol Scr_AllocVector{0x0, 0x0}; - WEAK symbol Scr_GetFloat{0x0, 0x0}; - WEAK symbol Scr_GetString{0x0, 0x0}; - WEAK symbol Scr_GetNumParam{0x0, 0x0}; - WEAK symbol Scr_ClearOutParams{0x0, 0x0}; - WEAK symbol Scr_GetEntityIdRef{0x0, 0x0}; - WEAK symbol Scr_GetEntityId{0x0, 0x0}; - WEAK symbol Scr_SetObjectField{0x0, 0x0}; + WEAK symbol Scr_AllocVector{0x0, 0x50B330}; + WEAK symbol Scr_GetFloat{0x0, 0x50F870}; + WEAK symbol Scr_GetString{0x0, 0x50FCB0}; + WEAK symbol Scr_GetNumParam{0x0, 0x50F9D0}; + WEAK symbol Scr_ClearOutParams{0x0, 0x50F070}; + WEAK symbol Scr_GetEntityIdRef{0x0, 0x50D8E0}; + WEAK symbol Scr_GetEntityId{0x0, 0x50D830}; + WEAK symbol Scr_SetObjectField{0x0, 0x459CD0}; - WEAK symbol ScrPlace_GetViewPlacement{0x0, 0x362840}; + WEAK symbol ScrPlace_GetViewPlacement{0x0, 0x362840}; WEAK symbol - DB_EnumXAssets_Internal{0x0, 0x0}; + DB_EnumXAssets_Internal{0x0, 0x394C60}; WEAK symbol DB_GetXAssetName{0x0, 0x0}; WEAK symbol DB_GetXAssetTypeSize{0x0, 0x0}; WEAK symbol LUI_OpenMenu{0x0, 0x1E1210}; - WEAK symbol LUI_BeginEvent{0x0, 0x0}; - WEAK symbol LUI_EndEvent{0x0, 0x0}; WEAK symbol LUI_EnterCriticalSection{0x0, 0x2669B0}; WEAK symbol LUI_LeaveCriticalSection{0x0, 0x26BDC0}; WEAK symbol Menu_IsMenuOpenAndVisible{0x0, 0x389F70}; - WEAK symbol SL_FindString{0x0, 0x0}; + WEAK symbol SL_FindString{0x0, 0x507FD0}; WEAK symbol SL_GetString{0x0, 0x5083A0}; - WEAK symbol SL_ConvertToString{0x0, 0x0}; - WEAK symbol SL_GetCanonicalString{0x0, 0x0}; + WEAK symbol SL_ConvertToString{0x0, 0x507CD0}; + WEAK symbol SL_GetCanonicalString{0x0, 0x504A00}; WEAK symbol SV_DirectConnect{0x0, 0x54DBF0}; - WEAK symbol SV_Cmd_ArgvBuffer{0x0, 0x0}; + WEAK symbol SV_Cmd_ArgvBuffer{0x0, 0x1CAC60}; WEAK symbol SV_Cmd_TokenizeString{0x0, 0x1CACE0}; WEAK symbol SV_Cmd_EndTokenizedString{0x0, 0x1CACA0}; WEAK symbol SV_AddBot{0x0, 0x54D4F0}; WEAK symbol SV_BotIsBot{0x0, 0x53B6D0}; - WEAK symbol SV_BotGetRandomName{0x0, 0x53ABD0}; + WEAK symbol SV_BotGetRandomName{0x0, 0x53ABD0}; WEAK symbol SV_SpawnTestClient{0x0, 0x550580}; - WEAK symbol SV_GetGuid{0x0, 0x0}; - WEAK symbol SV_GetClientPing{0x0, 0x0}; + WEAK symbol SV_GetGuid{0x0, 0x551D90}; + WEAK symbol SV_GetClientPing{0x0, 0x551D70}; WEAK symbol SV_GetPlayerstateForClientNum{0x0, 0x0}; - WEAK symbol SV_SetConfigstring{0x0, 0x0}; + WEAK symbol SV_SetConfigstring{0x0, 0x553E60}; WEAK symbol SV_Loaded{0x0, 0x553970}; - WEAK symbol SV_KickClientNum{0x0, 0x0}; + WEAK symbol SV_KickClientNum{0x0, 0x54C060}; WEAK symbol SV_MapExists{0x0, 0x54C0C0}; WEAK symbol SV_ExecuteClientCommand{0x0, 0x0}; - WEAK symbol SV_FastRestart{0x0, 0x0}; + WEAK symbol SV_FastRestart{0x0, 0x54BE00}; WEAK symbol SV_SendServerCommand{0x0, 0x1CC040}; WEAK symbol Sys_ShowConsole{0x0, 0x0}; @@ -204,7 +202,7 @@ namespace game WEAK symbol UI_SafeTranslateString{0x0, 0x4E8BC0}; - WEAK symbol longjmp{0x0, 0x0}; + WEAK symbol longjmp{0x0, 0x0}; WEAK symbol _setjmp{0x0, 0x0}; /*************************************************************** @@ -213,8 +211,8 @@ namespace game WEAK symbol sv_cmd_args{0x0, 0x2ED1EB0}; - WEAK symbol g_script_error_level{0x0, 0x0}; - WEAK symbol g_script_error{0x0, 0x0}; + WEAK symbol g_script_error_level{0x0, 0xB7AC1A4}; + WEAK symbol g_script_error{0x0, 0xB7AC2C0}; WEAK symbol levelEntityId{0x0, 0x0}; WEAK symbol gameEntityId{0x0, 0x0}; @@ -226,7 +224,7 @@ namespace game WEAK symbol g_poolSize{0x0, 0x0}; WEAK symbol g_classMap{0x0, 0x0}; - WEAK symbol scr_VarGlob{0x0, 0x0}; + WEAK symbol scr_VarGlob{0x0, 0xB138180}; WEAK symbol scr_VmPub{0x0, 0xB7AE3C0}; WEAK symbol scr_function_stack{0x0, 0x0}; @@ -248,7 +246,7 @@ namespace game namespace mp { WEAK symbol g_entities{0x0, 0x71F19E0}; - WEAK symbol svs_clients{0x0, 0x2DC3390}; + WEAK symbol svs_clients{0x0, 0x2DC3390}; WEAK symbol svs_numclients{0x0, 0x2DC338C}; WEAK symbol gameTime{0x0, 0x0};