Write gamepad axis configuration to config file

This commit is contained in:
Jan 2021-08-22 16:07:23 +02:00
parent dcbb120de1
commit 8cd99235c0
4 changed files with 270 additions and 41 deletions

View File

@ -45,6 +45,32 @@ namespace Game
GPAD_INVALID 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[] keyNum_t menuScrollButtonList[]
{ {
K_APAD_UP, K_APAD_UP,
@ -80,7 +106,6 @@ namespace Game
keyname_t combinedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v<decltype(extendedKeyNames)> + 1]; keyname_t combinedKeyNames[VANILLA_KEY_NAME_COUNT + std::extent_v<decltype(extendedKeyNames)> + 1];
GpadAxesGlob gaGlobs[MAX_GAMEPADS];
PlayerKeyState* playerKeys = reinterpret_cast<PlayerKeyState*>(0xA1B7D0); PlayerKeyState* playerKeys = reinterpret_cast<PlayerKeyState*>(0xA1B7D0);
keyname_t* vanillaKeyNames = reinterpret_cast<keyname_t*>(0x798580); keyname_t* vanillaKeyNames = reinterpret_cast<keyname_t*>(0x798580);
} }
@ -88,7 +113,8 @@ namespace Game
namespace Components namespace Components
{ {
Gamepad::GamePad Gamepad::gamePads[Game::MAX_GAMEPADS]{}; 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) 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::isHoldingMaxLookX = false;
bool Gamepad::isADS; bool Gamepad::isADS;
@ -161,6 +187,18 @@ namespace Components
Gamepad::ActionMapping(XINPUT_GAMEPAD_DPAD_UP, "actionslot 4"), 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 // Same thing
// void Gamepad::Vibrate(int leftVal, int rightVal) // void Gamepad::Vibrate(int leftVal, int rightVal)
@ -594,12 +632,14 @@ namespace Components
} }
} }
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(gamePadIndex < Game::MAX_GAMEPADS);
assert(physicalAxis < Game::GPAD_PHYSAXIS_COUNT && physicalAxis >= 0); 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); CL_GamepadGenerateAPad(gamePadIndex, physicalAxis, time);
} }
@ -870,7 +910,7 @@ namespace Components
return !down && lastDown; return !down && lastDown;
} }
void Gamepad::GPad_UpdateSticksDown(int gamePadIndex) void Gamepad::GPad_UpdateSticksDown(const int gamePadIndex)
{ {
assert(gamePadIndex < Game::MAX_GAMEPADS); assert(gamePadIndex < Game::MAX_GAMEPADS);
auto& gamePad = gamePads[gamePadIndex]; auto& gamePad = gamePads[gamePadIndex];
@ -1078,6 +1118,153 @@ namespace Components
IN_GamePadsMove(); 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<void(int, int)>(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<decltype(Game::physicalAxisNames)>; i++)
{
if (strcmp(str, Game::physicalAxisNames[i]) == 0)
return static_cast<Game::GamepadPhysicalAxis>(i);
}
return Game::GPAD_PHYSAXIS_NONE;
}
Game::GamepadVirtualAxis Gamepad::StringToVirtualAxis(const char* str)
{
for (auto i = 0u; i < std::extent_v<decltype(Game::virtualAxisNames)>; i++)
{
if (strcmp(str, Game::virtualAxisNames[i]) == 0)
return static_cast<Game::GamepadVirtualAxis>(i);
}
return Game::GPAD_VIRTAXIS_NONE;
}
Game::GamepadMapping Gamepad::StringToGamePadMapping(const char* str)
{
for (auto i = 0u; i < std::extent_v<decltype(Game::gamePadMappingTypeNames)>; i++)
{
if (strcmp(str, Game::gamePadMappingTypeNames[i]) == 0)
return static_cast<Game::GamepadMapping>(i);
}
return Game::GPAD_MAP_NONE;
}
void Gamepad::Axis_Bind_f(Command::Params* params)
{
if (params->length() < 4)
{
Logger::Print("bindaxis <real axis> <virtual axis> <input type>\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() void Gamepad::InitDvars()
{ {
gpad_enabled = Dvar::Register<bool>("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled"); gpad_enabled = Dvar::Register<bool>("gpad_enabled", false, Game::DVAR_FLAG_SAVED, "Game pad enabled");
@ -1137,8 +1324,16 @@ namespace Components
Utils::Hook(0x492127, MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x492127, MSG_ReadDeltaUsercmdKeyStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x492009, MSG_ReadDeltaUsercmdKeyStub2, 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(); CreateKeyNameMap();
Command::Add("bindaxis", Axis_Bind_f);
Command::Add("unbindallaxis", Axis_Unbindall_f);
if (Dedicated::IsEnabled()) if (Dedicated::IsEnabled())
return; return;

View File

@ -60,6 +60,19 @@ namespace Game
GPAD_PHYSAXIS_COUNT, 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 enum GamePadStickDir
{ {
GPAD_STICK_POS = 0x0, GPAD_STICK_POS = 0x0,
@ -73,7 +86,8 @@ namespace Game
GPAD_MAP_NONE = -1, GPAD_MAP_NONE = -1,
GPAD_MAP_LINEAR = 0x0, GPAD_MAP_LINEAR = 0x0,
GPAD_MAP_SQUARED = 0x1, GPAD_MAP_SQUARED = 0x1,
GPAD_MAP_COUNT = 0x2
GPAD_MAP_COUNT
}; };
struct ButtonToCodeMap_t struct ButtonToCodeMap_t
@ -98,7 +112,7 @@ namespace Game
struct GpadAxesGlob struct GpadAxesGlob
{ {
float axesValues[GPAD_PHYSAXIS_COUNT]; float axesValues[GPAD_PHYSAXIS_COUNT];
GamepadVirtualAxisMapping virtualAxes[GPAD_PHYSAXIS_COUNT]; GamepadVirtualAxisMapping virtualAxes[GPAD_VIRTAXIS_COUNT];
}; };
} }
@ -132,7 +146,10 @@ namespace Components
struct GamePadGlobals struct GamePadGlobals
{ {
Game::GpadAxesGlob axes;
unsigned nextScrollTime; unsigned nextScrollTime;
GamePadGlobals();
}; };
struct ActionMapping struct ActionMapping
@ -156,6 +173,8 @@ namespace Components
static GamePad gamePads[Game::MAX_GAMEPADS]; static GamePad gamePads[Game::MAX_GAMEPADS];
static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS]; static GamePadGlobals gamePadGlobals[Game::MAX_GAMEPADS];
static int gamePadBindingsModifiedFlags;
static bool isHoldingMaxLookX; static bool isHoldingMaxLookX;
static std::chrono::milliseconds timeAtFirstHeldMaxLookX; static std::chrono::milliseconds timeAtFirstHeldMaxLookX;
static bool isADS; static bool isADS;
@ -236,6 +255,17 @@ namespace Components
static void IN_GamePadsMove(); static void IN_GamePadsMove();
static void IN_Frame_Hk(); 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 InitDvars();
static void IN_Init_Hk(); static void IN_Init_Hk();

View File

@ -130,6 +130,7 @@ namespace Game
FS_FCloseFile_t FS_FCloseFile = FS_FCloseFile_t(0x462000); FS_FCloseFile_t FS_FCloseFile = FS_FCloseFile_t(0x462000);
FS_WriteFile_t FS_WriteFile = FS_WriteFile_t(0x426450); FS_WriteFile_t FS_WriteFile = FS_WriteFile_t(0x426450);
FS_Write_t FS_Write = FS_Write_t(0x4C06E0); 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_Read_t FS_Read = FS_Read_t(0x4A04C0);
FS_Seek_t FS_Seek = FS_Seek_t(0x4A63D0); FS_Seek_t FS_Seek = FS_Seek_t(0x4A63D0);
FS_FTell_t FS_FTell = FS_FTell_t(0x4E6760); FS_FTell_t FS_FTell = FS_FTell_t(0x4E6760);

View File

@ -302,6 +302,9 @@ namespace Game
typedef int(__cdecl * FS_Write_t)(const void* buffer, size_t size, int file); typedef int(__cdecl * FS_Write_t)(const void* buffer, size_t size, int file);
extern FS_Write_t FS_Write; 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); typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);
extern FS_Read_t FS_Read; extern FS_Read_t FS_Read;