From 8cd99235c0a782eae344e6d5c0a295349a088b8a Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 22 Aug 2021 16:07:23 +0200 Subject: [PATCH] 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;