diff --git a/data/gamesettings/mp/gamesettings_escort.cfg b/data/gamesettings/mp/gamesettings_escort.cfg new file mode 100644 index 00000000..5b713e17 --- /dev/null +++ b/data/gamesettings/mp/gamesettings_escort.cfg @@ -0,0 +1,26 @@ +gametype_setting timelimit 5 +gametype_setting scorelimit 0 +gametype_setting roundscorelimit 1 +gametype_setting roundwinlimit 2 +gametype_setting roundlimit 2 +gametype_setting preroundperiod 10 +gametype_setting teamCount 2 + +gametype_setting shutdownDamage 3 +gametype_setting bootTime 5 +gametype_setting rebootTime 15 +gametype_setting rebootPlayers 0 +gametype_setting movePlayers 1 +gametype_setting robotSpeed 1 +gametype_setting robotShield 0 + + +gametype_setting scoreHeroPowerGainFactor 0.788 //Score earned towards Hero Weapons and Abilities are multiplied by this factor +gametype_setting scoreHeroPowerTimeFactor 0.788 + +gametype_setting spawntraptriggertime 5 + +gametype_setting disableVehicleSpawners 1 + +gametype_setting gameAdvertisementRuleTimeLeft 3.5 +gametype_setting gameAdvertisementRuleRound 3 diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 6e7f249e..80a0245c 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -104,6 +104,9 @@ namespace dedicated_patches utils::hook::jump(0x14052F0F5_g, 0x14052F139_g); utils::hook::call(0x1402853D7_g, sv_get_player_xuid_stub); // PlayerCmd_GetXuid + + // Stop executing default_dedicated.cfg & language_settings.cfg + utils::hook::set(0x1405063C0_g, 0xC3); } }; } diff --git a/src/client/component/gamesettings.cpp b/src/client/component/gamesettings.cpp new file mode 100644 index 00000000..c511ef5c --- /dev/null +++ b/src/client/component/gamesettings.cpp @@ -0,0 +1,133 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include +#include + +namespace gamesettings +{ + namespace + { + // + std::unordered_map gamesettings_files; + + const std::string get_gamesettings_name(const std::vector& sub_strings) + { + if (sub_strings.size() > 2) + { + return sub_strings[sub_strings.size() - 2] + '/' + sub_strings[sub_strings.size() - 1]; + } + + return ""; + } + + const std::string get_gamesettings_path(const std::string& name) + { + const auto itr = gamesettings_files.find(name); + return (itr == gamesettings_files.end()) ? "" : itr->second; + } + + void search_gamesettings_folder(const std::string& gamesettings_dir) + { + if (!utils::io::directory_exists(gamesettings_dir)) + { + return; + } + + const auto files = utils::io::list_files(gamesettings_dir, true); + + for (const auto& path : files) + { + if (!std::filesystem::is_directory(path)) + { + auto sub_strings = utils::string::split(path.generic_string(), '/'); + gamesettings_files.insert_or_assign(get_gamesettings_name(sub_strings), path.generic_string()); + } + } + } + + bool has_gamesettings_file_on_disk(const char* path) + { + if (!path) + { + return false; + } + + auto sub_strings = utils::string::split(path, '/'); + auto gamesettings_name = get_gamesettings_name(sub_strings); + + return get_gamesettings_path(gamesettings_name) != ""; + } + + void cmd_exec_stub(utils::hook::assembler& a) + { + const auto exec_from_fastfile = a.newLabel(); + const auto exec_from_disk = a.newLabel(); + + a.pushad64(); + + a.mov(rcx, r10); + a.call_aligned(has_gamesettings_file_on_disk); + a.cmp(rax, 1); +; + a.popad64(); + + a.jnz(exec_from_fastfile); + + a.bind(exec_from_disk); + a.jmp(game::select(0x1420ED087, 0x1404F855E)); + + a.bind(exec_from_fastfile); + a.lea(rdx, ptr(rsp, (game::is_server() ? 0x30 : 0x40))); + a.jmp(game::select(0x1420ED007, 0x1404F853F)); + } + + int read_file_stub(const char* qpath, void** buffer) + { + auto sub_strings = utils::string::split(qpath, '/'); + auto game_settings_name = get_gamesettings_name(sub_strings); + + std::string gamesettings_data; + utils::io::read_file(get_gamesettings_path(game_settings_name), &gamesettings_data); + + if (!gamesettings_data.empty()) + { + ++(*game::fs_loadStack); + + auto len = static_cast(gamesettings_data.length()); + auto buf = game::FS_AllocMem(len + 1); + + *buffer = buf; + gamesettings_data.copy(reinterpret_cast(*buffer), len); + buf[len] = '\0'; + + return len; + } + + return utils::hook::invoke(game::select(0x1422A48D0, 0x140564F70), qpath, buffer); + } + + void search_gamesettings_files_on_disk() + { + const utils::nt::library host{}; + + search_gamesettings_folder((game::get_appdata_path() / "data/gamesettings").string()); + search_gamesettings_folder((host.get_folder() / "boiii/gamesettings").string()); + } + } + + struct component final : generic_component + { + void post_unpack() override + { + search_gamesettings_files_on_disk(); + + utils::hook::call(game::select(0x1420ED0A1, 0x1404F857D), read_file_stub); + utils::hook::jump(game::select(0x1420ED002, 0x1404F853A), utils::hook::assemble(cmd_exec_stub)); + } + }; +}; + +REGISTER_COMPONENT(gamesettings::component) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index f754090f..422a74c3 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -35,6 +35,7 @@ namespace game WEAK symbol Com_SwitchMode{ 0x14214A4D0 }; + WEAK symbol Com_LoadRawTextFile{0x1420F61B0}; WEAK symbol Cbuf_AddText{0x1420EC010, 0x1404F75B0}; WEAK symbol Cbuf_ExecuteBuffer{ @@ -180,6 +181,9 @@ namespace game WEAK symbol SV_Cmd_TokenizeString{0x1420EF130, 0x1404FA6C0}; WEAK symbol SV_Cmd_EndTokenizedString{0x1420EF0E0, 0x1404FA670}; + // FS + WEAK symbol FS_AllocMem{0x1422AC9F0, 0x14056C340}; + // Utils WEAK symbol I_CleanStr{0x1422E9050, 0x140580E80}; @@ -198,6 +202,8 @@ namespace game WEAK symbol s_dvarPool{0x157AC6220, 0x14A3CB620}; WEAK symbol g_dvarCount{0x157AC61CC, 0x14A3CB5FC}; + WEAK symbol fs_loadStack{0x157A65310, 0x14A39C650}; + // Client and dedi struct size differs :( WEAK symbol svs_clients_cl{0x1576F9318, 0}; WEAK symbol svs_clients{0x0, 0x14A178E98};