From 39c14fd77527d0df18eb5ffd960b86608324f487 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 00:49:45 -0600 Subject: [PATCH 01/83] [Modules] Added XInput stub module --- src/Components/Loader.cpp | 1 + src/Components/Loader.hpp | 3 ++- src/Components/Modules/XInput.cpp | 8 ++++++++ src/Components/Modules/XInput.hpp | 13 +++++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/Components/Modules/XInput.cpp create mode 100644 src/Components/Modules/XInput.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 30819a9f..a6c525f2 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -103,6 +103,7 @@ namespace Components Loader::Register(new StartupMessages()); Loader::Register(new Client()); + Loader::Register(new XInput()); Loader::Pregame = false; } diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 589f256a..82483cd0 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -131,4 +131,5 @@ namespace Components #include "Modules/StartupMessages.hpp" #include "Modules/Stats.hpp" -#include "Modules/Client.hpp" \ No newline at end of file +#include "Modules/XInput.hpp" +#include "Modules/Client.hpp" diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp new file mode 100644 index 00000000..cda6af1d --- /dev/null +++ b/src/Components/Modules/XInput.cpp @@ -0,0 +1,8 @@ +#include "STDInclude.hpp" + +namespace Components +{ + XInput::XInput() + { + } +} diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp new file mode 100644 index 00000000..5263d6b2 --- /dev/null +++ b/src/Components/Modules/XInput.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace Components +{ + class XInput : public Component + { + public: + XInput(); + + private: + + }; +} From 01dc00bd7f210327953c83c7436cf13049bc1ede Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 01:17:37 -0600 Subject: [PATCH 02/83] [XInput] Polling for input --- src/Components/Modules/XInput.cpp | 36 +++++++++++++++++++++++++++++++ src/Components/Modules/XInput.hpp | 8 ++++++- src/STDInclude.hpp | 3 +++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index cda6af1d..4feb3520 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -2,7 +2,43 @@ namespace Components { + XINPUT_STATE XInput::xiStates[XUSER_MAX_COUNT]; + + void XInput::PollXInputDevices() + { + for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) + { + XInputGetState(i, &xiStates[i]); + } + } + + __declspec(naked) void XInput::CL_FrameStub() + { + __asm + { + // poll the xinput devices on every client frame + pusha + pushad + + call XInput::PollXInputDevices + + popad + popa + + // execute the code we patched over + sub esp, 0Ch + push ebx + push ebp + push esi + + // return back to original code + push 0x486976 + retn + } + } + XInput::XInput() { + Utils::Hook(0x486970, XInput::CL_FrameStub, HOOK_JUMP).install()->quick(); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 5263d6b2..21670867 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -8,6 +8,12 @@ namespace Components XInput(); private: - + static XINPUT_STATE xiStates[XUSER_MAX_COUNT]; + + static void CL_FrameStub(); + static void PollXInputDevices(); + + static void CL_CreateCmdStub(); + static void CL_GamepadMove(int, Game::usercmd_s*); }; } diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 872e40c3..d6574ed3 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -48,6 +48,9 @@ #include #pragma comment(lib, "D3dx9.lib") +#include +#pragma comment (lib, "xinput.lib") + // Usefull for debugging template class Sizer { }; #define BindNum(x, y) Sizer y; From a737dd16e428efd55dcc41945e6f982c910d4b82 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 13:42:52 -0600 Subject: [PATCH 03/83] [XInput] Got lJoystick working --- src/Components/Modules/Script.cpp | 2 -- src/Components/Modules/XInput.cpp | 48 +++++++++++++++++++++++++------ src/Components/Modules/XInput.hpp | 1 + 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 51f0e394..3cd8f3d3 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -352,11 +352,9 @@ namespace Components { // execute our hook pushad - pusha call Script::StoreScriptBaseProgramNum - popa popad // execute overwritten code caused by the jump hook diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 4feb3520..9b31b0bf 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -3,12 +3,16 @@ namespace Components { XINPUT_STATE XInput::xiStates[XUSER_MAX_COUNT]; + int XInput::xiPlayerNum = -1; void XInput::PollXInputDevices() { - for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) + XInput::xiPlayerNum = -1; + + for (int i = XUSER_MAX_COUNT; i >= 0; i--) { - XInputGetState(i, &xiStates[i]); + if (XInputGetState(i, &xiStates[i]) == ERROR_SUCCESS) + XInput::xiPlayerNum = i; } } @@ -17,14 +21,8 @@ namespace Components __asm { // poll the xinput devices on every client frame - pusha - pushad - call XInput::PollXInputDevices - popad - popa - // execute the code we patched over sub esp, 0Ch push ebx @@ -37,8 +35,42 @@ namespace Components } } + void XInput::CL_GamepadMove(int localClientNum, Game::usercmd_s* cmd) + { + if (XInput::xiPlayerNum != -1) + { + XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; + + cmd->rightmove = xiState->Gamepad.sThumbLX / 256; + cmd->forwardmove = xiState->Gamepad.sThumbLY / 256; + } + } + + __declspec(naked) void XInput::CL_CreateCmdStub() + { + __asm + { + // do xinput! + push esi + push ebp + call XInput::CL_GamepadMove + add esp, 8h + + // execute code we patched over + add esp, 4 + fld st + pop ebx + + // return back + push 0x5A6DBF + retn + } + } + XInput::XInput() { Utils::Hook(0x486970, XInput::CL_FrameStub, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x5A6DB9, XInput::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 21670867..b2c1ab1e 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -9,6 +9,7 @@ namespace Components private: static XINPUT_STATE xiStates[XUSER_MAX_COUNT]; + static int xiPlayerNum; static void CL_FrameStub(); static void PollXInputDevices(); From d123ade36f23008223fd47ba48aaecda520c1b71 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 16:48:48 -0600 Subject: [PATCH 04/83] [XInput] Added sending movement components --- src/Components/Modules/XInput.cpp | 44 ++++++++++++++++++++++++++++--- src/Components/Modules/XInput.hpp | 6 ++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 9b31b0bf..c2f8f261 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -35,14 +35,14 @@ namespace Components } } - void XInput::CL_GamepadMove(int localClientNum, Game::usercmd_s* cmd) + void XInput::CL_GamepadMove(int, Game::usercmd_s* cmd) { if (XInput::xiPlayerNum != -1) { XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - cmd->rightmove = xiState->Gamepad.sThumbLX / 256; - cmd->forwardmove = xiState->Gamepad.sThumbLY / 256; + cmd->rightmove = static_cast(xiState->Gamepad.sThumbLX / 256); + cmd->forwardmove = static_cast(xiState->Gamepad.sThumbLY / 256); } } @@ -67,10 +67,48 @@ namespace Components } } + __declspec(naked) void XInput::MSG_WriteDeltaUsercmdKeyStub() + { + __asm + { + // fix stack pointer + add esp, 0Ch + + // put both forward move and rightmove values in the movement button + mov dl, byte ptr [edi+1Ah] // to_forwardMove + mov dh, byte ptr [edi+1Bh] // to_rightMove + + mov [esp+30h], dx // to_buttons + + mov dl, byte ptr [ebp+1Ah] // from_forwardMove + mov dh, byte ptr [ebp+1Bh] // from_rightMove + + mov [esp+2Ch], dx // from_buttons + + // return back + push 0x60E40E + retn + } + } + + __declspec(naked) void XInput::MSG_ReadDeltaUsercmdKeyStub() + { + + } + XInput::XInput() { Utils::Hook(0x486970, XInput::CL_FrameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x5A6DB9, XInput::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); + + // package the forward and right move components in the move buttons + Utils::Hook(0x60E38D, XInput::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + + // send two bytes instead of one for sending movement data + Utils::Hook::Set(0x60E501, 8); + Utils::Hook::Set(0x60E5CD, 8); + + //Utils::Hook(0x5A6DB9, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index b2c1ab1e..0a808b77 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -16,5 +16,9 @@ namespace Components static void CL_CreateCmdStub(); static void CL_GamepadMove(int, Game::usercmd_s*); - }; + + static void MSG_WriteDeltaUsercmdKeyStub(); + + static void MSG_ReadDeltaUsercmdKeyStub(); + } } From ef76acd8b40a98b2270d6074a2fb985f5f277867 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 17:37:46 -0600 Subject: [PATCH 05/83] [XInput] Stubbed user movement apply, make sure reading 8 bits for movement data --- src/Components/Modules/XInput.cpp | 27 ++++++++++++++++++++++++++- src/Components/Modules/XInput.hpp | 3 ++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index c2f8f261..c4dc50b8 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -93,13 +93,32 @@ namespace Components __declspec(naked) void XInput::MSG_ReadDeltaUsercmdKeyStub() { + __asm + { + // return back + push 0x4921BF + ret + } + } + __declspec(naked) void XInput::MSG_ReadDeltaUsercmdKeyStub2() + { + __asm + { + // return back + push 3 + push esi + push 0x492085 + ret + } } XInput::XInput() { + // poll xinput devices every client frame Utils::Hook(0x486970, XInput::CL_FrameStub, HOOK_JUMP).install()->quick(); + // use the xinput state when creating a usercmd Utils::Hook(0x5A6DB9, XInput::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); // package the forward and right move components in the move buttons @@ -109,6 +128,12 @@ namespace Components Utils::Hook::Set(0x60E501, 8); Utils::Hook::Set(0x60E5CD, 8); - //Utils::Hook(0x5A6DB9, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + // make sure to parse the movement data properally and apply it + Utils::Hook(0x492191, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492061, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + + // read two bytes instead of one for receiveing movement data + Utils::Hook::Set(0x492049, 8); + Utils::Hook::Set(0x492177, 8); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 0a808b77..7a1b328a 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -20,5 +20,6 @@ namespace Components static void MSG_WriteDeltaUsercmdKeyStub(); static void MSG_ReadDeltaUsercmdKeyStub(); - } + static void MSG_ReadDeltaUsercmdKeyStub2(); + }; } From 16c6d11916a3b1b72d55e97d1b6ff63c0d8b0f11 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 19:06:40 -0600 Subject: [PATCH 06/83] [XInput] Completed analog movement on server side --- src/Components/Modules/XInput.cpp | 50 +++++++++++++++++++++++++------ src/Components/Modules/XInput.hpp | 2 ++ src/Game/Functions.cpp | 2 ++ src/Game/Functions.hpp | 6 ++++ 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index c4dc50b8..88c27075 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -91,10 +91,39 @@ namespace Components } } + void XInput::ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to) + { + char forward; + char right; + + if (Game::MSG_ReadBit(msg)) + { + short movementBits = static_cast(key ^ Game::MSG_ReadBits(msg, 16)); + + forward = static_cast(movementBits); + right = static_cast(movementBits >> 8); + } + else + { + forward = from->forwardmove; + right = from->rightmove; + } + + to->forwardmove = forward; + to->rightmove = right; + } + __declspec(naked) void XInput::MSG_ReadDeltaUsercmdKeyStub() { __asm { + push ebx // to + push ebp // from + push edi // key + push esi // msg + call XInput::ApplyMovement + add esp, 10h + // return back push 0x4921BF ret @@ -105,6 +134,13 @@ namespace Components { __asm { + push ebx // to + push ebp // from + push edi // key + push esi // msg + call XInput::ApplyMovement + add esp, 10h + // return back push 3 push esi @@ -124,16 +160,12 @@ namespace Components // package the forward and right move components in the move buttons Utils::Hook(0x60E38D, XInput::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); - // send two bytes instead of one for sending movement data - Utils::Hook::Set(0x60E501, 8); - Utils::Hook::Set(0x60E5CD, 8); + // send two bytes for sending movement data + Utils::Hook::Set(0x60E501, 16); + Utils::Hook::Set(0x60E5CD, 16); // make sure to parse the movement data properally and apply it - Utils::Hook(0x492191, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); - Utils::Hook(0x492061, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); - - // read two bytes instead of one for receiveing movement data - Utils::Hook::Set(0x492049, 8); - Utils::Hook::Set(0x492177, 8); + Utils::Hook(0x492127, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492009, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 7a1b328a..6d92a134 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -19,6 +19,8 @@ namespace Components static void MSG_WriteDeltaUsercmdKeyStub(); + static void ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to); + static void MSG_ReadDeltaUsercmdKeyStub(); static void MSG_ReadDeltaUsercmdKeyStub2(); }; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 63e01a18..ab9b913f 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -176,6 +176,8 @@ namespace Game Menus_MenuIsInStack_t Menus_MenuIsInStack = Menus_MenuIsInStack_t(0x47ACB0); MSG_Init_t MSG_Init = MSG_Init_t(0x45FCA0); + MSG_ReadBit_t MSG_ReadBit = MSG_ReadBit_t(0x476D20); + MSG_ReadBits_t MSG_ReadBits = MSG_ReadBits_t(0x4C3900); MSG_ReadData_t MSG_ReadData = MSG_ReadData_t(0x4527C0); MSG_ReadLong_t MSG_ReadLong = MSG_ReadLong_t(0x4C9550); MSG_ReadShort_t MSG_ReadShort = MSG_ReadShort_t(0x40BDD0); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 8b125c82..789a4b46 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -420,6 +420,12 @@ namespace Game typedef int(__cdecl * MSG_ReadLong_t)(msg_t* msg); extern MSG_ReadLong_t MSG_ReadLong; + typedef int(__cdecl * MSG_ReadBit_t)(msg_t* msg); + extern MSG_ReadBit_t MSG_ReadBit; + + typedef int(__cdecl * MSG_ReadBits_t)(msg_t* msg, int bits); + extern MSG_ReadBits_t MSG_ReadBits; + typedef short(__cdecl * MSG_ReadShort_t)(msg_t* msg); extern MSG_ReadShort_t MSG_ReadShort; From 75d6be1939ea7711947c21139b439676a5fcbd48 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sat, 2 Jan 2021 19:09:19 -0600 Subject: [PATCH 07/83] Increased protocol --- src/Game/Structs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 6636d28d..37a6d3c2 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1,6 +1,6 @@ #pragma once -#define PROTOCOL 0x95 +#define PROTOCOL 0x96 #define NUM_CUSTOM_CLASSES 15 #define SEMANTIC_WATER_MAP 11 #define FX_ELEM_FIELD_COUNT 90 From 198a39c3db15000d377ef8dc7919945b32e561f7 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sun, 3 Jan 2021 00:32:58 -0600 Subject: [PATCH 08/83] [XInput] RJoyStick working, need to do vanilla acceleration and sensitivity --- src/Components/Modules/XInput.cpp | 3 +++ src/Game/Functions.cpp | 2 ++ src/Game/Functions.hpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 88c27075..e4fa8d41 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -43,6 +43,9 @@ namespace Components cmd->rightmove = static_cast(xiState->Gamepad.sThumbLX / 256); cmd->forwardmove = static_cast(xiState->Gamepad.sThumbLY / 256); + + Game::cl_angles[0] -= (xiState->Gamepad.sThumbRY / 32767.0f); + Game::cl_angles[1] -= (xiState->Gamepad.sThumbRX / 32767.0f); } } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index ab9b913f..be59b06f 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -349,6 +349,8 @@ namespace Game source_t **sourceFiles = reinterpret_cast(0x7C4A98); keywordHash_t **menuParseKeywordHash = reinterpret_cast(0x63AE928); + float* cl_angles = reinterpret_cast(0xB2F8D0); + int* svs_time = reinterpret_cast(0x31D9384); int* svs_numclients = reinterpret_cast(0x31D938C); client_t* svs_clients = reinterpret_cast(0x31D9390); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 789a4b46..4d06c0bb 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -790,6 +790,8 @@ namespace Game extern cmd_function_t** cmd_functions; + extern float* cl_angles; + extern int* svs_time; extern int* svs_numclients; extern client_t* svs_clients; From 2038ba5e8bcc14ae29806e2f5d480b147fd16d3c Mon Sep 17 00:00:00 2001 From: INeedBots Date: Sun, 3 Jan 2021 02:33:12 -0600 Subject: [PATCH 09/83] [XInput] Added buttons --- src/Components/Modules/XInput.cpp | 146 +++++++++++++++++++++++++++++- src/Components/Modules/XInput.hpp | 1 + src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 3 + 4 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index e4fa8d41..a86c0db4 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -3,13 +3,14 @@ namespace Components { XINPUT_STATE XInput::xiStates[XUSER_MAX_COUNT]; + XINPUT_STATE XInput::lastxiState = { 0 }; int XInput::xiPlayerNum = -1; void XInput::PollXInputDevices() { XInput::xiPlayerNum = -1; - for (int i = XUSER_MAX_COUNT; i >= 0; i--) + for (int i = XUSER_MAX_COUNT - 1; i >= 0; i--) { if (XInputGetState(i, &xiStates[i]) == ERROR_SUCCESS) XInput::xiPlayerNum = i; @@ -46,6 +47,149 @@ namespace Components Game::cl_angles[0] -= (xiState->Gamepad.sThumbRY / 32767.0f); Game::cl_angles[1] -= (xiState->Gamepad.sThumbRX / 32767.0f); + + bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger / 255.f > 0.5; + if (pressingLeftTrigger != XInput::lastxiState.Gamepad.bLeftTrigger / 255.f > 0.5) + { + if (pressingLeftTrigger) + Command::Execute("+speed"); + else + Command::Execute("-speed"); + } + + bool pressingRightTrigger = xiState->Gamepad.bRightTrigger / 255.f > 0.5; + if (pressingRightTrigger != XInput::lastxiState.Gamepad.bRightTrigger / 255.f > 0.5) + { + if (pressingRightTrigger) + Command::Execute("+attack"); + else + Command::Execute("-attack"); + } + + bool pressingWeapChange = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0; + if (pressingWeapChange != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0)) + { + if (pressingWeapChange) + Command::Execute("weapnext"); + } + + bool pressingReload = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0; + if (pressingReload != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0)) + { + if (pressingReload) + Command::Execute("+usereload"); + else + Command::Execute("-usereload"); + } + + bool pressingJump = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0; + if (pressingJump != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0)) + { + if (pressingJump) + Command::Execute("+gostand"); + else + Command::Execute("-gostand"); + } + + bool pressingKnife = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; + if (pressingKnife != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0)) + { + if (pressingKnife) + Command::Execute("+melee"); + else + Command::Execute("-melee"); + } + + bool pressingSprint = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0; + if (pressingSprint != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0)) + { + if (pressingSprint) + Command::Execute("+breath_sprint"); + else + Command::Execute("-breath_sprint"); + } + + bool pressingStance = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0; + if (pressingStance != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0)) + { + if (pressingStance) + Command::Execute("+stance"); + else + Command::Execute("-stance"); + } + + bool pressingSmoke = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0; + if (pressingSmoke != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0)) + { + if (pressingSmoke) + Command::Execute("+smoke"); + else + Command::Execute("-smoke"); + } + + bool pressingFrag = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0; + if (pressingFrag != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0)) + { + if (pressingFrag) + Command::Execute("+frag"); + else + Command::Execute("-frag"); + } + + bool pressingScore = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0; + if (pressingScore != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0)) + { + if (pressingScore) + Command::Execute("+scores"); + else + Command::Execute("-scores"); + } + + bool pressingAlt = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0; + if (pressingAlt != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0)) + { + if (pressingAlt) + Command::Execute("+actionslot 2"); + else + Command::Execute("-actionslot 2"); + } + + bool pressingKillstreak = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0; + if (pressingKillstreak != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0)) + { + if (pressingKillstreak) + Command::Execute("+actionslot 3"); + else + Command::Execute("-actionslot 3"); + } + + bool pressingNight = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0; + if (pressingNight != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0)) + { + if (pressingNight) + Command::Execute("+actionslot 4"); + else + Command::Execute("-actionslot 4"); + } + + bool pressingUp = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0; + if (pressingUp != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0)) + { + if (pressingUp) + Command::Execute("+actionslot 1"); + else + Command::Execute("-actionslot 1"); + } + + bool pressingStart = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0; + if (pressingStart != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0)) + { + if (pressingStart) + Command::Execute("togglemenu"); + } + + + memcpy(&XInput::lastxiState, xiState, sizeof XINPUT_STATE); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 6d92a134..6fe7b1ed 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -10,6 +10,7 @@ namespace Components private: static XINPUT_STATE xiStates[XUSER_MAX_COUNT]; static int xiPlayerNum; + static XINPUT_STATE lastxiState; static void CL_FrameStub(); static void PollXInputDevices(); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index be59b06f..6b2e44b2 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -34,6 +34,7 @@ namespace Game Cbuf_AddServerText_t Cbuf_AddServerText = Cbuf_AddServerText_t(0x4BB9B0); Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20); + CG_NextWeapon_f_t CG_NextWeapon_f = CG_NextWeapon_f_t(0x449DE0); CG_GetClientNum_t CG_GetClientNum = CG_GetClientNum_t(0x433700); CG_PlayBoltedEffect_t CG_PlayBoltedEffect = CG_PlayBoltedEffect_t(0x00430E10); CG_GetBoneIndex_t CG_GetBoneIndex = CG_GetBoneIndex_t(0x00504F20); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 4d06c0bb..65efc997 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -49,6 +49,9 @@ namespace Game typedef int(__cdecl * CG_GetClientNum_t)(); extern CG_GetClientNum_t CG_GetClientNum; + typedef void(__cdecl * CG_NextWeapon_f_t)(); + extern CG_NextWeapon_f_t CG_NextWeapon_f; + typedef std::int32_t(__cdecl* CG_PlayBoltedEffect_t) (std::int32_t, FxEffectDef*, std::int32_t, std::uint32_t); extern CG_PlayBoltedEffect_t CG_PlayBoltedEffect; From 38bb745d177cbba910d65848d85b22eb6b738d33 Mon Sep 17 00:00:00 2001 From: INeedBots Date: Mon, 4 Jan 2021 01:16:31 -0600 Subject: [PATCH 10/83] [Functions] Added cgameFOVSensitivityScale --- src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 6b2e44b2..b5fdfd03 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -351,6 +351,7 @@ namespace Game keywordHash_t **menuParseKeywordHash = reinterpret_cast(0x63AE928); float* cl_angles = reinterpret_cast(0xB2F8D0); + float* cgameFOVSensitivityScale = reinterpret_cast(0xB2F884); int* svs_time = reinterpret_cast(0x31D9384); int* svs_numclients = reinterpret_cast(0x31D938C); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 65efc997..2cee14e3 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -794,6 +794,7 @@ namespace Game extern cmd_function_t** cmd_functions; extern float* cl_angles; + extern float* cgameFOVSensitivityScale; extern int* svs_time; extern int* svs_numclients; From 784c4c8372a35ed986d69a367e7978437f8cf1b2 Mon Sep 17 00:00:00 2001 From: rackover Date: Sun, 2 May 2021 13:13:13 +0200 Subject: [PATCH 11/83] Bit of cleanup + horizontal gamepad view acceleration --- src/Components/Modules/XInput.cpp | 259 +++++++++++++++--------------- src/Components/Modules/XInput.hpp | 27 +++- 2 files changed, 155 insertions(+), 131 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index a86c0db4..f317d7b7 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -3,8 +3,51 @@ namespace Components { XINPUT_STATE XInput::xiStates[XUSER_MAX_COUNT]; - XINPUT_STATE XInput::lastxiState = { 0 }; + XINPUT_STATE XInput::lastXiState = { 0 }; int XInput::xiPlayerNum = -1; + std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) + bool XInput::isHoldingMaxLookX = false; + + float XInput::lockedSensitivityMultiplier = 0.6f; + float XInput::unlockedSensitivityMultiplier = 1.2f; + float XInput::generalSensitivityMultiplier = 1.3f; + + std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 250ms; + + std::vector mappings = { + XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), + //XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance", true, true), + XInput::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), + XInput::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), + XInput::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), + XInput::ActionMapping(XINPUT_GAMEPAD_RIGHT_SHOULDER, "frag"), + XInput::ActionMapping(XINPUT_GAMEPAD_LEFT_THUMB, "breath_sprint"), + XInput::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), + XInput::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), + XInput::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 3"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 2"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 1"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 4"), + }; + + + void XInput::Vibrate(int leftVal, int rightVal) + { + // Create a Vibraton State + XINPUT_VIBRATION Vibration; + + // Zeroise the Vibration + ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); + + // Set the Vibration Values + Vibration.wLeftMotorSpeed = leftVal; + Vibration.wRightMotorSpeed = rightVal; + + // Vibrate the controller + XInputSetState(xiPlayerNum, &Vibration); + } + void XInput::PollXInputDevices() { @@ -42,14 +85,48 @@ namespace Components { XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - cmd->rightmove = static_cast(xiState->Gamepad.sThumbLX / 256); - cmd->forwardmove = static_cast(xiState->Gamepad.sThumbLY / 256); + // Deadzones + float moveStickX = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLX / (float)std::numeric_limits().max() : .0f; + float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits().max() : .0f; - Game::cl_angles[0] -= (xiState->Gamepad.sThumbRY / 32767.0f); - Game::cl_angles[1] -= (xiState->Gamepad.sThumbRX / 32767.0f); + float viewStickX = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRX / (float)std::numeric_limits().max() : .0f; + float viewStickY = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRY / (float)std::numeric_limits().max() : .0f; - bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger / 255.f > 0.5; - if (pressingLeftTrigger != XInput::lastxiState.Gamepad.bLeftTrigger / 255.f > 0.5) + cmd->rightmove = moveStickX * std::numeric_limits().max(); + cmd->forwardmove = moveStickY * std::numeric_limits().max(); + + // Gamepad horizontal acceleration on view + if (abs(viewStickX) > 0.9f) { + if (!XInput::isHoldingMaxLookX) { + XInput::isHoldingMaxLookX = true; + XInput::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + } + else { + std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - XInput::timeAtFirstHeldMaxLookX; +#ifdef STEP_SENSITIVITY + if (hasBeenHoldingLeftXForMs < XInput::msBeforeUnlockingSensitivity) { + viewStickX *= XInput::lockedSensitivityMultiplier; + } + else { + viewStickX *= XInput::unlockedSensitivityMultiplier; + } +#else + float coeff = std::clamp(hasBeenHoldingLeftXForMs.count()/(float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); + viewStickX *= std::lerp(XInput::lockedSensitivityMultiplier, XInput::unlockedSensitivityMultiplier, coeff); +#endif + } + } + else{ + XInput::isHoldingMaxLookX = false; + XInput::timeAtFirstHeldMaxLookX = 0ms; + } + + + Game::cl_angles[0] -= viewStickY; + Game::cl_angles[1] -= viewStickX * generalSensitivityMultiplier; + + bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; + if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { if (pressingLeftTrigger) Command::Execute("+speed"); @@ -57,8 +134,8 @@ namespace Components Command::Execute("-speed"); } - bool pressingRightTrigger = xiState->Gamepad.bRightTrigger / 255.f > 0.5; - if (pressingRightTrigger != XInput::lastxiState.Gamepad.bRightTrigger / 255.f > 0.5) + bool pressingRightTrigger = xiState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; + if (pressingRightTrigger != XInput::lastXiState.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { if (pressingRightTrigger) Command::Execute("+attack"); @@ -66,51 +143,43 @@ namespace Components Command::Execute("-attack"); } - bool pressingWeapChange = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0; - if (pressingWeapChange != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0)) + // Buttons (on/off) mappings + for (size_t i = 0; i < mappings.size(); i++) { - if (pressingWeapChange) - Command::Execute("weapnext"); + auto mapping = mappings[i]; + auto action = mapping.action; + auto antiAction = mapping.action; + + if (mapping.isReversible) { + action = "+" + mapping.action; + antiAction = "-" + mapping.action; + } + else if (mapping.wasPressed) { + if (xiState->Gamepad.wButtons & mapping.input) { + // Button still pressed, do not send info + if (mapping.spamWhenHeld) { + Command::Execute(action.c_str()); + } + } + else { + mappings[i].wasPressed = false; + } + + continue; + } + + if (xiState->Gamepad.wButtons & mapping.input) { + Command::Execute(action.c_str()); + mappings[i].wasPressed = true; + } + else if (mapping.isReversible && mapping.wasPressed) { + mappings[i].wasPressed = false; + Command::Execute(antiAction.c_str()); + } } - bool pressingReload = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0; - if (pressingReload != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0)) - { - if (pressingReload) - Command::Execute("+usereload"); - else - Command::Execute("-usereload"); - } - - bool pressingJump = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0; - if (pressingJump != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0)) - { - if (pressingJump) - Command::Execute("+gostand"); - else - Command::Execute("-gostand"); - } - - bool pressingKnife = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; - if (pressingKnife != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0)) - { - if (pressingKnife) - Command::Execute("+melee"); - else - Command::Execute("-melee"); - } - - bool pressingSprint = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0; - if (pressingSprint != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0)) - { - if (pressingSprint) - Command::Execute("+breath_sprint"); - else - Command::Execute("-breath_sprint"); - } - - bool pressingStance = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0; - if (pressingStance != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0)) + bool pressingStance = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; + if (pressingStance != ((XInput::lastXiState.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0)) { if (pressingStance) Command::Execute("+stance"); @@ -118,78 +187,8 @@ namespace Components Command::Execute("-stance"); } - bool pressingSmoke = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0; - if (pressingSmoke != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0)) - { - if (pressingSmoke) - Command::Execute("+smoke"); - else - Command::Execute("-smoke"); - } - bool pressingFrag = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0; - if (pressingFrag != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0)) - { - if (pressingFrag) - Command::Execute("+frag"); - else - Command::Execute("-frag"); - } - - bool pressingScore = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0; - if (pressingScore != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0)) - { - if (pressingScore) - Command::Execute("+scores"); - else - Command::Execute("-scores"); - } - - bool pressingAlt = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0; - if (pressingAlt != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0)) - { - if (pressingAlt) - Command::Execute("+actionslot 2"); - else - Command::Execute("-actionslot 2"); - } - - bool pressingKillstreak = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0; - if (pressingKillstreak != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0)) - { - if (pressingKillstreak) - Command::Execute("+actionslot 3"); - else - Command::Execute("-actionslot 3"); - } - - bool pressingNight = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0; - if (pressingNight != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0)) - { - if (pressingNight) - Command::Execute("+actionslot 4"); - else - Command::Execute("-actionslot 4"); - } - - bool pressingUp = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0; - if (pressingUp != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0)) - { - if (pressingUp) - Command::Execute("+actionslot 1"); - else - Command::Execute("-actionslot 1"); - } - - bool pressingStart = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0; - if (pressingStart != ((XInput::lastxiState.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0)) - { - if (pressingStart) - Command::Execute("togglemenu"); - } - - - memcpy(&XInput::lastxiState, xiState, sizeof XINPUT_STATE); + memcpy(&XInput::lastXiState, xiState, sizeof XINPUT_STATE); } } @@ -222,16 +221,16 @@ namespace Components add esp, 0Ch // put both forward move and rightmove values in the movement button - mov dl, byte ptr [edi+1Ah] // to_forwardMove - mov dh, byte ptr [edi+1Bh] // to_rightMove + mov dl, byte ptr[edi + 1Ah] // to_forwardMove + mov dh, byte ptr[edi + 1Bh] // to_rightMove - mov [esp+30h], dx // to_buttons + mov[esp + 30h], dx // to_buttons - mov dl, byte ptr [ebp+1Ah] // from_forwardMove - mov dh, byte ptr [ebp+1Bh] // from_rightMove + mov dl, byte ptr[ebp + 1Ah] // from_forwardMove + mov dh, byte ptr[ebp + 1Bh] // from_rightMove + + mov[esp + 2Ch], dx // from_buttons - mov [esp+2Ch], dx // from_buttons - // return back push 0x60E40E retn @@ -255,7 +254,7 @@ namespace Components forward = from->forwardmove; right = from->rightmove; } - + to->forwardmove = forward; to->rightmove = right; } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 6fe7b1ed..a8660631 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -7,10 +7,35 @@ namespace Components public: XInput(); + struct ActionMapping { + int input; + std::string action; + bool isReversible; + bool wasPressed = false; + bool spamWhenHeld = false; + + ActionMapping(int input, std::string action, bool isReversible = true, bool spamWhenHeld = false) + { + this->action = action; + this->isReversible = isReversible; + this->input = input; + this->spamWhenHeld = spamWhenHeld; + } + }; + private: static XINPUT_STATE xiStates[XUSER_MAX_COUNT]; static int xiPlayerNum; - static XINPUT_STATE lastxiState; + static XINPUT_STATE lastXiState; + + static bool isHoldingMaxLookX; + static std::chrono::milliseconds timeAtFirstHeldMaxLookX; + static std::chrono::milliseconds msBeforeUnlockingSensitivity; + static float lockedSensitivityMultiplier; + static float unlockedSensitivityMultiplier; + static float generalSensitivityMultiplier; + + static void Vibrate(int leftVal = 0, int rightVal = 0); static void CL_FrameStub(); static void PollXInputDevices(); From 123ec699108e2e4eb52d127d907eccdab1b40874 Mon Sep 17 00:00:00 2001 From: rackover Date: Sun, 2 May 2021 16:13:33 +0200 Subject: [PATCH 12/83] Better sensitivity management & don't spam button command --- src/Components/Modules/XInput.cpp | 34 +++++++++---------------------- src/Components/Modules/XInput.hpp | 4 ++-- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index f317d7b7..a76ca1de 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -8,15 +8,15 @@ namespace Components std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool XInput::isHoldingMaxLookX = false; - float XInput::lockedSensitivityMultiplier = 0.6f; - float XInput::unlockedSensitivityMultiplier = 1.2f; - float XInput::generalSensitivityMultiplier = 1.3f; + float XInput::lockedSensitivityMultiplier = 0.5f; + float XInput::generalXSensitivityMultiplier = 1.6f; + float XInput::generalYSensitivityMultiplier = 0.8f; std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 250ms; std::vector mappings = { XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), - //XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance", true, true), + XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance"), XInput::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), XInput::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), XInput::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), @@ -107,12 +107,9 @@ namespace Components if (hasBeenHoldingLeftXForMs < XInput::msBeforeUnlockingSensitivity) { viewStickX *= XInput::lockedSensitivityMultiplier; } - else { - viewStickX *= XInput::unlockedSensitivityMultiplier; - } #else float coeff = std::clamp(hasBeenHoldingLeftXForMs.count()/(float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= std::lerp(XInput::lockedSensitivityMultiplier, XInput::unlockedSensitivityMultiplier, coeff); + viewStickX *= std::lerp(XInput::lockedSensitivityMultiplier, 1.0f, coeff); #endif } } @@ -122,8 +119,8 @@ namespace Components } - Game::cl_angles[0] -= viewStickY; - Game::cl_angles[1] -= viewStickX * generalSensitivityMultiplier; + Game::cl_angles[0] -= viewStickY * generalYSensitivityMultiplier; + Game::cl_angles[1] -= viewStickX * generalXSensitivityMultiplier; bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) @@ -157,9 +154,6 @@ namespace Components else if (mapping.wasPressed) { if (xiState->Gamepad.wButtons & mapping.input) { // Button still pressed, do not send info - if (mapping.spamWhenHeld) { - Command::Execute(action.c_str()); - } } else { mappings[i].wasPressed = false; @@ -169,7 +163,9 @@ namespace Components } if (xiState->Gamepad.wButtons & mapping.input) { - Command::Execute(action.c_str()); + if (mapping.spamWhenHeld || !mappings[i].wasPressed) { + Command::Execute(action.c_str()); + } mappings[i].wasPressed = true; } else if (mapping.isReversible && mapping.wasPressed) { @@ -178,16 +174,6 @@ namespace Components } } - bool pressingStance = (xiState->Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0; - if (pressingStance != ((XInput::lastXiState.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0)) - { - if (pressingStance) - Command::Execute("+stance"); - else - Command::Execute("-stance"); - } - - memcpy(&XInput::lastXiState, xiState, sizeof XINPUT_STATE); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index a8660631..1d79bd44 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -32,8 +32,8 @@ namespace Components static std::chrono::milliseconds timeAtFirstHeldMaxLookX; static std::chrono::milliseconds msBeforeUnlockingSensitivity; static float lockedSensitivityMultiplier; - static float unlockedSensitivityMultiplier; - static float generalSensitivityMultiplier; + static float generalXSensitivityMultiplier; + static float generalYSensitivityMultiplier; static void Vibrate(int leftVal = 0, int rightVal = 0); From fe5572c179dfa234c2b6db1ae96337312b30066f Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 13:04:05 +0200 Subject: [PATCH 13/83] Do not use C++20 std:lerp --- src/Components/Modules/XInput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index a76ca1de..dc8c4ff3 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -109,7 +109,7 @@ namespace Components } #else float coeff = std::clamp(hasBeenHoldingLeftXForMs.count()/(float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= std::lerp(XInput::lockedSensitivityMultiplier, 1.0f, coeff); + viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f -XInput::lockedSensitivityMultiplier); #endif } } From 04ef6c3fbe15322721ede889ae44b5061b0b4f95 Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 15:42:22 +0200 Subject: [PATCH 14/83] Vibrate the controller on start --- src/Components/Modules/XInput.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index dc8c4ff3..af7586df 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -296,8 +296,15 @@ namespace Components Utils::Hook::Set(0x60E501, 16); Utils::Hook::Set(0x60E5CD, 16); - // make sure to parse the movement data properally and apply it + // make sure to parse the movement data properly and apply it Utils::Hook(0x492127, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492009, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + + PollXInputDevices(); + + if (xiPlayerNum >= 0) { + Vibrate(3000, 3000); + } + } } From b3adacb71deec026633cff4869478716e04f3341 Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 15:47:46 +0200 Subject: [PATCH 15/83] Gamepad support for menus --- src/Components/Modules/XInput.cpp | 86 ++++++++++++++++++++++-- src/Components/Modules/XInput.hpp | 17 +++++ src/Game/Functions.cpp | 29 ++++++++ src/Game/Functions.hpp | 11 ++++ src/Game/Structs.hpp | 106 ++++++++++++++++++++++++++++++ 5 files changed, 243 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index af7586df..498bf066 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -8,11 +8,15 @@ namespace Components std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool XInput::isHoldingMaxLookX = false; - float XInput::lockedSensitivityMultiplier = 0.5f; - float XInput::generalXSensitivityMultiplier = 1.6f; + float XInput::lockedSensitivityMultiplier = 0.45f; + float XInput::generalXSensitivityMultiplier = 1.5f; float XInput::generalYSensitivityMultiplier = 0.8f; - std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 250ms; + float XInput::lastMenuNavigationDirection = .0f; + std::chrono::milliseconds XInput::lastNavigationTime = 0ms; + std::chrono::milliseconds XInput::msBetweenNavigations = 220ms; + + std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 350ms; std::vector mappings = { XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), @@ -31,6 +35,14 @@ namespace Components XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 4"), }; + std::vector menuMappings = { + XInput::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), + XInput::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), + XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW), + XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW), + XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW), + XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) + }; void XInput::Vibrate(int leftVal, int rightVal) { @@ -108,12 +120,12 @@ namespace Components viewStickX *= XInput::lockedSensitivityMultiplier; } #else - float coeff = std::clamp(hasBeenHoldingLeftXForMs.count()/(float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f -XInput::lockedSensitivityMultiplier); + float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); + viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f - XInput::lockedSensitivityMultiplier); #endif } } - else{ + else { XInput::isHoldingMaxLookX = false; XInput::timeAtFirstHeldMaxLookX = 0ms; } @@ -281,6 +293,67 @@ namespace Components } } + void XInput::MenuNavigate() { + + Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext); + +#define SIGN(d) ((d > 0) - (d < 0)) + + if (menuDef) { + PollXInputDevices(); + + if (XInput::xiPlayerNum != -1) + { + XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; + + // Up/Down + float moveStickX = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLX / (float)std::numeric_limits().max() : .0f; + float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits().max() : .0f; + + std::chrono::milliseconds now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime; + bool canNavigate = timeSinceLastNavigation > msBetweenNavigations; + + if (moveStickY > .0f) { + if (canNavigate || SIGN(moveStickY) != SIGN(lastMenuNavigationDirection)) { + Game::Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); + lastMenuNavigationDirection = moveStickY; + lastNavigationTime = now; + } + } + else if (moveStickY < .0f) { + if (canNavigate || SIGN(moveStickY) != SIGN(lastMenuNavigationDirection)) { + Game::Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); + lastMenuNavigationDirection = moveStickY; + lastNavigationTime = now; + } + } + else { + lastMenuNavigationDirection = .0f; + } + + for (size_t i = 0; i < menuMappings.size(); i++) + { + MenuMapping mapping = menuMappings[i]; + auto action = mapping.keystroke; + + if (mapping.wasPressed) { + if (xiState->Gamepad.wButtons & mapping.input) { + // Button still pressed, do not send info + } + else { + menuMappings[i].wasPressed = false; + } + } + else if(xiState->Gamepad.wButtons & mapping.input){ + Game::UI_KeyEvent(0, mapping.keystroke, 1); + menuMappings[i].wasPressed = true; + } + } + } + } + } + XInput::XInput() { // poll xinput devices every client frame @@ -306,5 +379,6 @@ namespace Components Vibrate(3000, 3000); } + Scheduler::OnFrame(MenuNavigate); } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 1d79bd44..36d584b5 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -23,6 +23,18 @@ namespace Components } }; + struct MenuMapping { + int input; + Game::keyNum_t keystroke; + bool wasPressed = false; + + MenuMapping(int input, Game::keyNum_t keystroke) + { + this->keystroke = keystroke; + this->input = input; + } + }; + private: static XINPUT_STATE xiStates[XUSER_MAX_COUNT]; static int xiPlayerNum; @@ -35,6 +47,10 @@ namespace Components static float generalXSensitivityMultiplier; static float generalYSensitivityMultiplier; + static std::chrono::milliseconds lastNavigationTime; + static std::chrono::milliseconds msBetweenNavigations; + static float lastMenuNavigationDirection; + static void Vibrate(int leftVal = 0, int rightVal = 0); static void CL_FrameStub(); @@ -42,6 +58,7 @@ namespace Components static void CL_CreateCmdStub(); static void CL_GamepadMove(int, Game::usercmd_s*); + static void MenuNavigate(); static void MSG_WriteDeltaUsercmdKeyStub(); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 954f771a..eeffd563 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -175,6 +175,8 @@ namespace Game Menus_FindByName_t Menus_FindByName = Menus_FindByName_t(0x487240); Menu_IsVisible_t Menu_IsVisible = Menu_IsVisible_t(0x4D77D0); Menus_MenuIsInStack_t Menus_MenuIsInStack = Menus_MenuIsInStack_t(0x47ACB0); + Menu_HandleKey_t Menu_HandleKey = Menu_HandleKey_t(0x4C4A00); + Menu_GetFocused_t Menu_GetFocused = Menu_GetFocused_t(0x4AFF10); MSG_Init_t MSG_Init = MSG_Init_t(0x45FCA0); MSG_ReadBit_t MSG_ReadBit = MSG_ReadBit_t(0x476D20); @@ -327,6 +329,7 @@ namespace Game UI_GetContext_t UI_GetContext = UI_GetContext_t(0x4F8940); UI_TextWidth_t UI_TextWidth = UI_TextWidth_t(0x6315C0); UI_DrawText_t UI_DrawText = UI_DrawText_t(0x49C0D0); + UI_KeyEvent_t UI_KeyEvent = UI_KeyEvent_t(0x4970F0); Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0); @@ -1141,6 +1144,32 @@ namespace Game } } + void Menu_SetNextCursorItem(Game::UiContext* a1, Game::menuDef_t* a2, int unk) + { + __asm + { + push unk + push a2 + mov eax, a1 + mov ebx, 0x639FE0 + call ebx + add esp, 0x8 // 2 args = 2x4 + } + } + + void Menu_SetPrevCursorItem(Game::UiContext* a1, Game::menuDef_t* a2, int unk) + { + __asm + { + push unk + push a2 + mov eax, a1 + mov ebx, 0x639F20 + call ebx + add esp, 0x8 // 2 args = 2x4 + } + } + __declspec(naked) void R_AddDebugLine(float* /*color*/, float* /*v1*/, float* /*v2*/) { __asm diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index a15cc01e..23cb11fb 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -414,6 +414,15 @@ namespace Game typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu); extern Menus_MenuIsInStack_t Menus_MenuIsInStack; + typedef menuDef_t*(__cdecl* Menu_GetFocused_t)(UiContext* ctx); + extern Menu_GetFocused_t Menu_GetFocused; + + typedef void(__cdecl* Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down); + extern Menu_HandleKey_t Menu_HandleKey; + + typedef bool(__cdecl* UI_KeyEvent_t)(int clientNum, Game::keyNum_t key, int down); + extern UI_KeyEvent_t UI_KeyEvent; + typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length); extern MSG_Init_t MSG_Init; @@ -874,6 +883,8 @@ namespace Game 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); + void Menu_SetPrevCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); const char* TableLookup(StringTable* stringtable, int row, int column); const char* UI_LocalizeMapName(const char* mapName); const char* UI_LocalizeGameType(const char* gameType); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 3f1a30e7..269717b8 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -173,6 +173,112 @@ namespace Game }; #pragma pack(pop) + enum keyNum_t + { + K_NONE = 0x0, + K_TAB = 0x9, + K_ENTER = 0xD, + K_ESCAPE = 0x1B, + K_SPACE = 0x20, + K_BACKSPACE = 0x7F, + K_ASCII_FIRST = 0x80, + K_ASCII_181 = 0x80, + K_ASCII_191 = 0x81, + K_ASCII_223 = 0x82, + K_ASCII_224 = 0x83, + K_ASCII_225 = 0x84, + K_ASCII_228 = 0x85, + K_ASCII_229 = 0x86, + K_ASCII_230 = 0x87, + K_ASCII_231 = 0x88, + K_ASCII_232 = 0x89, + K_ASCII_233 = 0x8A, + K_ASCII_236 = 0x8B, + K_ASCII_241 = 0x8C, + K_ASCII_242 = 0x8D, + K_ASCII_243 = 0x8E, + K_ASCII_246 = 0x8F, + K_ASCII_248 = 0x90, + K_ASCII_249 = 0x91, + K_ASCII_250 = 0x92, + K_ASCII_252 = 0x93, + K_END_ASCII_CHARS = 0x94, + K_COMMAND = 0x96, + K_CAPSLOCK = 0x97, + K_POWER = 0x98, + K_PAUSE = 0x99, + K_UPARROW = 0x9A, + K_DOWNARROW = 0x9B, + K_LEFTARROW = 0x9C, + K_RIGHTARROW = 0x9D, + K_ALT = 0x9E, + K_CTRL = 0x9F, + K_SHIFT = 0xA0, + K_INS = 0xA1, + K_DEL = 0xA2, + K_PGDN = 0xA3, + K_PGUP = 0xA4, + K_HOME = 0xA5, + K_END = 0xA6, + K_F1 = 0xA7, + K_F2 = 0xA8, + K_F3 = 0xA9, + K_F4 = 0xAA, + K_F5 = 0xAB, + K_F6 = 0xAC, + K_F7 = 0xAD, + K_F8 = 0xAE, + K_F9 = 0xAF, + K_F10 = 0xB0, + K_F11 = 0xB1, + K_F12 = 0xB2, + K_F13 = 0xB3, + K_F14 = 0xB4, + K_F15 = 0xB5, + K_KP_HOME = 0xB6, + K_KP_UPARROW = 0xB7, + K_KP_PGUP = 0xB8, + K_KP_LEFTARROW = 0xB9, + K_KP_5 = 0xBA, + K_KP_RIGHTARROW = 0xBB, + K_KP_END = 0xBC, + K_KP_DOWNARROW = 0xBD, + K_KP_PGDN = 0xBE, + K_KP_ENTER = 0xBF, + K_KP_INS = 0xC0, + K_KP_DEL = 0xC1, + K_KP_SLASH = 0xC2, + K_KP_MINUS = 0xC3, + K_KP_PLUS = 0xC4, + K_KP_NUMLOCK = 0xC5, + K_KP_STAR = 0xC6, + K_KP_EQUALS = 0xC7, + K_MOUSE1 = 0xC8, + K_MOUSE2 = 0xC9, + K_MOUSE3 = 0xCA, + K_MOUSE4 = 0xCB, + K_MOUSE5 = 0xCC, + K_MWHEELDOWN = 0xCD, + K_MWHEELUP = 0xCE, + K_AUX1 = 0xCF, + K_AUX2 = 0xD0, + K_AUX3 = 0xD1, + K_AUX4 = 0xD2, + K_AUX5 = 0xD3, + K_AUX6 = 0xD4, + K_AUX7 = 0xD5, + K_AUX8 = 0xD6, + K_AUX9 = 0xD7, + K_AUX10 = 0xD8, + K_AUX11 = 0xD9, + K_AUX12 = 0xDA, + K_AUX13 = 0xDB, + K_AUX14 = 0xDC, + K_AUX15 = 0xDD, + K_AUX16 = 0xDE, + K_LAST_KEY = 0xDF, + }; + struct __declspec(align(4)) PhysPreset { const char *name; From 1df84f753665882be6d6446696c0689f6802bee0 Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 15:54:12 +0200 Subject: [PATCH 16/83] Allow the user to use their keyboard even if the gamepad is plugged in --- src/Components/Modules/XInput.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 498bf066..192ba4b1 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -104,8 +104,11 @@ namespace Components float viewStickX = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRX / (float)std::numeric_limits().max() : .0f; float viewStickY = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRY / (float)std::numeric_limits().max() : .0f; - cmd->rightmove = moveStickX * std::numeric_limits().max(); - cmd->forwardmove = moveStickY * std::numeric_limits().max(); + if (moveStickX != 0 || moveStickY != 0) { + // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in + cmd->rightmove = moveStickX * std::numeric_limits().max(); + cmd->forwardmove = moveStickY * std::numeric_limits().max(); + } // Gamepad horizontal acceleration on view if (abs(viewStickX) > 0.9f) { From bac2afa028c2915b1ed23d70dc9df5ff1249d0ff Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 18:09:37 +0200 Subject: [PATCH 17/83] Overriding mouse is much better than overriding client angles --- src/Components/Modules/XInput.cpp | 128 ++++-- src/Components/Modules/XInput.hpp | 4 + src/Game/Structs.hpp | 638 ++++++++++++++++++++++++++---- 3 files changed, 653 insertions(+), 117 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 192ba4b1..307208f2 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -9,8 +9,8 @@ namespace Components bool XInput::isHoldingMaxLookX = false; float XInput::lockedSensitivityMultiplier = 0.45f; - float XInput::generalXSensitivityMultiplier = 1.5f; - float XInput::generalYSensitivityMultiplier = 0.8f; + float XInput::generalXSensitivityMultiplier = 3 * 1.5f; + float XInput::generalYSensitivityMultiplier = 4 * 0.8f; float XInput::lastMenuNavigationDirection = .0f; std::chrono::milliseconds XInput::lastNavigationTime = 0ms; @@ -18,6 +18,8 @@ namespace Components std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 350ms; + float sensitivityMultiplier = 1.0f; + std::vector mappings = { XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance"), @@ -101,49 +103,23 @@ namespace Components float moveStickX = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLX / (float)std::numeric_limits().max() : .0f; float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits().max() : .0f; - float viewStickX = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRX / (float)std::numeric_limits().max() : .0f; - float viewStickY = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRY / (float)std::numeric_limits().max() : .0f; - if (moveStickX != 0 || moveStickY != 0) { // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in cmd->rightmove = moveStickX * std::numeric_limits().max(); cmd->forwardmove = moveStickY * std::numeric_limits().max(); } - // Gamepad horizontal acceleration on view - if (abs(viewStickX) > 0.9f) { - if (!XInput::isHoldingMaxLookX) { - XInput::isHoldingMaxLookX = true; - XInput::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - } - else { - std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - XInput::timeAtFirstHeldMaxLookX; -#ifdef STEP_SENSITIVITY - if (hasBeenHoldingLeftXForMs < XInput::msBeforeUnlockingSensitivity) { - viewStickX *= XInput::lockedSensitivityMultiplier; - } -#else - float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f - XInput::lockedSensitivityMultiplier); -#endif - } - } - else { - XInput::isHoldingMaxLookX = false; - XInput::timeAtFirstHeldMaxLookX = 0ms; - } - - - Game::cl_angles[0] -= viewStickY * generalYSensitivityMultiplier; - Game::cl_angles[1] -= viewStickX * generalXSensitivityMultiplier; - bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { - if (pressingLeftTrigger) + if (pressingLeftTrigger) { + Command::Execute("+toggleads_throw"); Command::Execute("+speed"); - else + } + else { + Command::Execute("-toggleads_throw"); Command::Execute("-speed"); + } } bool pressingRightTrigger = xiState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; @@ -348,7 +324,7 @@ namespace Components menuMappings[i].wasPressed = false; } } - else if(xiState->Gamepad.wButtons & mapping.input){ + else if (xiState->Gamepad.wButtons & mapping.input) { Game::UI_KeyEvent(0, mapping.keystroke, 1); menuMappings[i].wasPressed = true; } @@ -357,6 +333,84 @@ namespace Components } } + void XInput::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) { + + XInput::CL_GetMouseMovementCl(clientActive, mx, my); + + if (XInput::xiPlayerNum != -1) + { + XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; + + float viewSensitivityMultiplier = Dvar::Var("xinput_sensitivity").get(); + float viewStickX = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRX / (float)std::numeric_limits().max() : .0f; + float viewStickY = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRY / (float)std::numeric_limits().max() : .0f; + + // Gamepad horizontal acceleration on view + if (abs(viewStickX) > 0.9f) { + if (!XInput::isHoldingMaxLookX) { + XInput::isHoldingMaxLookX = true; + XInput::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + } + else { + std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - XInput::timeAtFirstHeldMaxLookX; +#ifdef STEP_SENSITIVITY + if (hasBeenHoldingLeftXForMs < XInput::msBeforeUnlockingSensitivity) { + viewStickX *= XInput::lockedSensitivityMultiplier; + } +#else + float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); + viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f - XInput::lockedSensitivityMultiplier); +#endif + } + } + else { + XInput::isHoldingMaxLookX = false; + XInput::timeAtFirstHeldMaxLookX = 0ms; + } + + if (viewStickX != 0 || viewStickY != 0) { + *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier; + *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier; + } + } + + } + + + // Game -> Client DLL + __declspec(naked) void CL_GetMouseMovementStub() + { + __asm + { + push edx; + push ecx; + push eax; + call XInput::MouseOverride; + add esp, 0xC; + ret; + } + } + + + // Client DLL -> Game + void XInput::CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my) + { + __asm + { + push ebx; + push ecx; + push edx; + mov eax, result; + mov ecx, mx; + mov edx, my; + mov ebx, 5A60E0h; + call ebx; + pop edx; + pop ecx; + pop ebx; + } + } + XInput::XInput() { // poll xinput devices every client frame @@ -376,6 +430,10 @@ namespace Components Utils::Hook(0x492127, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492009, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + + Game::Dvar_RegisterFloat("xinput_sensitivity", 1.0f, 0.01f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + PollXInputDevices(); if (xiPlayerNum >= 0) { diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 36d584b5..b1969b8f 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -51,6 +51,10 @@ namespace Components static std::chrono::milliseconds msBetweenNavigations; static float lastMenuNavigationDirection; + static void CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my); + + static void MouseOverride(Game::clientActive_t* clientActive, float* my, float* mx); + static char MovementOverride(int a1, Game::usercmd_s* cmd); static void Vibrate(int leftVal = 0, int rightVal = 0); static void CL_FrameStub(); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 269717b8..b9f1e2e6 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -706,6 +706,562 @@ namespace Game MaterialShaderArgument *args; }; + enum OffhandClass + { + OFFHAND_CLASS_NONE = 0x0, + OFFHAND_CLASS_FRAG_GRENADE = 0x1, + OFFHAND_CLASS_SMOKE_GRENADE = 0x2, + OFFHAND_CLASS_FLASH_GRENADE = 0x3, + OFFHAND_CLASS_THROWINGKNIFE = 0x4, + OFFHAND_CLASS_OTHER = 0x5, + OFFHAND_CLASS_COUNT = 0x6, + }; + + enum ViewLockTypes + { + PLAYERVIEWLOCK_NONE = 0x0, + PLAYERVIEWLOCK_FULL = 0x1, + PLAYERVIEWLOCK_WEAPONJITTER = 0x2, + PLAYERVIEWLOCKCOUNT = 0x3, + }; + + struct SprintState + { + int sprintButtonUpRequired; + int sprintDelay; + int lastSprintStart; + int lastSprintEnd; + int sprintStartMaxLength; + }; + + + /* 1018 */ + struct MantleState + { + float yaw; + int timer; + int transIndex; + int flags; + }; + + /* 1019 */ + struct PlayerActiveWeaponState + { + int weapAnim; + int weaponTime; + int weaponDelay; + int weaponRestrictKickTime; + int weaponState; + int weapHandFlags; + unsigned int weaponShotCount; + }; + + /* 1020 */ + struct PlayerEquippedWeaponState + { + bool usedBefore; + bool dualWielding; + char weaponModel; + bool needsRechamber[2]; + }; + + /* 1021 */ + struct GlobalAmmo + { + int ammoType; + int ammoCount; + }; + + /* 1022 */ + struct ClipAmmo + { + int clipIndex; + int ammoCount[2]; + }; + + enum PlayerHandIndex + { + WEAPON_HAND_RIGHT = 0x0, + WEAPON_HAND_LEFT = 0x1, + NUM_WEAPON_HANDS = 0x2, + WEAPON_HAND_DEFAULT = 0x0, + }; + + /* 1023 */ + struct PlayerWeaponCommonState + { + int offHandIndex; + OffhandClass offhandPrimary; + OffhandClass offhandSecondary; + unsigned int weapon; + unsigned int primaryWeaponForAltMode; + int weapFlags; + float fWeaponPosFrac; + float aimSpreadScale; + int adsDelayTime; + int spreadOverride; + int spreadOverrideState; + PlayerHandIndex lastWeaponHand; + GlobalAmmo ammoNotInClip[15]; + ClipAmmo ammoInClip[15]; + int weapLockFlags; + int weapLockedEntnum; + float weapLockedPos[3]; + int weaponIdleTime; + }; + + enum ActionSlotType + { + ACTIONSLOTTYPE_DONOTHING = 0x0, + ACTIONSLOTTYPE_SPECIFYWEAPON = 0x1, + ACTIONSLOTTYPE_ALTWEAPONTOGGLE = 0x2, + ACTIONSLOTTYPE_NIGHTVISION = 0x3, + ACTIONSLOTTYPECOUNT = 0x4, + }; + + /* 1024 */ + struct ActionSlotParam_SpecifyWeapon + { + unsigned int index; + }; + + /* 1025 */ + struct ActionSlotParam + { + ActionSlotParam_SpecifyWeapon specifyWeapon; + }; + + enum objectiveState_t + { + OBJST_EMPTY = 0x0, + OBJST_ACTIVE = 0x1, + OBJST_INVISIBLE = 0x2, + OBJST_DONE = 0x3, + OBJST_CURRENT = 0x4, + OBJST_FAILED = 0x5, + OBJST_NUMSTATES = 0x6, + }; + + /* 1026 */ + struct objective_t + { + objectiveState_t state; + float origin[3]; + int entNum; + int teamNum; + int icon; + }; + + + /* 104 */ + enum he_type_t + { + HE_TYPE_FREE = 0x0, + HE_TYPE_TEXT = 0x1, + HE_TYPE_VALUE = 0x2, + HE_TYPE_PLAYERNAME = 0x3, + HE_TYPE_MAPNAME = 0x4, + HE_TYPE_GAMETYPE = 0x5, + HE_TYPE_MATERIAL = 0x6, + HE_TYPE_TIMER_DOWN = 0x7, + HE_TYPE_TIMER_UP = 0x8, + HE_TYPE_TIMER_STATIC = 0x9, + HE_TYPE_TENTHS_TIMER_DOWN = 0xA, + HE_TYPE_TENTHS_TIMER_UP = 0xB, + HE_TYPE_TENTHS_TIMER_STATIC = 0xC, + HE_TYPE_CLOCK_DOWN = 0xD, + HE_TYPE_CLOCK_UP = 0xE, + HE_TYPE_WAYPOINT = 0xF, + HE_TYPE_COUNT = 0x10, + }; + + struct hud_color + { + char r; + char g; + char b; + char a; + }; + + /* 1028 */ + union hudelem_color_t + { + hud_color __s0; + int rgba; + }; + + struct hudelem_s + { + he_type_t type; + float x; + float y; + float z; + int targetEntNum; + float fontScale; + float fromFontScale; + int fontScaleStartTime; + int fontScaleTime; + int font; + int alignOrg; + int alignScreen; + hudelem_color_t color; + hudelem_color_t fromColor; + int fadeStartTime; + int fadeTime; + int label; + int width; + int height; + int materialIndex; + int fromWidth; + int fromHeight; + int scaleStartTime; + int scaleTime; + float fromX; + float fromY; + int fromAlignOrg; + int fromAlignScreen; + int moveStartTime; + int moveTime; + int time; + int duration; + float value; + int text; + float sort; + hudelem_color_t glowColor; + int fxBirthTime; + int fxLetterTime; + int fxDecayStartTime; + int fxDecayDuration; + int soundID; + int flags; + }; + + struct $3EB5F037EADAEE8E2FA2A1F9FFF31312 + { + hudelem_s current[31]; + hudelem_s archival[31]; + }; + + struct playerState_s + { + int commandTime; + int pm_type; + int pm_time; + int pm_flags; + int otherFlags; + int linkFlags; + int bobCycle; + float origin[3]; + float velocity[3]; + int grenadeTimeLeft; + int throwbackGrenadeOwner; + int throwbackGrenadeTimeLeft; + unsigned int throwbackWeaponIndex; + int remoteEyesEnt; + int remoteEyesTagname; + int remoteControlEnt; + int foliageSoundTime; + int gravity; + float leanf; + int speed; + float delta_angles[3]; + int groundEntityNum; + float vLadderVec[3]; + int jumpTime; + float jumpOriginZ; + int legsTimer; + int legsAnim; + int torsoTimer; + int torsoAnim; + int legsAnimDuration; + int torsoAnimDuration; + int damageTimer; + int damageDuration; + int flinchYawAnim; + int corpseIndex; + int movementDir; + int eFlags; + int eventSequence; + int events[4]; + unsigned int eventParms[4]; + int oldEventSequence; + int unpredictableEventSequence; + int unpredictableEventSequenceOld; + int unpredictableEvents[4]; + unsigned int unpredictableEventParms[4]; + int clientNum; + int viewmodelIndex; + float viewangles[3]; + int viewHeightTarget; + float viewHeightCurrent; + int viewHeightLerpTime; + int viewHeightLerpTarget; + int viewHeightLerpDown; + float viewAngleClampBase[2]; + float viewAngleClampRange[2]; + int damageEvent; + int damageYaw; + int damagePitch; + int damageCount; + int damageFlags; + int stats[4]; + float proneDirection; + float proneDirectionPitch; + float proneTorsoPitch; + ViewLockTypes viewlocked; + int viewlocked_entNum; + float linkAngles[3]; + float linkWeaponAngles[3]; + int linkWeaponEnt; + int loopSound; + int cursorHint; + int cursorHintString; + int cursorHintEntIndex; + int cursorHintDualWield; + int iCompassPlayerInfo; + int radarEnabled; + int radarBlocked; + int radarMode; + int locationSelectionInfo; + SprintState sprintState; + float holdBreathScale; + int holdBreathTimer; + float moveSpeedScaleMultiplier; + MantleState mantleState; + PlayerActiveWeaponState weapState[2]; + unsigned int weaponsEquipped[15]; + PlayerEquippedWeaponState weapEquippedData[15]; + PlayerWeaponCommonState weapCommon; + float meleeChargeYaw; + int meleeChargeDist; + int meleeChargeTime; + unsigned int perks[2]; + unsigned int perkSlots[8]; + ActionSlotType actionSlotType[4]; + ActionSlotParam actionSlotParam[4]; + int weaponHudIconOverrides[6]; + int animScriptedType; + int shellshockIndex; + int shellshockTime; + int shellshockDuration; + float dofNearStart; + float dofNearEnd; + float dofFarStart; + float dofFarEnd; + float dofNearBlur; + float dofFarBlur; + float dofViewmodelStart; + float dofViewmodelEnd; + objective_t objective[32]; + int deltaTime; + int killCamEntity; + int killCamLookAtEntity; + int killCamClientNum; + $3EB5F037EADAEE8E2FA2A1F9FFF31312 hud; + unsigned int partBits[6]; + int recoilScale; + int diveDirection; + int stunTime; + }; + + struct clSnapshot_t + { + playerState_s ps; + int valid; + int snapFlags; + int serverTime; + int messageNum; + int deltaNum; + int ping; + int cmdNum; + int numEntities; + int numClients; + int parseEntitiesIndex; + int parseClientsIndex; + int serverCommandNum; + }; + + enum StanceState + { + CL_STANCE_STAND = 0x0, + CL_STANCE_CROUCH = 0x1, + CL_STANCE_PRONE = 0x2, + }; + + struct ClientArchiveData + { + int serverTime; + float origin[3]; + float velocity[3]; + int bobCycle; + int movementDir; + float viewangles[3]; + int locationSelectionInfo; + float selectedLocation[2]; + float selectedLocationAngle; + }; + + struct outPacket_t + { + int p_cmdNumber; + int p_serverTime; + int p_realtime; + }; + + enum team_t + { + TEAM_FREE = 0x0, + TEAM_AXIS = 0x1, + TEAM_ALLIES = 0x2, + TEAM_SPECTATOR = 0x3, + TEAM_NUM_TEAMS = 0x4, + }; + + struct clientState_s + { + int clientIndex; + team_t team; + int modelindex; + int dualWielding; + int riotShieldNext; + int attachModelIndex[6]; + int attachTagIndex[6]; + char name[16]; + float maxSprintTimeMultiplier; + int rank; + int prestige; + unsigned int perks[2]; + int diveState; + int voiceConnectivityBits; + unsigned int playerCardIcon; + unsigned int playerCardTitle; + unsigned int playerCardNameplate; + }; + +#pragma pack(push, 4) + struct usercmd_s + { + int serverTime; + int buttons; + int angles[3]; + unsigned __int16 weapon; + unsigned __int16 primaryWeaponForAltMode; + unsigned __int16 offHandIndex; + char forwardmove; + char rightmove; + float meleeChargeYaw; + char meleeChargeDist; + char selectedLoc[2]; + char selectedLocAngle; + char remoteControlAngles[2]; + }; +#pragma pack(pop) + + struct LerpEntityState + { + char pad[0x70]; + }; + + struct clientLinkInfo_t + { + __int16 parentId; + char tagName; + char flags; + }; + + struct entityState_s + { + int number; + int eType; + LerpEntityState lerp; + int time2; + int otherEntityNum; + int attackerEntityNum; + int groundEntityNum; + int loopSound; + int surfType; + + union + { + int brushModel; + int triggerModel; + int item; + int xmodel; + int primaryLight; + } index; + + int clientNum; + int iHeadIcon; + int iHeadIconTeam; + int solid; + unsigned int eventParm; + int eventSequence; + int events[4]; + unsigned int eventParms[4]; + unsigned __int16 weapon; + int legsAnim; + int torsoAnim; + int un1; + int un2; + clientLinkInfo_t clientLinkInfo; + unsigned int partBits[6]; + int clientMask[1]; + }; + + struct clientActive_t + { + bool usingAds; + int timeoutcount; + clSnapshot_t snap; + bool alwaysFalse; + int serverTime; + int oldServerTime; + int oldFrameServerTime; + int serverTimeDelta; + int oldSnapServerTime; + int extrapolatedSnapshot; + int newSnapshots; + int serverId; + char mapname[64]; + int parseEntitiesIndex; + int parseClientsIndex; + int mouseDx[2]; + int mouseDy[2]; + int mouseIndex; + bool stanceHeld; + StanceState stance; + StanceState stancePosition; + int stanceTime; + int cgameUserCmdWeapon; + int cgameUserCmdOffHandIndex; + float cgameFOVSensitivityScale; + float cgameMaxPitchSpeed; + float cgameMaxYawSpeed; + float cgameKickAngles[3]; + float cgameOrigin[3]; + float cgameVelocity[3]; + float cgameViewangles[3]; + int cgameBobCycle; + int cgameMovementDir; + int cgameExtraButtons; + int cgamePredictedDataServerTime; + float clViewangles[3]; + usercmd_s cmds[128]; + int cmdNumber; + ClientArchiveData clientArchive[256]; + int clientArchiveIndex; + int packetBackupCount; + int packetBackupMask; + int parseEntitiesCount; + int parseClientsCount; + outPacket_t outPackets[32]; + clSnapshot_t snapshots[32]; + entityState_s parseEntities[19200]; + clientState_s parseClients[576]; + int corruptedTranslationFile; + char translationVersion[256]; + }; + struct MaterialTechnique { const char *name; @@ -2822,18 +3378,6 @@ namespace Game WEAPON_FIRETYPE_BURSTFIRE_FIRST = 0x2, WEAPON_FIRETYPE_BURSTFIRE_LAST = 0x4, }; - - enum OffhandClass - { - OFFHAND_CLASS_NONE = 0x0, - OFFHAND_CLASS_FRAG_GRENADE = 0x1, - OFFHAND_CLASS_SMOKE_GRENADE = 0x2, - OFFHAND_CLASS_FLASH_GRENADE = 0x3, - OFFHAND_CLASS_THROWINGKNIFE = 0x4, - OFFHAND_CLASS_OTHER = 0x5, - OFFHAND_CLASS_COUNT = 0x6, - }; - enum weapStance_t { WEAPSTANCE_STAND = 0x0, @@ -4082,25 +4626,6 @@ namespace Game }; #pragma pack(pop) -#pragma pack(push, 4) - struct usercmd_s - { - int serverTime; - int buttons; - int angles[3]; - unsigned __int16 weapon; - unsigned __int16 primaryWeaponForAltMode; - unsigned __int16 offHandIndex; - char forwardmove; - char rightmove; - float meleeChargeYaw; - char meleeChargeDist; - char selectedLoc[2]; - char selectedLocAngle; - char remoteControlAngles[2]; - }; -#pragma pack(pop) - typedef char mapname_t[40]; struct traceWork_t @@ -4580,57 +5105,6 @@ namespace Game char pad3[724]; } gclient_t; - struct LerpEntityState - { - char pad[0x70]; - }; - - struct clientLinkInfo_t - { - __int16 parentId; - char tagName; - char flags; - }; - - struct entityState_s - { - int number; - int eType; - LerpEntityState lerp; - int time2; - int otherEntityNum; - int attackerEntityNum; - int groundEntityNum; - int loopSound; - int surfType; - - union - { - int brushModel; - int triggerModel; - int item; - int xmodel; - int primaryLight; - } index; - - int clientNum; - int iHeadIcon; - int iHeadIconTeam; - int solid; - unsigned int eventParm; - int eventSequence; - int events[4]; - unsigned int eventParms[4]; - unsigned __int16 weapon; - int legsAnim; - int torsoAnim; - int un1; - int un2; - clientLinkInfo_t clientLinkInfo; - unsigned int partBits[6]; - int clientMask[1]; - }; - struct EntHandle { unsigned __int16 number; From 0354dd985e9c504e390653f0637f2561ae8c51eb Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 21:45:47 +0200 Subject: [PATCH 18/83] Reduce sensitivity when aiming down sights --- src/Components/Modules/XInput.cpp | 27 +++++++++++++++++-------- src/Components/Modules/XInput.hpp | 2 ++ src/Game/Functions.cpp | 15 ++++++++++++++ src/Game/Functions.hpp | 2 ++ src/Game/Structs.hpp | 33 +++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 307208f2..4e0a21a4 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -7,10 +7,12 @@ namespace Components int XInput::xiPlayerNum = -1; std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool XInput::isHoldingMaxLookX = false; + bool XInput::isADS; float XInput::lockedSensitivityMultiplier = 0.45f; float XInput::generalXSensitivityMultiplier = 3 * 1.5f; float XInput::generalYSensitivityMultiplier = 4 * 0.8f; + float XInput::adsMultiplier = 0.3f; float XInput::lastMenuNavigationDirection = .0f; std::chrono::milliseconds XInput::lastNavigationTime = 0ms; @@ -18,8 +20,6 @@ namespace Components std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 350ms; - float sensitivityMultiplier = 1.0f; - std::vector mappings = { XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance"), @@ -97,6 +97,8 @@ namespace Components { if (XInput::xiPlayerNum != -1) { + Game::clientActive_t* clientActive = reinterpret_cast(0xB2C698); + XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; // Deadzones @@ -113,12 +115,12 @@ namespace Components if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { if (pressingLeftTrigger) { - Command::Execute("+toggleads_throw"); - Command::Execute("+speed"); + Command::Execute("+speed_throw"); + XInput::isADS = true; } else { - Command::Execute("-toggleads_throw"); - Command::Execute("-speed"); + Command::Execute("-speed_throw"); + XInput::isADS = false; } } @@ -368,9 +370,18 @@ namespace Components XInput::timeAtFirstHeldMaxLookX = 0ms; } + float adsMultiplier = 1.0f; + + auto ps = &clientActive->snap.ps; + + // DO NOT use clientActive->usingAds ! It only works for toggle ADS + if (Game::PM_IsAdsAllowed(ps) && XInput::isADS) { + adsMultiplier = XInput::adsMultiplier; + } + if (viewStickX != 0 || viewStickY != 0) { - *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier; - *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier; + *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier * adsMultiplier; + *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier * adsMultiplier; } } diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index b1969b8f..9525f9b8 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -46,6 +46,8 @@ namespace Components static float lockedSensitivityMultiplier; static float generalXSensitivityMultiplier; static float generalYSensitivityMultiplier; + static float adsMultiplier; + static bool isADS; static std::chrono::milliseconds lastNavigationTime; static std::chrono::milliseconds msBetweenNavigations; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index eeffd563..228af09e 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -970,6 +970,21 @@ namespace Game } } + bool PM_IsAdsAllowed(Game::playerState_s* playerState) + { + bool result; + + __asm + { + mov esi, playerState + mov ebx, 0x5755A0 + call ebx + mov result, al // AL + } + + return result; + } + __declspec(naked) void FS_AddLocalizedGameDirectory(const char* /*path*/, const char* /*dir*/) { __asm diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 23cb11fb..958fd661 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -900,6 +900,8 @@ namespace Game void FS_AddLocalizedGameDirectory(const char *path, const char *dir); + bool PM_IsAdsAllowed(Game::playerState_s* playerState); + void ShowMessageBox(const std::string& message, const std::string& title); unsigned int R_HashString(const char* string); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index b9f1e2e6..632729d7 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -111,6 +111,39 @@ namespace Game IMG_CATEGORY_TEMP = 0x7, } ; + enum buttons_t + { + KB_LEFT = 0x0, + KB_RIGHT = 0x1, + KB_FORWARD = 0x2, + KB_BACK = 0x3, + KB_LOOKUP = 0x4, + KB_LOOKDOWN = 0x5, + KB_MOVELEFT = 0x6, + KB_MOVERIGHT = 0x7, + KB_STRAFE = 0x8, + KB_SPEED = 0x9, + KB_UP = 0xA, + KB_DOWN = 0xB, + KB_ANYUP = 0xC, + KB_MLOOK = 0xD, + KB_ATTACK = 0xE, + KB_BREATH = 0xF, + KB_FRAG = 0x10, + KB_OFFHANDSECONDARY = 0x11, + KB_MELEE = 0x12, + KB_ACTIVATE = 0x13, + KB_RELOAD = 0x14, + KB_USE_RELOAD = 0x15, + KB_PRONE = 0x16, + KB_CROUCH = 0x17, + KB_THROW = 0x18, + KB_SPRINT = 0x19, + KB_NIGHTVISION = 0x1A, + KB_TALK = 0x1B, + NUM_BUTTONS = 0x1C + }; + enum DvarSetSource { DVAR_SOURCE_INTERNAL = 0x0, From 9f6b5c62143c1e3186de707d8192b12596785f06 Mon Sep 17 00:00:00 2001 From: rackover Date: Tue, 4 May 2021 22:12:07 +0200 Subject: [PATCH 19/83] Slap a bunch of DVars to make every parameter tweakable --- src/Components/Modules/XInput.cpp | 44 ++++++++++++++++++------------- src/Components/Modules/XInput.hpp | 5 ---- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 4e0a21a4..62b3e3e8 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -1,25 +1,20 @@ #include "STDInclude.hpp" +#define XINPUT_SENSITIVITY_MULTIPLIER 4 // Arbitrary value I multiply the xinput senstivity dvar with to get nicer values (0-10 range or something) + namespace Components { XINPUT_STATE XInput::xiStates[XUSER_MAX_COUNT]; XINPUT_STATE XInput::lastXiState = { 0 }; int XInput::xiPlayerNum = -1; - std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in miliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) + std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool XInput::isHoldingMaxLookX = false; bool XInput::isADS; - float XInput::lockedSensitivityMultiplier = 0.45f; - float XInput::generalXSensitivityMultiplier = 3 * 1.5f; - float XInput::generalYSensitivityMultiplier = 4 * 0.8f; - float XInput::adsMultiplier = 0.3f; - float XInput::lastMenuNavigationDirection = .0f; std::chrono::milliseconds XInput::lastNavigationTime = 0ms; std::chrono::milliseconds XInput::msBetweenNavigations = 220ms; - std::chrono::milliseconds XInput::msBeforeUnlockingSensitivity = 350ms; - std::vector mappings = { XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance"), @@ -31,10 +26,10 @@ namespace Components XInput::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), XInput::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), XInput::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 3"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 2"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 1"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 4"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 3"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 2"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 1"), + XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), }; std::vector menuMappings = { @@ -343,7 +338,13 @@ namespace Components { XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - float viewSensitivityMultiplier = Dvar::Var("xinput_sensitivity").get(); + float viewSensitivityMultiplier = Dvar::Var("xpad_sensitivity").get() * XINPUT_SENSITIVITY_MULTIPLIER; + + float lockedSensitivityMultiplier = Dvar::Var("xpad_early_multiplier").get(); + float generalXSensitivityMultiplier = Dvar::Var("xpad_horizontal_multiplier").get(); + float generalYSensitivityMultiplier = Dvar::Var("xpad_vertical_multiplier").get(); + std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(Dvar::Var("xpad_early_time").get()); + float viewStickX = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRX / (float)std::numeric_limits().max() : .0f; float viewStickY = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRY / (float)std::numeric_limits().max() : .0f; @@ -356,12 +357,12 @@ namespace Components else { std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - XInput::timeAtFirstHeldMaxLookX; #ifdef STEP_SENSITIVITY - if (hasBeenHoldingLeftXForMs < XInput::msBeforeUnlockingSensitivity) { - viewStickX *= XInput::lockedSensitivityMultiplier; + if (hasBeenHoldingLeftXForMs < msBeforeUnlockingSensitivity) { + viewStickX *= lockedSensitivityMultiplier; } #else - float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)XInput::msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= XInput::lockedSensitivityMultiplier + coeff * (1.0f - XInput::lockedSensitivityMultiplier); + float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); + viewStickX *= lockedSensitivityMultiplier + coeff * (1.0f - lockedSensitivityMultiplier); #endif } } @@ -376,7 +377,7 @@ namespace Components // DO NOT use clientActive->usingAds ! It only works for toggle ADS if (Game::PM_IsAdsAllowed(ps) && XInput::isADS) { - adsMultiplier = XInput::adsMultiplier; + adsMultiplier = Dvar::Var("xpad_ads_multiplier").get(); } if (viewStickX != 0 || viewStickY != 0) { @@ -443,7 +444,12 @@ namespace Components Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - Game::Dvar_RegisterFloat("xinput_sensitivity", 1.0f, 0.01f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + Game::Dvar_RegisterFloat("xpad_sensitivity", 1.0f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + Game::Dvar_RegisterInt("xpad_early_time", 350, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); + Game::Dvar_RegisterFloat("xpad_early_multiplier", 0.45f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); + Game::Dvar_RegisterFloat("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); + Game::Dvar_RegisterFloat("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); + Game::Dvar_RegisterFloat("xpad_ads_multiplier", 0.3f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); PollXInputDevices(); diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 9525f9b8..a2a48bc3 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -42,11 +42,6 @@ namespace Components static bool isHoldingMaxLookX; static std::chrono::milliseconds timeAtFirstHeldMaxLookX; - static std::chrono::milliseconds msBeforeUnlockingSensitivity; - static float lockedSensitivityMultiplier; - static float generalXSensitivityMultiplier; - static float generalYSensitivityMultiplier; - static float adsMultiplier; static bool isADS; static std::chrono::milliseconds lastNavigationTime; From 7f8995cf3ec917d8ebe3190035d1f43ed058dd87 Mon Sep 17 00:00:00 2001 From: rackover Date: Sun, 9 May 2021 01:24:37 +0200 Subject: [PATCH 20/83] Fix all killstreaks (but thermal on ac/cg) --- src/Components/Modules/Script.cpp | 2 +- src/Components/Modules/XInput.cpp | 52 ++++++++++++++++++++++++++++--- src/Components/Modules/XInput.hpp | 1 + src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 3 ++ src/Game/Structs.hpp | 7 +++++ 6 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 644c6ebf..72995ce6 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -546,7 +546,7 @@ namespace Components { int developer = Dvar::Var("developer").get(); - if (developer > 0) + if (developer > 0 && Dedicated::IsEnabled()) Utils::Hook::Set(0x48D8C7, 0x75); }); diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 62b3e3e8..2f908b47 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -92,8 +92,6 @@ namespace Components { if (XInput::xiPlayerNum != -1) { - Game::clientActive_t* clientActive = reinterpret_cast(0xB2C698); - XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; // Deadzones @@ -122,10 +120,12 @@ namespace Components bool pressingRightTrigger = xiState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; if (pressingRightTrigger != XInput::lastXiState.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { - if (pressingRightTrigger) + if (pressingRightTrigger) { Command::Execute("+attack"); - else + } + else { Command::Execute("-attack"); + } } // Buttons (on/off) mappings @@ -330,6 +330,29 @@ namespace Components } } + int XInput::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) { + + if (XInput::xiPlayerNum != -1) + { + XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; + + if (keyCode == Game::keyNum_t::K_MOUSE2) { + bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; + if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + { + if (pressingLeftTrigger) { + return 1; + } + else { + return 0; + } + } + } + } + + Utils::Hook::Call(0x48B2D0)(localClientNum, keyCode); + } + void XInput::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) { XInput::CL_GetMouseMovementCl(clientActive, mx, my); @@ -384,6 +407,23 @@ namespace Components *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier * adsMultiplier; *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier * adsMultiplier; } + + // Handling killstreaks + bool pressingRightTrigger = xiState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; + if (pressingRightTrigger != XInput::lastXiState.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + { + bool* isInPredator = reinterpret_cast(0x8EE3B8); + + if (pressingRightTrigger) { + Utils::Hook::Set(0xA1C4F4, Game::LOC_SEL_INPUT_CONFIRM); + if (*isInPredator) { + // Yea, that's how we boost + // Command::execute is sync by default so the predator event gets fired properly + Command::Execute("+attack"); + Command::Execute("-attack"); + } + } + } } } @@ -441,8 +481,10 @@ namespace Components // make sure to parse the movement data properly and apply it Utils::Hook(0x492127, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492009, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); - + Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); Game::Dvar_RegisterFloat("xpad_sensitivity", 1.0f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); Game::Dvar_RegisterInt("xpad_early_time", 350, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index a2a48bc3..d9a29500 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -49,6 +49,7 @@ namespace Components static float lastMenuNavigationDirection; static void CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my); + static int unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode); static void MouseOverride(Game::clientActive_t* clientActive, float* my, float* mx); static char MovementOverride(int a1, Game::usercmd_s* cmd); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 228af09e..a3cc417b 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -148,6 +148,7 @@ namespace Game Info_ValueForKey_t Info_ValueForKey = Info_ValueForKey_t(0x47C820); Key_SetCatcher_t Key_SetCatcher = Key_SetCatcher_t(0x43BD00); + Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive = Key_IsKeyCatcherActive_t(0x4DA010); LargeLocalInit_t LargeLocalInit = LargeLocalInit_t(0x4A62A0); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 958fd661..78bc7b65 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -342,6 +342,9 @@ namespace Game typedef void(__cdecl * Key_SetCatcher_t)(int localClientNum, int catcher); extern Key_SetCatcher_t Key_SetCatcher; + typedef bool(__cdecl* Key_IsKeyCatcherActive_t)(int localClientNum, int catcher); + extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive; + typedef void(__cdecl * LargeLocalInit_t)(); extern LargeLocalInit_t LargeLocalInit; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 632729d7..7309a984 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1097,6 +1097,13 @@ namespace Game int stunTime; }; + enum LocSelInputState + { + LOC_SEL_INPUT_NONE = 0x0, + LOC_SEL_INPUT_CONFIRM = 0x1, + LOC_SEL_INPUT_CANCEL = 0x2, + }; + struct clSnapshot_t { playerState_s ps; From 3157f60e6bdb7adb660ea381bab9a9704c2d2f76 Mon Sep 17 00:00:00 2001 From: rackover Date: Sun, 9 May 2021 18:56:10 +0200 Subject: [PATCH 21/83] Better deadzone handling for view / movement --- src/Components/Modules/XInput.cpp | 38 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 2f908b47..19b50d28 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -1,6 +1,7 @@ #include "STDInclude.hpp" #define XINPUT_SENSITIVITY_MULTIPLIER 4 // Arbitrary value I multiply the xinput senstivity dvar with to get nicer values (0-10 range or something) +#define SIGN(d) ((d > 0) - (d < 0)) namespace Components { @@ -41,6 +42,18 @@ namespace Components XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) }; + void GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y) { + float maxValue = (float)(std::numeric_limits().max() - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + x = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbLX - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbLX)) / maxValue : .0f; + y = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbLY - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbLY)) / maxValue : .0f; + } + + void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y) { + float maxValue = (float)(std::numeric_limits().max() - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + x = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbRX - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbRX)) / maxValue : .0f; + y = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbRY - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbRY)) / maxValue : .0f; + } + void XInput::Vibrate(int leftVal, int rightVal) { // Create a Vibraton State @@ -95,9 +108,9 @@ namespace Components XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; // Deadzones - float moveStickX = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLX / (float)std::numeric_limits().max() : .0f; - float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits().max() : .0f; - + float moveStickX, moveStickY; + GetLeftStick01Value(xiState, moveStickX, moveStickY); + if (moveStickX != 0 || moveStickY != 0) { // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in cmd->rightmove = moveStickX * std::numeric_limits().max(); @@ -273,8 +286,6 @@ namespace Components Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext); -#define SIGN(d) ((d > 0) - (d < 0)) - if (menuDef) { PollXInputDevices(); @@ -283,7 +294,6 @@ namespace Components XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; // Up/Down - float moveStickX = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLX / (float)std::numeric_limits().max() : .0f; float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits().max() : .0f; std::chrono::milliseconds now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); @@ -311,7 +321,6 @@ namespace Components for (size_t i = 0; i < menuMappings.size(); i++) { MenuMapping mapping = menuMappings[i]; - auto action = mapping.keystroke; if (mapping.wasPressed) { if (xiState->Gamepad.wButtons & mapping.input) { @@ -368,8 +377,8 @@ namespace Components float generalYSensitivityMultiplier = Dvar::Var("xpad_vertical_multiplier").get(); std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(Dvar::Var("xpad_early_time").get()); - float viewStickX = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRX / (float)std::numeric_limits().max() : .0f; - float viewStickY = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? xiState->Gamepad.sThumbRY / (float)std::numeric_limits().max() : .0f; + float viewStickX, viewStickY; + GetRightStick01Value(xiState, viewStickX, viewStickY); // Gamepad horizontal acceleration on view if (abs(viewStickX) > 0.9f) { @@ -392,6 +401,7 @@ namespace Components else { XInput::isHoldingMaxLookX = false; XInput::timeAtFirstHeldMaxLookX = 0ms; + viewStickX *= lockedSensitivityMultiplier; } float adsMultiplier = 1.0f; @@ -481,17 +491,17 @@ namespace Components // make sure to parse the movement data properly and apply it Utils::Hook(0x492127, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492009, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); - + Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - Game::Dvar_RegisterFloat("xpad_sensitivity", 1.0f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); - Game::Dvar_RegisterInt("xpad_early_time", 350, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); - Game::Dvar_RegisterFloat("xpad_early_multiplier", 0.45f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); + Game::Dvar_RegisterFloat("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + Game::Dvar_RegisterInt("xpad_early_time", 200, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); + Game::Dvar_RegisterFloat("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); Game::Dvar_RegisterFloat("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); Game::Dvar_RegisterFloat("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); - Game::Dvar_RegisterFloat("xpad_ads_multiplier", 0.3f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); + Game::Dvar_RegisterFloat("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); PollXInputDevices(); From cbfdde202923abb8daf19e5e4cee7e5fe08205cc Mon Sep 17 00:00:00 2001 From: Louvenarde Date: Sat, 14 Aug 2021 10:38:00 +0200 Subject: [PATCH 22/83] Slight refactor, tweaked the acceleration value and deadzones a little bit --- src/Components/Modules/XInput.cpp | 36 ++++++++++++++++++++++--------- src/Components/Modules/XInput.hpp | 5 ++++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index 19b50d28..bd5e0e2e 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -16,6 +16,7 @@ namespace Components std::chrono::milliseconds XInput::lastNavigationTime = 0ms; std::chrono::milliseconds XInput::msBetweenNavigations = 220ms; + // This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg std::vector mappings = { XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance"), @@ -33,6 +34,7 @@ namespace Components XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), }; + // Same thing std::vector menuMappings = { XInput::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), XInput::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), @@ -42,16 +44,24 @@ namespace Components XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) }; - void GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y) { - float maxValue = (float)(std::numeric_limits().max() - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); - x = abs(xiState->Gamepad.sThumbLX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbLX - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbLX)) / maxValue : .0f; - y = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbLY - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbLY)) / maxValue : .0f; + void XInput::GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y) { + GamepadStickTo01(xiState->Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, x); + GamepadStickTo01(xiState->Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, y); } - void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y) { - float maxValue = (float)(std::numeric_limits().max() - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); - x = abs(xiState->Gamepad.sThumbRX) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbRX - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbRX)) / maxValue : .0f; - y = abs(xiState->Gamepad.sThumbRY) > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE ? (xiState->Gamepad.sThumbRY - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE * SIGN(xiState->Gamepad.sThumbRY)) / maxValue : .0f; + void XInput::GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y) { + GamepadStickTo01(xiState->Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, x); + GamepadStickTo01(xiState->Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, y); + } + + void XInput::GamepadStickTo01(SHORT value, SHORT deadzone, float& output01) { + float maxValue = (float)(std::numeric_limits().max() - deadzone); + + output01 = abs(value) > deadzone ? (value - deadzone * SIGN(value)) / maxValue : .0f; + + // log2 allows for a more neat value curve from 0 to 1 + // It is not functional yet, because I suck at maths + //float test = (log2(abs(output01) + 1.f) - 1.f) * SIGN(value); } void XInput::Vibrate(int leftVal, int rightVal) @@ -380,8 +390,12 @@ namespace Components float viewStickX, viewStickY; GetRightStick01Value(xiState, viewStickX, viewStickY); +#ifdef DEBUG + Components::Logger::Print("X:%f \nY:%f\n(holdingMaxX: %d)\n", viewStickX, viewStickY, XInput::isHoldingMaxLookX); +#endif + // Gamepad horizontal acceleration on view - if (abs(viewStickX) > 0.9f) { + if (abs(viewStickX) > 0.80f) { if (!XInput::isHoldingMaxLookX) { XInput::isHoldingMaxLookX = true; XInput::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); @@ -402,6 +416,8 @@ namespace Components XInput::isHoldingMaxLookX = false; XInput::timeAtFirstHeldMaxLookX = 0ms; viewStickX *= lockedSensitivityMultiplier; + + Components::Logger::Print("multiplier will be %f\n", lockedSensitivityMultiplier); } float adsMultiplier = 1.0f; @@ -497,7 +513,7 @@ namespace Components Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); Game::Dvar_RegisterFloat("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); - Game::Dvar_RegisterInt("xpad_early_time", 200, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); + Game::Dvar_RegisterInt("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); Game::Dvar_RegisterFloat("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); Game::Dvar_RegisterFloat("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); Game::Dvar_RegisterFloat("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index d9a29500..7339e09b 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -52,7 +52,6 @@ namespace Components static int unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode); static void MouseOverride(Game::clientActive_t* clientActive, float* my, float* mx); - static char MovementOverride(int a1, Game::usercmd_s* cmd); static void Vibrate(int leftVal = 0, int rightVal = 0); static void CL_FrameStub(); @@ -68,5 +67,9 @@ namespace Components static void MSG_ReadDeltaUsercmdKeyStub(); static void MSG_ReadDeltaUsercmdKeyStub2(); + + static void GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y); + static void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y); + static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); }; } From 0f8acb940e35f5489693e52ac75464a800cb74d9 Mon Sep 17 00:00:00 2001 From: Louvenarde Date: Sat, 14 Aug 2021 13:51:22 +0200 Subject: [PATCH 23/83] Better dvar handling --- src/Components/Loader.cpp | 2 +- src/Components/Modules/XInput.cpp | 35 ++++++++++++++++++------------- src/Components/Modules/XInput.hpp | 7 +++++++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index a6c525f2..85dfabb6 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -101,9 +101,9 @@ namespace Components Loader::Register(new StructuredData()); Loader::Register(new ConnectProtocol()); Loader::Register(new StartupMessages()); + Loader::Register(new XInput()); Loader::Register(new Client()); - Loader::Register(new XInput()); Loader::Pregame = false; } diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/XInput.cpp index bd5e0e2e..26d1b079 100644 --- a/src/Components/Modules/XInput.cpp +++ b/src/Components/Modules/XInput.cpp @@ -11,6 +11,13 @@ namespace Components std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool XInput::isHoldingMaxLookX = false; bool XInput::isADS; + + Dvar::Var XInput::xpadSensitivity; + Dvar::Var XInput::xpadEarlyTime; + Dvar::Var XInput::xpadEarlyMultiplier; + Dvar::Var XInput::xpadHorizontalMultiplier; + Dvar::Var XInput::xpadVerticalMultiplier; + Dvar::Var XInput::xpadAdsMultiplier; float XInput::lastMenuNavigationDirection = .0f; std::chrono::milliseconds XInput::lastNavigationTime = 0ms; @@ -380,12 +387,12 @@ namespace Components { XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - float viewSensitivityMultiplier = Dvar::Var("xpad_sensitivity").get() * XINPUT_SENSITIVITY_MULTIPLIER; + float viewSensitivityMultiplier = xpadSensitivity.get() * XINPUT_SENSITIVITY_MULTIPLIER; - float lockedSensitivityMultiplier = Dvar::Var("xpad_early_multiplier").get(); - float generalXSensitivityMultiplier = Dvar::Var("xpad_horizontal_multiplier").get(); - float generalYSensitivityMultiplier = Dvar::Var("xpad_vertical_multiplier").get(); - std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(Dvar::Var("xpad_early_time").get()); + float lockedSensitivityMultiplier = xpadEarlyMultiplier.get(); + float generalXSensitivityMultiplier = xpadHorizontalMultiplier.get(); + float generalYSensitivityMultiplier = xpadVerticalMultiplier.get(); + std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(xpadEarlyTime.get()); float viewStickX, viewStickY; GetRightStick01Value(xiState, viewStickX, viewStickY); @@ -416,8 +423,6 @@ namespace Components XInput::isHoldingMaxLookX = false; XInput::timeAtFirstHeldMaxLookX = 0ms; viewStickX *= lockedSensitivityMultiplier; - - Components::Logger::Print("multiplier will be %f\n", lockedSensitivityMultiplier); } float adsMultiplier = 1.0f; @@ -426,7 +431,7 @@ namespace Components // DO NOT use clientActive->usingAds ! It only works for toggle ADS if (Game::PM_IsAdsAllowed(ps) && XInput::isADS) { - adsMultiplier = Dvar::Var("xpad_ads_multiplier").get(); + adsMultiplier = xpadAdsMultiplier.get(); } if (viewStickX != 0 || viewStickY != 0) { @@ -512,13 +517,13 @@ namespace Components Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - Game::Dvar_RegisterFloat("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); - Game::Dvar_RegisterInt("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); - Game::Dvar_RegisterFloat("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); - Game::Dvar_RegisterFloat("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); - Game::Dvar_RegisterFloat("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); - Game::Dvar_RegisterFloat("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); - + XInput::xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + XInput::xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); + XInput::xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); + XInput::xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); + XInput::xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); + XInput::xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); + PollXInputDevices(); if (xiPlayerNum >= 0) { diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/XInput.hpp index 7339e09b..60f2821e 100644 --- a/src/Components/Modules/XInput.hpp +++ b/src/Components/Modules/XInput.hpp @@ -48,6 +48,13 @@ namespace Components static std::chrono::milliseconds msBetweenNavigations; static float lastMenuNavigationDirection; + static Dvar::Var XInput::xpadSensitivity; + static Dvar::Var XInput::xpadEarlyTime; + static Dvar::Var XInput::xpadEarlyMultiplier; + static Dvar::Var XInput::xpadHorizontalMultiplier; + static Dvar::Var XInput::xpadVerticalMultiplier; + static Dvar::Var XInput::xpadAdsMultiplier; + static void CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my); static int unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode); From 64fdd043437dec41dde3925b2e908088b6ece5e7 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 21 Aug 2021 15:15:42 +0200 Subject: [PATCH 24/83] Rename XInput patch to Gamepad --- src/Components/Loader.hpp | 2 +- src/Components/Modules/{XInput.cpp => Gamepad.cpp} | 0 src/Components/Modules/{XInput.hpp => Gamepad.hpp} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/Components/Modules/{XInput.cpp => Gamepad.cpp} (100%) rename src/Components/Modules/{XInput.hpp => Gamepad.hpp} (100%) diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 82483cd0..8f55d1f1 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -131,5 +131,5 @@ namespace Components #include "Modules/StartupMessages.hpp" #include "Modules/Stats.hpp" -#include "Modules/XInput.hpp" +#include "Modules/Gamepad.hpp" #include "Modules/Client.hpp" diff --git a/src/Components/Modules/XInput.cpp b/src/Components/Modules/Gamepad.cpp similarity index 100% rename from src/Components/Modules/XInput.cpp rename to src/Components/Modules/Gamepad.cpp diff --git a/src/Components/Modules/XInput.hpp b/src/Components/Modules/Gamepad.hpp similarity index 100% rename from src/Components/Modules/XInput.hpp rename to src/Components/Modules/Gamepad.hpp From d4d1520f65d8fe7b33e211325eb4cb39787c060e Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 21 Aug 2021 15:16:51 +0200 Subject: [PATCH 25/83] =?UTF-8?q?=EF=BB=BFImplement=20cod=20native=20contr?= =?UTF-8?q?oller=20support=20like=20xinput=20value=20retrieval?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Components/Loader.cpp | 2 +- src/Components/Modules/Gamepad.cpp | 613 +++++++++++++++++++---------- src/Components/Modules/Gamepad.hpp | 184 ++++++--- src/Game/Functions.cpp | 13 +- src/Game/Functions.hpp | 3 +- 5 files changed, 533 insertions(+), 282 deletions(-) diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 85dfabb6..514a33a8 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -101,7 +101,7 @@ namespace Components Loader::Register(new StructuredData()); Loader::Register(new ConnectProtocol()); Loader::Register(new StartupMessages()); - Loader::Register(new XInput()); + Loader::Register(new Gamepad()); Loader::Register(new Client()); diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 26d1b079..c5a6c8b7 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1,154 +1,117 @@ #include "STDInclude.hpp" +#include + #define XINPUT_SENSITIVITY_MULTIPLIER 4 // Arbitrary value I multiply the xinput senstivity dvar with to get nicer values (0-10 range or something) #define SIGN(d) ((d > 0) - (d < 0)) namespace Components { - XINPUT_STATE XInput::xiStates[XUSER_MAX_COUNT]; - XINPUT_STATE XInput::lastXiState = { 0 }; - int XInput::xiPlayerNum = -1; - std::chrono::milliseconds XInput::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) - bool XInput::isHoldingMaxLookX = false; - bool XInput::isADS; - - Dvar::Var XInput::xpadSensitivity; - Dvar::Var XInput::xpadEarlyTime; - Dvar::Var XInput::xpadEarlyMultiplier; - Dvar::Var XInput::xpadHorizontalMultiplier; - Dvar::Var XInput::xpadVerticalMultiplier; - Dvar::Var XInput::xpadAdsMultiplier; + Gamepad::GamePad Gamepad::gamePads[1]{}; + std::chrono::milliseconds Gamepad::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) + bool Gamepad::isHoldingMaxLookX = false; + bool Gamepad::isADS; - float XInput::lastMenuNavigationDirection = .0f; - std::chrono::milliseconds XInput::lastNavigationTime = 0ms; - std::chrono::milliseconds XInput::msBetweenNavigations = 220ms; + Dvar::Var Gamepad::gpad_enabled; + Dvar::Var Gamepad::gpad_debug; + Dvar::Var Gamepad::gpad_present; + Dvar::Var Gamepad::gpad_sticksConfig; + Dvar::Var Gamepad::gpad_buttonConfig; + Dvar::Var Gamepad::gpad_menu_scroll_delay_first; + Dvar::Var Gamepad::gpad_menu_scroll_delay_rest; + Dvar::Var Gamepad::gpad_rumble; + Dvar::Var Gamepad::gpad_stick_pressed_hysteresis; + Dvar::Var Gamepad::gpad_stick_pressed; + Dvar::Var Gamepad::gpad_stick_deadzone_max; + Dvar::Var Gamepad::gpad_stick_deadzone_min; + Dvar::Var Gamepad::gpad_button_deadzone; + Dvar::Var Gamepad::gpad_button_rstick_deflect_max; + Dvar::Var Gamepad::gpad_button_lstick_deflect_max; + + Dvar::Var Gamepad::xpadSensitivity; + Dvar::Var Gamepad::xpadEarlyTime; + Dvar::Var Gamepad::xpadEarlyMultiplier; + Dvar::Var Gamepad::xpadHorizontalMultiplier; + Dvar::Var Gamepad::xpadVerticalMultiplier; + Dvar::Var Gamepad::xpadAdsMultiplier; + + Gamepad::GamePadStickDir Gamepad::lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; + std::chrono::milliseconds Gamepad::lastNavigationTime = 0ms; + std::chrono::milliseconds Gamepad::msBetweenNavigations = 220ms; // This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg - std::vector mappings = { - XInput::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), - XInput::ActionMapping(XINPUT_GAMEPAD_B, "stance"), - XInput::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), - XInput::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), - XInput::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), - XInput::ActionMapping(XINPUT_GAMEPAD_RIGHT_SHOULDER, "frag"), - XInput::ActionMapping(XINPUT_GAMEPAD_LEFT_THUMB, "breath_sprint"), - XInput::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), - XInput::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), - XInput::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 3"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 2"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 1"), - XInput::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), + std::vector mappings = { + Gamepad::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_B, "stance"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), + Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_SHOULDER, "frag"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_THUMB, "breath_sprint"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), + Gamepad::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 3"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 2"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 1"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), }; // Same thing - std::vector menuMappings = { - XInput::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), - XInput::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), - XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW), - XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW), - XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW), - XInput::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) + std::vector menuMappings = { + Gamepad::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), + Gamepad::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) }; - void XInput::GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y) { - GamepadStickTo01(xiState->Gamepad.sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, x); - GamepadStickTo01(xiState->Gamepad.sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, y); - } +// void Gamepad::Vibrate(int leftVal, int rightVal) +// { +// // Create a Vibraton State +// XINPUT_VIBRATION Vibration; +// +// // Zeroise the Vibration +// ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); +// +// // Set the Vibration Values +// Vibration.wLeftMotorSpeed = leftVal; +// Vibration.wRightMotorSpeed = rightVal; +// +// // Vibrate the controller +// XInputSetState(xiPlayerNum, &Vibration); +// } - void XInput::GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y) { - GamepadStickTo01(xiState->Gamepad.sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, x); - GamepadStickTo01(xiState->Gamepad.sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, y); - } - - void XInput::GamepadStickTo01(SHORT value, SHORT deadzone, float& output01) { - float maxValue = (float)(std::numeric_limits().max() - deadzone); - - output01 = abs(value) > deadzone ? (value - deadzone * SIGN(value)) / maxValue : .0f; - - // log2 allows for a more neat value curve from 0 to 1 - // It is not functional yet, because I suck at maths - //float test = (log2(abs(output01) + 1.f) - 1.f) * SIGN(value); - } - - void XInput::Vibrate(int leftVal, int rightVal) + void Gamepad::CL_GamepadMove(int, Game::usercmd_s* cmd) { - // Create a Vibraton State - XINPUT_VIBRATION Vibration; + auto& gamePad = gamePads[0]; - // Zeroise the Vibration - ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); - - // Set the Vibration Values - Vibration.wLeftMotorSpeed = leftVal; - Vibration.wRightMotorSpeed = rightVal; - - // Vibrate the controller - XInputSetState(xiPlayerNum, &Vibration); - } - - - void XInput::PollXInputDevices() - { - XInput::xiPlayerNum = -1; - - for (int i = XUSER_MAX_COUNT - 1; i >= 0; i--) + if (gamePad.enabled) { - if (XInputGetState(i, &xiStates[i]) == ERROR_SUCCESS) - XInput::xiPlayerNum = i; - } - } - - __declspec(naked) void XInput::CL_FrameStub() - { - __asm - { - // poll the xinput devices on every client frame - call XInput::PollXInputDevices - - // execute the code we patched over - sub esp, 0Ch - push ebx - push ebp - push esi - - // return back to original code - push 0x486976 - retn - } - } - - void XInput::CL_GamepadMove(int, Game::usercmd_s* cmd) - { - if (XInput::xiPlayerNum != -1) - { - XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - - // Deadzones - float moveStickX, moveStickY; - GetLeftStick01Value(xiState, moveStickX, moveStickY); - - if (moveStickX != 0 || moveStickY != 0) { + if (std::fabs(gamePad.sticks[0]) > 0.0f || std::fabs(gamePad.sticks[1]) > 0.0f) { // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in - cmd->rightmove = moveStickX * std::numeric_limits().max(); - cmd->forwardmove = moveStickY * std::numeric_limits().max(); + cmd->rightmove = static_cast(gamePad.sticks[0] * static_cast(std::numeric_limits().max())); + cmd->forwardmove = static_cast(gamePad.sticks[1] * static_cast(std::numeric_limits().max())); } - bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; - if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + const bool pressingLeftTrigger = gamePad.analogs[0] > TRIGGER_THRESHOLD_F; + const bool previouslyPressingLeftTrigger = gamePad.lastAnalogs[0] > TRIGGER_THRESHOLD_F; + if (pressingLeftTrigger != previouslyPressingLeftTrigger) { if (pressingLeftTrigger) { Command::Execute("+speed_throw"); - XInput::isADS = true; + isADS = true; } else { Command::Execute("-speed_throw"); - XInput::isADS = false; + isADS = false; } } - bool pressingRightTrigger = xiState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; - if (pressingRightTrigger != XInput::lastXiState.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; + const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; + if (pressingRightTrigger != previouslyPressingRightTrigger) { if (pressingRightTrigger) { Command::Execute("+attack"); @@ -159,9 +122,9 @@ namespace Components } // Buttons (on/off) mappings - for (size_t i = 0; i < mappings.size(); i++) - { - auto mapping = mappings[i]; + for (auto& i : mappings) + { + auto mapping = i; auto action = mapping.action; auto antiAction = mapping.action; @@ -170,40 +133,38 @@ namespace Components antiAction = "-" + mapping.action; } else if (mapping.wasPressed) { - if (xiState->Gamepad.wButtons & mapping.input) { + if (gamePad.digitals & mapping.input) { // Button still pressed, do not send info } else { - mappings[i].wasPressed = false; + i.wasPressed = false; } continue; } - if (xiState->Gamepad.wButtons & mapping.input) { - if (mapping.spamWhenHeld || !mappings[i].wasPressed) { - Command::Execute(action.c_str()); + if (gamePad.digitals & mapping.input) { + if (mapping.spamWhenHeld || !i.wasPressed) { + Command::Execute(action); } - mappings[i].wasPressed = true; + i.wasPressed = true; } else if (mapping.isReversible && mapping.wasPressed) { - mappings[i].wasPressed = false; - Command::Execute(antiAction.c_str()); + i.wasPressed = false; + Command::Execute(antiAction); } } - - memcpy(&XInput::lastXiState, xiState, sizeof XINPUT_STATE); } } - __declspec(naked) void XInput::CL_CreateCmdStub() + __declspec(naked) void Gamepad::CL_CreateCmdStub() { __asm { // do xinput! push esi push ebp - call XInput::CL_GamepadMove + call CL_GamepadMove add esp, 8h // execute code we patched over @@ -217,7 +178,7 @@ namespace Components } } - __declspec(naked) void XInput::MSG_WriteDeltaUsercmdKeyStub() + __declspec(naked) void Gamepad::MSG_WriteDeltaUsercmdKeyStub() { __asm { @@ -241,7 +202,7 @@ namespace Components } } - void XInput::ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to) + void Gamepad::ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to) { char forward; char right; @@ -263,7 +224,7 @@ namespace Components to->rightmove = right; } - __declspec(naked) void XInput::MSG_ReadDeltaUsercmdKeyStub() + __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub() { __asm { @@ -271,7 +232,7 @@ namespace Components push ebp // from push edi // key push esi // msg - call XInput::ApplyMovement + call ApplyMovement add esp, 10h // return back @@ -280,7 +241,7 @@ namespace Components } } - __declspec(naked) void XInput::MSG_ReadDeltaUsercmdKeyStub2() + __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub2() { __asm { @@ -288,7 +249,7 @@ namespace Components push ebp // from push edi // key push esi // msg - call XInput::ApplyMovement + call ApplyMovement add esp, 10h // return back @@ -299,72 +260,66 @@ namespace Components } } - void XInput::MenuNavigate() { - + void Gamepad::MenuNavigate() + { + auto& gamePad = gamePads[0]; Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext); - if (menuDef) { - PollXInputDevices(); - - if (XInput::xiPlayerNum != -1) + if (menuDef) + { + if (gamePad.enabled) { - XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - - // Up/Down - float moveStickY = abs(xiState->Gamepad.sThumbLY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE ? xiState->Gamepad.sThumbLY / (float)std::numeric_limits().max() : .0f; - std::chrono::milliseconds now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime; bool canNavigate = timeSinceLastNavigation > msBetweenNavigations; - if (moveStickY > .0f) { - if (canNavigate || SIGN(moveStickY) != SIGN(lastMenuNavigationDirection)) { + if (gamePad.stickDown[1][GPAD_STICK_POS]) { + if (canNavigate) { Game::Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = moveStickY; + lastMenuNavigationDirection = GPAD_STICK_POS; lastNavigationTime = now; } } - else if (moveStickY < .0f) { - if (canNavigate || SIGN(moveStickY) != SIGN(lastMenuNavigationDirection)) { + else if (gamePad.stickDown[1][GPAD_STICK_NEG]) { + if (canNavigate) { Game::Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = moveStickY; + lastMenuNavigationDirection = GPAD_STICK_NEG; lastNavigationTime = now; } } else { - lastMenuNavigationDirection = .0f; + lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; } - for (size_t i = 0; i < menuMappings.size(); i++) - { - MenuMapping mapping = menuMappings[i]; - + for (auto& mapping : menuMappings) + { if (mapping.wasPressed) { - if (xiState->Gamepad.wButtons & mapping.input) { + if (gamePad.digitals & mapping.input) { // Button still pressed, do not send info } else { - menuMappings[i].wasPressed = false; + mapping.wasPressed = false; } } - else if (xiState->Gamepad.wButtons & mapping.input) { + else if (gamePad.digitals & mapping.input) { Game::UI_KeyEvent(0, mapping.keystroke, 1); - menuMappings[i].wasPressed = true; + mapping.wasPressed = true; } } } } } - int XInput::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) { + int Gamepad::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) + { + const auto& gamePad = gamePads[0]; - if (XInput::xiPlayerNum != -1) + if (gamePad.enabled) { - XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - if (keyCode == Game::keyNum_t::K_MOUSE2) { - bool pressingLeftTrigger = xiState->Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; - if (pressingLeftTrigger != XInput::lastXiState.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + const bool pressingLeftTrigger = gamePad.analogs[0] > TRIGGER_THRESHOLD_F; + const bool previouslyPressingLeftTrigger = gamePad.lastAnalogs[0] > TRIGGER_THRESHOLD_F; + if (pressingLeftTrigger != previouslyPressingLeftTrigger) { if (pressingLeftTrigger) { return 1; @@ -376,17 +331,17 @@ namespace Components } } - Utils::Hook::Call(0x48B2D0)(localClientNum, keyCode); + return Utils::Hook::Call(0x48B2D0)(localClientNum, keyCode); } - void XInput::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) { + void Gamepad::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) + { + Gamepad::CL_GetMouseMovementCl(clientActive, mx, my); - XInput::CL_GetMouseMovementCl(clientActive, mx, my); + const auto& gamePad = gamePads[0]; - if (XInput::xiPlayerNum != -1) + if (gamePad.enabled) { - XINPUT_STATE* xiState = &xiStates[xiPlayerNum]; - float viewSensitivityMultiplier = xpadSensitivity.get() * XINPUT_SENSITIVITY_MULTIPLIER; float lockedSensitivityMultiplier = xpadEarlyMultiplier.get(); @@ -394,21 +349,17 @@ namespace Components float generalYSensitivityMultiplier = xpadVerticalMultiplier.get(); std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(xpadEarlyTime.get()); - float viewStickX, viewStickY; - GetRightStick01Value(xiState, viewStickX, viewStickY); - -#ifdef DEBUG - Components::Logger::Print("X:%f \nY:%f\n(holdingMaxX: %d)\n", viewStickX, viewStickY, XInput::isHoldingMaxLookX); -#endif + float viewStickX = gamePad.sticks[2]; + float viewStickY = gamePad.sticks[3]; // Gamepad horizontal acceleration on view if (abs(viewStickX) > 0.80f) { - if (!XInput::isHoldingMaxLookX) { - XInput::isHoldingMaxLookX = true; - XInput::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + if (!Gamepad::isHoldingMaxLookX) { + Gamepad::isHoldingMaxLookX = true; + Gamepad::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); } else { - std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - XInput::timeAtFirstHeldMaxLookX; + std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - Gamepad::timeAtFirstHeldMaxLookX; #ifdef STEP_SENSITIVITY if (hasBeenHoldingLeftXForMs < msBeforeUnlockingSensitivity) { viewStickX *= lockedSensitivityMultiplier; @@ -420,8 +371,8 @@ namespace Components } } else { - XInput::isHoldingMaxLookX = false; - XInput::timeAtFirstHeldMaxLookX = 0ms; + Gamepad::isHoldingMaxLookX = false; + Gamepad::timeAtFirstHeldMaxLookX = 0ms; viewStickX *= lockedSensitivityMultiplier; } @@ -430,7 +381,7 @@ namespace Components auto ps = &clientActive->snap.ps; // DO NOT use clientActive->usingAds ! It only works for toggle ADS - if (Game::PM_IsAdsAllowed(ps) && XInput::isADS) { + if (Game::PM_IsAdsAllowed(ps) && Gamepad::isADS) { adsMultiplier = xpadAdsMultiplier.get(); } @@ -440,8 +391,9 @@ namespace Components } // Handling killstreaks - bool pressingRightTrigger = xiState->Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD ? true : false; - if (pressingRightTrigger != XInput::lastXiState.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) + const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; + const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; + if (pressingRightTrigger != previouslyPressingRightTrigger) { bool* isInPredator = reinterpret_cast(0x8EE3B8); @@ -459,7 +411,6 @@ namespace Components } - // Game -> Client DLL __declspec(naked) void CL_GetMouseMovementStub() { @@ -468,15 +419,14 @@ namespace Components push edx; push ecx; push eax; - call XInput::MouseOverride; + call Gamepad::MouseOverride; add esp, 0xC; ret; } } - // Client DLL -> Game - void XInput::CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my) + void Gamepad::CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my) { __asm { @@ -494,42 +444,269 @@ namespace Components } } - XInput::XInput() + bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) { - // poll xinput devices every client frame - Utils::Hook(0x486970, XInput::CL_FrameStub, HOOK_JUMP).install()->quick(); + auto& gamePad = gamePads[gamePadIndex]; + + if (XInputGetCapabilities(portIndex, XINPUT_FLAG_GAMEPAD, &gamePad.caps) == ERROR_SUCCESS) + { + gamePad.enabled = true; + gamePad.portIndex = portIndex; + return true; + } + + gamePad.enabled = false; + return false; + } + + void Gamepad::GPad_RefreshAll() + { + auto currentGamePadNum = 0; + + for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < MAX_GAMEPADS; currentPort++) + { + if (GPad_Check(currentGamePadNum, currentPort)) + currentGamePadNum++; + } + } + + void Gamepad::GPad_ConvertStickToFloat(const short x, const short y, float& outX, float& outY) + { + Game::vec2_t stickVec; + stickVec[0] = static_cast(x) / static_cast(std::numeric_limits::max()); + stickVec[1] = static_cast(y) / static_cast(std::numeric_limits::max()); + + const auto deadZoneTotal = gpad_stick_deadzone_min.get() + gpad_stick_deadzone_max.get(); + auto len = Game::Vec2Normalize(stickVec); + + if (gpad_stick_deadzone_min.get() <= len) + { + if (1.0f - gpad_stick_deadzone_max.get() >= len) + len = (len - gpad_stick_deadzone_min.get()) / (1.0f - deadZoneTotal); + else + len = 1.0f; + } + else + len = 0.0f; + + outX = stickVec[0] * len; + outY = stickVec[1] * len; + } + + void Gamepad::GPad_UpdateSticksDown(int gamePadIndex) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + for(auto stickIndex = 0u; stickIndex < std::extent_v; stickIndex++) + { + for(auto dir = 0; dir < GPAD_STICK_DIR_COUNT; dir++) + { + gamePad.stickDownLast[stickIndex][dir] = gamePad.stickDown[stickIndex][dir]; + + auto threshold = gpad_stick_pressed.get(); + + if (gamePad.stickDownLast[stickIndex][dir]) + threshold -= gpad_stick_pressed_hysteresis.get(); + else + threshold += gpad_stick_pressed_hysteresis.get(); + + if(dir == GPAD_STICK_POS) + { + gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] > threshold; + } + else + { + assert(dir == GPAD_STICK_NEG); + gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] < -threshold; + } + } + } + } + + void Gamepad::GPad_UpdateSticks(const int gamePadIndex, const XINPUT_GAMEPAD& state) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + Game::vec2_t lVec, rVec; + GPad_ConvertStickToFloat(state.sThumbLX, state.sThumbLY, lVec[0], lVec[1]); + GPad_ConvertStickToFloat(state.sThumbRX, state.sThumbRY, rVec[0], rVec[1]); + + gamePad.lastSticks[0] = gamePad.sticks[0]; + gamePad.sticks[0] = lVec[0]; + gamePad.lastSticks[1] = gamePad.sticks[1]; + gamePad.sticks[1] = lVec[1]; + gamePad.lastSticks[2] = gamePad.sticks[2]; + gamePad.sticks[2] = rVec[0]; + gamePad.lastSticks[3] = gamePad.sticks[3]; + gamePad.sticks[3] = rVec[1]; + + GPad_UpdateSticksDown(gamePadIndex); + + #ifdef DEBUG + if(gpad_debug.get()) + { + Logger::Print("Left: X: %f Y: %f\n", lVec[0], lVec[1]); + Logger::Print("Right: X: %f Y: %f\n", rVec[0], rVec[1]); + Logger::Print("Down: %i:%i %i:%i %i:%i %i:%i\n", gamePad.stickDown[0][GPAD_STICK_POS], gamePad.stickDown[0][GPAD_STICK_NEG], + gamePad.stickDown[1][GPAD_STICK_POS], gamePad.stickDown[1][GPAD_STICK_NEG], + gamePad.stickDown[2][GPAD_STICK_POS], gamePad.stickDown[2][GPAD_STICK_NEG], + gamePad.stickDown[3][GPAD_STICK_POS], gamePad.stickDown[3][GPAD_STICK_NEG]); + } + #endif + } + + void Gamepad::GPad_UpdateDigitals(const int gamePadIndex, const XINPUT_GAMEPAD& state) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + gamePad.lastDigitals = gamePad.digitals; + gamePad.digitals = state.wButtons; + + const auto leftDeflect = gpad_button_lstick_deflect_max.get(); + if(std::fabs(gamePad.sticks[0]) > leftDeflect || std::fabs(gamePad.sticks[1]) > leftDeflect) + gamePad.digitals &= ~static_cast(XINPUT_GAMEPAD_LEFT_THUMB); + const auto rightDeflect = gpad_button_rstick_deflect_max.get(); + if(std::fabs(gamePad.sticks[2]) > leftDeflect || std::fabs(gamePad.sticks[3]) > rightDeflect) + gamePad.digitals &= ~static_cast(XINPUT_GAMEPAD_RIGHT_THUMB); + +#ifdef DEBUG + if (gpad_debug.get()) + { + Logger::Print("Buttons: %x\n", gamePad.digitals); + } +#endif + } + + void Gamepad::GPad_UpdateAnalogs(const int gamePadIndex, const XINPUT_GAMEPAD& state) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + const auto buttonDeadZone = gpad_button_deadzone.get(); + + gamePad.lastAnalogs[0] = gamePad.analogs[0]; + gamePad.analogs[0] = static_cast(state.bLeftTrigger) / static_cast(std::numeric_limits::max()); + if (gamePad.analogs[0] < buttonDeadZone) + gamePad.analogs[0] = 0.0f; + + + gamePad.lastAnalogs[1] = gamePad.analogs[1]; + gamePad.analogs[1] = static_cast(state.bRightTrigger) / static_cast(std::numeric_limits::max()); + if (gamePad.analogs[1] < buttonDeadZone) + gamePad.analogs[1] = 0.0f; + +#ifdef DEBUG + if (gpad_debug.get()) + { + Logger::Print("Triggers: %f %f\n", gamePad.analogs[0], gamePad.analogs[1]); + } +#endif + } + + void Gamepad::GPad_UpdateAll() + { + GPad_RefreshAll(); + + for(auto currentGamePadIndex = 0; currentGamePadIndex < MAX_GAMEPADS; currentGamePadIndex++) + { + const auto& gamePad = gamePads[currentGamePadIndex]; + if(!gamePad.enabled) + continue; + + XINPUT_STATE inputState; + if(XInputGetState(gamePad.portIndex, &inputState) != ERROR_SUCCESS) + continue; + + GPad_UpdateSticks(currentGamePadIndex, inputState.Gamepad); + GPad_UpdateDigitals(currentGamePadIndex, inputState.Gamepad); + GPad_UpdateAnalogs(currentGamePadIndex, inputState.Gamepad); + } + } + + void Gamepad::IN_GamePadsMove() + { + GPad_UpdateAll(); + } + + + void Gamepad::IN_Frame_Hk() + { + // Call original method + Utils::Hook::Call(0x64C490)(); + + IN_GamePadsMove(); + } + + void Gamepad::InitDvars() + { + gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); + gpad_debug = Dvar::Register("gpad_debug", false, 0, "Game pad debugging"); + gpad_present = Dvar::Register("gpad_present", false, 0, "Game pad present"); + gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "thumbstick_default", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); + gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "buttons_default", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); + gpad_menu_scroll_delay_first = Dvar::Register("gpad_menu_scroll_delay_first", 420, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for the first repeat, in milliseconds"); + gpad_menu_scroll_delay_rest = Dvar::Register("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for repeats after the first, in milliseconds"); + gpad_rumble = Dvar::Register("gpad_rumble", true, Game::DVAR_FLAG_SAVED, "Enable game pad rumble"); + gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, 0, "Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing"); + gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, 0, "Game pad stick pressed threshhold"); + gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, 0, "Game pad maximum stick deadzone"); + gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, 0, "Game pad minimum stick deadzone"); + gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, 0, "Game pad button deadzone threshhold"); + gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); + gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); + } + + void Gamepad::IN_Init_Hk() + { + // Call original method + Utils::Hook::Call(0x45D620)(); + + InitDvars(); + } + + Gamepad::Gamepad() + { + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) + return; + + Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); + + Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); // use the xinput state when creating a usercmd - Utils::Hook(0x5A6DB9, XInput::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5A6DB9, Gamepad::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); // package the forward and right move components in the move buttons - Utils::Hook(0x60E38D, XInput::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x60E38D, Gamepad::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); // send two bytes for sending movement data Utils::Hook::Set(0x60E501, 16); Utils::Hook::Set(0x60E5CD, 16); // make sure to parse the movement data properly and apply it - Utils::Hook(0x492127, XInput::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); - Utils::Hook(0x492009, XInput::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492127, Gamepad::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492009, Gamepad::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - XInput::xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); - XInput::xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); - XInput::xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); - XInput::xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); - XInput::xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); - XInput::xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); - - PollXInputDevices(); - - if (xiPlayerNum >= 0) { - Vibrate(3000, 3000); - } - Scheduler::OnFrame(MenuNavigate); + + xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); + xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); + xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); + xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); + xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); + + MessageBoxA(NULL, __FUNCTION__, "", 0); } } diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 60f2821e..c68d97ca 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -2,81 +2,143 @@ namespace Components { - class XInput : public Component - { - public: - XInput(); + class Gamepad : public Component + { + static constexpr auto MAX_GAMEPADS = 1; + static constexpr float TRIGGER_THRESHOLD_F = static_cast(XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / static_cast(0xFF); - struct ActionMapping { - int input; - std::string action; - bool isReversible; - bool wasPressed = false; - bool spamWhenHeld = false; + public: - ActionMapping(int input, std::string action, bool isReversible = true, bool spamWhenHeld = false) - { - this->action = action; - this->isReversible = isReversible; - this->input = input; - this->spamWhenHeld = spamWhenHeld; - } - }; + Gamepad(); + enum GamePadStickDir + { + GPAD_STICK_POS = 0x0, + GPAD_STICK_NEG = 0x1, - struct MenuMapping { - int input; - Game::keyNum_t keystroke; - bool wasPressed = false; + GPAD_STICK_DIR_COUNT + }; + + struct GamePad + { + bool enabled; + int portIndex; + unsigned short digitals; + unsigned short lastDigitals; + float analogs[2]; + float lastAnalogs[2]; + float sticks[4]; + float lastSticks[4]; + bool stickDown[4][GPAD_STICK_DIR_COUNT]; + bool stickDownLast[4][GPAD_STICK_DIR_COUNT]; + float lowRumble; + float highRumble; - MenuMapping(int input, Game::keyNum_t keystroke) - { - this->keystroke = keystroke; - this->input = input; - } - }; + XINPUT_VIBRATION rumble; + XINPUT_CAPABILITIES caps; + }; - private: - static XINPUT_STATE xiStates[XUSER_MAX_COUNT]; - static int xiPlayerNum; - static XINPUT_STATE lastXiState; + struct ActionMapping + { + int input; + std::string action; + bool isReversible; + bool wasPressed = false; + bool spamWhenHeld = false; - static bool isHoldingMaxLookX; - static std::chrono::milliseconds timeAtFirstHeldMaxLookX; - static bool isADS; + ActionMapping(int input, std::string action, bool isReversible = true, bool spamWhenHeld = false) + { + this->action = action; + this->isReversible = isReversible; + this->input = input; + this->spamWhenHeld = spamWhenHeld; + } + }; - static std::chrono::milliseconds lastNavigationTime; - static std::chrono::milliseconds msBetweenNavigations; - static float lastMenuNavigationDirection; + struct MenuMapping + { + int input; + Game::keyNum_t keystroke; + bool wasPressed = false; - static Dvar::Var XInput::xpadSensitivity; - static Dvar::Var XInput::xpadEarlyTime; - static Dvar::Var XInput::xpadEarlyMultiplier; - static Dvar::Var XInput::xpadHorizontalMultiplier; - static Dvar::Var XInput::xpadVerticalMultiplier; - static Dvar::Var XInput::xpadAdsMultiplier; + MenuMapping(int input, Game::keyNum_t keystroke) + { + this->keystroke = keystroke; + this->input = input; + } + }; - static void CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my); - static int unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode); + private: + static GamePad gamePads[MAX_GAMEPADS]; - static void MouseOverride(Game::clientActive_t* clientActive, float* my, float* mx); - static void Vibrate(int leftVal = 0, int rightVal = 0); + static bool isHoldingMaxLookX; + static std::chrono::milliseconds timeAtFirstHeldMaxLookX; + static bool isADS; - static void CL_FrameStub(); - static void PollXInputDevices(); + static std::chrono::milliseconds lastNavigationTime; + static std::chrono::milliseconds msBetweenNavigations; + static GamePadStickDir lastMenuNavigationDirection; - static void CL_CreateCmdStub(); - static void CL_GamepadMove(int, Game::usercmd_s*); - static void MenuNavigate(); + static Dvar::Var gpad_enabled; + static Dvar::Var gpad_debug; + static Dvar::Var gpad_present; + static Dvar::Var gpad_sticksConfig; + static Dvar::Var gpad_buttonConfig; + static Dvar::Var gpad_menu_scroll_delay_first; + static Dvar::Var gpad_menu_scroll_delay_rest; + static Dvar::Var gpad_rumble; + static Dvar::Var gpad_stick_pressed_hysteresis; + static Dvar::Var gpad_stick_pressed; + static Dvar::Var gpad_stick_deadzone_max; + static Dvar::Var gpad_stick_deadzone_min; + static Dvar::Var gpad_button_deadzone; + static Dvar::Var gpad_button_rstick_deflect_max; + static Dvar::Var gpad_button_lstick_deflect_max; - static void MSG_WriteDeltaUsercmdKeyStub(); + static Dvar::Var xpadSensitivity; + static Dvar::Var xpadEarlyTime; + static Dvar::Var xpadEarlyMultiplier; + static Dvar::Var xpadHorizontalMultiplier; + static Dvar::Var xpadVerticalMultiplier; + static Dvar::Var xpadAdsMultiplier; - static void ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to); + static void CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my); + static int unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode); - static void MSG_ReadDeltaUsercmdKeyStub(); - static void MSG_ReadDeltaUsercmdKeyStub2(); + static void MouseOverride(Game::clientActive_t* clientActive, float* my, float* mx); + static void Vibrate(int leftVal = 0, int rightVal = 0); - static void GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y); - static void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y); - static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); - }; + static void CL_FrameStub(); + static void PollXInputDevices(); + + static void CL_CreateCmdStub(); + static void CL_GamepadMove(int, Game::usercmd_s*); + static void MenuNavigate(); + + static void MSG_WriteDeltaUsercmdKeyStub(); + + static void ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to); + + static void MSG_ReadDeltaUsercmdKeyStub(); + static void MSG_ReadDeltaUsercmdKeyStub2(); + + static void GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y); + static void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y); + static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); + + static void GPad_ConvertStickToFloat(short x, short y, float& outX, float& outY); + + static void GPad_UpdateSticksDown(int gamePadIndex); + static void GPad_UpdateSticks(int gamePadIndex, const XINPUT_GAMEPAD& state); + static void GPad_UpdateDigitals(int gamePadIndex, const XINPUT_GAMEPAD& state); + static void GPad_UpdateAnalogs(int gamePadIndex, const XINPUT_GAMEPAD& state); + + static bool GPad_Check(int gamePadIndex, int portIndex); + static void GPad_RefreshAll(); + static void GPad_UpdateAll(); + static void IN_GamePadsMove(); + static void IN_Frame_Hk(); + + static void InitDvars(); + static void IN_Init_Hk(); + }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index a2b43cdb..8415b93d 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -704,12 +704,23 @@ namespace Game return atoi(StringTable_Lookup(rankTable, 0, maxrank, 7)); } - void Vec3Normalize(vec3_t& vec) + float Vec2Normalize(vec2_t& vec) + { + const float length = std::sqrt((vec[0] * vec[0]) + (vec[1] * vec[1])); + + vec[0] /= length; + vec[1] /= length; + + return length; + } + + float Vec3Normalize(vec3_t& vec) { const float length = static_cast(std::sqrt(std::pow(vec[0], 2) + std::pow(vec[1], 2) + std::pow(vec[2], 2))); vec[0] /= length; vec[1] /= length; vec[2] /= length; + return length; } void Vec2UnpackTexCoords(const PackedTexCoords in, vec2_t* out) diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 5166eb5b..37a243d6 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -936,7 +936,8 @@ namespace Game void Image_Setup(GfxImage* image, unsigned int width, unsigned int height, unsigned int depth, unsigned int flags, _D3DFORMAT format); - void Vec3Normalize(vec3_t& vec); + float Vec2Normalize(vec2_t& vec); + float Vec3Normalize(vec3_t& vec); void Vec2UnpackTexCoords(const PackedTexCoords in, vec2_t* out); void MatrixVecMultiply(const float(&mulMat)[3][3], const vec3_t& mulVec, vec3_t& solution); void QuatRot(vec3_t* vec, const vec4_t* quat); From ea8c35e063197bfead598661ddc895464eb8e202 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 21 Aug 2021 15:20:26 +0200 Subject: [PATCH 26/83] Reformatted gamepad patch --- src/Components/Modules/Gamepad.cpp | 1253 ++++++++++++++-------------- src/Components/Modules/Gamepad.hpp | 4 +- 2 files changed, 646 insertions(+), 611 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index c5a6c8b7..5289d3a7 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -7,706 +7,741 @@ namespace Components { - Gamepad::GamePad Gamepad::gamePads[1]{}; - std::chrono::milliseconds Gamepad::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) - bool Gamepad::isHoldingMaxLookX = false; - bool Gamepad::isADS; + Gamepad::GamePad Gamepad::gamePads[1]{}; + std::chrono::milliseconds Gamepad::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) + bool Gamepad::isHoldingMaxLookX = false; + bool Gamepad::isADS; - Dvar::Var Gamepad::gpad_enabled; - Dvar::Var Gamepad::gpad_debug; - Dvar::Var Gamepad::gpad_present; - Dvar::Var Gamepad::gpad_sticksConfig; - Dvar::Var Gamepad::gpad_buttonConfig; - Dvar::Var Gamepad::gpad_menu_scroll_delay_first; - Dvar::Var Gamepad::gpad_menu_scroll_delay_rest; - Dvar::Var Gamepad::gpad_rumble; - Dvar::Var Gamepad::gpad_stick_pressed_hysteresis; - Dvar::Var Gamepad::gpad_stick_pressed; - Dvar::Var Gamepad::gpad_stick_deadzone_max; - Dvar::Var Gamepad::gpad_stick_deadzone_min; - Dvar::Var Gamepad::gpad_button_deadzone; - Dvar::Var Gamepad::gpad_button_rstick_deflect_max; - Dvar::Var Gamepad::gpad_button_lstick_deflect_max; + Dvar::Var Gamepad::gpad_enabled; + Dvar::Var Gamepad::gpad_debug; + Dvar::Var Gamepad::gpad_present; + Dvar::Var Gamepad::gpad_sticksConfig; + Dvar::Var Gamepad::gpad_buttonConfig; + Dvar::Var Gamepad::gpad_menu_scroll_delay_first; + Dvar::Var Gamepad::gpad_menu_scroll_delay_rest; + Dvar::Var Gamepad::gpad_rumble; + Dvar::Var Gamepad::gpad_stick_pressed_hysteresis; + Dvar::Var Gamepad::gpad_stick_pressed; + Dvar::Var Gamepad::gpad_stick_deadzone_max; + Dvar::Var Gamepad::gpad_stick_deadzone_min; + Dvar::Var Gamepad::gpad_button_deadzone; + Dvar::Var Gamepad::gpad_button_rstick_deflect_max; + Dvar::Var Gamepad::gpad_button_lstick_deflect_max; - Dvar::Var Gamepad::xpadSensitivity; - Dvar::Var Gamepad::xpadEarlyTime; - Dvar::Var Gamepad::xpadEarlyMultiplier; - Dvar::Var Gamepad::xpadHorizontalMultiplier; - Dvar::Var Gamepad::xpadVerticalMultiplier; - Dvar::Var Gamepad::xpadAdsMultiplier; + Dvar::Var Gamepad::xpadSensitivity; + Dvar::Var Gamepad::xpadEarlyTime; + Dvar::Var Gamepad::xpadEarlyMultiplier; + Dvar::Var Gamepad::xpadHorizontalMultiplier; + Dvar::Var Gamepad::xpadVerticalMultiplier; + Dvar::Var Gamepad::xpadAdsMultiplier; - Gamepad::GamePadStickDir Gamepad::lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; - std::chrono::milliseconds Gamepad::lastNavigationTime = 0ms; - std::chrono::milliseconds Gamepad::msBetweenNavigations = 220ms; + Gamepad::GamePadStickDir Gamepad::lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; + std::chrono::milliseconds Gamepad::lastNavigationTime = 0ms; + std::chrono::milliseconds Gamepad::msBetweenNavigations = 220ms; - // This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg - std::vector mappings = { - Gamepad::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_B, "stance"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), - Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_SHOULDER, "frag"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_THUMB, "breath_sprint"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), - Gamepad::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 3"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 2"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 1"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), - }; + // This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg + std::vector mappings = { + Gamepad::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_B, "stance"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), + Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_SHOULDER, "frag"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_THUMB, "breath_sprint"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), + Gamepad::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 3"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 2"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 1"), + Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), + }; - // Same thing - std::vector menuMappings = { - Gamepad::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), - Gamepad::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) - }; + // Same thing + std::vector menuMappings = { + Gamepad::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), + Gamepad::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW), + Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) + }; -// void Gamepad::Vibrate(int leftVal, int rightVal) -// { -// // Create a Vibraton State -// XINPUT_VIBRATION Vibration; -// -// // Zeroise the Vibration -// ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); -// -// // Set the Vibration Values -// Vibration.wLeftMotorSpeed = leftVal; -// Vibration.wRightMotorSpeed = rightVal; -// -// // Vibrate the controller -// XInputSetState(xiPlayerNum, &Vibration); -// } + // void Gamepad::Vibrate(int leftVal, int rightVal) + // { + // // Create a Vibraton State + // XINPUT_VIBRATION Vibration; + // + // // Zeroise the Vibration + // ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); + // + // // Set the Vibration Values + // Vibration.wLeftMotorSpeed = leftVal; + // Vibration.wRightMotorSpeed = rightVal; + // + // // Vibrate the controller + // XInputSetState(xiPlayerNum, &Vibration); + // } - void Gamepad::CL_GamepadMove(int, Game::usercmd_s* cmd) - { - auto& gamePad = gamePads[0]; + void Gamepad::CL_GamepadMove(int, Game::usercmd_s* cmd) + { + auto& gamePad = gamePads[0]; - if (gamePad.enabled) - { - if (std::fabs(gamePad.sticks[0]) > 0.0f || std::fabs(gamePad.sticks[1]) > 0.0f) { - // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in - cmd->rightmove = static_cast(gamePad.sticks[0] * static_cast(std::numeric_limits().max())); - cmd->forwardmove = static_cast(gamePad.sticks[1] * static_cast(std::numeric_limits().max())); - } + if (gamePad.enabled) + { + if (std::fabs(gamePad.sticks[0]) > 0.0f || std::fabs(gamePad.sticks[1]) > 0.0f) + { + // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in + cmd->rightmove = static_cast(gamePad.sticks[0] * static_cast(std::numeric_limits().max())); + cmd->forwardmove = static_cast(gamePad.sticks[1] * static_cast(std::numeric_limits().max())); + } const bool pressingLeftTrigger = gamePad.analogs[0] > TRIGGER_THRESHOLD_F; const bool previouslyPressingLeftTrigger = gamePad.lastAnalogs[0] > TRIGGER_THRESHOLD_F; - if (pressingLeftTrigger != previouslyPressingLeftTrigger) - { - if (pressingLeftTrigger) { - Command::Execute("+speed_throw"); - isADS = true; - } - else { - Command::Execute("-speed_throw"); - isADS = false; - } - } - - const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; - const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; - if (pressingRightTrigger != previouslyPressingRightTrigger) - { - if (pressingRightTrigger) { - Command::Execute("+attack"); - } - else { - Command::Execute("-attack"); - } - } - - // Buttons (on/off) mappings - for (auto& i : mappings) + if (pressingLeftTrigger != previouslyPressingLeftTrigger) { - auto mapping = i; - auto action = mapping.action; - auto antiAction = mapping.action; - - if (mapping.isReversible) { - action = "+" + mapping.action; - antiAction = "-" + mapping.action; - } - else if (mapping.wasPressed) { - if (gamePad.digitals & mapping.input) { - // Button still pressed, do not send info - } - else { - i.wasPressed = false; - } - - continue; - } - - if (gamePad.digitals & mapping.input) { - if (mapping.spamWhenHeld || !i.wasPressed) { - Command::Execute(action); - } - i.wasPressed = true; - } - else if (mapping.isReversible && mapping.wasPressed) { - i.wasPressed = false; - Command::Execute(antiAction); - } - } - } - } - - __declspec(naked) void Gamepad::CL_CreateCmdStub() - { - __asm - { - // do xinput! - push esi - push ebp - call CL_GamepadMove - add esp, 8h - - // execute code we patched over - add esp, 4 - fld st - pop ebx - - // return back - push 0x5A6DBF - retn - } - } - - __declspec(naked) void Gamepad::MSG_WriteDeltaUsercmdKeyStub() - { - __asm - { - // fix stack pointer - add esp, 0Ch - - // put both forward move and rightmove values in the movement button - mov dl, byte ptr[edi + 1Ah] // to_forwardMove - mov dh, byte ptr[edi + 1Bh] // to_rightMove - - mov[esp + 30h], dx // to_buttons - - mov dl, byte ptr[ebp + 1Ah] // from_forwardMove - mov dh, byte ptr[ebp + 1Bh] // from_rightMove - - mov[esp + 2Ch], dx // from_buttons - - // return back - push 0x60E40E - retn - } - } - - void Gamepad::ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to) - { - char forward; - char right; - - if (Game::MSG_ReadBit(msg)) - { - short movementBits = static_cast(key ^ Game::MSG_ReadBits(msg, 16)); - - forward = static_cast(movementBits); - right = static_cast(movementBits >> 8); - } - else - { - forward = from->forwardmove; - right = from->rightmove; - } - - to->forwardmove = forward; - to->rightmove = right; - } - - __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub() - { - __asm - { - push ebx // to - push ebp // from - push edi // key - push esi // msg - call ApplyMovement - add esp, 10h - - // return back - push 0x4921BF - ret - } - } - - __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub2() - { - __asm - { - push ebx // to - push ebp // from - push edi // key - push esi // msg - call ApplyMovement - add esp, 10h - - // return back - push 3 - push esi - push 0x492085 - ret - } - } - - void Gamepad::MenuNavigate() - { - auto& gamePad = gamePads[0]; - Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext); - - if (menuDef) - { - if (gamePad.enabled) - { - std::chrono::milliseconds now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime; - bool canNavigate = timeSinceLastNavigation > msBetweenNavigations; - - if (gamePad.stickDown[1][GPAD_STICK_POS]) { - if (canNavigate) { - Game::Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = GPAD_STICK_POS; - lastNavigationTime = now; - } - } - else if (gamePad.stickDown[1][GPAD_STICK_NEG]) { - if (canNavigate) { - Game::Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = GPAD_STICK_NEG; - lastNavigationTime = now; - } - } - else { - lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; - } - - for (auto& mapping : menuMappings) + if (pressingLeftTrigger) { - if (mapping.wasPressed) { - if (gamePad.digitals & mapping.input) { - // Button still pressed, do not send info - } - else { - mapping.wasPressed = false; - } - } - else if (gamePad.digitals & mapping.input) { - Game::UI_KeyEvent(0, mapping.keystroke, 1); - mapping.wasPressed = true; - } - } - } - } - } + Command::Execute("+speed_throw"); + isADS = true; + } + else + { + Command::Execute("-speed_throw"); + isADS = false; + } + } - int Gamepad::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) + const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; + const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; + if (pressingRightTrigger != previouslyPressingRightTrigger) + { + if (pressingRightTrigger) + { + Command::Execute("+attack"); + } + else + { + Command::Execute("-attack"); + } + } + + // Buttons (on/off) mappings + for (auto& i : mappings) + { + auto mapping = i; + auto action = mapping.action; + auto antiAction = mapping.action; + + if (mapping.isReversible) + { + action = "+" + mapping.action; + antiAction = "-" + mapping.action; + } + else if (mapping.wasPressed) + { + if (gamePad.digitals & mapping.input) + { + // Button still pressed, do not send info + } + else + { + i.wasPressed = false; + } + + continue; + } + + if (gamePad.digitals & mapping.input) + { + if (mapping.spamWhenHeld || !i.wasPressed) + { + Command::Execute(action); + } + i.wasPressed = true; + } + else if (mapping.isReversible && mapping.wasPressed) + { + i.wasPressed = false; + Command::Execute(antiAction); + } + } + } + } + + __declspec(naked) void Gamepad::CL_CreateCmdStub() + { + __asm + { + // do xinput! + push esi + push ebp + call CL_GamepadMove + add esp, 8h + + // execute code we patched over + add esp, 4 + fld st + pop ebx + + // return back + push 0x5A6DBF + retn + } + } + + __declspec(naked) void Gamepad::MSG_WriteDeltaUsercmdKeyStub() + { + __asm + { + // fix stack pointer + add esp, 0Ch + + // put both forward move and rightmove values in the movement button + mov dl, byte ptr[edi + 1Ah] // to_forwardMove + mov dh, byte ptr[edi + 1Bh] // to_rightMove + + mov[esp + 30h], dx // to_buttons + + mov dl, byte ptr[ebp + 1Ah] // from_forwardMove + mov dh, byte ptr[ebp + 1Bh] // from_rightMove + + mov[esp + 2Ch], dx // from_buttons + + // return back + push 0x60E40E + retn + } + } + + void Gamepad::ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to) + { + char forward; + char right; + + if (Game::MSG_ReadBit(msg)) + { + short movementBits = static_cast(key ^ Game::MSG_ReadBits(msg, 16)); + + forward = static_cast(movementBits); + right = static_cast(movementBits >> 8); + } + else + { + forward = from->forwardmove; + right = from->rightmove; + } + + to->forwardmove = forward; + to->rightmove = right; + } + + __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub() + { + __asm + { + push ebx // to + push ebp // from + push edi // key + push esi // msg + call ApplyMovement + add esp, 10h + + // return back + push 0x4921BF + ret + } + } + + __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub2() + { + __asm + { + push ebx // to + push ebp // from + push edi // key + push esi // msg + call ApplyMovement + add esp, 10h + + // return back + push 3 + push esi + push 0x492085 + ret + } + } + + void Gamepad::MenuNavigate() + { + auto& gamePad = gamePads[0]; + Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext); + + if (menuDef) + { + if (gamePad.enabled) + { + std::chrono::milliseconds now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime; + bool canNavigate = timeSinceLastNavigation > msBetweenNavigations; + + if (gamePad.stickDown[1][GPAD_STICK_POS]) + { + if (canNavigate) + { + Game::Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); + lastMenuNavigationDirection = GPAD_STICK_POS; + lastNavigationTime = now; + } + } + else if (gamePad.stickDown[1][GPAD_STICK_NEG]) + { + if (canNavigate) + { + Game::Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); + lastMenuNavigationDirection = GPAD_STICK_NEG; + lastNavigationTime = now; + } + } + else + { + lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; + } + + for (auto& mapping : menuMappings) + { + if (mapping.wasPressed) + { + if (gamePad.digitals & mapping.input) + { + // Button still pressed, do not send info + } + else + { + mapping.wasPressed = false; + } + } + else if (gamePad.digitals & mapping.input) + { + Game::UI_KeyEvent(0, mapping.keystroke, 1); + mapping.wasPressed = true; + } + } + } + } + } + + int Gamepad::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) { const auto& gamePad = gamePads[0]; - if (gamePad.enabled) - { - if (keyCode == Game::keyNum_t::K_MOUSE2) { + if (gamePad.enabled) + { + if (keyCode == Game::keyNum_t::K_MOUSE2) + { const bool pressingLeftTrigger = gamePad.analogs[0] > TRIGGER_THRESHOLD_F; const bool previouslyPressingLeftTrigger = gamePad.lastAnalogs[0] > TRIGGER_THRESHOLD_F; - if (pressingLeftTrigger != previouslyPressingLeftTrigger) - { - if (pressingLeftTrigger) { - return 1; - } - else { - return 0; - } - } - } - } + if (pressingLeftTrigger != previouslyPressingLeftTrigger) + { + if (pressingLeftTrigger) + { + return 1; + } + else + { + return 0; + } + } + } + } - return Utils::Hook::Call(0x48B2D0)(localClientNum, keyCode); - } + return Utils::Hook::Call(0x48B2D0)(localClientNum, keyCode); + } - void Gamepad::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) + void Gamepad::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) { - Gamepad::CL_GetMouseMovementCl(clientActive, mx, my); + Gamepad::CL_GetMouseMovementCl(clientActive, mx, my); - const auto& gamePad = gamePads[0]; + const auto& gamePad = gamePads[0]; - if (gamePad.enabled) - { - float viewSensitivityMultiplier = xpadSensitivity.get() * XINPUT_SENSITIVITY_MULTIPLIER; + if (gamePad.enabled) + { + float viewSensitivityMultiplier = xpadSensitivity.get() * XINPUT_SENSITIVITY_MULTIPLIER; - float lockedSensitivityMultiplier = xpadEarlyMultiplier.get(); - float generalXSensitivityMultiplier = xpadHorizontalMultiplier.get(); - float generalYSensitivityMultiplier = xpadVerticalMultiplier.get(); - std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(xpadEarlyTime.get()); + float lockedSensitivityMultiplier = xpadEarlyMultiplier.get(); + float generalXSensitivityMultiplier = xpadHorizontalMultiplier.get(); + float generalYSensitivityMultiplier = xpadVerticalMultiplier.get(); + std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(xpadEarlyTime.get()); - float viewStickX = gamePad.sticks[2]; - float viewStickY = gamePad.sticks[3]; - - // Gamepad horizontal acceleration on view - if (abs(viewStickX) > 0.80f) { - if (!Gamepad::isHoldingMaxLookX) { - Gamepad::isHoldingMaxLookX = true; - Gamepad::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - } - else { - std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - Gamepad::timeAtFirstHeldMaxLookX; + float viewStickX = gamePad.sticks[2]; + float viewStickY = gamePad.sticks[3]; + + // Gamepad horizontal acceleration on view + if (abs(viewStickX) > 0.80f) + { + if (!Gamepad::isHoldingMaxLookX) + { + Gamepad::isHoldingMaxLookX = true; + Gamepad::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + } + else + { + std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - + Gamepad::timeAtFirstHeldMaxLookX; #ifdef STEP_SENSITIVITY if (hasBeenHoldingLeftXForMs < msBeforeUnlockingSensitivity) { viewStickX *= lockedSensitivityMultiplier; } #else - float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= lockedSensitivityMultiplier + coeff * (1.0f - lockedSensitivityMultiplier); + float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); + viewStickX *= lockedSensitivityMultiplier + coeff * (1.0f - lockedSensitivityMultiplier); #endif - } - } - else { - Gamepad::isHoldingMaxLookX = false; - Gamepad::timeAtFirstHeldMaxLookX = 0ms; - viewStickX *= lockedSensitivityMultiplier; - } - - float adsMultiplier = 1.0f; - - auto ps = &clientActive->snap.ps; - - // DO NOT use clientActive->usingAds ! It only works for toggle ADS - if (Game::PM_IsAdsAllowed(ps) && Gamepad::isADS) { - adsMultiplier = xpadAdsMultiplier.get(); - } - - if (viewStickX != 0 || viewStickY != 0) { - *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier * adsMultiplier; - *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier * adsMultiplier; - } - - // Handling killstreaks - const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; - const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; - if (pressingRightTrigger != previouslyPressingRightTrigger) - { - bool* isInPredator = reinterpret_cast(0x8EE3B8); - - if (pressingRightTrigger) { - Utils::Hook::Set(0xA1C4F4, Game::LOC_SEL_INPUT_CONFIRM); - if (*isInPredator) { - // Yea, that's how we boost - // Command::execute is sync by default so the predator event gets fired properly - Command::Execute("+attack"); - Command::Execute("-attack"); - } - } - } - } - - } - - // Game -> Client DLL - __declspec(naked) void CL_GetMouseMovementStub() - { - __asm - { - push edx; - push ecx; - push eax; - call Gamepad::MouseOverride; - add esp, 0xC; - ret; - } - } - - // Client DLL -> Game - void Gamepad::CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my) - { - __asm - { - push ebx; - push ecx; - push edx; - mov eax, result; - mov ecx, mx; - mov edx, my; - mov ebx, 5A60E0h; - call ebx; - pop edx; - pop ecx; - pop ebx; - } - } - - bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) - { - auto& gamePad = gamePads[gamePadIndex]; - - if (XInputGetCapabilities(portIndex, XINPUT_FLAG_GAMEPAD, &gamePad.caps) == ERROR_SUCCESS) - { - gamePad.enabled = true; - gamePad.portIndex = portIndex; - return true; - } - - gamePad.enabled = false; - return false; - } - - void Gamepad::GPad_RefreshAll() - { - auto currentGamePadNum = 0; - - for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < MAX_GAMEPADS; currentPort++) - { - if (GPad_Check(currentGamePadNum, currentPort)) - currentGamePadNum++; - } - } - - void Gamepad::GPad_ConvertStickToFloat(const short x, const short y, float& outX, float& outY) - { - Game::vec2_t stickVec; - stickVec[0] = static_cast(x) / static_cast(std::numeric_limits::max()); - stickVec[1] = static_cast(y) / static_cast(std::numeric_limits::max()); - - const auto deadZoneTotal = gpad_stick_deadzone_min.get() + gpad_stick_deadzone_max.get(); - auto len = Game::Vec2Normalize(stickVec); - - if (gpad_stick_deadzone_min.get() <= len) - { - if (1.0f - gpad_stick_deadzone_max.get() >= len) - len = (len - gpad_stick_deadzone_min.get()) / (1.0f - deadZoneTotal); - else - len = 1.0f; - } - else - len = 0.0f; - - outX = stickVec[0] * len; - outY = stickVec[1] * len; - } - - void Gamepad::GPad_UpdateSticksDown(int gamePadIndex) - { - assert(gamePadIndex < MAX_GAMEPADS); - - auto& gamePad = gamePads[gamePadIndex]; - - for(auto stickIndex = 0u; stickIndex < std::extent_v; stickIndex++) - { - for(auto dir = 0; dir < GPAD_STICK_DIR_COUNT; dir++) + } + } + else { - gamePad.stickDownLast[stickIndex][dir] = gamePad.stickDown[stickIndex][dir]; + Gamepad::isHoldingMaxLookX = false; + Gamepad::timeAtFirstHeldMaxLookX = 0ms; + viewStickX *= lockedSensitivityMultiplier; + } - auto threshold = gpad_stick_pressed.get(); + float adsMultiplier = 1.0f; - if (gamePad.stickDownLast[stickIndex][dir]) - threshold -= gpad_stick_pressed_hysteresis.get(); - else - threshold += gpad_stick_pressed_hysteresis.get(); + auto ps = &clientActive->snap.ps; - if(dir == GPAD_STICK_POS) - { - gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] > threshold; - } - else - { - assert(dir == GPAD_STICK_NEG); - gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] < -threshold; - } + // DO NOT use clientActive->usingAds ! It only works for toggle ADS + if (Game::PM_IsAdsAllowed(ps) && Gamepad::isADS) + { + adsMultiplier = xpadAdsMultiplier.get(); + } + + if (viewStickX != 0 || viewStickY != 0) + { + *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier * adsMultiplier; + *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier * adsMultiplier; + } + + // Handling killstreaks + const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; + const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; + if (pressingRightTrigger != previouslyPressingRightTrigger) + { + bool* isInPredator = reinterpret_cast(0x8EE3B8); + + if (pressingRightTrigger) + { + Utils::Hook::Set(0xA1C4F4, Game::LOC_SEL_INPUT_CONFIRM); + if (*isInPredator) + { + // Yea, that's how we boost + // Command::execute is sync by default so the predator event gets fired properly + Command::Execute("+attack"); + Command::Execute("-attack"); + } + } } } } - void Gamepad::GPad_UpdateSticks(const int gamePadIndex, const XINPUT_GAMEPAD& state) + // Game -> Client DLL + __declspec(naked) void CL_GetMouseMovementStub() { - assert(gamePadIndex < MAX_GAMEPADS); - - auto& gamePad = gamePads[gamePadIndex]; - - Game::vec2_t lVec, rVec; - GPad_ConvertStickToFloat(state.sThumbLX, state.sThumbLY, lVec[0], lVec[1]); - GPad_ConvertStickToFloat(state.sThumbRX, state.sThumbRY, rVec[0], rVec[1]); - - gamePad.lastSticks[0] = gamePad.sticks[0]; - gamePad.sticks[0] = lVec[0]; - gamePad.lastSticks[1] = gamePad.sticks[1]; - gamePad.sticks[1] = lVec[1]; - gamePad.lastSticks[2] = gamePad.sticks[2]; - gamePad.sticks[2] = rVec[0]; - gamePad.lastSticks[3] = gamePad.sticks[3]; - gamePad.sticks[3] = rVec[1]; - - GPad_UpdateSticksDown(gamePadIndex); - - #ifdef DEBUG - if(gpad_debug.get()) - { - Logger::Print("Left: X: %f Y: %f\n", lVec[0], lVec[1]); - Logger::Print("Right: X: %f Y: %f\n", rVec[0], rVec[1]); - Logger::Print("Down: %i:%i %i:%i %i:%i %i:%i\n", gamePad.stickDown[0][GPAD_STICK_POS], gamePad.stickDown[0][GPAD_STICK_NEG], - gamePad.stickDown[1][GPAD_STICK_POS], gamePad.stickDown[1][GPAD_STICK_NEG], - gamePad.stickDown[2][GPAD_STICK_POS], gamePad.stickDown[2][GPAD_STICK_NEG], - gamePad.stickDown[3][GPAD_STICK_POS], gamePad.stickDown[3][GPAD_STICK_NEG]); - } - #endif + __asm + { + push edx; + push ecx; + push eax; + call Gamepad::MouseOverride; + add esp, 0xC; + ret; + } } - void Gamepad::GPad_UpdateDigitals(const int gamePadIndex, const XINPUT_GAMEPAD& state) + // Client DLL -> Game + void Gamepad::CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my) { - assert(gamePadIndex < MAX_GAMEPADS); + __asm + { + push ebx; + push ecx; + push edx; + mov eax, result; + mov ecx, mx; + mov edx, my; + mov ebx, 5A60E0h; + call ebx; + pop edx; + pop ecx; + pop ebx; + } + } - auto& gamePad = gamePads[gamePadIndex]; + bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) + { + auto& gamePad = gamePads[gamePadIndex]; - gamePad.lastDigitals = gamePad.digitals; - gamePad.digitals = state.wButtons; + if (XInputGetCapabilities(portIndex, XINPUT_FLAG_GAMEPAD, &gamePad.caps) == ERROR_SUCCESS) + { + gamePad.enabled = true; + gamePad.portIndex = portIndex; + return true; + } - const auto leftDeflect = gpad_button_lstick_deflect_max.get(); - if(std::fabs(gamePad.sticks[0]) > leftDeflect || std::fabs(gamePad.sticks[1]) > leftDeflect) - gamePad.digitals &= ~static_cast(XINPUT_GAMEPAD_LEFT_THUMB); - const auto rightDeflect = gpad_button_rstick_deflect_max.get(); - if(std::fabs(gamePad.sticks[2]) > leftDeflect || std::fabs(gamePad.sticks[3]) > rightDeflect) - gamePad.digitals &= ~static_cast(XINPUT_GAMEPAD_RIGHT_THUMB); + gamePad.enabled = false; + return false; + } + + void Gamepad::GPad_RefreshAll() + { + auto currentGamePadNum = 0; + + for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < MAX_GAMEPADS; currentPort++) + { + if (GPad_Check(currentGamePadNum, currentPort)) + currentGamePadNum++; + } + } + + void Gamepad::GPad_ConvertStickToFloat(const short x, const short y, float& outX, float& outY) + { + Game::vec2_t stickVec; + stickVec[0] = static_cast(x) / static_cast(std::numeric_limits::max()); + stickVec[1] = static_cast(y) / static_cast(std::numeric_limits::max()); + + const auto deadZoneTotal = gpad_stick_deadzone_min.get() + gpad_stick_deadzone_max.get(); + auto len = Game::Vec2Normalize(stickVec); + + if (gpad_stick_deadzone_min.get() <= len) + { + if (1.0f - gpad_stick_deadzone_max.get() >= len) + len = (len - gpad_stick_deadzone_min.get()) / (1.0f - deadZoneTotal); + else + len = 1.0f; + } + else + len = 0.0f; + + outX = stickVec[0] * len; + outY = stickVec[1] * len; + } + + void Gamepad::GPad_UpdateSticksDown(int gamePadIndex) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + for (auto stickIndex = 0u; stickIndex < std::extent_v; stickIndex++) + { + for (auto dir = 0; dir < GPAD_STICK_DIR_COUNT; dir++) + { + gamePad.stickDownLast[stickIndex][dir] = gamePad.stickDown[stickIndex][dir]; + + auto threshold = gpad_stick_pressed.get(); + + if (gamePad.stickDownLast[stickIndex][dir]) + threshold -= gpad_stick_pressed_hysteresis.get(); + else + threshold += gpad_stick_pressed_hysteresis.get(); + + if (dir == GPAD_STICK_POS) + { + gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] > threshold; + } + else + { + assert(dir == GPAD_STICK_NEG); + gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] < -threshold; + } + } + } + } + + void Gamepad::GPad_UpdateSticks(const int gamePadIndex, const XINPUT_GAMEPAD& state) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + Game::vec2_t lVec, rVec; + GPad_ConvertStickToFloat(state.sThumbLX, state.sThumbLY, lVec[0], lVec[1]); + GPad_ConvertStickToFloat(state.sThumbRX, state.sThumbRY, rVec[0], rVec[1]); + + gamePad.lastSticks[0] = gamePad.sticks[0]; + gamePad.sticks[0] = lVec[0]; + gamePad.lastSticks[1] = gamePad.sticks[1]; + gamePad.sticks[1] = lVec[1]; + gamePad.lastSticks[2] = gamePad.sticks[2]; + gamePad.sticks[2] = rVec[0]; + gamePad.lastSticks[3] = gamePad.sticks[3]; + gamePad.sticks[3] = rVec[1]; + + GPad_UpdateSticksDown(gamePadIndex); #ifdef DEBUG - if (gpad_debug.get()) - { - Logger::Print("Buttons: %x\n", gamePad.digitals); - } + if (gpad_debug.get()) + { + Logger::Print("Left: X: %f Y: %f\n", lVec[0], lVec[1]); + Logger::Print("Right: X: %f Y: %f\n", rVec[0], rVec[1]); + Logger::Print("Down: %i:%i %i:%i %i:%i %i:%i\n", gamePad.stickDown[0][GPAD_STICK_POS], gamePad.stickDown[0][GPAD_STICK_NEG], + gamePad.stickDown[1][GPAD_STICK_POS], gamePad.stickDown[1][GPAD_STICK_NEG], + gamePad.stickDown[2][GPAD_STICK_POS], gamePad.stickDown[2][GPAD_STICK_NEG], + gamePad.stickDown[3][GPAD_STICK_POS], gamePad.stickDown[3][GPAD_STICK_NEG]); + } #endif } - void Gamepad::GPad_UpdateAnalogs(const int gamePadIndex, const XINPUT_GAMEPAD& state) + void Gamepad::GPad_UpdateDigitals(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < MAX_GAMEPADS); + assert(gamePadIndex < MAX_GAMEPADS); - auto& gamePad = gamePads[gamePadIndex]; + auto& gamePad = gamePads[gamePadIndex]; - const auto buttonDeadZone = gpad_button_deadzone.get(); + gamePad.lastDigitals = gamePad.digitals; + gamePad.digitals = state.wButtons; - gamePad.lastAnalogs[0] = gamePad.analogs[0]; - gamePad.analogs[0] = static_cast(state.bLeftTrigger) / static_cast(std::numeric_limits::max()); - if (gamePad.analogs[0] < buttonDeadZone) - gamePad.analogs[0] = 0.0f; - - - gamePad.lastAnalogs[1] = gamePad.analogs[1]; - gamePad.analogs[1] = static_cast(state.bRightTrigger) / static_cast(std::numeric_limits::max()); - if (gamePad.analogs[1] < buttonDeadZone) - gamePad.analogs[1] = 0.0f; + const auto leftDeflect = gpad_button_lstick_deflect_max.get(); + if (std::fabs(gamePad.sticks[0]) > leftDeflect || std::fabs(gamePad.sticks[1]) > leftDeflect) + gamePad.digitals &= ~static_cast(XINPUT_GAMEPAD_LEFT_THUMB); + const auto rightDeflect = gpad_button_rstick_deflect_max.get(); + if (std::fabs(gamePad.sticks[2]) > leftDeflect || std::fabs(gamePad.sticks[3]) > rightDeflect) + gamePad.digitals &= ~static_cast(XINPUT_GAMEPAD_RIGHT_THUMB); #ifdef DEBUG - if (gpad_debug.get()) - { - Logger::Print("Triggers: %f %f\n", gamePad.analogs[0], gamePad.analogs[1]); - } + if (gpad_debug.get()) + { + Logger::Print("Buttons: %x\n", gamePad.digitals); + } +#endif + } + + void Gamepad::GPad_UpdateAnalogs(const int gamePadIndex, const XINPUT_GAMEPAD& state) + { + assert(gamePadIndex < MAX_GAMEPADS); + + auto& gamePad = gamePads[gamePadIndex]; + + const auto buttonDeadZone = gpad_button_deadzone.get(); + + gamePad.lastAnalogs[0] = gamePad.analogs[0]; + gamePad.analogs[0] = static_cast(state.bLeftTrigger) / static_cast(std::numeric_limits::max()); + if (gamePad.analogs[0] < buttonDeadZone) + gamePad.analogs[0] = 0.0f; + + + gamePad.lastAnalogs[1] = gamePad.analogs[1]; + gamePad.analogs[1] = static_cast(state.bRightTrigger) / static_cast(std::numeric_limits::max()); + if (gamePad.analogs[1] < buttonDeadZone) + gamePad.analogs[1] = 0.0f; + +#ifdef DEBUG + if (gpad_debug.get()) + { + Logger::Print("Triggers: %f %f\n", gamePad.analogs[0], gamePad.analogs[1]); + } #endif } void Gamepad::GPad_UpdateAll() { - GPad_RefreshAll(); + GPad_RefreshAll(); - for(auto currentGamePadIndex = 0; currentGamePadIndex < MAX_GAMEPADS; currentGamePadIndex++) - { + for (auto currentGamePadIndex = 0; currentGamePadIndex < MAX_GAMEPADS; currentGamePadIndex++) + { const auto& gamePad = gamePads[currentGamePadIndex]; - if(!gamePad.enabled) - continue; + if (!gamePad.enabled) + continue; - XINPUT_STATE inputState; - if(XInputGetState(gamePad.portIndex, &inputState) != ERROR_SUCCESS) - continue; + XINPUT_STATE inputState; + if (XInputGetState(gamePad.portIndex, &inputState) != ERROR_SUCCESS) + continue; - GPad_UpdateSticks(currentGamePadIndex, inputState.Gamepad); - GPad_UpdateDigitals(currentGamePadIndex, inputState.Gamepad); - GPad_UpdateAnalogs(currentGamePadIndex, inputState.Gamepad); - } + GPad_UpdateSticks(currentGamePadIndex, inputState.Gamepad); + GPad_UpdateDigitals(currentGamePadIndex, inputState.Gamepad); + GPad_UpdateAnalogs(currentGamePadIndex, inputState.Gamepad); + } } void Gamepad::IN_GamePadsMove() { - GPad_UpdateAll(); + GPad_UpdateAll(); } - void Gamepad::IN_Frame_Hk() + void Gamepad::IN_Frame_Hk() { - // Call original method - Utils::Hook::Call(0x64C490)(); + // Call original method + Utils::Hook::Call(0x64C490)(); - IN_GamePadsMove(); + IN_GamePadsMove(); } - void Gamepad::InitDvars() + void Gamepad::InitDvars() { - gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); - gpad_debug = Dvar::Register("gpad_debug", false, 0, "Game pad debugging"); - gpad_present = Dvar::Register("gpad_present", false, 0, "Game pad present"); - gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "thumbstick_default", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); - gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "buttons_default", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); - gpad_menu_scroll_delay_first = Dvar::Register("gpad_menu_scroll_delay_first", 420, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for the first repeat, in milliseconds"); - gpad_menu_scroll_delay_rest = Dvar::Register("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for repeats after the first, in milliseconds"); - gpad_rumble = Dvar::Register("gpad_rumble", true, Game::DVAR_FLAG_SAVED, "Enable game pad rumble"); - gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, 0, "Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing"); - gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, 0, "Game pad stick pressed threshhold"); - gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, 0, "Game pad maximum stick deadzone"); - gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, 0, "Game pad minimum stick deadzone"); - gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, 0, "Game pad button deadzone threshhold"); - gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); - gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); + gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); + gpad_debug = Dvar::Register("gpad_debug", false, 0, "Game pad debugging"); + gpad_present = Dvar::Register("gpad_present", false, 0, "Game pad present"); + gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "thumbstick_default", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); + gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "buttons_default", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); + gpad_menu_scroll_delay_first = Dvar::Register("gpad_menu_scroll_delay_first", 420, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for the first repeat, in milliseconds"); + gpad_menu_scroll_delay_rest = Dvar::Register("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_FLAG_SAVED, + "Menu scroll key-repeat delay, for repeats after the first, in milliseconds"); + gpad_rumble = Dvar::Register("gpad_rumble", true, Game::DVAR_FLAG_SAVED, "Enable game pad rumble"); + gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, 0, + "Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing"); + gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, 0, "Game pad stick pressed threshhold"); + gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, 0, "Game pad maximum stick deadzone"); + gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, 0, "Game pad minimum stick deadzone"); + gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, 0, "Game pad button deadzone threshhold"); + gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); + gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); } - void Gamepad::IN_Init_Hk() - { - // Call original method - Utils::Hook::Call(0x45D620)(); + void Gamepad::IN_Init_Hk() + { + // Call original method + Utils::Hook::Call(0x45D620)(); - InitDvars(); - } + InitDvars(); + } - Gamepad::Gamepad() - { - if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) - return; + Gamepad::Gamepad() + { + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) + return; - Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); - Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); - // use the xinput state when creating a usercmd - Utils::Hook(0x5A6DB9, Gamepad::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); + // use the xinput state when creating a usercmd + Utils::Hook(0x5A6DB9, Gamepad::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); - // package the forward and right move components in the move buttons - Utils::Hook(0x60E38D, Gamepad::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + // package the forward and right move components in the move buttons + Utils::Hook(0x60E38D, Gamepad::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); - // send two bytes for sending movement data - Utils::Hook::Set(0x60E501, 16); - Utils::Hook::Set(0x60E5CD, 16); + // send two bytes for sending movement data + Utils::Hook::Set(0x60E501, 16); + Utils::Hook::Set(0x60E5CD, 16); - // make sure to parse the movement data properly and apply it - Utils::Hook(0x492127, Gamepad::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); - Utils::Hook(0x492009, Gamepad::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + // make sure to parse the movement data properly and apply it + Utils::Hook(0x492127, Gamepad::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492009, Gamepad::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); - Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - Scheduler::OnFrame(MenuNavigate); + Scheduler::OnFrame(MenuNavigate); - xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); - xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); - xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); - xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); - xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); - xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); + xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); + xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); + xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, + "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); + xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); + xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); + xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); - MessageBoxA(NULL, __FUNCTION__, "", 0); - } + MessageBoxA(NULL, __FUNCTION__, "", 0); + } } diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index c68d97ca..e3c19d98 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -8,8 +8,8 @@ namespace Components static constexpr float TRIGGER_THRESHOLD_F = static_cast(XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / static_cast(0xFF); public: - Gamepad(); + enum GamePadStickDir { GPAD_STICK_POS = 0x0, @@ -17,7 +17,7 @@ namespace Components GPAD_STICK_DIR_COUNT }; - + struct GamePad { bool enabled; From 2decfa2c453936c01b7278e5921164e5e538a6e2 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 21 Aug 2021 15:40:36 +0200 Subject: [PATCH 27/83] Apply patches important for dedicated servers as well in any case --- src/Components/Modules/Gamepad.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 5289d3a7..0d7d5088 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -707,13 +707,9 @@ namespace Components Gamepad::Gamepad() { - if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) + if (ZoneBuilder::IsEnabled()) return; - Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); - - Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); - // use the xinput state when creating a usercmd Utils::Hook(0x5A6DB9, Gamepad::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); @@ -728,6 +724,13 @@ namespace Components Utils::Hook(0x492127, Gamepad::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492009, Gamepad::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + if (Dedicated::IsEnabled()) + return; + + Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); + + Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); @@ -741,7 +744,5 @@ namespace Components xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); - - MessageBoxA(NULL, __FUNCTION__, "", 0); } } From 6d598df56dff2c3cf46419d44ebe1964cda0bcad Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 00:04:30 +0200 Subject: [PATCH 28/83] Add binding commands to keys for controllers --- src/Components/Modules/Dvar.cpp | 9 + src/Components/Modules/Dvar.hpp | 1 + src/Components/Modules/Gamepad.cpp | 370 ++++++++++++++++++++++++++--- src/Components/Modules/Gamepad.hpp | 136 ++++++++++- src/Game/Structs.hpp | 71 ++++++ 5 files changed, 539 insertions(+), 48 deletions(-) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index f342c658..2d2d3975 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -109,6 +109,7 @@ namespace Components Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%f", value)); } } + void Dvar::Var::setRaw(int integer) { @@ -126,6 +127,14 @@ namespace Components } } + void Dvar::Var::setRaw(bool value) + { + if (this->dvar) + { + this->dvar->current.enabled = value; + } + } + template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description) { return Game::Dvar_RegisterBool(name, value, flag.val, description); diff --git a/src/Components/Modules/Dvar.hpp b/src/Components/Modules/Dvar.hpp index 4775b575..b76d77f5 100644 --- a/src/Components/Modules/Dvar.hpp +++ b/src/Components/Modules/Dvar.hpp @@ -35,6 +35,7 @@ namespace Components // TODO: Add others void setRaw(int integer); void setRaw(float value); + void setRaw(bool value); private: Game::dvar_t* dvar; diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 0d7d5088..d6d02195 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -5,9 +5,76 @@ #define XINPUT_SENSITIVITY_MULTIPLIER 4 // Arbitrary value I multiply the xinput senstivity dvar with to get nicer values (0-10 range or something) #define SIGN(d) ((d > 0) - (d < 0)) +namespace Game +{ + ButtonToCodeMap_t buttonList[] + { + {GPAD_X, K_BUTTON_X}, + {GPAD_A, K_BUTTON_A}, + {GPAD_B, K_BUTTON_B}, + {GPAD_Y, K_BUTTON_Y}, + {GPAD_L_TRIG, K_BUTTON_LTRIG}, + {GPAD_R_TRIG, K_BUTTON_RTRIG}, + {GPAD_L_SHLDR, K_BUTTON_LSHLDR}, + {GPAD_R_SHLDR, K_BUTTON_RSHLDR}, + {GPAD_START, K_BUTTON_START}, + {GPAD_BACK, K_BUTTON_BACK}, + {GPAD_L3, K_BUTTON_LSTICK}, + {GPAD_R3, K_BUTTON_RSTICK}, + {GPAD_UP, K_DPAD_UP}, + {GPAD_DOWN, K_DPAD_DOWN}, + {GPAD_LEFT, K_DPAD_LEFT}, + {GPAD_RIGHT, K_DPAD_RIGHT} + }; + + StickToCodeMap_t analogStickList[] + { + {GPAD_LY, GPAD_STICK_POS, K_DPAD_UP}, + {GPAD_LY, GPAD_STICK_NEG, K_DPAD_DOWN}, + {GPAD_LX, GPAD_STICK_POS, K_DPAD_RIGHT}, + {GPAD_LX, GPAD_STICK_NEG, K_DPAD_LEFT}, + }; + + keyNum_t menuScrollButtonList[] + { + K_DPAD_UP, + K_DPAD_DOWN, + K_DPAD_LEFT, + K_DPAD_RIGHT + }; + + constexpr auto VANILLA_KEY_NAME_COUNT = 95; + keyname_t extendedKeyNames[] + { + {"BUTTON_A", K_BUTTON_A}, + {"BUTTON_B", K_BUTTON_B}, + {"BUTTON_X", K_BUTTON_X}, + {"BUTTON_Y", K_BUTTON_Y}, + {"BUTTON_LSHLDR", K_BUTTON_LSHLDR}, + {"BUTTON_RSHLDR", K_BUTTON_RSHLDR}, + {"BUTTON_START", K_BUTTON_START}, + {"BUTTON_BACK", K_BUTTON_BACK}, + {"BUTTON_LSTICK", K_BUTTON_LSTICK}, + {"BUTTON_RSTICK", K_BUTTON_RSTICK}, + {"BUTTON_LTRIG", K_BUTTON_LTRIG}, + {"BUTTON_RTRIG", K_BUTTON_RTRIG}, + {"DPAD_UP", K_DPAD_UP}, + {"DPAD_DOWN", K_DPAD_DOWN}, + {"DPAD_LEFT", K_DPAD_LEFT}, + {"DPAD_RIGHT", K_DPAD_RIGHT}, + }; + + keyname_t combinedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; + + GpadAxesGlob gaGlobs[MAX_GAMEPADS]; + PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); + keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); +} + namespace Components { - Gamepad::GamePad Gamepad::gamePads[1]{}; + Gamepad::GamePad Gamepad::gamePads[Game::MAX_GAMEPADS]{}; + Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GAMEPADS]{}; std::chrono::milliseconds Gamepad::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool Gamepad::isHoldingMaxLookX = false; bool Gamepad::isADS; @@ -35,7 +102,7 @@ namespace Components Dvar::Var Gamepad::xpadVerticalMultiplier; Dvar::Var Gamepad::xpadAdsMultiplier; - Gamepad::GamePadStickDir Gamepad::lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; + Game::GamePadStickDir Gamepad::lastMenuNavigationDirection = Game::GPAD_STICK_DIR_COUNT; std::chrono::milliseconds Gamepad::lastNavigationTime = 0ms; std::chrono::milliseconds Gamepad::msBetweenNavigations = 220ms; @@ -285,27 +352,27 @@ namespace Components std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime; bool canNavigate = timeSinceLastNavigation > msBetweenNavigations; - if (gamePad.stickDown[1][GPAD_STICK_POS]) + if (gamePad.stickDown[1][Game::GPAD_STICK_POS]) { if (canNavigate) { - Game::Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = GPAD_STICK_POS; + Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); + lastMenuNavigationDirection = Game::GPAD_STICK_POS; lastNavigationTime = now; } } - else if (gamePad.stickDown[1][GPAD_STICK_NEG]) + else if (gamePad.stickDown[1][Game::GPAD_STICK_NEG]) { if (canNavigate) { - Game::Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = GPAD_STICK_NEG; + Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); + lastMenuNavigationDirection = Game::GPAD_STICK_NEG; lastNavigationTime = now; } } else { - lastMenuNavigationDirection = GPAD_STICK_DIR_COUNT; + lastMenuNavigationDirection = Game::GPAD_STICK_DIR_COUNT; } for (auto& mapping : menuMappings) @@ -360,7 +427,7 @@ namespace Components void Gamepad::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) { - Gamepad::CL_GetMouseMovementCl(clientActive, mx, my); + CL_GetMouseMovementCl(clientActive, mx, my); const auto& gamePad = gamePads[0]; @@ -379,15 +446,15 @@ namespace Components // Gamepad horizontal acceleration on view if (abs(viewStickX) > 0.80f) { - if (!Gamepad::isHoldingMaxLookX) + if (!isHoldingMaxLookX) { - Gamepad::isHoldingMaxLookX = true; - Gamepad::timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); + isHoldingMaxLookX = true; + timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); } else { std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - - Gamepad::timeAtFirstHeldMaxLookX; + timeAtFirstHeldMaxLookX; #ifdef STEP_SENSITIVITY if (hasBeenHoldingLeftXForMs < msBeforeUnlockingSensitivity) { viewStickX *= lockedSensitivityMultiplier; @@ -400,8 +467,8 @@ namespace Components } else { - Gamepad::isHoldingMaxLookX = false; - Gamepad::timeAtFirstHeldMaxLookX = 0ms; + isHoldingMaxLookX = false; + timeAtFirstHeldMaxLookX = 0ms; viewStickX *= lockedSensitivityMultiplier; } @@ -410,7 +477,7 @@ namespace Components auto ps = &clientActive->snap.ps; // DO NOT use clientActive->usingAds ! It only works for toggle ADS - if (Game::PM_IsAdsAllowed(ps) && Gamepad::isADS) + if (PM_IsAdsAllowed(ps) && isADS) { adsMultiplier = xpadAdsMultiplier.get(); } @@ -478,6 +545,7 @@ namespace Components bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) { + assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; if (XInputGetCapabilities(portIndex, XINPUT_FLAG_GAMEPAD, &gamePad.caps) == ERROR_SUCCESS) @@ -495,13 +563,68 @@ namespace Components { auto currentGamePadNum = 0; - for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < MAX_GAMEPADS; currentPort++) + for (auto currentPort = 0; currentPort < XUSER_MAX_COUNT && currentGamePadNum < Game::MAX_GAMEPADS; currentPort++) { if (GPad_Check(currentGamePadNum, currentPort)) currentGamePadNum++; } } + void Gamepad::CL_GamepadResetMenuScrollTime(const int gamePadIndex, const int key, const bool down, const unsigned time) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + + if (!down) + return; + + const auto scrollDelayFirst = gpad_menu_scroll_delay_first.get(); + for(const auto scrollButton : Game::menuScrollButtonList) + { + if(key == scrollButton) + { + gamePadGlobal.nextScrollTime = scrollDelayFirst + time; + return; + } + } + } + + void Gamepad::CL_GamepadEvent(int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, const float value) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); + + Game::gaGlobs[gamePadIndex].axesValues[physicalAxis] = value; + } + + void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + + auto& keyState = Game::playerKeys[gamePadIndex]; + keyState.keys[key].down = buttonEvent == Game::GPAD_BUTTON_PRESSED || buttonEvent == Game::GPAD_BUTTON_UPDATE; + + if(buttonEvent == Game::GPAD_BUTTON_PRESSED) + { + if (++keyState.keys[key].repeats == 1) + keyState.anyKeyDown++; + } + else if(keyState.keys[key].repeats > 0) + { + keyState.keys[key].repeats = 0; + if (--keyState.anyKeyDown < 0) + keyState.anyKeyDown = 0; + } + } + + void Gamepad::CL_GamepadButtonEventForPort(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time, const Game::GamePadButton button) + { + if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) + CL_GamepadResetMenuScrollTime(gamePadIndex, key, buttonEvent == Game::GPAD_BUTTON_PRESSED, time); + + CL_GamepadButtonEvent(gamePadIndex, key, buttonEvent, time, button); + } + void Gamepad::GPad_ConvertStickToFloat(const short x, const short y, float& outX, float& outY) { Game::vec2_t stickVec; @@ -525,15 +648,121 @@ namespace Components outY = stickVec[1] * len; } + float Gamepad::GPad_GetStick(const int gamePadIndex, const Game::GamePadStick stick) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePad = gamePads[gamePadIndex]; + + return gamePad.sticks[stick]; + } + + float Gamepad::GPad_GetButton(const int gamePadIndex, Game::GamePadButton button) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePad = gamePads[gamePadIndex]; + + float value = 0.0f; + + if(button & Game::GPAD_DIGITAL_MASK) + { + const auto buttonValue = button & Game::GPAD_VALUE_MASK; + value = buttonValue & gamePad.digitals ? 1.0f : 0.0f; + } + else if(button & Game::GPAD_ANALOG_MASK) + { + const auto analogIndex = button & Game::GPAD_VALUE_MASK; + if (analogIndex < std::extent_v) + { + value = gamePad.analogs[analogIndex]; + } + } + + return value; + } + + bool Gamepad::GPad_IsButtonPressed(const int gamePadIndex, Game::GamePadButton button) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePad = gamePads[gamePadIndex]; + + bool down = false; + bool lastDown = false; + + if(button & Game::GPAD_DIGITAL_MASK) + { + const auto buttonValue = button & Game::GPAD_VALUE_MASK; + if (button & 0xF && buttonValue & gamePad.digitals && (gamePad.digitals & 0xF) != (button & 0xF)) + { + down = false; + lastDown = false; + } + else + { + down = (buttonValue & gamePad.digitals) != 0; + if (button & 0xF && buttonValue & gamePad.lastDigitals && (gamePad.lastDigitals & 0xF) != (button & 0xF)) + lastDown = false; + else + lastDown = (buttonValue & gamePad.lastDigitals) != 0; + } + } + else if(button & Game::GPAD_ANALOG_MASK) + { + const auto analogIndex = button & Game::GPAD_VALUE_MASK; + assert(analogIndex < std::extent_v); + + if(analogIndex < std::extent_v) + { + down = gamePad.analogs[analogIndex] > 0.0f; + lastDown = gamePad.lastAnalogs[analogIndex] > 0.0f; + } + } + + return down && !lastDown; + } + + bool Gamepad::GPad_ButtonRequiresUpdates(const int gamePadIndex, Game::GamePadButton button) + { + return button & Game::GPAD_ANALOG_MASK && GPad_GetButton(gamePadIndex, button) > 0.0f; + } + + bool Gamepad::GPad_IsButtonReleased(int gamePadIndex, Game::GamePadButton button) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePad = gamePads[gamePadIndex]; + + bool down = false; + bool lastDown = false; + + if (button & Game::GPAD_DIGITAL_MASK) + { + const auto buttonValue = button & Game::GPAD_VALUE_MASK; + + down = (gamePad.digitals & buttonValue) != 0; + lastDown = (gamePad.lastDigitals & buttonValue) != 0; + } + else if (button & Game::GPAD_ANALOG_MASK) + { + const auto analogIndex = button & Game::GPAD_VALUE_MASK; + assert(analogIndex < std::extent_v); + + if (analogIndex < std::extent_v) + { + down = gamePad.analogs[analogIndex] > 0.0f; + lastDown = gamePad.lastAnalogs[analogIndex] > 0.0f; + } + } + + return !down && lastDown; + } + void Gamepad::GPad_UpdateSticksDown(int gamePadIndex) { - assert(gamePadIndex < MAX_GAMEPADS); - + assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; for (auto stickIndex = 0u; stickIndex < std::extent_v; stickIndex++) { - for (auto dir = 0; dir < GPAD_STICK_DIR_COUNT; dir++) + for (auto dir = 0; dir < Game::GPAD_STICK_DIR_COUNT; dir++) { gamePad.stickDownLast[stickIndex][dir] = gamePad.stickDown[stickIndex][dir]; @@ -544,13 +773,13 @@ namespace Components else threshold += gpad_stick_pressed_hysteresis.get(); - if (dir == GPAD_STICK_POS) + if (dir == Game::GPAD_STICK_POS) { gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] > threshold; } else { - assert(dir == GPAD_STICK_NEG); + assert(dir == Game::GPAD_STICK_NEG); gamePad.stickDown[stickIndex][dir] = gamePad.sticks[stickIndex] < -threshold; } } @@ -559,7 +788,7 @@ namespace Components void Gamepad::GPad_UpdateSticks(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < MAX_GAMEPADS); + assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; @@ -583,17 +812,17 @@ namespace Components { Logger::Print("Left: X: %f Y: %f\n", lVec[0], lVec[1]); Logger::Print("Right: X: %f Y: %f\n", rVec[0], rVec[1]); - Logger::Print("Down: %i:%i %i:%i %i:%i %i:%i\n", gamePad.stickDown[0][GPAD_STICK_POS], gamePad.stickDown[0][GPAD_STICK_NEG], - gamePad.stickDown[1][GPAD_STICK_POS], gamePad.stickDown[1][GPAD_STICK_NEG], - gamePad.stickDown[2][GPAD_STICK_POS], gamePad.stickDown[2][GPAD_STICK_NEG], - gamePad.stickDown[3][GPAD_STICK_POS], gamePad.stickDown[3][GPAD_STICK_NEG]); + Logger::Print("Down: %i:%i %i:%i %i:%i %i:%i\n", gamePad.stickDown[0][Game::GPAD_STICK_POS], gamePad.stickDown[0][Game::GPAD_STICK_NEG], + gamePad.stickDown[1][Game::GPAD_STICK_POS], gamePad.stickDown[1][Game::GPAD_STICK_NEG], + gamePad.stickDown[2][Game::GPAD_STICK_POS], gamePad.stickDown[2][Game::GPAD_STICK_NEG], + gamePad.stickDown[3][Game::GPAD_STICK_POS], gamePad.stickDown[3][Game::GPAD_STICK_NEG]); } #endif } void Gamepad::GPad_UpdateDigitals(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < MAX_GAMEPADS); + assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; @@ -617,7 +846,7 @@ namespace Components void Gamepad::GPad_UpdateAnalogs(const int gamePadIndex, const XINPUT_GAMEPAD& state) { - assert(gamePadIndex < MAX_GAMEPADS); + assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; @@ -646,7 +875,7 @@ namespace Components { GPad_RefreshAll(); - for (auto currentGamePadIndex = 0; currentGamePadIndex < MAX_GAMEPADS; currentGamePadIndex++) + for (auto currentGamePadIndex = 0; currentGamePadIndex < Game::MAX_GAMEPADS; currentGamePadIndex++) { const auto& gamePad = gamePads[currentGamePadIndex]; if (!gamePad.enabled) @@ -665,6 +894,64 @@ namespace Components void Gamepad::IN_GamePadsMove() { GPad_UpdateAll(); + const auto time = Game::Sys_Milliseconds(); + + bool gpadPresent = false; + for(auto gamePadIndex = 0; gamePadIndex < Game::MAX_GAMEPADS; gamePadIndex++) + { + const auto& gamePad = gamePads[gamePadIndex]; + + if(gamePad.enabled) + { + gpadPresent = true; + const auto lx = GPad_GetStick(gamePadIndex, Game::GPAD_LX); + const auto ly = GPad_GetStick(gamePadIndex, Game::GPAD_LY); + const auto rx = GPad_GetStick(gamePadIndex, Game::GPAD_RX); + const auto ry = GPad_GetStick(gamePadIndex, Game::GPAD_RY); + const auto leftTrig = GPad_GetButton(gamePadIndex, Game::GPAD_L_TRIG); + const auto rightTrig = GPad_GetButton(gamePadIndex, Game::GPAD_R_TRIG); + + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_X, lx); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_Y, ly); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_X, rx); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_Y, ry); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LTRIGGER, leftTrig); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RTRIGGER, rightTrig); + + for (const auto& buttonMapping : Game::buttonList) + { + if(GPad_IsButtonPressed(gamePadIndex, buttonMapping.padButton)) + { + CL_GamepadButtonEventForPort( + gamePadIndex, + buttonMapping.code, + Game::GPAD_BUTTON_PRESSED, + time, + buttonMapping.padButton); + } + else if(GPad_ButtonRequiresUpdates(gamePadIndex, buttonMapping.padButton)) + { + CL_GamepadButtonEventForPort( + gamePadIndex, + buttonMapping.code, + Game::GPAD_BUTTON_UPDATE, + time, + buttonMapping.padButton); + } + else if(GPad_IsButtonReleased(gamePadIndex, buttonMapping.padButton)) + { + CL_GamepadButtonEventForPort( + gamePadIndex, + buttonMapping.code, + Game::GPAD_BUTTON_RELEASED, + time, + buttonMapping.padButton); + } + } + } + } + + gpad_present.setRaw(gpadPresent); } @@ -705,24 +992,37 @@ namespace Components InitDvars(); } + void Gamepad::CreateKeyNameMap() + { + memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); + memcpy(&Game::combinedKeyNames[Game::VANILLA_KEY_NAME_COUNT], Game::extendedKeyNames, sizeof(Game::keyname_t) * std::extent_v); + Game::combinedKeyNames[std::extent_v - 1] = { nullptr, 0 }; + + Utils::Hook::Set(0x4A780A, Game::combinedKeyNames); + Utils::Hook::Set(0x4A7810, Game::combinedKeyNames); + Utils::Hook::Set(0x435C9F, Game::combinedKeyNames); + } + Gamepad::Gamepad() { if (ZoneBuilder::IsEnabled()) return; // use the xinput state when creating a usercmd - Utils::Hook(0x5A6DB9, Gamepad::CL_CreateCmdStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x5A6DB9, CL_CreateCmdStub, HOOK_JUMP).install()->quick(); // package the forward and right move components in the move buttons - Utils::Hook(0x60E38D, Gamepad::MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x60E38D, MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); // send two bytes for sending movement data Utils::Hook::Set(0x60E501, 16); Utils::Hook::Set(0x60E5CD, 16); // make sure to parse the movement data properly and apply it - Utils::Hook(0x492127, Gamepad::MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); - Utils::Hook(0x492009, Gamepad::MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492127, MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x492009, MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + + CreateKeyNameMap(); if (Dedicated::IsEnabled()) return; diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index e3c19d98..8215d014 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -1,23 +1,115 @@ #pragma once +namespace Game +{ + static constexpr auto MAX_GAMEPADS = 1; + + static constexpr auto GPAD_VALUE_MASK = 0xFFFFFFFu; + static constexpr auto GPAD_DIGITAL_MASK = 1u << 28; + static constexpr auto GPAD_ANALOG_MASK = 1u << 29; + static constexpr auto GPAD_STICK_MASK = 1u << 30; + + enum GamePadButton + { + GPAD_NONE = 0, + GPAD_UP = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_UP & GPAD_VALUE_MASK), + GPAD_DOWN = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_DOWN & GPAD_VALUE_MASK), + GPAD_LEFT = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_LEFT & GPAD_VALUE_MASK), + GPAD_RIGHT = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_RIGHT & GPAD_VALUE_MASK), + GPAD_START = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_START & GPAD_VALUE_MASK), + GPAD_BACK = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_BACK & GPAD_VALUE_MASK), + GPAD_L3 = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_LEFT_THUMB & GPAD_VALUE_MASK), + GPAD_R3 = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_RIGHT_THUMB & GPAD_VALUE_MASK), + GPAD_L_SHLDR = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_LEFT_SHOULDER & GPAD_VALUE_MASK), + GPAD_R_SHLDR = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_RIGHT_SHOULDER & GPAD_VALUE_MASK), + GPAD_A = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_A & GPAD_VALUE_MASK), + GPAD_B = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_B & GPAD_VALUE_MASK), + GPAD_X = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_X & GPAD_VALUE_MASK), + GPAD_Y = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_Y & GPAD_VALUE_MASK), + GPAD_L_TRIG = GPAD_ANALOG_MASK | (0 & GPAD_VALUE_MASK), + GPAD_R_TRIG = GPAD_ANALOG_MASK | (1 & GPAD_VALUE_MASK), + }; + + enum GamePadStick + { + GPAD_INVALID = 0x0, + GPAD_LX = GPAD_STICK_MASK | (0 & GPAD_VALUE_MASK), + GPAD_LY = GPAD_STICK_MASK | (1 & GPAD_VALUE_MASK), + GPAD_RX = GPAD_STICK_MASK | (2 & GPAD_VALUE_MASK), + GPAD_RY = GPAD_STICK_MASK | (3 & GPAD_VALUE_MASK), + }; + + enum GamePadButtonEvent + { + GPAD_BUTTON_RELEASED = 0x0, + GPAD_BUTTON_PRESSED = 0x1, + GPAD_BUTTON_UPDATE = 0x2, + }; + + enum GamepadPhysicalAxis + { + GPAD_PHYSAXIS_NONE = -1, + GPAD_PHYSAXIS_RSTICK_X = 0x0, + GPAD_PHYSAXIS_RSTICK_Y = 0x1, + GPAD_PHYSAXIS_LSTICK_X = 0x2, + GPAD_PHYSAXIS_LSTICK_Y = 0x3, + GPAD_PHYSAXIS_RTRIGGER = 0x4, + GPAD_PHYSAXIS_LTRIGGER = 0x5, + + GPAD_PHYSAXIS_COUNT, + }; + + enum GamePadStickDir + { + GPAD_STICK_POS = 0x0, + GPAD_STICK_NEG = 0x1, + + GPAD_STICK_DIR_COUNT + }; + + enum GamepadMapping + { + GPAD_MAP_NONE = -1, + GPAD_MAP_LINEAR = 0x0, + GPAD_MAP_SQUARED = 0x1, + GPAD_MAP_COUNT = 0x2 + }; + + struct ButtonToCodeMap_t + { + GamePadButton padButton; + int code; + }; + + struct StickToCodeMap_t + { + GamePadStick padStick; + GamePadStickDir padStickDir; + int code; + }; + + struct GamepadVirtualAxisMapping + { + GamepadPhysicalAxis physicalAxis; + GamepadMapping mapType; + }; + + struct GpadAxesGlob + { + float axesValues[GPAD_PHYSAXIS_COUNT]; + GamepadVirtualAxisMapping virtualAxes[GPAD_PHYSAXIS_COUNT]; + }; +} + namespace Components { class Gamepad : public Component { - static constexpr auto MAX_GAMEPADS = 1; static constexpr float TRIGGER_THRESHOLD_F = static_cast(XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / static_cast(0xFF); public: Gamepad(); - enum GamePadStickDir - { - GPAD_STICK_POS = 0x0, - GPAD_STICK_NEG = 0x1, - - GPAD_STICK_DIR_COUNT - }; - struct GamePad { bool enabled; @@ -28,8 +120,8 @@ namespace Components float lastAnalogs[2]; float sticks[4]; float lastSticks[4]; - bool stickDown[4][GPAD_STICK_DIR_COUNT]; - bool stickDownLast[4][GPAD_STICK_DIR_COUNT]; + bool stickDown[4][Game::GPAD_STICK_DIR_COUNT]; + bool stickDownLast[4][Game::GPAD_STICK_DIR_COUNT]; float lowRumble; float highRumble; @@ -37,6 +129,11 @@ namespace Components XINPUT_CAPABILITIES caps; }; + struct GamePadGlobals + { + unsigned nextScrollTime; + }; + struct ActionMapping { int input; @@ -68,7 +165,8 @@ namespace Components }; private: - static GamePad gamePads[MAX_GAMEPADS]; + static GamePad gamePads[Game::MAX_GAMEPADS]; + static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; static bool isHoldingMaxLookX; static std::chrono::milliseconds timeAtFirstHeldMaxLookX; @@ -76,7 +174,7 @@ namespace Components static std::chrono::milliseconds lastNavigationTime; static std::chrono::milliseconds msBetweenNavigations; - static GamePadStickDir lastMenuNavigationDirection; + static Game::GamePadStickDir lastMenuNavigationDirection; static Dvar::Var gpad_enabled; static Dvar::Var gpad_debug; @@ -125,7 +223,17 @@ namespace Components static void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y); static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); + static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); + static void CL_GamepadEvent(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, float value); + static void CL_GamepadButtonEvent(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button); + static void CL_GamepadButtonEventForPort(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned int time, Game::GamePadButton button); + static void GPad_ConvertStickToFloat(short x, short y, float& outX, float& outY); + static float GPad_GetStick(int gamePadIndex, Game::GamePadStick stick); + static float GPad_GetButton(int gamePadIndex, Game::GamePadButton button); + static bool GPad_IsButtonPressed(int gamePadIndex, Game::GamePadButton button); + static bool GPad_ButtonRequiresUpdates(int gamePadIndex, Game::GamePadButton button); + static bool GPad_IsButtonReleased(int gamePadIndex, Game::GamePadButton button); static void GPad_UpdateSticksDown(int gamePadIndex); static void GPad_UpdateSticks(int gamePadIndex, const XINPUT_GAMEPAD& state); @@ -140,5 +248,7 @@ namespace Components static void InitDvars(); static void IN_Init_Hk(); + + static void CreateKeyNameMap(); }; } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index b437baa8..d99481d2 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -206,11 +206,48 @@ namespace Game }; #pragma pack(pop) + enum KeyCatch_t + { + KEYCATCH_CONSOLE = 0x1, + KEYCATCH_UNKNOWN2 = 0x2, + KEYCATCH_UNKNOWN4 = 0x4, + KEYCATCH_LOCATION_SELECTION = 0x8, + KEYCATCH_UI = 0x10, + KEYCATCH_CHAT = 0x20, + KEYCATCH_UNKNOWN40 = 0x40, + KEYCATCH_UNKNOWN80 = 0x80, + KEYCATCH_UNKNOWN100 = 0x100, + }; + enum keyNum_t { K_NONE = 0x0, + K_FIRSTGAMEPADBUTTON_RANGE_1 = 0x1, // First Gamepad 1 + K_BUTTON_A = 0x1, + K_BUTTON_B = 0x2, + K_BUTTON_X = 0x3, + K_BUTTON_Y = 0x4, + K_BUTTON_LSHLDR = 0x5, + K_BUTTON_RSHLDR = 0x6, + K_LASTGAMEPADBUTTON_RANGE_1 = 0x6, // Last Gamepad 1 K_TAB = 0x9, K_ENTER = 0xD, + K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, // First Gamepad 2 + K_BUTTON_START = 0xE, + K_BUTTON_BACK = 0xF, + K_BUTTON_LSTICK = 0x10, + K_BUTTON_RSTICK = 0x11, + K_BUTTON_LTRIG = 0x12, + K_BUTTON_RTRIG = 0x13, + K_FIRSTDPAD = 0x14, // First Dpad + K_DPAD_UP = 0x14, + K_DPAD_DOWN = 0x15, + K_DPAD_LEFT = 0x16, + K_DPAD_RIGHT = 0x17, + K_LASTDPAD = 0x17, // Last Dpad + K_DPAD_LEFTRIGHT = 0x18, + K_DPAD_UPDOWN = 0x19, + K_LASTGAMEPADBUTTON_RANGE_2 = 0x19, // Last Gamepad 2 K_ESCAPE = 0x1B, K_SPACE = 0x20, K_BACKSPACE = 0x7F, @@ -1104,6 +1141,40 @@ namespace Game LOC_SEL_INPUT_CANCEL = 0x2, }; + struct field_t + { + int cursor; + int scroll; + int drawWidth; + int widthInPixels; + float charHeight; + int fixedSize; + char buffer[256]; + }; + + struct KeyState + { + int down; + int repeats; + const char* binding; + }; + + struct PlayerKeyState + { + field_t chatField; + int chat_team; + int overstrikeMode; + int anyKeyDown; + KeyState keys[256]; + LocSelInputState locSelInputState; + }; + + struct keyname_t + { + const char* name; + int keynum; + }; + struct clSnapshot_t { playerState_s ps; From b6d7abdcd4a8feb38fb149d3f987b609e1a61b29 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 01:41:32 +0200 Subject: [PATCH 29/83] Execute gamepad keybinds --- src/Components/Modules/Gamepad.cpp | 90 +++++++++++++++++++++++++++--- src/Components/Modules/Gamepad.hpp | 1 + 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index d6d02195..f725992e 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -597,14 +597,22 @@ namespace Components Game::gaGlobs[gamePadIndex].axesValues[physicalAxis] = value; } + void Gamepad::UI_GamepadKeyEvent(int gamePadIndex, int key, bool down) + { + + } + void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button) { assert(gamePadIndex < Game::MAX_GAMEPADS); - auto& keyState = Game::playerKeys[gamePadIndex]; - keyState.keys[key].down = buttonEvent == Game::GPAD_BUTTON_PRESSED || buttonEvent == Game::GPAD_BUTTON_UPDATE; + const auto pressed = buttonEvent == Game::GPAD_BUTTON_PRESSED; + const auto pressedOrUpdated = pressed || buttonEvent == Game::GPAD_BUTTON_UPDATE; - if(buttonEvent == Game::GPAD_BUTTON_PRESSED) + auto& keyState = Game::playerKeys[gamePadIndex]; + keyState.keys[key].down = pressedOrUpdated; + + if(pressed) { if (++keyState.keys[key].repeats == 1) keyState.anyKeyDown++; @@ -615,6 +623,72 @@ namespace Components if (--keyState.anyKeyDown < 0) keyState.anyKeyDown = 0; } + + if(Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_LOCATION_SELECTION) && pressedOrUpdated) + { + if(key == Game::K_BUTTON_B || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+actionslot 4") == 0) + { + keyState.locSelInputState = Game::LOC_SEL_INPUT_CANCEL; + } + else if(key == Game::K_BUTTON_A || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+attack") == 0) + { + keyState.locSelInputState = Game::LOC_SEL_INPUT_CONFIRM; + } + return; + } + + keyState.locSelInputState = Game::LOC_SEL_INPUT_NONE; + + const auto* keyBinding = keyState.keys[key].binding; + + if (!keyBinding) + return; + + char cmd[1024]; + if(pressedOrUpdated) + { + if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) + { + UI_GamepadKeyEvent(gamePadIndex, key, pressedOrUpdated); + return; + } + + if(keyBinding[0] == '+') + { + float floatValue; + if (button) + floatValue = GPad_GetButton(gamePadIndex, button); + else + floatValue = 0.0f; + + sprintf_s(cmd, "%s %i %i %0.3f\n", keyBinding, key, time, floatValue); + Game::Cbuf_AddText(gamePadIndex, cmd); + } + else + { + Game::Cbuf_AddText(gamePadIndex, keyBinding); + Game::Cbuf_AddText(gamePadIndex, "\n"); + } + } + else + { + if (keyBinding[0] == '+') + { + float floatValue; + if (button) + floatValue = GPad_GetButton(gamePadIndex, button); + else + floatValue = 0.0f; + + sprintf_s(cmd, "-%s %i %i %0.3f\n", &keyBinding[1], key, time, floatValue); + Game::Cbuf_AddText(gamePadIndex, cmd); + } + + if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) + { + UI_GamepadKeyEvent(gamePadIndex, key, pressedOrUpdated); + } + } } void Gamepad::CL_GamepadButtonEventForPort(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time, const Game::GamePadButton button) @@ -1009,7 +1083,7 @@ namespace Components return; // use the xinput state when creating a usercmd - Utils::Hook(0x5A6DB9, CL_CreateCmdStub, HOOK_JUMP).install()->quick(); + //Utils::Hook(0x5A6DB9, CL_CreateCmdStub, HOOK_JUMP).install()->quick(); // package the forward and right move components in the move buttons Utils::Hook(0x60E38D, MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); @@ -1031,11 +1105,11 @@ namespace Components Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); - Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); + //Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + //Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); + //Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - Scheduler::OnFrame(MenuNavigate); + //Scheduler::OnFrame(MenuNavigate); xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 8215d014..6c0fd096 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -224,6 +224,7 @@ namespace Components static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); + static void UI_GamepadKeyEvent(int gamePadIndex, int key, bool down); static void CL_GamepadEvent(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, float value); static void CL_GamepadButtonEvent(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button); static void CL_GamepadButtonEventForPort(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned int time, Game::GamePadButton button); From 9b4a48f2c3f1fdff6e93ab9ed06a9d1a8706b086 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 13:44:46 +0200 Subject: [PATCH 30/83] Implement menu navigation using gamepad --- src/Components/Modules/Gamepad.cpp | 275 ++++++++++++++++------------- src/Components/Modules/Gamepad.hpp | 23 +-- src/Game/Functions.hpp | 2 +- src/Game/Structs.hpp | 8 + 4 files changed, 172 insertions(+), 136 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index f725992e..1c80f6d0 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -27,16 +27,30 @@ namespace Game {GPAD_RIGHT, K_DPAD_RIGHT} }; - StickToCodeMap_t analogStickList[] + StickToCodeMap_t analogStickList[4] { - {GPAD_LY, GPAD_STICK_POS, K_DPAD_UP}, - {GPAD_LY, GPAD_STICK_NEG, K_DPAD_DOWN}, - {GPAD_LX, GPAD_STICK_POS, K_DPAD_RIGHT}, - {GPAD_LX, GPAD_STICK_NEG, K_DPAD_LEFT}, + {GPAD_LX, K_APAD_RIGHT, K_APAD_LEFT}, + {GPAD_LY, K_APAD_UP, K_APAD_DOWN}, + {GPAD_RX, K_APAD_RIGHT, K_APAD_LEFT}, + {GPAD_RY, K_APAD_UP, K_APAD_DOWN}, + }; + + GamePadStick stickForAxis[GPAD_PHYSAXIS_COUNT] + { + GPAD_RX, + GPAD_RY, + GPAD_LX, + GPAD_LY, + GPAD_INVALID, + GPAD_INVALID }; keyNum_t menuScrollButtonList[] { + K_APAD_UP, + K_APAD_DOWN, + K_APAD_LEFT, + K_APAD_RIGHT, K_DPAD_UP, K_DPAD_DOWN, K_DPAD_LEFT, @@ -106,6 +120,29 @@ namespace Components std::chrono::milliseconds Gamepad::lastNavigationTime = 0ms; std::chrono::milliseconds Gamepad::msBetweenNavigations = 220ms; + struct ControllerMenuKeyMapping + { + Game::keyNum_t controllerKey; + Game::keyNum_t pcKey; + }; + + ControllerMenuKeyMapping controllerMenuKeyMappings[] + { + {Game::K_BUTTON_A, Game::K_KP_ENTER}, + {Game::K_BUTTON_START, Game::K_KP_ENTER}, + {Game::K_BUTTON_B, Game::K_ESCAPE}, + {Game::K_BUTTON_BACK, Game::K_ESCAPE}, + {Game::K_DPAD_UP, Game::K_KP_UPARROW}, + {Game::K_APAD_UP, Game::K_KP_UPARROW}, + {Game::K_DPAD_DOWN, Game::K_KP_DOWNARROW}, + {Game::K_APAD_DOWN, Game::K_KP_DOWNARROW}, + {Game::K_DPAD_LEFT, Game::K_KP_LEFTARROW}, + {Game::K_APAD_LEFT, Game::K_KP_LEFTARROW}, + {Game::K_DPAD_RIGHT, Game::K_KP_RIGHTARROW}, + {Game::K_APAD_RIGHT, Game::K_KP_RIGHTARROW}, + }; + + // This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg std::vector mappings = { Gamepad::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), @@ -125,14 +162,6 @@ namespace Components }; // Same thing - std::vector menuMappings = { - Gamepad::MenuMapping(XINPUT_GAMEPAD_A, Game::keyNum_t::K_KP_ENTER), - Gamepad::MenuMapping(XINPUT_GAMEPAD_B, Game::keyNum_t::K_ESCAPE), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_RIGHT, Game::keyNum_t::K_KP_RIGHTARROW), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_LEFT, Game::keyNum_t::K_KP_LEFTARROW), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_UP, Game::keyNum_t::K_KP_UPARROW), - Gamepad::MenuMapping(XINPUT_GAMEPAD_DPAD_DOWN, Game::keyNum_t::K_KP_DOWNARROW) - }; // void Gamepad::Vibrate(int leftVal, int rightVal) // { @@ -339,65 +368,6 @@ namespace Components } } - void Gamepad::MenuNavigate() - { - auto& gamePad = gamePads[0]; - Game::menuDef_t* menuDef = Game::Menu_GetFocused(Game::uiContext); - - if (menuDef) - { - if (gamePad.enabled) - { - std::chrono::milliseconds now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - std::chrono::milliseconds timeSinceLastNavigation = now - lastNavigationTime; - bool canNavigate = timeSinceLastNavigation > msBetweenNavigations; - - if (gamePad.stickDown[1][Game::GPAD_STICK_POS]) - { - if (canNavigate) - { - Menu_SetPrevCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = Game::GPAD_STICK_POS; - lastNavigationTime = now; - } - } - else if (gamePad.stickDown[1][Game::GPAD_STICK_NEG]) - { - if (canNavigate) - { - Menu_SetNextCursorItem(Game::uiContext, menuDef, 1); - lastMenuNavigationDirection = Game::GPAD_STICK_NEG; - lastNavigationTime = now; - } - } - else - { - lastMenuNavigationDirection = Game::GPAD_STICK_DIR_COUNT; - } - - for (auto& mapping : menuMappings) - { - if (mapping.wasPressed) - { - if (gamePad.digitals & mapping.input) - { - // Button still pressed, do not send info - } - else - { - mapping.wasPressed = false; - } - } - else if (gamePad.digitals & mapping.input) - { - Game::UI_KeyEvent(0, mapping.keystroke, 1); - mapping.wasPressed = true; - } - } - } - } - } - int Gamepad::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) { const auto& gamePad = gamePads[0]; @@ -589,20 +559,99 @@ namespace Components } } - void Gamepad::CL_GamepadEvent(int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, const float value) + void Gamepad::CL_GamepadGenerateAPad(const int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, unsigned time) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); + + auto& gamePad = gamePads[gamePadIndex]; + + const auto stick = Game::stickForAxis[physicalAxis]; + const auto stickIndex = stick & Game::GPAD_VALUE_MASK; + if(stick != Game::GPAD_INVALID) + { + assert(stickIndex < 4); + const auto& mapping = Game::analogStickList[stickIndex]; + + if(gamePad.stickDown[stickIndex][Game::GPAD_STICK_POS]) + { + const Game::GamePadButtonEvent event = gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS] ? Game::GPAD_BUTTON_UPDATE : Game::GPAD_BUTTON_PRESSED; + CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, event, time, Game::GPAD_NONE); + } + else if(gamePad.stickDown[stickIndex][Game::GPAD_STICK_NEG]) + { + const Game::GamePadButtonEvent event = gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG] ? Game::GPAD_BUTTON_UPDATE : Game::GPAD_BUTTON_PRESSED; + CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, event, time, Game::GPAD_NONE); + } + else if(gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS]) + { + CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, Game::GPAD_BUTTON_RELEASED, time, Game::GPAD_NONE); + } + else if(gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG]) + { + CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, Game::GPAD_BUTTON_RELEASED, time, Game::GPAD_NONE); + } + } + } + + void Gamepad::CL_GamepadEvent(int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, const float value, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); Game::gaGlobs[gamePadIndex].axesValues[physicalAxis] = value; + CL_GamepadGenerateAPad(gamePadIndex, physicalAxis, time); } - void Gamepad::UI_GamepadKeyEvent(int gamePadIndex, int key, bool down) + void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down) { - + for(const auto& mapping : controllerMenuKeyMappings) + { + if(mapping.controllerKey == key) + { + Game::UI_KeyEvent(gamePadIndex, mapping.pcKey, down); + return; + } + } + + // No point in sending unmapped controller keystrokes to the key event handler since it doesn't know how to use it anyway + // Game::UI_KeyEvent(gamePadIndex, key, down); } - void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button) + bool Gamepad::CL_CheckForIgnoreDueToRepeat(const int gamePadIndex, const int key, const int repeatCount, const unsigned time) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + + if(Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) + { + const int scrollDelayFirst = gpad_menu_scroll_delay_first.get(); + const int scrollDelayRest = gpad_menu_scroll_delay_rest.get(); + + for(const auto menuScrollButton : Game::menuScrollButtonList) + { + if(key == menuScrollButton) + { + if(repeatCount == 1) + { + gamePadGlobal.nextScrollTime = time + scrollDelayFirst; + return false; + } + + if(time > gamePadGlobal.nextScrollTime) + { + gamePadGlobal.nextScrollTime = time + scrollDelayRest; + return false; + } + break; + } + } + } + + return repeatCount > 1; + } + + void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time, const Game::GamePadButton button) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -612,18 +661,21 @@ namespace Components auto& keyState = Game::playerKeys[gamePadIndex]; keyState.keys[key].down = pressedOrUpdated; - if(pressed) + if(pressedOrUpdated) { if (++keyState.keys[key].repeats == 1) keyState.anyKeyDown++; } - else if(keyState.keys[key].repeats > 0) + else if(buttonEvent == Game::GPAD_BUTTON_RELEASED && keyState.keys[key].repeats > 0) { keyState.keys[key].repeats = 0; if (--keyState.anyKeyDown < 0) keyState.anyKeyDown = 0; } + if (pressedOrUpdated && CL_CheckForIgnoreDueToRepeat(gamePadIndex, key, keyState.keys[key].repeats, time)) + return; + if(Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_LOCATION_SELECTION) && pressedOrUpdated) { if(key == Game::K_BUTTON_B || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+actionslot 4") == 0) @@ -640,10 +692,7 @@ namespace Components keyState.locSelInputState = Game::LOC_SEL_INPUT_NONE; const auto* keyBinding = keyState.keys[key].binding; - - if (!keyBinding) - return; - + char cmd[1024]; if(pressedOrUpdated) { @@ -653,26 +702,29 @@ namespace Components return; } - if(keyBinding[0] == '+') + if (keyBinding) { - float floatValue; - if (button) - floatValue = GPad_GetButton(gamePadIndex, button); - else - floatValue = 0.0f; + if (keyBinding[0] == '+') + { + float floatValue; + if (button) + floatValue = GPad_GetButton(gamePadIndex, button); + else + floatValue = 0.0f; - sprintf_s(cmd, "%s %i %i %0.3f\n", keyBinding, key, time, floatValue); - Game::Cbuf_AddText(gamePadIndex, cmd); - } - else - { - Game::Cbuf_AddText(gamePadIndex, keyBinding); - Game::Cbuf_AddText(gamePadIndex, "\n"); + sprintf_s(cmd, "%s %i %i %0.3f\n", keyBinding, key, time, floatValue); + Game::Cbuf_AddText(gamePadIndex, cmd); + } + else + { + Game::Cbuf_AddText(gamePadIndex, keyBinding); + Game::Cbuf_AddText(gamePadIndex, "\n"); + } } } else { - if (keyBinding[0] == '+') + if (keyBinding && keyBinding[0] == '+') { float floatValue; if (button) @@ -765,19 +817,8 @@ namespace Components if(button & Game::GPAD_DIGITAL_MASK) { const auto buttonValue = button & Game::GPAD_VALUE_MASK; - if (button & 0xF && buttonValue & gamePad.digitals && (gamePad.digitals & 0xF) != (button & 0xF)) - { - down = false; - lastDown = false; - } - else - { - down = (buttonValue & gamePad.digitals) != 0; - if (button & 0xF && buttonValue & gamePad.lastDigitals && (gamePad.lastDigitals & 0xF) != (button & 0xF)) - lastDown = false; - else - lastDown = (buttonValue & gamePad.lastDigitals) != 0; - } + down = (buttonValue & gamePad.digitals) != 0; + lastDown = (buttonValue & gamePad.lastDigitals) != 0; } else if(button & Game::GPAD_ANALOG_MASK) { @@ -796,7 +837,7 @@ namespace Components bool Gamepad::GPad_ButtonRequiresUpdates(const int gamePadIndex, Game::GamePadButton button) { - return button & Game::GPAD_ANALOG_MASK && GPad_GetButton(gamePadIndex, button) > 0.0f; + return (button & Game::GPAD_ANALOG_MASK || button & Game::GPAD_DPAD_MASK) && GPad_GetButton(gamePadIndex, button) > 0.0f; } bool Gamepad::GPad_IsButtonReleased(int gamePadIndex, Game::GamePadButton button) @@ -985,12 +1026,12 @@ namespace Components const auto leftTrig = GPad_GetButton(gamePadIndex, Game::GPAD_L_TRIG); const auto rightTrig = GPad_GetButton(gamePadIndex, Game::GPAD_R_TRIG); - CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_X, lx); - CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_Y, ly); - CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_X, rx); - CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_Y, ry); - CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LTRIGGER, leftTrig); - CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RTRIGGER, rightTrig); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_X, lx, time); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_Y, ly, time); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_X, rx, time); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_Y, ry, time); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LTRIGGER, leftTrig, time); + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RTRIGGER, rightTrig, time); for (const auto& buttonMapping : Game::buttonList) { @@ -1109,8 +1150,6 @@ namespace Components //Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); //Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - //Scheduler::OnFrame(MenuNavigate); - xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 6c0fd096..b33f5ad3 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -5,6 +5,7 @@ namespace Game static constexpr auto MAX_GAMEPADS = 1; static constexpr auto GPAD_VALUE_MASK = 0xFFFFFFFu; + static constexpr auto GPAD_DPAD_MASK = XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT; static constexpr auto GPAD_DIGITAL_MASK = 1u << 28; static constexpr auto GPAD_ANALOG_MASK = 1u << 29; static constexpr auto GPAD_STICK_MASK = 1u << 30; @@ -84,8 +85,8 @@ namespace Game struct StickToCodeMap_t { GamePadStick padStick; - GamePadStickDir padStickDir; - int code; + int posCode; + int negCode; }; struct GamepadVirtualAxisMapping @@ -151,19 +152,6 @@ namespace Components } }; - struct MenuMapping - { - int input; - Game::keyNum_t keystroke; - bool wasPressed = false; - - MenuMapping(int input, Game::keyNum_t keystroke) - { - this->keystroke = keystroke; - this->input = input; - } - }; - private: static GamePad gamePads[Game::MAX_GAMEPADS]; static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; @@ -210,7 +198,6 @@ namespace Components static void CL_CreateCmdStub(); static void CL_GamepadMove(int, Game::usercmd_s*); - static void MenuNavigate(); static void MSG_WriteDeltaUsercmdKeyStub(); @@ -224,8 +211,10 @@ namespace Components static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); + static bool CL_CheckForIgnoreDueToRepeat(int gamePadIndex, int key, int repeatCount, unsigned int time); static void UI_GamepadKeyEvent(int gamePadIndex, int key, bool down); - static void CL_GamepadEvent(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, float value); + static void CL_GamepadGenerateAPad(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, unsigned time); + static void CL_GamepadEvent(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, float value, unsigned time); static void CL_GamepadButtonEvent(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button); static void CL_GamepadButtonEventForPort(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned int time, Game::GamePadButton button); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 37a243d6..fdeaeeb2 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -426,7 +426,7 @@ namespace Game typedef void(__cdecl* Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down); extern Menu_HandleKey_t Menu_HandleKey; - typedef bool(__cdecl* UI_KeyEvent_t)(int clientNum, Game::keyNum_t key, int down); + typedef bool(__cdecl* UI_KeyEvent_t)(int clientNum, int key, int down); extern UI_KeyEvent_t UI_KeyEvent; typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index d99481d2..269ec59d 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -249,6 +249,14 @@ namespace Game K_DPAD_UPDOWN = 0x19, K_LASTGAMEPADBUTTON_RANGE_2 = 0x19, // Last Gamepad 2 K_ESCAPE = 0x1B, + K_FIRSTGAMEPADBUTTON_RANGE_3 = 0x1C, // First Gamepad 3 + K_FIRSTAPAD = 0x1C, // First APad + K_APAD_UP = 0x1C, + K_APAD_DOWN = 0x1D, + K_APAD_LEFT = 0x1E, + K_APAD_RIGHT = 0x1F, + K_LASTAPAD = 0x1F, // Last APad + K_LASTGAMEPADBUTTON_RANGE_3 = 0x1F, // Last Gamepad 3 K_SPACE = 0x20, K_BACKSPACE = 0x7F, K_ASCII_FIRST = 0x80, From dcbb120de178f32d4e7dc4ff03f01da56b2577f2 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 14:00:59 +0200 Subject: [PATCH 31/83] Fix menu controller support taking keypad keys instead of normal keys --- src/Components/Modules/Gamepad.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 1c80f6d0..66503748 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -128,18 +128,18 @@ namespace Components ControllerMenuKeyMapping controllerMenuKeyMappings[] { - {Game::K_BUTTON_A, Game::K_KP_ENTER}, - {Game::K_BUTTON_START, Game::K_KP_ENTER}, + {Game::K_BUTTON_A, Game::K_ENTER}, + {Game::K_BUTTON_START, Game::K_ENTER}, {Game::K_BUTTON_B, Game::K_ESCAPE}, {Game::K_BUTTON_BACK, Game::K_ESCAPE}, - {Game::K_DPAD_UP, Game::K_KP_UPARROW}, - {Game::K_APAD_UP, Game::K_KP_UPARROW}, - {Game::K_DPAD_DOWN, Game::K_KP_DOWNARROW}, - {Game::K_APAD_DOWN, Game::K_KP_DOWNARROW}, - {Game::K_DPAD_LEFT, Game::K_KP_LEFTARROW}, - {Game::K_APAD_LEFT, Game::K_KP_LEFTARROW}, - {Game::K_DPAD_RIGHT, Game::K_KP_RIGHTARROW}, - {Game::K_APAD_RIGHT, Game::K_KP_RIGHTARROW}, + {Game::K_DPAD_UP, Game::K_UPARROW}, + {Game::K_APAD_UP, Game::K_UPARROW}, + {Game::K_DPAD_DOWN, Game::K_DOWNARROW}, + {Game::K_APAD_DOWN, Game::K_DOWNARROW}, + {Game::K_DPAD_LEFT, Game::K_LEFTARROW}, + {Game::K_APAD_LEFT, Game::K_LEFTARROW}, + {Game::K_DPAD_RIGHT, Game::K_RIGHTARROW}, + {Game::K_APAD_RIGHT, Game::K_RIGHTARROW}, }; From 8cd99235c0a782eae344e6d5c0a295349a088b8a Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 16:07:23 +0200 Subject: [PATCH 32/83] Write gamepad axis configuration to config file --- src/Components/Modules/Gamepad.cpp | 273 ++++++++++++++++++++++++----- src/Components/Modules/Gamepad.hpp | 34 +++- src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 3 + 4 files changed, 270 insertions(+), 41 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 66503748..f59beeb8 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -45,6 +45,32 @@ namespace Game GPAD_INVALID }; + const char* physicalAxisNames[GPAD_PHYSAXIS_COUNT] + { + "A_RSTICK_X", + "A_RSTICK_Y", + "A_LSTICK_X", + "A_LSTICK_Y", + "A_RTRIGGER", + "A_LTRIGGER" + }; + + const char* virtualAxisNames[GPAD_VIRTAXIS_COUNT] + { + "VA_SIDE", + "VA_FORWARD", + "VA_UP", + "VA_YAW", + "VA_PITCH", + "VA_ATTACK" + }; + + const char* gamePadMappingTypeNames[GPAD_MAP_COUNT] + { + "MAP_LINEAR", + "MAP_SQUARED" + }; + keyNum_t menuScrollButtonList[] { K_APAD_UP, @@ -80,7 +106,6 @@ namespace Game keyname_t combinedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; - GpadAxesGlob gaGlobs[MAX_GAMEPADS]; PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); } @@ -88,7 +113,8 @@ namespace Game namespace Components { Gamepad::GamePad Gamepad::gamePads[Game::MAX_GAMEPADS]{}; - Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GAMEPADS]{}; + Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GAMEPADS]{{}}; + int Gamepad::gamePadBindingsModifiedFlags = 0; std::chrono::milliseconds Gamepad::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) bool Gamepad::isHoldingMaxLookX = false; bool Gamepad::isADS; @@ -161,6 +187,18 @@ namespace Components Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), }; + Gamepad::GamePadGlobals::GamePadGlobals() + : axes{}, + nextScrollTime(0) + { + for (auto& virtualAxis : axes.virtualAxes) + { + virtualAxis.physicalAxis = Game::GPAD_PHYSAXIS_NONE; + virtualAxis.mapType = Game::GPAD_MAP_NONE; + } + } + + // Same thing // void Gamepad::Vibrate(int leftVal, int rightVal) @@ -549,9 +587,9 @@ namespace Components return; const auto scrollDelayFirst = gpad_menu_scroll_delay_first.get(); - for(const auto scrollButton : Game::menuScrollButtonList) + for (const auto scrollButton : Game::menuScrollButtonList) { - if(key == scrollButton) + if (key == scrollButton) { gamePadGlobal.nextScrollTime = scrollDelayFirst + time; return; @@ -568,46 +606,48 @@ namespace Components const auto stick = Game::stickForAxis[physicalAxis]; const auto stickIndex = stick & Game::GPAD_VALUE_MASK; - if(stick != Game::GPAD_INVALID) + if (stick != Game::GPAD_INVALID) { assert(stickIndex < 4); const auto& mapping = Game::analogStickList[stickIndex]; - if(gamePad.stickDown[stickIndex][Game::GPAD_STICK_POS]) + if (gamePad.stickDown[stickIndex][Game::GPAD_STICK_POS]) { const Game::GamePadButtonEvent event = gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS] ? Game::GPAD_BUTTON_UPDATE : Game::GPAD_BUTTON_PRESSED; CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, event, time, Game::GPAD_NONE); } - else if(gamePad.stickDown[stickIndex][Game::GPAD_STICK_NEG]) + else if (gamePad.stickDown[stickIndex][Game::GPAD_STICK_NEG]) { const Game::GamePadButtonEvent event = gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG] ? Game::GPAD_BUTTON_UPDATE : Game::GPAD_BUTTON_PRESSED; CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, event, time, Game::GPAD_NONE); } - else if(gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS]) + else if (gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS]) { CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, Game::GPAD_BUTTON_RELEASED, time, Game::GPAD_NONE); } - else if(gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG]) + else if (gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG]) { CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, Game::GPAD_BUTTON_RELEASED, time, Game::GPAD_NONE); } } } - void Gamepad::CL_GamepadEvent(int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, const float value, const unsigned time) + void Gamepad::CL_GamepadEvent(const int gamePadIndex, const Game::GamepadPhysicalAxis physicalAxis, const float value, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); - Game::gaGlobs[gamePadIndex].axesValues[physicalAxis] = value; + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + + gamePadGlobal.axes.axesValues[physicalAxis] = value; CL_GamepadGenerateAPad(gamePadIndex, physicalAxis, time); } void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down) { - for(const auto& mapping : controllerMenuKeyMappings) + for (const auto& mapping : controllerMenuKeyMappings) { - if(mapping.controllerKey == key) + if (mapping.controllerKey == key) { Game::UI_KeyEvent(gamePadIndex, mapping.pcKey, down); return; @@ -623,22 +663,22 @@ namespace Components assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; - if(Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) + if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) { const int scrollDelayFirst = gpad_menu_scroll_delay_first.get(); const int scrollDelayRest = gpad_menu_scroll_delay_rest.get(); - for(const auto menuScrollButton : Game::menuScrollButtonList) + for (const auto menuScrollButton : Game::menuScrollButtonList) { - if(key == menuScrollButton) + if (key == menuScrollButton) { - if(repeatCount == 1) + if (repeatCount == 1) { gamePadGlobal.nextScrollTime = time + scrollDelayFirst; return false; } - if(time > gamePadGlobal.nextScrollTime) + if (time > gamePadGlobal.nextScrollTime) { gamePadGlobal.nextScrollTime = time + scrollDelayRest; return false; @@ -661,12 +701,12 @@ namespace Components auto& keyState = Game::playerKeys[gamePadIndex]; keyState.keys[key].down = pressedOrUpdated; - if(pressedOrUpdated) + if (pressedOrUpdated) { if (++keyState.keys[key].repeats == 1) keyState.anyKeyDown++; } - else if(buttonEvent == Game::GPAD_BUTTON_RELEASED && keyState.keys[key].repeats > 0) + else if (buttonEvent == Game::GPAD_BUTTON_RELEASED && keyState.keys[key].repeats > 0) { keyState.keys[key].repeats = 0; if (--keyState.anyKeyDown < 0) @@ -676,13 +716,13 @@ namespace Components if (pressedOrUpdated && CL_CheckForIgnoreDueToRepeat(gamePadIndex, key, keyState.keys[key].repeats, time)) return; - if(Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_LOCATION_SELECTION) && pressedOrUpdated) + if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_LOCATION_SELECTION) && pressedOrUpdated) { - if(key == Game::K_BUTTON_B || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+actionslot 4") == 0) + if (key == Game::K_BUTTON_B || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+actionslot 4") == 0) { keyState.locSelInputState = Game::LOC_SEL_INPUT_CANCEL; } - else if(key == Game::K_BUTTON_A || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+attack") == 0) + else if (key == Game::K_BUTTON_A || keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "+attack") == 0) { keyState.locSelInputState = Game::LOC_SEL_INPUT_CONFIRM; } @@ -692,9 +732,9 @@ namespace Components keyState.locSelInputState = Game::LOC_SEL_INPUT_NONE; const auto* keyBinding = keyState.keys[key].binding; - + char cmd[1024]; - if(pressedOrUpdated) + if (pressedOrUpdated) { if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) { @@ -789,12 +829,12 @@ namespace Components float value = 0.0f; - if(button & Game::GPAD_DIGITAL_MASK) + if (button & Game::GPAD_DIGITAL_MASK) { const auto buttonValue = button & Game::GPAD_VALUE_MASK; value = buttonValue & gamePad.digitals ? 1.0f : 0.0f; } - else if(button & Game::GPAD_ANALOG_MASK) + else if (button & Game::GPAD_ANALOG_MASK) { const auto analogIndex = button & Game::GPAD_VALUE_MASK; if (analogIndex < std::extent_v) @@ -814,18 +854,18 @@ namespace Components bool down = false; bool lastDown = false; - if(button & Game::GPAD_DIGITAL_MASK) + if (button & Game::GPAD_DIGITAL_MASK) { const auto buttonValue = button & Game::GPAD_VALUE_MASK; down = (buttonValue & gamePad.digitals) != 0; lastDown = (buttonValue & gamePad.lastDigitals) != 0; } - else if(button & Game::GPAD_ANALOG_MASK) + else if (button & Game::GPAD_ANALOG_MASK) { const auto analogIndex = button & Game::GPAD_VALUE_MASK; assert(analogIndex < std::extent_v); - if(analogIndex < std::extent_v) + if (analogIndex < std::extent_v) { down = gamePad.analogs[analogIndex] > 0.0f; lastDown = gamePad.lastAnalogs[analogIndex] > 0.0f; @@ -851,7 +891,7 @@ namespace Components if (button & Game::GPAD_DIGITAL_MASK) { const auto buttonValue = button & Game::GPAD_VALUE_MASK; - + down = (gamePad.digitals & buttonValue) != 0; lastDown = (gamePad.lastDigitals & buttonValue) != 0; } @@ -870,7 +910,7 @@ namespace Components return !down && lastDown; } - void Gamepad::GPad_UpdateSticksDown(int gamePadIndex) + void Gamepad::GPad_UpdateSticksDown(const int gamePadIndex) { assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; @@ -1012,11 +1052,11 @@ namespace Components const auto time = Game::Sys_Milliseconds(); bool gpadPresent = false; - for(auto gamePadIndex = 0; gamePadIndex < Game::MAX_GAMEPADS; gamePadIndex++) + for (auto gamePadIndex = 0; gamePadIndex < Game::MAX_GAMEPADS; gamePadIndex++) { const auto& gamePad = gamePads[gamePadIndex]; - if(gamePad.enabled) + if (gamePad.enabled) { gpadPresent = true; const auto lx = GPad_GetStick(gamePadIndex, Game::GPAD_LX); @@ -1025,7 +1065,7 @@ namespace Components const auto ry = GPad_GetStick(gamePadIndex, Game::GPAD_RY); const auto leftTrig = GPad_GetButton(gamePadIndex, Game::GPAD_L_TRIG); const auto rightTrig = GPad_GetButton(gamePadIndex, Game::GPAD_R_TRIG); - + CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_X, lx, time); CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LSTICK_Y, ly, time); CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RSTICK_X, rx, time); @@ -1035,7 +1075,7 @@ namespace Components for (const auto& buttonMapping : Game::buttonList) { - if(GPad_IsButtonPressed(gamePadIndex, buttonMapping.padButton)) + if (GPad_IsButtonPressed(gamePadIndex, buttonMapping.padButton)) { CL_GamepadButtonEventForPort( gamePadIndex, @@ -1044,7 +1084,7 @@ namespace Components time, buttonMapping.padButton); } - else if(GPad_ButtonRequiresUpdates(gamePadIndex, buttonMapping.padButton)) + else if (GPad_ButtonRequiresUpdates(gamePadIndex, buttonMapping.padButton)) { CL_GamepadButtonEventForPort( gamePadIndex, @@ -1053,7 +1093,7 @@ namespace Components time, buttonMapping.padButton); } - else if(GPad_IsButtonReleased(gamePadIndex, buttonMapping.padButton)) + else if (GPad_IsButtonReleased(gamePadIndex, buttonMapping.padButton)) { CL_GamepadButtonEventForPort( gamePadIndex, @@ -1078,6 +1118,153 @@ namespace Components IN_GamePadsMove(); } + void Gamepad::Gamepad_WriteBindings(const int gamePadIndex, const int handle) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + + Game::FS_Printf(handle, "unbindallaxis\n"); + + for(auto virtualAxisIndex = 0u; virtualAxisIndex < Game::GPAD_VIRTAXIS_COUNT; virtualAxisIndex++) + { + const auto& axisMapping = gamePadGlobal.axes.virtualAxes[virtualAxisIndex]; + if (axisMapping.physicalAxis <= Game::GPAD_PHYSAXIS_NONE || axisMapping.physicalAxis >= Game::GPAD_PHYSAXIS_COUNT + || axisMapping.mapType <= Game::GPAD_MAP_NONE || axisMapping.mapType >= Game::GPAD_MAP_COUNT) + { + continue; + } + + const auto* physicalAxisName = Game::physicalAxisNames[axisMapping.physicalAxis]; + const auto* virtualAxisName = Game::virtualAxisNames[virtualAxisIndex]; + const auto* mappingName = Game::gamePadMappingTypeNames[axisMapping.mapType]; + + Game::FS_Printf(handle, "bindaxis %s %s %s\n", physicalAxisName, virtualAxisName, mappingName); + } + } + + void Gamepad::Key_WriteBindings_Hk(const int localClientNum, const int handle) + { + // Call original function + Utils::Hook::Call(0x4A5A20)(localClientNum, handle); + + Gamepad_WriteBindings(0, handle); + } + + void __declspec(naked) Gamepad::Com_WriteConfiguration_Modified_Stub() + { + __asm + { + mov eax, [ecx + 0x18] + or eax, gamePadBindingsModifiedFlags // Also check for gamePadBindingsModifiedFlags + test al, 1 + jz endMethod + mov gamePadBindingsModifiedFlags, 0 // Reset gamePadBindingsModifiedFlags + mov eax, [ecx + 0x18] // Restore eax to dvar_modified_flags + + push 0x60B26E + retn + + endMethod: + push 0x60B298 + retn + } + } + + + void Gamepad::Gamepad_BindAxis(const int gamePadIndex, const Game::GamepadPhysicalAxis realIndex, const Game::GamepadVirtualAxis axisIndex, const Game::GamepadMapping mapType) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + assert(realIndex > Game::GPAD_PHYSAXIS_NONE && realIndex < Game::GPAD_PHYSAXIS_COUNT); + assert(axisIndex > Game::GPAD_VIRTAXIS_NONE && axisIndex < Game::GPAD_VIRTAXIS_COUNT); + assert(mapType > Game::GPAD_MAP_NONE && mapType < Game::GPAD_MAP_COUNT); + + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + gamePadGlobal.axes.virtualAxes[axisIndex].physicalAxis = realIndex; + gamePadGlobal.axes.virtualAxes[axisIndex].mapType = mapType; + + gamePadBindingsModifiedFlags |= 1; + } + + Game::GamepadPhysicalAxis Gamepad::StringToPhysicalAxis(const char* str) + { + for (auto i = 0u; i < std::extent_v; i++) + { + if (strcmp(str, Game::physicalAxisNames[i]) == 0) + return static_cast(i); + } + + return Game::GPAD_PHYSAXIS_NONE; + } + + Game::GamepadVirtualAxis Gamepad::StringToVirtualAxis(const char* str) + { + for (auto i = 0u; i < std::extent_v; i++) + { + if (strcmp(str, Game::virtualAxisNames[i]) == 0) + return static_cast(i); + } + + return Game::GPAD_VIRTAXIS_NONE; + } + + Game::GamepadMapping Gamepad::StringToGamePadMapping(const char* str) + { + for (auto i = 0u; i < std::extent_v; i++) + { + if (strcmp(str, Game::gamePadMappingTypeNames[i]) == 0) + return static_cast(i); + } + + return Game::GPAD_MAP_NONE; + } + + void Gamepad::Axis_Bind_f(Command::Params* params) + { + if (params->length() < 4) + { + Logger::Print("bindaxis \n"); + return; + } + + const auto* physicalAxisText = params->get(1); + const auto* virtualAxisText = params->get(2); + const auto* mappingText = params->get(3); + + const Game::GamepadPhysicalAxis physicalAxis = StringToPhysicalAxis(physicalAxisText); + if (physicalAxis == Game::GPAD_PHYSAXIS_NONE) + { + Logger::Print("\"%s\" isn't a valid physical axis\n", physicalAxisText); + return; + } + + const Game::GamepadVirtualAxis virtualAxis = StringToVirtualAxis(virtualAxisText); + if (virtualAxis == Game::GPAD_VIRTAXIS_NONE) + { + Logger::Print("\"%s\" isn't a valid virtual axis\n", virtualAxisText); + return; + } + + const Game::GamepadMapping mapping = StringToGamePadMapping(mappingText); + if (mapping == Game::GPAD_MAP_NONE) + { + Logger::Print("\"%s\" isn't a valid input type\n", mappingText); + return; + } + + Gamepad_BindAxis(0, physicalAxis, virtualAxis, mapping); + } + + void Gamepad::Axis_Unbindall_f(Command::Params* params) + { + auto& gamePadGlobal = gamePadGlobals[0]; + + for (auto& virtualAxis : gamePadGlobal.axes.virtualAxes) + { + virtualAxis.physicalAxis = Game::GPAD_PHYSAXIS_NONE; + virtualAxis.mapType = Game::GPAD_MAP_NONE; + } + } + void Gamepad::InitDvars() { gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); @@ -1111,7 +1298,7 @@ namespace Components { memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); memcpy(&Game::combinedKeyNames[Game::VANILLA_KEY_NAME_COUNT], Game::extendedKeyNames, sizeof(Game::keyname_t) * std::extent_v); - Game::combinedKeyNames[std::extent_v - 1] = { nullptr, 0 }; + Game::combinedKeyNames[std::extent_v - 1] = {nullptr, 0}; Utils::Hook::Set(0x4A780A, Game::combinedKeyNames); Utils::Hook::Set(0x4A7810, Game::combinedKeyNames); @@ -1137,8 +1324,16 @@ namespace Components Utils::Hook(0x492127, MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492009, MSG_ReadDeltaUsercmdKeyStub2, HOOK_JUMP).install()->quick(); + // Also rewrite configuration when gamepad config is dirty + Utils::Hook(0x60B264, Com_WriteConfiguration_Modified_Stub, HOOK_JUMP).install()->quick(); + + Utils::Hook(0x60B223, Key_WriteBindings_Hk, HOOK_CALL).install()->quick(); + CreateKeyNameMap(); + Command::Add("bindaxis", Axis_Bind_f); + Command::Add("unbindallaxis", Axis_Unbindall_f); + if (Dedicated::IsEnabled()) return; diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index b33f5ad3..d0985139 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -60,6 +60,19 @@ namespace Game GPAD_PHYSAXIS_COUNT, }; + enum GamepadVirtualAxis + { + GPAD_VIRTAXIS_NONE = -1, + GPAD_VIRTAXIS_SIDE = 0x0, + GPAD_VIRTAXIS_FORWARD = 0x1, + GPAD_VIRTAXIS_UP = 0x2, + GPAD_VIRTAXIS_YAW = 0x3, + GPAD_VIRTAXIS_PITCH = 0x4, + GPAD_VIRTAXIS_ATTACK = 0x5, + + GPAD_VIRTAXIS_COUNT + }; + enum GamePadStickDir { GPAD_STICK_POS = 0x0, @@ -73,7 +86,8 @@ namespace Game GPAD_MAP_NONE = -1, GPAD_MAP_LINEAR = 0x0, GPAD_MAP_SQUARED = 0x1, - GPAD_MAP_COUNT = 0x2 + + GPAD_MAP_COUNT }; struct ButtonToCodeMap_t @@ -98,7 +112,7 @@ namespace Game struct GpadAxesGlob { float axesValues[GPAD_PHYSAXIS_COUNT]; - GamepadVirtualAxisMapping virtualAxes[GPAD_PHYSAXIS_COUNT]; + GamepadVirtualAxisMapping virtualAxes[GPAD_VIRTAXIS_COUNT]; }; } @@ -132,7 +146,10 @@ namespace Components struct GamePadGlobals { + Game::GpadAxesGlob axes; unsigned nextScrollTime; + + GamePadGlobals(); }; struct ActionMapping @@ -156,6 +173,8 @@ namespace Components static GamePad gamePads[Game::MAX_GAMEPADS]; static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; + static int gamePadBindingsModifiedFlags; + static bool isHoldingMaxLookX; static std::chrono::milliseconds timeAtFirstHeldMaxLookX; static bool isADS; @@ -236,6 +255,17 @@ namespace Components static void IN_GamePadsMove(); static void IN_Frame_Hk(); + static void Gamepad_WriteBindings(int gamePadIndex, int handle); + static void Key_WriteBindings_Hk(int localClientNum, int handle); + static void Com_WriteConfiguration_Modified_Stub(); + + static void Gamepad_BindAxis(int gamePadIndex, Game::GamepadPhysicalAxis realIndex, Game::GamepadVirtualAxis axisIndex, Game::GamepadMapping mapType); + static Game::GamepadPhysicalAxis StringToPhysicalAxis(const char* str); + static Game::GamepadVirtualAxis StringToVirtualAxis(const char* str); + static Game::GamepadMapping StringToGamePadMapping(const char* str); + static void Axis_Bind_f(Command::Params* params); + static void Axis_Unbindall_f(Command::Params* params); + static void InitDvars(); static void IN_Init_Hk(); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 8415b93d..d71c760f 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -130,6 +130,7 @@ namespace Game FS_FCloseFile_t FS_FCloseFile = FS_FCloseFile_t(0x462000); FS_WriteFile_t FS_WriteFile = FS_WriteFile_t(0x426450); FS_Write_t FS_Write = FS_Write_t(0x4C06E0); + FS_Printf_t FS_Printf = FS_Printf_t(0x459320); FS_Read_t FS_Read = FS_Read_t(0x4A04C0); FS_Seek_t FS_Seek = FS_Seek_t(0x4A63D0); FS_FTell_t FS_FTell = FS_FTell_t(0x4E6760); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index fdeaeeb2..ac477589 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -302,6 +302,9 @@ namespace Game typedef int(__cdecl * FS_Write_t)(const void* buffer, size_t size, int file); extern FS_Write_t FS_Write; + typedef int(__cdecl * FS_Printf_t)(int file, const char* fmt, ...); + extern FS_Printf_t FS_Printf; + typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file); extern FS_Read_t FS_Read; From 0875a87e26578c53868e94bcfab442f2e3ff392e Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 16:18:43 +0200 Subject: [PATCH 33/83] Add commands for applying gamepad stick and button configurations --- src/Components/Modules/Gamepad.cpp | 14 ++++++++++++++ src/Components/Modules/Gamepad.hpp | 2 ++ 2 files changed, 16 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index f59beeb8..1db9dd4e 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1265,6 +1265,18 @@ namespace Components } } + void Gamepad::Bind_GP_SticksConfigs_f(Command::Params* params) + { + const auto* stickConfigName = gpad_sticksConfig.get(); + Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", stickConfigName)); + } + + void Gamepad::Bind_GP_ButtonsConfigs_f(Command::Params* params) + { + const auto* buttonConfigName = gpad_buttonConfig.get(); + Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", buttonConfigName)); + } + void Gamepad::InitDvars() { gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); @@ -1333,6 +1345,8 @@ namespace Components Command::Add("bindaxis", Axis_Bind_f); Command::Add("unbindallaxis", Axis_Unbindall_f); + Command::Add("bindgpsticksconfigs", Bind_GP_SticksConfigs_f); + Command::Add("bindgpbuttonsconfigs", Bind_GP_ButtonsConfigs_f); if (Dedicated::IsEnabled()) return; diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index d0985139..ca133b7d 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -265,6 +265,8 @@ namespace Components static Game::GamepadMapping StringToGamePadMapping(const char* str); static void Axis_Bind_f(Command::Params* params); static void Axis_Unbindall_f(Command::Params* params); + static void Bind_GP_SticksConfigs_f(Command::Params* params); + static void Bind_GP_ButtonsConfigs_f(Command::Params* params); static void InitDvars(); static void IN_Init_Hk(); From 57e305277be6b83bcaf24bc6dcc47fb89686d2c7 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 20:51:57 +0200 Subject: [PATCH 34/83] Consider material text icons when calculating text width --- src/Components/Modules/Colors.cpp | 3 ++ src/Components/Modules/Colors.hpp | 2 + src/Components/Modules/Materials.cpp | 58 ++++++++++++++++++++++++++++ src/Components/Modules/Materials.hpp | 2 + src/Game/Functions.cpp | 15 +++++++ src/Game/Functions.hpp | 5 +++ 6 files changed, 85 insertions(+) diff --git a/src/Components/Modules/Colors.cpp b/src/Components/Modules/Colors.cpp index e13f914b..ef600954 100644 --- a/src/Components/Modules/Colors.cpp +++ b/src/Components/Modules/Colors.cpp @@ -2,6 +2,7 @@ namespace Components { + char Colors::LastColorIndex; Dvar::Var Colors::NewColors; Dvar::Var Colors::ColorBlind; Game::dvar_t* Colors::ColorAllyColorBlind; @@ -147,6 +148,8 @@ namespace Components Utils::Hook::Set(0x5A2E2E, limit); // No idea :P Utils::Hook::Set(0x5A2733, limit - '0'); // No idea :P + + LastColorIndex = limit; } char Colors::Add(uint8_t r, uint8_t g, uint8_t b) diff --git a/src/Components/Modules/Colors.hpp b/src/Components/Modules/Colors.hpp index be1f24de..bb783151 100644 --- a/src/Components/Modules/Colors.hpp +++ b/src/Components/Modules/Colors.hpp @@ -5,6 +5,8 @@ namespace Components class Colors : public Component { public: + static char LastColorIndex; + Colors(); ~Colors(); diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index 79d70a12..98ba4062 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -278,6 +278,61 @@ namespace Components } } + int Materials::R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font) + { + auto lineWidth = 0; + auto maxWidth = 0; + + if (maxChars <= 0) + maxChars = 0x7FFFFFFF; + + if (text == nullptr) + return 0; + + auto count = 0; + while (*text && count < maxChars) + { + const auto letter = Game::SEH_ReadCharFromString(&text, nullptr); + if (letter == '\r' || letter == '\n') + { + lineWidth = 0; + } + else + { + if (letter == '^' && text) + { + if (*text >= '0' && *text <= Colors::LastColorIndex) + { + text += 2; + continue; + } + + if (*text >= '\x01' && *text <= '\x02' && text[1] != '\0' && text[2] != '\0' && text[3] != '\0') + { + const auto width = text[1]; + const auto materialNameLength = text[3]; + + auto v9 = font->pixelHeight * (text[1] - 16) + 16; + auto w = ((((v9 >> 24) & 0x1F) + (signed int)v9) >> 5); + + lineWidth += w; + + text += 3; + for (auto currentLength = 0; currentLength < materialNameLength && *text; currentLength++) + text++; + continue; + } + } + + lineWidth += R_GetCharacterGlyph(font, letter)->dx; + if (lineWidth > maxWidth) + maxWidth = lineWidth; + count++; + } + } + return maxWidth; + } + #endif Materials::Materials() @@ -302,6 +357,9 @@ namespace Components // Debug material comparison Utils::Hook::Set(0x523894, Materials::MaterialComparePrint); + // Consider material text icons when calculating text width + Utils::Hook(0x5056C0, Materials::R_TextWidth_Hk, HOOK_JUMP).install()->quick(); + #ifdef DEBUG if (Flags::HasFlag("dump")) { diff --git a/src/Components/Modules/Materials.hpp b/src/Components/Modules/Materials.hpp index 2a2d55dd..a057cedb 100644 --- a/src/Components/Modules/Materials.hpp +++ b/src/Components/Modules/Materials.hpp @@ -33,6 +33,8 @@ namespace Components static int WriteDeathMessageIcon(char* string, int offset, Game::Material* material); static void DeathMessageStub(); + static int R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font); + #ifdef DEBUG static void DumpImageCfg(int, const char*, const char* material); static void DumpImageCfgPath(int, const char*, const char* material); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index d71c760f..75180c63 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -279,6 +279,7 @@ namespace Game SE_Load_t SE_Load = SE_Load_t(0x502A30); SEH_StringEd_GetString_t SEH_StringEd_GetString = SEH_StringEd_GetString_t(0x44BB30); + SEH_ReadCharFromString_t SEH_ReadCharFromString = SEH_ReadCharFromString_t(0x486560); Dvar_SetFromStringByName_t Dvar_SetFromStringByName = Dvar_SetFromStringByName_t(0x4F52E0); Dvar_SetFromStringByNameFromSource_t Dvar_SetFromStringByNameFromSource = Dvar_SetFromStringByNameFromSource_t(0x4FC770); @@ -1258,5 +1259,19 @@ namespace Game retn } } + + __declspec(naked) Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter) + { + __asm + { + mov edi, [esp + 8] + push [esp+4] + mov eax, 0x5055C0 + call eax + add esp,0x4 + + retn + } + } #pragma optimize("", on) } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index ac477589..d9b1cbcd 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -669,6 +669,9 @@ namespace Game typedef char* (__cdecl * SEH_StringEd_GetString_t)(const char* string); extern SEH_StringEd_GetString_t SEH_StringEd_GetString; + typedef int (__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); + extern SEH_ReadCharFromString_t SEH_ReadCharFromString; + typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue); extern SL_ConvertToString_t SL_ConvertToString; @@ -951,4 +954,6 @@ namespace Game void R_AddDebugString(float *color, float *pos, float scale, const char *str); void R_AddDebugBounds(float* color, Bounds* b); void R_AddDebugBounds(float* color, Bounds* b, const float(*quat)[4]); + + Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter); } From 885f5c46884fda05c720255ae51da8ef2fa00d9b Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 20:52:13 +0200 Subject: [PATCH 35/83] Add localized button names for gamepad keys --- src/Components/Modules/Gamepad.cpp | 32 ++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 1db9dd4e..704009c9 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -83,7 +83,6 @@ namespace Game K_DPAD_RIGHT }; - constexpr auto VANILLA_KEY_NAME_COUNT = 95; keyname_t extendedKeyNames[] { {"BUTTON_A", K_BUTTON_A}, @@ -104,10 +103,34 @@ namespace Game {"DPAD_RIGHT", K_DPAD_RIGHT}, }; + keyname_t extendedLocalizedKeyNames[] + { + {"^\x01\x40\x40\x08""button_a", K_BUTTON_A}, + {"^\x01\x40\x40\x08""button_b", K_BUTTON_B}, + {"^\x01\x40\x40\x08""button_x", K_BUTTON_X}, + {"^\x01\x40\x40\x08""button_y", K_BUTTON_Y}, + {"^\x01\x40\x40\x0D""button_lshldr", K_BUTTON_LSHLDR}, + {"^\x01\x40\x40\x0D""button_rshldr", K_BUTTON_RSHLDR}, + {"^\x01\x40\x40\x0C""button_start", K_BUTTON_START}, + {"^\x01\x40\x40\x0B""button_back", K_BUTTON_BACK}, + {"^\x01\x40\x40\x0D""button_lstick", K_BUTTON_LSTICK}, + {"^\x01\x40\x40\x0D""button_rstick", K_BUTTON_RSTICK}, + {"^\x01\x40\x40\x0C""button_ltrig", K_BUTTON_LTRIG}, + {"^\x01\x40\x40\x0C""button_rtrig", K_BUTTON_RTRIG}, + {"^\x01\x40\x40\x07""dpad_up", K_DPAD_UP}, + {"^\x01\x40\x40\x09""dpad_down", K_DPAD_DOWN}, + {"^\x01\x40\x40\x09""dpad_left", K_DPAD_LEFT}, + {"^\x01\x40\x40\x0A""dpad_right", K_DPAD_RIGHT}, + }; + + constexpr auto VANILLA_KEY_NAME_COUNT = 95; + constexpr auto VANILLA_LOCALIZED_KEY_NAME_COUNT = 95; keyname_t combinedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; + keyname_t combinedLocalizedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); + keyname_t* vanillaLocalizedKeyNames = reinterpret_cast(0x798880); } namespace Components @@ -1310,11 +1333,16 @@ namespace Components { memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); memcpy(&Game::combinedKeyNames[Game::VANILLA_KEY_NAME_COUNT], Game::extendedKeyNames, sizeof(Game::keyname_t) * std::extent_v); - Game::combinedKeyNames[std::extent_v - 1] = {nullptr, 0}; + Game::combinedKeyNames[std::extent_v -1] = { nullptr, 0 }; + + memcpy(Game::combinedLocalizedKeyNames, Game::vanillaLocalizedKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_LOCALIZED_KEY_NAME_COUNT); + memcpy(&Game::combinedLocalizedKeyNames[Game::VANILLA_LOCALIZED_KEY_NAME_COUNT], Game::extendedLocalizedKeyNames, sizeof(Game::keyname_t) * std::extent_v); + Game::combinedLocalizedKeyNames[std::extent_v -1] = { nullptr, 0 }; Utils::Hook::Set(0x4A780A, Game::combinedKeyNames); Utils::Hook::Set(0x4A7810, Game::combinedKeyNames); Utils::Hook::Set(0x435C9F, Game::combinedKeyNames); + Utils::Hook::Set(0x435C98, Game::combinedLocalizedKeyNames); } Gamepad::Gamepad() From 8b43ba490ca5ca2e82b25f68fe331b35acb25eb4 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 00:03:00 +0200 Subject: [PATCH 36/83] Fix width calculation errors in R_TextWidth reimplementation --- src/Components/Modules/Materials.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index 98ba4062..330d0b39 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -303,7 +303,7 @@ namespace Components { if (*text >= '0' && *text <= Colors::LastColorIndex) { - text += 2; + text++; continue; } @@ -312,12 +312,12 @@ namespace Components const auto width = text[1]; const auto materialNameLength = text[3]; - auto v9 = font->pixelHeight * (text[1] - 16) + 16; - auto w = ((((v9 >> 24) & 0x1F) + (signed int)v9) >> 5); + auto v9 = font->pixelHeight * (width - 16) + 16; + auto w = ((((v9 >> 24) & 0x1F) + v9) >> 5); lineWidth += w; - text += 3; + text += 4; for (auto currentLength = 0; currentLength < materialNameLength && *text; currentLength++) text++; continue; From 05861a0df4fefe1fdf4afc64cd5a95166a0f08d5 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 00:03:44 +0200 Subject: [PATCH 37/83] Draw only gamepad buttons when gamepad is in use --- src/Components/Modules/Gamepad.cpp | 107 ++++++++++++++++++++++++----- src/Components/Modules/Gamepad.hpp | 6 ++ 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 704009c9..ab161b80 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -105,22 +105,23 @@ namespace Game keyname_t extendedLocalizedKeyNames[] { - {"^\x01\x40\x40\x08""button_a", K_BUTTON_A}, - {"^\x01\x40\x40\x08""button_b", K_BUTTON_B}, - {"^\x01\x40\x40\x08""button_x", K_BUTTON_X}, - {"^\x01\x40\x40\x08""button_y", K_BUTTON_Y}, - {"^\x01\x40\x40\x0D""button_lshldr", K_BUTTON_LSHLDR}, - {"^\x01\x40\x40\x0D""button_rshldr", K_BUTTON_RSHLDR}, - {"^\x01\x40\x40\x0C""button_start", K_BUTTON_START}, - {"^\x01\x40\x40\x0B""button_back", K_BUTTON_BACK}, - {"^\x01\x40\x40\x0D""button_lstick", K_BUTTON_LSTICK}, - {"^\x01\x40\x40\x0D""button_rstick", K_BUTTON_RSTICK}, - {"^\x01\x40\x40\x0C""button_ltrig", K_BUTTON_LTRIG}, - {"^\x01\x40\x40\x0C""button_rtrig", K_BUTTON_RTRIG}, - {"^\x01\x40\x40\x07""dpad_up", K_DPAD_UP}, - {"^\x01\x40\x40\x09""dpad_down", K_DPAD_DOWN}, - {"^\x01\x40\x40\x09""dpad_left", K_DPAD_LEFT}, - {"^\x01\x40\x40\x0A""dpad_right", K_DPAD_RIGHT}, + // Material text icons pattern: 0x01 width height material_name_len + {"^\x01\x32\x32\x08""button_a", K_BUTTON_A}, + {"^\x01\x32\x32\x08""button_b", K_BUTTON_B}, + {"^\x01\x32\x32\x08""button_x", K_BUTTON_X}, + {"^\x01\x32\x32\x08""button_y", K_BUTTON_Y}, + {"^\x01\x32\x32\x0D""button_lshldr", K_BUTTON_LSHLDR}, + {"^\x01\x32\x32\x0D""button_rshldr", K_BUTTON_RSHLDR}, + {"^\x01\x32\x32\x0C""button_start", K_BUTTON_START}, + {"^\x01\x32\x32\x0B""button_back", K_BUTTON_BACK}, + {"^\x01\x48\x32\x0D""button_lstick", K_BUTTON_LSTICK}, + {"^\x01\x48\x32\x0D""button_rstick", K_BUTTON_RSTICK}, + {"^\x01\x32\x32\x0C""button_ltrig", K_BUTTON_LTRIG}, + {"^\x01\x32\x32\x0C""button_rtrig", K_BUTTON_RTRIG}, + {"^\x01\x32\x32\x07""dpad_up", K_DPAD_UP}, + {"^\x01\x32\x32\x09""dpad_down", K_DPAD_DOWN}, + {"^\x01\x32\x32\x09""dpad_left", K_DPAD_LEFT}, + {"^\x01\x32\x32\x0A""dpad_right", K_DPAD_RIGHT}, }; constexpr auto VANILLA_KEY_NAME_COUNT = 95; @@ -601,6 +602,13 @@ namespace Components } } + bool Gamepad::Key_IsValidGamePadChar(const int key) + { + return key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_1 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_1 + || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_2 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_2 + || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_3 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_3; + } + void Gamepad::CL_GamepadResetMenuScrollTime(const int gamePadIndex, const int key, const bool down, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -660,10 +668,14 @@ namespace Components assert(gamePadIndex < Game::MAX_GAMEPADS); assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); + auto& gamePad = gamePads[gamePadIndex]; auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; gamePadGlobal.axes.axesValues[physicalAxis] = value; CL_GamepadGenerateAPad(gamePadIndex, physicalAxis, time); + + if (std::fabs(value) > 0.0f) + gamePad.inUse = true; } void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down) @@ -808,9 +820,15 @@ namespace Components void Gamepad::CL_GamepadButtonEventForPort(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time, const Game::GamePadButton button) { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePad = gamePads[gamePadIndex]; + + gamePad.inUse = true; + if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) CL_GamepadResetMenuScrollTime(gamePadIndex, key, buttonEvent == Game::GPAD_BUTTON_PRESSED, time); + CL_GamepadButtonEvent(gamePadIndex, key, buttonEvent, time, button); } @@ -1277,7 +1295,7 @@ namespace Components Gamepad_BindAxis(0, physicalAxis, virtualAxis, mapping); } - void Gamepad::Axis_Unbindall_f(Command::Params* params) + void Gamepad::Axis_Unbindall_f(Command::Params*) { auto& gamePadGlobal = gamePadGlobals[0]; @@ -1329,6 +1347,55 @@ namespace Components InitDvars(); } + int Gamepad::Key_GetCommandAssignmentInternal_Hk(const char* cmd, int (*keys)[2]) + { + auto keyCount = 0; + + if (gamePads[0].inUse) + { + for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++) + { + if(!Key_IsValidGamePadChar(keyNum)) + continue; + + if(Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) + { + (*keys)[keyCount++] = keyNum; + + if (keyCount >= 2) + return keyNum; + } + } + } + else + { + for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++) + { + if (Key_IsValidGamePadChar(keyNum)) + continue; + + if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) + { + (*keys)[keyCount++] = keyNum; + + if (keyCount >= 2) + return keyNum; + } + } + } + + return keyCount; + } + + void Gamepad::CL_KeyEvent_Hk(const int localClientNum, const int key, const int down, const unsigned time) + { + // A keyboard key has been pressed. Mark controller as unused. + gamePads[0].inUse = false; + + // Call original function + Utils::Hook::Call(0x4F6480)(localClientNum, key, down, time); + } + void Gamepad::CreateKeyNameMap() { memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); @@ -1383,6 +1450,12 @@ namespace Components Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); + // Mark controller as unused when keyboard key is pressed + Utils::Hook(0x43D179, CL_KeyEvent_Hk, HOOK_CALL).install()->quick(); + + // Only return gamepad keys when gamepad enabled and only non gamepad keys when not + Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); + //Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); //Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); //Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index ca133b7d..a5143220 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -128,6 +128,7 @@ namespace Components struct GamePad { bool enabled; + bool inUse; int portIndex; unsigned short digitals; unsigned short lastDigitals; @@ -229,6 +230,8 @@ namespace Components static void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y); static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); + static bool Key_IsValidGamePadChar(const int key); + static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); static bool CL_CheckForIgnoreDueToRepeat(int gamePadIndex, int key, int repeatCount, unsigned int time); static void UI_GamepadKeyEvent(int gamePadIndex, int key, bool down); @@ -271,6 +274,9 @@ namespace Components static void InitDvars(); static void IN_Init_Hk(); + static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]); + static void Key_GetCommandAssignmentInternal_Stub(); + static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time); static void CreateKeyNameMap(); }; } From feef738c61d8f8ee227de31e0340014742228726 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 00:04:05 +0200 Subject: [PATCH 38/83] Make all material text icons (Hud icons) have white tint so they are not affected by color codes --- src/Components/Modules/Materials.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index 330d0b39..1add3f71 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -192,6 +192,12 @@ namespace Components add esp, 4h mov [esp + 20h], eax + + // Make all material text icons have white tint + mov eax,[esp + 0x50] + or eax,0x00FFFFFF + mov [esp + 0x50],eax + popad pop eax @@ -343,6 +349,7 @@ namespace Components Materials::ImageVersionCheckHook.initialize(0x53A456, Materials::ImageVersionCheck, HOOK_CALL)->install(); // Fix material pointer exploit + // Also make all material text icons have white tint Utils::Hook(0x534E0C, Materials::DrawMaterialStub, HOOK_CALL).install()->quick(); // Increment string pointer accordingly From b3e5f461f24465a4d4bc59dd4cb1be4b387c091d Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 00:45:33 +0200 Subject: [PATCH 39/83] Add gpad_in_use dvar that reflects whether a gamepad is currently being used --- src/Components/Modules/Gamepad.cpp | 7 +++++++ src/Components/Modules/Gamepad.hpp | 1 + 2 files changed, 8 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index ab161b80..39529bcc 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -146,6 +146,7 @@ namespace Components Dvar::Var Gamepad::gpad_enabled; Dvar::Var Gamepad::gpad_debug; Dvar::Var Gamepad::gpad_present; + Dvar::Var Gamepad::gpad_in_use; Dvar::Var Gamepad::gpad_sticksConfig; Dvar::Var Gamepad::gpad_buttonConfig; Dvar::Var Gamepad::gpad_menu_scroll_delay_first; @@ -675,7 +676,10 @@ namespace Components CL_GamepadGenerateAPad(gamePadIndex, physicalAxis, time); if (std::fabs(value) > 0.0f) + { gamePad.inUse = true; + gpad_in_use.setRaw(true); + } } void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down) @@ -824,6 +828,7 @@ namespace Components auto& gamePad = gamePads[gamePadIndex]; gamePad.inUse = true; + gpad_in_use.setRaw(true); if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) CL_GamepadResetMenuScrollTime(gamePadIndex, key, buttonEvent == Game::GPAD_BUTTON_PRESSED, time); @@ -1323,6 +1328,7 @@ namespace Components gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); gpad_debug = Dvar::Register("gpad_debug", false, 0, "Game pad debugging"); gpad_present = Dvar::Register("gpad_present", false, 0, "Game pad present"); + gpad_in_use = Dvar::Register("gpad_in_use", false, 0, "A game pad is in use"); gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "thumbstick_default", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "buttons_default", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); gpad_menu_scroll_delay_first = Dvar::Register("gpad_menu_scroll_delay_first", 420, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for the first repeat, in milliseconds"); @@ -1391,6 +1397,7 @@ namespace Components { // A keyboard key has been pressed. Mark controller as unused. gamePads[0].inUse = false; + gpad_in_use.setRaw(false); // Call original function Utils::Hook::Call(0x4F6480)(localClientNum, key, down, time); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index a5143220..95e8d0ea 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -187,6 +187,7 @@ namespace Components static Dvar::Var gpad_enabled; static Dvar::Var gpad_debug; static Dvar::Var gpad_present; + static Dvar::Var gpad_in_use; static Dvar::Var gpad_sticksConfig; static Dvar::Var gpad_buttonConfig; static Dvar::Var gpad_menu_scroll_delay_first; From cc9a2b0bac9b149e5dca95d14f89225ece937e6a Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 00:45:49 +0200 Subject: [PATCH 40/83] Make dvar set methods also set the latched values --- src/Components/Modules/Dvar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index 2d2d3975..dc95eb23 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -116,6 +116,7 @@ namespace Components if (this->dvar) { this->dvar->current.integer = integer; + this->dvar->latched.integer = integer; } } @@ -124,6 +125,7 @@ namespace Components if (this->dvar) { this->dvar->current.value = value; + this->dvar->latched.value = value; } } @@ -132,6 +134,7 @@ namespace Components if (this->dvar) { this->dvar->current.enabled = value; + this->dvar->latched.enabled = value; } } From 6434526fcb03348babbc95c492997b6d88c2f88a Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 01:19:20 +0200 Subject: [PATCH 41/83] Disable mouse cursor when controller is active --- src/Components/Modules/Gamepad.cpp | 38 ++++++++++++++++++++++++++++++ src/Components/Modules/Gamepad.hpp | 4 +++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 39529bcc..d8abc2c1 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1403,6 +1403,40 @@ namespace Components Utils::Hook::Call(0x4F6480)(localClientNum, key, down, time); } + bool Gamepad::IsGamePadInUse() + { + return gamePads[0].inUse; + } + + __declspec(naked) void Gamepad::CL_MouseEvent_Stub() + { + __asm + { + pushad + cmp eax, 6 + jz hideCursor + + call IsGamePadInUse + test al, al + jnz hideCursor + + // Continue checks + popad + push 0x4D7C68 + retn; + + hideCursor: + popad + push 0x4D7C8A + retn + } + } + + bool Gamepad::UI_RefreshViewport_Hk() + { + return Dvar::Var("cl_bypassMouseInput").get() || IsGamePadInUse(); + } + void Gamepad::CreateKeyNameMap() { memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); @@ -1460,6 +1494,10 @@ namespace Components // Mark controller as unused when keyboard key is pressed Utils::Hook(0x43D179, CL_KeyEvent_Hk, HOOK_CALL).install()->quick(); + // Hide cursor when controller is active + Utils::Hook(0x4D7C63, CL_MouseEvent_Stub, HOOK_JUMP).install()->quick(); // Disable cursor + Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick(); // Do not draw cursor + // Only return gamepad keys when gamepad enabled and only non gamepad keys when not Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 95e8d0ea..469e8958 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -276,8 +276,10 @@ namespace Components static void IN_Init_Hk(); static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]); - static void Key_GetCommandAssignmentInternal_Stub(); + static bool IsGamePadInUse(); static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time); + static void CL_MouseEvent_Stub(); + static bool UI_RefreshViewport_Hk(); static void CreateKeyNameMap(); }; } From 6043dabc3c8e1e585cfa0693e464c4a74e3522d4 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 13:25:14 +0200 Subject: [PATCH 42/83] Apply gamepad axis rotation to usercmds --- src/Components/Modules/Gamepad.cpp | 443 +++++++++-------------------- src/Components/Modules/Gamepad.hpp | 126 +++++--- src/Game/Functions.cpp | 2 + src/Game/Functions.hpp | 2 + 4 files changed, 233 insertions(+), 340 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index d8abc2c1..45a251e1 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -2,9 +2,6 @@ #include -#define XINPUT_SENSITIVITY_MULTIPLIER 4 // Arbitrary value I multiply the xinput senstivity dvar with to get nicer values (0-10 range or something) -#define SIGN(d) ((d > 0) - (d < 0)) - namespace Game { ButtonToCodeMap_t buttonList[] @@ -45,6 +42,16 @@ namespace Game GPAD_INVALID }; + GamepadPhysicalAxis axisSameStick[GPAD_PHYSAXIS_COUNT] + { + GPAD_PHYSAXIS_RSTICK_Y, + GPAD_PHYSAXIS_RSTICK_X, + GPAD_PHYSAXIS_LSTICK_Y, + GPAD_PHYSAXIS_LSTICK_X, + GPAD_PHYSAXIS_NONE, + GPAD_PHYSAXIS_NONE + }; + const char* physicalAxisNames[GPAD_PHYSAXIS_COUNT] { "A_RSTICK_X", @@ -130,6 +137,7 @@ namespace Game keyname_t combinedLocalizedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); + AimAssistGlobals* aaGlobArray = reinterpret_cast(0x7A2110); keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); keyname_t* vanillaLocalizedKeyNames = reinterpret_cast(0x798880); } @@ -159,6 +167,7 @@ namespace Components Dvar::Var Gamepad::gpad_button_deadzone; Dvar::Var Gamepad::gpad_button_rstick_deflect_max; Dvar::Var Gamepad::gpad_button_lstick_deflect_max; + Dvar::Var Gamepad::input_viewSensitivity; Dvar::Var Gamepad::xpadSensitivity; Dvar::Var Gamepad::xpadEarlyTime; @@ -193,25 +202,6 @@ namespace Components {Game::K_APAD_RIGHT, Game::K_RIGHTARROW}, }; - - // This should be read from a text file in the players/ folder, most probably / or from config_mp.cfg - std::vector mappings = { - Gamepad::ActionMapping(XINPUT_GAMEPAD_A, "gostand"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_B, "stance"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_X, "usereload"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_Y, "weapnext", false), - Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_SHOULDER, "smoke"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_SHOULDER, "frag"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_LEFT_THUMB, "breath_sprint"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_RIGHT_THUMB, "melee"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_START, "togglemenu", false), - Gamepad::ActionMapping(XINPUT_GAMEPAD_BACK, "scores"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_LEFT, "actionslot 3"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_RIGHT, "actionslot 2"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_DOWN, "actionslot 1"), - Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), - }; - Gamepad::GamePadGlobals::GamePadGlobals() : axes{}, nextScrollTime(0) @@ -223,132 +213,6 @@ namespace Components } } - - // Same thing - - // void Gamepad::Vibrate(int leftVal, int rightVal) - // { - // // Create a Vibraton State - // XINPUT_VIBRATION Vibration; - // - // // Zeroise the Vibration - // ZeroMemory(&Vibration, sizeof(XINPUT_VIBRATION)); - // - // // Set the Vibration Values - // Vibration.wLeftMotorSpeed = leftVal; - // Vibration.wRightMotorSpeed = rightVal; - // - // // Vibrate the controller - // XInputSetState(xiPlayerNum, &Vibration); - // } - - void Gamepad::CL_GamepadMove(int, Game::usercmd_s* cmd) - { - auto& gamePad = gamePads[0]; - - if (gamePad.enabled) - { - if (std::fabs(gamePad.sticks[0]) > 0.0f || std::fabs(gamePad.sticks[1]) > 0.0f) - { - // We check for 0:0 again so we don't overwrite keyboard input in case the user doesn't feel like using their gamepad, even though its plugged in - cmd->rightmove = static_cast(gamePad.sticks[0] * static_cast(std::numeric_limits().max())); - cmd->forwardmove = static_cast(gamePad.sticks[1] * static_cast(std::numeric_limits().max())); - } - - const bool pressingLeftTrigger = gamePad.analogs[0] > TRIGGER_THRESHOLD_F; - const bool previouslyPressingLeftTrigger = gamePad.lastAnalogs[0] > TRIGGER_THRESHOLD_F; - if (pressingLeftTrigger != previouslyPressingLeftTrigger) - { - if (pressingLeftTrigger) - { - Command::Execute("+speed_throw"); - isADS = true; - } - else - { - Command::Execute("-speed_throw"); - isADS = false; - } - } - - const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; - const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; - if (pressingRightTrigger != previouslyPressingRightTrigger) - { - if (pressingRightTrigger) - { - Command::Execute("+attack"); - } - else - { - Command::Execute("-attack"); - } - } - - // Buttons (on/off) mappings - for (auto& i : mappings) - { - auto mapping = i; - auto action = mapping.action; - auto antiAction = mapping.action; - - if (mapping.isReversible) - { - action = "+" + mapping.action; - antiAction = "-" + mapping.action; - } - else if (mapping.wasPressed) - { - if (gamePad.digitals & mapping.input) - { - // Button still pressed, do not send info - } - else - { - i.wasPressed = false; - } - - continue; - } - - if (gamePad.digitals & mapping.input) - { - if (mapping.spamWhenHeld || !i.wasPressed) - { - Command::Execute(action); - } - i.wasPressed = true; - } - else if (mapping.isReversible && mapping.wasPressed) - { - i.wasPressed = false; - Command::Execute(antiAction); - } - } - } - } - - __declspec(naked) void Gamepad::CL_CreateCmdStub() - { - __asm - { - // do xinput! - push esi - push ebp - call CL_GamepadMove - add esp, 8h - - // execute code we patched over - add esp, 4 - fld st - pop ebx - - // return back - push 0x5A6DBF - retn - } - } - __declspec(naked) void Gamepad::MSG_WriteDeltaUsercmdKeyStub() { __asm @@ -431,151 +295,6 @@ namespace Components } } - int Gamepad::unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode) - { - const auto& gamePad = gamePads[0]; - - if (gamePad.enabled) - { - if (keyCode == Game::keyNum_t::K_MOUSE2) - { - const bool pressingLeftTrigger = gamePad.analogs[0] > TRIGGER_THRESHOLD_F; - const bool previouslyPressingLeftTrigger = gamePad.lastAnalogs[0] > TRIGGER_THRESHOLD_F; - if (pressingLeftTrigger != previouslyPressingLeftTrigger) - { - if (pressingLeftTrigger) - { - return 1; - } - else - { - return 0; - } - } - } - } - - return Utils::Hook::Call(0x48B2D0)(localClientNum, keyCode); - } - - void Gamepad::MouseOverride(Game::clientActive_t* clientActive, float* mx, float* my) - { - CL_GetMouseMovementCl(clientActive, mx, my); - - const auto& gamePad = gamePads[0]; - - if (gamePad.enabled) - { - float viewSensitivityMultiplier = xpadSensitivity.get() * XINPUT_SENSITIVITY_MULTIPLIER; - - float lockedSensitivityMultiplier = xpadEarlyMultiplier.get(); - float generalXSensitivityMultiplier = xpadHorizontalMultiplier.get(); - float generalYSensitivityMultiplier = xpadVerticalMultiplier.get(); - std::chrono::milliseconds msBeforeUnlockingSensitivity = std::chrono::milliseconds(xpadEarlyTime.get()); - - float viewStickX = gamePad.sticks[2]; - float viewStickY = gamePad.sticks[3]; - - // Gamepad horizontal acceleration on view - if (abs(viewStickX) > 0.80f) - { - if (!isHoldingMaxLookX) - { - isHoldingMaxLookX = true; - timeAtFirstHeldMaxLookX = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - } - else - { - std::chrono::milliseconds hasBeenHoldingLeftXForMs = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - - timeAtFirstHeldMaxLookX; -#ifdef STEP_SENSITIVITY - if (hasBeenHoldingLeftXForMs < msBeforeUnlockingSensitivity) { - viewStickX *= lockedSensitivityMultiplier; - } -#else - float coeff = std::clamp(hasBeenHoldingLeftXForMs.count() / (float)msBeforeUnlockingSensitivity.count(), 0.0F, 1.0F); - viewStickX *= lockedSensitivityMultiplier + coeff * (1.0f - lockedSensitivityMultiplier); -#endif - } - } - else - { - isHoldingMaxLookX = false; - timeAtFirstHeldMaxLookX = 0ms; - viewStickX *= lockedSensitivityMultiplier; - } - - float adsMultiplier = 1.0f; - - auto ps = &clientActive->snap.ps; - - // DO NOT use clientActive->usingAds ! It only works for toggle ADS - if (PM_IsAdsAllowed(ps) && isADS) - { - adsMultiplier = xpadAdsMultiplier.get(); - } - - if (viewStickX != 0 || viewStickY != 0) - { - *(my) = viewStickX * viewSensitivityMultiplier * generalXSensitivityMultiplier * adsMultiplier; - *(mx) = -viewStickY * viewSensitivityMultiplier * generalYSensitivityMultiplier * adsMultiplier; - } - - // Handling killstreaks - const bool pressingRightTrigger = gamePad.analogs[1] > TRIGGER_THRESHOLD_F; - const bool previouslyPressingRightTrigger = gamePad.lastAnalogs[1] > TRIGGER_THRESHOLD_F; - if (pressingRightTrigger != previouslyPressingRightTrigger) - { - bool* isInPredator = reinterpret_cast(0x8EE3B8); - - if (pressingRightTrigger) - { - Utils::Hook::Set(0xA1C4F4, Game::LOC_SEL_INPUT_CONFIRM); - if (*isInPredator) - { - // Yea, that's how we boost - // Command::execute is sync by default so the predator event gets fired properly - Command::Execute("+attack"); - Command::Execute("-attack"); - } - } - } - } - } - - // Game -> Client DLL - __declspec(naked) void CL_GetMouseMovementStub() - { - __asm - { - push edx; - push ecx; - push eax; - call Gamepad::MouseOverride; - add esp, 0xC; - ret; - } - } - - // Client DLL -> Game - void Gamepad::CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my) - { - __asm - { - push ebx; - push ecx; - push edx; - mov eax, result; - mov ecx, mx; - mov edx, my; - mov ebx, 5A60E0h; - call ebx; - pop edx; - pop ecx; - pop ebx; - } - } - bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -610,6 +329,111 @@ namespace Components || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_3 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_3; } + float Gamepad::CL_GamepadAxisValue(const int gamePadIndex, const Game::GamepadVirtualAxis virtualAxis) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + assert(virtualAxis > Game::GPAD_VIRTAXIS_NONE && virtualAxis < Game::GPAD_VIRTAXIS_COUNT); + const auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + + const auto& [physicalAxis, mapType] = gamePadGlobal.axes.virtualAxes[virtualAxis]; + + if (physicalAxis <= Game::GPAD_PHYSAXIS_NONE || physicalAxis >= Game::GPAD_PHYSAXIS_COUNT) + return 0.0f; + + auto axisDeflection = gamePadGlobal.axes.axesValues[physicalAxis]; + + if (mapType == Game::GPAD_MAP_SQUARED) + { + const auto otherAxisSameStick = Game::axisSameStick[physicalAxis]; + + float otherAxisDeflection; + if (otherAxisSameStick <= Game::GPAD_PHYSAXIS_NONE || otherAxisSameStick >= Game::GPAD_PHYSAXIS_COUNT) + otherAxisDeflection = 0.0f; + else + otherAxisDeflection = gamePadGlobal.axes.axesValues[otherAxisSameStick]; + + axisDeflection = std::sqrt(axisDeflection * axisDeflection + otherAxisDeflection * otherAxisDeflection) * axisDeflection; + } + + return axisDeflection; + } + + char Gamepad::ClampChar(const int value) + { + return static_cast(std::clamp(value, std::numeric_limits::min(), std::numeric_limits::max())); + } + + void Gamepad::CL_GamepadMove(const int gamePadIndex, Game::usercmd_s* cmd, const float frame_time_base) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& gamePad = gamePads[gamePadIndex]; + auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + + if (!gpad_enabled.get() || !gamePad.enabled) + return; + + auto pitch = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_PITCH); + if (!Dvar::Var("input_invertPitch").get()) + pitch *= -1; + + auto yaw = -CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_YAW); + auto forward = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_FORWARD); + auto side = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_SIDE); + auto attack = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_ATTACK); + auto moveScale = static_cast(std::numeric_limits::max()); + + if (std::fabs(side) > 0.0f || std::fabs(forward) > 0.0f) + { + const auto length = std::fabs(side) <= std::fabs(forward) + ? side / forward + : forward / side; + moveScale = std::sqrt((length * length) + 1.0f) * moveScale; + } + + const auto forwardMove = static_cast(std::floor(forward * moveScale)); + const auto rightMove = static_cast(std::floor(side * moveScale)); + + const auto sensitivity = input_viewSensitivity.get(); + pitch *= sensitivity; + yaw *= sensitivity; + + if (Game::clients[0].cgameMaxPitchSpeed > 0 && Game::clients[0].cgameMaxPitchSpeed < std::fabs(pitch)) + pitch = std::signbit(pitch) ? -Game::clients[0].cgameMaxPitchSpeed : Game::clients[0].cgameMaxPitchSpeed; + if (Game::clients[0].cgameMaxYawSpeed > 0 && Game::clients[0].cgameMaxYawSpeed < std::fabs(yaw)) + yaw = std::signbit(yaw) ? -Game::clients[0].cgameMaxYawSpeed : Game::clients[0].cgameMaxYawSpeed; + + + Game::clients[0].clViewangles[0] += pitch; + Game::clients[0].clViewangles[1] += yaw; + + cmd->rightmove = ClampChar(cmd->rightmove + rightMove); + cmd->forwardmove = ClampChar(cmd->forwardmove + forwardMove); + } + + constexpr auto CL_MouseMove = 0x5A6240; + + __declspec(naked) void Gamepad::CL_MouseMove_Stub() + { + __asm + { + // Prepare args for our function call + push [esp+0x4] // frametime_base + push ebx // cmd + push eax // localClientNum + + push [esp+0x8] // restore frametime_base on the stack + call CL_MouseMove + add esp,4 + + // Call our function, the args were already prepared earlier + call CL_GamepadMove + add esp,0xC + + ret + } + } + + void Gamepad::CL_GamepadResetMenuScrollTime(const int gamePadIndex, const int key, const bool down, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -1171,7 +995,7 @@ namespace Components Game::FS_Printf(handle, "unbindallaxis\n"); - for(auto virtualAxisIndex = 0u; virtualAxisIndex < Game::GPAD_VIRTAXIS_COUNT; virtualAxisIndex++) + for (auto virtualAxisIndex = 0u; virtualAxisIndex < Game::GPAD_VIRTAXIS_COUNT; virtualAxisIndex++) { const auto& axisMapping = gamePadGlobal.axes.virtualAxes[virtualAxisIndex]; if (axisMapping.physicalAxis <= Game::GPAD_PHYSAXIS_NONE || axisMapping.physicalAxis >= Game::GPAD_PHYSAXIS_COUNT @@ -1199,7 +1023,7 @@ namespace Components void __declspec(naked) Gamepad::Com_WriteConfiguration_Modified_Stub() { __asm - { + { mov eax, [ecx + 0x18] or eax, gamePadBindingsModifiedFlags // Also check for gamePadBindingsModifiedFlags test al, 1 @@ -1210,10 +1034,10 @@ namespace Components push 0x60B26E retn - endMethod: + endMethod: push 0x60B298 retn - } + } } @@ -1343,6 +1167,8 @@ namespace Components gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, 0, "Game pad button deadzone threshhold"); gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); + + input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); } void Gamepad::IN_Init_Hk() @@ -1361,10 +1187,10 @@ namespace Components { for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++) { - if(!Key_IsValidGamePadChar(keyNum)) + if (!Key_IsValidGamePadChar(keyNum)) continue; - if(Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) + if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) { (*keys)[keyCount++] = keyNum; @@ -1411,11 +1237,11 @@ namespace Components __declspec(naked) void Gamepad::CL_MouseEvent_Stub() { __asm - { + { pushad cmp eax, 6 jz hideCursor - + call IsGamePadInUse test al, al jnz hideCursor @@ -1425,11 +1251,11 @@ namespace Components push 0x4D7C68 retn; - hideCursor: + hideCursor: popad push 0x4D7C8A retn - } + } } bool Gamepad::UI_RefreshViewport_Hk() @@ -1441,11 +1267,12 @@ namespace Components { memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); memcpy(&Game::combinedKeyNames[Game::VANILLA_KEY_NAME_COUNT], Game::extendedKeyNames, sizeof(Game::keyname_t) * std::extent_v); - Game::combinedKeyNames[std::extent_v -1] = { nullptr, 0 }; + Game::combinedKeyNames[std::extent_v - 1] = {nullptr, 0}; memcpy(Game::combinedLocalizedKeyNames, Game::vanillaLocalizedKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_LOCALIZED_KEY_NAME_COUNT); - memcpy(&Game::combinedLocalizedKeyNames[Game::VANILLA_LOCALIZED_KEY_NAME_COUNT], Game::extendedLocalizedKeyNames, sizeof(Game::keyname_t) * std::extent_v); - Game::combinedLocalizedKeyNames[std::extent_v -1] = { nullptr, 0 }; + memcpy(&Game::combinedLocalizedKeyNames[Game::VANILLA_LOCALIZED_KEY_NAME_COUNT], Game::extendedLocalizedKeyNames, + sizeof(Game::keyname_t) * std::extent_v); + Game::combinedLocalizedKeyNames[std::extent_v - 1] = {nullptr, 0}; Utils::Hook::Set(0x4A780A, Game::combinedKeyNames); Utils::Hook::Set(0x4A7810, Game::combinedKeyNames); @@ -1474,7 +1301,6 @@ namespace Components // Also rewrite configuration when gamepad config is dirty Utils::Hook(0x60B264, Com_WriteConfiguration_Modified_Stub, HOOK_JUMP).install()->quick(); - Utils::Hook(0x60B223, Key_WriteBindings_Hk, HOOK_CALL).install()->quick(); CreateKeyNameMap(); @@ -1505,6 +1331,9 @@ namespace Components //Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); //Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); + // Add gamepad inputs to usercmds + Utils::Hook(0x5A6DAE, CL_MouseMove_Stub, HOOK_CALL).install()->quick(); + xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 469e8958..86f579c4 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -114,6 +114,89 @@ namespace Game float axesValues[GPAD_PHYSAXIS_COUNT]; GamepadVirtualAxisMapping virtualAxes[GPAD_VIRTAXIS_COUNT]; }; + + struct AimAssistPlayerState + { + float velocity[3]; + int eFlags; + int linkFlags; + int pm_flags; + int weapFlags; + int weaponState; + float fWeaponPosFrac; + int weapIndex; + bool hasAmmo; + bool isDualWielding; + bool isThirdPerson; + bool isExtendedMelee; + }; + + struct AimTweakables + { + float slowdownRegionWidth; + float slowdownRegionHeight; + float autoAimRegionWidth; + float autoAimRegionHeight; + float autoMeleeRegionWidth; + float autoMeleeRegionHeight; + float lockOnRegionWidth; + float lockOnRegionHeight; + }; + + struct AimScreenTarget + { + int entIndex; + float clipMins[2]; + float clipMaxs[2]; + float aimPos[3]; + float velocity[3]; + float distSqr; + float crosshairDistSqr; + }; + + enum AutoMeleeState + { + AIM_MELEE_STATE_OFF = 0x0, + AIM_MELEE_STATE_TARGETED = 0x1, + AIM_MELEE_STATE_UPDATING = 0x2, + }; + + struct __declspec(align(16)) AimAssistGlobals + { + AimAssistPlayerState ps; + __declspec(align(8)) float screenMtx[4][4]; + float invScreenMtx[4][4]; + bool initialized; + int prevButtons; + AimTweakables tweakables; + float eyeOrigin[3]; + float viewOrigin[3]; + float viewAngles[3]; + float viewAxis[3][3]; + float fovTurnRateScale; + float fovScaleInv; + float adsLerp; + float pitchDelta; + float yawDelta; + float screenWidth; + float screenHeight; + AimScreenTarget screenTargets[64]; + int screenTargetCount; + int autoAimTargetEnt; + bool autoAimPressed; + bool autoAimActive; + float autoAimPitch; + float autoAimPitchTarget; + float autoAimYaw; + float autoAimYawTarget; + AutoMeleeState autoMeleeState; + int autoMeleeTargetEnt; + float autoMeleePitch; + float autoMeleePitchTarget; + float autoMeleeYaw; + float autoMeleeYawTarget; + int lockOnTargetEnt; + }; } namespace Components @@ -153,23 +236,6 @@ namespace Components GamePadGlobals(); }; - struct ActionMapping - { - int input; - std::string action; - bool isReversible; - bool wasPressed = false; - bool spamWhenHeld = false; - - ActionMapping(int input, std::string action, bool isReversible = true, bool spamWhenHeld = false) - { - this->action = action; - this->isReversible = isReversible; - this->input = input; - this->spamWhenHeld = spamWhenHeld; - } - }; - private: static GamePad gamePads[Game::MAX_GAMEPADS]; static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; @@ -200,6 +266,11 @@ namespace Components static Dvar::Var gpad_button_deadzone; static Dvar::Var gpad_button_rstick_deflect_max; static Dvar::Var gpad_button_lstick_deflect_max; + static Dvar::Var input_viewSensitivity; + static Dvar::Var aim_turnrate_pitch; + static Dvar::Var aim_turnrate_pitch_ads; + static Dvar::Var aim_turnrate_yaw; + static Dvar::Var aim_turnrate_yaw_ads; static Dvar::Var xpadSensitivity; static Dvar::Var xpadEarlyTime; @@ -208,18 +279,6 @@ namespace Components static Dvar::Var xpadVerticalMultiplier; static Dvar::Var xpadAdsMultiplier; - static void CL_GetMouseMovementCl(Game::clientActive_t* result, float* mx, float* my); - static int unk_CheckKeyHook(int localClientNum, Game::keyNum_t keyCode); - - static void MouseOverride(Game::clientActive_t* clientActive, float* my, float* mx); - static void Vibrate(int leftVal = 0, int rightVal = 0); - - static void CL_FrameStub(); - static void PollXInputDevices(); - - static void CL_CreateCmdStub(); - static void CL_GamepadMove(int, Game::usercmd_s*); - static void MSG_WriteDeltaUsercmdKeyStub(); static void ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to); @@ -227,11 +286,12 @@ namespace Components static void MSG_ReadDeltaUsercmdKeyStub(); static void MSG_ReadDeltaUsercmdKeyStub2(); - static void GetLeftStick01Value(XINPUT_STATE* xiState, float& x, float& y); - static void GetRightStick01Value(XINPUT_STATE* xiState, float& x, float& y); - static void GamepadStickTo01(SHORT value, SHORT deadzone, float& output01); + static bool Key_IsValidGamePadChar(int key); - static bool Key_IsValidGamePadChar(const int key); + static float CL_GamepadAxisValue(int gamePadIndex, Game::GamepadVirtualAxis virtualAxis); + static char ClampChar(int value); + static void CL_GamepadMove(int gamePadIndex, Game::usercmd_s* cmd, float frame_time_base); + static void CL_MouseMove_Stub(); static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); static bool CL_CheckForIgnoreDueToRepeat(int gamePadIndex, int key, int repeatCount, unsigned int time); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 75180c63..72f2e9f7 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -1274,4 +1274,6 @@ namespace Game } } #pragma optimize("", on) + + clientActive_t* clients = reinterpret_cast(0xB2C698); } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index d9b1cbcd..c8950f1b 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -956,4 +956,6 @@ namespace Game void R_AddDebugBounds(float* color, Bounds* b, const float(*quat)[4]); Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter); + + extern clientActive_t* clients; } From ac1ade1976d75a67168b35e005860dd636a27ad0 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 22:44:57 +0200 Subject: [PATCH 43/83] Fix release mode issues with R_TextWidth_Hk --- src/Components/Modules/Materials.cpp | 9 +++++---- src/Game/Functions.cpp | 13 +++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index 1add3f71..961bb38e 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -284,6 +284,8 @@ namespace Components } } +#endif + int Materials::R_TextWidth_Hk(const char* text, int maxChars, Game::Font_s* font) { auto lineWidth = 0; @@ -296,7 +298,7 @@ namespace Components return 0; auto count = 0; - while (*text && count < maxChars) + while (text && *text && count < maxChars) { const auto letter = Game::SEH_ReadCharFromString(&text, nullptr); if (letter == '\r' || letter == '\n') @@ -329,18 +331,17 @@ namespace Components continue; } } - + lineWidth += R_GetCharacterGlyph(font, letter)->dx; if (lineWidth > maxWidth) maxWidth = lineWidth; count++; } } + return maxWidth; } -#endif - Materials::Materials() { Materials::ImageNameLength = 7; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 72f2e9f7..9f177160 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -1260,16 +1260,21 @@ namespace Game } } - __declspec(naked) Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter) + __declspec(naked) Glyph* R_GetCharacterGlyph(Font_s* /*font */, unsigned int /*letter*/) { __asm { - mov edi, [esp + 8] - push [esp+4] + push eax + pushad + mov edi, [esp + 0x28 + 4] + push [esp + 0x24 + 4] mov eax, 0x5055C0 call eax add esp,0x4 - + mov [esp + 0x20],eax + + popad + pop eax retn } } From e49e17d6e6d9b9765aa297739024f484b543be65 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 23 Aug 2021 22:45:22 +0200 Subject: [PATCH 44/83] Add turnrates for controllers --- src/Components/Modules/Gamepad.cpp | 236 ++++++++++++++++++++++++++--- src/Components/Modules/Gamepad.hpp | 22 ++- src/Game/Functions.cpp | 51 ++++++- src/Game/Functions.hpp | 16 +- src/Game/Structs.hpp | 179 ++++++++++++++++++++++ 5 files changed, 477 insertions(+), 27 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 45a251e1..2df4870f 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -140,6 +140,9 @@ namespace Game AimAssistGlobals* aaGlobArray = reinterpret_cast(0x7A2110); keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); keyname_t* vanillaLocalizedKeyNames = reinterpret_cast(0x798880); + + constexpr auto VANILLA_AIM_ASSIST_GRAPH_COUNT = 4u; + GraphFloat* aaInputGraph = reinterpret_cast(0x7A2FC0); } namespace Components @@ -168,6 +171,15 @@ namespace Components Dvar::Var Gamepad::gpad_button_rstick_deflect_max; Dvar::Var Gamepad::gpad_button_lstick_deflect_max; Dvar::Var Gamepad::input_viewSensitivity; + Dvar::Var Gamepad::aim_turnrate_pitch; + Dvar::Var Gamepad::aim_turnrate_pitch_ads; + Dvar::Var Gamepad::aim_turnrate_yaw; + Dvar::Var Gamepad::aim_turnrate_yaw_ads; + Dvar::Var Gamepad::aim_accel_turnrate_enabled; + Dvar::Var Gamepad::aim_accel_turnrate_lerp; + Dvar::Var Gamepad::aim_input_graph_enabled; + Dvar::Var Gamepad::aim_input_graph_index; + Dvar::Var Gamepad::aim_scale_view_axis; Dvar::Var Gamepad::xpadSensitivity; Dvar::Var Gamepad::xpadEarlyTime; @@ -322,11 +334,167 @@ namespace Components } } - bool Gamepad::Key_IsValidGamePadChar(const int key) + float Gamepad::LinearTrack(const float target, const float current, const float rate, const float deltaTime) { - return key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_1 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_1 - || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_2 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_2 - || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_3 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_3; + const auto err = target - current; + float step; + if(err <= 0.0f) + step = -rate * deltaTime; + else + step = rate * deltaTime; + + if(std::fabs(err) <= 0.001f) + return target; + + if (std::fabs(step) <= std::fabs(err)) + return current + step; + + return target; + } + + void Gamepad::AimAssist_CalcAdjustedAxis(const Game::AimInput* input, float* pitchAxis, float* yawAxis) + { + assert(input); + assert(pitchAxis); + assert(yawAxis); + + const auto graphIndex = aim_input_graph_index.get(); + if(aim_input_graph_enabled.get() && graphIndex >= 0 && graphIndex < Game::VANILLA_AIM_ASSIST_GRAPH_COUNT) + { + const auto deflection = std::sqrt(input->pitchAxis * input->pitchAxis + input->yawAxis * input->yawAxis); + + float fraction; + if (deflection - 1.0f < 0.0f) + fraction = deflection; + else + fraction = 1.0f; + + if (0.0f - deflection >= 0.0f) + fraction = 0.0f; + + const auto graphScale = Game::GraphFloat_GetValue(&Game::aaInputGraph[graphIndex], fraction); + *pitchAxis = input->pitchAxis * graphScale; + *yawAxis = input->yawAxis * graphScale; + } + else + { + *pitchAxis = input->pitchAxis; + *yawAxis = input->yawAxis; + } + + if(aim_scale_view_axis.get()) + { + const auto absPitchAxis = std::fabs(*pitchAxis); + const auto absYawAxis = std::fabs(*yawAxis); + + if (absPitchAxis <= absYawAxis) + *pitchAxis = (1.0f - (absYawAxis - absPitchAxis)) * *pitchAxis; + else + *yawAxis = (1.0f - (absPitchAxis - absYawAxis)) * *yawAxis; + } + } + + void Gamepad::AimAssist_CalcSlowdown(const Game::AimInput* /*input*/, float* pitchScale, float* yawScale) + { + /*assert(input); */ + assert(pitchScale); + assert(yawScale); + + *pitchScale = 1.0f; + *yawScale = 1.0f; + } + + float Gamepad::AimAssist_Lerp(const float from, const float to, const float fraction) + { + return (to - from) * fraction + from; + } + + void Gamepad::AimAssist_ApplyTurnRates(const Game::AimInput* input, Game::AimOutput* output) + { + assert(input->localClientNum < Game::MAX_GAMEPADS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; + + auto slowdownPitchScale = 0.0f; + auto slowdownYawScale = 0.0f; + float adjustedPitchAxis; + float adjustedYawAxis; + + if(aaGlob.autoMeleeState == Game::AIM_MELEE_STATE_UPDATING) + { + adjustedPitchAxis = 0.0f; + adjustedYawAxis = 0.0f; + slowdownPitchScale = 1.0f; + slowdownYawScale = 1.0f; + } + else + { + AimAssist_CalcAdjustedAxis(input, &adjustedPitchAxis, &adjustedYawAxis); + AimAssist_CalcSlowdown(input, &slowdownPitchScale, &slowdownYawScale); + } + + const auto sensitivity = input_viewSensitivity.get(); + auto pitchTurnRate = AimAssist_Lerp(aim_turnrate_pitch.get(), aim_turnrate_pitch_ads.get(), aaGlob.adsLerp); + pitchTurnRate = slowdownPitchScale * aaGlob.fovTurnRateScale * sensitivity * pitchTurnRate; + auto yawTurnRate = AimAssist_Lerp(aim_turnrate_yaw.get(), aim_turnrate_yaw_ads.get(), aaGlob.adsLerp); + yawTurnRate = slowdownYawScale * aaGlob.fovTurnRateScale * sensitivity * yawTurnRate; + + if (input->pitchMax > 0 && input->pitchMax < pitchTurnRate) + pitchTurnRate = input->pitchMax; + if (input->yawMax > 0 && input->yawMax < yawTurnRate) + yawTurnRate = input->yawMax; + + const auto pitchSign = adjustedPitchAxis >= 0.0f ? 1.0f : -1.0f; + const auto yawSign = adjustedYawAxis >= 0.0f ? 1.0f : -1.0f; + + const auto pitchDelta = std::fabs(adjustedPitchAxis) * pitchTurnRate; + const auto yawDelta = std::fabs(adjustedYawAxis) * yawTurnRate; + + if(!aim_accel_turnrate_enabled.get()) + { + aaGlob.pitchDelta = pitchDelta; + aaGlob.yawDelta = yawDelta; + } + else + { + const auto accel = aim_accel_turnrate_lerp.get() * sensitivity; + if (pitchDelta <= aaGlob.pitchDelta) + aaGlob.pitchDelta = pitchDelta; + else + aaGlob.pitchDelta = LinearTrack(pitchDelta, aaGlob.pitchDelta, accel, input->deltaTime); + + if (yawDelta <= aaGlob.yawDelta) + aaGlob.yawDelta = yawDelta; + else + aaGlob.yawDelta = LinearTrack(yawDelta, aaGlob.yawDelta, accel, input->deltaTime); + } + + output->pitch = aaGlob.pitchDelta * input->deltaTime * pitchSign + output->pitch; + output->yaw = aaGlob.yawDelta * input->deltaTime * yawSign + output->yaw; + } + + void Gamepad::AimAssist_UpdateGamePadInput(const Game::AimInput* input, Game::AimOutput* output) + { + assert(input->localClientNum < Game::MAX_GAMEPADS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; + + output->pitch = input->pitch; + output->yaw = input->yaw; + + if(aaGlob.initialized) + { + Game::AimAssist_UpdateTweakables(input->localClientNum); + Game::AimAssist_UpdateAdsLerp(input); + AimAssist_ApplyTurnRates(input, output); + + Game::AimAssist_ApplyAutoAim(input, output); + } + + aaGlob.prevButtons = input->buttons; + } + + bool Gamepad::CG_ShouldUpdateViewAngles(const int localClientNum) + { + return !Game::Key_IsKeyCatcherActive(localClientNum, Game::KEYCATCH_MASK_ANY) || Game::UI_GetActiveMenu(localClientNum) == Game::UIMENU_SCOREBOARD; } float Gamepad::CL_GamepadAxisValue(const int gamePadIndex, const Game::GamepadVirtualAxis virtualAxis) @@ -367,7 +535,7 @@ namespace Components { assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; - auto& gamePadGlobal = gamePadGlobals[gamePadIndex]; + auto& clientActive = Game::clients[gamePadIndex]; if (!gpad_enabled.get() || !gamePad.enabled) return; @@ -379,7 +547,7 @@ namespace Components auto yaw = -CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_YAW); auto forward = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_FORWARD); auto side = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_SIDE); - auto attack = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_ATTACK); + //auto attack = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_ATTACK); auto moveScale = static_cast(std::numeric_limits::max()); if (std::fabs(side) > 0.0f || std::fabs(forward) > 0.0f) @@ -393,21 +561,32 @@ namespace Components const auto forwardMove = static_cast(std::floor(forward * moveScale)); const auto rightMove = static_cast(std::floor(side * moveScale)); - const auto sensitivity = input_viewSensitivity.get(); - pitch *= sensitivity; - yaw *= sensitivity; - - if (Game::clients[0].cgameMaxPitchSpeed > 0 && Game::clients[0].cgameMaxPitchSpeed < std::fabs(pitch)) - pitch = std::signbit(pitch) ? -Game::clients[0].cgameMaxPitchSpeed : Game::clients[0].cgameMaxPitchSpeed; - if (Game::clients[0].cgameMaxYawSpeed > 0 && Game::clients[0].cgameMaxYawSpeed < std::fabs(yaw)) - yaw = std::signbit(yaw) ? -Game::clients[0].cgameMaxYawSpeed : Game::clients[0].cgameMaxYawSpeed; - - - Game::clients[0].clViewangles[0] += pitch; - Game::clients[0].clViewangles[1] += yaw; - cmd->rightmove = ClampChar(cmd->rightmove + rightMove); cmd->forwardmove = ClampChar(cmd->forwardmove + forwardMove); + + // Check for frozen controls. Flag name should start with PMF_ + if(CG_ShouldUpdateViewAngles(gamePadIndex) && (clientActive.snap.ps.pm_flags & 0x800) == 0) + { + Game::AimInput aimInput{}; + Game::AimOutput aimOutput{}; + aimInput.deltaTime = frame_time_base; + aimInput.buttons = cmd->buttons; + aimInput.localClientNum = gamePadIndex; + aimInput.deltaTimeScaled = static_cast(Game::cls->frametime) * 0.001f; + aimInput.pitch = clientActive.clViewangles[0]; + aimInput.pitchAxis = pitch; + aimInput.pitchMax = clientActive.cgameMaxPitchSpeed; + aimInput.yaw = clientActive.clViewangles[1]; + aimInput.yawAxis = yaw; + aimInput.yawMax = clientActive.cgameMaxYawSpeed; + aimInput.forwardAxis = forward; + aimInput.rightAxis = side; + AimAssist_UpdateGamePadInput(&aimInput, &aimOutput); + clientActive.clViewangles[0] = aimOutput.pitch; + clientActive.clViewangles[1] = aimOutput.yaw; + cmd->meleeChargeDist = aimOutput.meleeChargeDist; + cmd->meleeChargeYaw = aimOutput.meleeChargeYaw; + } } constexpr auto CL_MouseMove = 0x5A6240; @@ -433,6 +612,12 @@ namespace Components } } + bool Gamepad::Key_IsValidGamePadChar(const int key) + { + return key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_1 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_1 + || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_2 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_2 + || key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_3 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_3; + } void Gamepad::CL_GamepadResetMenuScrollTime(const int gamePadIndex, const int key, const bool down, const unsigned time) { @@ -1135,13 +1320,13 @@ namespace Components } } - void Gamepad::Bind_GP_SticksConfigs_f(Command::Params* params) + void Gamepad::Bind_GP_SticksConfigs_f(Command::Params*) { const auto* stickConfigName = gpad_sticksConfig.get(); Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", stickConfigName)); } - void Gamepad::Bind_GP_ButtonsConfigs_f(Command::Params* params) + void Gamepad::Bind_GP_ButtonsConfigs_f(Command::Params*) { const auto* buttonConfigName = gpad_buttonConfig.get(); Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", buttonConfigName)); @@ -1169,6 +1354,15 @@ namespace Components gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); + aim_turnrate_pitch = Dvar::Var("aim_turnrate_pitch"); + aim_turnrate_pitch_ads = Dvar::Var("aim_turnrate_pitch_ads"); + aim_turnrate_yaw = Dvar::Var("aim_turnrate_yaw"); + aim_turnrate_yaw_ads = Dvar::Var("aim_turnrate_yaw_ads"); + aim_accel_turnrate_enabled = Dvar::Var("aim_accel_turnrate_enabled"); + aim_accel_turnrate_lerp = Dvar::Var("aim_accel_turnrate_lerp"); + aim_input_graph_enabled = Dvar::Var("aim_input_graph_enabled"); + aim_input_graph_index = Dvar::Var("aim_input_graph_index"); + aim_scale_view_axis = Dvar::Var("aim_scale_view_axis"); } void Gamepad::IN_Init_Hk() diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 86f579c4..bb4086cc 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -160,11 +160,14 @@ namespace Game AIM_MELEE_STATE_TARGETED = 0x1, AIM_MELEE_STATE_UPDATING = 0x2, }; - + +#pragma warning(push) +#pragma warning(disable: 4324) struct __declspec(align(16)) AimAssistGlobals { AimAssistPlayerState ps; - __declspec(align(8)) float screenMtx[4][4]; + char _pad1[4]; + float screenMtx[4][4]; float invScreenMtx[4][4]; bool initialized; int prevButtons; @@ -197,6 +200,7 @@ namespace Game float autoMeleeYawTarget; int lockOnTargetEnt; }; +#pragma warning(pop) } namespace Components @@ -271,6 +275,11 @@ namespace Components static Dvar::Var aim_turnrate_pitch_ads; static Dvar::Var aim_turnrate_yaw; static Dvar::Var aim_turnrate_yaw_ads; + static Dvar::Var aim_accel_turnrate_enabled; + static Dvar::Var aim_accel_turnrate_lerp; + static Dvar::Var aim_input_graph_enabled; + static Dvar::Var aim_input_graph_index; + static Dvar::Var aim_scale_view_axis; static Dvar::Var xpadSensitivity; static Dvar::Var xpadEarlyTime; @@ -286,13 +295,20 @@ namespace Components static void MSG_ReadDeltaUsercmdKeyStub(); static void MSG_ReadDeltaUsercmdKeyStub2(); - static bool Key_IsValidGamePadChar(int key); + static float LinearTrack(float target, float current, float rate, float deltaTime); + static void AimAssist_CalcAdjustedAxis(const Game::AimInput* input, float* pitchAxis, float* yawAxis); + static void AimAssist_CalcSlowdown(const Game::AimInput* input, float* pitchScale, float* yawScale); + static float AimAssist_Lerp(float from, float to, float fraction); + static void AimAssist_ApplyTurnRates(const Game::AimInput* input, Game::AimOutput* output); + static void AimAssist_UpdateGamePadInput(const Game::AimInput* input, Game::AimOutput* output); + static bool CG_ShouldUpdateViewAngles(int localClientNum); static float CL_GamepadAxisValue(int gamePadIndex, Game::GamepadVirtualAxis virtualAxis); static char ClampChar(int value); static void CL_GamepadMove(int gamePadIndex, Game::usercmd_s* cmd, float frame_time_base); static void CL_MouseMove_Stub(); + static bool Key_IsValidGamePadChar(int key); static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); static bool CL_CheckForIgnoreDueToRepeat(int gamePadIndex, int key, int repeatCount, unsigned int time); static void UI_GamepadKeyEvent(int gamePadIndex, int key, bool down); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 9f177160..2d37efde 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -325,6 +325,7 @@ namespace Game TeleportPlayer_t TeleportPlayer = TeleportPlayer_t(0x496850); UI_AddMenuList_t UI_AddMenuList = UI_AddMenuList_t(0x4533C0); + UI_GetActiveMenu_t UI_GetActiveMenu = UI_GetActiveMenu_t(0x4BE790); UI_CheckStringTranslation_t UI_CheckStringTranslation = UI_CheckStringTranslation_t(0x4FB010); UI_LoadMenus_t UI_LoadMenus = UI_LoadMenus_t(0x641460); UI_UpdateArenas_t UI_UpdateArenas = UI_UpdateArenas_t(0x4A95B0); @@ -341,6 +342,8 @@ namespace Game unzClose_t unzClose = unzClose_t(0x41BF20); + AimAssist_ApplyAutoAim_t AimAssist_ApplyAutoAim = AimAssist_ApplyAutoAim_t(0x56A360); + XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); unsigned int* g_poolSize = reinterpret_cast(0x7995E8); @@ -434,6 +437,10 @@ namespace Game GfxScene* scene = reinterpret_cast(0x6944914); + clientActive_t* clients = reinterpret_cast(0xB2C698); + + clientStatic_t* cls = reinterpret_cast(0xA7FE90); + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); @@ -920,7 +927,25 @@ namespace Game Game::R_AddDebugLine(color, v[3], v[7]); } + float GraphGetValueFromFraction(const int knotCount, const float(*knots)[2], const float fraction) + { + for (auto knotIndex = 1; knotIndex < knotCount; ++knotIndex) + { + if (knots[knotIndex][0] >= fraction) + { + const auto adjustedFraction = (fraction - knots[knotIndex - 1][0]) / (knots[knotIndex][0] - knots[knotIndex - 1][0]); + return (knots[knotIndex][1] - knots[knotIndex - 1][1]) * adjustedFraction + knots[knotIndex - 1][1]; + } + } + + return -1.0f; + } + + float GraphFloat_GetValue(const GraphFloat* graph, const float fraction) + { + return GraphGetValueFromFraction(graph->knotCount, graph->knots, fraction) * graph->scale; + } #pragma optimize("", off) __declspec(naked) float UI_GetScoreboardLeft(void* /*a1*/) @@ -1278,7 +1303,29 @@ namespace Game retn } } -#pragma optimize("", on) - clientActive_t* clients = reinterpret_cast(0xB2C698); + __declspec(naked) void AimAssist_UpdateTweakables(int /*localClientNum*/) + { + __asm + { + mov eax,[esp+0x4] + mov ebx,0x569950 + call ebx + retn + } + } + + __declspec(naked) void AimAssist_UpdateAdsLerp(const AimInput* /*aimInput*/) + { + __asm + { + mov eax, [esp + 0x4] + mov ebx, 0x569AA0 + call ebx + retn + } + } + + +#pragma optimize("", on) } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index c8950f1b..6f46da78 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -767,6 +767,9 @@ namespace Game typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close); extern UI_AddMenuList_t UI_AddMenuList; + + typedef uiMenuCommand_t(__cdecl* UI_GetActiveMenu_t)(int localClientNum); + extern UI_GetActiveMenu_t UI_GetActiveMenu; typedef char* (__cdecl * UI_CheckStringTranslation_t)(char*, char*); extern UI_CheckStringTranslation_t UI_CheckStringTranslation; @@ -801,6 +804,9 @@ namespace Game typedef void(__cdecl * unzClose_t)(void* handle); extern unzClose_t unzClose; + typedef void(__cdecl* AimAssist_ApplyAutoAim_t)(const AimInput* input, AimOutput* output); + extern AimAssist_ApplyAutoAim_t AimAssist_ApplyAutoAim; + extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; @@ -893,6 +899,10 @@ namespace Game extern GfxScene* scene; + extern clientActive_t* clients; + + extern clientStatic_t* cls; + 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); @@ -955,7 +965,11 @@ namespace Game void R_AddDebugBounds(float* color, Bounds* b); void R_AddDebugBounds(float* color, Bounds* b, const float(*quat)[4]); + float GraphGetValueFromFraction(int knotCount, const float(*knots)[2], float fraction); + float GraphFloat_GetValue(const GraphFloat* graph, const float fraction); + Glyph* R_GetCharacterGlyph(Font_s* font, unsigned int letter); - extern clientActive_t* clients; + void AimAssist_UpdateTweakables(int localClientNum); + void AimAssist_UpdateAdsLerp(const AimInput* input); } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 269ec59d..a04e3535 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -208,6 +208,7 @@ namespace Game enum KeyCatch_t { + KEYCATCH_MASK_ANY = -1, KEYCATCH_CONSOLE = 0x1, KEYCATCH_UNKNOWN2 = 0x2, KEYCATCH_UNKNOWN4 = 0x4, @@ -357,6 +358,22 @@ namespace Game K_LAST_KEY = 0xDF, }; + enum uiMenuCommand_t + { + UIMENU_NONE = 0x0, + UIMENU_MAIN = 0x1, + UIMENU_INGAME = 0x2, + UIMENU_PREGAME = 0x3, + UIMENU_POSTGAME = 0x4, + UIMENU_SCRIPT_POPUP = 0x5, + UIMENU_SCOREBOARD = 0x6, + UIMENU_PARTY = 0x7, + UIMENU_GAMELOBBY = 0x8, + UIMENU_PRIVATELOBBY = 0x9, + UIMENU_ENDOFGAME = 0xA, + UIMENU_MIGRATION = 0xB, + }; + struct __declspec(align(4)) PhysPreset { const char *name; @@ -1020,6 +1037,20 @@ namespace Game hudelem_s archival[31]; }; + enum pmtype_t + { + PM_NORMAL = 0x0, + PM_NORMAL_LINKED = 0x1, + PM_NOCLIP = 0x2, + PM_UFO = 0x3, + PM_MPVIEWER = 0x4, + PM_SPECTATOR = 0x5, + PM_INTERMISSION = 0x6, + PM_LASTSTAND = 0x7, + PM_DEAD = 0x8, + PM_DEAD_LINKED = 0x9, + }; + struct playerState_s { int commandTime; @@ -5962,6 +5993,154 @@ namespace Game int allowAddDObj; }; + struct AimInput + { + float deltaTime; + float deltaTimeScaled; + float pitch; + float pitchAxis; + float pitchMax; + float yaw; + float yawAxis; + float yawMax; + float forwardAxis; + float rightAxis; + int buttons; + int localClientNum; + }; + + struct AimOutput + { + float pitch; + float yaw; + float meleeChargeYaw; + char meleeChargeDist; + }; + + struct clientLogo_t + { + int startTime; + int duration; + int fadein; + int fadeout; + Material* material[2]; + }; + + struct vidConfig_t + { + unsigned int sceneWidth; + unsigned int sceneHeight; + unsigned int displayWidth; + unsigned int displayHeight; + unsigned int displayFrequency; + int isFullscreen; + float aspectRatioWindow; + float aspectRatioScenePixel; + float aspectRatioDisplayPixel; + unsigned int maxTextureSize; + unsigned int maxTextureMaps; + bool deviceSupportsGamma; + }; + + struct trDebugLine_t + { + float start[3]; + float end[3]; + float color[4]; + int depthTest; + }; + + struct trDebugString_t + { + float xyz[3]; + float color[4]; + float scale; + char text[96]; + }; + + struct clientDebugStringInfo_t + { + int max; + int num; + trDebugString_t* strings; + int* durations; + }; + + struct clientDebugLineInfo_t + { + int max; + int num; + trDebugLine_t* lines; + int* durations; + }; + + struct clientDebug_t + { + int prevFromServer; + int fromServer; + clientDebugStringInfo_t clStrings; + clientDebugStringInfo_t svStringsBuffer; + clientDebugStringInfo_t svStrings; + clientDebugLineInfo_t clLines; + clientDebugLineInfo_t svLinesBuffer; + clientDebugLineInfo_t svLines; + }; + + struct ClientMatchData + { + char def[64]; + char data[1024]; + }; + + struct clientStatic_t + { + int quit; + int hunkUsersStarted; + char servername[256]; + int rendererStarted; + int soundStarted; + int uiStarted; + int frametime; + float frametime_base; + int realtime; + bool gpuSyncedPrevFrame; + bool inputUpdatedPrevFrame; + clientLogo_t logo; + float mapCenter[3]; + int lastServerPinged; + int pingedServerCount; + int totalServersParsed; + int pingUpdateSource; + Material* whiteMaterial; + Material* consoleMaterial; + Font_s* consoleFont; + vidConfig_t vidConfig; + clientDebug_t debug; + int doVidRestart; + ClientMatchData matchData; + XNADDR xnaddrs[18]; + float debugRenderPos[3]; + int skelValid; + int skelTimeStamp; + volatile int skelMemPos; + char skelMemory[262144]; + char* skelMemoryStart; + bool allowedAllocSkel; + int serverId; + gameState_t gameState; + clSnapshot_t noDeltaSnapshot; + int nextNoDeltaEntity; + entityState_s noDeltaEntities[1024]; + }; + + struct GraphFloat + { + char name[64]; + float knots[32][2]; + unsigned __int16 knotCount; + float scale; + }; + #pragma endregion #ifndef IDA From 30c90e5985745576b3aab2f5959aff86162eab6f Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 11:24:43 +0200 Subject: [PATCH 45/83] Set mouse as used when mouse is moved instead of disabling it when gamepad is in use --- src/Components/Modules/Gamepad.cpp | 34 +++++++++++------------------- src/Components/Modules/Gamepad.hpp | 2 +- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 2df4870f..3fe67b53 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1428,28 +1428,16 @@ namespace Components return gamePads[0].inUse; } - __declspec(naked) void Gamepad::CL_MouseEvent_Stub() + int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy) { - __asm - { - pushad - cmp eax, 6 - jz hideCursor + if(dx != 0 || dy != 0) + { + gamePads[0].inUse = false; + gpad_in_use.setRaw(false); + } - call IsGamePadInUse - test al, al - jnz hideCursor - - // Continue checks - popad - push 0x4D7C68 - retn; - - hideCursor: - popad - push 0x4D7C8A - retn - } + // Call original function + return Utils::Hook::Call(0x4D7C50)(x, y, dx, dy); } bool Gamepad::UI_RefreshViewport_Hk() @@ -1514,9 +1502,11 @@ namespace Components // Mark controller as unused when keyboard key is pressed Utils::Hook(0x43D179, CL_KeyEvent_Hk, HOOK_CALL).install()->quick(); + // Mark controller as unused when mouse is moved + Utils::Hook(0x64C507, CL_MouseEvent_Hk, HOOK_CALL).install()->quick(); + // Hide cursor when controller is active - Utils::Hook(0x4D7C63, CL_MouseEvent_Stub, HOOK_JUMP).install()->quick(); // Disable cursor - Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick(); // Do not draw cursor + Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick(); // Only return gamepad keys when gamepad enabled and only non gamepad keys when not Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index bb4086cc..9483e039 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -354,7 +354,7 @@ namespace Components static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]); static bool IsGamePadInUse(); static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time); - static void CL_MouseEvent_Stub(); + static int CL_MouseEvent_Hk(int x, int y, int dx, int dy); static bool UI_RefreshViewport_Hk(); static void CreateKeyNameMap(); }; From 2c3bfbe62a1be584a9846b6ff52ea6576e117254 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 11:25:00 +0200 Subject: [PATCH 46/83] Retrieve gamepad dvars on creating dvars instead of referencing them by name --- src/Components/Modules/Gamepad.cpp | 8 ++++++-- src/Components/Modules/Gamepad.hpp | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 3fe67b53..83b32022 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -171,6 +171,7 @@ namespace Components Dvar::Var Gamepad::gpad_button_rstick_deflect_max; Dvar::Var Gamepad::gpad_button_lstick_deflect_max; Dvar::Var Gamepad::input_viewSensitivity; + Dvar::Var Gamepad::input_invertPitch; Dvar::Var Gamepad::aim_turnrate_pitch; Dvar::Var Gamepad::aim_turnrate_pitch_ads; Dvar::Var Gamepad::aim_turnrate_yaw; @@ -180,6 +181,7 @@ namespace Components Dvar::Var Gamepad::aim_input_graph_enabled; Dvar::Var Gamepad::aim_input_graph_index; Dvar::Var Gamepad::aim_scale_view_axis; + Dvar::Var Gamepad::cl_bypassMouseInput; Dvar::Var Gamepad::xpadSensitivity; Dvar::Var Gamepad::xpadEarlyTime; @@ -541,7 +543,7 @@ namespace Components return; auto pitch = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_PITCH); - if (!Dvar::Var("input_invertPitch").get()) + if (!input_invertPitch.get()) pitch *= -1; auto yaw = -CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_YAW); @@ -1354,6 +1356,7 @@ namespace Components gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); + input_invertPitch = Dvar::Register("input_invertPitch", false, Game::DVAR_FLAG_SAVED, "Invert gamepad pitch"); aim_turnrate_pitch = Dvar::Var("aim_turnrate_pitch"); aim_turnrate_pitch_ads = Dvar::Var("aim_turnrate_pitch_ads"); aim_turnrate_yaw = Dvar::Var("aim_turnrate_yaw"); @@ -1363,6 +1366,7 @@ namespace Components aim_input_graph_enabled = Dvar::Var("aim_input_graph_enabled"); aim_input_graph_index = Dvar::Var("aim_input_graph_index"); aim_scale_view_axis = Dvar::Var("aim_scale_view_axis"); + cl_bypassMouseInput = Dvar::Var("cl_bypassMouseInput"); } void Gamepad::IN_Init_Hk() @@ -1442,7 +1446,7 @@ namespace Components bool Gamepad::UI_RefreshViewport_Hk() { - return Dvar::Var("cl_bypassMouseInput").get() || IsGamePadInUse(); + return cl_bypassMouseInput.get() || IsGamePadInUse(); } void Gamepad::CreateKeyNameMap() diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 9483e039..c937dfe3 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -271,6 +271,7 @@ namespace Components static Dvar::Var gpad_button_rstick_deflect_max; static Dvar::Var gpad_button_lstick_deflect_max; static Dvar::Var input_viewSensitivity; + static Dvar::Var input_invertPitch; static Dvar::Var aim_turnrate_pitch; static Dvar::Var aim_turnrate_pitch_ads; static Dvar::Var aim_turnrate_yaw; @@ -280,6 +281,7 @@ namespace Components static Dvar::Var aim_input_graph_enabled; static Dvar::Var aim_input_graph_index; static Dvar::Var aim_scale_view_axis; + static Dvar::Var cl_bypassMouseInput; static Dvar::Var xpadSensitivity; static Dvar::Var xpadEarlyTime; From eaa6e6fb8c920bb1031c3c605a1b153e0a428ce5 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 11:37:53 +0200 Subject: [PATCH 47/83] Swap kbm keybinds for gamepad commands when trying to displayed localized button string and using controller --- src/Components/Modules/Gamepad.cpp | 11 +++++++++++ src/Components/Modules/Gamepad.hpp | 1 + 2 files changed, 12 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 83b32022..f5a4c456 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1377,12 +1377,23 @@ namespace Components InitDvars(); } + const char* Gamepad::GetGamePadCommand(const char* command) + { + if (strcmp(command, "+activate") == 0 || strcmp(command, "+reload") == 0) + return "+usereload"; + if (strcmp(command, "+melee_breath") == 0) + return "+holdbreath"; + + return command; + } + int Gamepad::Key_GetCommandAssignmentInternal_Hk(const char* cmd, int (*keys)[2]) { auto keyCount = 0; if (gamePads[0].inUse) { + cmd = GetGamePadCommand(cmd); for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++) { if (!Key_IsValidGamePadChar(keyNum)) diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index c937dfe3..7109071f 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -353,6 +353,7 @@ namespace Components static void InitDvars(); static void IN_Init_Hk(); + static const char* GetGamePadCommand(const char* command); static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]); static bool IsGamePadInUse(); static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time); From edf060bd4a8210be4f95e2b9e968567314a90798 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 11:48:04 +0200 Subject: [PATCH 48/83] Remove unused gamepad fields --- src/Components/Modules/Gamepad.cpp | 24 ++---------------------- src/Components/Modules/Gamepad.hpp | 10 ---------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index f5a4c456..c792b2d5 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -150,9 +150,6 @@ namespace Components Gamepad::GamePad Gamepad::gamePads[Game::MAX_GAMEPADS]{}; Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GAMEPADS]{{}}; int Gamepad::gamePadBindingsModifiedFlags = 0; - std::chrono::milliseconds Gamepad::timeAtFirstHeldMaxLookX = 0ms; // "For how much time in milliseconds has the player been holding a horizontal direction on their stick, fully" (-1.0 or 1.0) - bool Gamepad::isHoldingMaxLookX = false; - bool Gamepad::isADS; Dvar::Var Gamepad::gpad_enabled; Dvar::Var Gamepad::gpad_debug; @@ -190,10 +187,6 @@ namespace Components Dvar::Var Gamepad::xpadVerticalMultiplier; Dvar::Var Gamepad::xpadAdsMultiplier; - Game::GamePadStickDir Gamepad::lastMenuNavigationDirection = Game::GPAD_STICK_DIR_COUNT; - std::chrono::milliseconds Gamepad::lastNavigationTime = 0ms; - std::chrono::milliseconds Gamepad::msBetweenNavigations = 220ms; - struct ControllerMenuKeyMapping { Game::keyNum_t controllerKey; @@ -1482,9 +1475,6 @@ namespace Components if (ZoneBuilder::IsEnabled()) return; - // use the xinput state when creating a usercmd - //Utils::Hook(0x5A6DB9, CL_CreateCmdStub, HOOK_JUMP).install()->quick(); - // package the forward and right move components in the move buttons Utils::Hook(0x60E38D, MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); @@ -1510,8 +1500,10 @@ namespace Components if (Dedicated::IsEnabled()) return; + // Initialize gamepad environment Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); + // Gamepad on frame hook Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); // Mark controller as unused when keyboard key is pressed @@ -1526,19 +1518,7 @@ namespace Components // Only return gamepad keys when gamepad enabled and only non gamepad keys when not Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); - //Utils::Hook(0x5A617D, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - //Utils::Hook(0x5A6816, CL_GetMouseMovementStub, HOOK_CALL).install()->quick(); - //Utils::Hook(0x5A6829, unk_CheckKeyHook, HOOK_CALL).install()->quick(); - // Add gamepad inputs to usercmds Utils::Hook(0x5A6DAE, CL_MouseMove_Stub, HOOK_CALL).install()->quick(); - - xpadSensitivity = Dvar::Register("xpad_sensitivity", 1.9f, 0.1f, 10.0f, Game::DVAR_FLAG_SAVED, "View sensitivity for XInput-compatible gamepads"); - xpadEarlyTime = Dvar::Register("xpad_early_time", 130, 0, 1000, Game::DVAR_FLAG_SAVED, "Time (in milliseconds) of reduced view sensitivity"); - xpadEarlyMultiplier = Dvar::Register("xpad_early_multiplier", 0.25f, 0.01f, 1.0f, Game::DVAR_FLAG_SAVED, - "By how much the view sensitivity is multiplied during xpad_early_time when moving the view stick"); - xpadHorizontalMultiplier = Dvar::Register("xpad_horizontal_multiplier", 1.5f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Horizontal view sensitivity multiplier"); - xpadVerticalMultiplier = Dvar::Register("xpad_vertical_multiplier", 0.8f, 1.0f, 20.0f, Game::DVAR_FLAG_SAVED, "Vertical view sensitivity multiplier"); - xpadAdsMultiplier = Dvar::Register("xpad_ads_multiplier", 0.7f, 0.1f, 1.0f, Game::DVAR_FLAG_SAVED, "By how much the view sensitivity is multiplied when aiming down the sights."); } } diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 7109071f..c6d83a6f 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -207,8 +207,6 @@ namespace Components { class Gamepad : public Component { - static constexpr float TRIGGER_THRESHOLD_F = static_cast(XINPUT_GAMEPAD_TRIGGER_THRESHOLD) / static_cast(0xFF); - public: Gamepad(); @@ -246,14 +244,6 @@ namespace Components static int gamePadBindingsModifiedFlags; - static bool isHoldingMaxLookX; - static std::chrono::milliseconds timeAtFirstHeldMaxLookX; - static bool isADS; - - static std::chrono::milliseconds lastNavigationTime; - static std::chrono::milliseconds msBetweenNavigations; - static Game::GamePadStickDir lastMenuNavigationDirection; - static Dvar::Var gpad_enabled; static Dvar::Var gpad_debug; static Dvar::Var gpad_present; From fea24a509aa8dd73568748c711c829999b5f75b8 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 12:04:34 +0200 Subject: [PATCH 49/83] Remove button float value from gamepad plus(+) binds since basegame doesnt make use of it --- src/Components/Modules/Gamepad.cpp | 39 +++++++++--------------------- src/Components/Modules/Gamepad.hpp | 4 +-- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index c792b2d5..c121e936 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -650,20 +650,20 @@ namespace Components if (gamePad.stickDown[stickIndex][Game::GPAD_STICK_POS]) { const Game::GamePadButtonEvent event = gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS] ? Game::GPAD_BUTTON_UPDATE : Game::GPAD_BUTTON_PRESSED; - CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, event, time, Game::GPAD_NONE); + CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, event, time); } else if (gamePad.stickDown[stickIndex][Game::GPAD_STICK_NEG]) { const Game::GamePadButtonEvent event = gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG] ? Game::GPAD_BUTTON_UPDATE : Game::GPAD_BUTTON_PRESSED; - CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, event, time, Game::GPAD_NONE); + CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, event, time); } else if (gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_POS]) { - CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, Game::GPAD_BUTTON_RELEASED, time, Game::GPAD_NONE); + CL_GamepadButtonEvent(gamePadIndex, mapping.posCode, Game::GPAD_BUTTON_RELEASED, time); } else if (gamePad.stickDownLast[stickIndex][Game::GPAD_STICK_NEG]) { - CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, Game::GPAD_BUTTON_RELEASED, time, Game::GPAD_NONE); + CL_GamepadButtonEvent(gamePadIndex, mapping.negCode, Game::GPAD_BUTTON_RELEASED, time); } } } @@ -734,7 +734,7 @@ namespace Components return repeatCount > 1; } - void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time, const Game::GamePadButton button) + void Gamepad::CL_GamepadButtonEvent(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -789,13 +789,7 @@ namespace Components { if (keyBinding[0] == '+') { - float floatValue; - if (button) - floatValue = GPad_GetButton(gamePadIndex, button); - else - floatValue = 0.0f; - - sprintf_s(cmd, "%s %i %i %0.3f\n", keyBinding, key, time, floatValue); + sprintf_s(cmd, "%s %i %i\n", keyBinding, key, time); Game::Cbuf_AddText(gamePadIndex, cmd); } else @@ -809,13 +803,7 @@ namespace Components { if (keyBinding && keyBinding[0] == '+') { - float floatValue; - if (button) - floatValue = GPad_GetButton(gamePadIndex, button); - else - floatValue = 0.0f; - - sprintf_s(cmd, "-%s %i %i %0.3f\n", &keyBinding[1], key, time, floatValue); + sprintf_s(cmd, "-%s %i %i\n", &keyBinding[1], key, time); Game::Cbuf_AddText(gamePadIndex, cmd); } @@ -826,7 +814,7 @@ namespace Components } } - void Gamepad::CL_GamepadButtonEventForPort(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time, const Game::GamePadButton button) + void Gamepad::CL_GamepadButtonEventForPort(const int gamePadIndex, const int key, const Game::GamePadButtonEvent buttonEvent, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; @@ -838,7 +826,7 @@ namespace Components CL_GamepadResetMenuScrollTime(gamePadIndex, key, buttonEvent == Game::GPAD_BUTTON_PRESSED, time); - CL_GamepadButtonEvent(gamePadIndex, key, buttonEvent, time, button); + CL_GamepadButtonEvent(gamePadIndex, key, buttonEvent, time); } void Gamepad::GPad_ConvertStickToFloat(const short x, const short y, float& outX, float& outY) @@ -1131,8 +1119,7 @@ namespace Components gamePadIndex, buttonMapping.code, Game::GPAD_BUTTON_PRESSED, - time, - buttonMapping.padButton); + time); } else if (GPad_ButtonRequiresUpdates(gamePadIndex, buttonMapping.padButton)) { @@ -1140,8 +1127,7 @@ namespace Components gamePadIndex, buttonMapping.code, Game::GPAD_BUTTON_UPDATE, - time, - buttonMapping.padButton); + time); } else if (GPad_IsButtonReleased(gamePadIndex, buttonMapping.padButton)) { @@ -1149,8 +1135,7 @@ namespace Components gamePadIndex, buttonMapping.code, Game::GPAD_BUTTON_RELEASED, - time, - buttonMapping.padButton); + time); } } } diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index c6d83a6f..19243c22 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -306,8 +306,8 @@ namespace Components static void UI_GamepadKeyEvent(int gamePadIndex, int key, bool down); static void CL_GamepadGenerateAPad(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, unsigned time); static void CL_GamepadEvent(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, float value, unsigned time); - static void CL_GamepadButtonEvent(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned time, Game::GamePadButton button); - static void CL_GamepadButtonEventForPort(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned int time, Game::GamePadButton button); + static void CL_GamepadButtonEvent(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned time); + static void CL_GamepadButtonEventForPort(int gamePadIndex, int key, Game::GamePadButtonEvent buttonEvent, unsigned int time); static void GPad_ConvertStickToFloat(short x, short y, float& outX, float& outY); static float GPad_GetStick(int gamePadIndex, Game::GamePadStick stick); From 8adea24d67fff706ac0cd693379e77b25a03b701 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 17:20:52 +0200 Subject: [PATCH 50/83] Add gamepad location selection support --- src/Components/Modules/Gamepad.cpp | 96 ++++++++++++++++++++++++++---- src/Components/Modules/Gamepad.hpp | 3 + src/Game/Functions.cpp | 4 ++ src/Game/Functions.hpp | 8 +++ src/Game/Structs.hpp | 18 ++++++ 5 files changed, 119 insertions(+), 10 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index c121e936..cbf72ebe 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -179,6 +179,7 @@ namespace Components Dvar::Var Gamepad::aim_input_graph_index; Dvar::Var Gamepad::aim_scale_view_axis; Dvar::Var Gamepad::cl_bypassMouseInput; + Dvar::Var Gamepad::cg_mapLocationSelectionCursorSpeed; Dvar::Var Gamepad::xpadSensitivity; Dvar::Var Gamepad::xpadEarlyTime; @@ -223,7 +224,7 @@ namespace Components __declspec(naked) void Gamepad::MSG_WriteDeltaUsercmdKeyStub() { __asm - { + { // fix stack pointer add esp, 0Ch @@ -241,7 +242,7 @@ namespace Components // return back push 0x60E40E retn - } + } } void Gamepad::ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to) @@ -269,7 +270,7 @@ namespace Components __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub() { __asm - { + { push ebx // to push ebp // from push edi // key @@ -280,13 +281,13 @@ namespace Components // return back push 0x4921BF ret - } + } } __declspec(naked) void Gamepad::MSG_ReadDeltaUsercmdKeyStub2() { __asm - { + { push ebx // to push ebp // from push edi // key @@ -299,7 +300,7 @@ namespace Components push esi push 0x492085 ret - } + } } bool Gamepad::GPad_Check(const int gamePadIndex, const int portIndex) @@ -487,6 +488,77 @@ namespace Components aaGlob.prevButtons = input->buttons; } + + bool Gamepad::CG_HandleLocationSelectionInput_GamePad(const int localClientNum, Game::usercmd_s* cmd) + { + const auto frameTime = static_cast(Game::cgArray[0].frametime) * 0.001f; + const auto mapAspectRatio = Game::cgArray[0].compassMapWorldSize[0] / Game::cgArray[0].compassMapWorldSize[1]; + const auto selectionRequiresAngle = (Game::cgArray[0].predictedPlayerState.locationSelectionInfo & 0x80) != 0; + + auto up = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_FORWARD); + auto right = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_SIDE); + auto magnitude = up * up + right * right; + + if(magnitude > 1.0f) + { + magnitude = std::sqrt(magnitude); + up /= magnitude; + right /= magnitude; + } + + Game::cgArray[0].selectedLocation[0] += right * cg_mapLocationSelectionCursorSpeed.get() * frameTime; + Game::cgArray[0].selectedLocation[1] -= up * mapAspectRatio * cg_mapLocationSelectionCursorSpeed.get() * frameTime; + + if(selectionRequiresAngle) + { + const auto yawUp = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_PITCH); + const auto yawRight = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_YAW); + + if(std::fabs(yawUp) > 0.0f || std::fabs(yawRight) > 0.0f) + { + Game::vec2_t vec + { + yawUp, + -yawRight + }; + + Game::cgArray[0].selectedLocationAngle = Game::AngleNormalize360(Game::vectoyaw(&vec)); + Game::cgArray[0].selectedAngleLocation[0] = Game::cgArray[0].selectedLocation[0]; + Game::cgArray[0].selectedAngleLocation[1] = Game::cgArray[0].selectedLocation[1]; + } + } + else + { + Game::cgArray[0].selectedAngleLocation[0] = Game::cgArray[0].selectedLocation[0]; + Game::cgArray[0].selectedAngleLocation[1] = Game::cgArray[0].selectedLocation[1]; + } + + return true; + } + + constexpr auto CG_HandleLocationSelectionInput = 0x5A67A0; + __declspec(naked) void Gamepad::CG_HandleLocationSelectionInput_Stub() + { + __asm + { + // Prepare args for our function call + push esi // usercmd + push eax // localClientNum + + call CG_HandleLocationSelectionInput + + test al,al + jz exit_handling + + // Call our function, the args were already prepared earlier + call CG_HandleLocationSelectionInput_GamePad + + exit_handling: + add esp, 0x8 + ret + } + } + bool Gamepad::CG_ShouldUpdateViewAngles(const int localClientNum) { return !Game::Key_IsKeyCatcherActive(localClientNum, Game::KEYCATCH_MASK_ANY) || Game::UI_GetActiveMenu(localClientNum) == Game::UIMENU_SCOREBOARD; @@ -589,7 +661,7 @@ namespace Components __declspec(naked) void Gamepad::CL_MouseMove_Stub() { __asm - { + { // Prepare args for our function call push [esp+0x4] // frametime_base push ebx // cmd @@ -604,7 +676,7 @@ namespace Components add esp,0xC ret - } + } } bool Gamepad::Key_IsValidGamePadChar(const int key) @@ -1188,7 +1260,7 @@ namespace Components void __declspec(naked) Gamepad::Com_WriteConfiguration_Modified_Stub() { __asm - { + { mov eax, [ecx + 0x18] or eax, gamePadBindingsModifiedFlags // Also check for gamePadBindingsModifiedFlags test al, 1 @@ -1202,7 +1274,7 @@ namespace Components endMethod: push 0x60B298 retn - } + } } @@ -1345,6 +1417,7 @@ namespace Components aim_input_graph_index = Dvar::Var("aim_input_graph_index"); aim_scale_view_axis = Dvar::Var("aim_scale_view_axis"); cl_bypassMouseInput = Dvar::Var("cl_bypassMouseInput"); + cg_mapLocationSelectionCursorSpeed = Dvar::Var("cg_mapLocationSelectionCursorSpeed"); } void Gamepad::IN_Init_Hk() @@ -1503,6 +1576,9 @@ namespace Components // Only return gamepad keys when gamepad enabled and only non gamepad keys when not Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); + // Add gamepad inputs to location selection (eg airstrike location) handling + Utils::Hook(0x5A6D72, CG_HandleLocationSelectionInput_Stub, HOOK_CALL).install()->quick(); + // Add gamepad inputs to usercmds Utils::Hook(0x5A6DAE, CL_MouseMove_Stub, HOOK_CALL).install()->quick(); } diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 19243c22..469c9acc 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -272,6 +272,7 @@ namespace Components static Dvar::Var aim_input_graph_index; static Dvar::Var aim_scale_view_axis; static Dvar::Var cl_bypassMouseInput; + static Dvar::Var cg_mapLocationSelectionCursorSpeed; static Dvar::Var xpadSensitivity; static Dvar::Var xpadEarlyTime; @@ -294,6 +295,8 @@ namespace Components static void AimAssist_ApplyTurnRates(const Game::AimInput* input, Game::AimOutput* output); static void AimAssist_UpdateGamePadInput(const Game::AimInput* input, Game::AimOutput* output); + static bool CG_HandleLocationSelectionInput_GamePad(int localClientNum, Game::usercmd_s* cmd); + static void CG_HandleLocationSelectionInput_Stub(); static bool CG_ShouldUpdateViewAngles(int localClientNum); static float CL_GamepadAxisValue(int gamePadIndex, Game::GamepadVirtualAxis virtualAxis); static char ClampChar(int value); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 2d37efde..d9131420 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -339,6 +339,8 @@ namespace Game Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0); Vec3UnpackUnitVec_t Vec3UnpackUnitVec = Vec3UnpackUnitVec_t(0x45CA90); + vectoyaw_t vectoyaw = vectoyaw_t(0x45AD10); + AngleNormalize360_t AngleNormalize360 = AngleNormalize360_t(0x438DC0); unzClose_t unzClose = unzClose_t(0x41BF20); @@ -441,6 +443,8 @@ namespace Game clientStatic_t* cls = reinterpret_cast(0xA7FE90); + cg_s* cgArray = reinterpret_cast(0x7F0F78); + 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 6f46da78..b0b90efb 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -800,6 +800,12 @@ namespace Game typedef void (__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t *); extern Vec3UnpackUnitVec_t Vec3UnpackUnitVec; + + typedef float(__cdecl* vectoyaw_t)(vec2_t* vec); + extern vectoyaw_t vectoyaw; + + typedef float(__cdecl* AngleNormalize360_t)(float val); + extern AngleNormalize360_t AngleNormalize360; typedef void(__cdecl * unzClose_t)(void* handle); extern unzClose_t unzClose; @@ -903,6 +909,8 @@ namespace Game extern clientStatic_t* cls; + extern cg_s* cgArray; + 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 a04e3535..80c293bd 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -6141,6 +6141,24 @@ namespace Game float scale; }; + struct __declspec(align(8)) cg_s + { + playerState_s predictedPlayerState; + char _pad0[0x67638]; + int frametime; // + 0x6A754 + char _pad1[0x960C]; // + 0x6A758 + float compassMapWorldSize[2]; // + 0x73D64 + char _pad2[0x74]; // + 0x73D6C + float selectedLocation[2]; // + 0x73DE0 + float selectedLocationAngle; + float selectedAngleLocation[2]; + float selectedLocationPrev[2]; + float selectedLocationAnglePrev; + char _pad3[0x89740]; + }; + + constexpr auto aaaaaaa1 = sizeof(cg_s); + #pragma endregion #ifndef IDA From e2552f1aeb6143cd3ae2c0e563ce9a812d15907f Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 17:55:09 +0200 Subject: [PATCH 51/83] Add remote control (predator) controls for gamepad --- src/Components/Modules/Gamepad.cpp | 32 ++++++++++++++++++++++++++++++ src/Components/Modules/Gamepad.hpp | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index cbf72ebe..8acb152c 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -488,6 +488,35 @@ namespace Components aaGlob.prevButtons = input->buttons; } + void Gamepad::CL_RemoteControlMove_GamePad(const int localClientNum, Game::usercmd_s* cmd) + { + const auto up = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_FORWARD); + const auto right = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_SIDE); + const auto sensitivity = input_viewSensitivity.get(); + + constexpr auto scale = static_cast(std::numeric_limits::max()); + cmd->remoteControlAngles[0] = ClampChar(cmd->remoteControlAngles[0] + static_cast(std::floor(-up * scale * sensitivity))); + cmd->remoteControlAngles[1] = ClampChar(cmd->remoteControlAngles[1] + static_cast(std::floor(-right * scale * sensitivity))); + } + + constexpr auto CL_RemoteControlMove = 0x5A6BA0; + __declspec(naked) void Gamepad::CL_RemoteControlMove_Stub() + { + __asm + { + // Prepare args for our function call + push edi // usercmd + push eax // localClientNum + + call CL_RemoteControlMove + + // Call our function, the args were already prepared earlier + call CL_RemoteControlMove_GamePad + add esp, 0x8 + + ret + } + } bool Gamepad::CG_HandleLocationSelectionInput_GamePad(const int localClientNum, Game::usercmd_s* cmd) { @@ -1576,6 +1605,9 @@ namespace Components // Only return gamepad keys when gamepad enabled and only non gamepad keys when not Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); + // Add gamepad inputs to remote control (eg predator) handling + Utils::Hook(0x5A6D4E, CL_RemoteControlMove_Stub, HOOK_CALL).install()->quick(); + // Add gamepad inputs to location selection (eg airstrike location) handling Utils::Hook(0x5A6D72, CG_HandleLocationSelectionInput_Stub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 469c9acc..6816f2d3 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -295,6 +295,8 @@ namespace Components static void AimAssist_ApplyTurnRates(const Game::AimInput* input, Game::AimOutput* output); static void AimAssist_UpdateGamePadInput(const Game::AimInput* input, Game::AimOutput* output); + static void CL_RemoteControlMove_GamePad(int localClientNum, Game::usercmd_s* cmd); + static void CL_RemoteControlMove_Stub(); static bool CG_HandleLocationSelectionInput_GamePad(int localClientNum, Game::usercmd_s* cmd); static void CG_HandleLocationSelectionInput_Stub(); static bool CG_ShouldUpdateViewAngles(int localClientNum); From ff86a19cc33d198b2d6e4554e5049d37d7ae68cf Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 24 Aug 2021 18:09:06 +0200 Subject: [PATCH 52/83] Fix gamepad release compiling --- src/Components/Modules/Gamepad.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 8acb152c..d2db967d 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -490,6 +490,8 @@ namespace Components void Gamepad::CL_RemoteControlMove_GamePad(const int localClientNum, Game::usercmd_s* cmd) { + // Buttons are already handled by keyboard input handler + const auto up = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_FORWARD); const auto right = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_SIDE); const auto sensitivity = input_viewSensitivity.get(); @@ -518,8 +520,10 @@ namespace Components } } - bool Gamepad::CG_HandleLocationSelectionInput_GamePad(const int localClientNum, Game::usercmd_s* cmd) + bool Gamepad::CG_HandleLocationSelectionInput_GamePad(const int localClientNum, Game::usercmd_s* /*cmd*/) { + // Buttons are already handled by keyboard input handler + const auto frameTime = static_cast(Game::cgArray[0].frametime) * 0.001f; const auto mapAspectRatio = Game::cgArray[0].compassMapWorldSize[0] / Game::cgArray[0].compassMapWorldSize[1]; const auto selectionRequiresAngle = (Game::cgArray[0].predictedPlayerState.locationSelectionInfo & 0x80) != 0; From ae8dd7bb333bdf96676731290ecbd72b4e961c18 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 25 Aug 2021 19:42:41 +0200 Subject: [PATCH 53/83] Rename Automelee that was mistakenly named autoaim --- src/Components/Modules/Gamepad.cpp | 2 +- src/Game/Functions.cpp | 2 +- src/Game/Functions.hpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index d2db967d..9b72f5d9 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -482,7 +482,7 @@ namespace Components Game::AimAssist_UpdateAdsLerp(input); AimAssist_ApplyTurnRates(input, output); - Game::AimAssist_ApplyAutoAim(input, output); + Game::AimAssist_ApplyAutoMelee(input, output); } aaGlob.prevButtons = input->buttons; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index d9131420..6c2c35a5 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -344,7 +344,7 @@ namespace Game unzClose_t unzClose = unzClose_t(0x41BF20); - AimAssist_ApplyAutoAim_t AimAssist_ApplyAutoAim = AimAssist_ApplyAutoAim_t(0x56A360); + AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee = AimAssist_ApplyAutoMelee_t(0x56A360); XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); unsigned int* g_poolSize = reinterpret_cast(0x7995E8); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index b0b90efb..0ec533a3 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -810,8 +810,8 @@ namespace Game typedef void(__cdecl * unzClose_t)(void* handle); extern unzClose_t unzClose; - typedef void(__cdecl* AimAssist_ApplyAutoAim_t)(const AimInput* input, AimOutput* output); - extern AimAssist_ApplyAutoAim_t AimAssist_ApplyAutoAim; + typedef void(__cdecl* AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); + extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee; extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; From 7ce7ba883b65171f44c09079c179049fa017140b Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 25 Aug 2021 19:59:55 +0200 Subject: [PATCH 54/83] Add gamepad slowdown and lockon aimassists --- premake5.lua | 8 ++ src/Components/Modules/Gamepad.cpp | 187 ++++++++++++++++++++++++++++- src/Components/Modules/Gamepad.hpp | 58 ++++++++- src/Game/Functions.cpp | 1 + src/Game/Functions.hpp | 3 + src/Game/Structs.hpp | 10 ++ src/STDInclude.hpp | 1 + 7 files changed, 265 insertions(+), 3 deletions(-) diff --git a/premake5.lua b/premake5.lua index 91bee2df..20744831 100644 --- a/premake5.lua +++ b/premake5.lua @@ -79,6 +79,11 @@ newoption { description = "Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches." } +newoption { + trigger = "aimassist-enable", + description = "Enables code for controller aim assist." +} + newaction { trigger = "version", description = "Returns the version string for the current commit of the source code.", @@ -332,6 +337,9 @@ workspace "iw4x" if _OPTIONS["iw4x-zones"] then defines { "GENERATE_IW4X_SPECIFIC_ZONES" } end + if _OPTIONS["aimassist-enable"] then + defines { "AIM_ASSIST_ENABLED" } + end -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 9b72f5d9..9c4e9613 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1,6 +1,7 @@ #include "STDInclude.hpp" #include +#include namespace Game { @@ -180,6 +181,17 @@ namespace Components Dvar::Var Gamepad::aim_scale_view_axis; Dvar::Var Gamepad::cl_bypassMouseInput; Dvar::Var Gamepad::cg_mapLocationSelectionCursorSpeed; + Dvar::Var Gamepad::aim_aimAssistRangeScale; + Dvar::Var Gamepad::aim_slowdown_enabled; + Dvar::Var Gamepad::aim_slowdown_debug; + Dvar::Var Gamepad::aim_slowdown_pitch_scale; + Dvar::Var Gamepad::aim_slowdown_pitch_scale_ads; + Dvar::Var Gamepad::aim_slowdown_yaw_scale; + Dvar::Var Gamepad::aim_slowdown_yaw_scale_ads; + Dvar::Var Gamepad::aim_lockon_enabled; + Dvar::Var Gamepad::aim_lockon_deflection; + Dvar::Var Gamepad::aim_lockon_pitch_strength; + Dvar::Var Gamepad::aim_lockon_strength; Dvar::Var Gamepad::xpadSensitivity; Dvar::Var Gamepad::xpadEarlyTime; @@ -348,6 +360,116 @@ namespace Components return target; } + bool Gamepad::AimAssist_DoBoundsIntersectCenterBox(const float* clipMins, const float* clipMaxs, const float clipHalfWidth, const float clipHalfHeight) + { + return clipHalfWidth >= clipMins[0] && clipMaxs[0] >= -clipHalfWidth + && clipHalfHeight >= clipMins[1] && clipMaxs[1] >= -clipHalfHeight; + } + + bool Gamepad::AimAssist_IsPlayerUsingOffhand(Game::AimAssistPlayerState* ps) + { + if ((ps->weapFlags & 2) == 0) + return false; + + if (!ps->weapIndex) + return false; + + const auto* weaponDef = Game::BG_GetWeaponDef(ps->weapIndex); + + return weaponDef->offhandClass != Game::OFFHAND_CLASS_NONE; + } + + const Game::AimScreenTarget* Gamepad::AimAssist_GetBestTarget(const Game::AimAssistGlobals* aaGlob, const float range, const float regionWidth, const float regionHeight) + { + const auto rangeSqr = range * range; + for (auto targetIndex = 0; targetIndex < aaGlob->screenTargetCount; targetIndex++) + { + const auto* currentTarget = &aaGlob->screenTargets[targetIndex]; + if (currentTarget->distSqr <= rangeSqr && AimAssist_DoBoundsIntersectCenterBox(currentTarget->clipMins, currentTarget->clipMaxs, regionWidth, regionHeight)) + { + return currentTarget; + } + } + + return nullptr; + } + + const Game::AimScreenTarget* Gamepad::AimAssist_GetTargetFromEntity(const Game::AimAssistGlobals* aaGlob, const int entIndex) + { + if (entIndex == Game::AIM_TARGET_INVALID) + return nullptr; + + for (auto targetIndex = 0; targetIndex < aaGlob->screenTargetCount; targetIndex++) + { + const auto* currentTarget = &aaGlob->screenTargets[targetIndex]; + if (currentTarget->entIndex == entIndex) + return currentTarget; + } + + return nullptr; + } + + const Game::AimScreenTarget* Gamepad::AimAssist_GetPrevOrBestTarget(const Game::AimAssistGlobals* aaGlob, const float range, const float regionWidth, const float regionHeight, + const int prevTargetEnt) + { + const auto screenTarget = AimAssist_GetTargetFromEntity(aaGlob, prevTargetEnt); + + if (screenTarget && (range * range) > screenTarget->distSqr && AimAssist_DoBoundsIntersectCenterBox(screenTarget->clipMins, screenTarget->clipMaxs, regionWidth, regionHeight)) + return screenTarget; + + return AimAssist_GetBestTarget(aaGlob, range, regionWidth, regionHeight); + } + + void Gamepad::AimAssist_ApplyLockOn(const Game::AimInput* input, Game::AimOutput* output) + { +#ifdef AIM_ASSIST_ENABLED + + assert(input); + assert(input->localClientNum < Game::MAX_GAMEPADS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; + + const auto prevTargetEnt = aaGlob.lockOnTargetEnt; + aaGlob.lockOnTargetEnt = Game::AIM_TARGET_INVALID; + + if (!aim_lockon_enabled.get() || AimAssist_IsPlayerUsingOffhand(&aaGlob.ps) || aaGlob.autoAimActive || aaGlob.autoMeleeState == Game::AIM_MELEE_STATE_UPDATING) + return; + + const auto* weaponDef = Game::BG_GetWeaponDef(aaGlob.ps.weapIndex); + if (weaponDef->requireLockonToFire) + return; + + const auto deflection = aim_lockon_deflection.get(); + if (deflection > std::fabs(input->pitchAxis) && deflection > std::fabs(input->yawAxis) && deflection > std::fabs(input->rightAxis)) + return; + + if (!aaGlob.ps.weapIndex) + return; + + const auto aimAssistRange = AimAssist_Lerp(weaponDef->aimAssistRange, weaponDef->aimAssistRangeAds, aaGlob.adsLerp) * aim_aimAssistRangeScale.get(); + const auto screenTarget = AimAssist_GetPrevOrBestTarget(&aaGlob, aimAssistRange, aaGlob.tweakables.lockOnRegionWidth, aaGlob.tweakables.lockOnRegionHeight, prevTargetEnt); + + if (screenTarget && screenTarget->distSqr > 0.0f) + { + aaGlob.lockOnTargetEnt = screenTarget->entIndex; + const auto arcLength = std::sqrt(screenTarget->distSqr) * static_cast(M_PI); + + const auto pitchTurnRate = + (screenTarget->velocity[0] * aaGlob.viewAxis[2][0] + screenTarget->velocity[1] * aaGlob.viewAxis[2][1] + screenTarget->velocity[2] * aaGlob.viewAxis[2][2] + - (aaGlob.ps.velocity[0] * aaGlob.viewAxis[2][0] + aaGlob.ps.velocity[1] * aaGlob.viewAxis[2][1] + aaGlob.ps.velocity[2] * aaGlob.viewAxis[2][2])) + / arcLength * 180.0f * aim_lockon_pitch_strength.get(); + + const auto yawTurnRate = + (screenTarget->velocity[0] * aaGlob.viewAxis[1][0] + screenTarget->velocity[1] * aaGlob.viewAxis[1][1] + screenTarget->velocity[2] * aaGlob.viewAxis[1][2] + - (aaGlob.ps.velocity[0] * aaGlob.viewAxis[1][0] + aaGlob.ps.velocity[1] * aaGlob.viewAxis[1][1] + aaGlob.ps.velocity[2] * aaGlob.viewAxis[1][2])) + / arcLength * 180.0f * aim_lockon_strength.get(); + + output->pitch -= pitchTurnRate * input->deltaTime; + output->yaw += yawTurnRate * input->deltaTime; + } + +#endif + } + void Gamepad::AimAssist_CalcAdjustedAxis(const Game::AimInput* input, float* pitchAxis, float* yawAxis) { assert(input); @@ -390,14 +512,63 @@ namespace Components } } - void Gamepad::AimAssist_CalcSlowdown(const Game::AimInput* /*input*/, float* pitchScale, float* yawScale) + bool Gamepad::AimAssist_IsSlowdownActive(const Game::AimAssistPlayerState* ps) { - /*assert(input); */ + if (!aim_slowdown_enabled.get()) + return false; + + if (!ps->weapIndex) + return false; + + const auto* weaponDef = Game::BG_GetWeaponDef(ps->weapIndex); + if (weaponDef->requireLockonToFire) + return false; + + if (ps->linkFlags & 4) + return false; + + if (ps->weaponState >= Game::WEAPON_STUNNED_START && ps->weaponState <= Game::WEAPON_STUNNED_END) + return false; + + if (ps->eFlags & 0x300800) + return false; + + if (!ps->hasAmmo) + return false; + + return true; + } + + void Gamepad::AimAssist_CalcSlowdown(const Game::AimInput* input, float* pitchScale, float* yawScale) + { + assert(input); + assert(input->localClientNum < Game::MAX_GAMEPADS); + auto& aaGlob = Game::aaGlobArray[input->localClientNum]; assert(pitchScale); assert(yawScale); *pitchScale = 1.0f; *yawScale = 1.0f; + +#ifdef AIM_ASSIST_ENABLED + + if (!AimAssist_IsSlowdownActive(&aaGlob.ps)) + return; + + const auto* weaponDef = Game::BG_GetWeaponDef(aaGlob.ps.weapIndex); + const auto aimAssistRange = AimAssist_Lerp(weaponDef->aimAssistRange, weaponDef->aimAssistRangeAds, aaGlob.adsLerp) * aim_aimAssistRangeScale.get(); + const auto screenTarget = AimAssist_GetBestTarget(&aaGlob, aimAssistRange, aaGlob.tweakables.slowdownRegionWidth, aaGlob.tweakables.slowdownRegionHeight); + + if (screenTarget) + { + *pitchScale = AimAssist_Lerp(aim_slowdown_pitch_scale.get(), aim_slowdown_pitch_scale_ads.get(), aaGlob.adsLerp); + *yawScale = AimAssist_Lerp(aim_slowdown_yaw_scale.get(), aim_slowdown_yaw_scale_ads.get(), aaGlob.adsLerp); + } + + if (AimAssist_IsPlayerUsingOffhand(&aaGlob.ps)) + *pitchScale = 1.0f; + +#endif } float Gamepad::AimAssist_Lerp(const float from, const float to, const float fraction) @@ -483,6 +654,7 @@ namespace Components AimAssist_ApplyTurnRates(input, output); Game::AimAssist_ApplyAutoMelee(input, output); + AimAssist_ApplyLockOn(input, output); } aaGlob.prevButtons = input->buttons; @@ -1451,6 +1623,17 @@ namespace Components aim_scale_view_axis = Dvar::Var("aim_scale_view_axis"); cl_bypassMouseInput = Dvar::Var("cl_bypassMouseInput"); cg_mapLocationSelectionCursorSpeed = Dvar::Var("cg_mapLocationSelectionCursorSpeed"); + aim_aimAssistRangeScale = Dvar::Var("aim_aimAssistRangeScale"); + aim_slowdown_enabled = Dvar::Var("aim_slowdown_enabled"); + aim_slowdown_debug = Dvar::Var("aim_slowdown_debug"); + aim_slowdown_pitch_scale = Dvar::Var("aim_slowdown_pitch_scale"); + aim_slowdown_pitch_scale_ads = Dvar::Var("aim_slowdown_pitch_scale_ads"); + aim_slowdown_yaw_scale = Dvar::Var("aim_slowdown_yaw_scale"); + aim_slowdown_yaw_scale_ads = Dvar::Var("aim_slowdown_yaw_scale_ads"); + aim_lockon_enabled = Dvar::Var("aim_lockon_enabled"); + aim_lockon_deflection = Dvar::Var("aim_lockon_deflection"); + aim_lockon_pitch_strength = Dvar::Var("aim_lockon_pitch_strength"); + aim_lockon_strength = Dvar::Var("aim_lockon_strength"); } void Gamepad::IN_Init_Hk() diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 6816f2d3..dbcdeb08 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -115,6 +115,43 @@ namespace Game GamepadVirtualAxisMapping virtualAxes[GPAD_VIRTAXIS_COUNT]; }; + enum weaponstate_t + { + WEAPON_READY = 0x0, + WEAPON_RAISING = 0x1, + WEAPON_RAISING_ALTSWITCH = 0x2, + WEAPON_DROPPING = 0x3, + WEAPON_DROPPING_QUICK = 0x4, + WEAPON_DROPPING_ALT = 0x5, + WEAPON_FIRING = 0x6, + WEAPON_RECHAMBERING = 0x7, + WEAPON_RELOADING = 0x8, + WEAPON_RELOADING_INTERUPT = 0x9, + WEAPON_RELOAD_START = 0xA, + WEAPON_RELOAD_START_INTERUPT = 0xB, + WEAPON_RELOAD_END = 0xC, + WEAPON_MELEE_INIT = 0xD, + WEAPON_MELEE_FIRE = 0xE, + WEAPON_MELEE_END = 0xF, + WEAPON_OFFHAND_INIT = 0x10, + WEAPON_OFFHAND_PREPARE = 0x11, + WEAPON_OFFHAND_HOLD = 0x12, + WEAPON_OFFHAND_FIRE = 0x13, + WEAPON_OFFHAND_DETONATE = 0x14, + WEAPON_OFFHAND_END = 0x15, + WEAPON_DETONATING = 0x16, + WEAPON_SPRINT_RAISE = 0x17, + WEAPON_SPRINT_LOOP = 0x18, + WEAPON_SPRINT_DROP = 0x19, + WEAPON_STUNNED_START = 0x1A, + WEAPON_STUNNED_LOOP = 0x1B, + WEAPON_STUNNED_END = 0x1C, + WEAPON_NIGHTVISION_WEAR = 0x1D, + WEAPON_NIGHTVISION_REMOVE = 0x1E, + + WEAPONSTATES_NUM + }; + struct AimAssistPlayerState { float velocity[3]; @@ -142,7 +179,8 @@ namespace Game float lockOnRegionWidth; float lockOnRegionHeight; }; - + + constexpr auto AIM_TARGET_INVALID = 0x3FF; struct AimScreenTarget { int entIndex; @@ -273,6 +311,17 @@ namespace Components static Dvar::Var aim_scale_view_axis; static Dvar::Var cl_bypassMouseInput; static Dvar::Var cg_mapLocationSelectionCursorSpeed; + static Dvar::Var aim_aimAssistRangeScale; + static Dvar::Var aim_slowdown_enabled; + static Dvar::Var aim_slowdown_debug; + static Dvar::Var aim_slowdown_pitch_scale; + static Dvar::Var aim_slowdown_pitch_scale_ads; + static Dvar::Var aim_slowdown_yaw_scale; + static Dvar::Var aim_slowdown_yaw_scale_ads; + static Dvar::Var aim_lockon_enabled; + static Dvar::Var aim_lockon_deflection; + static Dvar::Var aim_lockon_pitch_strength; + static Dvar::Var aim_lockon_strength; static Dvar::Var xpadSensitivity; static Dvar::Var xpadEarlyTime; @@ -289,7 +338,14 @@ namespace Components static void MSG_ReadDeltaUsercmdKeyStub2(); static float LinearTrack(float target, float current, float rate, float deltaTime); + static bool AimAssist_DoBoundsIntersectCenterBox(const float* clipMins, const float* clipMaxs, float clipHalfWidth, float clipHalfHeight); + static bool AimAssist_IsPlayerUsingOffhand(Game::AimAssistPlayerState* ps); + static const Game::AimScreenTarget* AimAssist_GetBestTarget(const Game::AimAssistGlobals* aaGlob, float range, float regionWidth, float regionHeight); + static const Game::AimScreenTarget* AimAssist_GetTargetFromEntity(const Game::AimAssistGlobals* aaGlob, int entIndex); + static const Game::AimScreenTarget* AimAssist_GetPrevOrBestTarget(const Game::AimAssistGlobals* aaGlob, float range, float regionWidth, float regionHeight, int prevTargetEnt); + static void AimAssist_ApplyLockOn(const Game::AimInput* input, Game::AimOutput* output); static void AimAssist_CalcAdjustedAxis(const Game::AimInput* input, float* pitchAxis, float* yawAxis); + static bool AimAssist_IsSlowdownActive(const Game::AimAssistPlayerState* ps); static void AimAssist_CalcSlowdown(const Game::AimInput* input, float* pitchScale, float* yawScale); static float AimAssist_Lerp(float from, float to, float fraction); static void AimAssist_ApplyTurnRates(const Game::AimInput* input, Game::AimOutput* output); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 6c2c35a5..c9edb167 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -30,6 +30,7 @@ namespace Game BG_GetNumWeapons_t BG_GetNumWeapons = BG_GetNumWeapons_t(0x4F5CC0); BG_GetWeaponName_t BG_GetWeaponName = BG_GetWeaponName_t(0x4E6EC0); BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = BG_LoadWeaponDef_LoadObj_t(0x57B5F0); + BG_GetWeaponDef_t BG_GetWeaponDef = BG_GetWeaponDef_t(0x440EB0); Cbuf_AddServerText_t Cbuf_AddServerText = Cbuf_AddServerText_t(0x4BB9B0); Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 0ec533a3..1f762b72 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -40,6 +40,9 @@ namespace Game typedef void*(__cdecl * BG_LoadWeaponDef_LoadObj_t)(const char* filename); extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj; + typedef WeaponDef* (__cdecl* BG_GetWeaponDef_t)(int weaponIndex); + extern BG_GetWeaponDef_t BG_GetWeaponDef; + typedef void(__cdecl * Cbuf_AddServerText_t)(); extern Cbuf_AddServerText_t Cbuf_AddServerText; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 80c293bd..7dc0736c 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1288,6 +1288,16 @@ namespace Game unsigned int playerCardNameplate; }; + enum usercmdButtonBits + { + CMD_BUTTON_ATTACK = 0x1, + CMD_BUTTON_SPRINT = 0x2, + CMD_BUTTON_MELEE = 0x4, + CMD_BUTTON_ACTIVATE = 0x8, + CMD_BUTTON_RELOAD = 0x10, + CMD_BUTTON_USE_RELOAD = 0x20, + }; + #pragma pack(push, 4) struct usercmd_s { diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index e48f1ae4..36f7d469 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -10,6 +10,7 @@ #define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS +#define _USE_MATH_DEFINES // Requires Visual Leak Detector plugin: http://vld.codeplex.com/ #define VLD_FORCE_ENABLE From e5c68247efbf4cbc4c6621347d34dacd6c4b2b82 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 25 Aug 2021 20:01:47 +0200 Subject: [PATCH 55/83] Gamepad Patch formatting --- src/Components/Modules/Gamepad.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 9c4e9613..2c29c200 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -346,12 +346,12 @@ namespace Components { const auto err = target - current; float step; - if(err <= 0.0f) + if (err <= 0.0f) step = -rate * deltaTime; else step = rate * deltaTime; - if(std::fabs(err) <= 0.001f) + if (std::fabs(err) <= 0.001f) return target; if (std::fabs(step) <= std::fabs(err)) @@ -477,7 +477,7 @@ namespace Components assert(yawAxis); const auto graphIndex = aim_input_graph_index.get(); - if(aim_input_graph_enabled.get() && graphIndex >= 0 && graphIndex < Game::VANILLA_AIM_ASSIST_GRAPH_COUNT) + if (aim_input_graph_enabled.get() && graphIndex >= 0 && graphIndex < Game::VANILLA_AIM_ASSIST_GRAPH_COUNT) { const auto deflection = std::sqrt(input->pitchAxis * input->pitchAxis + input->yawAxis * input->yawAxis); @@ -500,7 +500,7 @@ namespace Components *yawAxis = input->yawAxis; } - if(aim_scale_view_axis.get()) + if (aim_scale_view_axis.get()) { const auto absPitchAxis = std::fabs(*pitchAxis); const auto absYawAxis = std::fabs(*yawAxis); @@ -586,7 +586,7 @@ namespace Components float adjustedPitchAxis; float adjustedYawAxis; - if(aaGlob.autoMeleeState == Game::AIM_MELEE_STATE_UPDATING) + if (aaGlob.autoMeleeState == Game::AIM_MELEE_STATE_UPDATING) { adjustedPitchAxis = 0.0f; adjustedYawAxis = 0.0f; @@ -615,8 +615,8 @@ namespace Components const auto pitchDelta = std::fabs(adjustedPitchAxis) * pitchTurnRate; const auto yawDelta = std::fabs(adjustedYawAxis) * yawTurnRate; - - if(!aim_accel_turnrate_enabled.get()) + + if (!aim_accel_turnrate_enabled.get()) { aaGlob.pitchDelta = pitchDelta; aaGlob.yawDelta = yawDelta; @@ -647,7 +647,7 @@ namespace Components output->pitch = input->pitch; output->yaw = input->yaw; - if(aaGlob.initialized) + if (aaGlob.initialized) { Game::AimAssist_UpdateTweakables(input->localClientNum); Game::AimAssist_UpdateAdsLerp(input); @@ -704,7 +704,7 @@ namespace Components auto right = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_SIDE); auto magnitude = up * up + right * right; - if(magnitude > 1.0f) + if (magnitude > 1.0f) { magnitude = std::sqrt(magnitude); up /= magnitude; @@ -714,12 +714,12 @@ namespace Components Game::cgArray[0].selectedLocation[0] += right * cg_mapLocationSelectionCursorSpeed.get() * frameTime; Game::cgArray[0].selectedLocation[1] -= up * mapAspectRatio * cg_mapLocationSelectionCursorSpeed.get() * frameTime; - if(selectionRequiresAngle) + if (selectionRequiresAngle) { const auto yawUp = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_PITCH); const auto yawRight = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_YAW); - if(std::fabs(yawUp) > 0.0f || std::fabs(yawRight) > 0.0f) + if (std::fabs(yawUp) > 0.0f || std::fabs(yawRight) > 0.0f) { Game::vec2_t vec { @@ -749,7 +749,7 @@ namespace Components // Prepare args for our function call push esi // usercmd push eax // localClientNum - + call CG_HandleLocationSelectionInput test al,al @@ -837,7 +837,7 @@ namespace Components cmd->forwardmove = ClampChar(cmd->forwardmove + forwardMove); // Check for frozen controls. Flag name should start with PMF_ - if(CG_ShouldUpdateViewAngles(gamePadIndex) && (clientActive.snap.ps.pm_flags & 0x800) == 0) + if (CG_ShouldUpdateViewAngles(gamePadIndex) && (clientActive.snap.ps.pm_flags & 0x800) == 0) { Game::AimInput aimInput{}; Game::AimOutput aimOutput{}; @@ -1712,7 +1712,7 @@ namespace Components int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy) { - if(dx != 0 || dy != 0) + if (dx != 0 || dy != 0) { gamePads[0].inUse = false; gpad_in_use.setRaw(false); @@ -1784,7 +1784,7 @@ namespace Components Utils::Hook(0x43D179, CL_KeyEvent_Hk, HOOK_CALL).install()->quick(); // Mark controller as unused when mouse is moved - Utils::Hook(0x64C507, CL_MouseEvent_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x64C507, CL_MouseEvent_Hk, HOOK_CALL).install()->quick(); // Hide cursor when controller is active Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick(); From 2d81e51a05efa215dc465aa3e8d5b51e97a98e0b Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 27 Aug 2021 00:01:48 +0200 Subject: [PATCH 56/83] Fix gamepad updating stick trying to normalize zero vectors when no gamepad input is happening --- src/Components/Modules/Gamepad.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 2c29c200..6e032929 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -635,8 +635,8 @@ namespace Components aaGlob.yawDelta = LinearTrack(yawDelta, aaGlob.yawDelta, accel, input->deltaTime); } - output->pitch = aaGlob.pitchDelta * input->deltaTime * pitchSign + output->pitch; - output->yaw = aaGlob.yawDelta * input->deltaTime * yawSign + output->yaw; + output->pitch += aaGlob.pitchDelta * input->deltaTime * pitchSign; + output->yaw += aaGlob.yawDelta * input->deltaTime * yawSign; } void Gamepad::AimAssist_UpdateGamePadInput(const Game::AimInput* input, Game::AimOutput* output) @@ -1108,6 +1108,13 @@ namespace Components void Gamepad::GPad_ConvertStickToFloat(const short x, const short y, float& outX, float& outY) { + if(x == 0 && y == 0) + { + outX = 0.0f; + outY = 0.0f; + return; + } + Game::vec2_t stickVec; stickVec[0] = static_cast(x) / static_cast(std::numeric_limits::max()); stickVec[1] = static_cast(y) / static_cast(std::numeric_limits::max()); From 925eb1d0a9709e5b3c02621164412083cf2da5c1 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 30 Aug 2021 19:29:41 +0200 Subject: [PATCH 57/83] Remove unused outdated xpad dvars for gamepad --- src/Components/Modules/Gamepad.cpp | 12 ++---------- src/Components/Modules/Gamepad.hpp | 9 +-------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 6e032929..a51839f2 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -193,13 +193,6 @@ namespace Components Dvar::Var Gamepad::aim_lockon_pitch_strength; Dvar::Var Gamepad::aim_lockon_strength; - Dvar::Var Gamepad::xpadSensitivity; - Dvar::Var Gamepad::xpadEarlyTime; - Dvar::Var Gamepad::xpadEarlyMultiplier; - Dvar::Var Gamepad::xpadHorizontalMultiplier; - Dvar::Var Gamepad::xpadVerticalMultiplier; - Dvar::Var Gamepad::xpadAdsMultiplier; - struct ControllerMenuKeyMapping { Game::keyNum_t controllerKey; @@ -803,7 +796,7 @@ namespace Components return static_cast(std::clamp(value, std::numeric_limits::min(), std::numeric_limits::max())); } - void Gamepad::CL_GamepadMove(const int gamePadIndex, Game::usercmd_s* cmd, const float frame_time_base) + void Gamepad::CL_GamepadMove(const int gamePadIndex, Game::usercmd_s* cmd, const float frameTimeBase) { assert(gamePadIndex < Game::MAX_GAMEPADS); auto& gamePad = gamePads[gamePadIndex]; @@ -841,7 +834,7 @@ namespace Components { Game::AimInput aimInput{}; Game::AimOutput aimOutput{}; - aimInput.deltaTime = frame_time_base; + aimInput.deltaTime = frameTimeBase; aimInput.buttons = cmd->buttons; aimInput.localClientNum = gamePadIndex; aimInput.deltaTimeScaled = static_cast(Game::cls->frametime) * 0.001f; @@ -862,7 +855,6 @@ namespace Components } constexpr auto CL_MouseMove = 0x5A6240; - __declspec(naked) void Gamepad::CL_MouseMove_Stub() { __asm diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index dbcdeb08..75c7a099 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -323,13 +323,6 @@ namespace Components static Dvar::Var aim_lockon_pitch_strength; static Dvar::Var aim_lockon_strength; - static Dvar::Var xpadSensitivity; - static Dvar::Var xpadEarlyTime; - static Dvar::Var xpadEarlyMultiplier; - static Dvar::Var xpadHorizontalMultiplier; - static Dvar::Var xpadVerticalMultiplier; - static Dvar::Var xpadAdsMultiplier; - static void MSG_WriteDeltaUsercmdKeyStub(); static void ApplyMovement(Game::msg_t* msg, int key, Game::usercmd_s* from, Game::usercmd_s* to); @@ -358,7 +351,7 @@ namespace Components static bool CG_ShouldUpdateViewAngles(int localClientNum); static float CL_GamepadAxisValue(int gamePadIndex, Game::GamepadVirtualAxis virtualAxis); static char ClampChar(int value); - static void CL_GamepadMove(int gamePadIndex, Game::usercmd_s* cmd, float frame_time_base); + static void CL_GamepadMove(int gamePadIndex, Game::usercmd_s* cmd, float frameTimeBase); static void CL_MouseMove_Stub(); static bool Key_IsValidGamePadChar(int key); From aa3c6d79c6b70c873e4e8c2db713fe43fc6c1de4 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 30 Aug 2021 19:30:06 +0200 Subject: [PATCH 58/83] Implement holding use button for activating for controllers --- src/Components/Modules/Gamepad.cpp | 44 ++++++++++++++++++++++++++++++ src/Components/Modules/Gamepad.hpp | 4 +++ 2 files changed, 48 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index a51839f2..df3b12cc 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -138,6 +138,7 @@ namespace Game keyname_t combinedLocalizedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); + kbutton_t* playersKb = reinterpret_cast(0xA1A9A8); AimAssistGlobals* aaGlobArray = reinterpret_cast(0x7A2110); keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); keyname_t* vanillaLocalizedKeyNames = reinterpret_cast(0x798880); @@ -168,6 +169,7 @@ namespace Components Dvar::Var Gamepad::gpad_button_deadzone; Dvar::Var Gamepad::gpad_button_rstick_deflect_max; Dvar::Var Gamepad::gpad_button_lstick_deflect_max; + Dvar::Var Gamepad::gpad_use_hold_time; Dvar::Var Gamepad::input_viewSensitivity; Dvar::Var Gamepad::input_invertPitch; Dvar::Var Gamepad::aim_turnrate_pitch; @@ -876,6 +878,44 @@ namespace Components } } + bool Gamepad::Gamepad_ShouldUse(const unsigned useTime) + { + // Only apply hold time to +usereload keybind + return !Game::playersKb[Game::KB_USE_RELOAD].active || useTime >= static_cast(gpad_use_hold_time.get()); + } + + __declspec(naked) void Gamepad::Player_UseEntity_Stub() + { + __asm + { + // Execute overwritten instructions + cmp eax, [ecx + 0x10] + jl skipUse + + // Call our custom check + push eax + pushad + push eax + call Gamepad_ShouldUse + add esp,4 + mov [esp + 0x20],eax + popad + pop eax + + // Skip use if custom check returns false + test al,al + jz skipUse + + // perform use + push 0x5FE39B + ret + + skipUse: + push 0x5FE3AF + ret + } + } + bool Gamepad::Key_IsValidGamePadChar(const int key) { return key >= Game::K_FIRSTGAMEPADBUTTON_RANGE_1 && key <= Game::K_LASTGAMEPADBUTTON_RANGE_1 @@ -1608,6 +1648,7 @@ namespace Components gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, 0, "Game pad button deadzone threshhold"); gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); + gpad_use_hold_time = Dvar::Register("gpad_use_hold_time", 250, 0, INT32_MAX, 0, "Time to hold the 'use' button on gamepads to activate use"); input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); input_invertPitch = Dvar::Register("input_invertPitch", false, Game::DVAR_FLAG_SAVED, "Invert gamepad pitch"); @@ -1791,6 +1832,9 @@ namespace Components // Only return gamepad keys when gamepad enabled and only non gamepad keys when not Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); + // Add hold time to gamepad usereload on hold prompts + Utils::Hook(0x5FE396, Player_UseEntity_Stub, HOOK_JUMP).install()->quick(); + // Add gamepad inputs to remote control (eg predator) handling Utils::Hook(0x5A6D4E, CL_RemoteControlMove_Stub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 75c7a099..d0e20d82 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -298,6 +298,7 @@ namespace Components static Dvar::Var gpad_button_deadzone; static Dvar::Var gpad_button_rstick_deflect_max; static Dvar::Var gpad_button_lstick_deflect_max; + static Dvar::Var gpad_use_hold_time; static Dvar::Var input_viewSensitivity; static Dvar::Var input_invertPitch; static Dvar::Var aim_turnrate_pitch; @@ -353,6 +354,9 @@ namespace Components static char ClampChar(int value); static void CL_GamepadMove(int gamePadIndex, Game::usercmd_s* cmd, float frameTimeBase); static void CL_MouseMove_Stub(); + + static bool Gamepad_ShouldUse(unsigned useTime); + static void Player_UseEntity_Stub(); static bool Key_IsValidGamePadChar(int key); static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); From a07a00da936d4d4a1e320fe9772d440a221f3b8f Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 30 Aug 2021 20:05:06 +0200 Subject: [PATCH 59/83] Fix gamepad use hold time by checking for used buttons from gentity instead of local player keys to work on dedicated servers --- src/Components/Modules/Gamepad.cpp | 7 ++++--- src/Components/Modules/Gamepad.hpp | 2 +- src/Game/Structs.hpp | 8 +++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index df3b12cc..c7679725 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -878,10 +878,10 @@ namespace Components } } - bool Gamepad::Gamepad_ShouldUse(const unsigned useTime) + bool Gamepad::Gamepad_ShouldUse(const Game::gentity_s* playerEnt, const unsigned useTime) { // Only apply hold time to +usereload keybind - return !Game::playersKb[Game::KB_USE_RELOAD].active || useTime >= static_cast(gpad_use_hold_time.get()); + return !(playerEnt->client->buttons & Game::CMD_BUTTON_USE_RELOAD) || useTime >= static_cast(gpad_use_hold_time.get()); } __declspec(naked) void Gamepad::Player_UseEntity_Stub() @@ -896,8 +896,9 @@ namespace Components push eax pushad push eax + push edi call Gamepad_ShouldUse - add esp,4 + add esp,8 mov [esp + 0x20],eax popad pop eax diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index d0e20d82..522afe33 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -355,7 +355,7 @@ namespace Components static void CL_GamepadMove(int gamePadIndex, Game::usercmd_s* cmd, float frameTimeBase); static void CL_MouseMove_Stub(); - static bool Gamepad_ShouldUse(unsigned useTime); + static bool Gamepad_ShouldUse(const Game::gentity_s* playerEnt, unsigned useTime); static void Player_UseEntity_Stub(); static bool Key_IsValidGamePadChar(int key); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 7dc0736c..b4d31f06 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -5262,7 +5262,13 @@ namespace Game unsigned int team; char pad2[436]; int flags; - char pad3[724]; + int spectatorClient; + int lastCmdTime; + int buttons; + int oldbuttons; + int latched_buttons; + int buttonsSinceLastFrame; + char pad3[700]; } gclient_t; struct EntHandle From 8b53ce4cfe9ce8468494497f2abfabd0ea04f191 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 30 Aug 2021 21:57:31 +0200 Subject: [PATCH 60/83] Swap gamepad attack and throw button on dualwield weapons to make left trigger match left weapon etc --- src/Components/Modules/Gamepad.cpp | 15 +++++++++++++++ src/Game/Structs.hpp | 9 +++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index c7679725..4e4adecb 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -831,6 +831,21 @@ namespace Components cmd->rightmove = ClampChar(cmd->rightmove + rightMove); cmd->forwardmove = ClampChar(cmd->forwardmove + forwardMove); + // Swap attack and throw buttons when using controller and akimbo to match "left trigger"="left weapon" and "right trigger"="right weapon" + if(gamePad.inUse && clientActive.snap.ps.weapCommon.lastWeaponHand == Game::WEAPON_HAND_LEFT) + { + auto oldButtons = cmd->buttons; + if (oldButtons & Game::CMD_BUTTON_ATTACK) + cmd->buttons |= Game::CMD_BUTTON_THROW; + else + cmd->buttons &= ~Game::CMD_BUTTON_THROW; + + if (oldButtons & Game::CMD_BUTTON_THROW) + cmd->buttons |= Game::CMD_BUTTON_ATTACK; + else + cmd->buttons &= ~Game::CMD_BUTTON_ATTACK; + } + // Check for frozen controls. Flag name should start with PMF_ if (CG_ShouldUpdateViewAngles(gamePadIndex) && (clientActive.snap.ps.pm_flags & 0x800) == 0) { diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index b4d31f06..18710994 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1296,6 +1296,15 @@ namespace Game CMD_BUTTON_ACTIVATE = 0x8, CMD_BUTTON_RELOAD = 0x10, CMD_BUTTON_USE_RELOAD = 0x20, + CMD_BUTTON_PRONE = 0x100, + CMD_BUTTON_CROUCH = 0x200, + CMD_BUTTON_UP = 0x400, + CMD_BUTTON_ADS = 0x800, + CMD_BUTTON_DOWN = 0x1000, + CMD_BUTTON_BREATH = 0x2000, + CMD_BUTTON_FRAG = 0x4000, + CMD_BUTTON_OFFHAND_SECONDARY = 0x8000, + CMD_BUTTON_THROW = 0x80000, }; #pragma pack(push, 4) From 9a9d2cd0586d1e959e56287d329bf7ac91b955eb Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 31 Aug 2021 18:12:53 +0200 Subject: [PATCH 61/83] Fix disabling gamepad not blocking all gamepad inputs --- src/Components/Modules/Gamepad.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 4e4adecb..3bab8d8a 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1418,6 +1418,9 @@ namespace Components void Gamepad::IN_GamePadsMove() { + if (!gpad_enabled.get()) + return; + GPad_UpdateAll(); const auto time = Game::Sys_Milliseconds(); From abc44e689732eb0f8288aea8dab2a259cf27f533 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 31 Aug 2021 18:13:06 +0200 Subject: [PATCH 62/83] Update gamepad dvar defaults --- src/Components/Modules/Gamepad.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 3bab8d8a..d7419a0d 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1653,8 +1653,8 @@ namespace Components gpad_debug = Dvar::Register("gpad_debug", false, 0, "Game pad debugging"); gpad_present = Dvar::Register("gpad_present", false, 0, "Game pad present"); gpad_in_use = Dvar::Register("gpad_in_use", false, 0, "A game pad is in use"); - gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "thumbstick_default", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); - gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "buttons_default", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); + gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); + gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); gpad_menu_scroll_delay_first = Dvar::Register("gpad_menu_scroll_delay_first", 420, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for the first repeat, in milliseconds"); gpad_menu_scroll_delay_rest = Dvar::Register("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for repeats after the first, in milliseconds"); From f8dd3f2b3a91ef4b59bdf02e5d59d84de9e319c9 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 31 Aug 2021 18:13:15 +0200 Subject: [PATCH 63/83] Add gamepad options menu --- src/Components/Modules/Menus.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index d18c8b9c..6d4fa7c4 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -897,6 +897,7 @@ namespace Components Menus::Add("ui_mp/theater_menu.menu"); Menus::Add("ui_mp/pc_options_multi.menu"); Menus::Add("ui_mp/pc_options_game.menu"); + Menus::Add("ui_mp/pc_options_gamepad.menu"); Menus::Add("ui_mp/stats_reset.menu"); Menus::Add("ui_mp/stats_unlock.menu"); Menus::Add("ui_mp/security_increase_popmenu.menu"); From f364e4db66d6556d63cf97a8025f0699db00b13d Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 1 Sep 2021 16:49:51 +0200 Subject: [PATCH 64/83] Fix gamepad Key_GetCommandAssignmentInternal returning wrong key count when a command is bound to 2 keys --- src/Components/Modules/Gamepad.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index d7419a0d..d3182fe5 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1730,7 +1730,7 @@ namespace Components (*keys)[keyCount++] = keyNum; if (keyCount >= 2) - return keyNum; + return keyCount; } } } @@ -1746,7 +1746,7 @@ namespace Components (*keys)[keyCount++] = keyNum; if (keyCount >= 2) - return keyNum; + return keyCount; } } } From 7a64545f92a6d7a9a19133035b6e47ca4ae37be6 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 1 Sep 2021 18:12:44 +0200 Subject: [PATCH 65/83] Add sv_allowAimAssist dvar to be able to disable aim assist server side --- src/Components/Modules/Gamepad.cpp | 8 +++++--- src/Components/Modules/Gamepad.hpp | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index d3182fe5..7eb6ffda 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -172,6 +172,7 @@ namespace Components Dvar::Var Gamepad::gpad_use_hold_time; Dvar::Var Gamepad::input_viewSensitivity; Dvar::Var Gamepad::input_invertPitch; + Dvar::Var Gamepad::sv_allowAimAssist; Dvar::Var Gamepad::aim_turnrate_pitch; Dvar::Var Gamepad::aim_turnrate_pitch_ads; Dvar::Var Gamepad::aim_turnrate_yaw; @@ -1671,6 +1672,7 @@ namespace Components input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); input_invertPitch = Dvar::Register("input_invertPitch", false, Game::DVAR_FLAG_SAVED, "Invert gamepad pitch"); + sv_allowAimAssist = Dvar::Register("sv_allowAimAssist", true, 0, "Controls whether aim assist features on clients are enabled"); aim_turnrate_pitch = Dvar::Var("aim_turnrate_pitch"); aim_turnrate_pitch_ads = Dvar::Var("aim_turnrate_pitch_ads"); aim_turnrate_yaw = Dvar::Var("aim_turnrate_yaw"); @@ -1808,6 +1810,9 @@ namespace Components if (ZoneBuilder::IsEnabled()) return; + // Initialize gamepad environment + Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); + // package the forward and right move components in the move buttons Utils::Hook(0x60E38D, MSG_WriteDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); @@ -1833,9 +1838,6 @@ namespace Components if (Dedicated::IsEnabled()) return; - // Initialize gamepad environment - Utils::Hook(0x467C03, IN_Init_Hk, HOOK_CALL).install()->quick(); - // Gamepad on frame hook Utils::Hook(0x475E9E, IN_Frame_Hk, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 522afe33..51421410 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -301,6 +301,7 @@ namespace Components static Dvar::Var gpad_use_hold_time; static Dvar::Var input_viewSensitivity; static Dvar::Var input_invertPitch; + static Dvar::Var sv_allowAimAssist; static Dvar::Var aim_turnrate_pitch; static Dvar::Var aim_turnrate_pitch_ads; static Dvar::Var aim_turnrate_yaw; From 67bfad3ae7fc2342fb2e54a370a348b066100cae Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 1 Sep 2021 18:32:12 +0200 Subject: [PATCH 66/83] Add non cheat protected dvars to disable gamepad lockon and slowdown aim assists additionally to the cheat protected ones --- src/Components/Modules/Gamepad.cpp | 25 +++++++++++++++++++++++-- src/Components/Modules/Gamepad.hpp | 3 +++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 7eb6ffda..d5e91e97 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -170,6 +170,8 @@ namespace Components Dvar::Var Gamepad::gpad_button_rstick_deflect_max; Dvar::Var Gamepad::gpad_button_lstick_deflect_max; Dvar::Var Gamepad::gpad_use_hold_time; + Dvar::Var Gamepad::gpad_lockon_enabled; + Dvar::Var Gamepad::gpad_slowdown_enabled; Dvar::Var Gamepad::input_viewSensitivity; Dvar::Var Gamepad::input_invertPitch; Dvar::Var Gamepad::sv_allowAimAssist; @@ -416,6 +418,23 @@ namespace Components return AimAssist_GetBestTarget(aaGlob, range, regionWidth, regionHeight); } + bool Gamepad::AimAssist_IsLockonActive(const int gamePadIndex) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& aaGlob = Game::aaGlobArray[gamePadIndex]; + + if (!aim_lockon_enabled.get() || !gpad_lockon_enabled.get()) + return false; + + if (AimAssist_IsPlayerUsingOffhand(&aaGlob.ps)) + return false; + + if (aaGlob.autoAimActive || aaGlob.autoMeleeState == Game::AIM_MELEE_STATE_UPDATING) + return false; + + return true; + } + void Gamepad::AimAssist_ApplyLockOn(const Game::AimInput* input, Game::AimOutput* output) { #ifdef AIM_ASSIST_ENABLED @@ -427,7 +446,7 @@ namespace Components const auto prevTargetEnt = aaGlob.lockOnTargetEnt; aaGlob.lockOnTargetEnt = Game::AIM_TARGET_INVALID; - if (!aim_lockon_enabled.get() || AimAssist_IsPlayerUsingOffhand(&aaGlob.ps) || aaGlob.autoAimActive || aaGlob.autoMeleeState == Game::AIM_MELEE_STATE_UPDATING) + if (!AimAssist_IsLockonActive(input->localClientNum)) return; const auto* weaponDef = Game::BG_GetWeaponDef(aaGlob.ps.weapIndex); @@ -510,7 +529,7 @@ namespace Components bool Gamepad::AimAssist_IsSlowdownActive(const Game::AimAssistPlayerState* ps) { - if (!aim_slowdown_enabled.get()) + if (!aim_slowdown_enabled.get() || !gpad_slowdown_enabled.get()) return false; if (!ps->weapIndex) @@ -1669,6 +1688,8 @@ namespace Components gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); gpad_use_hold_time = Dvar::Register("gpad_use_hold_time", 250, 0, INT32_MAX, 0, "Time to hold the 'use' button on gamepads to activate use"); + gpad_lockon_enabled = Dvar::Register("gpad_lockon_enabled", true, Game::DVAR_FLAG_SAVED, "Game pad lockon aim assist enabled"); + gpad_slowdown_enabled = Dvar::Register("gpad_slowdown_enabled", true, Game::DVAR_FLAG_SAVED, "Game pad slowdown aim assist enabled"); input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); input_invertPitch = Dvar::Register("input_invertPitch", false, Game::DVAR_FLAG_SAVED, "Invert gamepad pitch"); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 51421410..21106886 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -299,6 +299,8 @@ namespace Components static Dvar::Var gpad_button_rstick_deflect_max; static Dvar::Var gpad_button_lstick_deflect_max; static Dvar::Var gpad_use_hold_time; + static Dvar::Var gpad_lockon_enabled; + static Dvar::Var gpad_slowdown_enabled; static Dvar::Var input_viewSensitivity; static Dvar::Var input_invertPitch; static Dvar::Var sv_allowAimAssist; @@ -338,6 +340,7 @@ namespace Components static const Game::AimScreenTarget* AimAssist_GetBestTarget(const Game::AimAssistGlobals* aaGlob, float range, float regionWidth, float regionHeight); static const Game::AimScreenTarget* AimAssist_GetTargetFromEntity(const Game::AimAssistGlobals* aaGlob, int entIndex); static const Game::AimScreenTarget* AimAssist_GetPrevOrBestTarget(const Game::AimAssistGlobals* aaGlob, float range, float regionWidth, float regionHeight, int prevTargetEnt); + static bool AimAssist_IsLockonActive(int gamePadIndex); static void AimAssist_ApplyLockOn(const Game::AimInput* input, Game::AimOutput* output); static void AimAssist_CalcAdjustedAxis(const Game::AimInput* input, float* pitchAxis, float* yawAxis); static bool AimAssist_IsSlowdownActive(const Game::AimAssistPlayerState* ps); From 7e9f277ae909d42443d4b2df8e8d1b36570c509b Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 1 Sep 2021 18:36:03 +0200 Subject: [PATCH 67/83] Remove aim assist premake configuration value again in favor of being able to disable aim assist using the server dvar --- premake5.lua | 8 -------- src/Components/Modules/Gamepad.cpp | 10 +--------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/premake5.lua b/premake5.lua index 20744831..91bee2df 100644 --- a/premake5.lua +++ b/premake5.lua @@ -79,11 +79,6 @@ newoption { description = "Zonebuilder generates iw4x zones that cannot be loaded without IW4x specific patches." } -newoption { - trigger = "aimassist-enable", - description = "Enables code for controller aim assist." -} - newaction { trigger = "version", description = "Returns the version string for the current commit of the source code.", @@ -337,9 +332,6 @@ workspace "iw4x" if _OPTIONS["iw4x-zones"] then defines { "GENERATE_IW4X_SPECIFIC_ZONES" } end - if _OPTIONS["aimassist-enable"] then - defines { "AIM_ASSIST_ENABLED" } - end -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index d5e91e97..990a18fc 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -437,8 +437,6 @@ namespace Components void Gamepad::AimAssist_ApplyLockOn(const Game::AimInput* input, Game::AimOutput* output) { -#ifdef AIM_ASSIST_ENABLED - assert(input); assert(input->localClientNum < Game::MAX_GAMEPADS); auto& aaGlob = Game::aaGlobArray[input->localClientNum]; @@ -481,8 +479,6 @@ namespace Components output->pitch -= pitchTurnRate * input->deltaTime; output->yaw += yawTurnRate * input->deltaTime; } - -#endif } void Gamepad::AimAssist_CalcAdjustedAxis(const Game::AimInput* input, float* pitchAxis, float* yawAxis) @@ -564,9 +560,7 @@ namespace Components *pitchScale = 1.0f; *yawScale = 1.0f; - -#ifdef AIM_ASSIST_ENABLED - + if (!AimAssist_IsSlowdownActive(&aaGlob.ps)) return; @@ -582,8 +576,6 @@ namespace Components if (AimAssist_IsPlayerUsingOffhand(&aaGlob.ps)) *pitchScale = 1.0f; - -#endif } float Gamepad::AimAssist_Lerp(const float from, const float to, const float fraction) From ac57df648e4d2af00f92078671dd2982d78e9486 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 4 Sep 2021 11:15:14 +0200 Subject: [PATCH 68/83] Make gamepad predator missiles also controllable with right stick --- src/Components/Modules/Gamepad.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 990a18fc..424a781e 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -673,11 +673,15 @@ namespace Components const auto up = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_FORWARD); const auto right = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_SIDE); + const auto yaw = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_YAW); + const auto pitch = CL_GamepadAxisValue(localClientNum, Game::GPAD_VIRTAXIS_PITCH); const auto sensitivity = input_viewSensitivity.get(); constexpr auto scale = static_cast(std::numeric_limits::max()); - cmd->remoteControlAngles[0] = ClampChar(cmd->remoteControlAngles[0] + static_cast(std::floor(-up * scale * sensitivity))); - cmd->remoteControlAngles[1] = ClampChar(cmd->remoteControlAngles[1] + static_cast(std::floor(-right * scale * sensitivity))); + cmd->remoteControlAngles[0] = ClampChar(cmd->remoteControlAngles[0] + static_cast(std::floor(-up * scale * sensitivity)) + + static_cast(std::floor(-pitch * scale * sensitivity))); + cmd->remoteControlAngles[1] = ClampChar(cmd->remoteControlAngles[1] + static_cast(std::floor(-right * scale * sensitivity)) + + static_cast(std::floor(-yaw * scale * sensitivity))); } constexpr auto CL_RemoteControlMove = 0x5A6BA0; From cb2e24a52f38189d6564634f6f383e6ba1be75b0 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 4 Sep 2021 11:15:34 +0200 Subject: [PATCH 69/83] Make gamepad scoreboard toggable and scrollable --- src/Components/Modules/Gamepad.cpp | 45 ++++++++++++++++++++++++++++++ src/Components/Modules/Gamepad.hpp | 2 ++ src/Game/Functions.cpp | 4 +++ src/Game/Functions.hpp | 12 ++++++++ src/Game/Structs.hpp | 13 +++++---- 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 424a781e..49d3b70d 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1042,6 +1042,32 @@ namespace Components // Game::UI_KeyEvent(gamePadIndex, key, down); } + bool Gamepad::Scoreboard_HandleInput(int gamePadIndex, int key) + { + assert(gamePadIndex < Game::MAX_GAMEPADS); + auto& keyState = Game::playerKeys[gamePadIndex]; + + if (keyState.keys[key].binding && strcmp(keyState.keys[key].binding, "togglescores") == 0) + { + Game::Cbuf_AddText(gamePadIndex, "togglescores\n"); + return true; + } + + switch (key) + { + case Game::K_DPAD_UP: + Game::CG_ScrollScoreboardUp(Game::cgArray); + return true; + + case Game::K_DPAD_DOWN: + Game::CG_ScrollScoreboardDown(Game::cgArray); + return true; + + default: + return false; + } + } + bool Gamepad::CL_CheckForIgnoreDueToRepeat(const int gamePadIndex, const int key, const int repeatCount, const unsigned time) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -1113,6 +1139,13 @@ namespace Components return; } + const auto activeMenu = Game::UI_GetActiveMenu(gamePadIndex); + if(activeMenu == Game::UIMENU_SCOREBOARD) + { + if (buttonEvent == Game::GPAD_BUTTON_PRESSED && Scoreboard_HandleInput(gamePadIndex, key)) + return; + } + keyState.locSelInputState = Game::LOC_SEL_INPUT_NONE; const auto* keyBinding = keyState.keys[key].binding; @@ -1663,6 +1696,17 @@ namespace Components Game::Cbuf_AddText(0, Utils::String::VA("exec %s\n", buttonConfigName)); } + void Gamepad::Scores_Toggle_f(Command::Params*) + { + if(Game::cgArray[0].nextSnap) + { + if (Game::UI_GetActiveMenu(0) != Game::UIMENU_SCOREBOARD) + Game::CG_ScoresDown_f(); + else + Game::CG_ScoresUp_f(); + } + } + void Gamepad::InitDvars() { gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); @@ -1851,6 +1895,7 @@ namespace Components Command::Add("unbindallaxis", Axis_Unbindall_f); Command::Add("bindgpsticksconfigs", Bind_GP_SticksConfigs_f); Command::Add("bindgpbuttonsconfigs", Bind_GP_ButtonsConfigs_f); + Command::Add("togglescores", Scores_Toggle_f); if (Dedicated::IsEnabled()) return; diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 21106886..09488a78 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -364,6 +364,7 @@ namespace Components static bool Key_IsValidGamePadChar(int key); static void CL_GamepadResetMenuScrollTime(int gamePadIndex, int key, bool down, unsigned int time); + static bool Scoreboard_HandleInput(int gamePadIndex, int key); static bool CL_CheckForIgnoreDueToRepeat(int gamePadIndex, int key, int repeatCount, unsigned int time); static void UI_GamepadKeyEvent(int gamePadIndex, int key, bool down); static void CL_GamepadGenerateAPad(int gamePadIndex, Game::GamepadPhysicalAxis physicalAxis, unsigned time); @@ -401,6 +402,7 @@ namespace Components static void Axis_Unbindall_f(Command::Params* params); static void Bind_GP_SticksConfigs_f(Command::Params* params); static void Bind_GP_ButtonsConfigs_f(Command::Params* params); + static void Scores_Toggle_f(Command::Params* params); static void InitDvars(); static void IN_Init_Hk(); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index c9edb167..1ac39bc9 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -39,6 +39,10 @@ namespace Game CG_GetClientNum_t CG_GetClientNum = CG_GetClientNum_t(0x433700); CG_PlayBoltedEffect_t CG_PlayBoltedEffect = CG_PlayBoltedEffect_t(0x00430E10); CG_GetBoneIndex_t CG_GetBoneIndex = CG_GetBoneIndex_t(0x00504F20); + CG_ScoresDown_f_t CG_ScoresDown_f = CG_ScoresDown_f_t(0x580370); + CG_ScoresUp_f_t CG_ScoresUp_f = CG_ScoresUp_f_t(0x5802C0); + CG_ScrollScoreboardUp_t CG_ScrollScoreboardUp = CG_ScrollScoreboardUp_t(0x47A5C0); + CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown = CG_ScrollScoreboardDown_t(0x493B50); CL_GetClientName_t CL_GetClientName = CL_GetClientName_t(0x4563D0); CL_IsCgameInitialized_t CL_IsCgameInitialized = CL_IsCgameInitialized_t(0x43EB20); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 1f762b72..6e97fc7c 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -60,6 +60,18 @@ namespace Game typedef std::int32_t(__cdecl* CG_GetBoneIndex_t)(std::int32_t, std::uint32_t name, char* index); extern CG_GetBoneIndex_t CG_GetBoneIndex; + + typedef void(__cdecl * CG_ScoresDown_f_t)(); + extern CG_ScoresDown_f_t CG_ScoresDown_f; + + typedef void(__cdecl * CG_ScoresUp_f_t)(); + extern CG_ScoresUp_f_t CG_ScoresUp_f; + + typedef void(__cdecl * CG_ScrollScoreboardUp_t)(cg_s* cgameGlob); + extern CG_ScrollScoreboardUp_t CG_ScrollScoreboardUp; + + typedef void(__cdecl * CG_ScrollScoreboardDown_t)(cg_s* cgameGlob); + extern CG_ScrollScoreboardDown_t CG_ScrollScoreboardDown; typedef char*(__cdecl * CL_GetClientName_t)(int localClientNum, int index, char *buf, size_t size); extern CL_GetClientName_t CL_GetClientName; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 18710994..a73b370d 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -6169,21 +6169,22 @@ namespace Game struct __declspec(align(8)) cg_s { playerState_s predictedPlayerState; - char _pad0[0x67638]; + char _pad0[0x254]; + void* snap; + void* nextSnap; + char _pad1[0x673DC]; int frametime; // + 0x6A754 - char _pad1[0x960C]; // + 0x6A758 + char _pad2[0x960C]; // + 0x6A758 float compassMapWorldSize[2]; // + 0x73D64 - char _pad2[0x74]; // + 0x73D6C + char _pad3[0x74]; // + 0x73D6C float selectedLocation[2]; // + 0x73DE0 float selectedLocationAngle; float selectedAngleLocation[2]; float selectedLocationPrev[2]; float selectedLocationAnglePrev; - char _pad3[0x89740]; + char _pad4[0x89740]; }; - constexpr auto aaaaaaa1 = sizeof(cg_s); - #pragma endregion #ifndef IDA From 337b3961c4555ef621cd953510bd40e204abd218 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Thu, 9 Sep 2021 10:44:04 +0200 Subject: [PATCH 70/83] Fixed indent --- src/Components/Modules/Dvar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index 27effcb3..f1b8535a 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -116,7 +116,6 @@ namespace Components } } - void Dvar::Var::set(float value) { assert(this->dvar->type == Game::DVAR_TYPE_FLOAT); @@ -131,7 +130,7 @@ namespace Components assert(this->dvar->type == Game::DVAR_TYPE_BOOL); if (this->dvar) { - Game::Dvar_SetBool(this->dvar, enabled); + Game::Dvar_SetBool(this->dvar, enabled); } } From 7de4b0a3aa040a4362b0c2da40e52ec3be3eb09d Mon Sep 17 00:00:00 2001 From: Diavolo Date: Thu, 9 Sep 2021 10:50:49 +0200 Subject: [PATCH 71/83] Tab again X-( --- src/Components/Modules/Dvar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index f1b8535a..ad28175c 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -115,7 +115,7 @@ namespace Components Game::Dvar_SetInt(this->dvar, integer); } } - + void Dvar::Var::set(float value) { assert(this->dvar->type == Game::DVAR_TYPE_FLOAT); From 27c8a647dfac706ce91a2fff14aacb4fa3ec8b22 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Thu, 9 Sep 2021 11:36:48 +0200 Subject: [PATCH 72/83] Random tab i spotted --- src/Game/Structs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 84a1b091..3ca16df9 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -233,7 +233,7 @@ namespace Game K_LASTGAMEPADBUTTON_RANGE_1 = 0x6, // Last Gamepad 1 K_TAB = 0x9, K_ENTER = 0xD, - K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, // First Gamepad 2 + K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, // First Gamepad 2 K_BUTTON_START = 0xE, K_BUTTON_BACK = 0xF, K_BUTTON_LSTICK = 0x10, From 906e33ac41790b0d2fbb4f6f0110f2914698e220 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Thu, 9 Sep 2021 11:36:48 +0200 Subject: [PATCH 73/83] Some minor style changes --- src/Components/Modules/Gamepad.cpp | 30 +++++++++++++++--------------- src/Game/Functions.cpp | 2 ++ src/Game/Functions.hpp | 28 ++++++++++++++-------------- src/Game/Structs.hpp | 2 +- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 49d3b70d..8471d2d8 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -929,13 +929,13 @@ namespace Components push eax push edi call Gamepad_ShouldUse - add esp,8 - mov [esp + 0x20],eax + add esp, 8h + mov [esp + 0x20], eax popad pop eax // Skip use if custom check returns false - test al,al + test al, al jz skipUse // perform use @@ -1710,30 +1710,30 @@ namespace Components void Gamepad::InitDvars() { gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); - gpad_debug = Dvar::Register("gpad_debug", false, 0, "Game pad debugging"); - gpad_present = Dvar::Register("gpad_present", false, 0, "Game pad present"); - gpad_in_use = Dvar::Register("gpad_in_use", false, 0, "A game pad is in use"); + gpad_debug = Dvar::Register("gpad_debug", false, Game::DVAR_FLAG_NONE, "Game pad debugging"); + gpad_present = Dvar::Register("gpad_present", false, Game::DVAR_FLAG_NONE, "Game pad present"); + gpad_in_use = Dvar::Register("gpad_in_use", false, Game::DVAR_FLAG_NONE, "A game pad is in use"); gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "", Game::DVAR_FLAG_SAVED, "Game pad stick configuration"); gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "", Game::DVAR_FLAG_SAVED, "Game pad button configuration"); gpad_menu_scroll_delay_first = Dvar::Register("gpad_menu_scroll_delay_first", 420, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for the first repeat, in milliseconds"); gpad_menu_scroll_delay_rest = Dvar::Register("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_FLAG_SAVED, "Menu scroll key-repeat delay, for repeats after the first, in milliseconds"); gpad_rumble = Dvar::Register("gpad_rumble", true, Game::DVAR_FLAG_SAVED, "Enable game pad rumble"); - gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, 0, + gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_FLAG_NONE, "Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing"); - gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, 0, "Game pad stick pressed threshhold"); - gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, 0, "Game pad maximum stick deadzone"); - gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, 0, "Game pad minimum stick deadzone"); - gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, 0, "Game pad button deadzone threshhold"); - gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); - gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, 0, "Game pad maximum pad stick pressed value"); - gpad_use_hold_time = Dvar::Register("gpad_use_hold_time", 250, 0, INT32_MAX, 0, "Time to hold the 'use' button on gamepads to activate use"); + gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_FLAG_NONE, "Game pad stick pressed threshhold"); + gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_FLAG_NONE, "Game pad maximum stick deadzone"); + gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_FLAG_NONE, "Game pad minimum stick deadzone"); + gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_FLAG_NONE, "Game pad button deadzone threshhold"); + gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_FLAG_NONE, "Game pad maximum pad stick pressed value"); + gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_FLAG_NONE, "Game pad maximum pad stick pressed value"); + gpad_use_hold_time = Dvar::Register("gpad_use_hold_time", 250, 0, INT32_MAX, Game::DVAR_FLAG_NONE, "Time to hold the 'use' button on gamepads to activate use"); gpad_lockon_enabled = Dvar::Register("gpad_lockon_enabled", true, Game::DVAR_FLAG_SAVED, "Game pad lockon aim assist enabled"); gpad_slowdown_enabled = Dvar::Register("gpad_slowdown_enabled", true, Game::DVAR_FLAG_SAVED, "Game pad slowdown aim assist enabled"); input_viewSensitivity = Dvar::Register("input_viewSensitivity", 1.0f, 0.0001f, 5.0f, Game::DVAR_FLAG_SAVED, "View Sensitivity"); input_invertPitch = Dvar::Register("input_invertPitch", false, Game::DVAR_FLAG_SAVED, "Invert gamepad pitch"); - sv_allowAimAssist = Dvar::Register("sv_allowAimAssist", true, 0, "Controls whether aim assist features on clients are enabled"); + sv_allowAimAssist = Dvar::Register("sv_allowAimAssist", true, Game::DVAR_FLAG_NONE, "Controls whether aim assist features on clients are enabled"); aim_turnrate_pitch = Dvar::Var("aim_turnrate_pitch"); aim_turnrate_pitch_ads = Dvar::Var("aim_turnrate_pitch_ads"); aim_turnrate_yaw = Dvar::Var("aim_turnrate_yaw"); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index bc30cf8e..d581de63 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -739,9 +739,11 @@ namespace Game float Vec3Normalize(vec3_t& vec) { const float length = static_cast(std::sqrt(std::pow(vec[0], 2) + std::pow(vec[1], 2) + std::pow(vec[2], 2))); + vec[0] /= length; vec[1] /= length; vec[2] /= length; + return length; } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 7c434042..2461d673 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -40,7 +40,7 @@ namespace Game typedef void*(__cdecl * BG_LoadWeaponDef_LoadObj_t)(const char* filename); extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj; - typedef WeaponDef* (__cdecl* BG_GetWeaponDef_t)(int weaponIndex); + typedef WeaponDef* (__cdecl * BG_GetWeaponDef_t)(int weaponIndex); extern BG_GetWeaponDef_t BG_GetWeaponDef; typedef void(__cdecl * Cbuf_AddServerText_t)(); @@ -55,10 +55,10 @@ namespace Game typedef void(__cdecl * CG_NextWeapon_f_t)(); extern CG_NextWeapon_f_t CG_NextWeapon_f; - typedef std::int32_t(__cdecl* CG_PlayBoltedEffect_t) (std::int32_t, FxEffectDef*, std::int32_t, std::uint32_t); + typedef std::int32_t(__cdecl * CG_PlayBoltedEffect_t) (std::int32_t, FxEffectDef*, std::int32_t, std::uint32_t); extern CG_PlayBoltedEffect_t CG_PlayBoltedEffect; - typedef std::int32_t(__cdecl* CG_GetBoneIndex_t)(std::int32_t, std::uint32_t name, char* index); + typedef std::int32_t(__cdecl * CG_GetBoneIndex_t)(std::int32_t, std::uint32_t name, char* index); extern CG_GetBoneIndex_t CG_GetBoneIndex; typedef void(__cdecl * CG_ScoresDown_f_t)(); @@ -375,7 +375,7 @@ namespace Game typedef void(__cdecl * Key_SetCatcher_t)(int localClientNum, int catcher); extern Key_SetCatcher_t Key_SetCatcher; - typedef bool(__cdecl* Key_IsKeyCatcherActive_t)(int localClientNum, int catcher); + typedef bool(__cdecl * Key_IsKeyCatcherActive_t)(int localClientNum, int catcher); extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive; typedef void(__cdecl * LargeLocalInit_t)(); @@ -450,13 +450,13 @@ namespace Game typedef bool(__cdecl * Menus_MenuIsInStack_t)(UiContext *dc, menuDef_t *menu); extern Menus_MenuIsInStack_t Menus_MenuIsInStack; - typedef menuDef_t*(__cdecl* Menu_GetFocused_t)(UiContext* ctx); + typedef menuDef_t*(__cdecl * Menu_GetFocused_t)(UiContext* ctx); extern Menu_GetFocused_t Menu_GetFocused; - typedef void(__cdecl* Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down); + typedef void(__cdecl * Menu_HandleKey_t)(UiContext* ctx, menuDef_t* menu, Game::keyNum_t key, int down); extern Menu_HandleKey_t Menu_HandleKey; - typedef bool(__cdecl* UI_KeyEvent_t)(int clientNum, int key, int down); + typedef bool(__cdecl * UI_KeyEvent_t)(int clientNum, int key, int down); extern UI_KeyEvent_t UI_KeyEvent; typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length); @@ -501,10 +501,10 @@ namespace Game typedef void(__cdecl * MSG_WriteLong_t)(msg_t *msg, int c); extern MSG_WriteLong_t MSG_WriteLong; - typedef void(*MSG_WriteShort_t)(msg_t* msg, short s); + typedef void(__cdecl * MSG_WriteShort_t)(msg_t* msg, short s); extern MSG_WriteShort_t MSG_WriteShort; - typedef void(*MSG_WriteString_t)(msg_t* msg, const char *str); + typedef void(__cdecl * MSG_WriteString_t)(msg_t* msg, const char *str); extern MSG_WriteString_t MSG_WriteString; typedef int(__cdecl * MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size); @@ -696,7 +696,7 @@ namespace Game typedef char* (__cdecl * SEH_StringEd_GetString_t)(const char* string); extern SEH_StringEd_GetString_t SEH_StringEd_GetString; - typedef int (__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); + typedef int (__cdecl * SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); extern SEH_ReadCharFromString_t SEH_ReadCharFromString; typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue); @@ -795,7 +795,7 @@ namespace Game typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close); extern UI_AddMenuList_t UI_AddMenuList; - typedef uiMenuCommand_t(__cdecl* UI_GetActiveMenu_t)(int localClientNum); + typedef uiMenuCommand_t(__cdecl * UI_GetActiveMenu_t)(int localClientNum); extern UI_GetActiveMenu_t UI_GetActiveMenu; typedef char* (__cdecl * UI_CheckStringTranslation_t)(char*, char*); @@ -828,16 +828,16 @@ namespace Game typedef void (__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t *); extern Vec3UnpackUnitVec_t Vec3UnpackUnitVec; - typedef float(__cdecl* vectoyaw_t)(vec2_t* vec); + typedef float(__cdecl * vectoyaw_t)(vec2_t* vec); extern vectoyaw_t vectoyaw; - typedef float(__cdecl* AngleNormalize360_t)(float val); + typedef float(__cdecl * AngleNormalize360_t)(float val); extern AngleNormalize360_t AngleNormalize360; typedef void(__cdecl * unzClose_t)(void* handle); extern unzClose_t unzClose; - typedef void(__cdecl* AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); + typedef void(__cdecl * AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee; extern XAssetHeader* DB_XAssetPool; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 84a1b091..3ca16df9 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -233,7 +233,7 @@ namespace Game K_LASTGAMEPADBUTTON_RANGE_1 = 0x6, // Last Gamepad 1 K_TAB = 0x9, K_ENTER = 0xD, - K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, // First Gamepad 2 + K_FIRSTGAMEPADBUTTON_RANGE_2 = 0xE, // First Gamepad 2 K_BUTTON_START = 0xE, K_BUTTON_BACK = 0xF, K_BUTTON_LSTICK = 0x10, From e8185a27b90e1eaa3d0cd2b771d4723532316fd4 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Fri, 10 Sep 2021 11:35:15 +0200 Subject: [PATCH 74/83] Fixed compilation --- src/Components/Modules/Gamepad.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 8471d2d8..828becc1 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1023,7 +1023,7 @@ namespace Components if (std::fabs(value) > 0.0f) { gamePad.inUse = true; - gpad_in_use.setRaw(true); + gpad_in_use.set(true); } } @@ -1194,7 +1194,7 @@ namespace Components auto& gamePad = gamePads[gamePadIndex]; gamePad.inUse = true; - gpad_in_use.setRaw(true); + gpad_in_use.set(true); if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) CL_GamepadResetMenuScrollTime(gamePadIndex, key, buttonEvent == Game::GPAD_BUTTON_PRESSED, time); @@ -1525,7 +1525,7 @@ namespace Components } } - gpad_present.setRaw(gpadPresent); + gpad_present.set(gpadPresent); } @@ -1821,7 +1821,7 @@ namespace Components { // A keyboard key has been pressed. Mark controller as unused. gamePads[0].inUse = false; - gpad_in_use.setRaw(false); + gpad_in_use.set(false); // Call original function Utils::Hook::Call(0x4F6480)(localClientNum, key, down, time); @@ -1837,7 +1837,7 @@ namespace Components if (dx != 0 || dy != 0) { gamePads[0].inUse = false; - gpad_in_use.setRaw(false); + gpad_in_use.set(false); } // Call original function From cc39a7bbe5ca55c1d92192f0d6c7e99f282463fc Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 10 Sep 2021 11:40:30 +0200 Subject: [PATCH 75/83] Reintroduce setRaw dvar methods - Makes it possible to set the value of a dvar without using the game's way of first converting it to a string and checking all kinds of dvar flags --- src/Components/Modules/Dvar.cpp | 30 ++++++++++++++++++++++++++++++ src/Components/Modules/Dvar.hpp | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/src/Components/Modules/Dvar.cpp b/src/Components/Modules/Dvar.cpp index ad28175c..c83a1f7c 100644 --- a/src/Components/Modules/Dvar.cpp +++ b/src/Components/Modules/Dvar.cpp @@ -134,6 +134,36 @@ namespace Components } } + void Dvar::Var::setRaw(int integer) + { + assert(this->dvar->type == Game::DVAR_TYPE_INT); + if (this->dvar) + { + this->dvar->current.integer = integer; + this->dvar->latched.integer = integer; + } + } + + void Dvar::Var::setRaw(float value) + { + assert(this->dvar->type == Game::DVAR_TYPE_FLOAT); + if (this->dvar) + { + this->dvar->current.value = value; + this->dvar->latched.value = value; + } + } + + void Dvar::Var::setRaw(bool enabled) + { + assert(this->dvar->type == Game::DVAR_TYPE_BOOL); + if (this->dvar) + { + this->dvar->current.enabled = enabled; + this->dvar->latched.enabled = enabled; + } + } + template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description) { return Game::Dvar_RegisterBool(name, value, flag.val, description); diff --git a/src/Components/Modules/Dvar.hpp b/src/Components/Modules/Dvar.hpp index 47cf8102..33f291fb 100644 --- a/src/Components/Modules/Dvar.hpp +++ b/src/Components/Modules/Dvar.hpp @@ -33,6 +33,10 @@ namespace Components void set(float value); void set(bool enabled); + void setRaw(int integer); + void setRaw(float value); + void setRaw(bool enabled); + private: Game::dvar_t* dvar; }; From 8ca84eb882302c5b279040a74ae5f472f2d09fff Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 10 Sep 2021 11:41:44 +0200 Subject: [PATCH 76/83] Replace runtime critical usages of Dvar::set with Dvar::setRaw in gamepad patch --- src/Components/Modules/Gamepad.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 828becc1..8471d2d8 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1023,7 +1023,7 @@ namespace Components if (std::fabs(value) > 0.0f) { gamePad.inUse = true; - gpad_in_use.set(true); + gpad_in_use.setRaw(true); } } @@ -1194,7 +1194,7 @@ namespace Components auto& gamePad = gamePads[gamePadIndex]; gamePad.inUse = true; - gpad_in_use.set(true); + gpad_in_use.setRaw(true); if (Game::Key_IsKeyCatcherActive(gamePadIndex, Game::KEYCATCH_UI)) CL_GamepadResetMenuScrollTime(gamePadIndex, key, buttonEvent == Game::GPAD_BUTTON_PRESSED, time); @@ -1525,7 +1525,7 @@ namespace Components } } - gpad_present.set(gpadPresent); + gpad_present.setRaw(gpadPresent); } @@ -1821,7 +1821,7 @@ namespace Components { // A keyboard key has been pressed. Mark controller as unused. gamePads[0].inUse = false; - gpad_in_use.set(false); + gpad_in_use.setRaw(false); // Call original function Utils::Hook::Call(0x4F6480)(localClientNum, key, down, time); @@ -1837,7 +1837,7 @@ namespace Components if (dx != 0 || dy != 0) { gamePads[0].inUse = false; - gpad_in_use.set(false); + gpad_in_use.setRaw(false); } // Call original function From da669cccc0ade2889a6cabeb8f9c79c280f6113c Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 10 Sep 2021 12:40:53 +0200 Subject: [PATCH 77/83] Fix maps component using integer values for setting bool dvars --- src/Components/Modules/Maps.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index ee36600a..24ee1d5f 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -560,7 +560,7 @@ namespace Components } hasDlc.push_back(hasAllMaps); - Dvar::Var(Utils::String::VA("isDlcInstalled_%d", pack.index)).set(hasAllMaps ? 1 : 0); + Dvar::Var(Utils::String::VA("isDlcInstalled_%d", pack.index)).set(hasAllMaps ? true : false); } // Must have all of dlc 3 to 5 or it causes issues @@ -571,7 +571,7 @@ namespace Components sentMessage = true; } - Dvar::Var("isDlcInstalled_All").set(hasAllDlcs ? 1 : 0); + Dvar::Var("isDlcInstalled_All").set(hasAllDlcs ? true : false); } bool Maps::IsCustomMap() From 966d7c23f36ab7fd9836a902f5bb38dc0b1f64d3 Mon Sep 17 00:00:00 2001 From: Jan Date: Fri, 10 Sep 2021 13:19:08 +0200 Subject: [PATCH 78/83] Fix gamepad slowdown aimassist mask to fix slowdown not being active when having scrambler perk equipped --- src/Components/Modules/Gamepad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 8471d2d8..abbd83a6 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -541,7 +541,7 @@ namespace Components if (ps->weaponState >= Game::WEAPON_STUNNED_START && ps->weaponState <= Game::WEAPON_STUNNED_END) return false; - if (ps->eFlags & 0x300800) + if (ps->eFlags & 0x100C00) return false; if (!ps->hasAmmo) From d71dfd170b9fb48eda28d997f3d869d7354d66b3 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 11 Sep 2021 16:34:04 +0200 Subject: [PATCH 79/83] Move Gamepad structs to their respective correct location - Structs that are reversed from the Game are moved to Structs.hpp - Structs that are custom to the Gamepad patch are moved into the Gamepad component class - Offsets to the Game's memory are moved to the Functions.hpp header - Arrays that hold data are moved to the Gamepad components class as static fields --- src/Components/Modules/Gamepad.cpp | 278 +++++++++++++---------------- src/Components/Modules/Gamepad.hpp | 265 +++------------------------ src/Game/Functions.cpp | 9 + src/Game/Functions.hpp | 12 ++ src/Game/Structs.hpp | 238 ++++++++++++++++++++++++ 5 files changed, 409 insertions(+), 393 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index abbd83a6..7c8d2b87 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -3,57 +3,57 @@ #include #include -namespace Game +namespace Components { - ButtonToCodeMap_t buttonList[] + Game::ButtonToCodeMap_t Gamepad::buttonList[] { - {GPAD_X, K_BUTTON_X}, - {GPAD_A, K_BUTTON_A}, - {GPAD_B, K_BUTTON_B}, - {GPAD_Y, K_BUTTON_Y}, - {GPAD_L_TRIG, K_BUTTON_LTRIG}, - {GPAD_R_TRIG, K_BUTTON_RTRIG}, - {GPAD_L_SHLDR, K_BUTTON_LSHLDR}, - {GPAD_R_SHLDR, K_BUTTON_RSHLDR}, - {GPAD_START, K_BUTTON_START}, - {GPAD_BACK, K_BUTTON_BACK}, - {GPAD_L3, K_BUTTON_LSTICK}, - {GPAD_R3, K_BUTTON_RSTICK}, - {GPAD_UP, K_DPAD_UP}, - {GPAD_DOWN, K_DPAD_DOWN}, - {GPAD_LEFT, K_DPAD_LEFT}, - {GPAD_RIGHT, K_DPAD_RIGHT} + {Game::GPAD_X, Game::K_BUTTON_X}, + {Game::GPAD_A, Game::K_BUTTON_A}, + {Game::GPAD_B, Game::K_BUTTON_B}, + {Game::GPAD_Y, Game::K_BUTTON_Y}, + {Game::GPAD_L_TRIG, Game::K_BUTTON_LTRIG}, + {Game::GPAD_R_TRIG, Game::K_BUTTON_RTRIG}, + {Game::GPAD_L_SHLDR, Game::K_BUTTON_LSHLDR}, + {Game::GPAD_R_SHLDR, Game::K_BUTTON_RSHLDR}, + {Game::GPAD_START, Game::K_BUTTON_START}, + {Game::GPAD_BACK, Game::K_BUTTON_BACK}, + {Game::GPAD_L3, Game::K_BUTTON_LSTICK}, + {Game::GPAD_R3, Game::K_BUTTON_RSTICK}, + {Game::GPAD_UP, Game::K_DPAD_UP}, + {Game::GPAD_DOWN, Game::K_DPAD_DOWN}, + {Game::GPAD_LEFT, Game::K_DPAD_LEFT}, + {Game::GPAD_RIGHT, Game::K_DPAD_RIGHT} }; - StickToCodeMap_t analogStickList[4] + Game::StickToCodeMap_t Gamepad::analogStickList[4] { - {GPAD_LX, K_APAD_RIGHT, K_APAD_LEFT}, - {GPAD_LY, K_APAD_UP, K_APAD_DOWN}, - {GPAD_RX, K_APAD_RIGHT, K_APAD_LEFT}, - {GPAD_RY, K_APAD_UP, K_APAD_DOWN}, + {Game::GPAD_LX, Game::K_APAD_RIGHT, Game::K_APAD_LEFT}, + {Game::GPAD_LY, Game::K_APAD_UP, Game::K_APAD_DOWN}, + {Game::GPAD_RX, Game::K_APAD_RIGHT, Game::K_APAD_LEFT}, + {Game::GPAD_RY, Game::K_APAD_UP, Game::K_APAD_DOWN}, }; - GamePadStick stickForAxis[GPAD_PHYSAXIS_COUNT] + Game::GamePadStick Gamepad::stickForAxis[Game::GPAD_PHYSAXIS_COUNT] { - GPAD_RX, - GPAD_RY, - GPAD_LX, - GPAD_LY, - GPAD_INVALID, - GPAD_INVALID + Game::GPAD_RX, + Game::GPAD_RY, + Game::GPAD_LX, + Game::GPAD_LY, + Game::GPAD_INVALID, + Game::GPAD_INVALID }; - GamepadPhysicalAxis axisSameStick[GPAD_PHYSAXIS_COUNT] + Game::GamepadPhysicalAxis Gamepad::axisSameStick[Game::GPAD_PHYSAXIS_COUNT] { - GPAD_PHYSAXIS_RSTICK_Y, - GPAD_PHYSAXIS_RSTICK_X, - GPAD_PHYSAXIS_LSTICK_Y, - GPAD_PHYSAXIS_LSTICK_X, - GPAD_PHYSAXIS_NONE, - GPAD_PHYSAXIS_NONE + Game::GPAD_PHYSAXIS_RSTICK_Y, + Game::GPAD_PHYSAXIS_RSTICK_X, + Game::GPAD_PHYSAXIS_LSTICK_Y, + Game::GPAD_PHYSAXIS_LSTICK_X, + Game::GPAD_PHYSAXIS_NONE, + Game::GPAD_PHYSAXIS_NONE }; - const char* physicalAxisNames[GPAD_PHYSAXIS_COUNT] + const char* Gamepad::physicalAxisNames[Game::GPAD_PHYSAXIS_COUNT] { "A_RSTICK_X", "A_RSTICK_Y", @@ -63,7 +63,7 @@ namespace Game "A_LTRIGGER" }; - const char* virtualAxisNames[GPAD_VIRTAXIS_COUNT] + const char* Gamepad::virtualAxisNames[Game::GPAD_VIRTAXIS_COUNT] { "VA_SIDE", "VA_FORWARD", @@ -73,82 +73,83 @@ namespace Game "VA_ATTACK" }; - const char* gamePadMappingTypeNames[GPAD_MAP_COUNT] + const char* Gamepad::gamePadMappingTypeNames[Game::GPAD_MAP_COUNT] { "MAP_LINEAR", "MAP_SQUARED" }; - keyNum_t menuScrollButtonList[] + Game::keyNum_t Gamepad::menuScrollButtonList[] { - K_APAD_UP, - K_APAD_DOWN, - K_APAD_LEFT, - K_APAD_RIGHT, - K_DPAD_UP, - K_DPAD_DOWN, - K_DPAD_LEFT, - K_DPAD_RIGHT + Game::K_APAD_UP, + Game::K_APAD_DOWN, + Game::K_APAD_LEFT, + Game::K_APAD_RIGHT, + Game::K_DPAD_UP, + Game::K_DPAD_DOWN, + Game::K_DPAD_LEFT, + Game::K_DPAD_RIGHT }; - keyname_t extendedKeyNames[] + Game::keyname_t Gamepad::extendedKeyNames[] { - {"BUTTON_A", K_BUTTON_A}, - {"BUTTON_B", K_BUTTON_B}, - {"BUTTON_X", K_BUTTON_X}, - {"BUTTON_Y", K_BUTTON_Y}, - {"BUTTON_LSHLDR", K_BUTTON_LSHLDR}, - {"BUTTON_RSHLDR", K_BUTTON_RSHLDR}, - {"BUTTON_START", K_BUTTON_START}, - {"BUTTON_BACK", K_BUTTON_BACK}, - {"BUTTON_LSTICK", K_BUTTON_LSTICK}, - {"BUTTON_RSTICK", K_BUTTON_RSTICK}, - {"BUTTON_LTRIG", K_BUTTON_LTRIG}, - {"BUTTON_RTRIG", K_BUTTON_RTRIG}, - {"DPAD_UP", K_DPAD_UP}, - {"DPAD_DOWN", K_DPAD_DOWN}, - {"DPAD_LEFT", K_DPAD_LEFT}, - {"DPAD_RIGHT", K_DPAD_RIGHT}, + {"BUTTON_A", Game::K_BUTTON_A}, + {"BUTTON_B", Game::K_BUTTON_B}, + {"BUTTON_X", Game::K_BUTTON_X}, + {"BUTTON_Y", Game::K_BUTTON_Y}, + {"BUTTON_LSHLDR", Game::K_BUTTON_LSHLDR}, + {"BUTTON_RSHLDR", Game::K_BUTTON_RSHLDR}, + {"BUTTON_START", Game::K_BUTTON_START}, + {"BUTTON_BACK", Game::K_BUTTON_BACK}, + {"BUTTON_LSTICK", Game::K_BUTTON_LSTICK}, + {"BUTTON_RSTICK", Game::K_BUTTON_RSTICK}, + {"BUTTON_LTRIG", Game::K_BUTTON_LTRIG}, + {"BUTTON_RTRIG", Game::K_BUTTON_RTRIG}, + {"DPAD_UP", Game::K_DPAD_UP}, + {"DPAD_DOWN", Game::K_DPAD_DOWN}, + {"DPAD_LEFT", Game::K_DPAD_LEFT}, + {"DPAD_RIGHT", Game::K_DPAD_RIGHT}, }; - keyname_t extendedLocalizedKeyNames[] + Game::keyname_t Gamepad::extendedLocalizedKeyNames[] { // Material text icons pattern: 0x01 width height material_name_len - {"^\x01\x32\x32\x08""button_a", K_BUTTON_A}, - {"^\x01\x32\x32\x08""button_b", K_BUTTON_B}, - {"^\x01\x32\x32\x08""button_x", K_BUTTON_X}, - {"^\x01\x32\x32\x08""button_y", K_BUTTON_Y}, - {"^\x01\x32\x32\x0D""button_lshldr", K_BUTTON_LSHLDR}, - {"^\x01\x32\x32\x0D""button_rshldr", K_BUTTON_RSHLDR}, - {"^\x01\x32\x32\x0C""button_start", K_BUTTON_START}, - {"^\x01\x32\x32\x0B""button_back", K_BUTTON_BACK}, - {"^\x01\x48\x32\x0D""button_lstick", K_BUTTON_LSTICK}, - {"^\x01\x48\x32\x0D""button_rstick", K_BUTTON_RSTICK}, - {"^\x01\x32\x32\x0C""button_ltrig", K_BUTTON_LTRIG}, - {"^\x01\x32\x32\x0C""button_rtrig", K_BUTTON_RTRIG}, - {"^\x01\x32\x32\x07""dpad_up", K_DPAD_UP}, - {"^\x01\x32\x32\x09""dpad_down", K_DPAD_DOWN}, - {"^\x01\x32\x32\x09""dpad_left", K_DPAD_LEFT}, - {"^\x01\x32\x32\x0A""dpad_right", K_DPAD_RIGHT}, + {"^\x01\x32\x32\x08""button_a", Game::K_BUTTON_A}, + {"^\x01\x32\x32\x08""button_b", Game::K_BUTTON_B}, + {"^\x01\x32\x32\x08""button_x", Game::K_BUTTON_X}, + {"^\x01\x32\x32\x08""button_y", Game::K_BUTTON_Y}, + {"^\x01\x32\x32\x0D""button_lshldr", Game::K_BUTTON_LSHLDR}, + {"^\x01\x32\x32\x0D""button_rshldr", Game::K_BUTTON_RSHLDR}, + {"^\x01\x32\x32\x0C""button_start", Game::K_BUTTON_START}, + {"^\x01\x32\x32\x0B""button_back", Game::K_BUTTON_BACK}, + {"^\x01\x48\x32\x0D""button_lstick", Game::K_BUTTON_LSTICK}, + {"^\x01\x48\x32\x0D""button_rstick", Game::K_BUTTON_RSTICK}, + {"^\x01\x32\x32\x0C""button_ltrig", Game::K_BUTTON_LTRIG}, + {"^\x01\x32\x32\x0C""button_rtrig", Game::K_BUTTON_RTRIG}, + {"^\x01\x32\x32\x07""dpad_up", Game::K_DPAD_UP}, + {"^\x01\x32\x32\x09""dpad_down", Game::K_DPAD_DOWN}, + {"^\x01\x32\x32\x09""dpad_left", Game::K_DPAD_LEFT}, + {"^\x01\x32\x32\x0A""dpad_right", Game::K_DPAD_RIGHT}, + }; + Game::keyname_t Gamepad::combinedKeyNames[Game::KEY_NAME_COUNT + std::extent_v + 1]; + Game::keyname_t Gamepad::combinedLocalizedKeyNames[Game::KEY_NAME_COUNT + std::extent_v + 1]; + + Gamepad::ControllerMenuKeyMapping Gamepad::controllerMenuKeyMappings[] + { + {Game::K_BUTTON_A, Game::K_ENTER}, + {Game::K_BUTTON_START, Game::K_ENTER}, + {Game::K_BUTTON_B, Game::K_ESCAPE}, + {Game::K_BUTTON_BACK, Game::K_ESCAPE}, + {Game::K_DPAD_UP, Game::K_UPARROW}, + {Game::K_APAD_UP, Game::K_UPARROW}, + {Game::K_DPAD_DOWN, Game::K_DOWNARROW}, + {Game::K_APAD_DOWN, Game::K_DOWNARROW}, + {Game::K_DPAD_LEFT, Game::K_LEFTARROW}, + {Game::K_APAD_LEFT, Game::K_LEFTARROW}, + {Game::K_DPAD_RIGHT, Game::K_RIGHTARROW}, + {Game::K_APAD_RIGHT, Game::K_RIGHTARROW}, }; - constexpr auto VANILLA_KEY_NAME_COUNT = 95; - constexpr auto VANILLA_LOCALIZED_KEY_NAME_COUNT = 95; - keyname_t combinedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; - keyname_t combinedLocalizedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v + 1]; - - PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); - kbutton_t* playersKb = reinterpret_cast(0xA1A9A8); - AimAssistGlobals* aaGlobArray = reinterpret_cast(0x7A2110); - keyname_t* vanillaKeyNames = reinterpret_cast(0x798580); - keyname_t* vanillaLocalizedKeyNames = reinterpret_cast(0x798880); - - constexpr auto VANILLA_AIM_ASSIST_GRAPH_COUNT = 4u; - GraphFloat* aaInputGraph = reinterpret_cast(0x7A2FC0); -} - -namespace Components -{ Gamepad::GamePad Gamepad::gamePads[Game::MAX_GAMEPADS]{}; Gamepad::GamePadGlobals Gamepad::gamePadGlobals[Game::MAX_GAMEPADS]{{}}; int Gamepad::gamePadBindingsModifiedFlags = 0; @@ -198,28 +199,6 @@ namespace Components Dvar::Var Gamepad::aim_lockon_pitch_strength; Dvar::Var Gamepad::aim_lockon_strength; - struct ControllerMenuKeyMapping - { - Game::keyNum_t controllerKey; - Game::keyNum_t pcKey; - }; - - ControllerMenuKeyMapping controllerMenuKeyMappings[] - { - {Game::K_BUTTON_A, Game::K_ENTER}, - {Game::K_BUTTON_START, Game::K_ENTER}, - {Game::K_BUTTON_B, Game::K_ESCAPE}, - {Game::K_BUTTON_BACK, Game::K_ESCAPE}, - {Game::K_DPAD_UP, Game::K_UPARROW}, - {Game::K_APAD_UP, Game::K_UPARROW}, - {Game::K_DPAD_DOWN, Game::K_DOWNARROW}, - {Game::K_APAD_DOWN, Game::K_DOWNARROW}, - {Game::K_DPAD_LEFT, Game::K_LEFTARROW}, - {Game::K_APAD_LEFT, Game::K_LEFTARROW}, - {Game::K_DPAD_RIGHT, Game::K_RIGHTARROW}, - {Game::K_APAD_RIGHT, Game::K_RIGHTARROW}, - }; - Gamepad::GamePadGlobals::GamePadGlobals() : axes{}, nextScrollTime(0) @@ -488,7 +467,7 @@ namespace Components assert(yawAxis); const auto graphIndex = aim_input_graph_index.get(); - if (aim_input_graph_enabled.get() && graphIndex >= 0 && graphIndex < Game::VANILLA_AIM_ASSIST_GRAPH_COUNT) + if (aim_input_graph_enabled.get() && graphIndex >= 0 && static_cast(graphIndex) < Game::AIM_ASSIST_GRAPH_COUNT) { const auto deflection = std::sqrt(input->pitchAxis * input->pitchAxis + input->yawAxis * input->yawAxis); @@ -795,7 +774,7 @@ namespace Components if (mapType == Game::GPAD_MAP_SQUARED) { - const auto otherAxisSameStick = Game::axisSameStick[physicalAxis]; + const auto otherAxisSameStick = axisSameStick[physicalAxis]; float otherAxisDeflection; if (otherAxisSameStick <= Game::GPAD_PHYSAXIS_NONE || otherAxisSameStick >= Game::GPAD_PHYSAXIS_COUNT) @@ -964,7 +943,7 @@ namespace Components return; const auto scrollDelayFirst = gpad_menu_scroll_delay_first.get(); - for (const auto scrollButton : Game::menuScrollButtonList) + for (const auto scrollButton : menuScrollButtonList) { if (key == scrollButton) { @@ -981,12 +960,12 @@ namespace Components auto& gamePad = gamePads[gamePadIndex]; - const auto stick = Game::stickForAxis[physicalAxis]; + const auto stick = stickForAxis[physicalAxis]; const auto stickIndex = stick & Game::GPAD_VALUE_MASK; if (stick != Game::GPAD_INVALID) { assert(stickIndex < 4); - const auto& mapping = Game::analogStickList[stickIndex]; + const auto& mapping = analogStickList[stickIndex]; if (gamePad.stickDown[stickIndex][Game::GPAD_STICK_POS]) { @@ -1078,7 +1057,7 @@ namespace Components const int scrollDelayFirst = gpad_menu_scroll_delay_first.get(); const int scrollDelayRest = gpad_menu_scroll_delay_rest.get(); - for (const auto menuScrollButton : Game::menuScrollButtonList) + for (const auto menuScrollButton : menuScrollButtonList) { if (key == menuScrollButton) { @@ -1495,7 +1474,7 @@ namespace Components CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_LTRIGGER, leftTrig, time); CL_GamepadEvent(gamePadIndex, Game::GPAD_PHYSAXIS_RTRIGGER, rightTrig, time); - for (const auto& buttonMapping : Game::buttonList) + for (const auto& buttonMapping : buttonList) { if (GPad_IsButtonPressed(gamePadIndex, buttonMapping.padButton)) { @@ -1553,9 +1532,9 @@ namespace Components continue; } - const auto* physicalAxisName = Game::physicalAxisNames[axisMapping.physicalAxis]; - const auto* virtualAxisName = Game::virtualAxisNames[virtualAxisIndex]; - const auto* mappingName = Game::gamePadMappingTypeNames[axisMapping.mapType]; + const auto* physicalAxisName = physicalAxisNames[axisMapping.physicalAxis]; + const auto* virtualAxisName = virtualAxisNames[virtualAxisIndex]; + const auto* mappingName = gamePadMappingTypeNames[axisMapping.mapType]; Game::FS_Printf(handle, "bindaxis %s %s %s\n", physicalAxisName, virtualAxisName, mappingName); } @@ -1589,7 +1568,6 @@ namespace Components } } - void Gamepad::Gamepad_BindAxis(const int gamePadIndex, const Game::GamepadPhysicalAxis realIndex, const Game::GamepadVirtualAxis axisIndex, const Game::GamepadMapping mapType) { assert(gamePadIndex < Game::MAX_GAMEPADS); @@ -1606,9 +1584,9 @@ namespace Components Game::GamepadPhysicalAxis Gamepad::StringToPhysicalAxis(const char* str) { - for (auto i = 0u; i < std::extent_v; i++) + for (auto i = 0u; i < std::extent_v; i++) { - if (strcmp(str, Game::physicalAxisNames[i]) == 0) + if (strcmp(str, physicalAxisNames[i]) == 0) return static_cast(i); } @@ -1617,9 +1595,9 @@ namespace Components Game::GamepadVirtualAxis Gamepad::StringToVirtualAxis(const char* str) { - for (auto i = 0u; i < std::extent_v; i++) + for (auto i = 0u; i < std::extent_v; i++) { - if (strcmp(str, Game::virtualAxisNames[i]) == 0) + if (strcmp(str, virtualAxisNames[i]) == 0) return static_cast(i); } @@ -1628,9 +1606,9 @@ namespace Components Game::GamepadMapping Gamepad::StringToGamePadMapping(const char* str) { - for (auto i = 0u; i < std::extent_v; i++) + for (auto i = 0u; i < std::extent_v; i++) { - if (strcmp(str, Game::gamePadMappingTypeNames[i]) == 0) + if (strcmp(str, gamePadMappingTypeNames[i]) == 0) return static_cast(i); } @@ -1851,19 +1829,19 @@ namespace Components void Gamepad::CreateKeyNameMap() { - memcpy(Game::combinedKeyNames, Game::vanillaKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_KEY_NAME_COUNT); - memcpy(&Game::combinedKeyNames[Game::VANILLA_KEY_NAME_COUNT], Game::extendedKeyNames, sizeof(Game::keyname_t) * std::extent_v); - Game::combinedKeyNames[std::extent_v - 1] = {nullptr, 0}; + memcpy(combinedKeyNames, Game::keyNames, sizeof(Game::keyname_t) * Game::KEY_NAME_COUNT); + memcpy(&combinedKeyNames[Game::KEY_NAME_COUNT], extendedKeyNames, sizeof(Game::keyname_t) * std::extent_v); + combinedKeyNames[std::extent_v - 1] = {nullptr, 0}; - memcpy(Game::combinedLocalizedKeyNames, Game::vanillaLocalizedKeyNames, sizeof(Game::keyname_t) * Game::VANILLA_LOCALIZED_KEY_NAME_COUNT); - memcpy(&Game::combinedLocalizedKeyNames[Game::VANILLA_LOCALIZED_KEY_NAME_COUNT], Game::extendedLocalizedKeyNames, - sizeof(Game::keyname_t) * std::extent_v); - Game::combinedLocalizedKeyNames[std::extent_v - 1] = {nullptr, 0}; + memcpy(combinedLocalizedKeyNames, Game::localizedKeyNames, sizeof(Game::keyname_t) * Game::LOCALIZED_KEY_NAME_COUNT); + memcpy(&combinedLocalizedKeyNames[Game::LOCALIZED_KEY_NAME_COUNT], extendedLocalizedKeyNames, + sizeof(Game::keyname_t) * std::extent_v); + combinedLocalizedKeyNames[std::extent_v - 1] = {nullptr, 0}; - Utils::Hook::Set(0x4A780A, Game::combinedKeyNames); - Utils::Hook::Set(0x4A7810, Game::combinedKeyNames); - Utils::Hook::Set(0x435C9F, Game::combinedKeyNames); - Utils::Hook::Set(0x435C98, Game::combinedLocalizedKeyNames); + Utils::Hook::Set(0x4A780A, combinedKeyNames); + Utils::Hook::Set(0x4A7810, combinedKeyNames); + Utils::Hook::Set(0x435C9F, combinedKeyNames); + Utils::Hook::Set(0x435C98, combinedLocalizedKeyNames); } Gamepad::Gamepad() diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 09488a78..9808909f 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -1,252 +1,14 @@ #pragma once -namespace Game -{ - static constexpr auto MAX_GAMEPADS = 1; - - static constexpr auto GPAD_VALUE_MASK = 0xFFFFFFFu; - static constexpr auto GPAD_DPAD_MASK = XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT; - static constexpr auto GPAD_DIGITAL_MASK = 1u << 28; - static constexpr auto GPAD_ANALOG_MASK = 1u << 29; - static constexpr auto GPAD_STICK_MASK = 1u << 30; - - enum GamePadButton - { - GPAD_NONE = 0, - GPAD_UP = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_UP & GPAD_VALUE_MASK), - GPAD_DOWN = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_DOWN & GPAD_VALUE_MASK), - GPAD_LEFT = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_LEFT & GPAD_VALUE_MASK), - GPAD_RIGHT = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_RIGHT & GPAD_VALUE_MASK), - GPAD_START = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_START & GPAD_VALUE_MASK), - GPAD_BACK = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_BACK & GPAD_VALUE_MASK), - GPAD_L3 = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_LEFT_THUMB & GPAD_VALUE_MASK), - GPAD_R3 = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_RIGHT_THUMB & GPAD_VALUE_MASK), - GPAD_L_SHLDR = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_LEFT_SHOULDER & GPAD_VALUE_MASK), - GPAD_R_SHLDR = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_RIGHT_SHOULDER & GPAD_VALUE_MASK), - GPAD_A = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_A & GPAD_VALUE_MASK), - GPAD_B = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_B & GPAD_VALUE_MASK), - GPAD_X = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_X & GPAD_VALUE_MASK), - GPAD_Y = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_Y & GPAD_VALUE_MASK), - GPAD_L_TRIG = GPAD_ANALOG_MASK | (0 & GPAD_VALUE_MASK), - GPAD_R_TRIG = GPAD_ANALOG_MASK | (1 & GPAD_VALUE_MASK), - }; - - enum GamePadStick - { - GPAD_INVALID = 0x0, - GPAD_LX = GPAD_STICK_MASK | (0 & GPAD_VALUE_MASK), - GPAD_LY = GPAD_STICK_MASK | (1 & GPAD_VALUE_MASK), - GPAD_RX = GPAD_STICK_MASK | (2 & GPAD_VALUE_MASK), - GPAD_RY = GPAD_STICK_MASK | (3 & GPAD_VALUE_MASK), - }; - - enum GamePadButtonEvent - { - GPAD_BUTTON_RELEASED = 0x0, - GPAD_BUTTON_PRESSED = 0x1, - GPAD_BUTTON_UPDATE = 0x2, - }; - - enum GamepadPhysicalAxis - { - GPAD_PHYSAXIS_NONE = -1, - GPAD_PHYSAXIS_RSTICK_X = 0x0, - GPAD_PHYSAXIS_RSTICK_Y = 0x1, - GPAD_PHYSAXIS_LSTICK_X = 0x2, - GPAD_PHYSAXIS_LSTICK_Y = 0x3, - GPAD_PHYSAXIS_RTRIGGER = 0x4, - GPAD_PHYSAXIS_LTRIGGER = 0x5, - - GPAD_PHYSAXIS_COUNT, - }; - - enum GamepadVirtualAxis - { - GPAD_VIRTAXIS_NONE = -1, - GPAD_VIRTAXIS_SIDE = 0x0, - GPAD_VIRTAXIS_FORWARD = 0x1, - GPAD_VIRTAXIS_UP = 0x2, - GPAD_VIRTAXIS_YAW = 0x3, - GPAD_VIRTAXIS_PITCH = 0x4, - GPAD_VIRTAXIS_ATTACK = 0x5, - - GPAD_VIRTAXIS_COUNT - }; - - enum GamePadStickDir - { - GPAD_STICK_POS = 0x0, - GPAD_STICK_NEG = 0x1, - - GPAD_STICK_DIR_COUNT - }; - - enum GamepadMapping - { - GPAD_MAP_NONE = -1, - GPAD_MAP_LINEAR = 0x0, - GPAD_MAP_SQUARED = 0x1, - - GPAD_MAP_COUNT - }; - - struct ButtonToCodeMap_t - { - GamePadButton padButton; - int code; - }; - - struct StickToCodeMap_t - { - GamePadStick padStick; - int posCode; - int negCode; - }; - - struct GamepadVirtualAxisMapping - { - GamepadPhysicalAxis physicalAxis; - GamepadMapping mapType; - }; - - struct GpadAxesGlob - { - float axesValues[GPAD_PHYSAXIS_COUNT]; - GamepadVirtualAxisMapping virtualAxes[GPAD_VIRTAXIS_COUNT]; - }; - - enum weaponstate_t - { - WEAPON_READY = 0x0, - WEAPON_RAISING = 0x1, - WEAPON_RAISING_ALTSWITCH = 0x2, - WEAPON_DROPPING = 0x3, - WEAPON_DROPPING_QUICK = 0x4, - WEAPON_DROPPING_ALT = 0x5, - WEAPON_FIRING = 0x6, - WEAPON_RECHAMBERING = 0x7, - WEAPON_RELOADING = 0x8, - WEAPON_RELOADING_INTERUPT = 0x9, - WEAPON_RELOAD_START = 0xA, - WEAPON_RELOAD_START_INTERUPT = 0xB, - WEAPON_RELOAD_END = 0xC, - WEAPON_MELEE_INIT = 0xD, - WEAPON_MELEE_FIRE = 0xE, - WEAPON_MELEE_END = 0xF, - WEAPON_OFFHAND_INIT = 0x10, - WEAPON_OFFHAND_PREPARE = 0x11, - WEAPON_OFFHAND_HOLD = 0x12, - WEAPON_OFFHAND_FIRE = 0x13, - WEAPON_OFFHAND_DETONATE = 0x14, - WEAPON_OFFHAND_END = 0x15, - WEAPON_DETONATING = 0x16, - WEAPON_SPRINT_RAISE = 0x17, - WEAPON_SPRINT_LOOP = 0x18, - WEAPON_SPRINT_DROP = 0x19, - WEAPON_STUNNED_START = 0x1A, - WEAPON_STUNNED_LOOP = 0x1B, - WEAPON_STUNNED_END = 0x1C, - WEAPON_NIGHTVISION_WEAR = 0x1D, - WEAPON_NIGHTVISION_REMOVE = 0x1E, - - WEAPONSTATES_NUM - }; - - struct AimAssistPlayerState - { - float velocity[3]; - int eFlags; - int linkFlags; - int pm_flags; - int weapFlags; - int weaponState; - float fWeaponPosFrac; - int weapIndex; - bool hasAmmo; - bool isDualWielding; - bool isThirdPerson; - bool isExtendedMelee; - }; - - struct AimTweakables - { - float slowdownRegionWidth; - float slowdownRegionHeight; - float autoAimRegionWidth; - float autoAimRegionHeight; - float autoMeleeRegionWidth; - float autoMeleeRegionHeight; - float lockOnRegionWidth; - float lockOnRegionHeight; - }; - - constexpr auto AIM_TARGET_INVALID = 0x3FF; - struct AimScreenTarget - { - int entIndex; - float clipMins[2]; - float clipMaxs[2]; - float aimPos[3]; - float velocity[3]; - float distSqr; - float crosshairDistSqr; - }; - - enum AutoMeleeState - { - AIM_MELEE_STATE_OFF = 0x0, - AIM_MELEE_STATE_TARGETED = 0x1, - AIM_MELEE_STATE_UPDATING = 0x2, - }; - -#pragma warning(push) -#pragma warning(disable: 4324) - struct __declspec(align(16)) AimAssistGlobals - { - AimAssistPlayerState ps; - char _pad1[4]; - float screenMtx[4][4]; - float invScreenMtx[4][4]; - bool initialized; - int prevButtons; - AimTweakables tweakables; - float eyeOrigin[3]; - float viewOrigin[3]; - float viewAngles[3]; - float viewAxis[3][3]; - float fovTurnRateScale; - float fovScaleInv; - float adsLerp; - float pitchDelta; - float yawDelta; - float screenWidth; - float screenHeight; - AimScreenTarget screenTargets[64]; - int screenTargetCount; - int autoAimTargetEnt; - bool autoAimPressed; - bool autoAimActive; - float autoAimPitch; - float autoAimPitchTarget; - float autoAimYaw; - float autoAimYawTarget; - AutoMeleeState autoMeleeState; - int autoMeleeTargetEnt; - float autoMeleePitch; - float autoMeleePitchTarget; - float autoMeleeYaw; - float autoMeleeYawTarget; - int lockOnTargetEnt; - }; -#pragma warning(pop) -} - namespace Components { class Gamepad : public Component { - public: - Gamepad(); + struct ControllerMenuKeyMapping + { + Game::keyNum_t controllerKey; + Game::keyNum_t pcKey; + }; struct GamePad { @@ -276,7 +38,24 @@ namespace Components GamePadGlobals(); }; + public: + Gamepad(); + private: + static Game::ButtonToCodeMap_t buttonList[]; + static Game::StickToCodeMap_t analogStickList[4]; + static Game::GamePadStick stickForAxis[]; + static Game::GamepadPhysicalAxis axisSameStick[]; + static const char* physicalAxisNames[]; + static const char* virtualAxisNames[]; + static const char* gamePadMappingTypeNames[]; + static Game::keyNum_t menuScrollButtonList[]; + static Game::keyname_t extendedKeyNames[]; + static Game::keyname_t extendedLocalizedKeyNames[]; + static Game::keyname_t combinedKeyNames[]; + static Game::keyname_t combinedLocalizedKeyNames[]; + static ControllerMenuKeyMapping controllerMenuKeyMappings[]; + static GamePad gamePads[Game::MAX_GAMEPADS]; static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index d581de63..b0a623fc 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -454,6 +454,15 @@ namespace Game cg_s* cgArray = reinterpret_cast(0x7F0F78); + PlayerKeyState* playerKeys = reinterpret_cast(0xA1B7D0); + kbutton_t* playersKb = reinterpret_cast(0xA1A9A8); + AimAssistGlobals* aaGlobArray = reinterpret_cast(0x7A2110); + + keyname_t* keyNames = reinterpret_cast(0x798580); + keyname_t* localizedKeyNames = reinterpret_cast(0x798880); + + GraphFloat* aaInputGraph = reinterpret_cast(0x7A2FC0); + 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 2461d673..86a3334a 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -938,6 +938,18 @@ namespace Game extern cg_s* cgArray; + extern PlayerKeyState* playerKeys; + extern kbutton_t* playersKb; + extern AimAssistGlobals* aaGlobArray; + + constexpr auto KEY_NAME_COUNT = 95; + constexpr auto LOCALIZED_KEY_NAME_COUNT = 95; + extern keyname_t* keyNames; + extern keyname_t* localizedKeyNames; + + constexpr auto AIM_ASSIST_GRAPH_COUNT = 4u; + extern GraphFloat* aaInputGraph; + 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 3ca16df9..99064c9c 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -6198,6 +6198,244 @@ namespace Game char _pad4[0x89740]; }; + static constexpr auto MAX_GAMEPADS = 1; + + static constexpr auto GPAD_VALUE_MASK = 0xFFFFFFFu; + static constexpr auto GPAD_DPAD_MASK = XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_RIGHT; + static constexpr auto GPAD_DIGITAL_MASK = 1u << 28; + static constexpr auto GPAD_ANALOG_MASK = 1u << 29; + static constexpr auto GPAD_STICK_MASK = 1u << 30; + + enum GamePadButton + { + GPAD_NONE = 0, + GPAD_UP = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_UP & GPAD_VALUE_MASK), + GPAD_DOWN = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_DOWN & GPAD_VALUE_MASK), + GPAD_LEFT = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_LEFT & GPAD_VALUE_MASK), + GPAD_RIGHT = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_DPAD_RIGHT & GPAD_VALUE_MASK), + GPAD_START = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_START & GPAD_VALUE_MASK), + GPAD_BACK = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_BACK & GPAD_VALUE_MASK), + GPAD_L3 = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_LEFT_THUMB & GPAD_VALUE_MASK), + GPAD_R3 = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_RIGHT_THUMB & GPAD_VALUE_MASK), + GPAD_L_SHLDR = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_LEFT_SHOULDER & GPAD_VALUE_MASK), + GPAD_R_SHLDR = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_RIGHT_SHOULDER & GPAD_VALUE_MASK), + GPAD_A = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_A & GPAD_VALUE_MASK), + GPAD_B = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_B & GPAD_VALUE_MASK), + GPAD_X = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_X & GPAD_VALUE_MASK), + GPAD_Y = GPAD_DIGITAL_MASK | (XINPUT_GAMEPAD_Y & GPAD_VALUE_MASK), + GPAD_L_TRIG = GPAD_ANALOG_MASK | (0 & GPAD_VALUE_MASK), + GPAD_R_TRIG = GPAD_ANALOG_MASK | (1 & GPAD_VALUE_MASK), + }; + + enum GamePadStick + { + GPAD_INVALID = 0x0, + GPAD_LX = GPAD_STICK_MASK | (0 & GPAD_VALUE_MASK), + GPAD_LY = GPAD_STICK_MASK | (1 & GPAD_VALUE_MASK), + GPAD_RX = GPAD_STICK_MASK | (2 & GPAD_VALUE_MASK), + GPAD_RY = GPAD_STICK_MASK | (3 & GPAD_VALUE_MASK), + }; + + enum GamePadButtonEvent + { + GPAD_BUTTON_RELEASED = 0x0, + GPAD_BUTTON_PRESSED = 0x1, + GPAD_BUTTON_UPDATE = 0x2, + }; + + enum GamepadPhysicalAxis + { + GPAD_PHYSAXIS_NONE = -1, + GPAD_PHYSAXIS_RSTICK_X = 0x0, + GPAD_PHYSAXIS_RSTICK_Y = 0x1, + GPAD_PHYSAXIS_LSTICK_X = 0x2, + GPAD_PHYSAXIS_LSTICK_Y = 0x3, + GPAD_PHYSAXIS_RTRIGGER = 0x4, + GPAD_PHYSAXIS_LTRIGGER = 0x5, + + GPAD_PHYSAXIS_COUNT, + }; + + enum GamepadVirtualAxis + { + GPAD_VIRTAXIS_NONE = -1, + GPAD_VIRTAXIS_SIDE = 0x0, + GPAD_VIRTAXIS_FORWARD = 0x1, + GPAD_VIRTAXIS_UP = 0x2, + GPAD_VIRTAXIS_YAW = 0x3, + GPAD_VIRTAXIS_PITCH = 0x4, + GPAD_VIRTAXIS_ATTACK = 0x5, + + GPAD_VIRTAXIS_COUNT + }; + + enum GamePadStickDir + { + GPAD_STICK_POS = 0x0, + GPAD_STICK_NEG = 0x1, + + GPAD_STICK_DIR_COUNT + }; + + enum GamepadMapping + { + GPAD_MAP_NONE = -1, + GPAD_MAP_LINEAR = 0x0, + GPAD_MAP_SQUARED = 0x1, + + GPAD_MAP_COUNT + }; + + struct ButtonToCodeMap_t + { + GamePadButton padButton; + int code; + }; + + struct StickToCodeMap_t + { + GamePadStick padStick; + int posCode; + int negCode; + }; + + struct GamepadVirtualAxisMapping + { + GamepadPhysicalAxis physicalAxis; + GamepadMapping mapType; + }; + + struct GpadAxesGlob + { + float axesValues[GPAD_PHYSAXIS_COUNT]; + GamepadVirtualAxisMapping virtualAxes[GPAD_VIRTAXIS_COUNT]; + }; + + enum weaponstate_t + { + WEAPON_READY = 0x0, + WEAPON_RAISING = 0x1, + WEAPON_RAISING_ALTSWITCH = 0x2, + WEAPON_DROPPING = 0x3, + WEAPON_DROPPING_QUICK = 0x4, + WEAPON_DROPPING_ALT = 0x5, + WEAPON_FIRING = 0x6, + WEAPON_RECHAMBERING = 0x7, + WEAPON_RELOADING = 0x8, + WEAPON_RELOADING_INTERUPT = 0x9, + WEAPON_RELOAD_START = 0xA, + WEAPON_RELOAD_START_INTERUPT = 0xB, + WEAPON_RELOAD_END = 0xC, + WEAPON_MELEE_INIT = 0xD, + WEAPON_MELEE_FIRE = 0xE, + WEAPON_MELEE_END = 0xF, + WEAPON_OFFHAND_INIT = 0x10, + WEAPON_OFFHAND_PREPARE = 0x11, + WEAPON_OFFHAND_HOLD = 0x12, + WEAPON_OFFHAND_FIRE = 0x13, + WEAPON_OFFHAND_DETONATE = 0x14, + WEAPON_OFFHAND_END = 0x15, + WEAPON_DETONATING = 0x16, + WEAPON_SPRINT_RAISE = 0x17, + WEAPON_SPRINT_LOOP = 0x18, + WEAPON_SPRINT_DROP = 0x19, + WEAPON_STUNNED_START = 0x1A, + WEAPON_STUNNED_LOOP = 0x1B, + WEAPON_STUNNED_END = 0x1C, + WEAPON_NIGHTVISION_WEAR = 0x1D, + WEAPON_NIGHTVISION_REMOVE = 0x1E, + + WEAPONSTATES_NUM + }; + + struct AimAssistPlayerState + { + float velocity[3]; + int eFlags; + int linkFlags; + int pm_flags; + int weapFlags; + int weaponState; + float fWeaponPosFrac; + int weapIndex; + bool hasAmmo; + bool isDualWielding; + bool isThirdPerson; + bool isExtendedMelee; + }; + + struct AimTweakables + { + float slowdownRegionWidth; + float slowdownRegionHeight; + float autoAimRegionWidth; + float autoAimRegionHeight; + float autoMeleeRegionWidth; + float autoMeleeRegionHeight; + float lockOnRegionWidth; + float lockOnRegionHeight; + }; + + constexpr auto AIM_TARGET_INVALID = 0x3FF; + struct AimScreenTarget + { + int entIndex; + float clipMins[2]; + float clipMaxs[2]; + float aimPos[3]; + float velocity[3]; + float distSqr; + float crosshairDistSqr; + }; + + enum AutoMeleeState + { + AIM_MELEE_STATE_OFF = 0x0, + AIM_MELEE_STATE_TARGETED = 0x1, + AIM_MELEE_STATE_UPDATING = 0x2, + }; + +#pragma warning(push) +#pragma warning(disable: 4324) + struct __declspec(align(16)) AimAssistGlobals + { + AimAssistPlayerState ps; + char _pad1[4]; + float screenMtx[4][4]; + float invScreenMtx[4][4]; + bool initialized; + int prevButtons; + AimTweakables tweakables; + float eyeOrigin[3]; + float viewOrigin[3]; + float viewAngles[3]; + float viewAxis[3][3]; + float fovTurnRateScale; + float fovScaleInv; + float adsLerp; + float pitchDelta; + float yawDelta; + float screenWidth; + float screenHeight; + AimScreenTarget screenTargets[64]; + int screenTargetCount; + int autoAimTargetEnt; + bool autoAimPressed; + bool autoAimActive; + float autoAimPitch; + float autoAimPitchTarget; + float autoAimYaw; + float autoAimYawTarget; + AutoMeleeState autoMeleeState; + int autoMeleeTargetEnt; + float autoMeleePitch; + float autoMeleePitchTarget; + float autoMeleeYaw; + float autoMeleeYawTarget; + int lockOnTargetEnt; + }; +#pragma warning(pop) + #pragma endregion #ifndef IDA From d96780a88e52f20ab8803623162858acb53a65c5 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 11 Sep 2021 17:49:32 +0200 Subject: [PATCH 80/83] Add handling of zero length vector to normalization methods - Avoids having division by zero --- src/Game/Functions.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index b0a623fc..6692a23d 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -739,19 +739,25 @@ namespace Game { const float length = std::sqrt((vec[0] * vec[0]) + (vec[1] * vec[1])); - vec[0] /= length; - vec[1] /= length; + if(length > 0.0f) + { + vec[0] /= length; + vec[1] /= length; + } return length; } float Vec3Normalize(vec3_t& vec) { - const float length = static_cast(std::sqrt(std::pow(vec[0], 2) + std::pow(vec[1], 2) + std::pow(vec[2], 2))); + const float length = std::sqrt(std::pow(vec[0], 2.0f) + std::pow(vec[1], 2.0f) + std::pow(vec[2], 2.0f)); - vec[0] /= length; - vec[1] /= length; - vec[2] /= length; + if(length > 0.0f) + { + vec[0] /= length; + vec[1] /= length; + vec[2] /= length; + } return length; } From c0a1a99d8bedc6e6bb42eee95f0baf36dcdf411d Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 11 Sep 2021 17:49:58 +0200 Subject: [PATCH 81/83] Add comments to gamepad patch to explain commented out code and magic flag numbers --- src/Components/Modules/Gamepad.cpp | 6 ++++++ src/Components/Modules/Materials.cpp | 1 + 2 files changed, 7 insertions(+) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index 7c8d2b87..bb8055b1 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -345,9 +345,11 @@ namespace Components bool Gamepad::AimAssist_IsPlayerUsingOffhand(Game::AimAssistPlayerState* ps) { + // Check offhand flag if ((ps->weapFlags & 2) == 0) return false; + // If offhand weapon has no id we are not using one if (!ps->weapIndex) return false; @@ -520,6 +522,7 @@ namespace Components if (ps->weaponState >= Game::WEAPON_STUNNED_START && ps->weaponState <= Game::WEAPON_STUNNED_END) return false; + // The game checks for these flags. Their meaning is to be researched if necessary. if (ps->eFlags & 0x100C00) return false; @@ -809,7 +812,10 @@ namespace Components auto yaw = -CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_YAW); auto forward = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_FORWARD); auto side = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_SIDE); + + // The game implements an attack axis at this location. This axis is unused however so for this patch it was not implemented. //auto attack = CL_GamepadAxisValue(gamePadIndex, Game::GPAD_VIRTAXIS_ATTACK); + auto moveScale = static_cast(std::numeric_limits::max()); if (std::fabs(side) > 0.0f || std::fabs(forward) > 0.0f) diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index a701b381..173feefd 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -325,6 +325,7 @@ namespace Components const auto width = text[1]; const auto materialNameLength = text[3]; + // This is how the game calculates width and height. Probably some 1 byte floating point number. auto v9 = font->pixelHeight * (width - 16) + 16; auto w = ((((v9 >> 24) & 0x1F) + v9) >> 5); From 8ef991f81f4f0a517545a81d937e38f625844c95 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 11 Sep 2021 17:54:50 +0200 Subject: [PATCH 82/83] Move standard header include to precompiled header - Im getting forced to do this help --- src/Components/Modules/Gamepad.cpp | 3 --- src/STDInclude.hpp | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index bb8055b1..5ba7a66b 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -1,8 +1,5 @@ #include "STDInclude.hpp" -#include -#include - namespace Components { Game::ButtonToCodeMap_t Gamepad::buttonList[] diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 36f7d469..208e0cab 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include // Experimental C++17 features #include From c824fe31e250960dfd1121990667cb73db234c18 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 11 Sep 2021 20:38:22 +0200 Subject: [PATCH 83/83] [Dvar] Found another assert failed trigger --- src/Components/Modules/Dedicated.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index f19cae05..35f36861 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -218,7 +218,7 @@ namespace Components { if (!Dedicated::IsEnabled() && Dvar::Var("sv_dontrotate").get()) { - Dvar::Var("sv_dontrotate").set(0); + Dvar::Var("sv_dontrotate").set(false); return; }