From 27c085482fd62bad298e14a3b4dd6ded9416909d Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:21:17 +0200 Subject: [PATCH 01/11] Tier0: double sigscan mask buffer Some common (future) function signatures exceed this, which don't have other means of accessing it. --- src/tier0/module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tier0/module.cpp b/src/tier0/module.cpp index bd25aa1e..ee299bc6 100644 --- a/src/tier0/module.cpp +++ b/src/tier0/module.cpp @@ -123,7 +123,7 @@ CMemory CModule::FindPatternSIMD(const uint8_t* pPattern, const char* szMask, const uint8_t* pEnd = pData + nSize - nMaskLen; size_t nOccurrenceCount = 0; - int nMasks[64]; // 64*16 = enough masks for 1024 bytes. + int nMasks[128]; // 128*16 = enough masks for 2048 bytes. const int iNumMasks = static_cast(ceil(static_cast(nMaskLen) / 16.f)); memset(nMasks, '\0', iNumMasks * sizeof(int)); From 8c2400bab5c2ab3268b8953052c3fbecd097e58d Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:21:43 +0200 Subject: [PATCH 02/11] VScript: add 'sq_getentity' to SDK --- src/vscript/languages/squirrel_re/include/squirrel.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vscript/languages/squirrel_re/include/squirrel.h b/src/vscript/languages/squirrel_re/include/squirrel.h index 74a268cb..5bc73f6e 100644 --- a/src/vscript/languages/squirrel_re/include/squirrel.h +++ b/src/vscript/languages/squirrel_re/include/squirrel.h @@ -60,6 +60,7 @@ typedef uint64 SQHash; /*should be the same size of a pointer*/ typedef float SQFloat; typedef void* SQFunctor; +typedef void* SQEntity; typedef SQUnsignedInteger SQBool; typedef SQInteger SQRESULT; @@ -231,6 +232,7 @@ inline SQRESULT(*v_sq_pushstructure)(HSQUIRRELVM v, const SQChar* name, const SQ inline SQRESULT(*v_sq_compilebuffer)(HSQUIRRELVM v, SQBufState* bufferstate, const SQChar* buffer, SQInteger level, SQBool raiseerror); inline SQRESULT(*v_sq_call)(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror); inline SQRESULT(*v_sq_get)(HSQUIRRELVM v, SQInteger idx); +inline bool (*v_sq_getentity)(HSQUIRRELVM v, SQEntity* ent); inline SQRESULT (*v_sq_startconsttable)(HSQUIRRELVM v); inline SQRESULT (*v_sq_endconsttable)(HSQUIRRELVM v); @@ -261,6 +263,7 @@ class VSquirrelAPI : public IDetour LogFunAdr("sq_compilebuffer", v_sq_compilebuffer); LogFunAdr("sq_call", v_sq_call); LogFunAdr("sq_get", v_sq_get); + LogFunAdr("sq_getentity", v_sq_getentity); LogFunAdr("sq_startconsttable", v_sq_startconsttable); LogFunAdr("sq_endconsttable", v_sq_endconsttable); @@ -285,6 +288,7 @@ class VSquirrelAPI : public IDetour g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC 50 41 8B E9 49 8B F8").GetPtr(v_sq_compilebuffer); g_GameDll.FindPatternSIMD("4C 8B DC 49 89 5B 08 49 89 6B 10 49 89 73 18 57 48 83 EC 50 8B F2").GetPtr(v_sq_call); g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 48 8B F9 8B 49 78").GetPtr(v_sq_get); + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 41 ?? 48 8B FA 48 8B D9 F7 00").GetPtr(v_sq_getentity); g_GameDll.FindPatternSIMD("8B 51 78 4C 8B 49 60 44 8B C2 49 C1 E0 04 4C 03 81 ?? ?? ?? ?? 8D 42 01 89 41 78 41 F7 81 ?? ?? ?? ?? ?? ?? ?? ?? 74 0A 49 8B 81 ?? ?? ?? ?? FF 40 08 41 F7 00 ?? ?? ?? ?? 41 0F 10 81 ?? ?? ?? ?? 74 15").GetPtr(v_sq_startconsttable); g_GameDll.FindPatternSIMD("8B 41 78 45 33 C0 FF C8 8B D0 89 41 78 48 C1 E2 04 48 03 91 ?? ?? ?? ?? 8B 02 48 C7 02 ?? ?? ?? ?? 25 ?? ?? ?? ?? 74 15").GetPtr(v_sq_endconsttable); From 97fb6c91d39241ce8e4ba45ddb49442684543884 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:34:56 +0200 Subject: [PATCH 03/11] VScript: add code class descriptor class Used for script class functions, e.g. player.GetOrigin(). --- src/public/vscript/ivscript.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/public/vscript/ivscript.h b/src/public/vscript/ivscript.h index 4cf0ee93..f0f8383b 100644 --- a/src/public/vscript/ivscript.h +++ b/src/public/vscript/ivscript.h @@ -100,4 +100,36 @@ struct ScriptFunctionBinding_t }; static_assert(sizeof(ScriptFunctionBinding_t) == 0x68); +//--------------------------------------------------------- + +struct ScriptClassDescriptor_t +{ + void AddFunction(const SQChar* scriptName, const SQChar* nativeName, + const SQChar* helpString, const SQChar* returnString, + const SQChar* parameters, const ScriptDataType_t returnType, + const ScriptFunctionBindingStorageType_t function) + { + const int index = m_FunctionBindings.AddToTail(); + ScriptFunctionBinding_t& binding = m_FunctionBindings.Element(index); + + binding.Init(scriptName, nativeName, helpString, returnString, parameters, returnType, function); + } + + const char* m_ScriptName; + const char* m_Classname; + const char* m_Description; + + ScriptClassDescriptor_t* m_BaseDesc; + CUtlVector m_FunctionBindings; + + // TODO: CUtlMemory? + ssize_t m_Unk1; + ssize_t m_Unk2; + void* m_Unk3; + + ScriptClassDescriptor_t* m_NextDesc; +}; + +static_assert(sizeof(ScriptClassDescriptor_t) == 0x60); + #endif // IVSCRIPT_H From 3b3127c2cffda42af215b4a1777a3b56d1057371 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:36:20 +0200 Subject: [PATCH 04/11] VScript: add code class script globals and registraction callbacks Will be used to register custom script class functions. --- src/core/init.cpp | 6 ++ src/game/client/vscript_client.cpp | 95 ++++++++++++++++++++++++++ src/game/client/vscript_client.h | 83 ++++++++++++++++++++++ src/game/server/vscript_server.cpp | 106 +++++++++++++++++++++++++++++ src/game/server/vscript_server.h | 91 +++++++++++++++++++++++++ 5 files changed, 381 insertions(+) diff --git a/src/core/init.cpp b/src/core/init.cpp index a45be9dc..7b867923 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -647,6 +647,12 @@ void DetourRegister() // Register detour classes to be searched and hooked. REGISTER(VSquirrel); REGISTER(VScript); REGISTER(VScriptShared); +#ifndef CLIENT_DLL + REGISTER(VScriptServer); +#endif // !CLIENT_DLL +#ifndef DEDICATED + REGISTER(VScriptClient); +#endif // !DEDICATED // Squirrel REGISTER(VSquirrelAPI); diff --git a/src/game/client/vscript_client.cpp b/src/game/client/vscript_client.cpp index e91fa0bc..673b2577 100644 --- a/src/game/client/vscript_client.cpp +++ b/src/game/client/vscript_client.cpp @@ -513,3 +513,98 @@ static ConVar promo_version_accepted("promo_version_accepted", "0", FCVAR_RELEAS static ConVar player_setting_damage_closes_deathbox_menu("player_setting_damage_closes_deathbox_menu", "1", FCVAR_ARCHIVE | FCVAR_RELEASE, "Controls whether death box automatically closes when taking damage (used for menus)."); static ConVar show_motd_on_server_first_join("show_motd_on_server_first_join", "0", FCVAR_ARCHIVE | FCVAR_RELEASE, "Controls whether or not the server message of the day shows on first join for that server."); + +//--------------------------------------------------------------------------------- +// Purpose: script code class function registration +//--------------------------------------------------------------------------------- +static void Script_RegisterClientEntityClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientPlayerClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientAIClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientWeaponClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientProjectileClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientTitanSoulClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientPlayerDecoyClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterClientFirstPersonProxyClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} + +void VScriptClient::Detour(const bool bAttach) const +{ + DetourSetup(&v_Script_RegisterClientEntityClassFuncs, &Script_RegisterClientEntityClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientPlayerClassFuncs, &Script_RegisterClientPlayerClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientAIClassFuncs, &Script_RegisterClientAIClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientWeaponClassFuncs, &Script_RegisterClientWeaponClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientProjectileClassFuncs, &Script_RegisterClientProjectileClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientTitanSoulClassFuncs, &Script_RegisterClientTitanSoulClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientPlayerDecoyClassFuncs, &Script_RegisterClientPlayerDecoyClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterClientFirstPersonProxyClassFuncs, &Script_RegisterClientFirstPersonProxyClassFuncs, bAttach); +} diff --git a/src/game/client/vscript_client.h b/src/game/client/vscript_client.h index a2066ba4..db04913c 100644 --- a/src/game/client/vscript_client.h +++ b/src/game/client/vscript_client.h @@ -37,4 +37,87 @@ void Script_RegisterCoreClientFunctions(CSquirrelVM* s); s->RegisterFunction(#functionName, MKSTRING(Script_##functionName), \ helpString, returnType, parameters, VScriptCode::Client::##functionName); \ +inline void (*v_Script_RegisterClientEntityClassFuncs)(); +inline void (*v_Script_RegisterClientPlayerClassFuncs)(); +inline void (*v_Script_RegisterClientAIClassFuncs)(); +inline void (*v_Script_RegisterClientWeaponClassFuncs)(); +inline void (*v_Script_RegisterClientProjectileClassFuncs)(); +inline void (*v_Script_RegisterClientTitanSoulClassFuncs)(); +inline void (*v_Script_RegisterClientPlayerDecoyClassFuncs)(); +inline void (*v_Script_RegisterClientFirstPersonProxyClassFuncs)(); + +inline ScriptClassDescriptor_t* g_clientScriptEntityStruct; +inline ScriptClassDescriptor_t* g_clientScriptPlayerStruct; +inline ScriptClassDescriptor_t* g_clientScriptAIStruct; +inline ScriptClassDescriptor_t* g_clientScriptWeaponStruct; +inline ScriptClassDescriptor_t* g_clientScriptProjectileStruct; +inline ScriptClassDescriptor_t* g_clientScriptTitanSoulStruct; +inline ScriptClassDescriptor_t* g_clientScriptPlayerDecoyStruct; +inline ScriptClassDescriptor_t* g_clientScriptFirstPersonProxyStruct; + +/////////////////////////////////////////////////////////////////////////////// +class VScriptClient : public IDetour +{ + virtual void GetAdr(void) const + { + LogFunAdr("Script_RegisterClientEntityClassFuncs", v_Script_RegisterClientEntityClassFuncs); + LogFunAdr("Script_RegisterClientPlayerClassFuncs", v_Script_RegisterClientPlayerClassFuncs); + LogFunAdr("Script_RegisterClientAIClassFuncs", v_Script_RegisterClientAIClassFuncs); + LogFunAdr("Script_RegisterClientWeaponClassFuncs", v_Script_RegisterClientWeaponClassFuncs); + LogFunAdr("Script_RegisterClientProjectileClassFuncs", v_Script_RegisterClientProjectileClassFuncs); + LogFunAdr("Script_RegisterClientTitanSoulClassFuncs", v_Script_RegisterClientTitanSoulClassFuncs); + LogFunAdr("Script_RegisterClientPlayerDecoyClassFuncs", v_Script_RegisterClientPlayerDecoyClassFuncs); + LogFunAdr("Script_RegisterClientFirstPersonProxyClassFuncs", v_Script_RegisterClientFirstPersonProxyClassFuncs); + + LogVarAdr("g_clientScriptEntityStruct", g_clientScriptEntityStruct); + LogVarAdr("g_clientScriptPlayerStruct", g_clientScriptPlayerStruct); + LogVarAdr("g_clientScriptAIStruct", g_clientScriptAIStruct); + LogVarAdr("g_clientScriptWeaponStruct", g_clientScriptWeaponStruct); + LogVarAdr("g_clientScriptProjectileStruct", g_clientScriptProjectileStruct); + LogVarAdr("g_clientScriptTitanSoulStruct", g_clientScriptTitanSoulStruct); + LogVarAdr("g_clientScriptPlayerDecoyStruct", g_clientScriptPlayerDecoyStruct); + LogVarAdr("g_clientScriptFirstPersonProxyStruct", g_clientScriptFirstPersonProxyStruct); + } + virtual void GetFun(void) const + { + g_GameDll.FindPatternSIMD("40 55 48 8B EC 48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 C7 05") + .GetPtr(v_Script_RegisterClientEntityClassFuncs); + + g_GameDll.FindPatternSIMD("40 55 48 8B EC 48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 C7 05 ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 48 6B C1 ?? 48 8D 0D ?? ?? ?? ?? 48 03 05 ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C6 40 ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 89 08 48 8D 0D ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 48 6B C1 ?? 48 8D 0D ?? ?? ?? ?? 48 03 05 ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C6 40 ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 89 08 48 8D 0D ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 4C 8D 45 ?? 48 6B D9 ?? 48 8D 05") + .GetPtr(v_Script_RegisterClientPlayerClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 63 1D") + .GetPtr(v_Script_RegisterClientAIClassFuncs); + + g_GameDll.FindPatternSIMD("40 55 48 8B EC 48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 C7 05 ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 48 6B C1 ?? 48 8D 0D ?? ?? ?? ?? 48 03 05 ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C6 40 ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 89 08 48 8D 0D ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 48 6B C1 ?? 48 8D 0D ?? ?? ?? ?? 48 03 05 ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C6 40 ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 89 08 48 8D 0D ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 4C 8D 45 ?? 48 6B D9 ?? C7 45") + .GetPtr(v_Script_RegisterClientWeaponClassFuncs); + + g_GameDll.FindPatternSIMD("48 8B C4 48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 89 58 ?? 48 63 1D ?? ?? ?? ?? 48 89 68 ?? 33 ED 48 89 70 ?? 48 89 78 ?? 4C 89 60 ?? 4C 89 68 ?? 4C 89 70 ?? 44 8D 75 ?? 4C 89 78 ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 8D 43 ?? 4C 63 C8 49 8B C1 C6 05 ?? ?? ?? ?? ?? 48 2B C1 48 89 2D ?? ?? ?? ?? 48 85 C0 0F 8E ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 4D 85 C0 0F 88 ?? ?? ?? ?? 74 ?? 49 8D 49 ?? 48 8B C1 48 99 49 F7 F8 4C 2B C2 4C 03 C1 EB ?? 48 85 C9 4C 8B C1 4D 0F 44 C6 4D 3B C1 7D ?? 4D 03 C0 4D 3B C1 7C ?? 4D 3B C1 7D ?? 4D 85 C0 75 ?? 4D 85 C9 79 ?? 49 C7 C0 ?? ?? ?? ?? EB ?? 4B 8D 04 08 48 99 48 2B C2 48 D1 F8 4C 8B C0 49 3B C1 7C ?? 48 8B 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 89 05 ?? ?? ?? ?? 48 85 D2 74 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 08 48 8B C8 4D 6B C0 ?? 41 FF 51 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 49 6B F8 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 00 48 8B D7 48 8B C8 41 FF 50 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 8B 15 ?? ?? ?? ?? FF 05 ?? ?? ?? ?? 4C 8D 2D") + .GetPtr(v_Script_RegisterClientProjectileClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 6C 24 ?? 33 ED 48 89 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 89 74 24 ?? 48 89 7C 24 ?? 48 63 3D ?? ?? ?? ?? 4C 89 74 24 ?? 44 8D 75 ?? C6 05 ?? ?? ?? ?? ?? 48 89 2D ?? ?? ?? ?? 8D 47 ?? 4C 63 C0 49 8B C0 48 2B C1 48 85 C0 0F 8E ?? ?? ?? ?? 4C 8B 0D ?? ?? ?? ?? 4D 85 C9 0F 88 ?? ?? ?? ?? 74 ?? 49 8D 48 ?? 48 8B C1 48 99 49 F7 F9 48 2B CA 49 03 C9 EB ?? 48 85 C9 49 0F 44 CE 49 3B C8 7D ?? 48 03 C9 49 3B C8 7C ?? 49 3B C8 7D ?? 48 85 C9 75 ?? 4D 85 C0 79 ?? 48 C7 C1 ?? ?? ?? ?? EB ?? 0F 1F 40 ?? 0F 1F 84 00 ?? ?? ?? ?? 4A 8D 04 01 48 99 48 2B C2 48 D1 F8 48 8B C8 49 3B C0 7C ?? 48 8B 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 89 0D ?? ?? ?? ?? 48 85 D2 74 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 08 4C 6B C1 ?? 48 8B C8 41 FF 51 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 6B D9 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 00 48 8B D3 48 8B C8 41 FF 50 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 8B 15 ?? ?? ?? ?? FF 05 ?? ?? ?? ?? 48 8D 35") + .GetPtr(v_Script_RegisterClientTitanSoulClassFuncs); + + g_GameDll.FindPatternSIMD("80 3D ?? ?? ?? ?? ?? 75 ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 C7 05 ?? ?? ?? ?? ?? ?? ?? ?? C3 CC CC CC 48 8D 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC 48 89 5C 24") + .GetPtr(v_Script_RegisterClientPlayerDecoyClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 74 24 ?? 33 F6 48 89 05 ?? ?? ?? ?? 48 89 7C 24 ?? 48 63 3D ?? ?? ?? ?? 4C 89 74 24 ?? 8D 6E ?? 4C 8D 35 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 4C 89 35 ?? ?? ?? ?? 8D 47 ?? 48 89 35 ?? ?? ?? ?? 4C 63 C0") + .GetPtr(v_Script_RegisterClientFirstPersonProxyClassFuncs); + } + virtual void GetVar(void) const + { + CMemory(v_Script_RegisterClientEntityClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptEntityStruct); + CMemory(v_Script_RegisterClientPlayerClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptPlayerStruct); + CMemory(v_Script_RegisterClientAIClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptAIStruct); + CMemory(v_Script_RegisterClientWeaponClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptWeaponStruct); + CMemory(v_Script_RegisterClientProjectileClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptProjectileStruct); + CMemory(v_Script_RegisterClientTitanSoulClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptTitanSoulStruct); + CMemory(v_Script_RegisterClientPlayerDecoyClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptPlayerDecoyStruct); + CMemory(v_Script_RegisterClientFirstPersonProxyClassFuncs).FindPatternSelf("48 89 05", CMemory::Direction::DOWN, 150, 2).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_clientScriptFirstPersonProxyStruct); + } + virtual void GetCon(void) const { } + virtual void Detour(const bool bAttach) const; +}; +/////////////////////////////////////////////////////////////////////////////// + #endif // VSCRIPT_CLIENT_H diff --git a/src/game/server/vscript_server.cpp b/src/game/server/vscript_server.cpp index 0ca711d9..dc23e4bd 100644 --- a/src/game/server/vscript_server.cpp +++ b/src/game/server/vscript_server.cpp @@ -334,3 +334,109 @@ void Script_RegisterAdminPanelFunctions(CSquirrelVM* s) DEFINE_SERVER_SCRIPTFUNC_NAMED(s, UnbanPlayer, "Unbans a player from the server by nucleus id or ip address", "void", "string"); } + +//--------------------------------------------------------------------------------- +// Purpose: script code class function registration +//--------------------------------------------------------------------------------- +static void Script_RegisterServerEntityClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerPlayerClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerAIClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerWeaponClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerProjectileClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerTitanSoulClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerPlayerDecoyClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerSpawnpointClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} +//--------------------------------------------------------------------------------- +static void Script_RegisterServerFirstPersonProxyClassFuncs() +{ + static bool initialized = false; + + if (initialized) + return; + + initialized = true; +} + +void VScriptServer::Detour(const bool bAttach) const +{ + DetourSetup(&v_Script_RegisterServerEntityClassFuncs, &Script_RegisterServerEntityClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerPlayerClassFuncs, &Script_RegisterServerPlayerClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerAIClassFuncs, &Script_RegisterServerAIClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerWeaponClassFuncs, &Script_RegisterServerWeaponClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerProjectileClassFuncs, &Script_RegisterServerProjectileClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerTitanSoulClassFuncs, &Script_RegisterServerTitanSoulClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerPlayerDecoyClassFuncs, &Script_RegisterServerPlayerDecoyClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerSpawnpointClassFuncs, &Script_RegisterServerSpawnpointClassFuncs, bAttach); + DetourSetup(&v_Script_RegisterServerFirstPersonProxyClassFuncs, &Script_RegisterServerFirstPersonProxyClassFuncs, bAttach); +} diff --git a/src/game/server/vscript_server.h b/src/game/server/vscript_server.h index 8d811524..c2a88224 100644 --- a/src/game/server/vscript_server.h +++ b/src/game/server/vscript_server.h @@ -38,4 +38,95 @@ void Script_RegisterServerEnums(CSquirrelVM* const s); s->RegisterFunction(#functionName, MKSTRING(Script_##functionName), \ helpString, returnType, parameters, VScriptCode::Server::##functionName); \ +inline void (*v_Script_RegisterServerEntityClassFuncs)(); +inline void (*v_Script_RegisterServerPlayerClassFuncs)(); +inline void (*v_Script_RegisterServerAIClassFuncs)(); +inline void (*v_Script_RegisterServerWeaponClassFuncs)(); +inline void (*v_Script_RegisterServerProjectileClassFuncs)(); +inline void (*v_Script_RegisterServerTitanSoulClassFuncs)(); +inline void (*v_Script_RegisterServerPlayerDecoyClassFuncs)(); +inline void (*v_Script_RegisterServerSpawnpointClassFuncs)(); +inline void (*v_Script_RegisterServerFirstPersonProxyClassFuncs)(); + +inline ScriptClassDescriptor_t* g_serverScriptEntityStruct; +inline ScriptClassDescriptor_t* g_serverScriptPlayerStruct; +inline ScriptClassDescriptor_t* g_serverScriptAIStruct; +inline ScriptClassDescriptor_t* g_serverScriptWeaponStruct; +inline ScriptClassDescriptor_t* g_serverScriptProjectileStruct; +inline ScriptClassDescriptor_t* g_serverScriptTitanSoulStruct; +inline ScriptClassDescriptor_t* g_serverScriptPlayerDecoyStruct; +inline ScriptClassDescriptor_t* g_serverScriptSpawnpointStruct; +inline ScriptClassDescriptor_t* g_serverScriptFirstPersonProxyStruct; + +/////////////////////////////////////////////////////////////////////////////// +class VScriptServer : public IDetour +{ + virtual void GetAdr(void) const + { + LogFunAdr("Script_RegisterServerEntityClassFuncs", v_Script_RegisterServerEntityClassFuncs); + LogFunAdr("Script_RegisterServerPlayerClassFuncs", v_Script_RegisterServerPlayerClassFuncs); + LogFunAdr("Script_RegisterServerAIClassFuncs", v_Script_RegisterServerAIClassFuncs); + LogFunAdr("Script_RegisterServerWeaponClassFuncs", v_Script_RegisterServerWeaponClassFuncs); + LogFunAdr("Script_RegisterServerProjectileClassFuncs", v_Script_RegisterServerProjectileClassFuncs); + LogFunAdr("Script_RegisterServerTitanSoulClassFuncs", v_Script_RegisterServerTitanSoulClassFuncs); + LogFunAdr("Script_RegisterServerPlayerDecoyClassFuncs", v_Script_RegisterServerPlayerDecoyClassFuncs); + LogFunAdr("Script_RegisterServerSpawnpointClassFuncs", v_Script_RegisterServerSpawnpointClassFuncs); + LogFunAdr("Script_RegisterServerFirstPersonProxyClassFuncs", v_Script_RegisterServerFirstPersonProxyClassFuncs); + + LogVarAdr("g_serverScriptEntityStruct", g_serverScriptEntityStruct); + LogVarAdr("g_serverScriptPlayerStruct", g_serverScriptPlayerStruct); + LogVarAdr("g_serverScriptAIStruct", g_serverScriptAIStruct); + LogVarAdr("g_serverScriptWeaponStruct", g_serverScriptWeaponStruct); + LogVarAdr("g_serverScriptProjectileStruct", g_serverScriptProjectileStruct); + LogVarAdr("g_serverScriptTitanSoulStruct", g_serverScriptTitanSoulStruct); + LogVarAdr("g_serverScriptPlayerDecoyStruct", g_serverScriptPlayerDecoyStruct); + LogVarAdr("g_serverScriptSpawnpointStruct", g_serverScriptSpawnpointStruct); + LogVarAdr("g_serverScriptFirstPersonProxyStruct", g_serverScriptFirstPersonProxyStruct); + } + virtual void GetFun(void) const + { + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 D2 48 8D 05 ?? ?? ?? ?? 48 C7 05") + .GetPtr(v_Script_RegisterServerEntityClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 D2 48 8D 05 ?? ?? ?? ?? 48 89 05") + .GetPtr(v_Script_RegisterServerPlayerClassFuncs); + + g_GameDll.FindPatternSIMD("40 55 48 8B EC 48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05") + .GetPtr(v_Script_RegisterServerAIClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 5C 24 ?? 48 89 05 ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 C9 48 8D 05 ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? B0 ?? 48 89 15 ?? ?? ?? ?? 48 0F BE C0 48 8D 52 ?? 48 03 C1 48 69 C8 ?? ?? ?? ?? 48 8B C1 48 C1 E8 ?? 48 33 C8 0F B6 02 84 C0 75 ?? 48 8D 15 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 48 6B C1 ?? 48 8D 0D ?? ?? ?? ?? 48 03 05 ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 89 08 48 8D 0D ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 89 48 ?? 48 8D 0D ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C6 40 ?? ?? 48 C7 40 ?? ?? ?? ?? ?? 48 C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? C7 40 ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 C8 48 6B C1") + .GetPtr(v_Script_RegisterServerWeaponClassFuncs); + + g_GameDll.FindPatternSIMD("48 8B C4 48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 89 58 ?? 48 8D 15 ?? ?? ?? ?? 48 89 68 ?? 33 ED 48 89 70 ?? 8B CD 48 89 78 ?? 4C 89 60 ?? 4C 89 68 ?? 4C 89 70 ?? 4C 89 78 ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? B0 ?? C6 05 ?? ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 0F BE C0 48 8D 52 ?? 48 03 C1 48 69 C8 ?? ?? ?? ?? 48 8B C1 48 C1 E8 ?? 48 33 C8 0F B6 02 84 C0 75 ?? 48 8D 15 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 1D ?? ?? ?? ?? 41 BE ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 8D 43 ?? 4C 63 C8") + .GetPtr(v_Script_RegisterServerProjectileClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 89 5C 24 ?? 48 8D 05 ?? ?? ?? ?? 48 89 6C 24 ?? 48 8D 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 ED 48 89 74 24 ?? 48 8D 05 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 8B CD 48 8D 05 ?? ?? ?? ?? 48 89 7C 24 ?? 48 89 05 ?? ?? ?? ?? B0 ?? 4C 89 74 24 ?? 4C 89 7C 24 ?? C6 05 ?? ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 0F 1F 44 00 ?? 48 0F BE C0 48 8D 52 ?? 48 03 C1 48 69 C8 ?? ?? ?? ?? 48 8B C1 48 C1 E8 ?? 48 33 C8 0F B6 02 84 C0 75 ?? 48 8D 15 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 1D") + .GetPtr(v_Script_RegisterServerTitanSoulClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 89 5C 24 ?? 48 8D 05 ?? ?? ?? ?? 48 89 6C 24 ?? 48 8D 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 ED 48 8D 05 ?? ?? ?? ?? 48 89 74 24 ?? 48 89 05 ?? ?? ?? ?? 8B CD 48 8D 05 ?? ?? ?? ?? 48 89 7C 24 ?? 48 89 05 ?? ?? ?? ?? B0 ?? 4C 89 74 24 ?? C6 05 ?? ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 66 66 0F 1F 84 00 ?? ?? ?? ?? 48 0F BE C0 48 8D 52 ?? 48 03 C1 48 69 C8 ?? ?? ?? ?? 48 8B C1 48 C1 E8 ?? 48 33 C8 0F B6 02 84 C0 75 ?? 48 8D 15 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 3D ?? ?? ?? ?? 41 BE ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 8D 47 ?? 4C 63 C8 49 8B C1 48 2B C1 48 85 C0 0F 8E ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 4D 85 C0 0F 88 ?? ?? ?? ?? 74 ?? 49 8D 49 ?? 48 8B C1 48 99 49 F7 F8 4C 2B C2 4C 03 C1 EB ?? 48 85 C9 4C 8B C1 4D 0F 44 C6 4D 3B C1 7D ?? 0F 1F 00 4D 03 C0 4D 3B C1 7C ?? 4D 3B C1 7D ?? 4D 85 C0 75 ?? 4D 85 C9 79 ?? 49 C7 C0 ?? ?? ?? ?? EB ?? 4B 8D 04 08 48 99 48 2B C2 48 D1 F8 4C 8B C0 49 3B C1 7C ?? 48 8B 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 89 05 ?? ?? ?? ?? 48 85 D2 74 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 08 48 8B C8 4D 6B C0 ?? 41 FF 51 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 49 6B D8 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 00 48 8B D3 48 8B C8 41 FF 50 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 8B 15 ?? ?? ?? ?? FF 05 ?? ?? ?? ?? 48 6B CF ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 66 44 89 74 11 ?? C7 44 11 ?? ?? ?? ?? ?? 48 89 6C 11 ?? 89 6C 11 ?? 48 8D 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 89 54 01 ?? 48 8D 15 ?? ?? ?? ?? 48 89 14 01 48 8D 15 ?? ?? ?? ?? 48 89 54 01 ?? 48 8D 15 ?? ?? ?? ?? 48 89 54 01 ?? 48 89 6C 01 ?? 48 89 6C 01 ?? 40 88 6C 01 ?? 48 89 6C 01 ?? 48 89 6C 01 ?? 89 6C 01 ?? 48 63 3D ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 8D 47 ?? 4C 63 C8 49 8B C1 48 2B C1 48 85 C0 0F 8E ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 4D 85 C0 0F 88 ?? ?? ?? ?? 74 ?? 49 8D 49 ?? 48 8B C1 48 99 49 F7 F8 4C 2B C2 4C 03 C1 EB ?? 48 85 C9 4C 8B C1 4D 0F 44 C6 4D 3B C1 7D ?? 90 4D 03 C0 4D 3B C1 7C ?? 4D 3B C1 7D ?? 4D 85 C0 75 ?? 4D 85 C9 79 ?? 49 C7 C0 ?? ?? ?? ?? EB ?? 4B 8D 04 08 48 99 48 2B C2 48 D1 F8 4C 8B C0 49 3B C1 7C ?? 48 8B 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 89 05 ?? ?? ?? ?? 48 85 D2 74 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 08 48 8B C8 4D 6B C0 ?? 41 FF 51 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 49 6B D8 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 00 48 8B D3 48 8B C8 41 FF 50 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 8B 15 ?? ?? ?? ?? FF 05 ?? ?? ?? ?? 48 6B CF ?? 48 89 6C 11") + .GetPtr(v_Script_RegisterServerPlayerDecoyClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 89 5C 24 ?? 48 8D 05 ?? ?? ?? ?? 48 89 6C 24 ?? 48 8D 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 ED 48 8D 05 ?? ?? ?? ?? 48 89 74 24 ?? 48 89 05 ?? ?? ?? ?? 8B CD 48 8D 05 ?? ?? ?? ?? 48 89 7C 24 ?? 48 89 05 ?? ?? ?? ?? B0 ?? 4C 89 74 24 ?? C6 05 ?? ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 66 66 0F 1F 84 00 ?? ?? ?? ?? 48 0F BE C0 48 8D 52 ?? 48 03 C1 48 69 C8 ?? ?? ?? ?? 48 8B C1 48 C1 E8 ?? 48 33 C8 0F B6 02 84 C0 75 ?? 48 8D 15 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 63 3D ?? ?? ?? ?? 41 BE ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 8D 47 ?? 4C 63 C8 49 8B C1 48 2B C1 48 85 C0 0F 8E ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 4D 85 C0 0F 88 ?? ?? ?? ?? 74 ?? 49 8D 49 ?? 48 8B C1 48 99 49 F7 F8 4C 2B C2 4C 03 C1 EB ?? 48 85 C9 4C 8B C1 4D 0F 44 C6 4D 3B C1 7D ?? 0F 1F 00 4D 03 C0 4D 3B C1 7C ?? 4D 3B C1 7D ?? 4D 85 C0 75 ?? 4D 85 C9 79 ?? 49 C7 C0 ?? ?? ?? ?? EB ?? 4B 8D 04 08 48 99 48 2B C2 48 D1 F8 4C 8B C0 49 3B C1 7C ?? 48 8B 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 89 05 ?? ?? ?? ?? 48 85 D2 74 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 08 48 8B C8 4D 6B C0 ?? 41 FF 51 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 49 6B D8 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 00 48 8B D3 48 8B C8 41 FF 50 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 8B 15 ?? ?? ?? ?? FF 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 6B CF ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 66 44 89 74 11 ?? C7 44 11 ?? ?? ?? ?? ?? 48 89 6C 11 ?? 89 6C 11 ?? 49 8B D6 48 8B 1D ?? ?? ?? ?? 48 03 D9 48 89 43 ?? 48 8D 4B ?? 48 89 6B ?? 48 8D 05 ?? ?? ?? ?? 48 89 03 48 8D 05 ?? ?? ?? ?? 48 89 43 ?? 89 6B ?? 40 88 6B ?? 48 89 6B ?? 48 89 6B ?? 89 6B ?? C7 43 ?? ?? ?? ?? ?? 4C 89 73 ?? E8 ?? ?? ?? ?? 48 63 73 ?? 8D 46 ?? 48 63 D0 8B C6 48 2B 53 ?? 48 85 D2 7E ?? 48 8D 4B ?? E8 ?? ?? ?? ?? 8B 43 ?? FF C0 89 43 ?? 48 8B 43 ?? C7 04 B0 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 43 ?? 48 63 3D ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 8D 47 ?? 4C 63 C8 49 8B C1 48 2B C1 48 85 C0 0F 8E ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 4D 85 C0 0F 88 ?? ?? ?? ?? 74 ?? 49 8D 49 ?? 48 8B C1 48 99 49 F7 F8 4C 2B C2 4C 03 C1 EB ?? 48 85 C9 4C 8B C1 4D 0F 44 C6 4D 3B C1 7D ?? 90 4D 03 C0 4D 3B C1 7C ?? 4D 3B C1 7D ?? 4D 85 C0 75 ?? 4D 85 C9 79 ?? 49 C7 C0 ?? ?? ?? ?? EB ?? 4B 8D 04 08 48 99 48 2B C2 48 D1 F8 4C 8B C0 49 3B C1 7C ?? 48 8B 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 89 05 ?? ?? ?? ?? 48 85 D2 74 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 4C 8B 05 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 08 48 8B C8 4D 6B C0 ?? 41 FF 51 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 49 6B D8 ?? 48 85 C0 75 ?? E8 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 8B 00 48 8B D3 48 8B C8 41 FF 50 ?? 48 8B D0 48 89 05 ?? ?? ?? ?? EB ?? 48 8B 15 ?? ?? ?? ?? FF 05 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 6B CF ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 48 89 6C 11 ?? 66 44 89 74 11 ?? C7 44 11 ?? ?? ?? ?? ?? 48 89 6C 11 ?? 89 6C 11 ?? BA ?? ?? ?? ?? 48 8B 3D ?? ?? ?? ?? 48 03 F9 48 89 47 ?? 48 8D 4F ?? 48 89 6F ?? 48 8D 05 ?? ?? ?? ?? 48 89 07 48 8D 05 ?? ?? ?? ?? 48 89 47 ?? 89 6F ?? 40 88 6F ?? 48 89 6F ?? 48 89 6F ?? 89 6F ?? 44 89 77") + .GetPtr(v_Script_RegisterServerSpawnpointClassFuncs); + + g_GameDll.FindPatternSIMD("48 83 EC ?? 80 3D ?? ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 48 89 6C 24 ?? 48 8D 05 ?? ?? ?? ?? 48 89 74 24 ?? 48 8D 15 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 33 F6 48 8D 05 ?? ?? ?? ?? 48 89 7C 24 ?? 4C 89 74 24 ?? 8B CE 4C 8D 35 ?? ?? ?? ?? 48 89 05 ?? ?? ?? ?? 4C 89 35 ?? ?? ?? ?? B0 ?? C6 05 ?? ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 89 15 ?? ?? ?? ?? 48 0F BE C0 48 8D 52 ?? 48 03 C1 48 69 C8 ?? ?? ?? ?? 48 8B C1 48 C1 E8 ?? 48 33 C8 0F B6 02 84 C0 75 ?? 48 8D 15 ?? ?? ?? ?? 48 89 5C 24 ?? E8 ?? ?? ?? ?? 48 63 3D ?? ?? ?? ?? BD ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 8D 47 ?? 4C 63 C0") + .GetPtr(v_Script_RegisterServerFirstPersonProxyClassFuncs); + } + virtual void GetVar(void) const + { + CMemory(v_Script_RegisterServerEntityClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptEntityStruct); + CMemory(v_Script_RegisterServerPlayerClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptPlayerStruct); + CMemory(v_Script_RegisterServerAIClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptAIStruct); + CMemory(v_Script_RegisterServerWeaponClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptWeaponStruct); + CMemory(v_Script_RegisterServerProjectileClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptProjectileStruct); + CMemory(v_Script_RegisterServerTitanSoulClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptTitanSoulStruct); + CMemory(v_Script_RegisterServerPlayerDecoyClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptPlayerDecoyStruct); + CMemory(v_Script_RegisterServerSpawnpointClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptSpawnpointStruct); + CMemory(v_Script_RegisterServerFirstPersonProxyClassFuncs).Offset(0x50).FindPatternSelf("48 8D 15", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_serverScriptFirstPersonProxyStruct); + } + virtual void GetCon(void) const { } + virtual void Detour(const bool bAttach) const; +}; +/////////////////////////////////////////////////////////////////////////////// + #endif // VSCRIPT_SERVER_H From 8abbed283e8005e11d4742971632faf331a3a116 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:04:45 +0200 Subject: [PATCH 05/11] Engine: add implementation for registering new netmessages --- src/engine/client/client.cpp | 21 +++++++++++++++++++++ src/engine/client/client.h | 6 ++++++ src/engine/client/clientstate.cpp | 21 +++++++++++++++++++++ src/engine/client/clientstate.h | 6 ++++++ src/public/inetchannel.h | 15 +++++++++++++++ 5 files changed, 69 insertions(+) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 158e11a5..def08544 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -264,6 +264,18 @@ bool CClient::VConnect(CClient* pClient, const char* szName, CNetChan* pNetChan, return pClient->Connect(szName, pNetChan, bFakePlayer, conVars, szMessage, nMessageSize); } +//--------------------------------------------------------------------------------- +// Purpose: registers net messages +// Input : *pClient - +// *pChan - +// Output : true if setup was successful, false otherwise +//--------------------------------------------------------------------------------- +bool CClient::VConnectionStart(CClient* pClient, CNetChan* pChan) +{ + pClient->RegisterNetMsgs(pChan); + return CClient__ConnectionStart(pClient, pChan); +} + //--------------------------------------------------------------------------------- // Purpose: disconnect client // Input : nRepLvl - @@ -309,6 +321,14 @@ void CClient::VActivatePlayer(CClient* pClient) #endif // !CLIENT_DLL } +//--------------------------------------------------------------------------------- +// Purpose: registers net messages +// Input : *chan +//--------------------------------------------------------------------------------- +void CClient::RegisterNetMsgs(CNetChan* chan) +{ +} + //--------------------------------------------------------------------------------- // Purpose: send a net message with replay. // set 'CNetMessage::m_nGroup' to 'NoReplay' to disable replay. @@ -618,6 +638,7 @@ void VClient::Detour(const bool bAttach) const #ifndef CLIENT_DLL DetourSetup(&CClient__Clear, &CClient::VClear, bAttach); DetourSetup(&CClient__Connect, &CClient::VConnect, bAttach); + DetourSetup(&CClient__ConnectionStart, &CClient::VConnectionStart, bAttach); DetourSetup(&CClient__ActivatePlayer, &CClient::VActivatePlayer, bAttach); DetourSetup(&CClient__SendNetMsgEx, &CClient::VSendNetMsgEx, bAttach); //DetourSetup(&CClient__SendSnapshot, &CClient::VSendSnapshot, bAttach); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 9a273b36..c78ea429 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -104,6 +104,7 @@ public: inline bool IsFakeClient(void) const { return m_bFakePlayer; } inline bool IsHumanPlayer(void) const { if (!IsConnected() || IsFakeClient()) { return false; } return true; } + void RegisterNetMsgs(CNetChan* chan); bool SendNetMsgEx(CNetMessage* pMsg, bool bLocal, bool bForceReliable, bool bVoice); bool Authenticate(const char* const playerName, char* const reasonBuf, const size_t reasonBufLen); @@ -117,6 +118,8 @@ public: // Hook statics: static bool VConnect(CClient* pClient, const char* szName, CNetChan* pNetChan, bool bFakePlayer, CUtlVector* conVars, char* szMessage, int nMessageSize); + static bool VConnectionStart(CClient* pClient, CNetChan* pChan); + static void VActivatePlayer(CClient* pClient); static void* VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck); static bool VSendNetMsgEx(CClient* pClient, CNetMessage* pMsg, bool bLocal, bool bForceReliable, bool bVoice); @@ -291,6 +294,7 @@ private: /* ==== CBASECLIENT ===================================================================================================================================================== */ inline bool(*CClient__Connect)(CClient* pClient, const char* szName, CNetChan* pNetChan, bool bFakePlayer, CUtlVector* conVars, char* szMessage, int nMessageSize); inline bool(*CClient__Disconnect)(CClient* pClient, const Reputation_t nRepLvl, const char* szReason, ...); +inline bool(*CClient__ConnectionStart)(CClient* pClient, CNetChan* pChan); inline void(*CClient__Clear)(CClient* pClient); inline void(*CClient__ActivatePlayer)(CClient* pClient); inline bool(*CClient__SetSignonState)(CClient* pClient, SIGNONSTATE signon); @@ -309,6 +313,7 @@ class VClient : public IDetour { LogFunAdr("CClient::Connect", CClient__Connect); LogFunAdr("CClient::Disconnect", CClient__Disconnect); + LogFunAdr("CClient::ConnectionStart", CClient__ConnectionStart); LogFunAdr("CClient::Clear", CClient__Clear); LogFunAdr("CClient::ActivatePlayer", CClient__ActivatePlayer); LogFunAdr("CClient::SetSignonState", CClient__SetSignonState); @@ -324,6 +329,7 @@ class VClient : public IDetour { g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 20 41 0F B6 E9").GetPtr(CClient__Connect); g_GameDll.FindPatternSIMD("48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 8B F2").GetPtr(CClient__Disconnect); + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC ?? 48 8B 05 ?? ?? ?? ?? 48 8B EA 4C 8B F1").GetPtr(CClient__ConnectionStart); g_GameDll.FindPatternSIMD("40 53 41 56 41 57 48 83 EC 20 48 8B D9 48 89 74").GetPtr(CClient__Clear); g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 8B 81 B0 03 ?? ?? 48 8B D9 C6").GetPtr(CClient__ActivatePlayer); g_GameDll.FindPatternSIMD("40 53 55 56 57 41 56 48 83 EC 40 48 8B 05 ?? ?? ?? ??").GetPtr(CClient__SendNetMsgEx); diff --git a/src/engine/client/clientstate.cpp b/src/engine/client/clientstate.cpp index 777c6b10..b978f44b 100644 --- a/src/engine/client/clientstate.cpp +++ b/src/engine/client/clientstate.cpp @@ -162,6 +162,18 @@ float CClientState::GetFrameTime() const return m_flFrameTime; } +//--------------------------------------------------------------------------------- +// Purpose: registers net messages +// Input : *pClient - +// *pChan - +// Output : true if setup was successful, false otherwise +//--------------------------------------------------------------------------------- +bool CClientState::VConnectionStart(CClientState* pClient, CNetChan* pChan) +{ + pClient->RegisterNetMsgs(pChan); + return CClientState__ConnectionStart(pClient, pChan); +} + //------------------------------------------------------------------------------ // Purpose: called when connection to the server has been closed //------------------------------------------------------------------------------ @@ -491,8 +503,17 @@ void CClientState::Reconnect() Cbuf_AddText(ECommandTarget_t::CBUF_FIRST_PLAYER, buf, cmd_source_t::kCommandSrcCode); } +//--------------------------------------------------------------------------------- +// Purpose: registers net messages +// Input : *chan +//--------------------------------------------------------------------------------- +void CClientState::RegisterNetMsgs(CNetChan* chan) +{ +} + void VClientState::Detour(const bool bAttach) const { + DetourSetup(&CClientState__ConnectionStart, &CClientState::VConnectionStart, bAttach); DetourSetup(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing, bAttach); DetourSetup(&CClientState__ProcessStringCmd, &CClientState::_ProcessStringCmd, bAttach); DetourSetup(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick, bAttach); diff --git a/src/engine/client/clientstate.h b/src/engine/client/clientstate.h index 89b11709..0f68bf65 100644 --- a/src/engine/client/clientstate.h +++ b/src/engine/client/clientstate.h @@ -36,6 +36,7 @@ class CClientState : CS_INetChannelHandler, IConnectionlessPacketHandler, IServe { friend class ClientDataBlockReceiver; public: // Hook statics. + static bool VConnectionStart(CClientState* pClient, CNetChan* pChan); static void VConnectionClosing(CClientState* thisptr, const char* szReason); static bool _ProcessStringCmd(CClientState* thisptr, NET_StringCmd* msg); static bool VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg); @@ -66,6 +67,8 @@ public: void Reconnect(); + void RegisterNetMsgs(CNetChan* chan); + protected: FORCEINLINE CClientState* GetShiftedBasePointer(void) { @@ -225,6 +228,7 @@ extern CClientState** g_pClientState_Shifted; // Shifted by 0x10 forward! inline void(*CClientState__RunFrame)(CClientState* thisptr); inline void(*CClientState__Connect)(CClientState* thisptr, connectparams_t* connectParams); inline void(*CClientState__Disconnect)(CClientState* thisptr, bool bSendTrackingContext); +inline bool(*CClientState__ConnectionStart)(CClientState* thisptr, CNetChan* chan); inline void(*CClientState__ConnectionClosing)(CClientState* thisptr, const char* szReason); inline bool(*CClientState__HookClientStringTable)(CClientState* thisptr, const char* tableName); @@ -241,6 +245,7 @@ class VClientState : public IDetour LogFunAdr("CClientState::RunFrame", CClientState__RunFrame); LogFunAdr("CClientState::Connect", CClientState__Connect); LogFunAdr("CClientState::Disconnect", CClientState__Disconnect); + LogFunAdr("CClientState::ConnectionStart", CClientState__ConnectionStart); LogFunAdr("CClientState::ConnectionClosing", CClientState__ConnectionClosing); LogFunAdr("CClientState::HookClientStringTable", CClientState__HookClientStringTable); LogFunAdr("CClientState::ProcessStringCmd", CClientState__ProcessStringCmd); @@ -255,6 +260,7 @@ class VClientState : public IDetour g_GameDll.FindPatternSIMD("40 53 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 48 8B D9 7D 0B").GetPtr(CClientState__RunFrame); g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC ?? ?? ?? ?? 48 8B 32").GetPtr(CClientState__Connect); g_GameDll.FindPatternSIMD("40 56 57 41 54 41 55 41 57 48 83 EC 30 44 0F B6 FA").GetPtr(CClientState__Disconnect); + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 48 8B 05 ?? ?? ?? ?? 48 8B F2").GetPtr(CClientState__ConnectionStart); g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B DA 0F 8E ?? ?? ?? ??").GetPtr(CClientState__ConnectionClosing); g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 48 8B D9 48 8B FA 48 8B 89 ?? ?? ?? ?? 48 85 C9 0F 84 ?? ?? ?? ??").GetPtr(CClientState__HookClientStringTable); g_GameDll.FindPatternSIMD("40 53 48 81 EC ?? ?? ?? ?? 80 B9 ?? ?? ?? ?? ?? 48 8B DA").GetPtr(CClientState__ProcessStringCmd); diff --git a/src/public/inetchannel.h b/src/public/inetchannel.h index 6878e004..161625b2 100644 --- a/src/public/inetchannel.h +++ b/src/public/inetchannel.h @@ -7,6 +7,21 @@ #define MAX_FLOWS 2 // in & out #include "tier1/NetAdr.h" +#define REGISTER_NET_MSG( name ) \ + NET_##name * p##name = new NET_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_SVC_MSG( name ) \ + SVC_##name * p##name = new SVC_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + +#define REGISTER_CLC_MSG( name ) \ + CLC_##name * p##name = new CLC_##name(); \ + p##name->m_pMessageHandler = this; \ + chan->RegisterMessage( p##name ); \ + class IClientMessageHandler { public: From 9a68b154120506ab85eacb6d18fe677b35c36d0d Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:39:01 +0200 Subject: [PATCH 06/11] VScript: run initial registration code class callbacks first Must be ran within the hook as otherwise engine code class functions won't be registered. --- src/game/client/vscript_client.cpp | 8 ++++++++ src/game/server/vscript_server.cpp | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/game/client/vscript_client.cpp b/src/game/client/vscript_client.cpp index 673b2577..431228c5 100644 --- a/src/game/client/vscript_client.cpp +++ b/src/game/client/vscript_client.cpp @@ -519,6 +519,7 @@ static ConVar show_motd_on_server_first_join("show_motd_on_server_first_join", " //--------------------------------------------------------------------------------- static void Script_RegisterClientEntityClassFuncs() { + v_Script_RegisterClientEntityClassFuncs(); static bool initialized = false; if (initialized) @@ -529,6 +530,7 @@ static void Script_RegisterClientEntityClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientPlayerClassFuncs() { + v_Script_RegisterClientPlayerClassFuncs(); static bool initialized = false; if (initialized) @@ -539,6 +541,7 @@ static void Script_RegisterClientPlayerClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientAIClassFuncs() { + v_Script_RegisterClientAIClassFuncs(); static bool initialized = false; if (initialized) @@ -549,6 +552,7 @@ static void Script_RegisterClientAIClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientWeaponClassFuncs() { + v_Script_RegisterClientWeaponClassFuncs(); static bool initialized = false; if (initialized) @@ -559,6 +563,7 @@ static void Script_RegisterClientWeaponClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientProjectileClassFuncs() { + v_Script_RegisterClientProjectileClassFuncs(); static bool initialized = false; if (initialized) @@ -569,6 +574,7 @@ static void Script_RegisterClientProjectileClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientTitanSoulClassFuncs() { + v_Script_RegisterClientTitanSoulClassFuncs(); static bool initialized = false; if (initialized) @@ -579,6 +585,7 @@ static void Script_RegisterClientTitanSoulClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientPlayerDecoyClassFuncs() { + v_Script_RegisterClientPlayerDecoyClassFuncs(); static bool initialized = false; if (initialized) @@ -589,6 +596,7 @@ static void Script_RegisterClientPlayerDecoyClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterClientFirstPersonProxyClassFuncs() { + v_Script_RegisterClientFirstPersonProxyClassFuncs(); static bool initialized = false; if (initialized) diff --git a/src/game/server/vscript_server.cpp b/src/game/server/vscript_server.cpp index dc23e4bd..c5d03548 100644 --- a/src/game/server/vscript_server.cpp +++ b/src/game/server/vscript_server.cpp @@ -340,6 +340,7 @@ void Script_RegisterAdminPanelFunctions(CSquirrelVM* s) //--------------------------------------------------------------------------------- static void Script_RegisterServerEntityClassFuncs() { + v_Script_RegisterServerEntityClassFuncs(); static bool initialized = false; if (initialized) @@ -350,6 +351,7 @@ static void Script_RegisterServerEntityClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerPlayerClassFuncs() { + v_Script_RegisterServerPlayerClassFuncs(); static bool initialized = false; if (initialized) @@ -360,6 +362,7 @@ static void Script_RegisterServerPlayerClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerAIClassFuncs() { + v_Script_RegisterServerAIClassFuncs(); static bool initialized = false; if (initialized) @@ -370,6 +373,7 @@ static void Script_RegisterServerAIClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerWeaponClassFuncs() { + v_Script_RegisterServerWeaponClassFuncs(); static bool initialized = false; if (initialized) @@ -380,6 +384,7 @@ static void Script_RegisterServerWeaponClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerProjectileClassFuncs() { + v_Script_RegisterServerProjectileClassFuncs(); static bool initialized = false; if (initialized) @@ -390,6 +395,7 @@ static void Script_RegisterServerProjectileClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerTitanSoulClassFuncs() { + v_Script_RegisterServerTitanSoulClassFuncs(); static bool initialized = false; if (initialized) @@ -400,6 +406,7 @@ static void Script_RegisterServerTitanSoulClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerPlayerDecoyClassFuncs() { + v_Script_RegisterServerPlayerDecoyClassFuncs(); static bool initialized = false; if (initialized) @@ -410,6 +417,7 @@ static void Script_RegisterServerPlayerDecoyClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerSpawnpointClassFuncs() { + v_Script_RegisterServerSpawnpointClassFuncs(); static bool initialized = false; if (initialized) @@ -420,6 +428,7 @@ static void Script_RegisterServerSpawnpointClassFuncs() //--------------------------------------------------------------------------------- static void Script_RegisterServerFirstPersonProxyClassFuncs() { + v_Script_RegisterServerFirstPersonProxyClassFuncs(); static bool initialized = false; if (initialized) From 3b1622af95400814a85c8c8c24e9bac316d02bb5 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 20:01:10 +0200 Subject: [PATCH 07/11] Common: fix crash on dedicated server First change callback of cvar 'mp_gamemode' must be removed as its client only, calling this on the server causes a crash as we never initialize client specific systems, therefore, the globals used in the change callback are null. --- src/common/global.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/common/global.cpp b/src/common/global.cpp index 63721f29..13dae4a4 100644 --- a/src/common/global.cpp +++ b/src/common/global.cpp @@ -273,6 +273,12 @@ void ConVar_InitShipped(void) base_tickinterval_mp->RemoveFlags(FCVAR_DEVELOPMENTONLY); mp_gamemode->RemoveFlags(FCVAR_DEVELOPMENTONLY); + +#ifdef DEDICATED + // The base callback is for client builds only, must be removed from the + // dedicated server as it features client globals. + mp_gamemode->RemoveChangeCallback(mp_gamemode->GetChangeCallback(0), 0); +#endif // DEDICATED mp_gamemode->InstallChangeCallback(MP_GameMode_Changed_f, nullptr, false); net_usesocketsforloopback->RemoveFlags(FCVAR_DEVELOPMENTONLY); #ifndef DEDICATED From b11d7e3c9b1555673d6cb490e60eca19153195e9 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 20:08:28 +0200 Subject: [PATCH 08/11] Engine: add new netmsg 'SVC_SetClassVar' Netmessage SVC_SetClassVar allows the server to change class settings securely on the client. This was implemented due to popular demand, and previous approaches using a combination of ClientCommands (Cbuf and NET_StringCmd) were deemed insecure and unreliable. --- src/common/callback.h | 6 ++++ src/common/netmessages.cpp | 34 ++++++++++++++++++- src/common/netmessages.h | 54 ++++++++++++++++++++++++++++++- src/engine/client/clientstate.cpp | 1 + 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/common/callback.h b/src/common/callback.h index 9ca4d1ed..89dfe958 100644 --- a/src/common/callback.h +++ b/src/common/callback.h @@ -4,6 +4,8 @@ inline bool(*v_SetupGamemode)(const char* pszPlayList); /* ==== CONCOMMANDCALLBACK ============================================================================================================================================== */ inline void(*v__Cmd_Exec_f)(const CCommand& args); +inline bool(*v__setClassVarServer_f)(const CCommand& args); +inline bool(*v__setClassVarClient_f)(const CCommand& args); #ifndef DEDICATED inline void(*v__UIScript_Reset_f)(); #endif // !DEDICATED @@ -41,6 +43,8 @@ class VCallback : public IDetour { LogFunAdr("SetupGamemode", v_SetupGamemode); LogFunAdr("Cmd_Exec_f", v__Cmd_Exec_f); + LogFunAdr("SetClassVarServer_f", v__setClassVarServer_f); + LogFunAdr("SetClassVarClient_f", v__setClassVarClient_f); #ifndef DEDICATED LogFunAdr("UIScript_Reset_f", v__UIScript_Reset_f); #endif // !DEDICATED @@ -49,6 +53,8 @@ class VCallback : public IDetour { g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??").GetPtr(v_SetupGamemode); g_GameDll.FindPatternSIMD("40 55 53 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B D9").GetPtr(v__Cmd_Exec_f); + g_GameDll.FindPatternSIMD("41 56 48 83 EC ?? 8B 05 ?? ?? ?? ?? 4C 8B F1 FF C0").GetPtr(v__setClassVarServer_f); + g_GameDll.FindPatternSIMD("4C 8B DC 57 48 81 EC ?? ?? ?? ?? 8B 05").GetPtr(v__setClassVarClient_f); #ifndef DEDICATED g_GameDll.FindPatternSIMD("40 55 41 54 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 45 33 E4 48 8D 0D").GetPtr(v__UIScript_Reset_f); #endif // !DEDICATED diff --git a/src/common/netmessages.cpp b/src/common/netmessages.cpp index 2e76f72f..29973460 100644 --- a/src/common/netmessages.cpp +++ b/src/common/netmessages.cpp @@ -12,6 +12,7 @@ #include "tier1/cvar.h" #include "engine/net.h" #include "common/netmessages.h" +#include "common/callback.h" #include "game/shared/usermessages.h" /////////////////////////////////////////////////////////////////////////////////// @@ -64,6 +65,37 @@ bool SVC_UserMessage::ProcessImpl() return SVC_UserMessage_Process(this); // Need to return original. } +/////////////////////////////////////////////////////////////////////////////////// +// Net message to change class settings vars on the client +/////////////////////////////////////////////////////////////////////////////////// +bool SVC_SetClassVar::ReadFromBuffer(bf_read* buffer) +{ + const bool set = buffer->ReadString(m_szSetting, sizeof(m_szSetting)); + const bool var = buffer->ReadString(m_szVariable, sizeof(m_szVariable)); + + return set && var; +} +bool SVC_SetClassVar::WriteToBuffer(bf_write* buffer) +{ + const bool set = buffer->WriteString(m_szSetting); + const bool var = buffer->WriteString(m_szVariable); + + return set && var; +} +bool SVC_SetClassVar::Process(void) +{ + const char* pArgs[3] = { + "_setClassVarClient", + m_szSetting, + m_szVariable + }; + + CCommand command((int)V_ARRAYSIZE(pArgs), pArgs, cmd_source_t::kCommandSrcCode); + v__setClassVarClient_f(command); + + return true; +} + /////////////////////////////////////////////////////////////////////////////////// // Below functions are hooked as playlist overrides can be abused from the client. // The client could basically manage the server's playlists. Only allow read/write @@ -122,7 +154,7 @@ bool Base_CmdKeyValues::WriteToBufferImpl(Base_CmdKeyValues* thisptr, bf_write* // determine whether or not the message should be copied into the replay buffer, // regardless of the 'CNetMessage::m_Group' type. /////////////////////////////////////////////////////////////////////////////////// -bool ShouldReplayMessage(const CNetMessage* msg) +bool ShouldReplayMessage(const CNetMessage* msg) // todo(amos): rename to 'CanReplayMessage' { switch (msg->GetType()) { diff --git a/src/common/netmessages.h b/src/common/netmessages.h index 7e226b04..d6a2f79e 100644 --- a/src/common/netmessages.h +++ b/src/common/netmessages.h @@ -162,6 +162,15 @@ enum NetMessageType clc_AntiCheat = 63, clc_AntiCheatChallenge = 64, clc_GamepadMsg = 65, + + // NOTE: if you make new netmessages, the order should be as follows: + // - NET (messages shared between server & client). + // - SVC (messages originating from the server). + // - CLC (messages originating from the client. + // Reorder message indices to retain consistency here. + // -------------------------------------------------------------------- + // From here on, SDK netmessages are enumerated. + svc_SetClassVar = 66, }; //------------------------------------------------------------------------- @@ -176,10 +185,16 @@ enum NetMessageGroup class CNetMessage : public INetMessage { public: + virtual void SetNetChannel(CNetChan* netchan) { m_NetChannel = netchan; } + virtual void SetReliable(bool state) { m_bReliable = state; } + virtual bool IsReliable(void) const { return m_bReliable; } + virtual int GetGroup(void) const { return m_nGroup; } + virtual CNetChan* GetNetChannel(void) const { return m_NetChannel; } + int m_nGroup; bool m_bReliable; CNetChan* m_NetChannel; - INetMessageHandler* m_pMessageHandler; + INetChannelHandler* m_pMessageHandler; }; /////////////////////////////////////////////////////////////////////////////////////// @@ -445,6 +460,43 @@ private: bf_write m_DataOut; }; +class SVC_SetClassVar : public CNetMessage +{ +public: + SVC_SetClassVar() = default; + SVC_SetClassVar(const char* setting, const char* var) + { + V_strncpy(m_szSetting, setting, sizeof(m_szSetting)); + V_strncpy(m_szVariable, var, sizeof(m_szVariable)); + + m_szSetting[sizeof(m_szSetting) - 1] = '\0'; + m_szVariable[sizeof(m_szVariable) - 1] = '\0'; + + m_nGroup = 2; // must be set to 2 to avoid being copied into replay buffer + } + + virtual bool ReadFromBuffer(bf_read* buffer); + virtual bool WriteToBuffer(bf_write* buffer); + + virtual bool Process(void); + + virtual int GetType(void) const { return svc_SetClassVar; }; + virtual const char* GetName(void) const { return "svc_SetClassVar"; }; + + virtual const char* ToString(void) const + { + static char szBuf[4096]; + V_snprintf(szBuf, sizeof(szBuf), "%s: setting \"%s\", variable \"%s\"", this->GetName(), m_szSetting, m_szVariable); + + return szBuf; + }; + + virtual size_t GetSize(void) const { return sizeof(SVC_SetClassVar); } + + char m_szSetting[128]; + char m_szVariable[128]; +}; + /////////////////////////////////////////////////////////////////////////////////////// // Client messages: /////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/engine/client/clientstate.cpp b/src/engine/client/clientstate.cpp index b978f44b..058aa1fa 100644 --- a/src/engine/client/clientstate.cpp +++ b/src/engine/client/clientstate.cpp @@ -509,6 +509,7 @@ void CClientState::Reconnect() //--------------------------------------------------------------------------------- void CClientState::RegisterNetMsgs(CNetChan* chan) { + REGISTER_SVC_MSG(SetClassSettingsVar); } void VClientState::Detour(const bool bAttach) const From ba5801cce61851693b0e565323423de4d9d1d0ce Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 25 Sep 2024 20:12:14 +0200 Subject: [PATCH 09/11] Server: implement script utility to set class variables on connected players Allows setting class var changes on all connected players (SetClassVarSynced(key, val)), or on individual players (player.SetClassVar(key, val)). --- src/game/server/vscript_server.cpp | 103 +++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/game/server/vscript_server.cpp b/src/game/server/vscript_server.cpp index c5d03548..a69176b7 100644 --- a/src/game/server/vscript_server.cpp +++ b/src/game/server/vscript_server.cpp @@ -18,6 +18,7 @@ #include "vscript_server.h" #include #include +#include "player.h" /* ===================== @@ -275,6 +276,98 @@ namespace VScriptCode sq_pushbool(v, ::IsDedicated()); SCRIPT_CHECK_AND_RETURN(v, SQ_OK); } + + //----------------------------------------------------------------------------- + // Purpose: sets a class var on the server and each client + // TODO: currently, this relies on the client running _secClassVarServer + // for its player class vars to be adjusted on the server as well. Not really + // exploitable on the client as omitting this will prevent the server from + // setting it in their player instance effectively screwing up the prediction, + // but it might be nice to run it from the server and propagate all changes to + // each client individually from an architectural point of view. + // Furthermore (only for SetClassVarSynced, not the individual one from + // PlayerStruct) it might also be good to research potential ways to track + // class var changes and sync them back to clients connecting after this has + // been called. + //----------------------------------------------------------------------------- + SQRESULT SetClassVarSynced(HSQUIRRELVM v) + { + const SQChar* key = nullptr; + sq_getstring(v, 2, &key); + + if (!VALID_CHARSTAR(key)) + { + v_SQVM_ScriptError("Empty or null class key"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } + + const SQChar* val = nullptr; + sq_getstring(v, 3, &val); + + if (!VALID_CHARSTAR(val)) + { + v_SQVM_ScriptError("Empty or null class var"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } + + SVC_SetClassVar msg(key, val); + bool failure = false; + + for (int i = 0; i < gpGlobals->maxClients; i++) + { + CClient* const client = g_pServer->GetClient(i); + + // is this client fully connected + if (client->GetSignonState() != SIGNONSTATE::SIGNONSTATE_FULL) + continue; + + if (!client->SendNetMsgEx(&msg, false, true, false)) + failure = true; + } + + sq_pushbool(v, !failure); + SCRIPT_CHECK_AND_RETURN(v, SQ_OK); + } + } + + namespace PlayerEntity + { + //----------------------------------------------------------------------------- + // Purpose: sets a class var on the server and each client + //----------------------------------------------------------------------------- + SQRESULT ScriptSetClassVar(HSQUIRRELVM v) + { + CPlayer* player = nullptr; + + if (!v_sq_getentity(v, (SQEntity*)&player)) + return SQ_ERROR; + + const SQChar* key = nullptr; + sq_getstring(v, 2, &key); + + if (!VALID_CHARSTAR(key)) + { + v_SQVM_ScriptError("Empty or null class key"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } + + const SQChar* val = nullptr; + sq_getstring(v, 3, &val); + + if (!VALID_CHARSTAR(val)) + { + v_SQVM_ScriptError("Empty or null class var"); + SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); + } + + CClient* const client = g_pServer->GetClient(player->GetEdict() - 1); + SVC_SetClassVar msg(key, val); + + const bool success = client->SendNetMsgEx(&msg, false, true, false); + sq_pushbool(v, success); + + SCRIPT_CHECK_AND_RETURN(v, SQ_OK); + } } } @@ -311,6 +404,8 @@ void Script_RegisterCoreServerFunctions(CSquirrelVM* s) DEFINE_SERVER_SCRIPTFUNC_NAMED(s, SetAutoReloadState, "Set whether we can auto-reload the server", "void", "bool"); DEFINE_SERVER_SCRIPTFUNC_NAMED(s, GetServerID, "Gets the current server ID", "string", ""); + + DEFINE_SERVER_SCRIPTFUNC_NAMED(s, SetClassVarSynced, "Change a variable in the class settings for server and all connected clients", "bool", "string, string"); } //--------------------------------------------------------------------------------- @@ -358,6 +453,14 @@ static void Script_RegisterServerPlayerClassFuncs() return; initialized = true; + + g_serverScriptPlayerStruct->AddFunction("SetClassVar", + "ScriptSetClassVar", + "Change a variable in the player's class settings", + "bool", + "string, string", + 5, + VScriptCode::PlayerEntity::ScriptSetClassVar); } //--------------------------------------------------------------------------------- static void Script_RegisterServerAIClassFuncs() From 432cb923cc9fa4b322c39295b2e6eddd170c9980 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 28 Sep 2024 12:28:28 +0200 Subject: [PATCH 10/11] Engine: fix compile error Netmsg is defined as SVC_SetClassVar, not as SVC_SetClassSettingsVar. Rename was missed before submitting b11d7e3c9b1555673d6cb490e60eca19153195e9. --- src/engine/client/clientstate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/client/clientstate.cpp b/src/engine/client/clientstate.cpp index 058aa1fa..b328de96 100644 --- a/src/engine/client/clientstate.cpp +++ b/src/engine/client/clientstate.cpp @@ -509,7 +509,7 @@ void CClientState::Reconnect() //--------------------------------------------------------------------------------- void CClientState::RegisterNetMsgs(CNetChan* chan) { - REGISTER_SVC_MSG(SetClassSettingsVar); + REGISTER_SVC_MSG(SetClassVar); } void VClientState::Detour(const bool bAttach) const From d312597c91ddbc889e5817115bd18f2bb64a03bb Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 28 Sep 2024 12:43:11 +0200 Subject: [PATCH 11/11] Engine: rework class var command and netmsg design New command '_setClassVarClient' only sets the class var on the client, similar to how '_setClassVarServer' only sets it on the server. Command 'set' still has its old behavior, setting it on the server and client. The netmsg SVC_SetClassVar now only runs the _setClassVarClient handler, and if the netmsg was successfully sent, the code runs the _setClassVarServer handler directly instead of relying on the client to NET_StringMsg it in. This is a lot more reliable, secure and performant than the previous approach and drops the requirement of setting sv_cheats to function. --- src/common/callback.cpp | 29 ++++++++++++++++- src/common/callback.h | 17 ++++++++-- src/common/global.cpp | 3 ++ src/game/server/vscript_server.cpp | 50 +++++++++++++++++++++++------- 4 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/common/callback.cpp b/src/common/callback.cpp index 3a27f899..58b6c99e 100644 --- a/src/common/callback.cpp +++ b/src/common/callback.cpp @@ -23,6 +23,7 @@ #endif // !DEDICATED #include "engine/client/client.h" #include "engine/net.h" +#include "engine/cmd.h" #include "engine/host_cmd.h" #include "engine/host_state.h" #include "engine/enginetrace.h" @@ -256,6 +257,33 @@ void LanguageChanged_f(IConVar* pConVar, const char* pOldString, float flOldValu } #ifndef DEDICATED +void setClassVarClient_f(const CCommand& args) +{ + v__setClassVarClient_f(args); +} + +static ConCommand _setClassVarClient("_setClassVarClient", setClassVarClient_f, "Set a class var on the client", FCVAR_DEVELOPMENTONLY|FCVAR_CLIENTDLL|FCVAR_CHEAT|FCVAR_SERVER_CAN_EXECUTE); + +/* +===================== +Set_f + + Set a class var on the server & client. +===================== +*/ +void Set_f(const CCommand& args) +{ + v__setClassVarClient_f(args); + + const char* key = args.Arg(1); + const char* val = args.Arg(2); + + char buf[256]; + V_snprintf(buf, sizeof(buf), "_setClassVarServer %s \"%s\"\n", key, val); + + Cbuf_AddText(ECommandTarget_t::CBUF_FIRST_PLAYER, buf, cmd_source_t::kCommandSrcInvalid); +} + /* ===================== Mat_CrossHair_f @@ -583,7 +611,6 @@ void UIScript_Reset_f() } #endif // !DEDICATED - void VCallback::Detour(const bool bAttach) const { DetourSetup(&v__Cmd_Exec_f, &Cmd_Exec_f, bAttach); diff --git a/src/common/callback.h b/src/common/callback.h index 89dfe958..2426dbc7 100644 --- a/src/common/callback.h +++ b/src/common/callback.h @@ -4,12 +4,16 @@ inline bool(*v_SetupGamemode)(const char* pszPlayList); /* ==== CONCOMMANDCALLBACK ============================================================================================================================================== */ inline void(*v__Cmd_Exec_f)(const CCommand& args); -inline bool(*v__setClassVarServer_f)(const CCommand& args); -inline bool(*v__setClassVarClient_f)(const CCommand& args); +inline void(*v__setClassVarServer_f)(const CCommand& args); +inline void(*v__setClassVarClient_f)(const CCommand& args); #ifndef DEDICATED inline void(*v__UIScript_Reset_f)(); #endif // !DEDICATED +#ifndef CLIENT_DLL +inline int* g_nCommandClientIndex = nullptr; +#endif // !CLIENT_DLL + /////////////////////////////////////////////////////////////////////////////// void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData); #ifndef CLIENT_DLL @@ -25,6 +29,7 @@ void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValu #endif // !DEDICATED void LanguageChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue, ChangeUserData_t pUserData); #ifndef DEDICATED +void Set_f(const CCommand& args); void Mat_CrossHair_f(const CCommand& args); void Line_f(const CCommand& args); void Sphere_f(const CCommand& args); @@ -36,6 +41,7 @@ void CVHelp_f(const CCommand& args); void CVList_f(const CCommand& args); void CVDiff_f(const CCommand& args); void CVFlag_f(const CCommand& args); + /////////////////////////////////////////////////////////////////////////////// class VCallback : public IDetour { @@ -59,7 +65,12 @@ class VCallback : public IDetour g_GameDll.FindPatternSIMD("40 55 41 54 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 45 33 E4 48 8D 0D").GetPtr(v__UIScript_Reset_f); #endif // !DEDICATED } - virtual void GetVar(void) const { } + virtual void GetVar(void) const + { +#ifndef CLIENT_DLL + CMemory(v__setClassVarServer_f).FindPatternSelf("8B 05").ResolveRelativeAddressSelf(2, 6).GetPtr(g_nCommandClientIndex); +#endif // !CLIENT_DLL + } virtual void GetCon(void) const { } virtual void Detour(const bool bAttach) const; }; diff --git a/src/common/global.cpp b/src/common/global.cpp index 13dae4a4..faed4cfc 100644 --- a/src/common/global.cpp +++ b/src/common/global.cpp @@ -385,6 +385,7 @@ void ConCommand_InitShipped(void) //------------------------------------------------------------------------- // CLIENT DLL | ConCommand* give = g_pCVar->FindCommand("give"); + ConCommand* set = g_pCVar->FindCommand("set"); #endif // !DEDICATED help->m_fnCommandCallback = CVHelp_f; @@ -403,6 +404,7 @@ void ConCommand_InitShipped(void) #ifndef DEDICATED mat_crosshair->m_fnCommandCallback = Mat_CrossHair_f; give->m_fnCompletionCallback = Game_Give_f_CompletionFunc; + set->m_fnCommandCallback = Set_f; #endif // !DEDICATED /// ------------------------------------------------------ [ FLAG REMOVAL ] @@ -474,6 +476,7 @@ void ConCommand_PurgeShipped(void) "getpos_bind", "connect", "silent_connect", + "set", "ping", "gameui_activate", "gameui_hide", diff --git a/src/game/server/vscript_server.cpp b/src/game/server/vscript_server.cpp index a69176b7..986edde8 100644 --- a/src/game/server/vscript_server.cpp +++ b/src/game/server/vscript_server.cpp @@ -19,6 +19,7 @@ #include #include #include "player.h" +#include /* ===================== @@ -279,16 +280,8 @@ namespace VScriptCode //----------------------------------------------------------------------------- // Purpose: sets a class var on the server and each client - // TODO: currently, this relies on the client running _secClassVarServer - // for its player class vars to be adjusted on the server as well. Not really - // exploitable on the client as omitting this will prevent the server from - // setting it in their player instance effectively screwing up the prediction, - // but it might be nice to run it from the server and propagate all changes to - // each client individually from an architectural point of view. - // Furthermore (only for SetClassVarSynced, not the individual one from - // PlayerStruct) it might also be good to research potential ways to track - // class var changes and sync them back to clients connecting after this has - // been called. + // TODO: it might also be good to research potential ways to track class var + // changes and sync them back to clients connecting after this has been called. //----------------------------------------------------------------------------- SQRESULT SetClassVarSynced(HSQUIRRELVM v) { @@ -310,8 +303,17 @@ namespace VScriptCode SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR); } + const char* pArgs[3] = { + "_setClassVarServer", + key, + val + }; + SVC_SetClassVar msg(key, val); + const CCommand cmd((int)V_ARRAYSIZE(pArgs), pArgs, cmd_source_t::kCommandSrcCode); + bool failure = false; + const int oldIdx = *g_nCommandClientIndex; for (int i = 0; i < gpGlobals->maxClients; i++) { @@ -321,10 +323,17 @@ namespace VScriptCode if (client->GetSignonState() != SIGNONSTATE::SIGNONSTATE_FULL) continue; - if (!client->SendNetMsgEx(&msg, false, true, false)) + if (client->SendNetMsgEx(&msg, false, true, false)) + { + *g_nCommandClientIndex = client->GetUserID(); + v__setClassVarServer_f(cmd); + } + else // Not all clients have their class var set. failure = true; } + *g_nCommandClientIndex = oldIdx; + sq_pushbool(v, !failure); SCRIPT_CHECK_AND_RETURN(v, SQ_OK); } @@ -364,8 +373,25 @@ namespace VScriptCode SVC_SetClassVar msg(key, val); const bool success = client->SendNetMsgEx(&msg, false, true, false); - sq_pushbool(v, success); + if (success) + { + const char* pArgs[3] = { + "_setClassVarServer", + key, + val + }; + + const CCommand cmd((int)V_ARRAYSIZE(pArgs), pArgs, cmd_source_t::kCommandSrcCode); + const int oldIdx = *g_nCommandClientIndex; + + *g_nCommandClientIndex = client->GetUserID(); + v__setClassVarServer_f(cmd); + + *g_nCommandClientIndex = oldIdx; + } + + sq_pushbool(v, success); SCRIPT_CHECK_AND_RETURN(v, SQ_OK); } }