From 007b7e033bd0ec60ea348cc08c104a812dcc208e Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 1 Apr 2023 14:00:09 +0200 Subject: [PATCH] feat(chat): g_deadChat functionality --- src/client/component/chat.cpp | 34 +++++++++++++++++++++++++++++++++- src/client/game/structs.hpp | 21 ++++++++++++++------- src/client/game/utils.cpp | 7 +++++++ 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/client/component/chat.cpp b/src/client/component/chat.cpp index dd990e20..e9422255 100644 --- a/src/client/component/chat.cpp +++ b/src/client/component/chat.cpp @@ -1,12 +1,13 @@ #include #include "loader/component_loader.hpp" -#include "chat.hpp" + #include "game/game.hpp" #include "game/utils.hpp" #include #include +#include "chat.hpp" #include "command.hpp" #include "client_command.hpp" @@ -14,6 +15,8 @@ namespace chat { namespace { + const game::dvar_t* g_deadChat; + void cmd_say_f(game::gentity_s* ent, const command::params_sv& params) { if (params.size() < 2) @@ -57,6 +60,31 @@ namespace chat { game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE_0, utils::string::va("v \"%Iu %d %d %s\"", -1, 0, 0, text.data())); } + + // This function has probably a different name + void g_say_to_stub(utils::hook::assembler& a) + { + const auto no_dead_chat = a.newLabel(); + + // game's code + a.mov(rax, qword_ptr(rbx)); + + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&g_deadChat))); + a.mov(al, byte_ptr(rax, 0x28)); // dvar_t.current.value.enabled + a.test(al, al); + + a.pop(rax); + + a.je(no_dead_chat); + + a.jmp(0x140299061_g); + + a.bind(no_dead_chat); + a.cmp(dword_ptr(rax, 0x16AE0), 0x0); // game's code + a.jmp(0x14029905B_g); + } } const char* get_client_name(const uint64_t xuid) @@ -76,6 +104,7 @@ namespace chat return "Unknown Soldier"; } + class component final : public generic_component { public: @@ -130,6 +159,9 @@ namespace chat // Kill say fallback utils::hook::set(0x1402FF987_g, 0xEB); + + g_deadChat = game::register_dvar_bool("g_deadChat", false, game::DVAR_NONE, "Allow dead players to chat with living players"); + utils::hook::jump(0x140299051_g, utils::hook::assemble(g_say_to_stub)); } else { diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index cd60213e..be6386f3 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -676,7 +676,8 @@ namespace game struct DvarValue { - union { + union + { bool enabled; int integer; uint32_t unsignedInt; @@ -693,27 +694,33 @@ namespace game union DvarLimits { - struct { + struct + { int stringCount; const char** strings; } enumeration; - struct { + struct + { int min; int max; } integer; - struct { + struct + { int64_t min; int64_t max; } integer64; - struct { + struct + { uint64_t min; uint64_t max; } unsignedInt64; - struct { + struct + { float min; float max; } value; - struct { + struct + { vec_t min; vec_t max; } vector; diff --git a/src/client/game/utils.cpp b/src/client/game/utils.cpp index 532f98d6..b33c08ef 100644 --- a/src/client/game/utils.cpp +++ b/src/client/game/utils.cpp @@ -5,6 +5,13 @@ namespace game { + static_assert(offsetof(dvar_t, debugName) == 8); + static_assert(offsetof(dvar_t, description) == 16); + static_assert(offsetof(dvar_t, flags) == 24); + static_assert(offsetof(dvar_t, type) == 28); + static_assert(offsetof(dvar_t, modified) == 32); + static_assert(offsetof(dvar_t, current) == 40); + std::string get_dvar_string(const char* dvar_name) { const auto* dvar = Dvar_FindVar(dvar_name);