From c86f0c5c6a39a1beb69cc5149774541406d0b927 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 25 Nov 2023 17:41:08 +0100 Subject: [PATCH] Check if we have enough room for new execution markers Make sure we always have enough room for new execution markers. Engine normally truncates the head of the vector if out of room; we want to avoid it as this will cause the cookies to shift, and thus cause them to misalign with their respective commands. --- r5dev/engine/client/clientstate.cpp | 55 +++++++++++++++++---- r5dev/engine/client/clientstate.h | 15 ++++++ r5dev/engine/client/vengineclient_impl.cpp | 45 ++++++++++++++++- r5dev/engine/client/vengineclient_impl.h | 17 +++++-- r5dev/engine/cmd.cpp | 56 +++++++++++++++++++++- r5dev/engine/cmd.h | 53 ++++++++++++++++---- 6 files changed, 218 insertions(+), 23 deletions(-) diff --git a/r5dev/engine/client/clientstate.cpp b/r5dev/engine/client/clientstate.cpp index 9124f29d..dd794624 100644 --- a/r5dev/engine/client/clientstate.cpp +++ b/r5dev/engine/client/clientstate.cpp @@ -13,11 +13,15 @@ #include "tier0/frametask.h" #include "engine/common.h" #include "engine/host.h" +#ifndef CLIENT_DLL +#include "engine/server/server.h" +#endif // !CLIENT_DLL #include "clientstate.h" #include "common/callback.h" #include "cdll_engine_int.h" #include "vgui/vgui_baseui_interface.h" #include +#include //------------------------------------------------------------------------------ @@ -146,25 +150,58 @@ void CClientState::VConnectionClosing(CClientState* thisptr, const char* szReaso // no longer can process server ticks every frame unlike previous games. // Without this, the server CPU and frame time don't get updated to the client. //------------------------------------------------------------------------------ -bool CClientState::VProcessServerTick(CClientState* pClientState, SVC_ServerTick* pServerTick) +bool CClientState::VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg) { - if (pServerTick->m_NetTick.m_nCommandTick != -1) + if (msg->m_NetTick.m_nCommandTick != -1) { - return CClientState__ProcessServerTick(pClientState, pServerTick); + return CClientState__ProcessServerTick(thisptr, msg); } else // Statistics only. { - char* pShifted = reinterpret_cast(pClientState) - 0x10; // Shifted due to compiler optimizations. - CClientState* pClient_Adj = reinterpret_cast(pShifted); + CClientState* const thisptr_ADJ = thisptr->GetShiftedBasePointer(); - CNetChan* pChan = pClient_Adj->m_NetChannel; - pChan->SetRemoteFramerate(pServerTick->m_NetTick.m_flHostFrameTime, pServerTick->m_NetTick.m_flHostFrameTimeStdDeviation); - pChan->SetRemoteCPUStatistics(pServerTick->m_NetTick.m_nServerCPU); + CNetChan* const pChan = thisptr_ADJ->m_NetChannel; + pChan->SetRemoteFramerate(msg->m_NetTick.m_flHostFrameTime, msg->m_NetTick.m_flHostFrameTimeStdDeviation); + pChan->SetRemoteCPUStatistics(msg->m_NetTick.m_nServerCPU); return true; } } +bool CClientState::_ProcessStringCmd(CClientState* thisptr, NET_StringCmd* msg) +{ + CClientState* const thisptr_ADJ = thisptr->GetShiftedBasePointer(); + + if (thisptr_ADJ->m_bRestrictServerCommands +#ifndef CLIENT_DLLInternalProcessStringCmd + && !g_pServer->IsActive() +#endif // !CLIENT_DLL + ) + { + CCommand args; + args.Tokenize(msg->cmd, cmd_source_t::kCommandSrcInvalid); + + if (args.ArgC() > 0) + { + if (!Cbuf_AddTextWithMarkers(msg->cmd, + eCmdExecutionMarker_Enable_FCVAR_SERVER_CAN_EXECUTE, + eCmdExecutionMarker_Disable_FCVAR_SERVER_CAN_EXECUTE)) + { + DevWarning(eDLL_T::CLIENT, "%s: No room for %i execution markers; command \"%s\" ignored\n", + __FUNCTION__, 2, msg->cmd); + } + + return true; + } + } + else + { + Cbuf_AddText(Cbuf_GetCurrentPlayer(), msg->cmd, cmd_source_t::kCommandSrcCode); + } + + return true; +} + //------------------------------------------------------------------------------ // Purpose: get authentication token for current connection context // Input : *connectParams - @@ -251,6 +288,7 @@ void CClientState::VConnect(CClientState* thisptr, connectparams_t* connectParam void VClientState::Attach() const { DetourAttach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing); + DetourAttach(&CClientState__ProcessStringCmd, &CClientState::_ProcessStringCmd); DetourAttach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick); DetourAttach(&CClientState__Connect, &CClientState::VConnect); } @@ -258,6 +296,7 @@ void VClientState::Attach() const void VClientState::Detach() const { DetourDetach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing); + DetourDetach(&CClientState__ProcessStringCmd, &CClientState::_ProcessStringCmd); DetourDetach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick); DetourDetach(&CClientState__Connect, &CClientState::VConnect); } diff --git a/r5dev/engine/client/clientstate.h b/r5dev/engine/client/clientstate.h index a11af46e..a3a03500 100644 --- a/r5dev/engine/client/clientstate.h +++ b/r5dev/engine/client/clientstate.h @@ -36,6 +36,7 @@ class CClientState : CS_INetChannelHandler, IConnectionlessPacketHandler, IServe friend class ClientDataBlockReceiver; public: // Hook statics. static void VConnectionClosing(CClientState* thisptr, const char* szReason); + static bool _ProcessStringCmd(CClientState* thisptr, NET_StringCmd* msg); static bool VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg); static void VConnect(CClientState* thisptr, connectparams_t* connectParams); @@ -59,6 +60,14 @@ public: bool Authenticate(connectparams_t* connectParams, char* const reasonBuf, const size_t reasonBufLen) const; +protected: + FORCEINLINE CClientState* GetShiftedBasePointer(void) + { + char* const pShifted = reinterpret_cast(this) - 0x10; // Shifted due to compiler optimizations. + return reinterpret_cast(pShifted); + } + +public: int m_Socket; int _padding_maybe; CNetChan* m_NetChannel; @@ -221,6 +230,9 @@ inline void(*CClientState__Disconnect)(CClientState* thisptr, bool bSendTracking inline CMemory p_CClientState__ConnectionClosing; inline void(*CClientState__ConnectionClosing)(CClientState* thisptr, const char* szReason); +inline CMemory p_CClientState__ProcessStringCmd; +inline bool(*CClientState__ProcessStringCmd)(CClientState* thisptr, NET_StringCmd* msg); + inline CMemory p_CClientState__ProcessServerTick; inline bool(*CClientState__ProcessServerTick)(CClientState* thisptr, SVC_ServerTick* msg); @@ -233,6 +245,7 @@ class VClientState : public IDetour LogFunAdr("CClientState::Connect", p_CClientState__Connect.GetPtr()); LogFunAdr("CClientState::Disconnect", p_CClientState__Disconnect.GetPtr()); LogFunAdr("CClientState::ConnectionClosing", p_CClientState__ConnectionClosing.GetPtr()); + LogFunAdr("CClientState::ProcessStringCmd", p_CClientState__ProcessStringCmd.GetPtr()); LogFunAdr("CClientState::ProcessServerTick", p_CClientState__ProcessServerTick.GetPtr()); LogVarAdr("g_ClientState", reinterpret_cast(g_pClientState)); LogVarAdr("g_ClientState_Shifted", reinterpret_cast(g_pClientState_Shifted)); @@ -249,6 +262,7 @@ class VClientState : public IDetour p_CClientState__Disconnect = g_GameDll.FindPatternSIMD("40 56 57 41 54 41 55 41 57 48 83 EC 30 44 0F B6 FA"); p_CClientState__ConnectionClosing = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B DA 0F 8E ?? ?? ?? ??"); #endif + p_CClientState__ProcessStringCmd = g_GameDll.FindPatternSIMD("40 53 48 81 EC ?? ?? ?? ?? 80 B9 ?? ?? ?? ?? ?? 48 8B DA"); p_CClientState__ProcessServerTick = g_GameDll.FindPatternSIMD("40 57 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B F9 7C 66"); p_CClientState__Connect = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC ?? ?? ?? ?? 48 8B 32"); @@ -258,6 +272,7 @@ class VClientState : public IDetour CClientState__Connect = p_CClientState__Connect.RCast(); CClientState__Disconnect = p_CClientState__Disconnect.RCast(); CClientState__ConnectionClosing = p_CClientState__ConnectionClosing.RCast(); + CClientState__ProcessStringCmd = p_CClientState__ProcessStringCmd.RCast(); CClientState__ProcessServerTick = p_CClientState__ProcessServerTick.RCast(); } virtual void GetVar(void) const diff --git a/r5dev/engine/client/vengineclient_impl.cpp b/r5dev/engine/client/vengineclient_impl.cpp index 21a8e397..5462f276 100644 --- a/r5dev/engine/client/vengineclient_impl.cpp +++ b/r5dev/engine/client/vengineclient_impl.cpp @@ -5,6 +5,7 @@ //=============================================================================// #include "core/stdafx.h" +#include "engine/cmd.h" #include "clientstate.h" #include "vengineclient_impl.h" @@ -61,4 +62,46 @@ int CEngineClient::GetLocalPlayer() const static int index = 36; #endif return CallVFunc(index, this); -} \ No newline at end of file +} + +//--------------------------------------------------------------------------------- +// Purpose: execute client command +// Input : *thisptr - +// *szCmdString - +// Output : +//--------------------------------------------------------------------------------- +void CEngineClient::_ClientCmd(CEngineClient* thisptr, const char* const szCmdString) +{ + const bool restrictClientCommands = g_pClientState->m_bRestrictClientCommands; + const int numMarkers = 2; + + if (restrictClientCommands && !Cbuf_HasRoomForExecutionMarkers(numMarkers)) + { + DevWarning(eDLL_T::CLIENT, "%s: No room for %i execution markers; command \"%s\" ignored\n", + __FUNCTION__, numMarkers, szCmdString); + return; + } + + if (restrictClientCommands) + { + Cbuf_AddExecutionMarker(Cbuf_GetCurrentPlayer(), eCmdExecutionMarker_Enable_FCVAR_CLIENTCMD_CAN_EXECUTE); + } + + Cbuf_AddText(Cbuf_GetCurrentPlayer(), szCmdString, cmd_source_t::kCommandSrcCode); + Cbuf_AddText(Cbuf_GetCurrentPlayer(), "\n", cmd_source_t::kCommandSrcCode); + + if (restrictClientCommands) + { + Cbuf_AddExecutionMarker(Cbuf_GetCurrentPlayer(), eCmdExecutionMarker_Disable_FCVAR_CLIENTCMD_CAN_EXECUTE); + } +} + +void HVEngineClient::Attach() const +{ + DetourAttach(&CEngineClient__ClientCmd, &CEngineClient::_ClientCmd); +} + +void HVEngineClient::Detach() const +{ + DetourDetach(&CEngineClient__ClientCmd, &CEngineClient::_ClientCmd); +} diff --git a/r5dev/engine/client/vengineclient_impl.h b/r5dev/engine/client/vengineclient_impl.h index 4872861e..6c346d4c 100644 --- a/r5dev/engine/client/vengineclient_impl.h +++ b/r5dev/engine/client/vengineclient_impl.h @@ -8,10 +8,16 @@ public: void SetRestrictClientCommands(bool bRestrict); bool GetRestrictClientCommands() const; int GetLocalPlayer(); // Local player index. + + // Hook statics: + static void _ClientCmd(CEngineClient* thisptr, const char* const szCmdString); }; /* ==== CVENGINECLIENT ================================================================================================================================================== */ /////////////////////////////////////////////////////////////////////////////// +inline CMemory p_CEngineClient__ClientCmd; +inline void(*CEngineClient__ClientCmd)(CEngineClient* thisptr, const char* const szCmdString); + inline CMemory g_pEngineClientVFTable = nullptr; inline CEngineClient* g_pEngineClient = nullptr; @@ -21,15 +27,20 @@ class HVEngineClient : public IDetour virtual void GetAdr(void) const { LogConAdr("CEngineClient::`vftable'", g_pEngineClientVFTable.GetPtr()); + LogFunAdr("CEngineClient::ClientCmd", p_CEngineClient__ClientCmd.GetPtr()); + } + virtual void GetFun(void) const + { + p_CEngineClient__ClientCmd = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 80 3D ?? ?? ?? ?? ?? 48 8B DA 74 0C"); + CEngineClient__ClientCmd = p_CEngineClient__ClientCmd.RCast(); } - virtual void GetFun(void) const { } virtual void GetVar(void) const { } virtual void GetCon(void) const { g_pEngineClientVFTable = g_GameDll.GetVirtualMethodTable(".?AVCEngineClient@@"); g_pEngineClient = g_pEngineClientVFTable.RCast(); } - virtual void Attach(void) const { } - virtual void Detach(void) const { } + virtual void Attach(void) const; + virtual void Detach(void) const; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/engine/cmd.cpp b/r5dev/engine/cmd.cpp index 527343c6..50f2e37d 100644 --- a/r5dev/engine/cmd.cpp +++ b/r5dev/engine/cmd.cpp @@ -1,8 +1,60 @@ #include "core/stdafx.h" #include "tier1/cmd.h" #include "tier1/cvar.h" +#include "tier1/commandbuffer.h" #include "engine/cmd.h" +CCommandBuffer** s_pCommandBuffer = nullptr; // array size = ECommandTarget_t::CBUF_COUNT. +LPCRITICAL_SECTION s_pCommandBufferMutex = nullptr; + +//============================================================================= +// List of execution markers +//============================================================================= +CUtlVector* g_pExecutionMarkers = nullptr; + +//----------------------------------------------------------------------------- +// Purpose: checks if there's room left for execution markers +// Input : cExecutionMarkers - +// Output : true if there's room for execution markers, false otherwise +//----------------------------------------------------------------------------- +bool Cbuf_HasRoomForExecutionMarkers(const int cExecutionMarkers) +{ + return (g_pExecutionMarkers->Count() + cExecutionMarkers) < MAX_EXECUTION_MARKERS; +} + +//----------------------------------------------------------------------------- +// Purpose: adds command text at the end of the command buffer with execution markers +// Input : *pText - +// markerLeft - +// markerRight - +// Output : true if there's room for execution markers, false otherwise +//----------------------------------------------------------------------------- +bool Cbuf_AddTextWithMarkers(const char* const pText, const ECmdExecutionMarker markerLeft, const ECmdExecutionMarker markerRight) +{ + if (Cbuf_HasRoomForExecutionMarkers(2)) + { + Cbuf_AddExecutionMarker(Cbuf_GetCurrentPlayer(), markerLeft); + Cbuf_AddText(Cbuf_GetCurrentPlayer(), pText, cmd_source_t::kCommandSrcCode); + Cbuf_AddExecutionMarker(Cbuf_GetCurrentPlayer(), markerRight); + + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: adds command text at the end of the buffer +//----------------------------------------------------------------------------- +//void Cbuf_AddText(ECommandTarget_t eTarget, const char* pText, int nTickDelay) +//{ +// LOCK_COMMAND_BUFFER(); +// if (!s_pCommandBuffer[(int)eTarget]->AddText(pText, nTickDelay, cmd_source_t::kCommandSrcInvalid)) +// { +// Error(eDLL_T::ENGINE, NO_ERROR, "%s: buffer overflow\n", __FUNCTION__); +// } +//} + //----------------------------------------------------------------------------- // Purpose: Sends the entire command line over to the server // Input : *args - @@ -19,8 +71,8 @@ bool Cmd_ForwardToServer(const CCommand* args) if (args->ArgC() == 0) return false; - double flStartTime = Plat_FloatTime(); - int nCmdQuotaLimit = cl_quota_stringCmdsPerSecond->GetInt(); + const double flStartTime = Plat_FloatTime(); + const int nCmdQuotaLimit = cl_quota_stringCmdsPerSecond->GetInt(); const char* pszCmdString = nullptr; // Special case: "cmd whatever args..." is forwarded as "whatever args..."; diff --git a/r5dev/engine/cmd.h b/r5dev/engine/cmd.h index 0840ebc1..63e0c514 100644 --- a/r5dev/engine/cmd.h +++ b/r5dev/engine/cmd.h @@ -1,5 +1,17 @@ #ifndef CMD_H #define CMD_H +#include "tier1/commandbuffer.h" + +#define MAX_EXECUTION_MARKERS 2048 + +typedef enum +{ + eCmdExecutionMarker_Enable_FCVAR_SERVER_CAN_EXECUTE = 'a', + eCmdExecutionMarker_Disable_FCVAR_SERVER_CAN_EXECUTE = 'b', + + eCmdExecutionMarker_Enable_FCVAR_CLIENTCMD_CAN_EXECUTE = 'c', + eCmdExecutionMarker_Disable_FCVAR_CLIENTCMD_CAN_EXECUTE = 'd' +} ECmdExecutionMarker; //----------------------------------------------------------------------------- // Purpose: Returns current player calling this function @@ -11,10 +23,16 @@ FORCEINLINE ECommandTarget_t Cbuf_GetCurrentPlayer(void) return ECommandTarget_t::CBUF_FIRST_PLAYER; } +extern bool Cbuf_HasRoomForExecutionMarkers(const int cExecutionMarkers); +extern bool Cbuf_AddTextWithMarkers(const char* text, const ECmdExecutionMarker markerLeft, const ECmdExecutionMarker markerRight); + /* ==== COMMAND_BUFFER ================================================================================================================================================== */ inline CMemory p_Cbuf_AddText; inline void(*Cbuf_AddText)(ECommandTarget_t eTarget, const char* pText, cmd_source_t cmdSource); +inline CMemory p_Cbuf_AddExecutionMarker; +inline void(*Cbuf_AddExecutionMarker)(ECommandTarget_t target, ECmdExecutionMarker marker); + inline CMemory p_Cbuf_Execute; inline void(*Cbuf_Execute)(void); @@ -24,30 +42,47 @@ inline void(*v_Cmd_Dispatch)(ECommandTarget_t eTarget, const ConCommandBase* pCm inline CMemory p_Cmd_ForwardToServer; inline bool(*v_Cmd_ForwardToServer)(const CCommand* pCommand); +extern CCommandBuffer** s_pCommandBuffer; +extern LPCRITICAL_SECTION s_pCommandBufferMutex; + +extern CUtlVector* g_pExecutionMarkers; + + /////////////////////////////////////////////////////////////////////////////// class VCmd : public IDetour { virtual void GetAdr(void) const { LogFunAdr("Cbuf_AddText", p_Cbuf_AddText.GetPtr()); + LogFunAdr("Cbuf_AddExecutionMarker", p_Cbuf_AddExecutionMarker.GetPtr()); LogFunAdr("Cbuf_Execute", p_Cbuf_Execute.GetPtr()); LogFunAdr("Cmd_Dispatch", p_Cmd_Dispatch.GetPtr()); LogFunAdr("Cmd_ForwardToServer", p_Cmd_ForwardToServer.GetPtr()); + LogVarAdr("s_CommandBuffer", reinterpret_cast(s_pCommandBuffer)); + LogVarAdr("s_CommandBufferMutex", reinterpret_cast(s_pCommandBufferMutex)); + LogVarAdr("g_ExecutionMarkers", reinterpret_cast(g_pExecutionMarkers)); } virtual void GetFun(void) const { - p_Cbuf_AddText = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 63 D9 41 8B F8 48 8D 0D ?? ?? ?? ?? 48 8B F2 FF 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 41 B9 ?? ?? ?? ??"); - p_Cbuf_Execute = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 FF 15 ?? ?? ?? ??"); + p_Cbuf_AddText = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 63 D9 41 8B F8 48 8D 0D ?? ?? ?? ?? 48 8B F2 FF 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 41 B9 ?? ?? ?? ??"); + p_Cbuf_AddExecutionMarker = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 05 ?? ?? ?? ??"); + p_Cbuf_Execute = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 FF 15 ?? ?? ?? ??"); - p_Cmd_Dispatch = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 8B ?? 0C 49 FF C7").FollowNearCallSelf(); - p_Cmd_ForwardToServer = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 59 04"); + p_Cmd_Dispatch = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 8B ?? 0C 49 FF C7").FollowNearCallSelf(); + p_Cmd_ForwardToServer = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 59 04"); - Cbuf_AddText = p_Cbuf_AddText.RCast(); /*48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 63 D9 41 8B F8 48 8D 0D ?? ?? ?? ?? 48 8B F2 FF 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 41 B9 ?? ?? ?? ??*/ - Cbuf_Execute = p_Cbuf_Execute.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 FF 15 ?? ?? ?? ??*/ - v_Cmd_Dispatch = p_Cmd_Dispatch.RCast(); - v_Cmd_ForwardToServer = p_Cmd_ForwardToServer.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 59 04*/ + Cbuf_AddText = p_Cbuf_AddText.RCast(); /*48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 63 D9 41 8B F8 48 8D 0D ?? ?? ?? ?? 48 8B F2 FF 15 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 41 B9 ?? ?? ?? ??*/ + Cbuf_AddExecutionMarker = p_Cbuf_AddExecutionMarker.RCast(); + Cbuf_Execute = p_Cbuf_Execute.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 FF 15 ?? ?? ?? ??*/ + v_Cmd_Dispatch = p_Cmd_Dispatch.RCast(); + v_Cmd_ForwardToServer = p_Cmd_ForwardToServer.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 44 8B 59 04*/ + } + virtual void GetVar(void) const + { + s_pCommandBuffer = p_Cbuf_AddText.FindPattern("48 8D 05").ResolveRelativeAddressSelf(3, 7).RCast(); + s_pCommandBufferMutex = p_Cbuf_AddText.FindPattern("48 8D 0D").ResolveRelativeAddressSelf(3, 7).RCast(); + g_pExecutionMarkers = p_Cbuf_AddExecutionMarker.FindPattern("48 8B 0D").ResolveRelativeAddressSelf(3, 7).RCast*>(); } - virtual void GetVar(void) const { } virtual void GetCon(void) const { } virtual void Attach(void) const; virtual void Detach(void) const;