custom native ui & client script functions (#52)

* custom native ui & client script functions

* spacing is hard

* sq_pushbool, sq_pushstring, sq_getstring, sq_getinteger

* sq_pushinteger, sq_newarray, sq_arrayappend, sq_newtable, sq_newslot

* Re-factored code.

Co-authored-by: IcePixelx <41352111+PixieCore@users.noreply.github.com>
This commit is contained in:
r-ex 2021-09-14 16:25:22 +01:00 committed by GitHub
parent b42e85b1f4
commit 25c5a5c9af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 202 additions and 1 deletions

View File

@ -456,6 +456,33 @@ struct Interface
__int64* NextInterfacePtr;
};
struct SQFuncRegistration
{
const char* scriptName; // 00
const char* nativeName; // 08
const char* helpString; // 10
const char* retValType; // 18
const char* argTypes; // 20
int16_t unk28; // 28
int16_t padding1; // 2A
int32_t unk2c; // 2C
int64_t unk30; // 30
int32_t unk38; // 38
int32_t padding2; // 3C
int64_t unk40; // 40
int64_t unk48; // 48
int64_t unk50; // 50
int32_t unk58; // 58
int32_t padding3; // 5C
void* funcPtr; // 60
SQFuncRegistration()
{
memset(this, 0, sizeof(SQFuncRegistration));
this->padding2 = 6;
}
};
/////////////////////////////////////////////////////////////////////////////
// Initialize Game Globals
@ -474,11 +501,17 @@ namespace GameGlobals
ConVar* CreateCustomConVar(const char* name, const char* defaultValue, int flags, const char* helpString, bool bMin, float fMin, bool bMax, float fMax, void* callback, void* unk);
void* CreateCustomConCommand(const char* name, const char* helpString, int flags, void* callback, void* callbackAfterExecution);
// Script
void Script_RegisterFunction(void* sqvm, const char* name, const char* helpString, const char* retValType, const char* argTypes, void* funcPtr);
void RegisterUIScriptFunctions(void* sqvm);
void RegisterClientScriptFunctions(void* sqvm);
// Init
void InitGameGlobals();
void InitAllCommandVariations();
void InitPlaylist();
extern std::vector<std::string> allPlaylists;
extern bool IsInitialized;

View File

@ -25,6 +25,7 @@ namespace Hooks
__int64 SQVM_Warning(void* sqvm, int a2, int a3, int* stringSize, void** string);
__int64 SQVM_LoadRson(const char* rson_name);
bool SQVM_LoadScript(void* sqvm, const char* script_path, const char* script_name, int flag);
void SQVM_RegisterOriginFuncs(void* sqvm);
using SQVM_WarningFn = __int64(*)(void*, int, int, int*, void**);
extern SQVM_WarningFn originalSQVM_Warning;
@ -34,6 +35,9 @@ namespace Hooks
using SQVM_LoadScriptFn = bool(*)(void*, const char*, const char*, int);
extern SQVM_LoadScriptFn originalSQVM_LoadScript;
using SQVM_RegisterOriginFuncsFn = void(*)(void*);
extern SQVM_RegisterOriginFuncsFn originalSQVM_RegisterOriginFuncs;
#pragma endregion
#pragma region CServer

View File

