From 98e95347d5f85ce690bdc42a3b1a0bf7878029ba Mon Sep 17 00:00:00 2001 From: quaK <38787176+Joelrau@users.noreply.github.com> Date: Fri, 23 Sep 2022 01:04:20 +0300 Subject: [PATCH] stuff --- src/client/component/command.cpp | 245 +++++++++++++++++++++++++++---- src/client/component/command.hpp | 4 +- src/client/component/logger.cpp | 3 - src/client/component/lui.cpp | 118 +++++++++++++++ src/client/component/patches.cpp | 26 +++- src/client/component/splash.cpp | 198 +++++++++++++++++++++++++ src/client/game/dvars.cpp | 10 +- src/client/game/dvars.hpp | 6 +- src/client/game/game.cpp | 21 ++- src/client/game/game.hpp | 2 + src/client/game/structs.hpp | 21 ++- src/client/game/symbols.hpp | 32 +++- 12 files changed, 634 insertions(+), 52 deletions(-) create mode 100644 src/client/component/lui.cpp create mode 100644 src/client/component/splash.cpp diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index 5c1986ff..65520c5b 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -154,7 +154,7 @@ namespace command void client_println(int client_num, const std::string& text) { - if (game::Com_GameMode_GetActiveGameMode() == game::GAME_TYPE_SP) + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) { game::CG_Utils_GameMessage(client_num, text.data(), 0); // why is nothing printed? } @@ -167,6 +167,11 @@ namespace command bool cheats_ok(int client_num) { + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) + { + return true; + } + const auto sv_cheats = game::Dvar_FindVar("sv_cheats"); if (!sv_cheats || !sv_cheats->current.enabled) { @@ -176,6 +181,87 @@ namespace command return true; } + + void start_map_for_party() + { + auto* mapname = game::Dvar_FindVar("ui_mapname"); + auto* gametype = game::Dvar_FindVar("ui_gametype"); + auto* clients = game::Dvar_FindVar("ui_maxclients"); + auto* private_clients = game::Dvar_FindVar("ui_privateClients"); + auto* hardcore = game::Dvar_FindVar("ui_hardcore"); + + game::Com_FrontEndScene_ShutdownAndDisable(); + + if (!game::environment::is_dedi() && !game::Com_FrontEndScene_IsActive()) + { + game::Com_Shutdown("EXE_ENDOFGAME"); + } + + game::SV_CmdsMP_StartMapForParty( + mapname->current.string, + gametype->current.string, + clients->current.integer, + private_clients->current.integer, + hardcore->current.enabled, + false, + false); + } + + void perform_game_initialization() + { + command::execute("onlinegame 1", true); + command::execute("xstartprivatematch", true); //command::execute("xstartprivateparty", true); + command::execute("xblive_privatematch 1", true); + } + + bool start_map(const std::string& mapname, bool dev) + { + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) + { + console::info("Starting sp map: %s\n", mapname.data()); + command::execute(utils::string::va("spmap %s", mapname.data()), true); + return true; + } + + if (mapname.empty()) + { + console::error("No map specified.\n"); + return false; + } + + if (!game::SV_MapExists(mapname.data())) + { + console::error("Map \"%s\" doesn't exist.\n", mapname.data()); + return false; + } + + if (!game::Com_GameMode_SupportsMap(mapname.data())) + { + console::error("Cannot load map \"%s\" in current game mode.\n", mapname.data()); + return false; + } + + auto* current_mapname = game::Dvar_FindVar("mapname"); + + command::execute((dev ? "set sv_cheats 1" : "set sv_cheats 0"), true); + + if (current_mapname && utils::string::to_lower(current_mapname->current.string) == + utils::string::to_lower(mapname) && (game::SV_Loaded() && !game::Com_FrontEndScene_IsActive())) + { + console::info("Restarting map: %s\n", mapname.data()); + command::execute("map_restart", false); + return true; + } + + command::execute(utils::string::va("ui_mapname %s", mapname.data()), true); + + console::info("Starting map: %s\n", mapname.data()); + + perform_game_initialization(); + + game::Cbuf_AddCall(0, start_map_for_party); + return true; + } } params::params() @@ -316,8 +402,8 @@ namespace command void post_unpack() override { utils::hook::jump(0xBB1DC0_b, dvar_command_stub, true); - //client_command_mp_hook.create(0xB105D0_b, &client_command_mp); - //client_command_sp_hook.create(0x483130_b, &client_command_sp); + client_command_mp_hook.create(0xB105D0_b, &client_command_mp); + client_command_sp_hook.create(0x483130_b, &client_command_sp); add_commands(); } @@ -331,72 +417,175 @@ namespace command *reinterpret_cast(1) = 0; }); - add("god", []() + add("noMode", []() { - if (!game::SV_Loaded()) + game::Com_GameMode_SetDesiredGameMode(game::GAME_MODE_NONE); + }); + + add("spMode", []() + { + game::Com_GameMode_SetDesiredGameMode(game::GAME_MODE_SP); + }); + + add("mpMode", []() + { + game::Com_GameMode_SetDesiredGameMode(game::GAME_MODE_MP); + }); + + add("cpMode", []() + { + game::Com_GameMode_SetDesiredGameMode(game::GAME_MODE_CP); + }); + + static const char* a1 = "map_sp"; + static const char* a2 = "map_restart_sp"; + static const char* a3 = "fast_restart_sp"; + + // patch singleplayer "map" -> "map_sp" + utils::hook::set(0x1BBA800_b + 0, a1); + utils::hook::set(0x1BBA800_b + 24, a1); + utils::hook::set(0x1BBA800_b + 56, a1); + + // patch singleplayer map_restart -> "map_restart_sp" + utils::hook::set(0x1BBA740_b + 0, a2); + utils::hook::set(0x1BBA740_b + 24, a2); + utils::hook::set(0x1BBA740_b + 56, a2); + + // patch singleplayer fast_restart -> "fast_restart_sp" + utils::hook::set(0x1BBA700_b + 0, a3); + utils::hook::set(0x1BBA700_b + 24, a3); + utils::hook::set(0x1BBA700_b + 56, a3); + + add("map", [](const params& args) + { + if (args.size() != 2) { return; } - game::g_entities[0].flags ^= 1; - client_println(0, - game::g_entities[0].flags & 1 + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) + { + command::execute(utils::string::va("spmap %s", args.get(1))); + return; + } + + start_map(args.get(1), false); + }); + + add("devmap", [](const params& args) + { + if (args.size() != 2) + { + return; + } + + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) + { + command::execute(utils::string::va("spmap %s", args.get(1))); + return; + } + + start_map(args.get(1), true); + }); + + add("map_restart", [](const params&) + { + if (!game::SV_Loaded() || game::Com_FrontEnd_IsInFrontEnd()) + { + return; + } + + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) + { + game::Cbuf_AddCall(0, game::SV_CmdsSP_MapRestart_f); + return; + } + + game::SV_CmdsMP_RequestMapRestart(1, 0); + }); + + add("fast_restart", [](const params&) + { + if (!game::SV_Loaded() || game::Com_FrontEnd_IsInFrontEnd()) + { + return; + } + + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_MODE_SP) + { + game::Cbuf_AddCall(0, game::SV_CmdsSP_FastRestart_f); + return; + } + + game::SV_CmdsMP_RequestMapRestart(0, 0); + }); + + add_sv("god", [](const int client_num, const params_sv&) + { + if (!cheats_ok(client_num)) + { + return; + } + + game::g_entities[client_num].flags ^= 1; + client_println(client_num, + game::g_entities[client_num].flags & 1 ? "GAME_GODMODE_ON" : "GAME_GODMODE_OFF"); }); - add("demigod", []() + add_sv("demigod", [](const int client_num, const params_sv&) { - if (!game::SV_Loaded()) + if (!cheats_ok(client_num)) { return; } - game::g_entities[0].flags ^= 2; - client_println(0, - game::g_entities[0].flags & 2 + game::g_entities[client_num].flags ^= 2; + client_println(client_num, + game::g_entities[client_num].flags & 2 ? "GAME_DEMI_GODMODE_ON" : "GAME_DEMI_GODMODE_OFF"); }); - add("notarget", []() + add_sv("notarget", [](const int client_num, const params_sv&) { - if (!game::SV_Loaded()) + if (!cheats_ok(client_num)) { return; } - game::g_entities[0].flags ^= 4; - client_println(0, - game::g_entities[0].flags & 4 + game::g_entities[client_num].flags ^= 4; + client_println(client_num, + game::g_entities[client_num].flags & 4 ? "GAME_NOTARGETON" : "GAME_NOTARGETOFF"); }); - add("noclip", []() + add_sv("noclip", [](const int client_num, const params_sv&) { - if (!game::SV_Loaded()) + if (!cheats_ok(client_num)) { return; } - game::g_entities[0].client->flags ^= 1; - client_println(0, - game::g_entities[0].client->flags & 1 + game::g_entities[client_num].client->flags ^= 1; + client_println(client_num, + game::g_entities[client_num].client->flags & 1 ? "GAME_NOCLIPON" : "GAME_NOCLIPOFF"); }); - add("ufo", []() + add_sv("ufo", [](const int client_num, const params_sv&) { - if (!game::SV_Loaded()) + if (!cheats_ok(client_num)) { return; } - game::g_entities[0].client->flags ^= 1; - client_println(0, - game::g_entities[0].client->flags & 1 + game::g_entities[client_num].client->flags ^= 1; + client_println(client_num, + game::g_entities[client_num].client->flags & 1 ? "GAME_UFOON" : "GAME_UFOOFF"); }); diff --git a/src/client/component/command.hpp b/src/client/component/command.hpp index d0732a09..8cac8b06 100644 --- a/src/client/component/command.hpp +++ b/src/client/component/command.hpp @@ -14,7 +14,7 @@ namespace command const char* operator[](const int index) const { - return this->get(index); // + return this->get(index); } private: @@ -33,7 +33,7 @@ namespace command const char* operator[](const int index) const { - return this->get(index); // + return this->get(index); } private: diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp index 96dfc818..f0a1b5ae 100644 --- a/src/client/component/logger.cpp +++ b/src/client/component/logger.cpp @@ -95,9 +95,6 @@ namespace logger if (!game::environment::is_dedi()) { - // LUI_Interface_DebugPrint - utils::hook::jump(0x61C430_b, print_debug); - // R_WarnOncePerFrame utils::hook::call(0xE4B121_b, r_warn_once_per_frame_vsnprintf_stub); } diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp new file mode 100644 index 00000000..e63c314a --- /dev/null +++ b/src/client/component/lui.cpp @@ -0,0 +1,118 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "command.hpp" +#include "console.hpp" + +#include +#include + +namespace lui +{ + void print_debug_lui(const char* msg, ...) + { + if (!dvars::lui_debug || !dvars::lui_debug->current.enabled) + { + return; + } + + char buffer[0x1000]{ 0 }; + + va_list ap; + va_start(ap, msg); + + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap); + + va_end(ap); + + console::debug(buffer); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + dvars::lui_debug = game::Dvar_RegisterBool("lui_debug", false, game::DvarFlags::DVAR_FLAG_SAVED, + "Print LUI DebugPrint to console. (DEV)"); + + // LUI_Interface_DebugPrint + utils::hook::jump(0x61C430_b, print_debug_lui); + + command::add("luiOpenMenu", [](const command::params& params) + { + if (params.size() == 2) + { + game::LUI_OpenMenu(0, params.get(1), 0, 0, 0); + } + else + { + auto command = params.get(0); + console::error("Incorrect number of arguments for \"%s\".\n", command); + } + }); + + command::add("luiOpenPopup", [](const command::params& params) + { + if (params.size() == 2) + { + game::LUI_OpenMenu(0, params.get(1), 1, 0, 0); + } + else + { + auto command = params.get(0); + console::error("Incorrect number of arguments for \"%s\".\n", command); + } + }); + + command::add("luiOpenModalPopup", [](const command::params& params) + { + if (params.size() == 2) + { + game::LUI_OpenMenu(0, params.get(1), 1, 1, 0); + } + else + { + auto command = params.get(0); + console::error("Incorrect number of arguments for \"%s\".\n", command); + } + }); + + + command::add("luiLeaveMenu", [](const command::params& params) + { + if (params.size() == 2) + { + game::LUI_CloseMenu(0, params.get(1), 0); + } + else + { + auto command = params.get(0); + console::error("Incorrect number of arguments for \"%s\".\n", command); + } + }); + + command::add("luiCloseAll", []() + { + game::LUI_CoD_CLoseAll(0); + }); + + command::add("luiReload", []() + { + game::CL_Keys_RemoveCatcher(0, -65); + game::LUI_CoD_Shutdown(); + game::LUI_CoD_Init(game::Com_FrontEnd_IsInFrontEnd(), false); + }); + } + }; +} + +REGISTER_COMPONENT(lui::component) \ No newline at end of file diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index c3ad07cc..e5733144 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -15,6 +15,7 @@ namespace patches namespace { utils::hook::detour com_register_common_dvars_hook; + utils::hook::detour com_game_mode_supports_feature_hook; utils::hook::detour cg_set_client_dvar_from_server_hook; utils::hook::detour live_get_map_index_hook; utils::hook::detour content_do_we_have_content_pack_hook; @@ -31,12 +32,13 @@ namespace patches return std::string{ username, username_len - 1 }; } - game::dvar_t* name_dvar; - game::dvar_t* com_maxfps; - game::dvar_t* cg_fov; - game::dvar_t* cg_fovScale; void com_register_common_dvars_stub() { + game::dvar_t* name_dvar; + game::dvar_t* com_maxfps; + game::dvar_t* cg_fov; + game::dvar_t* cg_fovScale; + name_dvar = game::Dvar_RegisterString("name", get_login_username().data(), game::DVAR_FLAG_SAVED, "Player name."); com_maxfps = game::Dvar_RegisterInt("com_maxfps", 0, 0, 1000, game::DVAR_FLAG_SAVED, "Cap frames per second"); cg_fov = game::Dvar_RegisterFloat("cg_fov", 65.0f, 1.0f, 160.f, game::DVAR_FLAG_SAVED, @@ -59,6 +61,16 @@ namespace patches return com_register_common_dvars_hook.invoke(); } + bool com_game_mode_supports_feature_stub(game::Com_GameMode_Feature feature) + { + if (feature == game::FEATURE_TIMESCALE) + { + return true; + } + + return com_game_mode_supports_feature_hook.invoke(feature); + } + const char* live_get_local_client_name() { return game::Dvar_FindVar("name")->current.string; @@ -168,6 +180,9 @@ namespace patches // register custom dvars com_register_common_dvars_hook.create(0xBADF30_b, com_register_common_dvars_stub); + // patch some features + com_game_mode_supports_feature_hook.create(0x5AFDE0_b, com_game_mode_supports_feature_stub); + // get client name from dvar utils::hook::jump(0xD32770_b, live_get_local_client_name); @@ -193,6 +208,9 @@ namespace patches // don't reset our fov utils::hook::set(0x8A6160_b, 0xC3); + + // some [data validation] anti tamper thing that kills performance + dvars::override::register_int("dvl", 0, 0, 0, game::DVAR_FLAG_READ); } }; } diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp new file mode 100644 index 00000000..dd186335 --- /dev/null +++ b/src/client/component/splash.cpp @@ -0,0 +1,198 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include "game_module.hpp" + +#include +#include + +namespace splash +{ + namespace + { + HANDLE load_splash_image() + { + const auto self = game_module::get_host_module(); + return LoadImageA(self, MAKEINTRESOURCE(IMAGE_SPLASH), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + } + } + + class component final : public component_interface + { + public: + component() + : image_(load_splash_image()) + { + this->window_thread_ = std::thread([this] + { + this->draw(); + }); + } + + ~component() + { + if (this->window_thread_.joinable()) + { + this->window_thread_.detach(); + } + } + + void pre_destroy() override + { + this->destroy(); + } + + void post_unpack() override + { + utils::hook::set(0xD58240_b, 0xC3); // disable splash + this->destroy(); + } + + void hide() + { + if (this->window_ && IsWindow(this->window_)) + { + ShowWindow(this->window_, SW_HIDE); + UpdateWindow(this->window_); + } + + this->destroy(); + } + + private: + std::atomic_bool join_safe_{ false }; + HWND window_{}; + HANDLE image_{}; + std::thread window_thread_{}; + + void destroy() + { + if (this->window_ && IsWindow(this->window_)) + { + ShowWindow(this->window_, SW_HIDE); + DestroyWindow(this->window_); + this->window_ = nullptr; + + if (this->window_thread_.joinable()) + { + this->window_thread_.join(); + } + + this->window_ = nullptr; + } + else if (this->window_thread_.joinable()) + { + this->window_thread_.detach(); + } + } + + void draw() + { + this->show(); + while (this->draw_frame()) + { + std::this_thread::sleep_for(1ms); + } + + this->window_ = nullptr; + UnregisterClassA("IW7 Splash Screen", game_module::get_host_module()); + } + + bool draw_frame() const + { + if (!this->window_) + { + return false; + } + + MSG msg{}; + bool success = true; + + while (PeekMessageW(&msg, nullptr, NULL, NULL, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + + if (msg.message == WM_DESTROY && msg.hwnd == this->window_) + { + PostQuitMessage(0); + } + + if (msg.message == WM_QUIT) + { + success = false; + } + } + return success; + } + + void show() + { + WNDCLASSA wnd_class; + + const utils::nt::library host = game_module::get_host_module(); + + wnd_class.style = CS_DROPSHADOW; + wnd_class.cbClsExtra = 0; + wnd_class.cbWndExtra = 0; + wnd_class.lpszMenuName = nullptr; + wnd_class.lpfnWndProc = DefWindowProcA; + wnd_class.hInstance = host; + wnd_class.hIcon = LoadIconA(host, MAKEINTRESOURCEA(1)); + wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING); + wnd_class.hbrBackground = reinterpret_cast(6); + wnd_class.lpszClassName = "IW7 Splash Screen"; + + if (RegisterClassA(&wnd_class)) + { + const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN); + const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN); + + if (image_) + { + this->window_ = CreateWindowExA(WS_EX_APPWINDOW, "IW7 Splash Screen", "IW7", + WS_POPUP | WS_SYSMENU, + (x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr, + nullptr, + host, nullptr); + + if (this->window_) + { + auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, + 0, 0, + 320, 100, this->window_, nullptr, host, nullptr); + if (image_window) + { + RECT rect; + SendMessageA(image_window, 0x172u, 0, reinterpret_cast(image_)); + GetWindowRect(image_window, &rect); + + const int width = rect.right - rect.left; + rect.left = (x_pixels - width) / 2; + + const int height = rect.bottom - rect.top; + rect.top = (y_pixels - height) / 2; + + rect.right = rect.left + width; + rect.bottom = rect.top + height; + AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0); + SetWindowPos(this->window_, nullptr, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER); + + SetWindowRgn(this->window_, + CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15, + 15), TRUE); + + ShowWindow(this->window_, SW_SHOW); + UpdateWindow(this->window_); + } + } + } + } + } + }; +} + +REGISTER_COMPONENT(splash::component) \ No newline at end of file diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index b8cb3e43..1b74ecf1 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -21,6 +21,8 @@ namespace dvars game::dvar_t* branding = nullptr; + game::dvar_t* lui_debug = nullptr; + game::dvar_t* r_fullbright = nullptr; std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain) @@ -131,7 +133,7 @@ namespace dvars } } - std::unordered_map dvar_names; + std::unordered_map dvar_names; std::string dvar_get_name(const game::dvar_t* dvar) { @@ -144,12 +146,12 @@ namespace dvars return ""; } - void dvar_set_name(const game::dvar_t* dvar, const std::string& name) + void dvar_set_name(const game::dvar_t* dvar, const char* name) { dvar_names[dvar] = name; } - std::unordered_map dvar_descriptions; + std::unordered_map dvar_descriptions; std::string dvar_get_description(const game::dvar_t* dvar) { @@ -162,7 +164,7 @@ namespace dvars return ""; } - void dvar_set_description(const game::dvar_t* dvar, const std::string& description) + void dvar_set_description(const game::dvar_t* dvar, const char* description) { dvar_descriptions[dvar] = description; } diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index 412646b4..b7dfd342 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -17,12 +17,14 @@ namespace dvars extern game::dvar_t* branding; + extern game::dvar_t* lui_debug; + extern game::dvar_t* r_fullbright; std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain); std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain); std::string dvar_get_name(const game::dvar_t* dvar); std::string dvar_get_description(const game::dvar_t* dvar); - void dvar_set_name(const game::dvar_t* dvar, const std::string& name); - void dvar_set_description(const game::dvar_t* dvar, const std::string& description); + void dvar_set_name(const game::dvar_t* dvar, const char* name); + void dvar_set_description(const game::dvar_t* dvar, const char* description); } diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index 715b57fb..d483f2e3 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -13,6 +13,15 @@ namespace game base_address = reinterpret_cast(module); } + namespace environment + { + bool is_dedi() + { + static const auto dedicated = utils::flags::has_flag("dedicated"); + return dedicated; + } + } + int Cmd_Argc() { return cmd_args->argc[cmd_args->nesting]; @@ -131,12 +140,16 @@ namespace game }), &callback); } - namespace environment + void SV_CmdsMP_RequestMapRestart(bool loadScripts, bool migrate) { - bool is_dedi() + if (!Com_IsAnyLocalServerStarting()) { - static const auto dedicated = utils::flags::has_flag("dedicated"); - return dedicated; + SND_StopSounds(2); + SND_SetMusicState("\0"); + *sv_map_restart = 1; + *sv_loadScripts = loadScripts; + *sv_migrate = migrate; + Cbuf_AddCall(0, SV_CmdsMP_CheckLoadGame); } } } diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 0083abaf..2d73914c 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -51,6 +51,8 @@ namespace game extern const char* g_assetNames[ASSET_TYPE_COUNT]; const char* DB_GetXAssetName(const XAsset* asset); void DB_EnumXAssets(const std::int32_t type, const std::function& callback); + + void SV_CmdsMP_RequestMapRestart(bool loadScripts, bool migrate); } uintptr_t operator"" _b(const uintptr_t ptr); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 06ca5891..a221c2a8 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -16,10 +16,15 @@ namespace game enum GameModeType : std::uint32_t { - GAME_TYPE_NONE = 0x0, - GAME_TYPE_SP = 0x1, - GAME_TYPE_MP = 0x2, - GAME_TYPE_CP = 0x3, + GAME_MODE_NONE = 0x0, + GAME_MODE_SP = 0x1, + GAME_MODE_MP = 0x2, + GAME_MODE_CP = 0x3, + }; + + enum Com_GameMode_Feature : std::int32_t + { + FEATURE_TIMESCALE = 69, }; enum errorParm @@ -55,6 +60,14 @@ namespace game void(__cdecl* function)(); }; + struct SvCommandInfo + { + const char* name; + void(__fastcall* func)(); + cmd_function_s clvar; + cmd_function_s svvar; + }; + enum DvarSetSource : std::uint32_t { DVAR_SOURCE_INTERNAL = 0x0, diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 352ab03e..58b6410d 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -12,14 +12,26 @@ namespace game WEAK symbol Com_Quit_f{ 0xBADC90 }; + WEAK symbol Com_FrontEnd_IsInFrontEnd{ 0x5AE6C0 }; WEAK symbol Com_FrontEndScene_IsActive{ 0x5AEBA0 }; + WEAK symbol Com_FrontEndScene_ShutdownAndDisable{ 0x5AEFB0 }; + WEAK symbol Com_GameMode_SetDesiredGameMode{ 0x5AFDA0 }; WEAK symbol Com_GameMode_GetActiveGameMode{ 0x5AFD50 }; + WEAK symbol Com_GameMode_SupportsMap{ 0x5AFE10 }; + + WEAK symbol Com_IsAnyLocalServerStarting{ 0xBAD9C0 }; + WEAK symbol Com_IsAnyLocalServerRunning{ 0xBAD9A0 }; + + WEAK symbol Com_Shutdown{ 0xBAFEA0 }; WEAK symbol Cbuf_AddText{ 0xB7C290 }; WEAK symbol Cbuf_AddCall{ 0xB7C220 }; WEAK symbol CG_Utils_GameMessage{ 0x1D7FC0 }; + WEAK symbol CG_Utils_BoldGameMessage{ 0x1D7F10 }; + + WEAK symbol CL_Keys_RemoveCatcher{ 0x9A9B00 }; WEAK symbol Cmd_ExecuteSingleCommand{ 0xB7D040 }; WEAK symbol Cmd_AddCommandInternal{ 0xB7C8F0 }; @@ -49,7 +61,7 @@ namespace game WEAK symbol Dvar_RegisterVec4{ 0xCEC110 }; - WEAK symbol Dvar_SetFromStringByChecksum{ 0xCECDB0 }; + WEAK symbol Dvar_SetFromStringByChecksum{ 0xCECDB0 }; WEAK symbol Dvar_SetFromStringByName{ 0xCECF30 }; WEAK symbol Dvar_SetFromStringFromSource{ 0xCECFF0 }; @@ -67,6 +79,11 @@ namespace game WEAK symbol Key_KeynumToString{ 0x9A95E0 }; WEAK symbol LUI_CoD_InFrontEnd{ 0x615080 }; + WEAK symbol LUI_CoD_Init{ 0x615090 }; + WEAK symbol LUI_CoD_Shutdown{ 0x617610 }; + WEAK symbol LUI_OpenMenu{ 0xCC0CA0 }; + WEAK symbol LUI_CloseMenu{ 0xCC0C40 }; + WEAK symbol LUI_CoD_CLoseAll{ 0x6135C0 }; WEAK symbol Live_SyncOnlineDataFlags{ 0xDC5CE0 }; @@ -95,8 +112,17 @@ namespace game WEAK symbol SV_Cmd_TokenizeString{ 0xB7DD00 }; WEAK symbol SV_Cmd_EndTokenizedString{ 0xB7DCC0 }; + WEAK symbol SV_CmdsMP_StartMapForParty{ 0xC4D150 }; + WEAK symbol SV_CmdsMP_CheckLoadGame{ 0xC4C9E0 }; + WEAK symbol SV_CmdsSP_MapRestart_f{ 0xC12B30 }; + WEAK symbol SV_CmdsSP_FastRestart_f{ 0xC12AF0 }; WEAK symbol SV_GameSendServerCommand{ 0xC54780 }; WEAK symbol SV_Loaded{ 0xC114C0 }; + WEAK symbol SV_MapExists{ 0xCDB620 }; + + WEAK symbol SND_StopSounds{ 0xCA06E0 }; + WEAK symbol SND_SetMusicState{ 0xC9E110 }; /*************************************************************** * Variables @@ -119,4 +145,8 @@ namespace game WEAK symbol svs_numclients{ 0x6B229E0 }; WEAK symbol svs_clients{ 0x6B22950 }; + + WEAK symbol sv_map_restart{ 0x6B2C9D4 }; + WEAK symbol sv_loadScripts{ 0x6B2C9D8 }; + WEAK symbol sv_migrate{ 0x6B2C9DC }; }