- Версия SA-MP
-
- 0.3.7 (R1)
- 0.3.7-R3
- 0.3.7-R4
прив
не знаю зачем калкор сделал открытие чата через событие WM_CHAR, но этот плагин позволяет исправить эту фигню. благодаря этому чат будет нормально открываться на всех раскладках
какая разница между уже имеющимися аналогами? плагин делает работу такой, какая она была изначально задумана, что позволяет, например, не открывать чат если в инпут имгуи/мимгуи вводится что-либо
ну и ещё поддержка р1, р3-1, р4-2 на месте, без зависимости от клео/сф/муна
аналога на луа нет, а если будет то окажется нестабильным
не знаю зачем калкор сделал открытие чата через событие WM_CHAR, но этот плагин позволяет исправить эту фигню. благодаря этому чат будет нормально открываться на всех раскладках
какая разница между уже имеющимися аналогами? плагин делает работу такой, какая она была изначально задумана, что позволяет, например, не открывать чат если в инпут имгуи/мимгуи вводится что-либо
ну и ещё поддержка р1, р3-1, р4-2 на месте, без зависимости от клео/сф/муна
аналога на луа нет, а если будет то окажется нестабильным
C++:
rtdhook_call* mainloop_hook = nullptr;
bool open_input = false;
enum SampVersion {
SAMP_NOT_LOADED,
SAMP_UNKNOWN,
SAMP_037_R1,
SAMP_037_R3_1,
SAMP_037_R4_2
};
uintptr_t samp_get_base()
{
return reinterpret_cast<uintptr_t>(GetModuleHandleA("samp.dll"));
}
SampVersion samp_get_version()
{
static SampVersion samp_ver = SampVersion::SAMP_NOT_LOADED;
if (samp_ver <= SampVersion::SAMP_UNKNOWN)
{
auto base = samp_get_base();
if (base == 0) return SampVersion::SAMP_NOT_LOADED;
auto* ntHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(base + reinterpret_cast<IMAGE_DOS_HEADER*>(base)->e_lfanew);
auto ep = ntHeader->OptionalHeader.AddressOfEntryPoint;
switch (ep)
{
case 0x31DF13:
samp_ver = SampVersion::SAMP_037_R1;
break;
case 0xCC4D0:
samp_ver = SampVersion::SAMP_037_R3_1;
break;
case 0xCBCB0:
samp_ver = SampVersion::SAMP_037_R4_2;
break;
default:
samp_ver = SampVersion::SAMP_UNKNOWN;
#ifdef _DEBUG
assert(0);
#endif
}
}
return samp_ver;
}
LRESULT CALLBACK handle_wndproc(WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (Msg == WM_KEYDOWN && wParam == 0x54) // T key
{
open_input = true; // Lazy to lock CInput WM_CHAR
return 0;
}
return CallWindowProcA(lpPrevWndFunc, hWnd, Msg, wParam, lParam);
}
void mainloop()
{
static bool once = false;
static SampVersion version = SAMP_NOT_LOADED;
if (!once && *reinterpret_cast<uintptr_t*>(0x00C8D4C0) == 9 && samp_get_base() != 0)
{
once = true;
version = samp_get_version();
if (version >= SAMP_037_R1)
{
uintptr_t override_mem = 0;
uintptr_t hook_ptr = 0;
switch (version)
{
case SAMP_037_R3_1:
override_mem = 0x0613CB;
hook_ptr = 0x0613CB + 1;
break;
case SAMP_037_R4_2:
override_mem = 0x061B3B;
hook_ptr = 0x061B3B + 1;
break;
case SAMP_037_R1:
hook_ptr = 0x05E02B;
break;
}
if (override_mem)
{
DWORD old_protection;
VirtualProtect((LPVOID)(samp_get_base() + override_mem), 2, PAGE_EXECUTE_READWRITE, &old_protection);
*reinterpret_cast<uint16_t*>(samp_get_base() + override_mem) = 0xE890;
VirtualProtect((LPVOID)(samp_get_base() + override_mem), 2, old_protection, &old_protection);
}
if (hook_ptr)
{
auto* hook = new rtdhook_call(samp_get_base() + hook_ptr, &handle_wndproc);
hook->install();
}
}
}
if (open_input)
{
static uintptr_t func_ptr = 0;
if (!func_ptr)
{
switch (version)
{
case SAMP_037_R3_1:
func_ptr = 0x060E20;
break;
case SAMP_037_R4_2:
func_ptr = 0x61590;
break;
case SAMP_037_R1:
func_ptr = 0x5DA80;
break;
}
}
if (func_ptr)
reinterpret_cast<int(*)(WPARAM)>(samp_get_base() + func_ptr)('T');
open_input = false;
}
reinterpret_cast<void(*)()>(mainloop_hook->getHookedFunctionAddress())();
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD fdwReason,
LPVOID lpReserved
)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
mainloop_hook = new rtdhook_call(0x53E968, &mainloop);
mainloop_hook->install();
}
return TRUE;
}