diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index f297f48a..f9f42354 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -2,38 +2,96 @@ namespace Components { - Game::dvar_t* Elevators::SV_DisableElevators; + Dvar::Var Elevators::BG_Elevators; - __declspec(naked) void Elevators::PM_GroundTraceStub() + int Elevators::PM_CorrectAllSolid(Game::pmove_s* pm, Game::pml_t* pml, Game::trace_t* trace) + { + assert(pm != nullptr); + assert(pm->ps != nullptr); + + Game::vec3_t point; + auto* ps = pm->ps; + + auto i = 0; + const auto elevatorSetting = Elevators::BG_Elevators.get(); + while (true) + { + point[0] = ps->origin[0] + Game::CorrectSolidDeltas[i][0]; + point[1] = ps->origin[1] + Game::CorrectSolidDeltas[i][1]; + point[2] = ps->origin[2] + Game::CorrectSolidDeltas[i][2]; + + Game::PM_playerTrace(pm, trace, point, point, &pm->bounds, ps->clientNum, pm->tracemask); + + // If the player wishes to glitch without effort they can do so + if (!trace->startsolid || elevatorSetting == Elevators::EASY) + { + ps->origin[0] = point[0]; + ps->origin[1] = point[1]; + ps->origin[2] = point[2]; + point[2] = (ps->origin[2] - 1.0f) - 0.25f; + + Game::PM_playerTrace(pm, trace, ps->origin, point, &pm->bounds, ps->clientNum, pm->tracemask); + + // If elevators are disabled we need to check that startsolid is false before proceeding + // like later versions of the game do + if (!trace->startsolid || elevatorSetting >= Elevators::ENABLED) + { + break; + } + } + + i += 1; + if (i >= 26) + { + ps->groundEntityNum = Game::ENTITYNUM_NONE; + pml->groundPlane = 0; + pml->almostGroundPlane = 0; + pml->walking = 0; + Game::Jump_ClearState(ps); + return 0; + } + } + + pml->groundTrace = *trace; + + const auto fraction = trace->fraction; + ps->origin[0] += fraction * (point[0] - ps->origin[0]); + ps->origin[1] += fraction * (point[1] - ps->origin[1]); + ps->origin[2] += fraction * (point[2] - ps->origin[2]); + + return 1; + } + + void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* trace, const float* f3, + const float* f4, const Game::Bounds* bounds, int a6, int a7) + { + Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7); + + // Allow the player to stand even when there is no headroom + if (Elevators::BG_Elevators.get() == Elevators::EASY) + { + trace->allsolid = false; + } + } + + __declspec(naked) void Elevators::PM_CorrectAllSolidStub() { __asm { push eax - mov eax, Elevators::SV_DisableElevators - cmp byte ptr [eax + 16], 1 + pushad + + push [esp + 0x8 + 0x24] + push [esp + 0x8 + 0x24] + push eax + call Elevators::PM_CorrectAllSolid + add esp, 0xC + + mov [esp + 0x20], eax + popad pop eax - // Always skip PM_CorrectAllSolid if SV_DisableElevators is set to 1 - je noElevators - - // Original code - cmp byte ptr [esp + 0x50], 0 - rep movsd - mov esi, [esp + 0x58] - - // Original code flow - push 0x573694 - retn - - noElevators: - - // Original code - rep movsd - mov esi, [esp + 0x58] - - // Jump over call to PM_CorrectAllSolid - push 0x5736AE - retn + ret } } @@ -41,12 +99,23 @@ namespace Components { Dvar::OnInit([] { - Elevators::SV_DisableElevators = Game::Dvar_RegisterBool("sv_disableElevators", - false, Game::DVAR_FLAG_REPLICATED, "Disable elevators"); + static const char* values[] = + { + "off", + "normal", + "easy", + nullptr + }; + + Elevators::BG_Elevators = Game::Dvar_RegisterEnum("bg_elevators", values, + Elevators::ENABLED, Game::DVAR_FLAG_REPLICATED, "Elevators glitch settings"); }); - // Hook PM_GroundTrace so me way skip PM_CorrectAllSolid (disable elevators) - Utils::Hook(0x573689, Elevators::PM_GroundTraceStub, HOOK_JUMP).install()->quick(); + //Replace PM_CorrectAllSolid + Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); + + // Place hook in PM_CheckDuck + Utils::Hook(0x570EC5, Elevators::PM_Trace_Hk, HOOK_CALL).install()->quick(); } Elevators::~Elevators() diff --git a/src/Components/Modules/Elevators.hpp b/src/Components/Modules/Elevators.hpp index 73af502a..02b0b64e 100644 --- a/src/Components/Modules/Elevators.hpp +++ b/src/Components/Modules/Elevators.hpp @@ -9,8 +9,11 @@ namespace Components ~Elevators(); private: - static Game::dvar_t* SV_DisableElevators; + enum ElevatorSettings { DISABLED, ENABLED, EASY }; + static Dvar::Var BG_Elevators; - static void PM_GroundTraceStub(); + static int PM_CorrectAllSolid(Game::pmove_s* move, Game::pml_t* pml, Game::trace_t* trace); + static void PM_CorrectAllSolidStub(); + static void PM_Trace_Hk(Game::pmove_s*, Game::trace_t*, const float*, const float*, const Game::Bounds*, int, int); }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 86d8b5c5..b09916fe 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -377,6 +377,10 @@ namespace Game Field_AdjustScroll_t Field_AdjustScroll = Field_AdjustScroll_t(0x488C10); AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee = AimAssist_ApplyAutoMelee_t(0x56A360); + Jump_ClearState_t Jump_ClearState = Jump_ClearState_t(0x04B3890); + PM_playerTrace_t PM_playerTrace = PM_playerTrace_t(0x458980); + PM_Trace_t PM_Trace = PM_Trace_t(0x441F60); + XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); unsigned int* g_poolSize = reinterpret_cast(0x7995E8); @@ -493,6 +497,8 @@ namespace Game GraphFloat* aaInputGraph = reinterpret_cast(0x7A2FC0); + vec3_t* CorrectSolidDeltas = reinterpret_cast(0x739BB8); // Count 26 + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 7da47215..9e7b7132 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -759,7 +759,7 @@ namespace Game typedef void(__cdecl * SV_Cmd_EndTokenizedString_t)(); extern SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString; - typedef void(__cdecl* SV_Cmd_ArgvBuffer_t)(int arg, char* buf, int size); + typedef void(__cdecl * SV_Cmd_ArgvBuffer_t)(int arg, char* buf, int size); extern SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer; typedef void(__cdecl * SV_SetConfigstring_t)(int index, const char* string); @@ -894,6 +894,15 @@ namespace Game typedef void(__cdecl * AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee; + typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps); + extern Jump_ClearState_t Jump_ClearState; + + typedef void(__cdecl * PM_playerTrace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); + extern PM_playerTrace_t PM_playerTrace; + + typedef void(__cdecl * PM_Trace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); + extern PM_Trace_t PM_Trace; + extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; @@ -944,6 +953,7 @@ namespace Game extern int* serverMessageSequence; constexpr auto MAX_GENTITIES = 2048u; + constexpr auto ENTITYNUM_NONE = MAX_GENTITIES - 1; extern gentity_t* g_entities; extern netadr_t* connectedHost; @@ -1013,6 +1023,8 @@ namespace Game constexpr auto AIM_ASSIST_GRAPH_COUNT = 4u; extern GraphFloat* aaInputGraph; + extern vec3_t* CorrectSolidDeltas; + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); void Menu_FreeItemMemory(Game::itemDef_s* item); void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 8a74e54d..bad13871 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -211,6 +211,31 @@ namespace Game FL_MOVER_SLIDE = 0x8000000 }; + typedef enum + { + HITLOC_NONE, + HITLOC_HELMET, + HITLOC_HEAD, + HITLOC_NECK, + HITLOC_TORSO_UPR, + HITLOC_TORSO_LWR, + HITLOC_R_ARM_UPR, + HITLOC_L_ARM_UPR, + HITLOC_R_ARM_LWR, + HITLOC_L_ARM_LWR, + HITLOC_R_HAND, + HITLOC_L_HAND, + HITLOC_R_LEG_UPR, + HITLOC_L_LEG_UPR, + HITLOC_R_LEG_LWR, + HITLOC_L_LEG_LWR, + HITLOC_R_FOOT, + HITLOC_L_FOOT, + HITLOC_GUN, + HITLOC_SHIELD, + HITLOC_NUM + } hitLocation_t; + struct FxEffectDef; struct pathnode_t; struct pathnode_tree_t; @@ -1132,7 +1157,7 @@ namespace Game int unpredictableEventSequenceOld; int unpredictableEvents[4]; unsigned int unpredictableEventParms[4]; - int clientNum; + int clientNum; // 260 int viewmodelIndex; float viewangles[3]; int viewHeightTarget; @@ -5348,21 +5373,42 @@ namespace Game PLAYER_FLAG_FROZEN = 1 << 2, }; + typedef enum + { + SESS_STATE_PLAYING = 0x0, + SESS_STATE_DEAD = 0x1, + SESS_STATE_SPECTATOR = 0x2, + SESS_STATE_INTERMISSION = 0x3 + } sessionState_t; + + typedef enum + { + CON_DISCONNECTED = 0x0, + CON_CONNECTING = 0x1, + CON_CONNECTED = 0x2 + } clientConnected_t; + typedef struct gclient_s { - unsigned char pad[12764]; - unsigned int team; + playerState_s ps; + sessionState_t sessionState; // 12572 + char pad0[40]; + clientConnected_t connected; // 12616 + char pad1[144]; + unsigned int team; // 12764 char pad2[436]; - int flags; + int flags; // 13204 int spectatorClient; int lastCmdTime; int buttons; - int oldbuttons; - int latched_buttons; - int buttonsSinceLastFrame; - char pad3[700]; + int oldbuttons; // 13220 + int latched_buttons; // 13224 + int buttonsSinceLastFrame; // 13228 + char pad3[700]; // 13232 } gclient_t; + static_assert(sizeof(gclient_t) == 13932); + struct EntHandle { unsigned __int16 number; @@ -6930,15 +6976,43 @@ namespace Game const char* args[9]; }; + enum TraceHitType + { + TRACE_HITTYPE_NONE = 0, + TRACE_HITTYPE_ENTITY = 1, + TRACE_HITTYPE_DYNENT_MODEL = 2, + TRACE_HITTYPE_DYNENT_BRUSH = 3, + TRACE_HITTYPE_GLASS = 4 + }; + + 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 pmove_s { playerState_s* ps; usercmd_s cmd; usercmd_s oldcmd; - int tracemask; + int tracemask; // 84 int numtouch; int touchents[32]; - char __pad0[24]; + Bounds bounds; // 220 float xyspeed; int proneChange; float maxSprintTimeMultiplier; @@ -6952,6 +7026,27 @@ namespace Game unsigned char handler; }; + static_assert(sizeof(pmove_s) == 296); + + 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]; + int holdrand; + }; + + static_assert(sizeof(pml_t) == 0x84); + enum EffectiveStance { PM_EFF_STANCE_DEFAULT = 0,