From 8f074c26cb314a6ead56dac29b8d44321cbfa87c Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Tue, 31 May 2022 01:06:47 +0200 Subject: [PATCH] CS strafing dvar --- src/client/component/gameplay.cpp | 2 +- src/client/component/movement.cpp | 180 ++++++++++++++++++++++++++++++ src/client/game/structs.hpp | 44 +++++++- src/common/utils/vector.cpp | 59 ++++++++++ src/common/utils/vector.hpp | 12 ++ 5 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 src/client/component/movement.cpp create mode 100644 src/common/utils/vector.cpp create mode 100644 src/common/utils/vector.hpp diff --git a/src/client/component/gameplay.cpp b/src/client/component/gameplay.cpp index 724a5adb..bbc74010 100644 --- a/src/client/component/gameplay.cpp +++ b/src/client/component/gameplay.cpp @@ -133,7 +133,7 @@ namespace gameplay }); } - void pm_player_trace_stub(game::pmove_t* pm, game::trace_t* trace, const float* f3, + void pm_player_trace_stub(game::mp::pmove_t* pm, game::trace_t* trace, const float* f3, const float* f4, const game::Bounds* bounds, int a6, int a7) { pm_player_trace_hook.invoke(pm, trace, f3, f4, bounds, a6, a7); diff --git a/src/client/component/movement.cpp b/src/client/component/movement.cpp new file mode 100644 index 00000000..e1b52750 --- /dev/null +++ b/src/client/component/movement.cpp @@ -0,0 +1,180 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include +#include + +// https://github.com/xoxor4d/iw3xo-dev/blob/develop/src/components/modules/movement.cpp :) + +namespace movement +{ + namespace + { + utils::hook::detour pm_airmove_hook; + + game::dvar_t* pm_cs_airAccelerate; + game::dvar_t* pm_cs_airSpeedCap; + game::dvar_t* pm_cs_strafing; + + void pm_air_accelerate(game::vec3_t wishdir, float wishspeed, game::mp::playerState_s* ps, game::mp::pml_t* pml) + { + float wishspd = wishspeed, accelspeed, currentspeed, addspeed; + + auto accel = pm_cs_airAccelerate->current.value; + auto airspeedcap = pm_cs_airSpeedCap->current.value; + + if (wishspd > airspeedcap) + { + wishspd = airspeedcap; + } + + currentspeed = utils::vector::product(ps->velocity, wishdir); + addspeed = wishspd - currentspeed; + + if (addspeed > 0) + { + accelspeed = pml->frametime * accel * wishspeed * 1.0f; + + if (accelspeed > addspeed) + { + accelspeed = addspeed; + } + + for (auto i = 0; i < 3; i++) + { + ps->velocity[i] += wishdir[i] * accelspeed; + } + } + } + + void pm_clip_velocity(game::vec3_t in, game::vec3_t normal, game::vec3_t out, float overbounce) + { + float backoff, change, angle, adjust; + + angle = normal[2]; + backoff = utils::vector::product(in, normal) * overbounce; + + for (auto i = 0; i < 3; i++) + { + change = normal[i] * backoff; + out[i] = in[i] - change; + } + + adjust = utils::vector::product(out, normal); + + if (adjust < 0) + { + game::vec3_t reduce{}; + + utils::vector::scale(normal, adjust, reduce); + utils::vector::subtract(out, reduce, out); + } + } + + void pm_try_playermove(game::mp::pmove_t* pm, game::mp::pml_t* pml) + { + const auto surf_slope = 0.7f; + const auto ps = pm->ps; + + game::vec3_t end{}; + game::trace_t trace{}; + + if (utils::vector::length(ps->velocity) == 0) + { + return; + } + + utils::vector::ma(ps->origin, pml->frametime, ps->velocity, end); + utils::hook::invoke(0x2D14C0_b, pm, &trace, ps->origin, end, + &pm->bounds, ps->clientNum, pm->tracemask); // PM_playerTrace + + if (trace.fraction == 1) + { + return; + } + + if (trace.normal[2] > surf_slope) + { + return; + } + + pm_clip_velocity(ps->velocity, trace.normal, ps->velocity, 1.0f); + } + + void pm_airmove_stub(game::mp::pmove_t* pm, game::mp::pml_t* pml) + { + if (!pm_cs_strafing->current.enabled) + { + return pm_airmove_hook.invoke(pm, pml); + } + + const auto ps = pm->ps; + + ps->sprintButtonUpRequired = 1; + + float fmove{}, smove{}, wishspeed{}; + game::vec3_t wishvel{}, wishdir{}; + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.rightmove; + + pml->forward[2] = 0.0f; + pml->right[2] = 0.0f; + + utils::vector::normalize(pml->forward); + utils::vector::normalize(pml->right); + + for (auto i = 0; i < 2; i++) + { + wishvel[i] = pml->forward[i] * fmove + pml->right[i] * smove; + } + + wishvel[2] = 0; + + utils::vector::copy(wishvel, wishdir); + wishspeed = utils::vector::normalize(wishdir); + + if (wishspeed != 0 && (wishspeed > 320.0f)) + { + utils::vector::scale(wishvel, 320.0f / wishspeed, wishvel); + wishspeed = 320.0f; + } + + pm_air_accelerate(wishdir, wishspeed, ps, pml); + + utils::hook::invoke(0x2D3380_b, pm, pml, 1, 1); // PM_StepSlideMove + + pm_try_playermove(pm, pml); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_sp()) + { + return; + } + + pm_airmove_hook.create(0x2C93B0_b, pm_airmove_stub); + + pm_cs_airAccelerate = dvars::register_float("pm_cs_airAccelerate", 100.0f, 1.0f, 500.0f, + game::DvarFlags::DVAR_FLAG_REPLICATED, + "Defines player acceleration mid-air"); + + pm_cs_airSpeedCap = dvars::register_float("pm_cs_airSpeedCap", 30.0f, 1.0f, 500.0f, + game::DvarFlags::DVAR_FLAG_REPLICATED, + "Maximum speed mid-air"); + + pm_cs_strafing = dvars::register_bool("pm_cs_strafing", false, + game::DvarFlags::DVAR_FLAG_REPLICATED, + "Enable CS like strafing"); + } + }; +} + +REGISTER_COMPONENT(movement::component) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index c3ef5ed1..bc1d7635 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1442,9 +1442,12 @@ namespace game struct trace_t { - char __pad0[41]; + float fraction; + float normal[3]; + char __pad0[25]; bool allsolid; bool startsolid; + char __pad1[0x2C]; // not correct }; struct Bounds @@ -1453,10 +1456,6 @@ namespace game float halfSize[3]; }; - struct pmove_t - { - }; - // made up struct client_state_t { @@ -1519,6 +1518,14 @@ namespace game static_assert(offsetof(gclient_s, name) == 18834); static_assert(offsetof(gclient_s, flags) == 19488); + struct usercmd_s + { + char __pad0[28]; + char forwardmove; + char rightmove; + char __pad1[34]; + }; + struct EntityState { uint16_t entityNum; @@ -1540,6 +1547,33 @@ namespace game struct playerState_s { + int clientNum; + char __pad0[116]; + vec3_t origin; + vec3_t velocity; + char __pad1[312]; + int sprintButtonUpRequired; + }; + + struct pmove_t + { + playerState_s* ps; + usercmd_s cmd; + usercmd_s oldcmd; + int tracemask; + int numtouch; + int touchents[32]; + Bounds bounds; + }; + + static_assert(offsetof(pmove_t, touchents) == 144); + + struct pml_t + { + float forward[3]; + float right[3]; + float up[3]; + float frametime; }; struct clientHeader_t diff --git a/src/common/utils/vector.cpp b/src/common/utils/vector.cpp new file mode 100644 index 00000000..aa0357ef --- /dev/null +++ b/src/common/utils/vector.cpp @@ -0,0 +1,59 @@ +#include "vector.hpp" +#include + +namespace utils::vector +{ + float normalize(float* v) + { + const auto length = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + + if (length) + { + const auto ilength = 1 / length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + } + + void copy(const float* in, float* out, int size) + { + for (auto i = 0; i < size; i++) + { + out[i] = in[i]; + } + } + + void scale(const float* in, float scale, float* out) + { + out[0] = in[0] * scale; + out[1] = in[1] * scale; + out[2] = in[2] * scale; + } + + void ma(const float* v1, float scale, const float* v2, float* out) + { + out[0] = v1[0] + scale * v2[0]; + out[1] = v1[1] + scale * v2[1]; + out[2] = v1[2] + scale * v2[2]; + } + + void subtract(const float* veca, const float* vecb, float* out) + { + out[0] = veca[0] - vecb[0]; + out[1] = veca[1] - vecb[1]; + out[2] = veca[2] - vecb[2]; + } + + float length(float* v) + { + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + } + + float product(const float* v1, const float* v2) + { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; + } +} diff --git a/src/common/utils/vector.hpp b/src/common/utils/vector.hpp new file mode 100644 index 00000000..6bf74ae1 --- /dev/null +++ b/src/common/utils/vector.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace utils::vector +{ + float normalize(float* v); + void copy(const float* in, float* out, int size = 3); + void scale(const float* in, float scale, float* out); + void ma(const float* v1, float scale, const float* v2, float* out); + void subtract(const float* veca, const float* vecb, float* out); + float length(float* v); + float product(const float* v1, const float* v2); +}