diff --git a/deps/rapidjson b/deps/rapidjson index e4bde977..fd3dc29a 160000 --- a/deps/rapidjson +++ b/deps/rapidjson @@ -1 +1 @@ -Subproject commit e4bde977440d4a00f820b6586899e48a972d2493 +Subproject commit fd3dc29a5c2852df569e1ea81dbde2c412ac5051 diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index 971f551b..4386d98d 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -10,6 +10,7 @@ #include #include #include "utils/io.hpp" +#include namespace command { @@ -296,38 +297,6 @@ namespace command console::info("Total %i matches\n", matches.size()); });*/ - add("dvarDump", [](const params& argument) - { - console::info("================================ DVAR DUMP ========================================\n"); - std::string filename; - if (argument.size() == 2) - { - filename = "h1-mod/"; - filename.append(argument[1]); - if (!filename.ends_with(".txt")) - { - filename.append(".txt"); - } - } - for (auto i = 0; i < *game::dvarCount; i++) - { - const auto dvar = game::sortedDvars[i]; - if (dvar) - { - if (!filename.empty()) - { - const auto line = std::format("{} \"{}\"\r\n", dvar->hash, - game::Dvar_ValueToString(dvar, dvar->current)); - utils::io::write_file(filename, line, i != 0); - } - console::info("%s \"%s\"\n", dvar->hash, - game::Dvar_ValueToString(dvar, dvar->current)); - } - } - console::info("\n%i dvars\n", *game::dvarCount); - console::info("================================ END DVAR DUMP ====================================\n"); - }); - add("commandDump", [](const params& argument) { console::info("================================ COMMAND DUMP =====================================\n"); @@ -360,6 +329,7 @@ namespace command console::info("\n%i commands\n", i); console::info("================================ END COMMAND DUMP =================================\n"); }); + /* add("listassetpool", [](const params& params) { @@ -502,7 +472,7 @@ namespace command : "^1off")); }); - /*add("give", [](const params& params) + add("give", [](const params& params) { if (!game::SV_Loaded()) { @@ -546,7 +516,7 @@ namespace command { game::G_TakePlayerWeapon(ps, wp); } - });*/ + }); } static void add_commands_mp() diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp index e2563a5f..dca1d458 100644 --- a/src/client/component/game_console.cpp +++ b/src/client/component/game_console.cpp @@ -336,6 +336,8 @@ namespace game_console } } + + void draw_output_scrollbar(const float x, float y, const float width, const float height, output_queue& output) { const auto _x = (x + width) - 10.0f; diff --git a/src/client/component/game_console.hpp b/src/client/component/game_console.hpp index 144f2064..82a7aabd 100644 --- a/src/client/component/game_console.hpp +++ b/src/client/component/game_console.hpp @@ -2,19 +2,9 @@ namespace game_console { - enum console_type - { - con_type_error = 1, - con_type_warning = 3, - con_type_info = 7 - }; - - //void print(int type, const char* fmt, ...); - bool console_char_event(int local_client_num, int key); bool console_key_event(int local_client_num, int key, int down); + bool match_compare(const std::string& input, const std::string& text, const bool exact); void find_matches(std::string input, std::vector& suggestions, const bool exact); - - void execute(const char* cmd); } \ No newline at end of file diff --git a/src/client/component/localized_strings.cpp b/src/client/component/localized_strings.cpp index 3fd2491c..18a80644 100644 --- a/src/client/component/localized_strings.cpp +++ b/src/client/component/localized_strings.cpp @@ -3,6 +3,7 @@ #include "localized_strings.hpp" #include #include +#include #include "game/game.hpp" namespace localized_strings @@ -11,37 +12,30 @@ namespace localized_strings { utils::hook::detour seh_string_ed_get_string_hook; - std::unordered_map& get_localized_overrides() - { - static std::unordered_map overrides; - return overrides; - } - - std::mutex& get_synchronization_mutex() - { - static std::mutex mutex; - return mutex; - } + using localized_map = std::unordered_map; + utils::concurrency::container localized_overrides; const char* seh_string_ed_get_string(const char* reference) { - std::lock_guard _(get_synchronization_mutex()); + return localized_overrides.access([&](const localized_map& map) + { + const auto entry = map.find(reference); + if (entry != map.end()) + { + return utils::string::va("%s", entry->second.data()); + } - auto& overrides = get_localized_overrides(); - const auto entry = overrides.find(reference); - if (entry != overrides.end()) - { - return utils::string::va("%s", entry->second.data()); - } - - return seh_string_ed_get_string_hook.invoke(reference); + return seh_string_ed_get_string_hook.invoke(reference); + }); } } void override(const std::string& key, const std::string& value) { - std::lock_guard _(get_synchronization_mutex()); - get_localized_overrides()[key] = value; + localized_overrides.access([&](localized_map& map) + { + map[key] = value; + }); } class component final : public component_interface @@ -50,7 +44,7 @@ namespace localized_strings void post_unpack() override { // Change some localized strings - seh_string_ed_get_string_hook.create(SELECT_VALUE(0x1403924A0, 0x1404BB2A0), &seh_string_ed_get_string); // H1(1.4) + seh_string_ed_get_string_hook.create(SELECT_VALUE(0x1403924A0, 0x1404BB2A0), &seh_string_ed_get_string); } }; } diff --git a/src/client/component/map_rotation.cpp b/src/client/component/map_rotation.cpp new file mode 100644 index 00000000..9e3002e8 --- /dev/null +++ b/src/client/component/map_rotation.cpp @@ -0,0 +1,180 @@ +#include +#include "loader/component_loader.hpp" +#include "command.hpp" +#include "scheduler.hpp" +#include +#include +#include "game/game.hpp" +#include + +namespace map_rotation +{ + DWORD previousPriority; + namespace + { + void set_dvar(const std::string& dvar, const std::string& value) + { + command::execute(utils::string::va("%s \"%s\"", dvar.data(), value.data()), true); + } + + void set_gametype(const std::string& gametype) + { + set_dvar("g_gametype", gametype); + } + + void launch_map(const std::string& mapname) + { + command::execute(utils::string::va("map %s", mapname.data()), false); + } + + void launch_default_map() + { + auto* mapname = game::Dvar_FindVar("mapname"); + if (mapname && mapname->current.string && strlen(mapname->current.string) && mapname->current.string != + "mp_vlobby_room"s) + { + launch_map(mapname->current.string); + } + else + { + launch_map("mp_crash_snow"); + } + } + + std::string load_current_map_rotation() + { + auto* rotation = game::Dvar_FindVar("sv_mapRotationCurrent"); + if (!strlen(rotation->current.string)) + { + rotation = game::Dvar_FindVar("sv_mapRotation"); + set_dvar("sv_mapRotationCurrent", rotation->current.string); + } + + return rotation->current.string; + } + + std::vector parse_current_map_rotation() + { + const auto rotation = load_current_map_rotation(); + return utils::string::split(rotation, ' '); + } + + void store_new_rotation(const std::vector& elements, const size_t index) + { + std::string value{}; + + for (auto i = index; i < elements.size(); ++i) + { + if (i != index) + { + value.push_back(' '); + } + + value.append(elements[i]); + } + + set_dvar("sv_mapRotationCurrent", value); + } + + void change_process_priority() + { + auto* const dvar = game::Dvar_FindVar("sv_autoPriority"); + if (dvar && dvar->current.enabled) + { + scheduler::on_game_initialized([]() + { + //printf("=======================setting OLD priority=======================\n"); + SetPriorityClass(GetCurrentProcess(), previousPriority); + }, scheduler::pipeline::main, 1s); + + previousPriority = GetPriorityClass(GetCurrentProcess()); + //printf("=======================setting NEW priority=======================\n"); + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + } + } + + void perform_map_rotation() + { + if (game::Live_SyncOnlineDataFlags(0) != 0) + { + scheduler::on_game_initialized(perform_map_rotation, scheduler::pipeline::main, 1s); + return; + } + + const auto rotation = parse_current_map_rotation(); + + for (size_t i = 0; !rotation.empty() && i < (rotation.size() - 1); i += 2) + { + const auto& key = rotation[i]; + const auto& value = rotation[i + 1]; + + if (key == "gametype") + { + set_gametype(value); + } + else if (key == "map") + { + store_new_rotation(rotation, i + 2); + change_process_priority(); + if (!game::SV_MapExists(value.data())) + { + printf("map_rotation: '%s' map doesn't exist!\n", value.data()); + launch_default_map(); + return; + } + launch_map(value); + return; + } + else + { + printf("Invalid map rotation key: %s\n", key.data()); + } + } + + launch_default_map(); + } + + void trigger_map_rotation() + { + scheduler::schedule([]() + { + if (game::CL_IsCgameInitialized()) + { + return scheduler::cond_continue; + } + + command::execute("map_rotate", false); + return scheduler::cond_end; + }, scheduler::pipeline::main, 1s); + } + + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (!game::environment::is_dedi()) + { + return; + } + + scheduler::once([]() + { + dvars::register_string("sv_mapRotation", "", game::DVAR_FLAG_NONE, true); + dvars::register_string("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, true); + dvars::register_string("sv_autoPriority", "", game::DVAR_FLAG_NONE, true); + }, scheduler::pipeline::main); + + command::add("map_rotate", &perform_map_rotation); + + // Hook GScr_ExitLevel + utils::hook::jump(0x140376630, &trigger_map_rotation); // not sure if working + + previousPriority = GetPriorityClass(GetCurrentProcess()); + } + }; +} + +REGISTER_COMPONENT(map_rotation::component) \ No newline at end of file diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index 45565a57..3c3ac18d 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace scheduler { @@ -146,25 +147,55 @@ namespace scheduler }, type, delay); } + void on_game_initialized(const std::function& callback, const pipeline type, + const std::chrono::milliseconds delay) + { + schedule([=]() + { + const auto dw_init = game::environment::is_sp() ? true : game::Live_SyncOnlineDataFlags(0) == 0; + if (dw_init && game::Sys_IsDatabaseReady2()) + { + once(callback, type, delay); + return cond_end; + } + + return cond_continue; + }, pipeline::main); + } + class component final : public component_interface { public: + void post_start() override + { + thread = utils::thread::create_named_thread("Async Scheduler", []() + { + while (!kill) + { + execute(pipeline::async); + std::this_thread::sleep_for(10ms); + } + }); + } + void post_unpack() override { - //thread = std::thread([]() - //{ - // while (!kill) - // { - // execute(pipeline::async); - // std::this_thread::sleep_for(10ms); - // } - //}); r_end_frame_hook.create(SELECT_VALUE(0x1404F7310, 0x1405FE470), scheduler::r_end_frame_stub); // H1(1.4) g_run_frame_hook.create(SELECT_VALUE(0x1402772D0, 0x1402772D0), scheduler::server_frame_stub); // H1(1.4) main_frame_hook.create(SELECT_VALUE(0x1401CE8D0, 0x1401CE8D0), scheduler::main_frame_stub); // H1(1.4) + + } + + void pre_destroy() override + { + kill = true; + if (thread.joinable()) + { + thread.join(); + } } }; } -REGISTER_COMPONENT(scheduler::component) +REGISTER_COMPONENT(scheduler::component) \ No newline at end of file diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index c11e00d7..7109b80b 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -2,6 +2,7 @@ #include #include "game.hpp" +#include namespace dvars { @@ -217,6 +218,7 @@ namespace dvars "fs_userDocuments", "fs_usermapdir", "g_gametype", + "gametype", "g_hardcore", "g_listEntity", "g_loadScripts", @@ -325,10 +327,10 @@ namespace dvars "sv_lastSaveCommitedToDevice", "sv_local_client_snapshot_msec", "sv_mapname", - "mapname", + "mapname", "sv_mapRotation", "sv_mapRotationCurrent", - "cl_maxpackets", + "cl_maxpackets", "sv_maxclients", "sv_maxPhysExplosionSpheres", "sv_maxPing", @@ -382,6 +384,10 @@ namespace dvars "sv_wwwDownload", "sv_zlib_threshold", "sv_zombietime", + "sv_mapRotation", + "sv_mapRotationCurrent", + "sv_autoPriority", + //"xpartygo", "svwp", "syncTimeTimeout", "sys_configSum", @@ -490,7 +496,8 @@ namespace dvars "custom_scr_team_teamkillspawndelay", "custom_scr_vehicles_enabled", "name", - "custom_timelimit" + "custom_timelimit", + "map" }; bool can_add_dvar_to_list(std::string name) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index db1ad670..08d1d8f6 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -15,6 +15,8 @@ namespace game WEAK symbol Com_Frame_Try_Block_Function{ 0, 0x1400D8310 }; //H1MP MWR TEST + WEAK symbol Com_GetCurrentCoDPlayMode{ 0, 0x1405039A0 }; // H1(1.4) + WEAK symbol BG_GetWeaponNameComplete{ 0, 0x140165580 }; WEAK symbol Com_Quit_f{ 0x140352BE0, 0x1400DA830 }; // H1(1.4) @@ -93,6 +95,7 @@ namespace game WEAK symbol G_GetClientScore{ 0, 0x140342F90 }; // H1(1.4) WEAK symbol SV_GetGuid{ 0, 0x140484B90 }; // H1(1.4) WEAK symbol SV_GetClientPing{ 0, 0x140484B70 }; // H1(1.4) + WEAK symbol SV_GetPlayerstateForClientNum{ 0x1404426D0, 0 }; // H1SP(1.4) WEAK symbol H1_AddBaseDrawTextCmd{ 0x1404F3DC0,0x1405FB1F0 }; // H1(1.4) @@ -134,7 +137,7 @@ namespace game WEAK symbol FindEntityId{ 0, 0x1405C1C50 }; WEAK symbol GetEntityFieldValue{ 0, 0x1405C6100 }; - WEAK symbol G_GetWeaponForName{ 0, 0x14051B260 }; + WEAK symbol G_GetWeaponForName{ 0x1402C2A90, 0 }; // H1SP(1.4) //WEAK symbol //G_GivePlayerWeapon{ 0, 0x14051B660 }; @@ -144,6 +147,7 @@ namespace game WEAK symbol G_InitializeAmmo{ 0, 0x1404C4110 }; WEAK symbol G_SelectWeapon{ 0,0x14051C0D0 }; + WEAK symbol G_TakePlayerWeapon{ 0x1402C3900, 0 }; // H1SP(1.4) WEAK symbol Image_Setup{ 0, 0x14074B2A0 }; @@ -167,7 +171,9 @@ namespace game WEAK symbol SL_ConvertToString{ 0x14036D420, 0x1405BFBB0 }; WEAK symbol SL_GetString{ 0x14036D9A0, 0x1405C0170 }; - WEAK symbol SV_Loaded{ 0x140442F60, 0x140442F60 }; + WEAK symbol SV_Loaded{ 0x140442F60, 0x1404864A0 }; // H1(1.4) + + WEAK symbol SV_MapExists{ 0, 0x14047ED60 }; // H1(1.4) WEAK symbol Sys_ShowConsole{ 0x1403E3B90, 0x140514910 }; // H1(1.4)