From 0f614c06dea4d154c39b53fc1327a60c79323e42 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Mon, 14 Mar 2022 23:54:41 +0000 Subject: [PATCH] Bounce logic to sp/mp --- src/game/game.cpp | 9 ++++ src/game/game.hpp | 9 ++++ src/game/structs.hpp | 85 +++++++++++++++++++++++++++++++++- src/module/command.cpp | 29 ++++++++++++ src/module/command.hpp | 2 + src/module/player_movement.cpp | 79 ++++++++++++++++++++++++++++--- src/module/player_movement.hpp | 4 ++ 7 files changed, 209 insertions(+), 8 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 34bf66d..0248eaf 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -15,6 +15,8 @@ namespace game Dvar_RegisterBool_t Dvar_RegisterBool; + Dvar_RegisterFloat_t Dvar_RegisterFloat; + Dvar_SetIntByName_t Dvar_SetIntByName; Dvar_SetFromStringByName_t Dvar_SetFromStringByName; @@ -61,6 +63,8 @@ namespace game PM_WeaponUseAmmo_t PM_WeaponUseAmmo; + Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand; + decltype(longjmp)* _longjmp; CmdArgs* sv_cmd_args; @@ -608,6 +612,8 @@ namespace game native::Dvar_RegisterBool = native::Dvar_RegisterBool_t(SELECT_VALUE(0x4914D0, 0x5BE9F0, 0x0)); + native::Dvar_RegisterFloat = native::Dvar_RegisterFloat_t(SELECT_VALUE(0x4F9CC0, 0x5BEA80, 0x0)); + native::Dvar_SetIntByName = native::Dvar_SetIntByName_t(SELECT_VALUE(0x5396B0, 0x5BF560, 0x0)); native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t( @@ -658,6 +664,9 @@ namespace game native::PM_WeaponUseAmmo = native::PM_WeaponUseAmmo_t(SELECT_VALUE(0x463F80, 0x42E930, 0x0)); + native::Cmd_ExecuteSingleCommand = native::Cmd_ExecuteSingleCommand_t( + SELECT_VALUE(0x4D6960, 0x5462B0, 0x4CC360)); + native::_longjmp = reinterpret_cast(SELECT_VALUE(0x73AC20, 0x7363BC, 0x655558)); native::sv_cmd_args = reinterpret_cast(SELECT_VALUE(0x1757218, 0x1CAA998, 0x1B5E7D8)); diff --git a/src/game/game.hpp b/src/game/game.hpp index bd0dbd6..2afcf93 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -27,6 +27,10 @@ namespace game unsigned __int16 flags, const char* description); extern Dvar_RegisterBool_t Dvar_RegisterBool; + typedef const dvar_t* (*Dvar_RegisterFloat_t)(const char* dvarName, float value, + float min, float max, unsigned __int16 flags, const char* description); + extern Dvar_RegisterFloat_t Dvar_RegisterFloat; + typedef void (*Dvar_SetIntByName_t)(const char* dvarName, int value); extern Dvar_SetIntByName_t Dvar_SetIntByName; @@ -96,6 +100,9 @@ namespace game typedef void (*PM_WeaponUseAmmo_t)(playerState_s* ps, const Weapon weapon, bool isAlternate, int amount, PlayerHandIndex hand); extern PM_WeaponUseAmmo_t PM_WeaponUseAmmo; + typedef void (*Cmd_ExecuteSingleCommand_t)(LocalClientNum_t localClientNum, int controllerIndex, const char* text); + extern Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand; + extern decltype(longjmp)* _longjmp; constexpr auto CMD_MAX_NESTING = 8; @@ -120,6 +127,8 @@ namespace game extern int* svs_clientCount; + constexpr auto MAX_GENTITIES = 2048u; + constexpr auto ENTITYNUM_NONE = MAX_GENTITIES - 1u; extern gentity_s* g_entities; namespace mp diff --git a/src/game/structs.hpp b/src/game/structs.hpp index 7e71567..7c96b1a 100644 --- a/src/game/structs.hpp +++ b/src/game/structs.hpp @@ -615,6 +615,53 @@ namespace game float halfSize[3]; }; + enum TraceHitType + { + TRACE_HITTYPE_NONE = 0x0, + TRACE_HITTYPE_ENTITY = 0x1, + TRACE_HITTYPE_DYNENT_MODEL = 0x2, + TRACE_HITTYPE_DYNENT_BRUSH = 0x3, + TRACE_HITTYPE_GLASS = 0x4, + }; + + struct trace_t + { + float fraction; + float normal[3]; + int surfaceFlags; + int contents; + const char* material; + TraceHitType hitType; + unsigned __int16 hitId; + unsigned __int16 modelIndex; + unsigned __int16 partName; + unsigned __int16 partGroup; + bool allsolid; + bool startsolid; + bool walkable; + }; + + static_assert(sizeof(trace_t) == 0x2C); + + struct pml_t + { + float forward[3]; + float right[3]; + float up[3]; + float frametime; + int msec; + int walking; + int groundPlane; + int almostGroundPlane; + trace_t groundTrace; + float impactSpeed; + float previous_origin[3]; + float previous_velocity[3]; + unsigned int holdrand; + }; + + static_assert(sizeof(pml_t) == 0x84); + struct usercmd_s { int serverTime; @@ -662,6 +709,40 @@ namespace game static_assert(sizeof(Weapon) == 4); + enum ViewLockTypes + { + PLAYERVIEWLOCK_NONE = 0x0, + PLAYERVIEWLOCK_FULL = 0x1, + PLAYERVIEWLOCK_WEAPONJITTER = 0x2, + PLAYERVIEWLOCKCOUNT = 0x3, + }; + + enum playerStateFlag + { + PMF_PRONE = 0x1, + PMF_DUCKED = 0x2, + PMF_MANTLE = 0x4, + PMF_LADDER = 0x8, + PMF_SIGHT_AIMING = 0x10, + PMF_BACKWARDS_RUN = 0x20, + PMF_WALKING = 0x40, + PMF_TIME_HARDLANDING = 0x80, + PMF_TIME_KNOCKBACK = 0x100, + PMF_PRONEMOVE_OVERRIDDEN = 0x200, + PMF_RESPAWNED = 0x400, + PMF_FROZEN = 0x800, + PMF_LADDER_FALL = 0x1000, + PMF_JUMPING = 0x2000, + PMF_SPRINTING = 0x4000, + PMF_SHELLSHOCKED = 0x8000, + PMF_MELEE_CHARGE = 0x10000, + PMF_NO_SPRINT = 0x20000, + PMF_NO_JUMP = 0x40000, + PMF_REMOTE_CONTROLLING = 0x80000, + PMF_ANIM_SCRIPTED = 0x100000, + PMF_DIVING = 0x400000, + }; + struct playerState_s { unsigned char __pad0[0x4EC]; @@ -915,8 +996,8 @@ namespace game struct gentity_s { - entityState_s s; - entityShared_t r; + sp::entityState_s s; + sp::entityShared_t r; sp::gclient_s* client; // 0x10C unsigned char __pad0[0x2C]; int flags; diff --git a/src/module/command.cpp b/src/module/command.cpp index 0b1afcc..912a971 100644 --- a/src/module/command.cpp +++ b/src/module/command.cpp @@ -123,6 +123,20 @@ void command::add_sp_sv(const char* name, std::functioncurrent.enabled) + return; + const auto* ent = &game::native::sp::g_entities[0]; if (ent->health < 1) @@ -233,6 +250,9 @@ void command::add_sp_commands() add("ufo", []() { + if (!game::native::Dvar_FindVar("sv_running")->current.enabled) + return; + const auto* ent = &game::native::sp::g_entities[0]; if (ent->health < 1) @@ -248,6 +268,9 @@ void command::add_sp_commands() add("god", []() { + if (!game::native::Dvar_FindVar("sv_running")->current.enabled) + return; + auto* ent = &game::native::sp::g_entities[0]; if (ent->health < 1) @@ -263,6 +286,9 @@ void command::add_sp_commands() add("demigod", []() { + if (!game::native::Dvar_FindVar("sv_running")->current.enabled) + return; + auto* ent = &game::native::sp::g_entities[0]; if (ent->health < 1) @@ -278,6 +304,9 @@ void command::add_sp_commands() add("notarget", []() { + if (!game::native::Dvar_FindVar("sv_running")->current.enabled) + return; + auto* ent = &game::native::sp::g_entities[0]; if (ent->health < 1) diff --git a/src/module/command.hpp b/src/module/command.hpp index 6bbbbfa..6f22252 100644 --- a/src/module/command.hpp +++ b/src/module/command.hpp @@ -51,6 +51,8 @@ public: static void add_sv(const char* name, std::function callback); static void add_sp_sv(const char* name, std::function callback); + static void execute(std::string command, bool sync = false); + void post_load() override; private: diff --git a/src/module/player_movement.cpp b/src/module/player_movement.cpp index 338d264..9e9e26c 100644 --- a/src/module/player_movement.cpp +++ b/src/module/player_movement.cpp @@ -4,12 +4,7 @@ #include "utils/hook.hpp" const game::native::dvar_t* player_movement::player_sustainAmmo; - -void player_movement::post_load() -{ - if (game::is_mp()) this->patch_mp(); - else if (game::is_sp()) this->patch_sp(); -} +const game::native::dvar_t* player_movement::pm_bounces; void player_movement::pm_weapon_use_ammo(game::native::playerState_s* ps, const game::native::Weapon weapon, bool is_alternate, int amount, game::native::PlayerHandIndex hand) @@ -20,6 +15,60 @@ void player_movement::pm_weapon_use_ammo(game::native::playerState_s* ps, const } } +__declspec(naked) void player_movement::pm_step_slide_move_stub_mp() +{ + __asm + { + // Check value of pm_bounces + push eax + mov eax, player_movement::pm_bounces + cmp byte ptr [eax + 0xC], 1 + pop eax + + // Bounce if enabled is true + je bounce + + // Code hook skipped + cmp dword ptr [esp + 0x24], 0 + jnz dontBounce + + bounce: + push 0x424D58 + retn + + dontBounce: + push 0x424D6C + retn + } +} + +__declspec(naked) void player_movement::pm_step_slide_move_stub_sp() +{ + __asm + { + // Check value of pm_bounces + push eax + mov eax, player_movement::pm_bounces + cmp byte ptr [eax + 0xC], 1 + pop eax + + // Bounce if enabled is true + je bounce + + // Code hook skipped + cmp dword ptr [esp + 0x24], 0 + jnz dontBounce + + bounce: + push 0x43D91F + retn + + dontBounce: + push 0x43D933 + retn + } +} + const game::native::dvar_t* player_movement::dvar_register_player_sustain_ammo(const char* dvar_name, bool value, unsigned __int16 /*flags*/, const char* description) { @@ -36,6 +85,8 @@ void player_movement::patch_mp() utils::hook(0x42B5DA, &player_movement::pm_weapon_use_ammo, HOOK_CALL).install()->quick(); utils::hook(0x42B2BD, &player_movement::pm_weapon_use_ammo, HOOK_CALL).install()->quick(); utils::hook(0x42AE95, &player_movement::pm_weapon_use_ammo, HOOK_CALL).install()->quick(); + + utils::hook(0x424D51, &player_movement::pm_step_slide_move_stub_mp, HOOK_JUMP).install()->quick(); } void player_movement::patch_sp() @@ -46,6 +97,22 @@ void player_movement::patch_sp() utils::hook(0x648C3A, &player_movement::pm_weapon_use_ammo, HOOK_CALL).install()->quick(); utils::hook(0x64891D, &player_movement::pm_weapon_use_ammo, HOOK_CALL).install()->quick(); utils::hook(0x6484E2, &player_movement::pm_weapon_use_ammo, HOOK_CALL).install()->quick(); + + utils::hook(0x43D918, &player_movement::pm_step_slide_move_stub_sp, HOOK_JUMP).install()->quick(); +} + +void player_movement::post_load() +{ + if (game::is_dedi()) + { + return; + } + + player_movement::pm_bounces = game::native::Dvar_RegisterBool("pm_bounces", false, + game::native::dvar_flags::DVAR_CODINFO, "CoD4 Bounces"); + + if (game::is_mp()) this->patch_mp(); + else if (game::is_sp()) this->patch_sp(); } REGISTER_MODULE(player_movement); diff --git a/src/module/player_movement.hpp b/src/module/player_movement.hpp index 1066761..e17e853 100644 --- a/src/module/player_movement.hpp +++ b/src/module/player_movement.hpp @@ -9,6 +9,7 @@ public: private: static const game::native::dvar_t* player_sustainAmmo; + static const game::native::dvar_t* pm_bounces; static void pm_weapon_use_ammo(game::native::playerState_s* ps, const game::native::Weapon weapon, bool isAlternate, int amount, game::native::PlayerHandIndex hand); @@ -16,6 +17,9 @@ private: static const game::native::dvar_t* dvar_register_player_sustain_ammo(const char* dvar_name, bool value, unsigned __int16 flags, const char* description); + static void pm_step_slide_move_stub_mp(); + static void pm_step_slide_move_stub_sp(); + static void patch_mp(); static void patch_sp(); };