diff --git a/src/client/component/gameplay.cpp b/src/client/component/gameplay.cpp new file mode 100644 index 00000000..ffcf30f4 --- /dev/null +++ b/src/client/component/gameplay.cpp @@ -0,0 +1,90 @@ +#include +#include "loader/component_loader.hpp" + +#include "dvars.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include +#include + +namespace gameplay +{ + namespace + { + utils::hook::detour stuck_in_client_hook; + + void stuck_in_client_stub(void* entity) + { + if (dvars::g_playerEjection->current.enabled) + { + stuck_in_client_hook.invoke(entity); + } + } + + void* bg_bounces_stub() + { + return utils::hook::assemble([](utils::hook::assembler& a) + { + const auto no_bounce = a.newLabel(); + const auto loc_70FB6F = a.newLabel(); + + a.push(rax); + + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::bg_bounces))); + a.mov(al, byte_ptr(rax, 0x10)); + a.cmp(ptr(rbp, -0x66), al); + + a.pop(rax); + a.jz(no_bounce); + a.jmp(0x70FBF0_b); + + a.bind(no_bounce); + a.cmp(ptr(rsp, 0x44), r14d); + a.jnz(loc_70FB6F); + a.jmp(0x70FBE1_b); + + a.bind(loc_70FB6F); + a.jmp(0x70FB6F_b); + }); + } + + void* g_gravity_stub() + { + return utils::hook::assemble([](utils::hook::assembler& a) + { + a.mov(rax, qword_ptr(reinterpret_cast(&dvars::g_gravity))); + a.mov(eax, dword_ptr(rax, 0x10)); + a.mov(dword_ptr(rdi, 0x78), eax); + + a.call(0xBB3030_b); + a.mov(ptr(rdi, 0x32C), eax); + + a.jmp(0xAFA342_b); + }); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // Implement bounces + dvars::bg_bounces = game::Dvar_RegisterBool("bg_bounces", false, game::DVAR_FLAG_REPLICATED, "Enables bounces"); + utils::hook::jump(0x70FBB7_b, bg_bounces_stub(), true); + + // Implement gravity dvar + dvars::g_gravity = game::Dvar_RegisterInt("g_gravity", 800, 0, 1000, game::DVAR_FLAG_REPLICATED, "Game gravity in inches per second squared"); + utils::hook::nop(0xAFA330_b, 13); + utils::hook::jump(0xAFA330_b, g_gravity_stub(), true); + + dvars::g_playerEjection = game::Dvar_RegisterBool("g_playerEjection", true, game::DVAR_FLAG_REPLICATED, "Flag whether player ejection is on or off"); + stuck_in_client_hook.create(0xAFD9B0_b, stuck_in_client_stub); + } + }; +} + +REGISTER_COMPONENT(gameplay::component) \ No newline at end of file diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index 1b74ecf1..b4f69635 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -25,6 +25,11 @@ namespace dvars game::dvar_t* r_fullbright = nullptr; + game::dvar_t* bg_bounces = nullptr; + game::dvar_t* g_gravity = nullptr; + + game::dvar_t* g_playerEjection = nullptr; + std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain) { if (domain.vector.min == -FLT_MAX) diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index b7dfd342..adb4344b 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -21,6 +21,11 @@ namespace dvars extern game::dvar_t* r_fullbright; + extern game::dvar_t* bg_bounces; + extern game::dvar_t* g_gravity; + + extern game::dvar_t* g_playerEjection; + std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain); std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain); std::string dvar_get_name(const game::dvar_t* dvar);