Write gamepad axis configuration to config file
This commit is contained in:
parent
dcbb120de1
commit
8cd99235c0
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user