diff --git a/src/client/component/dvar_cheats.cpp b/src/client/component/dvar_cheats.cpp index fba24253..66c49e6c 100644 --- a/src/client/component/dvar_cheats.cpp +++ b/src/client/component/dvar_cheats.cpp @@ -83,92 +83,45 @@ namespace dvar_cheats return true; } - const auto dvar_flag_checks_stub = utils::hook::assemble([](utils::hook::assembler& a) + void* get_dvar_flag_checks_stub() { - const auto can_set_value = a.newLabel(); - const auto zero_source = a.newLabel(); - - a.pushad64(); - a.mov(r8, rdi); - a.mov(edx, esi); - a.mov(rcx, rbx); - a.call_aligned(apply_sv_cheats); //check if we are setting sv_cheats - a.popad64(); - a.cmp(esi, 0); - a.jz(zero_source); //if the SetSource is 0 (INTERNAL) ignore flag checks - - a.pushad64(); - a.mov(edx, esi); //source - a.mov(rcx, rbx); //dvar - a.call_aligned(dvar_flag_checks); //protect read/write/cheat/replicated dvars - a.cmp(al, 1); - a.jz(can_set_value); - - // if we get here, we are non-zero source and CANNOT set values - a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag - a.jmp(0x1404FDCAB); - - // if we get here, we are non-zero source and CAN set values - a.bind(can_set_value); - a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag - a.cmp(esi, 1); - a.jmp(0x1404FDA22); - - // if we get here, we are zero source and ignore flags - a.bind(zero_source); - a.jmp(0x1404FDA62); - }); - - void cg_set_client_dvar_from_server(const int local_client_num, void* cg, const char* dvar_id, const char* value) - { - const auto* dvar = game::Dvar_FindVar(dvar_id); - if (dvar) + return utils::hook::assemble([](utils::hook::assembler& a) { - // If we send as string, it can't be set with source SERVERCMD because the game only allows that source on real server cmd dvars. - // Just use external instead as if it was being set by the console - game::Dvar_SetFromStringByNameFromSource(dvar_id, value, game::DvarSetSource::DVAR_SOURCE_EXTERNAL); - } - else - { - // Not a dvar name, assume it is an id and the game will handle normally - game::CG_SetClientDvarFromServer(local_client_num, cg, dvar_id, value); - } + const auto can_set_value = a.newLabel(); + const auto zero_source = a.newLabel(); + + a.pushad64(); + a.mov(r8, rdi); + a.mov(edx, esi); + a.mov(rcx, rbx); + a.call_aligned(apply_sv_cheats); // check if we are setting sv_cheats + a.popad64(); + a.cmp(esi, 0); + a.jz(zero_source); // if the SetSource is 0 (INTERNAL) ignore flag checks + + a.pushad64(); + a.mov(edx, esi); // source + a.mov(rcx, rbx); // dvar + a.call_aligned(dvar_flag_checks); // protect read/write/cheat/replicated dvars + a.cmp(al, 1); + a.jz(can_set_value); + + // if we get here, we are non-zero source and CANNOT set values + a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag + a.jmp(0x18655C_b); + + // if we get here, we are non-zero source and CAN set values + a.bind(can_set_value); + a.popad64(); // if I do this before the jz it won't work. for some reason the popad64 is affecting the ZR flag + a.cmp(esi, 1); + a.jmp(0x1861EE_b); + + // if we get here, we are zero source and ignore flags + a.bind(zero_source); + a.jmp(0x18628F_b); + }); } - void set_client_dvar_by_string(const int entity_num, const char* value) - { - const auto* dvar = game::Scr_GetString(0); // grab the original dvar again since it's never stored on stack - const auto* command = utils::string::va("q %s \"%s\"", dvar, value); - - game::SV_GameSendServerCommand(entity_num, game::SV_CMD_RELIABLE, command); - } - - const auto player_cmd_set_client_dvar = utils::hook::assemble([](utils::hook::assembler& a) - { - const auto set_by_string = a.newLabel(); - - a.pushad64(); - - // check if we didn't find a network dvar index - a.mov(ecx, dword_ptr(rsp, 0x8C8)); - a.cmp(ecx, 0); - a.je(set_by_string); - - // we found an index, handle normally - a.popad64(); - a.mov(r8d, ptr(rsp, 0x848)); - a.lea(r9, ptr(rsp, 0x30)); - a.jmp(0x1402E2E57); - - // no index, let's send the dvar as a string - a.bind(set_by_string); - a.movzx(ecx, word_ptr(rsp, 0x8C0)); //entity_num - a.lea(rdx, ptr(rsp, 0xB0)); //value - a.call_aligned(set_client_dvar_by_string); - a.popad64(); - a.jmp(0x1402E2E7D); - }); - class component final : public component_interface { public: @@ -179,23 +132,16 @@ namespace dvar_cheats return; } - utils::hook::nop(0x1404FDA0D, 4); // let our stub handle zero-source sets - utils::hook::jump(0x1404FDA14, dvar_flag_checks_stub, true); // check extra dvar flags when setting values - - // utils::hook::nop(0x14032AACC, 5); // remove error in PlayerCmd_SetClientDvar if setting a non-network dvar - // utils::hook::set(0x14032AA9B, 0xEB); - // don't check flags on the dvars, send any existing dvar instead - // utils::hook::jump(0x14032AB14, player_cmd_set_client_dvar, true); // send non-network dvars as string - // utils::hook::call(0x1401BB782, cg_set_client_dvar_from_server); - // check for dvars being sent as string before parsing ids + utils::hook::nop(0x1861D4_b, 8); // let our stub handle zero-source sets + utils::hook::jump(0x1861DF_b, get_dvar_flag_checks_stub(), true); // check extra dvar flags when setting values scheduler::once([]() { dvars::register_bool("sv_cheats", false, game::DvarFlags::DVAR_FLAG_REPLICATED, - "Allow cheat commands and dvars on this server"); + "Allow cheat commands and dvars on this server"); }, scheduler::pipeline::main); } }; } -//REGISTER_COMPONENT(dvar_cheats::component) +REGISTER_COMPONENT(dvar_cheats::component) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index ef5f6802..a99508f6 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -232,8 +232,8 @@ namespace game WEAK symbol gfxDrawMethod{0x0, 0x0}; - WEAK symbol dvarCount{0x0, 0x0}; - WEAK symbol dvarPool{0x0, 0x0}; + WEAK symbol dvarCount{0x0, 0x2999C34}; + WEAK symbol dvarPool{0x0, 0x344DF20}; WEAK symbol DB_XAssetPool{0x0, 0x0}; WEAK symbol g_assetNames{0x0, 0x0};