@ -29,6 +29,27 @@ namespace
/*0x140B1E55*/
FUNC_AT_ADDRESS(addr_SQVM_Warning_ReturnAddr, void*, r5_patterns.PatternSearch("E8 ? ? ? ? 85 C0 0F 99 C3").OffsetSelf(0x5).GetPtr());
/*0x141061A50*/
FUNC_AT_ADDRESS(addr_sq_pushstring, void(*)(void*, char*, __int64), r5_patterns.PatternSearch("E8 ? ? ? ? 8D 55 FE").FollowNearCall().GetPtr());
/*0x141061CD0*/
FUNC_AT_ADDRESS(addr_sq_pushbool, void(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 41 0F B6 17").FollowNearCall().GetPtr());
/*0x141061C70*/
FUNC_AT_ADDRESS(addr_sq_pushinteger, void(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 41 0F B7 17").FollowNearCall().GetPtr());
/*0x141062040*/
FUNC_AT_ADDRESS(addr_sq_newarray, void(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 49 63 F5").FollowNearCall().GetPtr());
/*0x1410621F0*/
FUNC_AT_ADDRESS(addr_sq_arrayappend, __int64(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 49 63 46 38").FollowNearCall().GetPtr());
/*0x141061FB0*/
FUNC_AT_ADDRESS(addr_sq_newtable, void(*)(void*), r5_patterns.PatternSearch("E8 ? ? ? ? 83 C6 04").FollowNearCall().GetPtr());
/*0x141064250*/
FUNC_AT_ADDRESS(addr_sq_newslot, __int64(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 49 63 46 18").FollowNearCall().GetPtr());
//DWORD64 p_SQVM_LoadScript = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // For S0 and S1
/*0x141055630*/
@ -37,6 +58,9 @@ namespace
/*0x140C957E0*/
FUNC_AT_ADDRESS(addr_SQVM_LoadRson, int(*)(const char*), r5_patterns.PatternSearch("4C 8B DC 49 89 5B 08 57 48 81 EC A0 00 00 00 33").GetPtr());
/*0x140834A00*/
FUNC_AT_ADDRESS(addr_SQVM_RegisterOriginFuncs, void(*)(void*), r5_patterns.PatternSearch("E8 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 48 8B 05 ? ? ? ? C7 05 ? ? ? ? ? ? ? ?").FollowNearCall().GetPtr());
#pragma endregion
#pragma region NetChannel
@ -56,7 +80,6 @@ namespace
MemoryAddress addr_NetChan_EncKeyPtr = MemoryAddress(0x160686DC0);
char* addr_NetChan_EncKey = addr_NetChan_EncKeyPtr.Offset(4816).RCast<char*>();
/*0x140263E70*/
FUNC_AT_ADDRESS(addr_NetChan_SetEncKey, void(*)(uintptr_t, const char*), MemoryAddress(0x140263E70).GetPtr());
@ -132,18 +155,32 @@ namespace
PRINT_ADDRESS("SQVM_LoadRson", addr_SQVM_LoadRson);
PRINT_ADDRESS("SQVM_Warning", addr_SQVM_Warning);
PRINT_ADDRESS("SQVM_Warning_ReturnAddr", addr_SQVM_Warning_ReturnAddr);
PRINT_ADDRESS("SQVM_RegisterOriginFuncs", addr_SQVM_RegisterOriginFuncs);
PRINT_ADDRESS("sq_arrayappend", addr_sq_arrayappend);
PRINT_ADDRESS("sq_newarray", addr_sq_newarray);
PRINT_ADDRESS("sq_newslot", addr_sq_newslot);
PRINT_ADDRESS("sq_newtable", addr_sq_newtable);
PRINT_ADDRESS("sq_pushbool", addr_sq_pushbool);
PRINT_ADDRESS("sq_pushinteger", addr_sq_pushinteger);
PRINT_ADDRESS("sq_pushstring", addr_sq_pushstring);
PRINT_ADDRESS("NET_PrintFunc", addr_NET_PrintFunc);
PRINT_ADDRESS("NET_ReceiveDatagram", addr_NET_ReceiveDatagram);
PRINT_ADDRESS("NET_SendDatagram ", addr_NET_SendDatagram);
PRINT_ADDRESS("CClientState::m_bRestrictServerCommands", addr_m_bRestrictServerCommands);
PRINT_ADDRESS("CClient::Clear", addr_CClient_Clear);
PRINT_ADDRESS("INetChannel::Shutdown", addr_NetChan_Shutdown);
PRINT_ADDRESS("INetChannel::SetEncryptionKey", addr_NetChan_SetEncKey);
PRINT_ADDRESS("INetChannel::EncryptionKey", addr_NetChan_EncKey)
PRINT_ADDRESS("CHLClient::FrameStageNotify", addr_CHLClient_FrameStageNotify);
PRINT_ADDRESS("CVEngineServer::IsPersistenceDataAvailable", addr_CVEngineServer_IsPersistenceDataAvailable);
PRINT_ADDRESS("CServer::ConnectClient", addr_CServer_ConnectClient);
PRINT_ADDRESS("CServer::RejectConnection", addr_CServer_RejectConnection);
PRINT_ADDRESS("CBaseFileSystem::FileSystemWarning", addr_CBaseFileSystem_FileSystemWarning);
PRINT_ADDRESS("MSG_EngineError", addr_MSG_EngineError);
PRINT_ADDRESS("LoadPlaylist", addr_LoadPlaylist);
PRINT_ADDRESS("MapVPKCache", addr_MapVPKCache);
PRINT_ADDRESS("MemAlloc_Wrapper", addr_MemAlloc_Wrapper);
PRINT_ADDRESS("KeyValues::FindKey", addr_KeyValues_FindKey);
std::cout << "+--------------------------------------------------------+" << std::endl;
// TODO implement error handling when sigscan fails or result is 0
}

14
r5dev/include/squirrel.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
char* sq_getstring(void* sqvm, int i);
int sq_getinteger(void* sqvm, int i);
void sq_pushbool(void* sqvm, int val);
void sq_pushstring(void* sqvm, char* string, int len);
void sq_pushinteger(void* sqvm, int val);
void sq_newarray(void* sqvm, int size);
void sq_arrayappend(void* sqvm, int idx);
void sq_newtable(void* sqvm);
void sq_newslot(void* sqvm, int idx);

View File

@ -328,6 +328,7 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib (
<ClInclude Include="include\patterns.h" />
<ClInclude Include="include\pch.h" />
<ClInclude Include="include\r5dev.h" />
<ClInclude Include="include\squirrel.h" />
<ClInclude Include="include\structs.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
@ -413,6 +414,10 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib (
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
</ClCompile>
<ClCompile Include="src\squirrel.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Use</PrecompiledHeader>
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="r5dev.def" />

View File

@ -201,6 +201,9 @@
<ClCompile Include="src\hooks\connectclient.cpp">
<Filter>hooks\src\cserver</Filter>
</ClCompile>
<ClCompile Include="src\squirrel.cpp">
<Filter>r5-sdk\src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\external\imgui\include\imgui_impl_win32.h">
@ -573,6 +576,9 @@
<ClInclude Include="..\shared\include\banlist.h">
<Filter>shared\include</Filter>
</ClInclude>
<ClInclude Include="include\squirrel.h">
<Filter>r5-sdk\include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="r5dev.def">

View File

@ -2,6 +2,7 @@
#include "gameclasses.h"
#include "id3dx.h"
#include "cgameconsole.h"
#include "squirrel.h"
// Need this for a re-factor later.
// Interface* interfaces = *reinterpret_cast<Interface**>(0x167F4FA48);
@ -460,6 +461,39 @@ namespace GameGlobals
return allocatedConvar; // Return allocated ConVar.
}
void Script_RegisterFunction(void* sqvm, const char* name, const char* helpString, const char* retValType, const char* argTypes, void* funcPtr)
{
static MemoryAddress Script_RegisterFunction = MemoryAddress(0x141056040);
SQFuncRegistration* func = new SQFuncRegistration();
func->scriptName = name;
func->nativeName = name;
func->helpString = helpString;
func->retValType = retValType;
func->argTypes = argTypes;
func->funcPtr = funcPtr;
Script_RegisterFunction.RCast<void(*)(void*, SQFuncRegistration*, char unk)>()(sqvm, func, 1);
}
int Script_NativeTest(void* sqvm)
{
// function code goes here
return 1;
}
void RegisterUIScriptFunctions(void* sqvm)
{
// Script_RegisterFunction(sqvm, "UINativeTest", "native ui function", "void", "", &Script_NativeTest);
}
void RegisterClientScriptFunctions(void* sqvm)
{
// Script_RegisterFunction(sqvm, "ClientNativeTest", "native client function", "void", "", &Script_NativeTest);
}
void DisconnectClient(CClient* client, const char* reason, unsigned __int8 unk1, char unk2)
{
if (!client) // Client valid?

View File

@ -21,6 +21,7 @@ void Hooks::InstallHooks()
MH_CreateHook(addr_SQVM_Warning, &Hooks::SQVM_Warning, reinterpret_cast<void**>(&originalSQVM_Warning));
MH_CreateHook(addr_SQVM_LoadRson, &Hooks::SQVM_LoadRson, reinterpret_cast<void**>(&originalSQVM_LoadRson));
MH_CreateHook(addr_SQVM_LoadScript, &Hooks::SQVM_LoadScript, reinterpret_cast<void**>(&originalSQVM_LoadScript));
MH_CreateHook(addr_SQVM_RegisterOriginFuncs, &Hooks::SQVM_RegisterOriginFuncs, reinterpret_cast<void**>(&originalSQVM_RegisterOriginFuncs));
///////////////////////////////////////////////////////////////////////////////
// Hook Game Functions
@ -77,6 +78,7 @@ void Hooks::InstallHooks()
MH_EnableHook(addr_SQVM_Warning);
MH_EnableHook(addr_SQVM_LoadRson);
MH_EnableHook(addr_SQVM_LoadScript);
MH_EnableHook(addr_SQVM_RegisterOriginFuncs);
///////////////////////////////////////////////////////////////////////////////
// Enable Game hooks
@ -111,6 +113,7 @@ void Hooks::RemoveHooks()
MH_RemoveHook(addr_SQVM_Print);
MH_RemoveHook(addr_SQVM_LoadRson);
MH_RemoveHook(addr_SQVM_LoadScript);
MH_RemoveHook(addr_SQVM_RegisterOriginFuncs);
///////////////////////////////////////////////////////////////////////////////
// Unhook Game Functions

View File

@ -6,6 +6,7 @@ namespace Hooks
SQVM_WarningFn originalSQVM_Warning = nullptr;
SQVM_LoadRsonFn originalSQVM_LoadRson = nullptr;
SQVM_LoadScriptFn originalSQVM_LoadScript = nullptr;
SQVM_RegisterOriginFuncsFn originalSQVM_RegisterOriginFuncs = nullptr;
}
static std::ostringstream oss_print;
@ -178,4 +179,17 @@ bool Hooks::SQVM_LoadScript(void* sqvm, const char* script_path, const char* scr
}
return originalSQVM_LoadScript(sqvm, script_path, script_name, flag);
}
void Hooks::SQVM_RegisterOriginFuncs(void* sqvm) {
static MemoryAddress UIVM = MemoryAddress(0x14D4151F0);
originalSQVM_RegisterOriginFuncs(sqvm);
if (sqvm == *(UIVM.RCast<void**>())) {
GameGlobals::RegisterUIScriptFunctions(sqvm);
}
else {
GameGlobals::RegisterClientScriptFunctions(sqvm);
}
}

51
r5dev/src/squirrel.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "pch.h"
#include "patterns.h"
char* sq_getstring(void* sqvm, int i)
{
std::uintptr_t thisptr = reinterpret_cast<std::uintptr_t>(sqvm);
return *(char**)(*(__int64*)(thisptr + 0x58) + 0x10 * i + 0x8) + 0x40;
}
int sq_getinteger(void* sqvm, int i)
{
std::uintptr_t thisptr = reinterpret_cast<std::uintptr_t>(sqvm);
return *(int*)(*(__int64*)(thisptr + 0x58) + 0x10 * i + 0x8);
}
void sq_pushbool(void* sqvm, int val)
{
addr_sq_pushbool(sqvm, val);
}
void sq_pushstring(void* sqvm, char* string, int len)
{
addr_sq_pushstring(sqvm, string, len);
}
void sq_pushinteger(void* sqvm, int val)
{
addr_sq_pushinteger(sqvm, val);
}
void sq_newarray(void* sqvm, int size)
{
addr_sq_newarray(sqvm, size);
}
void sq_arrayappend(void* sqvm, int idx)
{
addr_sq_arrayappend(sqvm, idx);
}
void sq_newtable(void* sqvm)
{
addr_sq_newtable(sqvm);
}
void sq_newslot(void* sqvm, int idx)
{
addr_sq_newslot(sqvm, idx);
}