diff --git a/src/client/component/dedicated.cpp b/src/client/component/dedicated.cpp index 03b951b..40cc3c1 100644 --- a/src/client/component/dedicated.cpp +++ b/src/client/component/dedicated.cpp @@ -198,25 +198,6 @@ namespace dedicated return hwnd; } - void sys_error_stub(const char* msg, ...) - { - char buffer[2048]{}; - - va_list ap; - va_start(ap, msg); - - vsnprintf_s(buffer, _TRUNCATE, msg, ap); - - va_end(ap); - - scheduler::once([]() - { - command::execute("map_rotate"); - }, scheduler::pipeline::main, 3s); - - game::Com_Error(game::ERR_DROP, "%s", buffer); - } - void add_commands() { command::add("map", [](const command::params& params) @@ -364,9 +345,6 @@ namespace dedicated utils::hook::nop(0x1404F8BE1, 2); // ^ utils::hook::set(0x140328660, 0xC3); // Disable image pak file loading - // Stop crashing from sys_errors - utils::hook::jump(0x1404FF510, sys_error_stub); - // Reduce min required memory utils::hook::set(0x1404FA6BD, 0x80000000); utils::hook::set(0x1404FA76F, 0x80000000); diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp index f5bb265..5a28a84 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -7,10 +7,10 @@ #include "console.hpp" #include "fastfiles.hpp" - #include -#include #include +#include +#include namespace fastfiles { @@ -32,6 +32,12 @@ namespace fastfiles return; } + const auto out_name = std::format("gsc_dump/{}.gscbin", name); + if (utils::io::file_exists(out_name)) + { + return; + } + std::string buffer; buffer.append(header.scriptfile->name, std::strlen(header.scriptfile->name) + 1); buffer.append(reinterpret_cast(&header.scriptfile->compressedLen), 4); @@ -40,12 +46,38 @@ namespace fastfiles buffer.append(header.scriptfile->buffer, header.scriptfile->compressedLen); buffer.append(reinterpret_cast(header.scriptfile->bytecode), header.scriptfile->bytecodeLen); - const auto out_name = std::format("gsc_dump/{}.gscbin", name); utils::io::write_file(out_name, buffer); - console::info("Dumped %s\n", out_name.data()); + console::info("Dumped %s\n", out_name.c_str()); } + void dump_csv_table(const std::string& name, game::XAssetHeader header) + { + if (!dvars::g_dump_string_tables->current.enabled) + { + return; + } + + const auto out_name = std::format("csv_dump/{}.csv", name); + if (utils::io::file_exists(out_name)) + { + return; + } + + std::string buffer; + + for (auto row = 0; row < header.stringTable->rowCount; row++) + { + for (auto column = 0; column < header.stringTable->columnCount; column++) + { + const auto* string = header.stringTable->values[(row * header.stringTable->columnCount) + column].string; + buffer.append(utils::string::va("%s%s", string ? string : "", (column == header.stringTable->columnCount - 1) ? "\n" : ",")); + } + } + + utils::io::write_file(out_name, buffer); + console::info("Dumped %s\n", out_name.c_str()); + } game::XAssetHeader db_find_x_asset_header_stub(game::XAssetType type, const char* name, int allow_create_default) { @@ -58,6 +90,11 @@ namespace fastfiles dump_gsc_script(name, result); } + if (type == game::ASSET_TYPE_STRINGTABLE) + { + dump_csv_table(name, result); + } + if (diff > 100) { console::print( @@ -110,6 +147,7 @@ namespace fastfiles db_find_x_asset_header_hook.create(game::DB_FindXAssetHeader, db_find_x_asset_header_stub); dvars::g_dump_scripts = game::Dvar_RegisterBool("g_dumpScripts", false, game::DVAR_FLAG_NONE, "Dump GSC scripts to binary format"); + dvars::g_dump_string_tables = game::Dvar_RegisterBool("g_dumpStringTables", false, game::DVAR_FLAG_NONE, "Dump CSV files"); utils::hook::call(SELECT_VALUE(0x1402752DF, 0x140156350), p_mem_free_stub); utils::hook::call(SELECT_VALUE(0x140276004, 0x140324259), p_mem_free_stub); diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 25f445e..fa4735a 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -295,6 +295,8 @@ namespace patches utils::hook::nop(0x1404758C0, 16); utils::hook::jump(0x1404758C0, game::engine::SV_GameSendServerCommand, true); + utils::hook::call(0x140477399, game::engine::SV_SendServerCommand); + // Register dvars com_register_dvars_hook.create(0x140413A90, &com_register_dvars_stub); diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index e5a1e23..a10b151 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -25,6 +25,7 @@ namespace dvars game::dvar_t* g_rocketPushbackScale = nullptr; game::dvar_t* g_enableElevators = nullptr; game::dvar_t* g_dump_scripts = nullptr; + game::dvar_t* g_dump_string_tables = nullptr; game::dvar_t* g_log = nullptr; game::dvar_t* bg_surfacePenetration = nullptr; diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index b805a63..0dedd0f 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -24,6 +24,7 @@ namespace dvars extern game::dvar_t* g_rocketPushbackScale; extern game::dvar_t* g_enableElevators; extern game::dvar_t* g_dump_scripts; + extern game::dvar_t* g_dump_string_tables; extern game::dvar_t* g_log; extern game::dvar_t* bg_surfacePenetration; diff --git a/src/client/game/engine/sv_game.cpp b/src/client/game/engine/sv_game.cpp index 4f83e3b..950d401 100644 --- a/src/client/game/engine/sv_game.cpp +++ b/src/client/game/engine/sv_game.cpp @@ -178,4 +178,29 @@ namespace game::engine assert(static_cast(clientNum) < sv_maxclients->current.unsignedInt); SV_SendServerCommand(&mp::svs_clients[clientNum], type, "%s", text); } + + void SV_ReconnectClients(int savepersist) + { + const auto* sv_maxclients = Dvar_FindVar("sv_maxclients"); + for (int i = 0; i < sv_maxclients->current.integer; ++i) + { + mp::client_t* client = &mp::svs_clients[i]; + if (client->header.state < CS_CONNECTED) + { + continue; + } + + SV_AddServerCommand(client, SV_CMD_RELIABLE, utils::string::va("%c", savepersist != 0 ? 107 : 118)); + const char* denied = ClientConnect(i, client->scriptId); + if (denied) + { + SV_DropClient(client, denied, true); + console::info("SV_MapRestart_f: dropped client %i - denied!\n", i); + } + else if (client->header.state == CS_ACTIVE) + { + SV_ClientEnterWorld(client, &client->lastUsercmd); + } + } + } } diff --git a/src/client/game/engine/sv_game.hpp b/src/client/game/engine/sv_game.hpp index f1b7b70..c1c5a46 100644 --- a/src/client/game/engine/sv_game.hpp +++ b/src/client/game/engine/sv_game.hpp @@ -2,5 +2,7 @@ namespace game::engine { + void SV_SendServerCommand(mp::client_t* cl, svscmd_type type, const char* fmt, ...); void SV_GameSendServerCommand(int clientNum, svscmd_type type, const char* text); + void SV_ReconnectClients(int savepersist); } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 2d2f9b3..84a21e5 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -990,6 +990,27 @@ namespace game LOOKUP_ERROR_COUNT = 0x5, }; + struct ComStreamSyncModel + { + unsigned __int16 modelIndex; + unsigned __int8 alternateIndex; + }; + + static_assert(sizeof(ComStreamSyncModel) == 4); + + struct ComStreamedSyncModelList + { + unsigned int modelCount; + ComStreamSyncModel models[18]; + }; + + static_assert(sizeof(ComStreamedSyncModelList) == 0x4C); + + struct ComStreamedSyncSwapBuffer + { + ComStreamedSyncModelList modelLists[2]; + }; + struct StructuredDataEnumEntry { unsigned int name; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index b4abdc0..93e694b 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -30,6 +30,7 @@ namespace game WEAK symbol Com_SetSlowMotion{0, 0x1404158C0}; WEAK symbol Com_TokenizeString{0x1403B4150, 0x1403F7CC0}; WEAK symbol Com_EndTokenizeString{0x1403B37C0, 0x1403F7330}; + WEAK symbol Com_StreamSync_UpdateLaunchData{0x0, 0x140411B50}; WEAK symbol Conbuf_AppendText{0x14043DDE0, 0x1405028C0}; @@ -220,6 +221,10 @@ namespace game WEAK symbol SV_Loaded{0x140491820, 0x1404770C0}; WEAK symbol SV_StartMap{0, 0x140470170}; WEAK symbol SV_StartMapForParty{0, 0x1404702F0}; + WEAK symbol SV_StreamSync_ClientConnect{0x0, 0x140488080}; + WEAK symbol ClientConnect{0x0, 0x140387630}; + WEAK symbol SV_ClientEnterWorld{0x0, 0x1404710F0}; + WEAK symbol SV_DropClient{0x0, 0x140472110}; WEAK symbol SV_AddBot{0, 0x140470920}; WEAK symbol SV_BotIsBot{0, 0x140461340}; @@ -344,6 +349,8 @@ namespace game WEAK symbol serverTime{0, 0x14647B280}; WEAK symbol g_zones_0{0, 0x143A46498}; + + WEAK symbol s_launchDataAvailable{0x0, 0x1445CE354}; } namespace hks