feature: binds
This commit is contained in:
parent
6158430274
commit
847b6090b2
@ -118,6 +118,8 @@ namespace game
|
|||||||
|
|
||||||
Win_LocalizeRef_t Win_LocalizeRef;
|
Win_LocalizeRef_t Win_LocalizeRef;
|
||||||
|
|
||||||
|
Key_KeynumToString_t Key_KeynumToString;
|
||||||
|
|
||||||
decltype(longjmp)* _longjmp;
|
decltype(longjmp)* _longjmp;
|
||||||
|
|
||||||
CmdArgs* sv_cmd_args;
|
CmdArgs* sv_cmd_args;
|
||||||
@ -174,6 +176,8 @@ namespace game
|
|||||||
|
|
||||||
const char** g_assetNames;
|
const char** g_assetNames;
|
||||||
|
|
||||||
|
const char** command_whitelist;
|
||||||
|
|
||||||
int Vec4Compare(const float* a, const float* b)
|
int Vec4Compare(const float* a, const float* b)
|
||||||
{
|
{
|
||||||
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3];
|
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3];
|
||||||
@ -842,6 +846,8 @@ namespace game
|
|||||||
|
|
||||||
native::Win_LocalizeRef = native::Win_LocalizeRef_t(SELECT_VALUE(0x49D7E0, 0x5CBE90));
|
native::Win_LocalizeRef = native::Win_LocalizeRef_t(SELECT_VALUE(0x49D7E0, 0x5CBE90));
|
||||||
|
|
||||||
|
native::Key_KeynumToString = native::Key_KeynumToString_t(SELECT_VALUE(0x4BB000, 0x48C080));
|
||||||
|
|
||||||
native::_longjmp = reinterpret_cast<decltype(longjmp)*>(SELECT_VALUE(0x73AC20, 0x7363BC));
|
native::_longjmp = reinterpret_cast<decltype(longjmp)*>(SELECT_VALUE(0x73AC20, 0x7363BC));
|
||||||
|
|
||||||
native::sv_cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1757218, 0x1CAA998));
|
native::sv_cmd_args = reinterpret_cast<native::CmdArgs*>(SELECT_VALUE(0x1757218, 0x1CAA998));
|
||||||
@ -903,5 +909,7 @@ namespace game
|
|||||||
native::db_hashCritSect = reinterpret_cast<native::FastCriticalSection*>(SELECT_VALUE(0xFA9E7C, 0x18596E4));
|
native::db_hashCritSect = reinterpret_cast<native::FastCriticalSection*>(SELECT_VALUE(0xFA9E7C, 0x18596E4));
|
||||||
|
|
||||||
native::g_assetNames = reinterpret_cast<const char**>(SELECT_VALUE(0x92A688, 0x8AAB30));
|
native::g_assetNames = reinterpret_cast<const char**>(SELECT_VALUE(0x92A688, 0x8AAB30));
|
||||||
|
|
||||||
|
native::command_whitelist = reinterpret_cast<const char**>(SELECT_VALUE(0x929FA0, 0x8AA3B8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,10 @@ namespace game
|
|||||||
extern LargeLocalResetToMark_t LargeLocalResetToMark;
|
extern LargeLocalResetToMark_t LargeLocalResetToMark;
|
||||||
|
|
||||||
typedef const char* (*Win_LocalizeRef_t)(const char* ref);
|
typedef const char* (*Win_LocalizeRef_t)(const char* ref);
|
||||||
extern Win_LocalizeRef_t Win_LocalizeRer;
|
extern Win_LocalizeRef_t Win_LocalizeRef;
|
||||||
|
|
||||||
|
typedef const char* (*Key_KeynumToString_t)(int keynum, int translate);
|
||||||
|
extern Key_KeynumToString_t Key_KeynumToString;
|
||||||
|
|
||||||
extern decltype(longjmp)* _longjmp;
|
extern decltype(longjmp)* _longjmp;
|
||||||
|
|
||||||
@ -308,6 +311,8 @@ namespace game
|
|||||||
|
|
||||||
extern const char** g_assetNames;
|
extern const char** g_assetNames;
|
||||||
|
|
||||||
|
extern const char** command_whitelist;
|
||||||
|
|
||||||
// Global Definitions & Functions
|
// Global Definitions & Functions
|
||||||
constexpr auto JUMP_LAND_SLOWDOWN_TIME = 1800;
|
constexpr auto JUMP_LAND_SLOWDOWN_TIME = 1800;
|
||||||
|
|
||||||
|
@ -1399,6 +1399,43 @@ namespace game
|
|||||||
|
|
||||||
static_assert(sizeof(fileHandleData_t) == 0x11C);
|
static_assert(sizeof(fileHandleData_t) == 0x11C);
|
||||||
|
|
||||||
|
struct field_t
|
||||||
|
{
|
||||||
|
int cursor;
|
||||||
|
int scroll;
|
||||||
|
int drawWidth;
|
||||||
|
int widthInPixels;
|
||||||
|
float charHeight;
|
||||||
|
int fixedSize;
|
||||||
|
char buffer[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LocSelInputState
|
||||||
|
{
|
||||||
|
LOC_SEL_INPUT_NONE = 0x0,
|
||||||
|
LOC_SEL_INPUT_CONFIRM = 0x1,
|
||||||
|
LOC_SEL_INPUT_CANCEL = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyState
|
||||||
|
{
|
||||||
|
int down;
|
||||||
|
int repeats;
|
||||||
|
int binding;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlayerKeyState
|
||||||
|
{
|
||||||
|
field_t chatField;
|
||||||
|
int chat_team;
|
||||||
|
int overstrikeMode;
|
||||||
|
int anyKeyDown;
|
||||||
|
KeyState keys[256];
|
||||||
|
LocSelInputState locSelInputState;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(PlayerKeyState) == 0xD28);
|
||||||
|
|
||||||
namespace mp
|
namespace mp
|
||||||
{
|
{
|
||||||
enum ConfigString
|
enum ConfigString
|
||||||
|
147
src/module/binding.cpp
Normal file
147
src/module/binding.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include <loader/module_loader.hpp>
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::vector<std::string> custom_binds;
|
||||||
|
|
||||||
|
utils::hook::detour key_get_binding_for_cmd_hook;
|
||||||
|
|
||||||
|
utils::hook::detour cl_execute_key_hook;
|
||||||
|
|
||||||
|
game::native::KeyState* keys;
|
||||||
|
|
||||||
|
int key_write_bindings_to_buffer([[maybe_unused]] int local_client_num, char* buffer, int buffer_size)
|
||||||
|
{
|
||||||
|
buffer_size = buffer_size - 4;
|
||||||
|
auto bytes_used = 0;
|
||||||
|
|
||||||
|
for (auto keyIndex = 0; keyIndex < 256; ++keyIndex)
|
||||||
|
{
|
||||||
|
if (keys[keyIndex].binding && keys[keyIndex].binding < 91)
|
||||||
|
{
|
||||||
|
auto len = sprintf_s(&buffer[bytes_used], buffer_size - bytes_used, "bind %s \"%s\"\n",
|
||||||
|
game::native::Key_KeynumToString(keyIndex, false), game::native::command_whitelist[keys[keyIndex].binding]);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_used += len;
|
||||||
|
}
|
||||||
|
else if (keys[keyIndex].binding >= 91)
|
||||||
|
{
|
||||||
|
auto value = keys[keyIndex].binding - 91;
|
||||||
|
if (static_cast<std::size_t>(value) < custom_binds.size() && !custom_binds[value].empty())
|
||||||
|
{
|
||||||
|
auto len = sprintf_s(&buffer[bytes_used], buffer_size - bytes_used, "bind %s \"%s\"\n",
|
||||||
|
game::native::Key_KeynumToString(keyIndex, false), custom_binds[value].data());
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_used += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[bytes_used] = '\0';
|
||||||
|
return bytes_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void key_write_bindings_to_buffer_stub()
|
||||||
|
{
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push [esp + 0x20 + 0x8] // bufferSize
|
||||||
|
push [esp + 0x20 + 0x8] // buffer
|
||||||
|
push eax // localClientNum
|
||||||
|
call key_write_bindings_to_buffer
|
||||||
|
add esp, 0xC
|
||||||
|
|
||||||
|
popad
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_binding_for_custom_command(const char* command)
|
||||||
|
{
|
||||||
|
auto index = 0;
|
||||||
|
for (const auto& bind : custom_binds)
|
||||||
|
{
|
||||||
|
if (bind == command)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
custom_binds.emplace_back(command);
|
||||||
|
index = static_cast<int>(custom_binds.size()) - 1;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int key_get_binding_for_cmd_stub(const char* command)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i <= 91; i++)
|
||||||
|
{
|
||||||
|
if (game::native::command_whitelist[i] && !std::strcmp(command, game::native::command_whitelist[i]))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 91 + get_binding_for_custom_command(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cl_execute_key_stub(game::native::LocalClientNum_t local_client_num, int key, int down)
|
||||||
|
{
|
||||||
|
if (key >= 91)
|
||||||
|
{
|
||||||
|
key -= 91;
|
||||||
|
|
||||||
|
if (static_cast<std::uint32_t>(key) < custom_binds.size() && !custom_binds[key].empty())
|
||||||
|
{
|
||||||
|
game::native::Cbuf_AddText(local_client_num, utils::string::va("%s\n", custom_binds[key].data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_execute_key_hook.invoke<void>(local_client_num, key, down);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class binding final : public module
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_load() override
|
||||||
|
{
|
||||||
|
if (game::is_sp())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = reinterpret_cast<game::native::KeyState*>(0xB3C760);
|
||||||
|
|
||||||
|
utils::hook(0x48C53A, key_write_bindings_to_buffer_stub, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
|
key_get_binding_for_cmd_hook.create(0x48C1C0, &key_get_binding_for_cmd_stub);
|
||||||
|
|
||||||
|
cl_execute_key_hook.create(0x48AF00, cl_execute_key_stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
REGISTER_MODULE(binding)
|
Loading…
Reference in New Issue
Block a user