From bab89ec8280921c8976ba62d488d659a2eb43893 Mon Sep 17 00:00:00 2001 From: Jack Back Date: Wed, 13 Mar 2024 09:22:05 +0000 Subject: [PATCH 1/7] maint: fix typo in build instructions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4609b53..fd8e51a 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ This is a client modification for S1! - Install [Premake5][premake5-link] and add it to your system PATH - Clone this repository using [Git][git-link] - Update the submodules using ``git submodule update --init --recursive`` -- Run Premake with this options ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported. +- Run Premake with the option ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported. - Build project via solution file in `build\s1-mod.sln`. -Only x64 is supported. Do not attempt to build for Windows ARM 64. +Only the x64 platform is supported. Do not attempt to build for Windows ARM 64 or Win32. ### Premake arguments From e2e5e281c2cb68f69816603889a4bcfa03f20d3c Mon Sep 17 00:00:00 2001 From: Jack Back Date: Sun, 31 Mar 2024 19:13:28 +0200 Subject: [PATCH 2/7] maint: dump changes --- src/client/component/gsc/script_extension.cpp | 8 ++--- src/client/component/gsc/script_extension.hpp | 2 -- src/client/component/gsc/script_loading.cpp | 35 ++++++++----------- src/client/component/network.cpp | 8 ++--- src/client/component/patches.cpp | 7 ++-- src/client/component/rcon.cpp | 12 +++---- src/client/component/stats.cpp | 20 +++++------ src/client/game/dvars.cpp | 3 ++ src/client/game/dvars.hpp | 7 ++-- src/client/main.cpp | 21 ++++++++++- src/client/std_include.hpp | 2 ++ 11 files changed, 68 insertions(+), 57 deletions(-) diff --git a/src/client/component/gsc/script_extension.cpp b/src/client/component/gsc/script_extension.cpp index 5b0e3a2..c45f4fb 100644 --- a/src/client/component/gsc/script_extension.cpp +++ b/src/client/component/gsc/script_extension.cpp @@ -1,6 +1,8 @@ #include #include "loader/component_loader.hpp" #include "game/game.hpp" +#include "game/dvars.hpp" + #include "game/scripting/functions.hpp" #include @@ -19,8 +21,6 @@ namespace gsc std::uint16_t function_id_start = 0x2DF; void* func_table[0x1000]; - const game::dvar_t* developer_script = nullptr; - namespace { #define RVA(ptr) static_cast(reinterpret_cast(ptr) - 0x140000000) @@ -135,7 +135,7 @@ namespace gsc void vm_error_stub(int mark_pos) { - if (!developer_script->current.enabled && !force_error_print) + if (!dvars::com_developer_script->current.enabled && !force_error_print) { utils::hook::invoke(0x1404B6790, mark_pos); return; @@ -263,8 +263,6 @@ namespace gsc return; } - developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); - utils::hook::nop(0x1403FB7F7 + 5, 2); utils::hook::call(0x1403FB7F7, vm_call_builtin_function); diff --git a/src/client/component/gsc/script_extension.hpp b/src/client/component/gsc/script_extension.hpp index bdd44ff..9fab151 100644 --- a/src/client/component/gsc/script_extension.hpp +++ b/src/client/component/gsc/script_extension.hpp @@ -4,8 +4,6 @@ namespace gsc { extern void* func_table[0x1000]; - extern const game::dvar_t* developer_script; - void scr_error(const char* error); void override_function(const std::string& name, game::BuiltinFunction func); void add_function(const std::string& name, game::BuiltinFunction function); diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp index 5f3bd65..1010774 100644 --- a/src/client/component/gsc/script_loading.cpp +++ b/src/client/component/gsc/script_loading.cpp @@ -1,6 +1,7 @@ #include #include "loader/component_loader.hpp" #include "game/game.hpp" +#include "game/dvars.hpp" #include #include @@ -10,7 +11,6 @@ #include "component/filesystem.hpp" #include "component/console.hpp" #include "component/scripting.hpp" -#include "component/fastfiles.hpp" #include "script_loading.hpp" @@ -26,8 +26,6 @@ namespace gsc std::unordered_map loaded_scripts; utils::memory::allocator script_allocator; - const game::dvar_t* developer_script; - void clear() { main_handles.clear(); @@ -228,18 +226,6 @@ namespace gsc clear(); - fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](const game::XAssetHeader header) - { - const std::string name = header.rawfile->name; - - if (name.ends_with(".gsc") && name.starts_with("scripts/")) - { - // Remove .gsc from the file name as it will be re-added by the game later - const auto base_name = name.substr(0, name.size() - 4); - load_script(base_name); - } - }, true); - for (const auto& path : filesystem::get_search_paths()) { load_scripts(path); @@ -292,11 +278,19 @@ namespace gsc void scr_begin_load_scripts_stub() { - const auto comp_mode = developer_script->current.enabled ? - xsk::gsc::build::dev : - xsk::gsc::build::prod; + auto build = xsk::gsc::build::prod; - gsc_ctx->init(comp_mode, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair> + if (dvars::com_developer && dvars::com_developer->current.integer > 0) + { + build = static_cast(static_cast(build) | static_cast(xsk::gsc::build::dev_maps)); + } + + if (dvars::com_developer_script && dvars::com_developer_script->current.enabled) + { + build = static_cast(static_cast(build) | static_cast(xsk::gsc::build::dev_blocks)); + } + + gsc_ctx->init(build, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair> { const auto script_name = std::filesystem::path(included_path).replace_extension().string(); @@ -364,7 +358,8 @@ namespace gsc utils::hook::call(SELECT_VALUE(0x1403309E9, 0x1403309E9), scr_begin_load_scripts_stub); // GScr_LoadScripts utils::hook::call(SELECT_VALUE(0x14023DA84, 0x140330B9C), scr_end_load_scripts_stub); // GScr_LoadScripts - developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); + dvars::com_developer = game::Dvar_RegisterInt("developer", 0, 0, 2, game::DVAR_FLAG_NONE, "Enable development options"); + dvars::com_developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments"); if (game::environment::is_sp()) { diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index e813a1d..a895d9b 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -3,9 +3,9 @@ #include "game/game.hpp" #include "command.hpp" -#include "network.hpp" #include "console.hpp" #include "dvars.hpp" +#include "network.hpp" #include #include @@ -273,12 +273,8 @@ namespace network utils::hook::set(0x1403DAD14, max_packet_size); utils::hook::set(0x1403DAD35, max_packet_size); - // ignore built in "print" oob command and add in our own + // ignore built in "print" oob command for security reasons utils::hook::set(0x14020A723, 0xEB); - on("print", [](const game::netadr_s&, const std::string& data) - { - console::info("%s", data.data()); - }); } } }; diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 6408da2..fed15d4 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -35,6 +35,7 @@ namespace patches { return; } + return sv_kick_client_num_hook.invoke(client_num, reason); } @@ -100,7 +101,7 @@ namespace patches } else { - char command[0x1000] = {0}; + char command[0x1000]{}; game::Dvar_GetCombinedString(command, 1); game::Dvar_SetCommand(args.get(0), command); } @@ -226,10 +227,6 @@ namespace patches SetThreadExecutionState(ES_DISPLAY_REQUIRED); }, scheduler::pipeline::main); - // Allow kbam input when gamepad is enabled - utils::hook::nop(SELECT_VALUE(0x14013EF83, 0x140206DB3), 2); - utils::hook::nop(SELECT_VALUE(0x14013CBAC, 0x140204710), 6); - if (game::environment::is_sp()) { patch_sp(); diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp index a9216e4..e1901b3 100644 --- a/src/client/component/rcon.cpp +++ b/src/client/component/rcon.cpp @@ -79,7 +79,7 @@ namespace rcon strncpy_s(clean_name, client->name, _TRUNCATE); game::I_CleanStr(clean_name); - if (client->header.state >= 1) + if (client->header.state > game::CA_DISCONNECTED) { buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n", i, @@ -136,12 +136,13 @@ namespace rcon return; } - console::info("%s", build_status_buffer().data()); + const auto status = build_status_buffer(); + console::info("%s", status.data()); }); if (!game::environment::is_dedi()) { - command::add("rcon", [&](const command::params& params) + command::add("rcon", [](const command::params& params) { static std::string rcon_password{}; @@ -178,9 +179,8 @@ namespace rcon const auto password = message.substr(0, pos); const auto command = message.substr(pos + 1); - const auto rcon_password = game::Dvar_FindVar("rcon_password"); - if (command.empty() || !rcon_password || !rcon_password->current.string || !strlen( - rcon_password->current.string)) + const auto* rcon_password = game::Dvar_FindVar("rcon_password"); + if (command.empty() || !rcon_password || !*rcon_password->current.string) { return; } diff --git a/src/client/component/stats.cpp b/src/client/component/stats.cpp index 2450b63..90d167c 100644 --- a/src/client/component/stats.cpp +++ b/src/client/component/stats.cpp @@ -12,8 +12,8 @@ namespace stats { namespace { - game::dvar_t* cg_unlock_all_items; - game::dvar_t* cg_unlock_all_loot; + const game::dvar_t* cg_unlock_all_items; + const game::dvar_t* cg_unlock_all_loot; utils::hook::detour is_item_locked_hook1; utils::hook::detour is_item_locked_hook2; @@ -74,17 +74,17 @@ namespace stats } else { - // unlock all - cg_unlock_all_items = game::Dvar_RegisterBool("cg_unlockall_items", false, game::DVAR_FLAG_SAVED, "Unlock items that are level-locked by the player's stats."); + // unlock all + cg_unlock_all_items = game::Dvar_RegisterBool("cg_unlockall_items", false, game::DVAR_FLAG_SAVED, "Unlock items that are level-locked by the player's stats."); cg_unlock_all_loot = game::Dvar_RegisterBool("cg_unlockall_loot", false, game::DVAR_FLAG_SAVED, "Unlock supply drop loot."); - game::Dvar_RegisterBool("cg_unlockall_classes", false, game::DVAR_FLAG_SAVED, "Unlock extra class slots."); + game::Dvar_RegisterBool("cg_unlockall_classes", false, game::DVAR_FLAG_SAVED, "Unlock extra class slots."); - is_item_locked_hook1.create(0x1403BD790, is_item_locked_stub1); // LiveStorage_IsItemUnlockedFromTable_LocalClient - is_item_locked_hook2.create(0x1403BD290, is_item_locked_stub2); // LiveStorage_IsItemUnlockedFromTable - is_item_locked_hook3.create(0x1403BAF60, is_loot_locked_stub); // unlocks supply drop loot - } + is_item_locked_hook1.create(0x1403BD790, is_item_locked_stub1); // LiveStorage_IsItemUnlockedFromTable_LocalClient + is_item_locked_hook2.create(0x1403BD290, is_item_locked_stub2); // LiveStorage_IsItemUnlockedFromTable + is_item_locked_hook3.create(0x1403BAF60, is_loot_locked_stub); // unlocks supply drop loot + } - command::add("setPlayerDataInt", [](const command::params& params) + command::add("setPlayerDataInt", [](const command::params& params) { if (params.size() < 2) { diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index 7423c2f..d80d00b 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -40,6 +40,9 @@ namespace dvars game::dvar_t* sv_cheats = nullptr; + game::dvar_t* com_developer = nullptr; + game::dvar_t* com_developer_script = nullptr; + std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain) { if (domain.vector.min == -FLT_MAX) diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index fe3e7aa..40bbe82 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -39,6 +39,9 @@ namespace dvars extern game::dvar_t* sv_cheats; - std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain); - std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain); + extern game::dvar_t* com_developer; + extern game::dvar_t* com_developer_script; + + std::string dvar_get_vector_domain(int components, const game::dvar_limits& domain); + std::string dvar_get_domain(game::dvar_type type, const game::dvar_limits& domain); } diff --git a/src/client/main.cpp b/src/client/main.cpp index 2f06702..c0ad37d 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -12,6 +12,21 @@ #include +const char* get_current_date() +{ + auto now = std::chrono::system_clock::now(); + auto current_time = std::chrono::system_clock::to_time_t(now); + std::tm local_time{}; + + (void)localtime_s(&local_time, ¤t_time); + + std::stringstream ss; + ss << std::put_time(&local_time, "%Y%m%d_%H%M%S"); + + const auto result = ss.str(); + return utils::string::va("%s", result.data()); +} + LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info) { if (exception_info->ExceptionRecord->ExceptionCode == 0x406D1388) @@ -38,7 +53,7 @@ LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info) | MiniDumpWithThreadInfo; CreateDirectoryA("minidumps", nullptr); - const auto* file_name = utils::string::va("minidumps\\s1-mod_%s_%u.dmp", SHORTVERSION, static_cast(std::time(nullptr))); + const auto* file_name = utils::string::va("minidumps\\s1-mod_%s_%s.dmp", SHORTVERSION, get_current_date()); constexpr auto file_share = FILE_SHARE_READ | FILE_SHARE_WRITE; const auto file_handle = CreateFileA(file_name, GENERIC_WRITE | GENERIC_READ, file_share, nullptr, @@ -166,7 +181,11 @@ FARPROC load_binary(const launcher::mode mode) binary.data())); } +#ifdef INJECT_HOST_AS_LIB return loader.load_library(binary); +#else + return loader.load(self, data); +#endif } void remove_crash_file() diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index 4ba2eb3..0ab229c 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -32,6 +32,8 @@ #include #include +#define INJECT_HOST_AS_LIB + // min and max is required by gdi, therefore NOMINMAX won't work #ifdef max #undef max From 6b849fdb2197682f538b72f077927d70a2e304b6 Mon Sep 17 00:00:00 2001 From: Jack Back Date: Sun, 31 Mar 2024 22:33:05 +0200 Subject: [PATCH 3/7] maint(network): very good fix --- src/client/component/network.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index a895d9b..294ce58 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -97,6 +97,11 @@ namespace network // Rather than try and let the player in, just tell them they are a duplicate player and reject connection game::NET_OutOfBandPrint(game::NS_SERVER, from, "error\nYou are already connected to the server."); } + + void* memmove_stub(void* dest, const void* src, std::size_t count) + { + return std::memmove(dest, src, std::min(count, 1262)); + } } void on(const std::string& command, const callback& callback) @@ -275,6 +280,9 @@ namespace network // ignore built in "print" oob command for security reasons utils::hook::set(0x14020A723, 0xEB); + + // patch buffer overflow + utils::hook::call(0x1403DA8A4, memmove_stub); // NET_GetDeferredClientPacket } } }; From 7cc285705b04657f1a0587eda2362973477383a2 Mon Sep 17 00:00:00 2001 From: Jack Back Date: Mon, 1 Apr 2024 00:02:28 +0200 Subject: [PATCH 4/7] maint(deps): bump gsc-tool --- deps/gsc-tool | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/gsc-tool b/deps/gsc-tool index 2dbff1a..b8e30e6 160000 --- a/deps/gsc-tool +++ b/deps/gsc-tool @@ -1 +1 @@ -Subproject commit 2dbff1a408096e418c5b3eda01bc9a91eee6587b +Subproject commit b8e30e6334aa33ea731caf8d0700a9e6c7794c09 From 0c2ed72792ed9424ba1bd813ac87ba31b4f77c4e Mon Sep 17 00:00:00 2001 From: Jack Back Date: Mon, 1 Apr 2024 12:14:23 +0200 Subject: [PATCH 5/7] maint(network): rename function --- src/client/component/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 294ce58..3be9886 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -282,7 +282,7 @@ namespace network utils::hook::set(0x14020A723, 0xEB); // patch buffer overflow - utils::hook::call(0x1403DA8A4, memmove_stub); // NET_GetDeferredClientPacket + utils::hook::call(0x1403DA8A4, memmove_stub); // NET_DeferPacketToClient } } }; From 1ac8a93a32364824baa6dfc155eeb99d577712fd Mon Sep 17 00:00:00 2001 From: Jack Back Date: Mon, 1 Apr 2024 18:01:38 +0200 Subject: [PATCH 6/7] maint(bots): update logic --- src/client/component/bots.cpp | 44 ++++++++++++++++++++------------ src/client/component/network.cpp | 2 +- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 6c0a9c3..5c06b7f 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -64,7 +64,7 @@ namespace bots // SV_BotGetRandomName const auto* const bot_name = game::SV_BotGetRandomName(); - auto* bot_ent = game::SV_AddBot(bot_name); + const auto* bot_ent = game::SV_AddBot(bot_name); if (bot_ent) { spawn_bot(bot_ent->s.number); @@ -79,22 +79,13 @@ namespace bots volatile bool bot_names_received = false; std::vector bot_names; - const char* get_random_bot_name() - { - if (bot_names.empty()) - { - return get_bot_name_hook.invoke(); - } - - const auto index = std::rand() % bot_names.size(); - const auto& name = bot_names.at(index); - - return utils::string::va("%.*s", static_cast(name.size()), name.data()); - } - - bool should_update_bot_names() + bool should_use_remote_bot_names() { +#ifdef ALLOW_CUSTOM_BOT_NAMES return !filesystem::exists("bots.txt"); +#else + return true; +#endif } void parse_bot_names_from_file() @@ -122,11 +113,30 @@ namespace bots } } + const char* get_random_bot_name() + { + if (!bot_names_received && bot_names.empty()) + { + // last attempt to use custom names if they can be found + parse_bot_names_from_file(); + } + + if (bot_names.empty()) + { + return get_bot_name_hook.invoke(); + } + + const auto index = std::rand() % bot_names.size(); + const auto& name = bot_names.at(index); + + return utils::string::va("%.*s", static_cast(name.size()), name.data()); + } + void update_bot_names() { bot_names_received = false; - game::netadr_s master; + game::netadr_s master{}; if (server_list::get_master_server(master)) { console::info("Getting bots...\n"); @@ -167,7 +177,7 @@ namespace bots } }); - if (should_update_bot_names()) + if (should_use_remote_bot_names()) { scheduler::on_game_initialized([]() -> void { diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 3be9886..02cccee 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -167,7 +167,7 @@ namespace network { if (a.port) { - return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], htons(a.port)); + return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ::htons(a.port)); } return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); From 0857be79df676ee800af609279caad51a3a56785 Mon Sep 17 00:00:00 2001 From: 6arelyFuture Date: Fri, 26 Apr 2024 10:38:53 +0200 Subject: [PATCH 7/7] maint: April update --- src/client/component/bots.cpp | 1 + src/client/component/network.cpp | 25 +++++++++++++++----- src/client/component/patches.cpp | 6 ++--- src/client/component/rcon.cpp | 7 +++++- src/client/game/demonware/services/bdDML.cpp | 2 +- src/client/game/dvars.cpp | 12 +++++----- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 5c06b7f..70656d7 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -197,6 +197,7 @@ namespace bots { const std::string received_data{ data }; bot_names = utils::string::split(received_data, '\n'); + console::info("Got %zu names from the master server\n", bot_names.size()); bot_names_received = true; } }); diff --git a/src/client/component/network.cpp b/src/client/component/network.cpp index 02cccee..3c36aa4 100644 --- a/src/client/component/network.cpp +++ b/src/client/component/network.cpp @@ -6,6 +6,7 @@ #include "console.hpp" #include "dvars.hpp" #include "network.hpp" +#include "party.hpp" #include #include @@ -89,8 +90,7 @@ namespace network return net_compare_base_address(a1, a2) && a1->port == a2->port; } - void reconnect_migratated_client(void*, game::netadr_s* from, const int, const int, const char*, - const char*, bool) + void reconnect_migrated_client(void*, game::netadr_s* from, const int, const int, const char*, const char*, bool) { // This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid // We don't want this to do anything. It decides to crash seemingly randomly @@ -210,7 +210,7 @@ namespace network utils::hook::nop(0x14043FFF8, 6); utils::hook::jump(0x1403DA700, net_compare_address); - utils::hook::jump(0x1403DA750, net_compare_base_address); + utils::hook::jump(0x1403DA750, net_compare_address); // don't establish secure conenction utils::hook::set(0x140232BBD, 0xEB); @@ -244,8 +244,8 @@ namespace network // ignore dw handle in SV_DirectConnect utils::hook::set(0x140439BA8, 0xEB); utils::hook::set(0x140439DA5, 0xEB); - utils::hook::call(0x140439B9B, &net_compare_address); - utils::hook::call(0x140439D98, &net_compare_address); + utils::hook::call(0x140439B9B, net_compare_address); + utils::hook::call(0x140439D98, net_compare_address); // increase cl_maxpackets dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED); @@ -264,7 +264,7 @@ namespace network utils::hook::jump(0x1404D842B, 0x1404D8453); // don't try to reconnect client - utils::hook::call(0x140439D4D, reconnect_migratated_client); + utils::hook::call(0x140439D4D, reconnect_migrated_client); utils::hook::nop(0x140439D28, 4); // this crashes when reconnecting for some reason // allow server owner to modify net_port before the socket bind @@ -280,6 +280,19 @@ namespace network // ignore built in "print" oob command for security reasons utils::hook::set(0x14020A723, 0xEB); + if (!game::environment::is_dedi()) + { + // we need this on the client for RCon + on("print", [](const game::netadr_s& address, const std::string& message) + { + if (address != party::get_target()) + { + return; + } + + console::info("%s", message.data()); + }); + } // patch buffer overflow utils::hook::call(0x1403DA8A4, memmove_stub); // NET_DeferPacketToClient diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index fed15d4..e810bcb 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -94,9 +94,9 @@ namespace patches { if (args.size() == 1) { - const auto* const current = game::Dvar_ValueToString(dvar, dvar->current); - const auto* const reset = game::Dvar_ValueToString(dvar, dvar->reset); - console::info("\"%s\" is: \"%s^7\" default: \"%s^7\"\n", dvar->name, current, reset); + const std::string current = game::Dvar_ValueToString(dvar, dvar->current); + const std::string reset = game::Dvar_ValueToString(dvar, dvar->reset); + console::info("\"%s\" is: \"%s^7\" default: \"%s^7\"\n", dvar->name, current.data(), reset.data()); console::info(" %s\n", dvars::dvar_get_domain(dvar->type, dvar->domain).data()); } else diff --git a/src/client/component/rcon.cpp b/src/client/component/rcon.cpp index e1901b3..2c8ea40 100644 --- a/src/client/component/rcon.cpp +++ b/src/client/component/rcon.cpp @@ -16,6 +16,7 @@ namespace rcon { bool is_redirecting_ = false; game::netadr_s redirect_target_ = {}; + std::string redirect_buffer = {}; std::recursive_mutex redirect_lock; void setup_redirect(const game::netadr_s& target) @@ -24,14 +25,18 @@ namespace rcon is_redirecting_ = true; redirect_target_ = target; + redirect_buffer.clear(); } void clear_redirect() { std::lock_guard $(redirect_lock); + network::send(redirect_target_, "print", redirect_buffer, '\n'); + is_redirecting_ = false; redirect_target_ = {}; + redirect_buffer.clear(); } void send_rcon_command(const std::string& password, const std::string& data) @@ -104,7 +109,7 @@ namespace rcon if (is_redirecting_) { - network::send(redirect_target_, "print", message); + redirect_buffer.append(message); return true; } diff --git a/src/client/game/demonware/services/bdDML.cpp b/src/client/game/demonware/services/bdDML.cpp index 75e18ca..ece1aa2 100644 --- a/src/client/game/demonware/services/bdDML.cpp +++ b/src/client/game/demonware/services/bdDML.cpp @@ -12,7 +12,7 @@ namespace demonware { auto result = new bdDMLRawData; result->country_code = "US"; - result->country_code = "'Murica"; + result->country = "United States of America"; result->region = "New York"; result->city = "New York"; result->latitude = 0; diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index d80d00b..211a33d 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -76,14 +76,14 @@ namespace dvars switch (type) { case game::dvar_type::boolean: - return "Domain is 0 or 1"s; + return "Domain is 0 or 1"; case game::dvar_type::value: if (domain.value.min == -FLT_MAX) { if (domain.value.max == FLT_MAX) { - return "Domain is any number"s; + return "Domain is any number"; } else { @@ -114,7 +114,7 @@ namespace dvars { if (domain.integer.max == INT_MAX) { - return "Domain is any integer"s; + return "Domain is any integer"; } else { @@ -131,10 +131,10 @@ namespace dvars } case game::dvar_type::color: - return "Domain is any 4-component color, in RGBA format"s; + return "Domain is any 4-component color, in RGBA format"; case game::dvar_type::enumeration: - str = "Domain is one of the following:"s; + str = "Domain is one of the following:"; for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index) { @@ -144,7 +144,7 @@ namespace dvars return str; case game::dvar_type::string: - return "Domain is any text"s; + return "Domain is any text"; default: return utils::string::va("unhandled dvar type '%i'", type);