From 514a407e4c0a5189ec2458fc151f671f05712b87 Mon Sep 17 00:00:00 2001 From: Marvin D <41352111+IcePixelx@users.noreply.github.com> Date: Sun, 18 Sep 2022 13:55:44 +0200 Subject: [PATCH 01/39] RPakHeader_t/RPakLoadedInfo_t additions --- r5dev/engine/host_state.cpp | 2 +- r5dev/rtech/rtech_utils.h | 61 ++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp index 44a0dc11..7c385d5c 100644 --- a/r5dev/engine/host_state.cpp +++ b/r5dev/engine/host_state.cpp @@ -330,7 +330,7 @@ FORCEINLINE void CHostState::GameShutDown(void) #ifndef CLIENT_DLL g_pServerGameDLL->GameShutdown(); #endif // !CLIENT_DLL - m_bActiveGame = 0; + m_bActiveGame = false; ResetLevelName(); } } diff --git a/r5dev/rtech/rtech_utils.h b/r5dev/rtech/rtech_utils.h index 78742b0f..95b8e580 100644 --- a/r5dev/rtech/rtech_utils.h +++ b/r5dev/rtech/rtech_utils.h @@ -114,31 +114,33 @@ struct RPakUnknownStruct_t struct RPakHeader_t { - uint32_t m_nMagic; // 'RPak' - uint16_t m_nVersion; // R2 = '7' R5 = '8' - uint8_t m_nFlags[0x2]; // - uint8_t m_nHash0[0x8]; // - uint8_t m_nHash1[0x8]; // - uint64_t m_nSizeDisk; // Compressed size - uint64_t m_nEmbeddedStarpakOffset; // - uint8_t unk0[0x8]; // - uint64_t m_nSizeMemory; // Decompressed size - uint64_t m_nEmbeddedStarpakSize; // - uint8_t unk1[0x8]; // + uint32_t m_nMagic; // 'RPak' + uint16_t m_nVersion; // R2 = '7' R5 = '8' + uint8_t m_nFlags[0x2]; // + uint8_t m_nHash0[0x8]; // + uint8_t m_nHash1[0x8]; // + uint64_t m_nSizeDisk; // Compressed size + uint64_t m_nEmbeddedStarpakOffset; // + uint8_t unk0[0x8]; // + uint64_t m_nSizeMemory; // Decompressed size + uint64_t m_nEmbeddedStarpakSize; // + uint8_t unk1[0x8]; // - uint16_t m_nStarpakReferenceSize; // - uint16_t m_nStarpakOptReferenceSize; // - uint16_t m_nVirtualSegmentCount; // * 0x10 - uint16_t m_nVirtualSegmentBlockCount; // * 0xC + uint16_t m_nStarpakReferenceSize; // + uint16_t m_nStarpakOptReferenceSize; // + uint16_t m_nVirtualSegmentCount; // * 0x10 + uint16_t m_nMemPageCount; // * 0xC - uint32_t m_nPatchIndex; // + uint32_t m_nPatchIndex; // - uint32_t m_nDescriptorCount; // - uint32_t m_nAssetEntryCount; // File entry count - uint32_t m_nGuidDescriptorCount; // - uint32_t m_nRelationsCounts; // + uint32_t m_nDescriptorCount; // + uint32_t m_nAssetEntryCount; // File entry count + uint32_t m_nGuidDescriptorCount; // + uint32_t m_nRelationsCounts; // - uint8_t unk2[0x1C]; // + uint8_t unk2[0x10]; // + uint32_t m_nMemPageOffset; // Size not verified. Offsets every page by x amount, if not 0 start of first page has data corresponding for 'patching some page' + uint8_t unk3[0x8]; // }; struct __declspec(align(8)) RPakPatchCompressedHeader_t @@ -424,11 +426,22 @@ public: char* m_pszFileName; //0x0018 void* m_pMalloc; //0x0020 uint64_t* m_pAssetGuids; //0x0028 size of the array is m_nAssetCount - char pad_0030[128]; //0x0030 +#if defined GAMEDLL_S3 + void* m_pVSegBuffers[4]; //0x0030 + char pad_0050[16]; //0x0050 + void* m_pPakInfo; //0x0060 + RPakLoadedInfo_t* m_pUnknownLoadedPakInfo; //0x0068 + char pad_0070[4]; //0x0070 + int8_t m_nUnk3; //0x0074 + char pad_0075[51]; //0x0075 + uint32_t m_nUnk4; //0x00A8 + uint8_t m_nUnk5; //0x00AC +#endif #if not defined GAMEDLL_S3 - char pad_00B0[48]; + char pad_0030[128]; //0x0030 + char pad_00B0[48]; //0x00B0 #endif // !GAMEDLL_S3 - uint64_t m_nUnkEnd; //0x00B0 + uint64_t m_nUnkEnd; //0x00B0/0x00E8 }; //Size: 0x00B8/0x00E8 /* ==== RTECH =========================================================================================================================================================== */ From e90d2572b1ab680ea1dec12c4f21adc1951fd930 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sun, 18 Sep 2022 19:01:37 +0200 Subject: [PATCH 02/39] Implement 'ThreadInServerFrameThread()' Tier0 export in r2, inline in r5. --- r5dev/tier0/threadtools.cpp | 5 +++++ r5dev/tier0/threadtools.h | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/r5dev/tier0/threadtools.cpp b/r5dev/tier0/threadtools.cpp index e3e86baa..ff03656e 100644 --- a/r5dev/tier0/threadtools.cpp +++ b/r5dev/tier0/threadtools.cpp @@ -40,6 +40,11 @@ bool ThreadInRenderThread() return (ThreadGetCurrentId() == g_ThreadRenderThreadID); } +bool ThreadInServerFrameThread() +{ + return (ThreadGetCurrentId() == (*g_ThreadServerFrameThreadID)); +} + ThreadId_t ThreadGetCurrentId() { #ifdef _WIN32 diff --git a/r5dev/tier0/threadtools.h b/r5dev/tier0/threadtools.h index 468e9559..28ba2594 100644 --- a/r5dev/tier0/threadtools.h +++ b/r5dev/tier0/threadtools.h @@ -55,6 +55,7 @@ inline void ThreadPause() bool ThreadInMainThread(); bool ThreadInRenderThread(); +bool ThreadInServerFrameThread(); ThreadId_t ThreadGetCurrentId(); //----------------------------------------------------------------------------- @@ -215,6 +216,7 @@ inline auto v_DeclareCurrentThreadIsMainThread = p_DeclareCurrentThreadIsMainThr inline ThreadId_t* g_ThreadMainThreadID = nullptr; inline ThreadId_t g_ThreadRenderThreadID = NULL; +inline ThreadId_t* g_ThreadServerFrameThreadID = nullptr; /////////////////////////////////////////////////////////////////////////////// class CThreadFastMutex @@ -248,6 +250,7 @@ class VThreadTools : public IDetour spdlog::debug("| FUN: CThreadFastMutex::ReleaseWaiter : {:#18x} |\n", p_MutexInternal_ReleaseWaiter.GetPtr()); spdlog::debug("| FUN: DeclareCurrentThreadIsMainThread : {:#18x} |\n", p_DeclareCurrentThreadIsMainThread.GetPtr()); spdlog::debug("| VAR: g_ThreadMainThreadID : {:#18x} |\n", reinterpret_cast(g_ThreadMainThreadID)); + spdlog::debug("| VAR: g_ThreadServerFrameThreadID : {:#18x} |\n", reinterpret_cast(g_ThreadServerFrameThreadID)); spdlog::debug("+----------------------------------------------------------------+\n"); } virtual void GetFun(void) const @@ -262,7 +265,9 @@ class VThreadTools : public IDetour } virtual void GetVar(void) const { - g_ThreadMainThreadID = p_DeclareCurrentThreadIsMainThread.FindPattern("89 05").ResolveRelativeAddressSelf(0x2, 0x6).RCast(); + g_ThreadMainThreadID = p_DeclareCurrentThreadIsMainThread.FindPattern("89 05").ResolveRelativeAddressSelf(0x2, 0x6).RCast(); + g_ThreadServerFrameThreadID = g_GameDll.FindPatternSIMD(reinterpret_cast("\x83\x79\x00\x00\x75\x28\x8B"), "xx?xxxx") + .FindPatternSelf("8B 05").ResolveRelativeAddressSelf(0x2, 0x6).RCast(); } virtual void GetCon(void) const { } virtual void Attach(void) const { } From 7d8d515190491a52b49ff684ec3f0b7dc27867d7 Mon Sep 17 00:00:00 2001 From: rexx <67599507+r-ex@users.noreply.github.com> Date: Sun, 18 Sep 2022 20:42:16 +0100 Subject: [PATCH 03/39] add global text chat use sv_forceChatToTeamOnly 0 to enable global chat --- r5dev/core/init.cpp | 2 ++ r5dev/game/server/gameinterface.cpp | 23 +++++++++++++++++++++++ r5dev/game/server/gameinterface.h | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 6bbc3f50..053eda63 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -191,6 +191,7 @@ void Systems_Init() #ifndef CLIENT_DLL Persistence_Attach(); IVEngineServer_Attach(); + CServerGameDLL_Attach(); #endif // !CLIENT_DLL SQAPI_Attach(); @@ -317,6 +318,7 @@ void Systems_Shutdown() #ifndef CLIENT_DLL Persistence_Detach(); IVEngineServer_Detach(); + CServerGameDLL_Detach(); #endif // !CLIENT_DLL SQAPI_Detach(); SQVM_Detach(); diff --git a/r5dev/game/server/gameinterface.cpp b/r5dev/game/server/gameinterface.cpp index 16842435..24bad774 100644 --- a/r5dev/game/server/gameinterface.cpp +++ b/r5dev/game/server/gameinterface.cpp @@ -56,6 +56,29 @@ float CServerGameDLL::GetTickInterval(void) return CallVFunc(index, this); } +void __fastcall CServerGameDLL::OnReceivedSayTextMessage(void* thisptr, int senderId, const char* text, bool isTeamChat) +{ +#if defined(GAMEDLL_S3) + // set isTeamChat to false so that we can let the convar sv_forceChatToTeamOnly decide whether team chat should be enforced + // this isn't a great way of doing it but it works so meh + CServerGameDLL__OnReceivedSayTextMessage(thisptr, senderId, text, false); +#endif +} + +void CServerGameDLL_Attach() +{ +#if defined(GAMEDLL_S3) + DetourAttach((LPVOID*)&CServerGameDLL__OnReceivedSayTextMessage, &CServerGameDLL::OnReceivedSayTextMessage); +#endif +} + +void CServerGameDLL_Detach() +{ +#if defined(GAMEDLL_S3) + DetourDetach((LPVOID*)&CServerGameDLL__OnReceivedSayTextMessage, &CServerGameDLL::OnReceivedSayTextMessage); +#endif +} + // Pointer to CServerGameDLL virtual function table. CServerGameDLL* g_pServerGameDLL = nullptr; CServerGameClients* g_pServerGameClients = nullptr; diff --git a/r5dev/game/server/gameinterface.h b/r5dev/game/server/gameinterface.h index 513a7d9f..0b670cd5 100644 --- a/r5dev/game/server/gameinterface.h +++ b/r5dev/game/server/gameinterface.h @@ -13,14 +13,22 @@ public: void LevelShutdown(void); void GameShutdown(void); float GetTickInterval(void); + + static void __fastcall OnReceivedSayTextMessage(void* thisptr, int senderId, const char* text, bool isTeamChat); }; class CServerGameClients { }; +inline CMemory p_CServerGameDLL__OnReceivedSayTextMessage; +inline auto CServerGameDLL__OnReceivedSayTextMessage = p_CServerGameDLL__OnReceivedSayTextMessage.RCast(); + extern CServerGameDLL* g_pServerGameDLL; extern CServerGameClients* g_pServerGameClients; +void CServerGameDLL_Attach(); +void CServerGameDLL_Detach(); + /////////////////////////////////////////////////////////////////////////////// class VServerGameDLL : public IDetour { @@ -30,7 +38,14 @@ class VServerGameDLL : public IDetour spdlog::debug("| VAR: g_pServerGameClients : {:#18x} |\n", reinterpret_cast(g_pServerGameClients)); spdlog::debug("+----------------------------------------------------------------+\n"); } - virtual void GetFun(void) const { } + virtual void GetFun(void) const + { +#if defined(GAMEDLL_S3) + p_CServerGameDLL__OnReceivedSayTextMessage = g_GameDll.FindPatternSIMD(reinterpret_cast("\x85\xD2\x0F\x8E\x00\x00\x00\x00\x4C\x8B\xDC"), "xxxx????xxx"); + + CServerGameDLL__OnReceivedSayTextMessage = p_CServerGameDLL__OnReceivedSayTextMessage.RCast(); +#endif + } virtual void GetVar(void) const { g_pServerGameDLL = p_SV_CreateBaseline.Offset(0x0).FindPatternSelf("48 8B", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).Deref().RCast(); From f81780a72dccc49922745680edad8a0b64607b88 Mon Sep 17 00:00:00 2001 From: rexx <67599507+r-ex@users.noreply.github.com> Date: Sun, 18 Sep 2022 21:49:14 +0100 Subject: [PATCH 04/39] fix flags on sv_forceChatToTeamOnly --- r5dev/tier1/IConVar.cpp | 4 ++++ r5dev/tier1/cvar.cpp | 1 + r5dev/tier1/cvar.h | 1 + 3 files changed, 6 insertions(+) diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index d5db9bc2..85c59b56 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -255,6 +255,10 @@ void ConVar::InitShipped(void) const hostport = g_pCVar->FindVar("hostport"); host_hasIrreversibleShutdown = g_pCVar->FindVar("host_hasIrreversibleShutdown"); net_usesocketsforloopback = g_pCVar->FindVar("net_usesocketsforloopback"); + sv_forceChatToTeamOnly = g_pCVar->FindVar("sv_forceChatToTeamOnly"); + + sv_forceChatToTeamOnly->RemoveFlags(FCVAR_DEVELOPMENTONLY); + sv_forceChatToTeamOnly->AddFlags(FCVAR_REPLICATED); #ifndef CLIENT_DLL ai_script_nodes_draw->SetValue(-1); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index 9a0a19f2..ccbc61f3 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -66,6 +66,7 @@ ConVar* sv_pylonVisibility = nullptr; ConVar* sv_pylonRefreshInterval = nullptr; ConVar* sv_banlistRefreshInterval = nullptr; ConVar* sv_statusRefreshInterval = nullptr; +ConVar* sv_forceChatToTeamOnly = nullptr; ConVar* sv_autoReloadRate = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index f585a45f..a4798f07 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -62,6 +62,7 @@ extern ConVar* sv_pylonVisibility; extern ConVar* sv_pylonRefreshInterval; extern ConVar* sv_banlistRefreshInterval; extern ConVar* sv_statusRefreshInterval; +extern ConVar* sv_forceChatToTeamOnly; extern ConVar* sv_autoReloadRate; From fdd74aa622aee8fbb624a2470b23234e34d89c1f Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sun, 18 Sep 2022 23:19:50 +0200 Subject: [PATCH 05/39] Implement net message processing budget Implement net message process budget (channel gets removed if value is exceeded). Use 'net_processLimit' to enable the implementation on the server. It will get enabled by default after testing and some cleanup. This helps against people trying to slow the server down by spamming net messages with a higher rate, e.g. using 'bind "mousewheel_up" "status"'. --- r5dev/core/init.cpp | 4 +- r5dev/engine/client/client.cpp | 21 +++++++++ r5dev/engine/client/client.h | 23 +++++++--- r5dev/engine/net.cpp | 6 +-- r5dev/engine/net.h | 2 +- r5dev/engine/net_chan.cpp | 44 ++++++++++++++++++- r5dev/networksystem/bansystem.cpp | 14 +++--- .../resource/playlist/playlists_r5_patch.txt | 4 ++ r5dev/server/vengineserver_impl.cpp | 6 +-- r5dev/server/vengineserver_impl.h | 31 ++++++++++--- r5dev/tier1/IConVar.cpp | 1 + r5dev/tier1/cvar.cpp | 1 + r5dev/tier1/cvar.h | 1 + 13 files changed, 130 insertions(+), 28 deletions(-) diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 053eda63..77a65ea1 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -182,7 +182,7 @@ void Systems_Init() #endif // !DEDICATED && GAMEDLL_S3 NET_Attach(); - //NetChan_Attach(); + NetChan_Attach(); ConCommand_Attach(); IConVar_Attach(); @@ -309,7 +309,7 @@ void Systems_Shutdown() #endif // !DEDICATED && GAMEDLL_S3 NET_Detach(); - //NetChan_Detach(); + NetChan_Detach(); ConCommand_Detach(); IConVar_Detach(); diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index 1a6c7cb8..775e26e6 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -250,6 +250,27 @@ bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, return v_CClient_Connect(pClient, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize); } +//--------------------------------------------------------------------------------- +// Purpose: disconnect client +// Input : nBadRep - +// *szReason - +// ... - +//--------------------------------------------------------------------------------- +void CClient::Disconnect(int nBadRep/*!!ENUM!!*/, const char* szReason, ...) +{ + char szBuf[1024]; + {///////////////////////////// + va_list vArgs{}; + va_start(vArgs, szReason); + + vsnprintf(szBuf, sizeof(szBuf), szReason, vArgs); + + szBuf[sizeof(szBuf) - 1] = '\0'; + va_end(vArgs); + }///////////////////////////// + v_CClient_Disconnect(this, nBadRep, szBuf); +} + /////////////////////////////////////////////////////////////////////////////////// void CBaseClient_Attach() { diff --git a/r5dev/engine/client/client.h b/r5dev/engine/client/client.h index 8e6cacc2..9f29a9c5 100644 --- a/r5dev/engine/client/client.h +++ b/r5dev/engine/client/client.h @@ -38,6 +38,7 @@ public: bool IsFakeClient(void) const; bool IsHumanPlayer(void) const; bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize); + void Disconnect(int nBadRep /*!!ENUM!!*/, const char* szReason, ...); static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize); void Clear(void); static void VClear(CClient* pBaseClient); @@ -87,10 +88,13 @@ static_assert(sizeof(CClient) == 0x4A4C0); /* ==== CBASECLIENT ===================================================================================================================================================== */ inline CMemory p_CClient_Connect; -inline auto v_CClient_Connect = p_CClient_Connect.RCast(); +inline auto v_CClient_Connect = p_CClient_Connect.RCast(); + +inline CMemory p_CClient_Disconnect; +inline auto v_CClient_Disconnect = p_CClient_Disconnect.RCast(); inline CMemory p_CClient_Clear; -inline auto v_CClient_Clear = p_CClient_Clear.RCast(); +inline auto v_CClient_Clear = p_CClient_Clear.RCast(); /////////////////////////////////////////////////////////////////////////////// void CBaseClient_Attach(); @@ -102,17 +106,24 @@ class VClient : public IDetour virtual void GetAdr(void) const { spdlog::debug("| FUN: CClient::Connect : {:#18x} |\n", p_CClient_Connect.GetPtr()); + spdlog::debug("| FUN: CClient::Disconnect : {:#18x} |\n", p_CClient_Disconnect.GetPtr()); spdlog::debug("| FUN: CClient::Clear : {:#18x} |\n", p_CClient_Clear.GetPtr()); spdlog::debug("| VAR: g_pClient[128] : {:#18x} |\n", reinterpret_cast(g_pClient)); spdlog::debug("+----------------------------------------------------------------+\n"); } virtual void GetFun(void) const { - p_CClient_Connect = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x56\x57\x41\x56\x48\x83\xEC\x20\x41\x0F\xB6\xE9"), "xxxx?xxxx?xxxxxxxxxxxx"); - p_CClient_Clear = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x41\x56\x41\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x89\x74"), "xxxxxxxxxxxxxxxx"); + p_CClient_Connect = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x56\x57\x41\x56\x48\x83\xEC\x20\x41\x0F\xB6\xE9"), "xxxx?xxxx?xxxxxxxxxxxx"); +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2) + p_CClient_Disconnect = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x8B\xC4\x4C\x89\x40\x18\x4C\x89\x48\x20\x53\x56\x57\x48\x81\xEC\x00\x00\x00\x00\x83\xB9\x00\x00\x00\x00\x00\x49\x8B\xF8\x0F\xB6\xF2"), "xxxxxxxxxxxxxxxxx????xx?????xxxxxx"); +#else // !GAMEDLL_S0 || !GAMEDLL_S1 || !GAMEDLL_S2 + p_CClient_Disconnect = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x8B\xC4\x4C\x89\x40\x18\x4C\x89\x48\x20\x53\x56\x57\x48\x81\xEC\x00\x00\x00\x00\x83\xB9\x00\x00\x00\x00\x00\x49\x8B\xF8\x8B\xF2"), "xxxxxxxxxxxxxxxxx????xx?????xxxxx"); +#endif + p_CClient_Clear = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x41\x56\x41\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x89\x74"), "xxxxxxxxxxxxxxxx"); - v_CClient_Connect = p_CClient_Connect.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 20 41 0F B6 E9*/ - v_CClient_Clear = p_CClient_Clear.RCast(); /*40 53 41 56 41 57 48 83 EC 20 48 8B D9 48 89 74*/ + v_CClient_Connect = p_CClient_Connect.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 20 41 0F B6 E9*/ + v_CClient_Disconnect = p_CClient_Disconnect.RCast(); /*48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 8B F2*/ + v_CClient_Clear = p_CClient_Clear.RCast(); /*40 53 41 56 41 57 48 83 EC 20 48 8B D9 48 89 74*/ } virtual void GetVar(void) const { diff --git a/r5dev/engine/net.cpp b/r5dev/engine/net.cpp index 2504e1a6..d7d29dea 100644 --- a/r5dev/engine/net.cpp +++ b/r5dev/engine/net.cpp @@ -162,7 +162,7 @@ void NET_Shutdown(void* thisptr, const char* szReason, uint8_t bBadRep, bool bRe // bBadRep - // bRemoveNow - //----------------------------------------------------------------------------- -void NET_DisconnectClient(CClient* pClient, int nIndex, const char* szReason, uint8_t bBadRep, bool bRemoveNow) +void NET_RemoveChannel(CClient* pClient, int nIndex, const char* szReason, uint8_t bBadRep, bool bRemoveNow) { #ifndef CLIENT_DLL if (!pClient || std::strlen(szReason) == NULL || !pClient->GetNetChan()) @@ -170,9 +170,9 @@ void NET_DisconnectClient(CClient* pClient, int nIndex, const char* szReason, ui return; } - v_NET_Shutdown(pClient->GetNetChan(), szReason, bBadRep, bRemoveNow); // Shutdown netchan. + v_NET_Shutdown(pClient->GetNetChan(), szReason, bBadRep, bRemoveNow); // Shutdown NetChannel. pClient->Clear(); // Reset CClient instance for client. - g_bIsPersistenceVarSet[nIndex] = false; // Reset Persistence var. + g_ServerPlayer[nIndex].Reset(); // Reset ServerPlayer slot. #endif // !CLIENT_DLL } #endif // !NETCONSOLE diff --git a/r5dev/engine/net.h b/r5dev/engine/net.h index 02fc0129..ce6d1c40 100644 --- a/r5dev/engine/net.h +++ b/r5dev/engine/net.h @@ -43,7 +43,7 @@ void NET_SetKey(string svNetKey); void NET_GenerateKey(); void NET_PrintFunc(const char* fmt, ...); void NET_Shutdown(void* thisptr, const char* szReason, uint8_t bBadRep, bool bRemoveNow); -void NET_DisconnectClient(CClient* pClient, int nIndex, const char* szReason, uint8_t bBadRep, bool bRemoveNow); +void NET_RemoveChannel(CClient* pClient, int nIndex, const char* szReason, uint8_t bBadRep, bool bRemoveNow); void NET_Attach(); void NET_Detach(); diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index d95fd30b..d308d7c3 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -8,6 +8,12 @@ #include "tier1/cvar.h" #include "engine/net.h" #include "engine/net_chan.h" +#ifndef CLIENT_DLL +#include "engine/server/server.h" +#include "engine/client/client.h" +#include "server/vengineserver_impl.h" +#endif // !CLIENT_DLL + //----------------------------------------------------------------------------- // Purpose: gets the netchannel name @@ -201,9 +207,45 @@ void CNetChan::Clear(bool bStopProcessing) v_NetChan_Clear(this, bStopProcessing); } +//----------------------------------------------------------------------------- +// Purpose: process message +// Input : *pChan - +// *pMsg - +// Output : true on success, false on failure +//----------------------------------------------------------------------------- bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) { +#ifndef CLIENT_DLL + if (!ThreadInServerFrameThread() || !net_processLimit->GetInt()) + return v_NetChan_ProcessMessages(pChan, pMsg); + + const double flStartTime = Plat_FloatTime(); + const bool bResult = v_NetChan_ProcessMessages(pChan, pMsg); + + CClient* pClient = reinterpret_cast(pChan->m_MessageHandler); + uint16_t nSlot = pClient->GetUserID(); + ServerPlayer_t* pSlot = &g_ServerPlayer[nSlot]; + + if (flStartTime - pSlot->m_flLastNetProcessTime >= 1.0 || + pSlot->m_flLastNetProcessTime == -1.0) + { + pSlot->m_flLastNetProcessTime = flStartTime; + pSlot->m_flCurrentNetProcessTime = 0.0; + } + pSlot->m_flCurrentNetProcessTime += + (Plat_FloatTime() * 1000) - (flStartTime * 1000); + + if (pSlot->m_flCurrentNetProcessTime >= + net_processLimit->GetDouble()) + { + pClient->Disconnect(2, "#DISCONNECT_NETCHAN_OVERFLOW"); + return false; + } + + return bResult; +#else // !CLIENT_DLL return v_NetChan_ProcessMessages(pChan, pMsg); +#endif } /////////////////////////////////////////////////////////////////////////////// @@ -214,4 +256,4 @@ void NetChan_Attach() void NetChan_Detach() { DetourDetach((LPVOID*)&v_NetChan_ProcessMessages, &CNetChan::ProcessMessages); -} \ No newline at end of file +} diff --git a/r5dev/networksystem/bansystem.cpp b/r5dev/networksystem/bansystem.cpp index 53f7b656..7b8ce776 100644 --- a/r5dev/networksystem/bansystem.cpp +++ b/r5dev/networksystem/bansystem.cpp @@ -227,7 +227,7 @@ void CBanSystem::BanListCheck(void) if (AddEntry(svIpAddress, pClient->GetNucleusID()) && !bSave) bSave = true; - NET_DisconnectClient(pClient, c, m_vRefuseList[i].first.c_str(), 0, true); + NET_RemoveChannel(pClient, c, m_vRefuseList[i].first.c_str(), 0, true); } } @@ -299,7 +299,7 @@ void CBanSystem::KickPlayerByName(const string& svPlayerName) if (strlen(pNetChan->GetName()) > 0) { if (svPlayerName.compare(pNetChan->GetName()) == NULL) // Our wanted name? - NET_DisconnectClient(pClient, i, "Kicked from server", 0, true); + NET_RemoveChannel(pClient, i, "Kicked from server", 0, true); } } } @@ -344,14 +344,14 @@ void CBanSystem::KickPlayerById(const string& svHandle) continue; } - NET_DisconnectClient(pClient, i, "Kicked from server", 0, true); + NET_RemoveChannel(pClient, i, "Kicked from server", 0, true); } else { if (svHandle.compare(pNetChan->GetAddress()) != NULL) continue; - NET_DisconnectClient(pClient, i, "Kicked from server", 0, true); + NET_RemoveChannel(pClient, i, "Kicked from server", 0, true); } } } @@ -386,7 +386,7 @@ void CBanSystem::BanPlayerByName(const string& svPlayerName) if (AddEntry(pNetChan->GetAddress(), pClient->GetNucleusID()) && !bSave) bSave = true; - NET_DisconnectClient(pClient, i, "Banned from server", 0, true); + NET_RemoveChannel(pClient, i, "Banned from server", 0, true); } } } @@ -441,7 +441,7 @@ void CBanSystem::BanPlayerById(const string& svHandle) bSave = true; Save(); - NET_DisconnectClient(pClient, i, "Banned from server", 0, true); + NET_RemoveChannel(pClient, i, "Banned from server", 0, true); } else { @@ -452,7 +452,7 @@ void CBanSystem::BanPlayerById(const string& svHandle) bSave = true; Save(); - NET_DisconnectClient(pClient, i, "Banned from server", 0, true); + NET_RemoveChannel(pClient, i, "Banned from server", 0, true); } } diff --git a/r5dev/resource/playlist/playlists_r5_patch.txt b/r5dev/resource/playlist/playlists_r5_patch.txt index ffcb4d58..c21d2f3c 100644 --- a/r5dev/resource/playlist/playlists_r5_patch.txt +++ b/r5dev/resource/playlist/playlists_r5_patch.txt @@ -1067,6 +1067,10 @@ playlists "DISCONNECT_BANNED" "The client's game account has been banned: Banned" "VALVE_REJECT_BANNED" "You have been banned from this server." + + "DISCONNECT_SEND_RELIABLEOVERFLOW" "Connection to server overflowed (code:river)." + "DISCONNECT_SEND_OVERFLOW" "Connection to server overflowed (code:dam)." + "DISCONNECT_NETCHAN_OVERFLOW" "Connection to server overflowed (code:vulkan)." } } } diff --git a/r5dev/server/vengineserver_impl.cpp b/r5dev/server/vengineserver_impl.cpp index 26e62f39..dc64b5e3 100644 --- a/r5dev/server/vengineserver_impl.cpp +++ b/r5dev/server/vengineserver_impl.cpp @@ -18,7 +18,7 @@ bool HIVEngineServer__PersistenceAvailable(void* entidx, int clienthandle) CClient* pClient = g_pClient->GetClient(clienthandle); // Get client instance. pClient->SetPersistenceState(PERSISTENCE::PERSISTENCE_READY); // Set the client instance to 'ready'. - if (!g_bIsPersistenceVarSet[clienthandle] && sv_showconnecting->GetBool()) + if (!g_ServerPlayer[clienthandle].m_bPersistenceEnabled && sv_showconnecting->GetBool()) { CNetChan* pNetChan = pClient->GetNetChan(); @@ -34,7 +34,7 @@ bool HIVEngineServer__PersistenceAvailable(void* entidx, int clienthandle) DevMsg(eDLL_T::SERVER, " |- ADR : | '%s'\n", svIpAddress.c_str()); DevMsg(eDLL_T::SERVER, " -------------------------------------------------------------\n"); - g_bIsPersistenceVarSet[clienthandle] = true; + g_ServerPlayer[clienthandle].m_bPersistenceEnabled = true; } /////////////////////////////////////////////////////////////////////////// return IVEngineServer__PersistenceAvailable(entidx, clienthandle); @@ -51,4 +51,4 @@ void IVEngineServer_Detach() } /////////////////////////////////////////////////////////////////////////////// -bool g_bIsPersistenceVarSet[MAX_PLAYERS]; +ServerPlayer_t g_ServerPlayer[MAX_PLAYERS]; diff --git a/r5dev/server/vengineserver_impl.h b/r5dev/server/vengineserver_impl.h index e11fe8c0..ab6010c1 100644 --- a/r5dev/server/vengineserver_impl.h +++ b/r5dev/server/vengineserver_impl.h @@ -13,6 +13,9 @@ inline auto IVEngineServer__GetNumHumanPlayers = p_IVEngineServer__GetNumHumanPl inline CMemory p_IVEngineServer__GetNumFakeClients; inline auto IVEngineServer__GetNumFakeClients = p_IVEngineServer__GetNumFakeClients.RCast(); +//inline CMemory p_RunFrameServer; +//inline auto v_RunFrameServer = p_RunFrameServer.RCast(); + inline bool* g_bDedicated = nullptr; /////////////////////////////////////////////////////////////////////////////// @@ -22,7 +25,22 @@ void IVEngineServer_Attach(); void IVEngineServer_Detach(); /////////////////////////////////////////////////////////////////////////////// -extern bool g_bIsPersistenceVarSet[MAX_PLAYERS]; + +struct ServerPlayer_t +{ + inline void Reset(void) + { + m_flCurrentNetProcessTime = 0.0; + m_flLastNetProcessTime = 0.0; + m_bPersistenceEnabled = false; + } + + double m_flCurrentNetProcessTime; + double m_flLastNetProcessTime; + bool m_bPersistenceEnabled; +}; + +extern ServerPlayer_t g_ServerPlayer[MAX_PLAYERS]; /////////////////////////////////////////////////////////////////////////////// class HVEngineServer : public IDetour @@ -33,6 +51,7 @@ class HVEngineServer : public IDetour spdlog::debug("| FUN: IVEngineServer::IsDedicatedServer : {:#18x} |\n", p_IVEngineServer__IsDedicatedServer.GetPtr()); spdlog::debug("| FUN: IVEngineServer::GetNumHumanPlayers : {:#18x} |\n", p_IVEngineServer__GetNumHumanPlayers.GetPtr()); spdlog::debug("| FUN: IVEngineServer::GetNumFakeClients : {:#18x} |\n", p_IVEngineServer__GetNumFakeClients.GetPtr()); + //spdlog::debug("| FUN: RunFrameServer : {:#18x} |\n", p_RunFrameServer.GetPtr()); spdlog::debug("| VAR: g_bDedicated : {:#18x} |\n", reinterpret_cast(g_bDedicated)); spdlog::debug("+----------------------------------------------------------------+\n"); } @@ -42,11 +61,13 @@ class HVEngineServer : public IDetour p_IVEngineServer__IsDedicatedServer = g_GameDll.FindPatternSIMD(reinterpret_cast("\x0F\xB6\x05\x00\x00\x00\x00\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x48\x8B\x05\x00\x00\x00\x00\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x40\x53"), "xxx????xxxxxxxxxxxx????xxxxxxxxxxx"); p_IVEngineServer__GetNumHumanPlayers = g_GameDll.FindPatternSIMD(reinterpret_cast("\x8B\x15\x00\x00\x00\x00\x33\xC0\x85\xD2\x7E\x24"), "xx????xxxxxx"); p_IVEngineServer__GetNumFakeClients = g_GameDll.FindPatternSIMD(reinterpret_cast("\x8B\x05\x00\x00\x00\x00\x33\xC9\x85\xC0\x7E\x2D"), "xx????xxxxxx"); +// p_RunFrameServer = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x57\x48\x83\xEC\x30\x0F\x29\x74\x24\x00\x48\x8D\x0D\x00\x00\x00\x00"), "xxxx?xxxxxxxxx?xxx????"); - IVEngineServer__PersistenceAvailable = p_IVEngineServer__PersistenceAvailable.RCast(); /*3B 15 ?? ?? ?? ?? 7D 33*/ - IVEngineServer__IsDedicatedServer = p_IVEngineServer__IsDedicatedServer.RCast(); /*0F B6 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC 48 8B 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC 40 53*/ - IVEngineServer__GetNumHumanPlayers = p_IVEngineServer__GetNumHumanPlayers.RCast(); /*8B 15 ?? ?? ?? ?? 33 C0 85 D2 7E 24*/ - IVEngineServer__GetNumFakeClients = p_IVEngineServer__GetNumFakeClients.RCast(); /*8B 05 ?? ?? ?? ?? 33 C9 85 C0 7E 2D*/ + IVEngineServer__PersistenceAvailable = p_IVEngineServer__PersistenceAvailable.RCast(); /*3B 15 ?? ?? ?? ?? 7D 33*/ + IVEngineServer__IsDedicatedServer = p_IVEngineServer__IsDedicatedServer.RCast(); /*0F B6 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC 48 8B 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC 40 53*/ + IVEngineServer__GetNumHumanPlayers = p_IVEngineServer__GetNumHumanPlayers.RCast(); /*8B 15 ?? ?? ?? ?? 33 C0 85 D2 7E 24*/ + IVEngineServer__GetNumFakeClients = p_IVEngineServer__GetNumFakeClients.RCast(); /*8B 05 ?? ?? ?? ?? 33 C9 85 C0 7E 2D*/ +// v_RunFrameServer = p_RunFrameServer.RCast(); /*48 89 5C 24 ?? 57 48 83 EC 30 0F 29 74 24 ?? 48 8D 0D ?? ?? ?? ??*/ } virtual void GetVar(void) const { diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 85c59b56..4d339371 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -203,6 +203,7 @@ void ConVar::Init(void) const net_tracePayload = ConVar::Create("net_tracePayload" , "0", FCVAR_DEVELOPMENTONLY , "Log the payload of the send/recv datagram to a file on the disk.", false, 0.f, false, 0.f, nullptr, nullptr); net_encryptionEnable = ConVar::Create("net_encryptionEnable" , "1", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED , "Use AES encryption on game packets.", false, 0.f, false, 0.f, nullptr, nullptr); net_useRandomKey = ConVar::Create("net_useRandomKey" , "1" , FCVAR_RELEASE , "Use random AES encryption key for game packets.", false, 0.f, false, 0.f, &NET_UseRandomKeyChanged_f, nullptr); + net_processLimit = ConVar::Create("net_processLimit" , "0" , FCVAR_RELEASE , "Net message process budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled."); //------------------------------------------------------------------------- // NETWORKSYSTEM | pylon_matchmaking_hostname = ConVar::Create("pylon_matchmaking_hostname", "ms.r5reloaded.com", FCVAR_RELEASE , "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index ccbc61f3..13963f3d 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -172,6 +172,7 @@ ConVar* net_tracePayload = nullptr; ConVar* net_encryptionEnable = nullptr; ConVar* net_useRandomKey = nullptr; ConVar* net_usesocketsforloopback = nullptr; +ConVar* net_processLimit = nullptr; ConVar* pylon_matchmaking_hostname = nullptr; ConVar* pylon_host_update_interval = nullptr; ConVar* pylon_showdebuginfo = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index a4798f07..6ba32f97 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -167,6 +167,7 @@ extern ConVar* net_tracePayload; extern ConVar* net_encryptionEnable; extern ConVar* net_useRandomKey; extern ConVar* net_usesocketsforloopback; +extern ConVar* net_processLimit; extern ConVar* pylon_matchmaking_hostname; extern ConVar* pylon_host_update_interval; extern ConVar* pylon_showdebuginfo; From 1ed7fd8203c0ac1024023d6a4966654567a36102 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Sep 2022 01:17:34 +0200 Subject: [PATCH 06/39] Light warning string cleanup --- r5dev/vstdlib/callback.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/r5dev/vstdlib/callback.cpp b/r5dev/vstdlib/callback.cpp index 3464aee1..2515ca7e 100644 --- a/r5dev/vstdlib/callback.cpp +++ b/r5dev/vstdlib/callback.cpp @@ -649,7 +649,7 @@ void RCON_CmdQuery_f(const CCommand& args) { if (!RCONClient()->IsInitialized()) { - Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: uninitialized\n"); + Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: %s\n", "uninitialized"); return; } else if (RCONClient()->IsConnected()) @@ -680,7 +680,7 @@ void RCON_CmdQuery_f(const CCommand& args) } else { - Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: unconnected\n"); + Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: %s\n", "unconnected"); return; } } From 3311c99917a73d55ac0390d4f8bc944c21c32df9 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Sep 2022 01:18:14 +0200 Subject: [PATCH 07/39] SQVM: use const qualifiers for SQCONTEXT --- r5dev/squirrel/sqscript.cpp | 11 +++++------ r5dev/squirrel/sqscript.h | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index 5a306853..95be0ee8 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -203,7 +203,7 @@ SQBool Script_CreateUIVM() // Input : context - // Output : SQVM* //--------------------------------------------------------------------------------- -CSquirrelVM* Script_GetContextObject(SQCONTEXT context) +CSquirrelVM* Script_GetContextObject(const SQCONTEXT context) { switch (context) { @@ -258,7 +258,7 @@ SQBool Script_LoadScript(HSQUIRRELVM v, const SQChar* szScriptPath, const SQChar // Input : *code - // context - //--------------------------------------------------------------------------------- -void Script_Execute(const SQChar* code, SQCONTEXT context) +void Script_Execute(const SQChar* code, const SQCONTEXT context) { if (!ThreadInMainThread()) { @@ -274,7 +274,7 @@ void Script_Execute(const SQChar* code, SQCONTEXT context) CSquirrelVM* script = Script_GetContextObject(context); if (!script) { - Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script with no handle to script context\n", SQVM_GetContextName(context)); + Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script with no handle to VM\n", SQVM_GetContextName(context)); return; } @@ -285,11 +285,10 @@ void Script_Execute(const SQChar* code, SQCONTEXT context) return; } - SQRESULT compileResult{}; SQBufState bufState = SQBufState(code); + SQRESULT compileResult = sq_compilebuffer(v, &bufState, "console", -1); - compileResult = sq_compilebuffer(v, &bufState, "console", -1); - if (compileResult >= 0) + if (compileResult >= NULL) { sq_pushroottable(v); SQRESULT callResult = sq_call(v, 1, false, false); diff --git a/r5dev/squirrel/sqscript.h b/r5dev/squirrel/sqscript.h index 03a65e78..1d09d352 100644 --- a/r5dev/squirrel/sqscript.h +++ b/r5dev/squirrel/sqscript.h @@ -114,12 +114,12 @@ SQBool Script_CreateServerVM(); SQBool Script_CreateClientVM(CHLClient* hlclient); #endif // !DEDICATED SQBool Script_CreateUIVM(); -CSquirrelVM* Script_GetContextObject(SQCONTEXT context); +CSquirrelVM* Script_GetContextObject(const SQCONTEXT context); SQInteger Script_LoadRson(const SQChar* szRsonName); SQBool Script_LoadScript(HSQUIRRELVM v, const SQChar* szScriptPath, const SQChar* szScriptName, SQInteger nFlag); -void Script_Execute(const SQChar* code, SQCONTEXT context); +void Script_Execute(const SQChar* code, const SQCONTEXT context); void SQScript_Attach(); void SQScript_Detach(); From 58cadb529b59a92fd7e032ea1fab14582a631a6e Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Sep 2022 01:28:43 +0200 Subject: [PATCH 08/39] 'Bad behaving player' systems improvement * Use 'CClient::Disconnect(..)' for all kicks and bans (this automatically clears the entire CClient slot, and removes the net channel). * Only force disconnect when 'CNetChan::m_nSignonState' has a value that is not NULL. * Clear the ServerPlayer slot on 'CClient::Disconnect(..)' and 'CClient::Connect(..)'. * Only kick player for NetChannel overflow when value exceeds processing budget (not equals). --- r5dev/engine/client/client.cpp | 38 +++++++++++++++++++------------ r5dev/engine/client/client.h | 18 +++++++++++---- r5dev/engine/net_chan.cpp | 7 +++--- r5dev/networksystem/bansystem.cpp | 16 ++++++------- r5dev/server/vengineserver_impl.h | 5 ++++ 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index 775e26e6..2ceca251 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -9,6 +9,7 @@ // /////////////////////////////////////////////////////////////////////////////////// #include "core/stdafx.h" +#include "engine/server/server.h" #include "engine/client/client.h" //--------------------------------------------------------------------------------- @@ -207,16 +208,18 @@ bool CClient::IsHumanPlayer(void) const //--------------------------------------------------------------------------------- void CClient::Clear(void) { + g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot. v_CClient_Clear(this); } //--------------------------------------------------------------------------------- // Purpose: throw away any residual garbage in the channel -// Input : *pBaseClient - +// Input : *pClient - //--------------------------------------------------------------------------------- -void CClient::VClear(CClient* pBaseClient) +void CClient::VClear(CClient* pClient) { - v_CClient_Clear(pBaseClient); + g_ServerPlayer[pClient->GetUserID()].Reset(); // Reset ServerPlayer slot. + v_CClient_Clear(pClient); } //--------------------------------------------------------------------------------- @@ -247,28 +250,33 @@ bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, v //--------------------------------------------------------------------------------- bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize) { - return v_CClient_Connect(pClient, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize); + bool bResult = v_CClient_Connect(pClient, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize); + g_ServerPlayer[pClient->GetUserID()].Reset(); // Reset ServerPlayer slot. + return bResult; } //--------------------------------------------------------------------------------- // Purpose: disconnect client -// Input : nBadRep - +// Input : nRepLvl - // *szReason - // ... - //--------------------------------------------------------------------------------- -void CClient::Disconnect(int nBadRep/*!!ENUM!!*/, const char* szReason, ...) +void CClient::Disconnect(const Reputation_t nRepLvl, const char* szReason, ...) { - char szBuf[1024]; - {///////////////////////////// - va_list vArgs{}; - va_start(vArgs, szReason); + if (m_nSignonState != SIGNONSTATE::SIGNONSTATE_NONE) + { + char szBuf[1024]; + {///////////////////////////// + va_list vArgs{}; + va_start(vArgs, szReason); - vsnprintf(szBuf, sizeof(szBuf), szReason, vArgs); + vsnprintf(szBuf, sizeof(szBuf), szReason, vArgs); - szBuf[sizeof(szBuf) - 1] = '\0'; - va_end(vArgs); - }///////////////////////////// - v_CClient_Disconnect(this, nBadRep, szBuf); + szBuf[sizeof(szBuf) - 1] = '\0'; + va_end(vArgs); + }///////////////////////////// + v_CClient_Disconnect(this, nRepLvl, szBuf); + } } /////////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/engine/client/client.h b/r5dev/engine/client/client.h index 9f29a9c5..5de6b826 100644 --- a/r5dev/engine/client/client.h +++ b/r5dev/engine/client/client.h @@ -3,6 +3,16 @@ #include "common/protocol.h" #include "engine/net_chan.h" +//----------------------------------------------------------------------------- +// Enumerations +//----------------------------------------------------------------------------- +enum Reputation_t +{ + REP_NONE = 0, + REP_REMOVE_ONLY, + REP_MARK +}; + //----------------------------------------------------------------------------- // Forward declarations //----------------------------------------------------------------------------- @@ -38,10 +48,10 @@ public: bool IsFakeClient(void) const; bool IsHumanPlayer(void) const; bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize); - void Disconnect(int nBadRep /*!!ENUM!!*/, const char* szReason, ...); + void Disconnect(const Reputation_t nRepLvl, const char* szReason, ...); static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize); void Clear(void); - static void VClear(CClient* pBaseClient); + static void VClear(CClient* pClient); private: uint32_t m_nUserID; //0x0010 @@ -91,7 +101,7 @@ inline CMemory p_CClient_Connect; inline auto v_CClient_Connect = p_CClient_Connect.RCast(); inline CMemory p_CClient_Disconnect; -inline auto v_CClient_Disconnect = p_CClient_Disconnect.RCast(); +inline auto v_CClient_Disconnect = p_CClient_Disconnect.RCast(); inline CMemory p_CClient_Clear; inline auto v_CClient_Clear = p_CClient_Clear.RCast(); @@ -122,7 +132,7 @@ class VClient : public IDetour p_CClient_Clear = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x41\x56\x41\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x89\x74"), "xxxxxxxxxxxxxxxx"); v_CClient_Connect = p_CClient_Connect.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 20 41 0F B6 E9*/ - v_CClient_Disconnect = p_CClient_Disconnect.RCast(); /*48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 8B F2*/ + v_CClient_Disconnect = p_CClient_Disconnect.RCast(); /*48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 8B F2*/ v_CClient_Clear = p_CClient_Clear.RCast(); /*40 53 41 56 41 57 48 83 EC 20 48 8B D9 48 89 74*/ } virtual void GetVar(void) const diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index d308d7c3..12639b95 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -223,8 +223,7 @@ bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) const bool bResult = v_NetChan_ProcessMessages(pChan, pMsg); CClient* pClient = reinterpret_cast(pChan->m_MessageHandler); - uint16_t nSlot = pClient->GetUserID(); - ServerPlayer_t* pSlot = &g_ServerPlayer[nSlot]; + ServerPlayer_t* pSlot = &g_ServerPlayer[pClient->GetUserID()]; if (flStartTime - pSlot->m_flLastNetProcessTime >= 1.0 || pSlot->m_flLastNetProcessTime == -1.0) @@ -235,10 +234,10 @@ bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) pSlot->m_flCurrentNetProcessTime += (Plat_FloatTime() * 1000) - (flStartTime * 1000); - if (pSlot->m_flCurrentNetProcessTime >= + if (pSlot->m_flCurrentNetProcessTime > net_processLimit->GetDouble()) { - pClient->Disconnect(2, "#DISCONNECT_NETCHAN_OVERFLOW"); + pClient->Disconnect(REP_MARK, "#DISCONNECT_NETCHAN_OVERFLOW"); return false; } diff --git a/r5dev/networksystem/bansystem.cpp b/r5dev/networksystem/bansystem.cpp index 7b8ce776..d53ab5da 100644 --- a/r5dev/networksystem/bansystem.cpp +++ b/r5dev/networksystem/bansystem.cpp @@ -223,11 +223,11 @@ void CBanSystem::BanListCheck(void) string svIpAddress = pNetChan->GetAddress(); - Warning(eDLL_T::SERVER, "Removing client '%s' from slot '%hu' ('%llu' is banned from this server!)\n", svIpAddress.c_str(), pClient->GetHandle(), pClient->GetNucleusID()); + Warning(eDLL_T::SERVER, "Removing client '%s' from slot '%i' ('%llu' is banned from this server!)\n", svIpAddress.c_str(), c, pClient->GetNucleusID()); if (AddEntry(svIpAddress, pClient->GetNucleusID()) && !bSave) bSave = true; - NET_RemoveChannel(pClient, c, m_vRefuseList[i].first.c_str(), 0, true); + pClient->Disconnect(Reputation_t::REP_MARK, m_vRefuseList[i].first.c_str()); } } @@ -299,7 +299,7 @@ void CBanSystem::KickPlayerByName(const string& svPlayerName) if (strlen(pNetChan->GetName()) > 0) { if (svPlayerName.compare(pNetChan->GetName()) == NULL) // Our wanted name? - NET_RemoveChannel(pClient, i, "Kicked from server", 0, true); + pClient->Disconnect(REP_MARK, "Kicked from server"); } } } @@ -344,14 +344,14 @@ void CBanSystem::KickPlayerById(const string& svHandle) continue; } - NET_RemoveChannel(pClient, i, "Kicked from server", 0, true); + pClient->Disconnect(REP_MARK, "Kicked from server"); } else { if (svHandle.compare(pNetChan->GetAddress()) != NULL) continue; - NET_RemoveChannel(pClient, i, "Kicked from server", 0, true); + pClient->Disconnect(REP_MARK, "Kicked from server"); } } } @@ -386,7 +386,7 @@ void CBanSystem::BanPlayerByName(const string& svPlayerName) if (AddEntry(pNetChan->GetAddress(), pClient->GetNucleusID()) && !bSave) bSave = true; - NET_RemoveChannel(pClient, i, "Banned from server", 0, true); + pClient->Disconnect(REP_MARK, "Banned from server"); } } } @@ -441,7 +441,7 @@ void CBanSystem::BanPlayerById(const string& svHandle) bSave = true; Save(); - NET_RemoveChannel(pClient, i, "Banned from server", 0, true); + pClient->Disconnect(REP_MARK, "Banned from server"); } else { @@ -452,7 +452,7 @@ void CBanSystem::BanPlayerById(const string& svHandle) bSave = true; Save(); - NET_RemoveChannel(pClient, i, "Banned from server", 0, true); + pClient->Disconnect(REP_MARK, "Banned from server"); } } diff --git a/r5dev/server/vengineserver_impl.h b/r5dev/server/vengineserver_impl.h index ab6010c1..91291454 100644 --- a/r5dev/server/vengineserver_impl.h +++ b/r5dev/server/vengineserver_impl.h @@ -28,6 +28,11 @@ void IVEngineServer_Detach(); struct ServerPlayer_t { + ServerPlayer_t(void) + : m_flCurrentNetProcessTime(0.0) + , m_flLastNetProcessTime(0.0) + , m_bPersistenceEnabled(false) + {} inline void Reset(void) { m_flCurrentNetProcessTime = 0.0; From 7b0baf5d1f3d52d26ac5b3c1701a8d34541e533d Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Sep 2022 01:46:35 +0200 Subject: [PATCH 09/39] CLogSystem: make notify fade out animation 500ms slower --- r5dev/vgui/vgui_debugpanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/r5dev/vgui/vgui_debugpanel.cpp b/r5dev/vgui/vgui_debugpanel.cpp index a36bfb0c..12604ffa 100644 --- a/r5dev/vgui/vgui_debugpanel.cpp +++ b/r5dev/vgui/vgui_debugpanel.cpp @@ -112,9 +112,9 @@ void CLogSystem::DrawNotify(void) float flTimeleft = pNotify->m_flLifeRemaining; - if (flTimeleft < .5f) + if (flTimeleft < 1.0f) { - float f = clamp(flTimeleft, 0.0f, .5f) / .5f; + float f = clamp(flTimeleft, 0.0f, 1.0f) / 1.0f; c[3] = (int)(f * 255.0f); if (i == 0 && f < 0.2f) From 41f801365ae2c746b4825e251b6b6af41ebbb273 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Sep 2022 20:21:18 +0200 Subject: [PATCH 10/39] CConsole: fixed color bug when missing newline * Fixed bug where the in-game console could not color the line when no newline was found. * Changed behavior to only newline when: '\n' has been found, or the context has changed (using a print without newline will continue to print on the same line in the console). * Pass ImVec4 parameter in 'CTextLogger::InsertTextAt' by reference. --- r5dev/thirdparty/imgui/include/imgui_logger.h | 3 +- r5dev/thirdparty/imgui/src/imgui_logger.cpp | 49 +++++++++++++------ 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/r5dev/thirdparty/imgui/include/imgui_logger.h b/r5dev/thirdparty/imgui/include/imgui_logger.h index 824b7f83..7b6bfea5 100644 --- a/r5dev/thirdparty/imgui/include/imgui_logger.h +++ b/r5dev/thirdparty/imgui/include/imgui_logger.h @@ -185,7 +185,8 @@ private: Coordinates SanitizeCoordinates(const Coordinates& aValue) const; void Advance(Coordinates& aCoordinates) const; void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd); - int InsertTextAt(Coordinates& aWhere, const char* aValue, ImVec4 aColor); + int InsertTextAt(Coordinates& aWhere, const char* aValue, const ImVec4& aColor); + void MarkNewline(Coordinates& aWhere, const ImVec4& aColor, int aIndex); Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const; Coordinates FindWordStart(const Coordinates& aFrom) const; Coordinates FindWordEnd(const Coordinates& aFrom) const; diff --git a/r5dev/thirdparty/imgui/src/imgui_logger.cpp b/r5dev/thirdparty/imgui/src/imgui_logger.cpp index 4265db97..87ea7102 100644 --- a/r5dev/thirdparty/imgui/src/imgui_logger.cpp +++ b/r5dev/thirdparty/imgui/src/imgui_logger.cpp @@ -196,7 +196,24 @@ void CTextLogger::DeleteRange(const Coordinates & aStart, const Coordinates & aE } } -int CTextLogger::InsertTextAt(Coordinates& /* inout */ aWhere, const char * aValue, ImVec4 aColor) +void CTextLogger::MarkNewline(Coordinates& /* inout */ aWhere, const ImVec4& aColor, int aIndex) +{ + if (aIndex < static_cast(m_Lines[aWhere.m_nLine].size())) + { + Line& newLine = InsertLine(aWhere.m_nLine + 1); + Line& line = m_Lines[aWhere.m_nLine]; + newLine.insert(newLine.begin(), line.begin() + aIndex, line.end()); + line.erase(line.begin() + aIndex, line.end()); + } + else + { + Line& newLine = InsertLine(aWhere.m_nLine + 1); + Line& line = m_Lines[aWhere.m_nLine]; + line.insert(line.begin() + aIndex, Glyph('\n', aColor)); + } +} + +int CTextLogger::InsertTextAt(Coordinates& /* inout */ aWhere, const char * aValue, const ImVec4& aColor) { int cindex = GetCharacterIndex(aWhere); int totalLines = 0; @@ -212,19 +229,7 @@ int CTextLogger::InsertTextAt(Coordinates& /* inout */ aWhere, const char * aVal } else if (*aValue == '\n') { - if (cindex < static_cast(m_Lines[aWhere.m_nLine].size())) - { - Line& newLine = InsertLine(aWhere.m_nLine + 1); - Line& line = m_Lines[aWhere.m_nLine]; - newLine.insert(newLine.begin(), line.begin() + cindex, line.end()); - line.erase(line.begin() + cindex, line.end()); - } - else - { - Line& newLine = InsertLine(aWhere.m_nLine + 1); - Line& line = m_Lines[aWhere.m_nLine]; - line.insert(line.begin() + cindex, Glyph(*aValue, aColor)); - } + MarkNewline(aWhere, aColor, cindex); ++aWhere.m_nLine; aWhere.m_nColumn = 0; cindex = 0; @@ -234,12 +239,28 @@ int CTextLogger::InsertTextAt(Coordinates& /* inout */ aWhere, const char * aVal else { Line& line = m_Lines[aWhere.m_nLine]; + if (!line.empty() && ImGui::ColorConvertFloat4ToU32(aColor) != ImGui::ColorConvertFloat4ToU32(line[0].m_Color)) + { + MarkNewline(aWhere, line[0].m_Color, cindex); + ++aWhere.m_nLine; + aWhere.m_nColumn = 0; + cindex = 0; + ++totalLines; + continue; + } + int d = UTF8CharLength(*aValue); while (d-- > 0 && *aValue != '\0') line.insert(line.begin() + cindex++, Glyph(*aValue++, aColor)); ++aWhere.m_nColumn; } } + if (!*aValue) + { + Line& line = m_Lines[aWhere.m_nLine]; + if (!line.empty()) + line.insert(line.begin() + cindex, Glyph(' ', aColor)); + } return totalLines; } From 21756f805769472d193c5ad07c8a18e2d9dac4cd Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 19 Sep 2022 20:21:40 +0200 Subject: [PATCH 11/39] Update SDK version to 'VGameSDK004' --- r5dev/tier0/basetypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/tier0/basetypes.h b/r5dev/tier0/basetypes.h index 783cb840..2ba292d8 100644 --- a/r5dev/tier0/basetypes.h +++ b/r5dev/tier0/basetypes.h @@ -134,7 +134,7 @@ #endif // Max BSP file name len. #define MAX_MAP_NAME 64 -#define SDK_VERSION "VGameSDK003" // Increment this with every /breaking/ SDK change (i.e. security/backend changes breaking compatibility). +#define SDK_VERSION "VGameSDK004" // Increment this with every /breaking/ SDK change (i.e. security/backend changes breaking compatibility). #define SDK_ARRAYSIZE(arr) ((sizeof(arr) / sizeof(*arr))) // Name due to IMGUI implementation and NT implementation that we shouldn't share across everywhere. #ifndef DEDICATED From dcc2c6224b848e83ceb89928006c6a834d1312fa Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Tue, 20 Sep 2022 02:00:52 +0200 Subject: [PATCH 12/39] Improve NetChan process time limit * Check if m_MessageHandler is removed before running limit test. * Add warning DevMsg if client exceeds value. * Default 'net_processTimeBudget' value to '200'. --- r5dev/engine/net_chan.cpp | 12 +++++++++--- r5dev/tier1/IConVar.cpp | 2 +- r5dev/tier1/cvar.cpp | 2 +- r5dev/tier1/cvar.h | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index 12639b95..1e63a76c 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -216,12 +216,15 @@ void CNetChan::Clear(bool bStopProcessing) bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) { #ifndef CLIENT_DLL - if (!ThreadInServerFrameThread() || !net_processLimit->GetInt()) + if (!ThreadInServerFrameThread() || !net_processTimeBudget->GetInt()) return v_NetChan_ProcessMessages(pChan, pMsg); const double flStartTime = Plat_FloatTime(); const bool bResult = v_NetChan_ProcessMessages(pChan, pMsg); + if (!pChan->m_MessageHandler) // NetChannel removed? + return bResult; + CClient* pClient = reinterpret_cast(pChan->m_MessageHandler); ServerPlayer_t* pSlot = &g_ServerPlayer[pClient->GetUserID()]; @@ -235,9 +238,12 @@ bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) (Plat_FloatTime() * 1000) - (flStartTime * 1000); if (pSlot->m_flCurrentNetProcessTime > - net_processLimit->GetDouble()) + net_processTimeBudget->GetDouble()) { - pClient->Disconnect(REP_MARK, "#DISCONNECT_NETCHAN_OVERFLOW"); + Warning(eDLL_T::ENGINE, "Removing netchannel '%s' ('%s' exceeded frame budget by '%3.1f'ms!)\n", + pChan->GetName(), pChan->GetAddress(), (pSlot->m_flCurrentNetProcessTime - net_processTimeBudget->GetDouble())); + pClient->Disconnect(Reputation_t::REP_MARK, "#DISCONNECT_NETCHAN_OVERFLOW"); + return false; } diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 4d339371..9d7952fe 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -203,7 +203,7 @@ void ConVar::Init(void) const net_tracePayload = ConVar::Create("net_tracePayload" , "0", FCVAR_DEVELOPMENTONLY , "Log the payload of the send/recv datagram to a file on the disk.", false, 0.f, false, 0.f, nullptr, nullptr); net_encryptionEnable = ConVar::Create("net_encryptionEnable" , "1", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED , "Use AES encryption on game packets.", false, 0.f, false, 0.f, nullptr, nullptr); net_useRandomKey = ConVar::Create("net_useRandomKey" , "1" , FCVAR_RELEASE , "Use random AES encryption key for game packets.", false, 0.f, false, 0.f, &NET_UseRandomKeyChanged_f, nullptr); - net_processLimit = ConVar::Create("net_processLimit" , "0" , FCVAR_RELEASE , "Net message process budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled."); + net_processTimeBudget = ConVar::Create("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled."); //------------------------------------------------------------------------- // NETWORKSYSTEM | pylon_matchmaking_hostname = ConVar::Create("pylon_matchmaking_hostname", "ms.r5reloaded.com", FCVAR_RELEASE , "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index 13963f3d..45003d49 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -172,7 +172,7 @@ ConVar* net_tracePayload = nullptr; ConVar* net_encryptionEnable = nullptr; ConVar* net_useRandomKey = nullptr; ConVar* net_usesocketsforloopback = nullptr; -ConVar* net_processLimit = nullptr; +ConVar* net_processTimeBudget = nullptr; ConVar* pylon_matchmaking_hostname = nullptr; ConVar* pylon_host_update_interval = nullptr; ConVar* pylon_showdebuginfo = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index 6ba32f97..612716ab 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -167,7 +167,7 @@ extern ConVar* net_tracePayload; extern ConVar* net_encryptionEnable; extern ConVar* net_useRandomKey; extern ConVar* net_usesocketsforloopback; -extern ConVar* net_processLimit; +extern ConVar* net_processTimeBudget; extern ConVar* pylon_matchmaking_hostname; extern ConVar* pylon_host_update_interval; extern ConVar* pylon_showdebuginfo; From 793c2e8e509a7298f4a14b4d6be5cac460943505 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Tue, 20 Sep 2022 02:04:25 +0200 Subject: [PATCH 13/39] Rename 'Reputation_t' enumerant --- r5dev/engine/client/client.h | 2 +- r5dev/engine/net_chan.cpp | 2 +- r5dev/networksystem/bansystem.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/r5dev/engine/client/client.h b/r5dev/engine/client/client.h index 5de6b826..65805738 100644 --- a/r5dev/engine/client/client.h +++ b/r5dev/engine/client/client.h @@ -10,7 +10,7 @@ enum Reputation_t { REP_NONE = 0, REP_REMOVE_ONLY, - REP_MARK + REP_MARK_BAD }; //----------------------------------------------------------------------------- diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index 1e63a76c..5d284ca7 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -242,7 +242,7 @@ bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) { Warning(eDLL_T::ENGINE, "Removing netchannel '%s' ('%s' exceeded frame budget by '%3.1f'ms!)\n", pChan->GetName(), pChan->GetAddress(), (pSlot->m_flCurrentNetProcessTime - net_processTimeBudget->GetDouble())); - pClient->Disconnect(Reputation_t::REP_MARK, "#DISCONNECT_NETCHAN_OVERFLOW"); + pClient->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_NETCHAN_OVERFLOW"); return false; } diff --git a/r5dev/networksystem/bansystem.cpp b/r5dev/networksystem/bansystem.cpp index d53ab5da..794f75f8 100644 --- a/r5dev/networksystem/bansystem.cpp +++ b/r5dev/networksystem/bansystem.cpp @@ -227,7 +227,7 @@ void CBanSystem::BanListCheck(void) if (AddEntry(svIpAddress, pClient->GetNucleusID()) && !bSave) bSave = true; - pClient->Disconnect(Reputation_t::REP_MARK, m_vRefuseList[i].first.c_str()); + pClient->Disconnect(Reputation_t::REP_MARK_BAD, m_vRefuseList[i].first.c_str()); } } @@ -299,7 +299,7 @@ void CBanSystem::KickPlayerByName(const string& svPlayerName) if (strlen(pNetChan->GetName()) > 0) { if (svPlayerName.compare(pNetChan->GetName()) == NULL) // Our wanted name? - pClient->Disconnect(REP_MARK, "Kicked from server"); + pClient->Disconnect(REP_MARK_BAD, "Kicked from server"); } } } @@ -344,14 +344,14 @@ void CBanSystem::KickPlayerById(const string& svHandle) continue; } - pClient->Disconnect(REP_MARK, "Kicked from server"); + pClient->Disconnect(REP_MARK_BAD, "Kicked from server"); } else { if (svHandle.compare(pNetChan->GetAddress()) != NULL) continue; - pClient->Disconnect(REP_MARK, "Kicked from server"); + pClient->Disconnect(REP_MARK_BAD, "Kicked from server"); } } } @@ -386,7 +386,7 @@ void CBanSystem::BanPlayerByName(const string& svPlayerName) if (AddEntry(pNetChan->GetAddress(), pClient->GetNucleusID()) && !bSave) bSave = true; - pClient->Disconnect(REP_MARK, "Banned from server"); + pClient->Disconnect(REP_MARK_BAD, "Banned from server"); } } } @@ -441,7 +441,7 @@ void CBanSystem::BanPlayerById(const string& svHandle) bSave = true; Save(); - pClient->Disconnect(REP_MARK, "Banned from server"); + pClient->Disconnect(REP_MARK_BAD, "Banned from server"); } else { @@ -452,7 +452,7 @@ void CBanSystem::BanPlayerById(const string& svHandle) bSave = true; Save(); - pClient->Disconnect(REP_MARK, "Banned from server"); + pClient->Disconnect(REP_MARK_BAD, "Banned from server"); } } From 7804241376413301d6b4bb28c9ba4ab8633c5727 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Tue, 20 Sep 2022 22:48:55 +0200 Subject: [PATCH 14/39] CClient: add rate limit logic for 'ProcessStringCmd' Client's can run string commands on the server with no rate limit. This means when you run 50k+ commands that are unknown, or spam 30k 'status' commands, you will be able to hang the server for 800/1200ms (15k/30kms if script printing to console is enabled!). Although the netchan processing budget system will kick you, the damage has already been done at this point. This change effectively breaks the ability to DOS the server from the client using networked string commands. In easier words; binding 'status' to your mousewheel will get you kicked from the server, without hitching the server. --- r5dev/common/netmessages.h | 7 +++ r5dev/engine/client/client.cpp | 49 +++++++++++++++++++ r5dev/engine/client/client.h | 13 ++++- .../resource/playlist/playlists_r5_patch.txt | 1 + r5dev/server/vengineserver_impl.h | 6 +++ r5dev/tier1/IConVar.cpp | 6 ++- r5dev/tier1/cvar.cpp | 2 + r5dev/tier1/cvar.h | 2 + 8 files changed, 83 insertions(+), 3 deletions(-) diff --git a/r5dev/common/netmessages.h b/r5dev/common/netmessages.h index d8ef82a1..9d30c4d3 100644 --- a/r5dev/common/netmessages.h +++ b/r5dev/common/netmessages.h @@ -87,6 +87,13 @@ public: bf_write m_DataOut; }; +struct NET_StringCmd : CNetMessage, INetMessageHandler +{ + const char* cmd; + char buffer[1024]; +}; + + //------------------------------------------------------------------------- // MM_HEARTBEAT //------------------------------------------------------------------------- diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index 2ceca251..f5a1f56e 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -9,6 +9,7 @@ // /////////////////////////////////////////////////////////////////////////////////// #include "core/stdafx.h" +#include "tier1/cvar.h" #include "engine/server/server.h" #include "engine/client/client.h" @@ -279,16 +280,64 @@ void CClient::Disconnect(const Reputation_t nRepLvl, const char* szReason, ...) } } +//--------------------------------------------------------------------------------- +// Purpose: process string commands (kicking anyone attempting to DOS) +// Input : *pClient - (ADJ) +// *pMsg - +// Output : false if cmd should be passed to CServerGameClients +//--------------------------------------------------------------------------------- +bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg) +{ +#ifndef CLIENT_DLL +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + CClient* pClient_Adj = pClient; +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + /* Original function called method "CClient::ExecuteStringCommand" with an optimization + * that shifted the 'this' pointer with 8 bytes. + * Since this has been inlined with "CClient::ProcessStringCmd" as of S2, the shifting + * happens directly to anything calling this function. */ + char* pShifted = reinterpret_cast(pClient) - 8; + CClient* pClient_Adj = reinterpret_cast(pShifted); +#endif // !GAMEDLL_S0 || !GAMEDLL_S1 + ServerPlayer_t* pSlot = &g_ServerPlayer[pClient_Adj->GetUserID()]; + double flStartTime = Plat_FloatTime(); + int nCmdQuota = sv_quota_stringCmdsPerSecond->GetInt(); + + if (!nCmdQuota) + return true; + + if (flStartTime - pSlot->m_flStringCommandQuotaTimeStart >= 1.0) + { + pSlot->m_flStringCommandQuotaTimeStart = flStartTime; + pSlot->m_nStringCommandQuotaCount = 0; + } + ++pSlot->m_nStringCommandQuotaCount; + + if (pSlot->m_nStringCommandQuotaCount > nCmdQuota) + { + Warning(eDLL_T::SERVER, "Removing client '%s' from slot '%i' ('%llu' exceeded string command quota!)\n", + pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient->GetNucleusID()); + + pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_STRINGCMD_OVERFLOW"); + return true; + } +#endif // !CLIENT_DLL + + return v_CClient_ProcessStringCmd(pClient, pMsg); +} + /////////////////////////////////////////////////////////////////////////////////// void CBaseClient_Attach() { DetourAttach((LPVOID*)&v_CClient_Clear, &CClient::VClear); DetourAttach((LPVOID*)&v_CClient_Connect, &CClient::VConnect); + DetourAttach((LPVOID*)&v_CClient_ProcessStringCmd, &CClient::VProcessStringCmd); } void CBaseClient_Detach() { DetourDetach((LPVOID*)&v_CClient_Clear, &CClient::VClear); DetourDetach((LPVOID*)&v_CClient_Connect, &CClient::VConnect); + DetourDetach((LPVOID*)&v_CClient_ProcessStringCmd, &CClient::VProcessStringCmd); } /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/engine/client/client.h b/r5dev/engine/client/client.h index 65805738..775a91da 100644 --- a/r5dev/engine/client/client.h +++ b/r5dev/engine/client/client.h @@ -22,7 +22,7 @@ class CClient; /////////////////////////////////////////////////////////////////////////////// extern CClient* g_pClient; -class CClient : INetChannelHandler, IClientMessageHandler +class CClient : IClientMessageHandler, INetChannelHandler { public: CClient* GetClient(int nIndex) const; @@ -52,6 +52,7 @@ public: static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize); void Clear(void); static void VClear(CClient* pClient); + static bool VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg); private: uint32_t m_nUserID; //0x0010 @@ -106,6 +107,9 @@ inline auto v_CClient_Disconnect = p_CClient_Disconnect.RCast(); +inline CMemory p_CClient_ProcessStringCmd; +inline auto v_CClient_ProcessStringCmd = p_CClient_ProcessStringCmd.RCast(); + /////////////////////////////////////////////////////////////////////////////// void CBaseClient_Attach(); void CBaseClient_Detach(); @@ -118,6 +122,7 @@ class VClient : public IDetour spdlog::debug("| FUN: CClient::Connect : {:#18x} |\n", p_CClient_Connect.GetPtr()); spdlog::debug("| FUN: CClient::Disconnect : {:#18x} |\n", p_CClient_Disconnect.GetPtr()); spdlog::debug("| FUN: CClient::Clear : {:#18x} |\n", p_CClient_Clear.GetPtr()); + spdlog::debug("| FUN: CClient::ProcessStringCmd : {:#18x} |\n", p_CClient_ProcessStringCmd.GetPtr()); spdlog::debug("| VAR: g_pClient[128] : {:#18x} |\n", reinterpret_cast(g_pClient)); spdlog::debug("+----------------------------------------------------------------+\n"); } @@ -130,10 +135,16 @@ class VClient : public IDetour p_CClient_Disconnect = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x8B\xC4\x4C\x89\x40\x18\x4C\x89\x48\x20\x53\x56\x57\x48\x81\xEC\x00\x00\x00\x00\x83\xB9\x00\x00\x00\x00\x00\x49\x8B\xF8\x8B\xF2"), "xxxxxxxxxxxxxxxxx????xx?????xxxxx"); #endif p_CClient_Clear = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x41\x56\x41\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x89\x74"), "xxxxxxxxxxxxxxxx"); +#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) + p_CClient_ProcessStringCmd = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x83\xEC\x28\x4C\x8B\x42\x20"), "xxxxxxxx"); +#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) + p_CClient_ProcessStringCmd = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x6C\x24\x00\x57\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\x7A\x20"), "xxxx?xxxx????xxxx"); +#endif // !GAMEDLL_S0 || !GAMEDLL_S1 v_CClient_Connect = p_CClient_Connect.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 20 41 0F B6 E9*/ v_CClient_Disconnect = p_CClient_Disconnect.RCast(); /*48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 8B F2*/ v_CClient_Clear = p_CClient_Clear.RCast(); /*40 53 41 56 41 57 48 83 EC 20 48 8B D9 48 89 74*/ + v_CClient_ProcessStringCmd = p_CClient_ProcessStringCmd.RCast(); /*48 89 6C 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 7A 20*/ } virtual void GetVar(void) const { diff --git a/r5dev/resource/playlist/playlists_r5_patch.txt b/r5dev/resource/playlist/playlists_r5_patch.txt index c21d2f3c..2fc283ea 100644 --- a/r5dev/resource/playlist/playlists_r5_patch.txt +++ b/r5dev/resource/playlist/playlists_r5_patch.txt @@ -1071,6 +1071,7 @@ playlists "DISCONNECT_SEND_RELIABLEOVERFLOW" "Connection to server overflowed (code:river)." "DISCONNECT_SEND_OVERFLOW" "Connection to server overflowed (code:dam)." "DISCONNECT_NETCHAN_OVERFLOW" "Connection to server overflowed (code:vulkan)." + "DISCONNECT_STRINGCMD_OVERFLOW" "Connection to server overflowed (code:mountain)." } } } diff --git a/r5dev/server/vengineserver_impl.h b/r5dev/server/vengineserver_impl.h index 91291454..afc744cc 100644 --- a/r5dev/server/vengineserver_impl.h +++ b/r5dev/server/vengineserver_impl.h @@ -31,17 +31,23 @@ struct ServerPlayer_t ServerPlayer_t(void) : m_flCurrentNetProcessTime(0.0) , m_flLastNetProcessTime(0.0) + , m_flStringCommandQuotaTimeStart(0.0) + , m_nStringCommandQuotaCount(0) , m_bPersistenceEnabled(false) {} inline void Reset(void) { m_flCurrentNetProcessTime = 0.0; m_flLastNetProcessTime = 0.0; + m_flStringCommandQuotaTimeStart = 0.0; + m_nStringCommandQuotaCount = 0; m_bPersistenceEnabled = false; } double m_flCurrentNetProcessTime; double m_flLastNetProcessTime; + double m_flStringCommandQuotaTimeStart; + int m_nStringCommandQuotaCount; bool m_bPersistenceEnabled; }; diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 9d7952fe..f3b448bc 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -105,7 +105,8 @@ void ConVar::Init(void) const sv_banlistRefreshInterval = ConVar::Create("sv_banlistRefreshInterval", "1.0", FCVAR_RELEASE, "Banlist refresh interval (seconds).", true, 1.f, false, 0.f, nullptr, nullptr); sv_statusRefreshInterval = ConVar::Create("sv_statusRefreshInterval" , "0.5", FCVAR_RELEASE, "Server status bar update interval (seconds).", false, 0.f, false, 0.f, nullptr, nullptr); - sv_autoReloadRate = ConVar::Create("sv_autoReloadRate" , "0", FCVAR_RELEASE, "Time in seconds between each server auto-reload (disabled if null). ", true, 0.f, false, 0.f, nullptr, nullptr); + sv_autoReloadRate = ConVar::Create("sv_autoReloadRate" , "0", FCVAR_RELEASE, "Time in seconds between each server auto-reload (disabled if null). ", true, 0.f, false, 0.f, nullptr, nullptr); + sv_quota_stringCmdsPerSecond = ConVar::Create("sv_quota_stringCmdsPerSecond", "16", FCVAR_RELEASE, "How many string commands per second clients are allowed to submit, 0 to disallow all string commands.", true, 0.f, false, 0.f, nullptr, nullptr); #ifdef DEDICATED sv_rcon_debug = ConVar::Create("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_sendlogs = ConVar::Create("sv_rcon_sendlogs" , "0" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); @@ -203,7 +204,7 @@ void ConVar::Init(void) const net_tracePayload = ConVar::Create("net_tracePayload" , "0", FCVAR_DEVELOPMENTONLY , "Log the payload of the send/recv datagram to a file on the disk.", false, 0.f, false, 0.f, nullptr, nullptr); net_encryptionEnable = ConVar::Create("net_encryptionEnable" , "1", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED , "Use AES encryption on game packets.", false, 0.f, false, 0.f, nullptr, nullptr); net_useRandomKey = ConVar::Create("net_useRandomKey" , "1" , FCVAR_RELEASE , "Use random AES encryption key for game packets.", false, 0.f, false, 0.f, &NET_UseRandomKeyChanged_f, nullptr); - net_processTimeBudget = ConVar::Create("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled."); + net_processTimeBudget = ConVar::Create("net_processTimeBudget" ,"150" , FCVAR_RELEASE , "Net message process budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled."); //------------------------------------------------------------------------- // NETWORKSYSTEM | pylon_matchmaking_hostname = ConVar::Create("pylon_matchmaking_hostname", "ms.r5reloaded.com", FCVAR_RELEASE , "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr); @@ -263,6 +264,7 @@ void ConVar::InitShipped(void) const #ifndef CLIENT_DLL ai_script_nodes_draw->SetValue(-1); + bhit_enable->SetValue(0); #endif // !CLIENT_DLL #ifndef DEDICATED cl_threaded_bone_setup->RemoveFlags(FCVAR_DEVELOPMENTONLY); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index 45003d49..d01115c2 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -69,6 +69,7 @@ ConVar* sv_statusRefreshInterval = nullptr; ConVar* sv_forceChatToTeamOnly = nullptr; ConVar* sv_autoReloadRate = nullptr; +ConVar* sv_quota_stringCmdsPerSecond = nullptr; #ifdef DEDICATED ConVar* sv_rcon_debug = nullptr; @@ -173,6 +174,7 @@ ConVar* net_encryptionEnable = nullptr; ConVar* net_useRandomKey = nullptr; ConVar* net_usesocketsforloopback = nullptr; ConVar* net_processTimeBudget = nullptr; + ConVar* pylon_matchmaking_hostname = nullptr; ConVar* pylon_host_update_interval = nullptr; ConVar* pylon_showdebuginfo = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index 612716ab..54a07246 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -65,6 +65,7 @@ extern ConVar* sv_statusRefreshInterval; extern ConVar* sv_forceChatToTeamOnly; extern ConVar* sv_autoReloadRate; +extern ConVar* sv_quota_stringCmdsPerSecond; #ifdef DEDICATED extern ConVar* sv_rcon_debug; @@ -168,6 +169,7 @@ extern ConVar* net_encryptionEnable; extern ConVar* net_useRandomKey; extern ConVar* net_usesocketsforloopback; extern ConVar* net_processTimeBudget; + extern ConVar* pylon_matchmaking_hostname; extern ConVar* pylon_host_update_interval; extern ConVar* pylon_showdebuginfo; From 7a48c5ab6e9967615cbe6474015d64ecddb3580c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 00:38:46 +0200 Subject: [PATCH 15/39] Use shifted pointer --- r5dev/engine/client/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index f5a1f56e..ccfdf3ae 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -316,7 +316,7 @@ bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg) if (pSlot->m_nStringCommandQuotaCount > nCmdQuota) { Warning(eDLL_T::SERVER, "Removing client '%s' from slot '%i' ('%llu' exceeded string command quota!)\n", - pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient->GetNucleusID()); + pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient_Adj->GetNucleusID()); pClient_Adj->Disconnect(Reputation_t::REP_MARK_BAD, "#DISCONNECT_STRINGCMD_OVERFLOW"); return true; From 7912b79fa2f9d5a1b5f4c1dc4277e67222d719d9 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 02:38:58 +0200 Subject: [PATCH 16/39] CL_CopyExistingEntity: implement missing bounds check Implement bounds check for non-sanitized value of u.m_nNewEntity. Debug builds of the engine have an assertion, however in release these are stripped. This fixes a full chain client RCE exploit, for more information, see: https://ctf.re/source-engine/exploitation/2021/05/01/source-engine-2/ --- r5dev/core/init.cpp | 9 ++++++++ r5dev/engine/client/cl_ents_parse.cpp | 33 +++++++++++++++++++++++++++ r5dev/engine/client/cl_ents_parse.h | 32 ++++++++++++++++++++++++++ r5dev/engine/host.h | 4 ++-- r5dev/public/const.h | 7 +++++- r5dev/vproj/clientsdk.vcxproj | 2 ++ r5dev/vproj/clientsdk.vcxproj.filters | 6 +++++ r5dev/vproj/gamesdk.vcxproj | 2 ++ r5dev/vproj/gamesdk.vcxproj.filters | 6 +++++ 9 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 r5dev/engine/client/cl_ents_parse.cpp create mode 100644 r5dev/engine/client/cl_ents_parse.h diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 77a65ea1..c4e2ac07 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -63,6 +63,9 @@ #include "rtech/rtech_utils.h" #include "rtech/stryder/stryder.h" #include "rtech/rui/rui.h" +#ifndef DEDICATED +#include "engine/client/cl_ents_parse.h" +#endif // !DEDICATED #include "engine/client/cl_main.h" #include "engine/client/client.h" #include "engine/client/clientstate.h" @@ -149,6 +152,9 @@ void Systems_Init() #ifdef DEDICATED //PRX_Attach(); #endif // DEDICATED +#ifndef DEDICATED + CL_Ents_Parse_Attach(); +#endif // !DEDICATED CBaseClient_Attach(); CBaseFileSystem_Attach(); @@ -276,6 +282,9 @@ void Systems_Shutdown() #ifdef DEDICATED //PRX_Detach(); #endif // DEDICATED +#ifndef DEDICATED + CL_Ents_Parse_Detach(); +#endif // !DEDICATED CBaseClient_Detach(); CBaseFileSystem_Detach(); diff --git a/r5dev/engine/client/cl_ents_parse.cpp b/r5dev/engine/client/cl_ents_parse.cpp new file mode 100644 index 00000000..6bf20a9a --- /dev/null +++ b/r5dev/engine/client/cl_ents_parse.cpp @@ -0,0 +1,33 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: Parsing of entity network packets. +// +// $NoKeywords: $ +//=============================================================================// + + +#include "core/stdafx.h" +#include "tier0/frametask.h" +#include "public/const.h" +#include "engine/host.h" +#include "engine/client/cl_ents_parse.h" + +bool CL_CopyExistingEntity(__int64 a1, unsigned int* a2, char* a3) +{ + int nNewEntity = *reinterpret_cast(a1 + 40); + if (nNewEntity >= MAX_EDICTS || nNewEntity < 0) + { + v_Host_Error("CL_CopyExistingEntity: m_nNewEntity >= MAX_EDICTS"); + return false; + } + return v_CL_CopyExistingEntity(a1, a2, a3); +} + +void CL_Ents_Parse_Attach() +{ + DetourAttach((LPVOID*)&v_CL_CopyExistingEntity, &CL_CopyExistingEntity); +} +void CL_Ents_Parse_Detach() +{ + DetourDetach((LPVOID*)&v_CL_CopyExistingEntity, &CL_CopyExistingEntity); +} \ No newline at end of file diff --git a/r5dev/engine/client/cl_ents_parse.h b/r5dev/engine/client/cl_ents_parse.h new file mode 100644 index 00000000..cba4ba0b --- /dev/null +++ b/r5dev/engine/client/cl_ents_parse.h @@ -0,0 +1,32 @@ +#ifndef CL_ENTS_PARSE_H +#define CL_ENTS_PARSE_H + +inline CMemory p_CL_CopyExistingEntity; +inline auto v_CL_CopyExistingEntity = p_CL_CopyExistingEntity.RCast(); + + +/////////////////////////////////////////////////////////////////////////////// +class V_CL_Ents_Parse : public IDetour +{ + virtual void GetAdr(void) const + { + spdlog::debug("| FUN: CL_CopyExistingEntity : {:#18x} |\n", p_CL_CopyExistingEntity.GetPtr()); + spdlog::debug("+----------------------------------------------------------------+\n"); + } + virtual void GetFun(void) const + { + p_CL_CopyExistingEntity = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x48\x83\xEC\x70\x4C\x63\x51\x28"), "xxxxxxxxxx"); + v_CL_CopyExistingEntity = p_CL_CopyExistingEntity.RCast(); /*40 53 48 83 EC 70 4C 63 51 28*/ + } + virtual void GetVar(void) const { } + virtual void GetCon(void) const { } + virtual void Attach(void) const { } + virtual void Detach(void) const { } +}; +/////////////////////////////////////////////////////////////////////////////// + +void CL_Ents_Parse_Attach(); +void CL_Ents_Parse_Detach(); + +REGISTER(V_CL_Ents_Parse); +#endif // !CL_ENTS_PARSE_H diff --git a/r5dev/engine/host.h b/r5dev/engine/host.h index ecf24131..6b8fc228 100644 --- a/r5dev/engine/host.h +++ b/r5dev/engine/host.h @@ -7,7 +7,7 @@ inline CMemory p_Host_RunFrame_Render; inline auto v_Host_RunFrame_Render = p_Host_RunFrame_Render.RCast(); inline CMemory p_Host_Error; -inline auto v_Host_Error = p_Host_Error.RCast(); +inline auto v_Host_Error = p_Host_Error.RCast(); inline CMemory p_VCR_EnterPausedState; inline auto v_VCR_EnterPausedState = p_VCR_EnterPausedState.RCast(); @@ -47,7 +47,7 @@ class VHost : public IDetour v_Host_RunFrame = p_Host_RunFrame.RCast(); v_Host_RunFrame_Render = p_Host_Error.RCast(); - v_Host_Error = p_Host_Error.RCast(); + v_Host_Error = p_Host_Error.RCast(); v_VCR_EnterPausedState = p_VCR_EnterPausedState.RCast(); } virtual void GetVar(void) const diff --git a/r5dev/public/const.h b/r5dev/public/const.h index 806799a3..b797e11a 100644 --- a/r5dev/public/const.h +++ b/r5dev/public/const.h @@ -8,6 +8,11 @@ #ifndef CONST_H #define CONST_H +// How many bits to use to encode an edict. +#define MAX_EDICT_BITS 14 // # of bits needed to represent max edicts +// Max # of edicts in a level +#define MAX_EDICTS (1< + @@ -170,6 +171,7 @@ + diff --git a/r5dev/vproj/clientsdk.vcxproj.filters b/r5dev/vproj/clientsdk.vcxproj.filters index 77a060f1..607c2890 100644 --- a/r5dev/vproj/clientsdk.vcxproj.filters +++ b/r5dev/vproj/clientsdk.vcxproj.filters @@ -594,6 +594,9 @@ sdk\engine + + sdk\engine\client + @@ -1754,6 +1757,9 @@ sdk\engine + + sdk\engine\client + diff --git a/r5dev/vproj/gamesdk.vcxproj b/r5dev/vproj/gamesdk.vcxproj index 21a1ee84..d77e2633 100644 --- a/r5dev/vproj/gamesdk.vcxproj +++ b/r5dev/vproj/gamesdk.vcxproj @@ -29,6 +29,7 @@ + @@ -180,6 +181,7 @@ + diff --git a/r5dev/vproj/gamesdk.vcxproj.filters b/r5dev/vproj/gamesdk.vcxproj.filters index 2bc16ec9..b678ae2c 100644 --- a/r5dev/vproj/gamesdk.vcxproj.filters +++ b/r5dev/vproj/gamesdk.vcxproj.filters @@ -633,6 +633,9 @@ sdk\engine + + sdk\engine\client + @@ -1841,6 +1844,9 @@ sdk\engine + + sdk\engine\client + From 693516ceb311f348c82643b7c9d522339c310fa8 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 20:13:51 +0200 Subject: [PATCH 17/39] CL_CopyExistingEntity: remove Host_Error call Calling Host_Error at this stage will cause a dead lock. Removed the call after performing several test (i think the reason all error calls are removed as of Titanfall 2 and Apex Legends (compared to Titanfall 1) is for this reason). Returning false does the job and allows the client to recover as soon as a valid packet comes in. --- r5dev/engine/client/cl_ents_parse.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/r5dev/engine/client/cl_ents_parse.cpp b/r5dev/engine/client/cl_ents_parse.cpp index 6bf20a9a..91698307 100644 --- a/r5dev/engine/client/cl_ents_parse.cpp +++ b/r5dev/engine/client/cl_ents_parse.cpp @@ -4,12 +4,8 @@ // // $NoKeywords: $ //=============================================================================// - - #include "core/stdafx.h" -#include "tier0/frametask.h" #include "public/const.h" -#include "engine/host.h" #include "engine/client/cl_ents_parse.h" bool CL_CopyExistingEntity(__int64 a1, unsigned int* a2, char* a3) @@ -17,7 +13,13 @@ bool CL_CopyExistingEntity(__int64 a1, unsigned int* a2, char* a3) int nNewEntity = *reinterpret_cast(a1 + 40); if (nNewEntity >= MAX_EDICTS || nNewEntity < 0) { - v_Host_Error("CL_CopyExistingEntity: m_nNewEntity >= MAX_EDICTS"); + // Value isn't sanitized in release builds for + // every game powered by the Source Engine 1 + // causing read/write outside of array bounds. + // This defect has let to the achievement of a + // full-chain RCE exploit. We hook and perform + // sanity checks for the value of m_nNewEntity + // here to prevent this behavior from happening. return false; } return v_CL_CopyExistingEntity(a1, a2, a3); From 8e75c57f0da3d0408287c4354927541a954ccc8e Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 20:40:34 +0200 Subject: [PATCH 18/39] Use retail/dev naming convention Renamed 'debug' cfg's to 'dev', refered anything in code as retail/dev/prod. --- r5dev/engine/client/cl_ents_parse.cpp | 2 +- ...up_dedi_debug.cfg => startup_dedi_dev.cfg} | 0 .../{startup_debug.cfg => startup_dev.cfg} | 0 r5dev/sdklauncher/sdklauncher.cpp | 98 +++++++++---------- r5dev/sdklauncher/sdklauncher_const.h | 20 +--- 5 files changed, 55 insertions(+), 65 deletions(-) rename r5dev/resource/cfg/{startup_dedi_debug.cfg => startup_dedi_dev.cfg} (100%) rename r5dev/resource/cfg/{startup_debug.cfg => startup_dev.cfg} (100%) diff --git a/r5dev/engine/client/cl_ents_parse.cpp b/r5dev/engine/client/cl_ents_parse.cpp index 91698307..090249cf 100644 --- a/r5dev/engine/client/cl_ents_parse.cpp +++ b/r5dev/engine/client/cl_ents_parse.cpp @@ -11,7 +11,7 @@ bool CL_CopyExistingEntity(__int64 a1, unsigned int* a2, char* a3) { int nNewEntity = *reinterpret_cast(a1 + 40); - if (nNewEntity >= MAX_EDICTS || nNewEntity < 0) + if (nNewEntity >= MAX_EDICTS || nNewEntity < NULL) { // Value isn't sanitized in release builds for // every game powered by the Source Engine 1 diff --git a/r5dev/resource/cfg/startup_dedi_debug.cfg b/r5dev/resource/cfg/startup_dedi_dev.cfg similarity index 100% rename from r5dev/resource/cfg/startup_dedi_debug.cfg rename to r5dev/resource/cfg/startup_dedi_dev.cfg diff --git a/r5dev/resource/cfg/startup_debug.cfg b/r5dev/resource/cfg/startup_dev.cfg similarity index 100% rename from r5dev/resource/cfg/startup_debug.cfg rename to r5dev/resource/cfg/startup_dev.cfg diff --git a/r5dev/sdklauncher/sdklauncher.cpp b/r5dev/sdklauncher/sdklauncher.cpp index a7c156a0..17368387 100644 --- a/r5dev/sdklauncher/sdklauncher.cpp +++ b/r5dev/sdklauncher/sdklauncher.cpp @@ -17,7 +17,7 @@ void CLauncher::InitSurface() } /////////////////////////////////////////////////////////////////////////////// -// Purpose: initializes the console (release builds only) +// Purpose: initializes the console (development only) /////////////////////////////////////////////////////////////////////////////// void CLauncher::InitConsole() { @@ -41,16 +41,16 @@ void CLauncher::InitLogger() // Purpose: handles user input pre-init // Input : argc - // *argv - -// Output : exit_code (-1 if EP should continue to HandleInput) +// Output : exit_code (-1 if EntryPoint should continue to HandleInput) /////////////////////////////////////////////////////////////////////////////// int CLauncher::HandleCmdLine(int argc, char* argv[]) { for (int i = 1; i < __argc; ++i) { std::string arg = __argv[i]; - if ((arg == "-debug") || (arg == "-dbg")) + if ((arg == "-developer") || (arg == "-dev")) { - if (g_pLauncher->Setup(eLaunchMode::LM_HOST_DEBUG, eLaunchState::LS_CHEATS)) + if (g_pLauncher->Setup(eLaunchMode::LM_HOST_DEV, eLaunchState::LS_CHEATS)) { if (g_pLauncher->Launch()) { @@ -62,7 +62,7 @@ int CLauncher::HandleCmdLine(int argc, char* argv[]) Sleep(2000); return EXIT_FAILURE; } - if ((arg == "-release") || (arg == "-rel")) + if ((arg == "-retail") || (arg == "-prod")) { if (g_pLauncher->Setup(eLaunchMode::LM_HOST, eLaunchState::LS_CHEATS)) { @@ -78,7 +78,7 @@ int CLauncher::HandleCmdLine(int argc, char* argv[]) } if ((arg == "-dedicated_dev") || (arg == "-dedid")) { - if (g_pLauncher->Setup(eLaunchMode::LM_SERVER_DEBUG, eLaunchState::LS_CHEATS)) + if (g_pLauncher->Setup(eLaunchMode::LM_SERVER_DEV, eLaunchState::LS_CHEATS)) { if (g_pLauncher->Launch()) { @@ -106,7 +106,7 @@ int CLauncher::HandleCmdLine(int argc, char* argv[]) } if ((arg == "-client_dev") || (arg == "-cld")) { - if (g_pLauncher->Setup(eLaunchMode::LM_CLIENT_DEBUG, eLaunchState::LS_CHEATS)) + if (g_pLauncher->Setup(eLaunchMode::LM_CLIENT_DEV, eLaunchState::LS_CHEATS)) { if (g_pLauncher->Launch()) { @@ -143,23 +143,23 @@ int CLauncher::HandleCmdLine(int argc, char* argv[]) int CLauncher::HandleInput() { std::cout << "----------------------------------------------------------------------------------------------------------------------" << std::endl; - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "If a DEBUG option has been chosen as launch parameter, do not broadcast servers to the Server Browser!\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "If a DEV option has been chosen as launch parameter, do not broadcast servers to the Server Browser!\n"); g_pLauncher->AddLog(spdlog::level::level_enum::warn, "All FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ConVar's/ConCommand's will be enabled.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Connected clients will be able to set and execute anything flagged FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Connected clients will be able to set and execute anything marked FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY.\n"); std::cout << "----------------------------------------------------------------------------------------------------------------------" << std::endl; - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use DEBUG HOST [0] for research and development purposes.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use RELEASE HOST [1] for playing the game and creating servers.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use DEBUG SERVER [2] for research and development purposes.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use RELEASE SERVER [3] for running and hosting dedicated servers.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use DEBUG CLIENT [4] for research and development purposes.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use RELEASE CLIENT [5] for running client only builds against remote servers.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use DEV HOST [0] for research and development purposes.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use RETAIL HOST [1] for playing the game and creating servers.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use DEV SERVER [2] for research and development purposes.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use RETAIL SERVER [3] for running and hosting dedicated servers.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use DEV CLIENT [4] for research and development purposes.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::warn, "Use RETAIL CLIENT [5] for running client only builds against remote servers.\n"); std::cout << "----------------------------------------------------------------------------------------------------------------------" << std::endl; - g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '0' for 'DEBUG HOST'.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '1' for 'RELEASE HOST'.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '2' for 'DEBUG SERVER'.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '3' for 'RELEASE SERVER'.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '4' for 'DEBUG CLIENT'.\n"); - g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '5' for 'RELEASE CLIENT'.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '0' for 'DEV HOST'.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '1' for 'RETAIL HOST'.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '2' for 'DEV SERVER'.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '3' for 'RETAIL SERVER'.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '4' for 'DEV CLIENT'.\n"); + g_pLauncher->AddLog(spdlog::level::level_enum::info, "Enter '5' for 'RETAIL CLIENT'.\n"); std::cout << "----------------------------------------------------------------------------------------------------------------------" << std::endl; std::cout << "User input: "; @@ -171,7 +171,7 @@ int CLauncher::HandleInput() eLaunchMode mode = static_cast(std::stoi(input)); switch (mode) { - case eLaunchMode::LM_HOST_DEBUG: + case eLaunchMode::LM_HOST_DEV: { if (g_pLauncher->Setup(mode, eLaunchState::LS_CHEATS)) { @@ -199,7 +199,7 @@ int CLauncher::HandleInput() Sleep(2000); return EXIT_FAILURE; } - case eLaunchMode::LM_SERVER_DEBUG: + case eLaunchMode::LM_SERVER_DEV: { if (g_pLauncher->Setup(mode, eLaunchState::LS_CHEATS)) { @@ -227,7 +227,7 @@ int CLauncher::HandleInput() Sleep(2000); return EXIT_FAILURE; } - case eLaunchMode::LM_CLIENT_DEBUG: + case eLaunchMode::LM_CLIENT_DEV: { if (g_pLauncher->Setup(mode, eLaunchState::LS_CHEATS)) { @@ -290,9 +290,9 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) /////////////////////////////////////////////////////////////////////////// switch (lMode) { - case eLaunchMode::LM_HOST_DEBUG: + case eLaunchMode::LM_HOST_DEV: { - fs::path cfgPath = fs::current_path() /= "platform\\cfg\\startup_debug.cfg"; + fs::path cfgPath = fs::current_path() /= "platform\\cfg\\startup_dev.cfg"; std::ifstream cfgFile(cfgPath); if (cfgFile.good() && cfgFile) { @@ -302,7 +302,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) } else { - AddLog(spdlog::level::level_enum::err, "File 'platform\\cfg\\startup_debug.cfg' does not exist!\n"); + AddLog(spdlog::level::level_enum::err, "File 'platform\\cfg\\startup_dev.cfg' does not exist!\n"); return false; } @@ -310,7 +310,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCmdLineArgs; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHING GAME [DEBUG] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHING GAME [DEV] ***\n"); break; } case eLaunchMode::LM_HOST: @@ -333,12 +333,12 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCmdLineArgs; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHING GAME [RELEASE] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHING GAME [RETAIL] ***\n"); break; } - case eLaunchMode::LM_SERVER_DEBUG: + case eLaunchMode::LM_SERVER_DEV: { - fs::path cfgPath = fs::current_path() /= "platform\\cfg\\startup_dedi_debug.cfg"; + fs::path cfgPath = fs::current_path() /= "platform\\cfg\\startup_dedi_dev.cfg"; std::ifstream cfgFile(cfgPath); if (cfgFile.good() && cfgFile) { @@ -348,7 +348,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) } else { - AddLog(spdlog::level::level_enum::err, "File 'platform\\cfg\\startup_dedi_debug.cfg' does not exist!\n"); + AddLog(spdlog::level::level_enum::err, "File 'platform\\cfg\\startup_dedi_dev.cfg' does not exist!\n"); return false; } @@ -356,7 +356,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) m_svGameExe = m_svCurrentDir + "\\r5apex_ds.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex_ds.exe " + svCmdLineArgs; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHING DEDICATED [DEBUG] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHING DEDICATED [DEV] ***\n"); break; } case eLaunchMode::LM_SERVER: @@ -379,12 +379,12 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) m_svGameExe = m_svCurrentDir + "\\r5apex_ds.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex_ds.exe " + svCmdLineArgs; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHING DEDICATED [RELEASE] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHING DEDICATED [RETAIL] ***\n"); break; } - case eLaunchMode::LM_CLIENT_DEBUG: + case eLaunchMode::LM_CLIENT_DEV: { - fs::path cfgPath = fs::current_path() /= "platform\\cfg\\startup_client_debug.cfg"; + fs::path cfgPath = fs::current_path() /= "platform\\cfg\\startup_client_dev.cfg"; std::ifstream cfgFile(cfgPath); if (cfgFile.good() && cfgFile) { @@ -394,7 +394,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) } else { - AddLog(spdlog::level::level_enum::err, "File 'platform\\cfg\\startup_client_debug.cfg' does not exist!\n"); + AddLog(spdlog::level::level_enum::err, "File 'platform\\cfg\\startup_client_dev.cfg' does not exist!\n"); return false; } @@ -402,7 +402,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCmdLineArgs; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHING CLIENT [DEBUG] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHING CLIENT [DEV] ***\n"); break; } case eLaunchMode::LM_CLIENT: @@ -425,7 +425,7 @@ bool CLauncher::Setup(eLaunchMode lMode, eLaunchState lState) m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCmdLineArgs; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHING CLIENT [RELEASE] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHING CLIENT [RETAIL] ***\n"); break; } default: @@ -460,13 +460,13 @@ bool CLauncher::Setup(eLaunchMode lMode, const string& svCommandLine) /////////////////////////////////////////////////////////////////////////// switch (lMode) { - case eLaunchMode::LM_HOST_DEBUG: + case eLaunchMode::LM_HOST_DEV: { m_svWorkerDll = m_svCurrentDir + "\\gamesdk.dll"; m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCommandLine; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR HOST [DEBUG] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR HOST [DEV] ***\n"); break; } case eLaunchMode::LM_HOST: @@ -475,16 +475,16 @@ bool CLauncher::Setup(eLaunchMode lMode, const string& svCommandLine) m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCommandLine; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR HOST [RELEASE] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR HOST [RETAIL] ***\n"); break; } - case eLaunchMode::LM_SERVER_DEBUG: + case eLaunchMode::LM_SERVER_DEV: { m_svWorkerDll = m_svCurrentDir + "\\dedicated.dll"; m_svGameExe = m_svCurrentDir + "\\r5apex_ds.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex_ds.exe " + svCommandLine; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR DEDICATED [DEBUG] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR DEDICATED [DEV] ***\n"); break; } case eLaunchMode::LM_SERVER: @@ -493,16 +493,16 @@ bool CLauncher::Setup(eLaunchMode lMode, const string& svCommandLine) m_svGameExe = m_svCurrentDir + "\\r5apex_ds.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex_ds.exe " + svCommandLine; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR DEDICATED [RELEASE] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR DEDICATED [RETAIL] ***\n"); break; } - case eLaunchMode::LM_CLIENT_DEBUG: + case eLaunchMode::LM_CLIENT_DEV: { m_svWorkerDll = m_svCurrentDir + "\\bin\\x64_retail\\client.dll"; m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCommandLine; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR CLIENT [DEBUG] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR CLIENT [DEV] ***\n"); break; } case eLaunchMode::LM_CLIENT: @@ -511,7 +511,7 @@ bool CLauncher::Setup(eLaunchMode lMode, const string& svCommandLine) m_svGameExe = m_svCurrentDir + "\\r5apex.exe"; m_svCmdLine = m_svCurrentDir + "\\r5apex.exe " + svCommandLine; - AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR CLIENT [RELEASE] ***\n"); + AddLog(spdlog::level::level_enum::info, "*** LAUNCHER SETUP FOR CLIENT [RETAIL] ***\n"); break; } default: @@ -592,7 +592,7 @@ bool CLauncher::Launch() const } /////////////////////////////////////////////////////////////////////////////// -// Entrypoint. +// EntryPoint. /////////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[], char* envp[]) { diff --git a/r5dev/sdklauncher/sdklauncher_const.h b/r5dev/sdklauncher/sdklauncher_const.h index cdd2206e..ad87bf6a 100644 --- a/r5dev/sdklauncher/sdklauncher_const.h +++ b/r5dev/sdklauncher/sdklauncher_const.h @@ -1,26 +1,16 @@ #pragma once //----------------------------------------------------------------------------- -// Launch and inject specified dll based on launchmode +// Launch and inject specified dll based on launch mode //----------------------------------------------------------------------------- -//enum class eLaunchMode : int -//{ -// LM_NULL, -// LM_DEBUG_GAME, // Debug worker DLL. -// LM_RELEASE_GAME, // Release worker DLL. -// LM_DEBUG_DEDI, // Debug dedicated DLL. -// LM_RELEASE_DEDI // Release dedicated DLL. -//}; - - enum class eLaunchMode : int { LM_NONE = -1, - LM_HOST_DEBUG, + LM_HOST_DEV, LM_HOST, - LM_SERVER_DEBUG, + LM_SERVER_DEV, LM_SERVER, - LM_CLIENT_DEBUG, + LM_CLIENT_DEV, LM_CLIENT, }; @@ -32,5 +22,5 @@ enum class eLaunchState : int LS_NULL, LS_NOCHEATS, // Disabled cheats LS_CHEATS, // Enable cheats - LS_DEBUG // Enable debug + LS_DEV // Enable devonly }; \ No newline at end of file From c269d297b842b1064ae15093cb7cc46d109d19a4 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 20:41:10 +0200 Subject: [PATCH 19/39] Update basepanel.cpp --- r5dev/sdklauncher/basepanel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/r5dev/sdklauncher/basepanel.cpp b/r5dev/sdklauncher/basepanel.cpp index 2d3173f4..11615640 100644 --- a/r5dev/sdklauncher/basepanel.cpp +++ b/r5dev/sdklauncher/basepanel.cpp @@ -740,7 +740,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters) if (this->m_DevelopmentToggle->Checked()) { svParameters.append("-devsdk\n"); - results = eLaunchMode::LM_HOST_DEBUG; + results = eLaunchMode::LM_HOST_DEV; } else results = eLaunchMode::LM_HOST; @@ -865,7 +865,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters) if (this->m_DevelopmentToggle->Checked()) { svParameters.append("-devsdk\n"); - results = eLaunchMode::LM_SERVER_DEBUG; + results = eLaunchMode::LM_SERVER_DEV; } else results = eLaunchMode::LM_SERVER; @@ -951,7 +951,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters) if (this->m_DevelopmentToggle->Checked()) { svParameters.append("-devsdk\n"); - results = eLaunchMode::LM_CLIENT_DEBUG; + results = eLaunchMode::LM_CLIENT_DEV; } else results = eLaunchMode::LM_CLIENT; From 4c7ed958949bb098046653af44392df90ac6d990 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 20:57:26 +0200 Subject: [PATCH 20/39] Update CFG files Set 'sv_quota_stringCmdsPerSecond' to "256" for development. Enable 'bhit_enable' for development. --- r5dev/resource/cfg/autoexec_client_dev.cfg | 4 ++-- r5dev/resource/cfg/autoexec_dev.cfg | 1 + r5dev/resource/cfg/autoexec_server_dev.cfg | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/r5dev/resource/cfg/autoexec_client_dev.cfg b/r5dev/resource/cfg/autoexec_client_dev.cfg index 0e3ed573..bd135be8 100644 --- a/r5dev/resource/cfg/autoexec_client_dev.cfg +++ b/r5dev/resource/cfg/autoexec_client_dev.cfg @@ -73,5 +73,5 @@ cl_ent_absbox "1" // Display entity abs bo ////////////////////////// mat_showdxoutput "1" // Shows debug information from the DirectX hook system. gl_clear_color_buffer "1" // Enable or disable the clearing of the main color buffer. -//mat_sync_rt "1" // Enable to debug render threads more easily (!slower!). -//mat_sync_rt_flushes_gpu "1" // Enable to debug render threads more easily (!slower!). +//mat_sync_rt "1" // Enable to debug render threads more easily ( !slower! ). +//mat_sync_rt_flushes_gpu "1" // Enable to debug render threads more easily ( !slower! ). diff --git a/r5dev/resource/cfg/autoexec_dev.cfg b/r5dev/resource/cfg/autoexec_dev.cfg index 54853d22..039d3a7e 100644 --- a/r5dev/resource/cfg/autoexec_dev.cfg +++ b/r5dev/resource/cfg/autoexec_dev.cfg @@ -3,6 +3,7 @@ ////////////////////////// sv_cheats "1" // Allow cheats on the server. mp_allowed "1" // Whether multiplayer is allowed or not. +bhit_enable "1" // Bullet trajectory debug. developer "1" // Required for certain script functionality. ////////////////////////// diff --git a/r5dev/resource/cfg/autoexec_server_dev.cfg b/r5dev/resource/cfg/autoexec_server_dev.cfg index b76da7b7..41bd23a0 100644 --- a/r5dev/resource/cfg/autoexec_server_dev.cfg +++ b/r5dev/resource/cfg/autoexec_server_dev.cfg @@ -6,6 +6,7 @@ ////////////////////////// //hostname "R5" // Determines the name of the server displayed in the server browser. sv_requireOriginToken "0" // Enables origin token verification on the server +sv_quota_stringCmdsPerSecond "256" // Max string commands per second from a specific client. ////////////////////////// //// SIMULATION //// !!WARNING!!: CHANGING THESE CAN CAUSE SIMULATION ISSUES. DO NOT CHANGE FOR NON-DEBUG ACTIVITY! @@ -25,4 +26,4 @@ sv_visualizetraces "1" // Show native and script related debug tr ////////////////////////// ai_ainRebuildOnMapStart "0" // Whether to rebuild the AI Network graph on level load. ai_ainDumpOnLoad "0" // Whether to dump the parsed AI Network graph file loaded from disk. -ai_ainDebugConnect "1" // Show AI Network graph connection debug. \ No newline at end of file +ai_ainDebugConnect "1" // Show AI Network graph connection debug. From 63f4aafb67638ffbeeab84fd61da8adf6a8e2a4c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:04:41 +0200 Subject: [PATCH 21/39] Update playlists file --- r5dev/resource/playlist/playlists_r5_patch.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/r5dev/resource/playlist/playlists_r5_patch.txt b/r5dev/resource/playlist/playlists_r5_patch.txt index 2fc283ea..f186e14e 100644 --- a/r5dev/resource/playlist/playlists_r5_patch.txt +++ b/r5dev/resource/playlist/playlists_r5_patch.txt @@ -1,7 +1,7 @@ playlists { version stable - versionNum 224 + versionNum 225 Gamemodes { defaults @@ -959,7 +959,7 @@ playlists character_select_time_min 4.0 survival_enable_gladiator_intros 1 match_ending_enabled 0 - player_revive_enabled 0 + player_revive_enabled 0 max_teams 2 max_players 2 min_players 1 @@ -1065,8 +1065,8 @@ playlists "PLAYER_ENDED_KILLSTREAK" "`1%s1`0 ended `1%s2`0's killstreak" "PLAYER_ENDED_OWN_KILLSTREAK" "`1%s1`0 ended their own killstreak" - "DISCONNECT_BANNED" "The client's game account has been banned: Banned" "VALVE_REJECT_BANNED" "You have been banned from this server." + "DISCONNECT_BANNED" "The client's game account has been banned." "DISCONNECT_SEND_RELIABLEOVERFLOW" "Connection to server overflowed (code:river)." "DISCONNECT_SEND_OVERFLOW" "Connection to server overflowed (code:dam)." From 0b77621129f1f0c3c6fb725af58e8cff6bd69bd7 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:07:43 +0200 Subject: [PATCH 22/39] Add missing function dbg print --- r5dev/game/server/gameinterface.h | 1 + 1 file changed, 1 insertion(+) diff --git a/r5dev/game/server/gameinterface.h b/r5dev/game/server/gameinterface.h index 0b670cd5..8dc11315 100644 --- a/r5dev/game/server/gameinterface.h +++ b/r5dev/game/server/gameinterface.h @@ -34,6 +34,7 @@ class VServerGameDLL : public IDetour { virtual void GetAdr(void) const { + spdlog::debug("| FUN: OnReceivedSayTextMessage : {:#18x} |\n", p_CServerGameDLL__OnReceivedSayTextMessage.GetPtr()); spdlog::debug("| VAR: g_pServerGameDLL : {:#18x} |\n", reinterpret_cast(g_pServerGameDLL)); spdlog::debug("| VAR: g_pServerGameClients : {:#18x} |\n", reinterpret_cast(g_pServerGameClients)); spdlog::debug("+----------------------------------------------------------------+\n"); From df986f7d3bee7cec573785c8fc1f3fb2a7547155 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:23:09 +0200 Subject: [PATCH 23/39] ConVar renames Renamed: - sv_pylonRefreshInterval => sv_pylonRefreshRate. - sv_banlistRefreshInterval => sv_banlistRefreshRate. - sv_statusRefreshInterval => sv_statusRefreshRate. --- r5dev/engine/host_state.cpp | 4 ++-- r5dev/tier1/IConVar.cpp | 9 ++++----- r5dev/tier1/cvar.cpp | 6 +++--- r5dev/tier1/cvar.h | 6 +++--- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp index 7c385d5c..c5fb73fa 100644 --- a/r5dev/engine/host_state.cpp +++ b/r5dev/engine/host_state.cpp @@ -232,7 +232,7 @@ FORCEINLINE void CHostState::Think(void) const bInitialized = true; } #ifndef CLIENT_DLL - if (banListTimer.GetDurationInProgress().GetSeconds() > sv_banlistRefreshInterval->GetDouble()) + if (banListTimer.GetDurationInProgress().GetSeconds() > sv_banlistRefreshRate->GetDouble()) { g_pBanSystem->BanListCheck(); banListTimer.Start(); @@ -273,7 +273,7 @@ FORCEINLINE void CHostState::Think(void) const reloadTimer.Start(); } } - if (statsTimer.GetDurationInProgress().GetSeconds() > sv_statusRefreshInterval->GetDouble()) + if (statsTimer.GetDurationInProgress().GetSeconds() > sv_statusRefreshRate->GetDouble()) { string svCurrentPlaylist = KeyValues_GetCurrentPlaylist(); int32_t nPlayerCount = g_pServer->GetNumHumanPlayers(); diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index f3b448bc..86cc71d5 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -101,11 +101,10 @@ void ConVar::Init(void) const #endif // !DEDICATED sv_showconnecting = ConVar::Create("sv_showconnecting" , "1", FCVAR_RELEASE, "Logs information about the connecting client to the console.", false, 0.f, false, 0.f, nullptr, nullptr); sv_pylonVisibility = ConVar::Create("sv_pylonVisibility", "0", FCVAR_RELEASE, "Determines the visibility to the Pylon master server.", false, 0.f, false, 0.f, nullptr, "0 = Offline, 1 = Hidden, 2 = Public."); - sv_pylonRefreshInterval = ConVar::Create("sv_pylonRefreshInterval" , "5.0", FCVAR_RELEASE, "Pylon server host request post update interval (seconds).", true, 2.f, true, 8.f, nullptr, nullptr); - sv_banlistRefreshInterval = ConVar::Create("sv_banlistRefreshInterval", "1.0", FCVAR_RELEASE, "Banlist refresh interval (seconds).", true, 1.f, false, 0.f, nullptr, nullptr); - sv_statusRefreshInterval = ConVar::Create("sv_statusRefreshInterval" , "0.5", FCVAR_RELEASE, "Server status bar update interval (seconds).", false, 0.f, false, 0.f, nullptr, nullptr); - - sv_autoReloadRate = ConVar::Create("sv_autoReloadRate" , "0", FCVAR_RELEASE, "Time in seconds between each server auto-reload (disabled if null). ", true, 0.f, false, 0.f, nullptr, nullptr); + sv_pylonRefreshRate = ConVar::Create("sv_pylonRefreshRate" , "5.0", FCVAR_RELEASE, "Pylon host refresh rate (seconds).", true, 2.f, true, 8.f, nullptr, nullptr); + sv_banlistRefreshRate = ConVar::Create("sv_banlistRefreshRate", "1.0", FCVAR_RELEASE, "Banned list refresh rate (seconds).", true, 1.f, false, 0.f, nullptr, nullptr); + sv_statusRefreshRate = ConVar::Create("sv_statusRefreshRate" , "0.5", FCVAR_RELEASE, "Server status refresh rate (seconds).", false, 0.f, false, 0.f, nullptr, nullptr); + sv_autoReloadRate = ConVar::Create("sv_autoReloadRate" , "0" , FCVAR_RELEASE, "Time in seconds between each server auto-reload (disabled if null). ", true, 0.f, false, 0.f, nullptr, nullptr); sv_quota_stringCmdsPerSecond = ConVar::Create("sv_quota_stringCmdsPerSecond", "16", FCVAR_RELEASE, "How many string commands per second clients are allowed to submit, 0 to disallow all string commands.", true, 0.f, false, 0.f, nullptr, nullptr); #ifdef DEDICATED sv_rcon_debug = ConVar::Create("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index d01115c2..fe9e5758 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -63,9 +63,9 @@ ConVar* navmesh_draw_poly_bounds_inner = nullptr; ConVar* sv_showconnecting = nullptr; ConVar* sv_pylonVisibility = nullptr; -ConVar* sv_pylonRefreshInterval = nullptr; -ConVar* sv_banlistRefreshInterval = nullptr; -ConVar* sv_statusRefreshInterval = nullptr; +ConVar* sv_pylonRefreshRate = nullptr; +ConVar* sv_banlistRefreshRate = nullptr; +ConVar* sv_statusRefreshRate = nullptr; ConVar* sv_forceChatToTeamOnly = nullptr; ConVar* sv_autoReloadRate = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index 54a07246..9b3db641 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -59,9 +59,9 @@ extern ConVar* navmesh_draw_poly_bounds_inner; #endif // DEDICATED extern ConVar* sv_showconnecting; extern ConVar* sv_pylonVisibility; -extern ConVar* sv_pylonRefreshInterval; -extern ConVar* sv_banlistRefreshInterval; -extern ConVar* sv_statusRefreshInterval; +extern ConVar* sv_pylonRefreshRate; +extern ConVar* sv_banlistRefreshRate; +extern ConVar* sv_statusRefreshRate; extern ConVar* sv_forceChatToTeamOnly; extern ConVar* sv_autoReloadRate; From 678909f40f1105ef163ea3d5e299bd3ef7ddd757 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:47:45 +0200 Subject: [PATCH 24/39] Increment SDK version Version gate next release due to several security fixes. --- r5dev/tier0/basetypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/tier0/basetypes.h b/r5dev/tier0/basetypes.h index 2ba292d8..baed3f8b 100644 --- a/r5dev/tier0/basetypes.h +++ b/r5dev/tier0/basetypes.h @@ -134,7 +134,7 @@ #endif // Max BSP file name len. #define MAX_MAP_NAME 64 -#define SDK_VERSION "VGameSDK004" // Increment this with every /breaking/ SDK change (i.e. security/backend changes breaking compatibility). +#define SDK_VERSION "VGameSDK005" // Increment this with every /breaking/ SDK change (i.e. security/backend changes breaking compatibility). #define SDK_ARRAYSIZE(arr) ((sizeof(arr) / sizeof(*arr))) // Name due to IMGUI implementation and NT implementation that we shouldn't share across everywhere. #ifndef DEDICATED From 42c6be9e085e82e80c6380fdc70468f3f2a1b340 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 00:08:49 +0200 Subject: [PATCH 25/39] Fix client.dll compile errors --- r5dev/engine/client/client.cpp | 6 ++++++ r5dev/engine/server/server.h | 8 +++++++- r5dev/tier1/IConVar.cpp | 4 ++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index ccfdf3ae..0b76cdf5 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -209,7 +209,9 @@ bool CClient::IsHumanPlayer(void) const //--------------------------------------------------------------------------------- void CClient::Clear(void) { +#ifndef CLIENT_DLL g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot. +#endif // !CLIENT_DLL v_CClient_Clear(this); } @@ -219,7 +221,9 @@ void CClient::Clear(void) //--------------------------------------------------------------------------------- void CClient::VClear(CClient* pClient) { +#ifndef CLIENT_DLL g_ServerPlayer[pClient->GetUserID()].Reset(); // Reset ServerPlayer slot. +#endif // !CLIENT_DLL v_CClient_Clear(pClient); } @@ -252,7 +256,9 @@ bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, v bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize) { bool bResult = v_CClient_Connect(pClient, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize); +#ifndef CLIENT_DLL g_ServerPlayer[pClient->GetUserID()].Reset(); // Reset ServerPlayer slot. +#endif // !CLIENT_DLL return bResult; } diff --git a/r5dev/engine/server/server.h b/r5dev/engine/server/server.h index a02c98bd..ae12f961 100644 --- a/r5dev/engine/server/server.h +++ b/r5dev/engine/server/server.h @@ -103,14 +103,17 @@ class VServer : public IDetour { virtual void GetAdr(void) const { +#ifndef CLIENT_DLL spdlog::debug("| FUN: CServer::Think : {:#18x} |\n", p_CServer_Think.GetPtr()); spdlog::debug("| FUN: CServer::ConnectClient : {:#18x} |\n", p_CServer_Authenticate.GetPtr()); spdlog::debug("| FUN: CServer::RejectConnection : {:#18x} |\n", p_CServer_RejectConnection.GetPtr()); spdlog::debug("| VAR: g_pServer[128] : {:#18x} |\n", reinterpret_cast(g_pServer)); spdlog::debug("+----------------------------------------------------------------+\n"); +#endif // !CLIENT_DLL } virtual void GetFun(void) const { +#ifndef CLIENT_DLL p_CServer_Think = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x81\xEC\x00\x00\x00\x00\x80\x3D\x00\x00\x00\x00\x00"), "xxxx?xxxx?xxxx????xx?????"); #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) p_CServer_Authenticate = g_GameDll.FindPatternSIMD(reinterpret_cast("\x44\x89\x44\x24\x00\x55\x56\x57\x48\x8D\xAC\x24\x00\x00\x00\x00"), "xxxx?xxxxxxx????"); @@ -122,13 +125,16 @@ class VServer : public IDetour p_CServer_RejectConnection = g_GameDll.FindPatternSIMD(reinterpret_cast("\x4C\x89\x4C\x24\x00\x53\x55\x56\x57\x48\x81\xEC\x00\x00\x00\x00\x49\x8B\xD9"), "xxxx?xxxxxxx????xxx"); v_CServer_Think = p_CServer_Think.RCast(); /*48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ??*/ - v_CServer_ConnectClient = p_CServer_Authenticate.RCast(); /*40 55 57 41 55 41 57 48 8D AC 24 ?? ?? ?? ??*/ + v_CServer_ConnectClient = p_CServer_Authenticate.RCast(); /*40 55 57 41 55 41 57 48 8D AC 24 ?? ?? ?? ??*/ v_CServer_RejectConnection = p_CServer_RejectConnection.RCast(); /*4C 89 4C 24 ?? 53 55 56 57 48 81 EC ?? ?? ?? ?? 49 8B D9*/ +#endif // !CLIENT_DLL } virtual void GetVar(void) const { +#ifndef CLIENT_DLL g_pServer = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x57\x48\x83\xEC\x20\x48\x0F\xBF\xD1"), "xxxx?xxxxxxxxx") .FindPatternSelf("48 8D 3D").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); +#endif // !CLIENT_DLL } virtual void GetCon(void) const { } virtual void Attach(void) const { } diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 86cc71d5..92e2b9e6 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -256,12 +256,12 @@ void ConVar::InitShipped(void) const hostport = g_pCVar->FindVar("hostport"); host_hasIrreversibleShutdown = g_pCVar->FindVar("host_hasIrreversibleShutdown"); net_usesocketsforloopback = g_pCVar->FindVar("net_usesocketsforloopback"); - sv_forceChatToTeamOnly = g_pCVar->FindVar("sv_forceChatToTeamOnly"); +#ifndef CLIENT_DLL + sv_forceChatToTeamOnly = g_pCVar->FindVar("sv_forceChatToTeamOnly"); sv_forceChatToTeamOnly->RemoveFlags(FCVAR_DEVELOPMENTONLY); sv_forceChatToTeamOnly->AddFlags(FCVAR_REPLICATED); -#ifndef CLIENT_DLL ai_script_nodes_draw->SetValue(-1); bhit_enable->SetValue(0); #endif // !CLIENT_DLL From 3af0c7c0b01b3f09f3d833724fcb2fb95753e51e Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 00:22:43 +0200 Subject: [PATCH 26/39] Fix dedicated.dll compile errors --- r5dev/engine/host_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/engine/host_state.cpp b/r5dev/engine/host_state.cpp index c5fb73fa..4b90e17e 100644 --- a/r5dev/engine/host_state.cpp +++ b/r5dev/engine/host_state.cpp @@ -239,7 +239,7 @@ FORCEINLINE void CHostState::Think(void) const } #endif // !CLIENT_DLL #ifdef DEDICATED - if (pylonTimer.GetDurationInProgress().GetSeconds() > sv_pylonRefreshInterval->GetDouble()) + if (pylonTimer.GetDurationInProgress().GetSeconds() > sv_pylonRefreshRate->GetDouble()) { const NetGameServer_t netGameServer { From eec4d9598eeb6bbb199c5d25c71a508dca836d71 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 15:00:01 +0200 Subject: [PATCH 27/39] CSquirrelVM: define "DEVELOPER" to value of "ceveloper" convar In this retail engine, "DEV" is always zero, except for scripts.rson. I think Respawn Entertainment defined this as zero for production builds under each context except the global one.. To fix this problem, we define a new constant named "DEVELOPER", change all references in scripts that where DEV (now R5DEV due to legacy reasons to mitigate this problem), to DEVELOPER. When the game is launched with -dev, anything within #if DEVELOPER with compiled, like the development behavior of DEV. --- r5dev/squirrel/sqapi.cpp | 8 -------- r5dev/squirrel/sqapi.h | 7 ------- r5dev/squirrel/sqscript.cpp | 33 +++++++++++++++++++++++++-------- r5dev/squirrel/sqscript.h | 21 ++++++++++++++------- r5dev/tier1/IConVar.cpp | 1 + r5dev/tier1/cvar.cpp | 2 ++ r5dev/tier1/cvar.h | 2 ++ 7 files changed, 44 insertions(+), 30 deletions(-) diff --git a/r5dev/squirrel/sqapi.cpp b/r5dev/squirrel/sqapi.cpp index 3b19ab71..d46ffddd 100644 --- a/r5dev/squirrel/sqapi.cpp +++ b/r5dev/squirrel/sqapi.cpp @@ -44,12 +44,6 @@ void sq_pushinteger(HSQUIRRELVM v, SQInteger val) v_sq_pushinteger(v, val); } -//--------------------------------------------------------------------------------- -void sq_pushconstant(HSQUIRRELVM v, const SQChar* name, SQInteger val) -{ - v_sq_pushconstant(v, name, val); -} - //--------------------------------------------------------------------------------- void sq_newarray(HSQUIRRELVM v, SQInteger size) { @@ -98,7 +92,6 @@ void SQAPI_Attach() DetourAttach((LPVOID*)&v_sq_pushbool, &sq_pushbool); DetourAttach((LPVOID*)&v_sq_pushstring, &sq_pushstring); DetourAttach((LPVOID*)&v_sq_pushinteger, &sq_pushinteger); - DetourAttach((LPVOID*)&v_sq_pushconstant, &sq_pushconstant); DetourAttach((LPVOID*)&v_sq_newarray, &sq_newarray); DetourAttach((LPVOID*)&v_sq_newtable, &sq_newtable); DetourAttach((LPVOID*)&v_sq_newslot, &sq_newslot); @@ -114,7 +107,6 @@ void SQAPI_Detach() DetourDetach((LPVOID*)&v_sq_pushbool, &sq_pushbool); DetourDetach((LPVOID*)&v_sq_pushstring, &sq_pushstring); DetourDetach((LPVOID*)&v_sq_pushinteger, &sq_pushinteger); - DetourDetach((LPVOID*)&v_sq_pushconstant, &sq_pushconstant); DetourDetach((LPVOID*)&v_sq_newarray, &sq_newarray); DetourDetach((LPVOID*)&v_sq_newtable, &sq_newtable); DetourDetach((LPVOID*)&v_sq_newslot, &sq_newslot); diff --git a/r5dev/squirrel/sqapi.h b/r5dev/squirrel/sqapi.h index 490be28f..8d2eba1c 100644 --- a/r5dev/squirrel/sqapi.h +++ b/r5dev/squirrel/sqapi.h @@ -10,7 +10,6 @@ SQRESULT sq_pushroottable(HSQUIRRELVM v); void sq_pushbool(HSQUIRRELVM v, SQBool b); void sq_pushstring(HSQUIRRELVM v, const SQChar* string, SQInteger len); void sq_pushinteger(HSQUIRRELVM v, SQInteger val); -void sq_pushconstant(HSQUIRRELVM v, const SQChar* name, SQInteger val); void sq_newarray(HSQUIRRELVM v, SQInteger size); void sq_newtable(HSQUIRRELVM v); SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx); @@ -35,9 +34,6 @@ inline auto v_sq_pushstring = p_sq_pushstring.RCast(); -inline CMemory p_sq_pushconstant; -inline auto v_sq_pushconstant = p_sq_pushconstant.RCast(); - inline CMemory p_sq_newarray; inline auto v_sq_newarray = p_sq_newarray.RCast(); @@ -68,7 +64,6 @@ class VSqapi : public IDetour spdlog::debug("| FUN: sq_pushbool : {:#18x} |\n", p_sq_pushbool.GetPtr()); spdlog::debug("| FUN: sq_pushstring : {:#18x} |\n", p_sq_pushstring.GetPtr()); spdlog::debug("| FUN: sq_pushinteger : {:#18x} |\n", p_sq_pushinteger.GetPtr()); - spdlog::debug("| FUN: sq_pushconstant : {:#18x} |\n", p_sq_pushconstant.GetPtr()); spdlog::debug("| FUN: sq_newarray : {:#18x} |\n", p_sq_newarray.GetPtr()); spdlog::debug("| FUN: sq_arrayappend : {:#18x} |\n", p_sq_arrayappend.GetPtr()); spdlog::debug("| FUN: sq_newtable : {:#18x} |\n", p_sq_newtable.GetPtr()); @@ -88,7 +83,6 @@ class VSqapi : public IDetour p_sq_pushstring = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x56\x48\x83\xEC\x30\x48\x8B\xF1\x48\x85\xD2\x0F\x84\x8F\x00"), "xxxxxxxxxxxxxxxx"); #endif p_sq_pushinteger = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x83\xEC\x38\x33\xC0\x48\xC7\x44\x24\x20\x02\x00\x00\x05\x48"), "xxxxxxxxxxxxxxxx"); - p_sq_pushconstant = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x30\x4C\x8B"), "xxxx?xxxx?xxxx?xxxxxxx"); p_sq_newarray = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x30\x48\x8B\xD9\x48\xC7\x44\x24\x20\x40"), "xxxxxxxxxxxxxxxxxxx"); p_sq_newtable = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x30\x48\x8B\xD9\x48\xC7\x44\x24\x20\x20"), "xxxxxxxxxxxxxxxxxxx"); p_sq_newslot = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x48\x83\xEC\x30\x44\x8B\x49\x00\x48\x8B\xD9\x41\x8B\xC1"), "xxxxxxxxx?xxxxxx"); @@ -105,7 +99,6 @@ class VSqapi : public IDetour v_sq_pushbool = p_sq_pushbool.RCast(); /*48 83 EC 38 33 C0 48 C7 44 24 20 08 00 00 01 48*/ v_sq_pushstring = p_sq_pushstring.RCast(); /*40 56 48 83 EC 30 48 8B F1 48 85 D2 0F 84 8F 00*/ v_sq_pushinteger = p_sq_pushinteger.RCast(); /*48 83 EC 38 33 C0 48 C7 44 24 20 02 00 00 05 48*/ - v_sq_pushconstant = p_sq_pushconstant.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 4C 8B*/ v_sq_newarray = p_sq_newarray.RCast(); /*48 89 5C 24 08 57 48 83 EC 30 48 8B D9 48 C7 44 24 20 40*/ v_sq_newtable = p_sq_newtable.RCast(); /*48 89 5C 24 08 57 48 83 EC 30 48 8B D9 48 C7 44 24 20 20*/ v_sq_newslot = p_sq_newslot.RCast(); /*40 53 48 83 EC 20 8B 41 ?? 48 8B D9 2B 41 ?? 83 F8 02 7D*/ diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index 95be0ee8..14cfae3d 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -125,18 +125,32 @@ void Script_RegisterUIFunctions(CSquirrelVM* pSquirrelVM) Script_RegisterFunction(pSquirrelVM, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); } +//--------------------------------------------------------------------------------- +// Purpose: registers global constant for target context +// Input : *pSquirrelVM - +// *name - +// val - +//--------------------------------------------------------------------------------- +SQRESULT Script_RegisterConstant(CSquirrelVM* pSquirrelVM, const SQChar* name, SQInteger val) +{ + return v_Script_RegisterConstant(pSquirrelVM, name, val); +} + //--------------------------------------------------------------------------------- // Purpose: Initialize all CLIENT/UI global structs and register SDK (CLIENT/UI) script functions // Input : *pSquirrelVM - // context - (1 = CLIENT 2 = UI) //--------------------------------------------------------------------------------- -SQRESULT Script_InitializeCLGlobalStructs(CSquirrelVM* pSquirrelVM, SQCONTEXT context) +SQRESULT Script_InitializeCLGlobalStructs(HSQUIRRELVM v, SQCONTEXT context) { - SQRESULT results = v_Script_InitializeCLGlobalStructs(pSquirrelVM, context); + SQRESULT results = v_Script_InitializeCLGlobalStructs(v, context); + if (context == SQCONTEXT::CLIENT) Script_RegisterClientFunctions(g_pClientScript.GetValue()); if (context == SQCONTEXT::UI) Script_RegisterUIFunctions(g_pUIScript.GetValue()); + + Script_RegisterConstant(Script_GetContextObject(context), "DEVELOPER", developer->GetInt()); return results; } #endif // !DEDICATED @@ -146,10 +160,11 @@ SQRESULT Script_InitializeCLGlobalStructs(CSquirrelVM* pSquirrelVM, SQCONTEXT co // Purpose: Initialize all SERVER global structs and register SDK (SERVER) script functions // Input : *pSquirrelVM - //--------------------------------------------------------------------------------- -void Script_InitializeSVGlobalStructs(CSquirrelVM* pSquirrelVM) +void Script_InitializeSVGlobalStructs(HSQUIRRELVM v) { - v_Script_InitializeSVGlobalStructs(pSquirrelVM); - Script_RegisterServerFunctions(g_pServerScript.GetValue()); + v_Script_InitializeSVGlobalStructs(v); + Script_RegisterServerFunctions(Script_GetContextObject(SQCONTEXT::SERVER)); + Script_RegisterConstant(Script_GetContextObject(SQCONTEXT::SERVER), "DEVELOPER", developer->GetInt()); } //--------------------------------------------------------------------------------- @@ -160,7 +175,7 @@ SQBool Script_CreateServerVM() { SQBool results = v_Script_CreateServerVM(); if (results) - DevMsg(eDLL_T::SERVER, "Created SERVER VM: '%p'\n", g_pServerScript.GetValue()); + DevMsg(eDLL_T::SERVER, "Created SERVER VM: '%p'\n", Script_GetContextObject(SQCONTEXT::SERVER)); else Error(eDLL_T::SERVER, EXIT_FAILURE, "Failed to create SERVER VM\n"); return results; @@ -177,7 +192,7 @@ SQBool Script_CreateClientVM(CHLClient* pHlClient) { SQBool results = v_Script_CreateClientVM(pHlClient); if (results) - DevMsg(eDLL_T::CLIENT, "Created CLIENT VM: '%p'\n", g_pClientScript.GetValue()); + DevMsg(eDLL_T::CLIENT, "Created CLIENT VM: '%p'\n", Script_GetContextObject(SQCONTEXT::CLIENT)); else Error(eDLL_T::CLIENT, EXIT_FAILURE, "Failed to create CLIENT VM\n"); return results; @@ -191,7 +206,7 @@ SQBool Script_CreateUIVM() { SQBool results = v_Script_CreateUIVM(); if (results) - DevMsg(eDLL_T::UI, "Created UI VM: '%p'\n", g_pUIScript.GetValue()); + DevMsg(eDLL_T::UI, "Created UI VM: '%p'\n", Script_GetContextObject(SQCONTEXT::UI)); else Error(eDLL_T::UI, EXIT_FAILURE, "Failed to create UI VM\n"); return results; @@ -298,6 +313,7 @@ void Script_Execute(const SQChar* code, const SQCONTEXT context) //--------------------------------------------------------------------------------- void SQScript_Attach() { + DetourAttach((LPVOID*)&v_Script_RegisterConstant, &Script_RegisterConstant); #ifndef DEDICATED DetourAttach((LPVOID*)&v_Script_InitializeCLGlobalStructs, &Script_InitializeCLGlobalStructs); #endif // !DEDICATED @@ -315,6 +331,7 @@ void SQScript_Attach() //--------------------------------------------------------------------------------- void SQScript_Detach() { + DetourDetach((LPVOID*)&v_Script_RegisterConstant, &Script_RegisterConstant); #ifndef DEDICATED DetourDetach((LPVOID*)&v_Script_InitializeCLGlobalStructs, &Script_InitializeCLGlobalStructs); #endif // !DEDICATED diff --git a/r5dev/squirrel/sqscript.h b/r5dev/squirrel/sqscript.h index 1d09d352..2cb8c933 100644 --- a/r5dev/squirrel/sqscript.h +++ b/r5dev/squirrel/sqscript.h @@ -60,13 +60,16 @@ private: inline CMemory p_Script_RegisterFunction; inline auto v_Script_RegisterFunction = p_Script_RegisterFunction.RCast(); + +inline CMemory p_Script_RegisterConstant; +inline auto v_Script_RegisterConstant = p_Script_RegisterConstant.RCast(); #if !defined (CLIENT_DLL) inline CMemory p_Script_InitializeSVGlobalStructs; -inline auto v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); +inline auto v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); #endif // !CLIENT_DLL #if !defined (DEDICATED) inline CMemory p_Script_InitializeCLGlobalStructs; -inline auto v_Script_InitializeCLGlobalStructs = p_Script_InitializeCLGlobalStructs.RCast(); +inline auto v_Script_InitializeCLGlobalStructs = p_Script_InitializeCLGlobalStructs.RCast(); #endif // !DEDICATED #if !defined (CLIENT_DLL) && defined (GAMEDLL_S0) || defined (GAMEDLL_S1) inline CMemory p_Script_CreateServerVM; @@ -100,14 +103,15 @@ inline CMemory g_pClientScript; inline CMemory g_pUIScript; #endif // !DEDICATED +SQRESULT Script_RegisterConstant(CSquirrelVM* pSquirrelVM, const SQChar* name, SQInteger val); SQRESULT Script_RegisterFunction(CSquirrelVM* pSquirrelVM, const SQChar* szScriptName, const SQChar* szNativeName, const SQChar* szHelpString, const SQChar* szRetValType, const SQChar* szArgTypes, void* pFunction); void Script_RegisterServerFunctions(CSquirrelVM* pSquirrelVM); void Script_RegisterClientFunctions(CSquirrelVM* pSquirrelVM); void Script_RegisterUIFunctions(CSquirrelVM* pSquirrelVM); -SQRESULT Script_InitializeCLGlobalStructs(CSquirrelVM*, SQCONTEXT context); -void Script_InitializeSVGlobalStructs(CSquirrelVM* pSquirrelVM); +SQRESULT Script_InitializeCLGlobalStructs(HSQUIRRELVM v, SQCONTEXT context); +void Script_InitializeSVGlobalStructs(HSQUIRRELVM v); SQBool Script_CreateServerVM(); #ifndef DEDICATED @@ -128,7 +132,8 @@ class VSquirrelVM : public IDetour { virtual void GetAdr(void) const { - spdlog::debug("| FUN: Script_RegisterFunc : {:#18x} |\n", p_Script_RegisterFunction.GetPtr()); + spdlog::debug("| FUN: Script_RegisterConstant : {:#18x} |\n", p_Script_RegisterConstant.GetPtr()); + spdlog::debug("| FUN: Script_RegisterFunction : {:#18x} |\n", p_Script_RegisterFunction.GetPtr()); #ifndef CLIENT_DLL spdlog::debug("| FUN: Script_InitializeSVGlobalStructs : {:#18x} |\n", p_Script_InitializeSVGlobalStructs.GetPtr()); #endif // !CLIENT_DLL @@ -155,6 +160,7 @@ class VSquirrelVM : public IDetour } virtual void GetFun(void) const { + p_Script_RegisterConstant = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x30\x4C\x8B"), "xxxx?xxxx?xxxx?xxxxxxx"); p_Script_RegisterFunction = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x83\xEC\x38\x45\x0F\xB6\xC8"), "xxxxxxxx"); #if !defined (CLIENT_DLL) p_Script_InitializeSVGlobalStructs = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x30\x48\x8B\x3D\x00\x00\x00\x00\x48\x8B\xF1"), "xxxx?xxxxxxxx????xxx"); @@ -181,12 +187,13 @@ class VSquirrelVM : public IDetour #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) p_Script_LoadScript = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x8B\xC4\x48\x89\x48\x08\x55\x41\x56\x48\x8D\x68"), "xxxxxxxxxxxxx"); #endif + v_Script_RegisterConstant = p_Script_RegisterConstant.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 4C 8B*/ v_Script_RegisterFunction = p_Script_RegisterFunction.RCast(); /*48 83 EC 38 45 0F B6 C8*/ #if !defined (CLIENT_DLL) - v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); /*48 89 74 24 ?? 57 48 83 EC 30 48 8B 3D ?? ?? ?? ?? 48 8B F1*/ + v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); /*48 89 74 24 ?? 57 48 83 EC 30 48 8B 3D ?? ?? ?? ?? 48 8B F1*/ #endif // !CLIENT_DLL #if !defined (DEDICATED) - v_Script_InitializeCLGlobalStructs = p_Script_InitializeCLGlobalStructs.RCast(); /*48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 48 63 C2 48 8D 3D ?? ?? ?? ??*/ + v_Script_InitializeCLGlobalStructs = p_Script_InitializeCLGlobalStructs.RCast(); /*48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 48 63 C2 48 8D 3D ?? ?? ?? ??*/ #endif // !DEDICATED #if !defined (CLIENT_DLL) v_Script_CreateServerVM = p_Script_CreateServerVM.RCast(); /*40 53 56 48 83 EC 48 48 8D 0D ?? ?? ?? ??*/ diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index 92e2b9e6..cc685943 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -230,6 +230,7 @@ void ConVar::InitShipped(void) const #if !defined (GAMEDLL_S0) && !defined (GAMEDLL_S1) bhit_enable = g_pCVar->FindVar("bhit_enable"); #endif // !GAMEDLL_S0 && !GAMEDLL_S1 + developer = g_pCVar->FindVar("developer"); #endif // !CLIENT_DLL #ifndef DEDICATED cl_threaded_bone_setup = g_pCVar->FindVar("cl_threaded_bone_setup"); diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index fe9e5758..73921678 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -14,6 +14,8 @@ ConVar* old_gather_props = nullptr; ConVar* enable_debug_overlays = nullptr; ConVar* cm_unset_all_cmdquery = nullptr; +ConVar* developer = nullptr; + ConVar* staticProp_defaultBuildFrustum = nullptr; ConVar* staticProp_no_fade_scalar = nullptr; ConVar* staticProp_gather_size_weight = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index 9b3db641..ae9be600 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -10,6 +10,8 @@ extern ConVar* old_gather_props; extern ConVar* enable_debug_overlays; extern ConVar* cm_unset_all_cmdquery; +extern ConVar* developer; + extern ConVar* staticProp_defaultBuildFrustum; extern ConVar* staticProp_no_fade_scalar; extern ConVar* staticProp_gather_size_weight; From 8e880b8052ea1b2918a8558b2a280e738974079d Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 15:26:21 +0200 Subject: [PATCH 28/39] CSquirrelVM: define "DEVELOPER" at the earliest stage possible 'Script_DestroySignalEntryListHead' is the last function to be called before 'init.nut' is loaded and parsed. Defining "DEVELOPER" with value of "developer" convar allows us to utilize this constant in 'init.nut'. --- r5dev/squirrel/sqscript.cpp | 19 ++++++++++++++++--- r5dev/squirrel/sqscript.h | 24 +++++++++++++++--------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index 14cfae3d..1677fea6 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -149,8 +149,6 @@ SQRESULT Script_InitializeCLGlobalStructs(HSQUIRRELVM v, SQCONTEXT context) Script_RegisterClientFunctions(g_pClientScript.GetValue()); if (context == SQCONTEXT::UI) Script_RegisterUIFunctions(g_pUIScript.GetValue()); - - Script_RegisterConstant(Script_GetContextObject(context), "DEVELOPER", developer->GetInt()); return results; } #endif // !DEDICATED @@ -164,7 +162,6 @@ void Script_InitializeSVGlobalStructs(HSQUIRRELVM v) { v_Script_InitializeSVGlobalStructs(v); Script_RegisterServerFunctions(Script_GetContextObject(SQCONTEXT::SERVER)); - Script_RegisterConstant(Script_GetContextObject(SQCONTEXT::SERVER), "DEVELOPER", developer->GetInt()); } //--------------------------------------------------------------------------------- @@ -237,6 +234,20 @@ CSquirrelVM* Script_GetContextObject(const SQCONTEXT context) } } +//--------------------------------------------------------------------------------- +// Purpose: destroys the signal entry list head +// Input : *s - +// v - +// f - +// Output : true on success, false otherwise +//--------------------------------------------------------------------------------- +SQBool Script_DestroySignalEntryListHead(CSquirrelVM* s, HSQUIRRELVM v, SQFloat f) +{ + SQBool result = v_Script_DestroySignalEntryListHead(s, v, f); + Script_RegisterConstant(s, "DEVELOPER", developer->GetInt()); + return result; +} + //--------------------------------------------------------------------------------- // Purpose: prints the global include file the compiler loads for loading scripts // Input : *szRsonName - @@ -325,6 +336,7 @@ void SQScript_Attach() DetourAttach((LPVOID*)&v_Script_CreateClientVM, &Script_CreateClientVM); DetourAttach((LPVOID*)&v_Script_CreateUIVM, &Script_CreateUIVM); #endif // !DEDICATED + DetourAttach((LPVOID*)&v_Script_DestroySignalEntryListHead, &Script_DestroySignalEntryListHead); DetourAttach((LPVOID*)&v_Script_LoadRson, &Script_LoadRson); DetourAttach((LPVOID*)&v_Script_LoadScript, &Script_LoadScript); } @@ -343,6 +355,7 @@ void SQScript_Detach() DetourDetach((LPVOID*)&v_Script_CreateClientVM, &Script_CreateClientVM); DetourDetach((LPVOID*)&v_Script_CreateUIVM, &Script_CreateUIVM); #endif // !DEDICATED + DetourDetach((LPVOID*)&v_Script_DestroySignalEntryListHead, &Script_DestroySignalEntryListHead); DetourDetach((LPVOID*)&v_Script_LoadRson, &Script_LoadRson); DetourDetach((LPVOID*)&v_Script_LoadScript, &Script_LoadScript); } diff --git a/r5dev/squirrel/sqscript.h b/r5dev/squirrel/sqscript.h index 2cb8c933..8e107502 100644 --- a/r5dev/squirrel/sqscript.h +++ b/r5dev/squirrel/sqscript.h @@ -89,6 +89,9 @@ inline auto v_Script_CreateClientVM = p_Script_CreateClientVM.RCast(); #endif // !DEDICATED +inline CMemory p_Script_DestroySignalEntryListHead; +inline auto v_Script_DestroySignalEntryListHead = p_Script_DestroySignalEntryListHead.RCast(); + inline CMemory p_Script_LoadRson; inline auto v_Script_LoadRson = p_Script_LoadRson.RCast(); @@ -147,6 +150,7 @@ class VSquirrelVM : public IDetour spdlog::debug("| FUN: Script_CreateClientVM : {:#18x} |\n", p_Script_CreateClientVM.GetPtr()); spdlog::debug("| FUN: Script_CreateUIVM : {:#18x} |\n", p_Script_CreateUIVM.GetPtr()); #endif // !DEDICATED + spdlog::debug("| FUN: Script_DestroySignalEntryListHead : {:#18x} |\n", p_Script_DestroySignalEntryListHead.GetPtr()); spdlog::debug("| FUN: Script_LoadRson : {:#18x} |\n", p_Script_LoadRson.GetPtr()); spdlog::debug("| FUN: Script_LoadScript : {:#18x} |\n", p_Script_LoadScript.GetPtr()); #ifndef CLIENT_DLL @@ -181,29 +185,31 @@ class VSquirrelVM : public IDetour #if !defined (DEDICATED) p_Script_CreateUIVM = g_GameDll.FindPatternSIMD(reinterpret_cast("\x40\x53\x48\x83\xEC\x20\x48\x8B\x1D\x00\x00\x00\x00\xC6\x05\x00\x00\x00\x00\x00"), "xxxxxxxxx????xx?????"); #endif // !DEDICATED + p_Script_DestroySignalEntryListHead = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x56\x57\x41\x56\x48\x83\xEC\x50\x44\x8B\x42\x78"), "xxxx?xxxx?xxxxxxxxxxxx"); p_Script_LoadRson = g_GameDll.FindPatternSIMD(reinterpret_cast("\x4C\x8B\xDC\x49\x89\x5B\x08\x57\x48\x81\xEC\xA0\x00\x00\x00\x33"), "xxxxxxxxxxxxxxxx"); #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) p_Script_LoadScript = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C"), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) p_Script_LoadScript = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x8B\xC4\x48\x89\x48\x08\x55\x41\x56\x48\x8D\x68"), "xxxxxxxxxxxxx"); #endif - v_Script_RegisterConstant = p_Script_RegisterConstant.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 4C 8B*/ - v_Script_RegisterFunction = p_Script_RegisterFunction.RCast(); /*48 83 EC 38 45 0F B6 C8*/ + v_Script_RegisterConstant = p_Script_RegisterConstant.RCast(); /*48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 4C 8B*/ + v_Script_RegisterFunction = p_Script_RegisterFunction.RCast(); /*48 83 EC 38 45 0F B6 C8*/ #if !defined (CLIENT_DLL) - v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); /*48 89 74 24 ?? 57 48 83 EC 30 48 8B 3D ?? ?? ?? ?? 48 8B F1*/ + v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); /*48 89 74 24 ?? 57 48 83 EC 30 48 8B 3D ?? ?? ?? ?? 48 8B F1*/ #endif // !CLIENT_DLL #if !defined (DEDICATED) - v_Script_InitializeCLGlobalStructs = p_Script_InitializeCLGlobalStructs.RCast(); /*48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 48 63 C2 48 8D 3D ?? ?? ?? ??*/ + v_Script_InitializeCLGlobalStructs = p_Script_InitializeCLGlobalStructs.RCast(); /*48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 48 63 C2 48 8D 3D ?? ?? ?? ??*/ #endif // !DEDICATED #if !defined (CLIENT_DLL) - v_Script_CreateServerVM = p_Script_CreateServerVM.RCast(); /*40 53 56 48 83 EC 48 48 8D 0D ?? ?? ?? ??*/ + v_Script_CreateServerVM = p_Script_CreateServerVM.RCast(); /*40 53 56 48 83 EC 48 48 8D 0D ?? ?? ?? ??*/ #endif // !CLIENT_DLL #if !defined (DEDICATED) - v_Script_CreateClientVM = p_Script_CreateClientVM.RCast(); /*40 53 41 57 48 83 EC 68 48 83 3D ?? ?? ?? ?? ??*/ - v_Script_CreateUIVM = p_Script_CreateUIVM.RCast(); /*40 53 48 83 EC 20 48 8B 1D ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ??*/ + v_Script_CreateClientVM = p_Script_CreateClientVM.RCast(); /*40 53 41 57 48 83 EC 68 48 83 3D ?? ?? ?? ?? ??*/ + v_Script_CreateUIVM = p_Script_CreateUIVM.RCast(); /*40 53 48 83 EC 20 48 8B 1D ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ??*/ #endif // !DEDICATED - v_Script_LoadRson = p_Script_LoadRson.RCast(); /*4C 8B DC 49 89 5B 08 57 48 81 EC A0 00 00 00 33*/ - v_Script_LoadScript = p_Script_LoadScript.RCast(); /*48 8B C4 48 89 48 08 55 41 56 48 8D 68*/ + v_Script_DestroySignalEntryListHead = p_Script_DestroySignalEntryListHead.RCast();/*48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 50 44 8B 42*/ + v_Script_LoadRson = p_Script_LoadRson.RCast(); /*4C 8B DC 49 89 5B 08 57 48 81 EC A0 00 00 00 33*/ + v_Script_LoadScript = p_Script_LoadScript.RCast(); /*48 8B C4 48 89 48 08 55 41 56 48 8D 68*/ } virtual void GetVar(void) const { From 7818385fa08486e623a893fd98e179b28b660296 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 16:26:55 +0200 Subject: [PATCH 29/39] Improve naming convention in sqcript.h/cpp Use Squirrel's naming convention. --- r5dev/squirrel/sqscript.cpp | 172 ++++++++++++++++++------------------ r5dev/squirrel/sqscript.h | 64 +++++++------- 2 files changed, 118 insertions(+), 118 deletions(-) diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index 1677fea6..6d07cfbc 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -12,27 +12,27 @@ //--------------------------------------------------------------------------------- // Purpose: registers and exposes code functions to target context -// Input : *pSquirrelVM - -// *szName - -// *szHelpString - -// *szRetValType - -// *szArgTypes - -// *pFunction - +// Input : *s - +// *scriptname - +// *nativename - +// *helpstring - +// *returntype - +// *arguments - +// *functor - //--------------------------------------------------------------------------------- -SQRESULT Script_RegisterFunction(CSquirrelVM* pSquirrelVM, const SQChar* szScriptName,const SQChar* szNativeName, - const SQChar* szHelpString, const SQChar* szRetValType, const SQChar* szArgTypes, void* pFunction) +SQRESULT Script_RegisterFunction(CSquirrelVM* s, const SQChar* scriptname, const SQChar* nativename, + const SQChar* helpstring, const SQChar* returntype, const SQChar* parameters, void* functor) { - ScriptFunctionBinding_t* sqFunc = new ScriptFunctionBinding_t(); + ScriptFunctionBinding_t* binding = MemAllocSingleton()->Alloc(sizeof(ScriptFunctionBinding_t)); + binding->_scriptname = scriptname; + binding->_nativename = nativename; + binding->_helpstring = helpstring; + binding->_returntype = returntype; + binding->_parameters = parameters; + binding->_functor = functor; - sqFunc->m_szScriptName = szScriptName; - sqFunc->m_szNativeName = szNativeName; - sqFunc->m_szHelpString = szHelpString; - sqFunc->m_szRetValType = szRetValType; - sqFunc->m_szArgTypes = szArgTypes; - sqFunc->m_pFunction = pFunction; - - SQRESULT results = v_Script_RegisterFunction(pSquirrelVM, sqFunc, 1); - delete sqFunc; + SQRESULT results = v_Script_RegisterFunction(s, binding, 1); + MemAllocSingleton()->Free(binding); return results; } @@ -40,105 +40,105 @@ SQRESULT Script_RegisterFunction(CSquirrelVM* pSquirrelVM, const SQChar* szScrip #ifndef CLIENT_DLL //--------------------------------------------------------------------------------- // Purpose: registers script functions in SERVER context -// Input : *pSquirrelVM - +// Input : *s - //--------------------------------------------------------------------------------- -void Script_RegisterServerFunctions(CSquirrelVM* pSquirrelVM) +void Script_RegisterServerFunctions(CSquirrelVM* s) { - Script_RegisterFunction(pSquirrelVM, "SDKNativeTest", "Script_SDKNativeTest", "Native SERVER test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); - Script_RegisterFunction(pSquirrelVM, "GetSDKVersion", "Script_GetSDKVersion", "Gets the SDK version as a string", "string", "", &VSquirrel::SHARED::GetSDKVersion); + Script_RegisterFunction(s, "SDKNativeTest", "Script_SDKNativeTest", "Native SERVER test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); + Script_RegisterFunction(s, "GetSDKVersion", "Script_GetSDKVersion", "Gets the SDK version as a string", "string", "", &VSquirrel::SHARED::GetSDKVersion); - Script_RegisterFunction(pSquirrelVM, "GetNumHumanPlayers", "Script_GetNumHumanPlayers", "Gets the number of human players on the server", "int", "", &VSquirrel::SERVER::GetNumHumanPlayers); - Script_RegisterFunction(pSquirrelVM, "GetNumFakeClients", "Script_GetNumFakeClients", "Gets the number of bot players on the server", "int", "", &VSquirrel::SERVER::GetNumFakeClients); + Script_RegisterFunction(s, "GetNumHumanPlayers", "Script_GetNumHumanPlayers", "Gets the number of human players on the server", "int", "", &VSquirrel::SERVER::GetNumHumanPlayers); + Script_RegisterFunction(s, "GetNumFakeClients", "Script_GetNumFakeClients", "Gets the number of bot players on the server", "int", "", &VSquirrel::SERVER::GetNumFakeClients); - Script_RegisterFunction(pSquirrelVM, "GetAvailableMaps", "Script_GetAvailableMaps", "Gets an array of all available maps", "array< string >", "", &VSquirrel::SHARED::GetAvailableMaps); - Script_RegisterFunction(pSquirrelVM, "GetAvailablePlaylists", "Script_GetAvailablePlaylists", "Gets an array of all available playlists", "array< string >", "", &VSquirrel::SHARED::GetAvailablePlaylists); + Script_RegisterFunction(s, "GetAvailableMaps", "Script_GetAvailableMaps", "Gets an array of all available maps", "array< string >", "", &VSquirrel::SHARED::GetAvailableMaps); + Script_RegisterFunction(s, "GetAvailablePlaylists", "Script_GetAvailablePlaylists", "Gets an array of all available playlists", "array< string >", "", &VSquirrel::SHARED::GetAvailablePlaylists); - Script_RegisterFunction(pSquirrelVM, "KickPlayerByName", "Script_KickPlayerByName", "Kicks a player from the server by name", "void", "string", &VSquirrel::SHARED::KickPlayerByName); - Script_RegisterFunction(pSquirrelVM, "KickPlayerById", "Script_KickPlayerById", "Kicks a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::KickPlayerById); + Script_RegisterFunction(s, "KickPlayerByName", "Script_KickPlayerByName", "Kicks a player from the server by name", "void", "string", &VSquirrel::SHARED::KickPlayerByName); + Script_RegisterFunction(s, "KickPlayerById", "Script_KickPlayerById", "Kicks a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::KickPlayerById); - Script_RegisterFunction(pSquirrelVM, "BanPlayerByName", "Script_BanPlayerByName", "Bans a player from the server by name", "void", "string", &VSquirrel::SHARED::BanPlayerByName); - Script_RegisterFunction(pSquirrelVM, "BanPlayerById", "Script_BanPlayerById", "Bans a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::BanPlayerById); + Script_RegisterFunction(s, "BanPlayerByName", "Script_BanPlayerByName", "Bans a player from the server by name", "void", "string", &VSquirrel::SHARED::BanPlayerByName); + Script_RegisterFunction(s, "BanPlayerById", "Script_BanPlayerById", "Bans a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::BanPlayerById); - Script_RegisterFunction(pSquirrelVM, "UnbanPlayer", "Script_UnbanPlayer", "Unbans a player from the server by nucleus id or ip address", "void", "string", &VSquirrel::SHARED::UnbanPlayer); + Script_RegisterFunction(s, "UnbanPlayer", "Script_UnbanPlayer", "Unbans a player from the server by nucleus id or ip address", "void", "string", &VSquirrel::SHARED::UnbanPlayer); - Script_RegisterFunction(pSquirrelVM, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); + Script_RegisterFunction(s, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); } #endif // !CLIENT_DLL #ifndef DEDICATED //--------------------------------------------------------------------------------- // Purpose: registers script functions in CLIENT context -// Input : *pSquirrelVM - +// Input : *s - //--------------------------------------------------------------------------------- -void Script_RegisterClientFunctions(CSquirrelVM* pSquirrelVM) +void Script_RegisterClientFunctions(CSquirrelVM* s) { - Script_RegisterFunction(pSquirrelVM, "SDKNativeTest", "Script_SDKNativeTest", "Native CLIENT test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); - Script_RegisterFunction(pSquirrelVM, "GetSDKVersion", "Script_GetSDKVersion", "Gets the SDK version as a string", "string", "", &VSquirrel::SHARED::GetSDKVersion); + Script_RegisterFunction(s, "SDKNativeTest", "Script_SDKNativeTest", "Native CLIENT test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); + Script_RegisterFunction(s, "GetSDKVersion", "Script_GetSDKVersion", "Gets the SDK version as a string", "string", "", &VSquirrel::SHARED::GetSDKVersion); - Script_RegisterFunction(pSquirrelVM, "GetAvailableMaps", "Script_GetAvailableMaps", "Gets an array of all available maps", "array< string >", "", &VSquirrel::SHARED::GetAvailableMaps); - Script_RegisterFunction(pSquirrelVM, "GetAvailablePlaylists", "Script_GetAvailablePlaylists", "Gets an array of all available playlists", "array< string >", "", &VSquirrel::SHARED::GetAvailablePlaylists); + Script_RegisterFunction(s, "GetAvailableMaps", "Script_GetAvailableMaps", "Gets an array of all available maps", "array< string >", "", &VSquirrel::SHARED::GetAvailableMaps); + Script_RegisterFunction(s, "GetAvailablePlaylists", "Script_GetAvailablePlaylists", "Gets an array of all available playlists", "array< string >", "", &VSquirrel::SHARED::GetAvailablePlaylists); - Script_RegisterFunction(pSquirrelVM, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); + Script_RegisterFunction(s, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); } //--------------------------------------------------------------------------------- // Purpose: registers script functions in UI context -// Input : *pSquirrelVM - +// Input : *s - //--------------------------------------------------------------------------------- -void Script_RegisterUIFunctions(CSquirrelVM* pSquirrelVM) +void Script_RegisterUIFunctions(CSquirrelVM* s) { - Script_RegisterFunction(pSquirrelVM, "SDKNativeTest", "Script_SDKNativeTest", "Native UI test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); + Script_RegisterFunction(s, "SDKNativeTest", "Script_SDKNativeTest", "Native UI test function", "void", "", &VSquirrel::SHARED::SDKNativeTest); - Script_RegisterFunction(pSquirrelVM, "RefreshServerList", "Script_RefreshServerList", "Refreshes the public server list and returns the count", "int", "", &VSquirrel::UI::RefreshServerCount); + Script_RegisterFunction(s, "RefreshServerList", "Script_RefreshServerList", "Refreshes the public server list and returns the count", "int", "", &VSquirrel::UI::RefreshServerCount); // Functions for retrieving server browser data - Script_RegisterFunction(pSquirrelVM, "GetServerName", "Script_GetServerName", "Gets the name of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerName); - Script_RegisterFunction(pSquirrelVM, "GetServerDescription", "Script_GetServerDescription", "Gets the description of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerDescription); - Script_RegisterFunction(pSquirrelVM, "GetServerMap", "Script_GetServerMap", "Gets the map of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerMap); - Script_RegisterFunction(pSquirrelVM, "GetServerPlaylist", "Script_GetServerPlaylist", "Gets the playlist of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerPlaylist); - Script_RegisterFunction(pSquirrelVM, "GetServerCurrentPlayers", "Script_GetServerCurrentPlayers", "Gets the current player count of the server at the specified index of the server list", "int", "int", &VSquirrel::UI::GetServerCurrentPlayers); - Script_RegisterFunction(pSquirrelVM, "GetServerMaxPlayers", "Script_GetServerMaxPlayers", "Gets the max player count of the server at the specified index of the server list", "int", "int", &VSquirrel::UI::GetServerMaxPlayers); - Script_RegisterFunction(pSquirrelVM, "GetServerCount", "Script_GetServerCount", "Gets the number of public servers", "int", "", &VSquirrel::UI::GetServerCount); + Script_RegisterFunction(s, "GetServerName", "Script_GetServerName", "Gets the name of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerName); + Script_RegisterFunction(s, "GetServerDescription", "Script_GetServerDescription", "Gets the description of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerDescription); + Script_RegisterFunction(s, "GetServerMap", "Script_GetServerMap", "Gets the map of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerMap); + Script_RegisterFunction(s, "GetServerPlaylist", "Script_GetServerPlaylist", "Gets the playlist of the server at the specified index of the server list", "string", "int", &VSquirrel::UI::GetServerPlaylist); + Script_RegisterFunction(s, "GetServerCurrentPlayers", "Script_GetServerCurrentPlayers", "Gets the current player count of the server at the specified index of the server list", "int", "int", &VSquirrel::UI::GetServerCurrentPlayers); + Script_RegisterFunction(s, "GetServerMaxPlayers", "Script_GetServerMaxPlayers", "Gets the max player count of the server at the specified index of the server list", "int", "int", &VSquirrel::UI::GetServerMaxPlayers); + Script_RegisterFunction(s, "GetServerCount", "Script_GetServerCount", "Gets the number of public servers", "int", "", &VSquirrel::UI::GetServerCount); // Misc main menu functions - Script_RegisterFunction(pSquirrelVM, "GetSDKVersion", "Script_GetSDKVersion", "Gets the SDK version as a string", "string", "", &VSquirrel::SHARED::GetSDKVersion); - Script_RegisterFunction(pSquirrelVM, "GetPromoData", "Script_GetPromoData", "Gets promo data for specified slot type", "string", "int", &VSquirrel::UI::GetPromoData); + Script_RegisterFunction(s, "GetSDKVersion", "Script_GetSDKVersion", "Gets the SDK version as a string", "string", "", &VSquirrel::SHARED::GetSDKVersion); + Script_RegisterFunction(s, "GetPromoData", "Script_GetPromoData", "Gets promo data for specified slot type", "string", "int", &VSquirrel::UI::GetPromoData); // Functions for connecting to servers - Script_RegisterFunction(pSquirrelVM, "CreateServer", "Script_CreateServer", "Start server with the specified settings", "void", "string, string, string, string, int", &VSquirrel::UI::CreateServerFromMenu); - Script_RegisterFunction(pSquirrelVM, "SetEncKeyAndConnect", "Script_SetEncKeyAndConnect", "Set the encryption key to that of the specified server and connects to it", "void", "int", &VSquirrel::UI::SetEncKeyAndConnect); - Script_RegisterFunction(pSquirrelVM, "JoinPrivateServerFromMenu", "Script_JoinPrivateServerFromMenu", "Joins private server by token", "void", "string", &VSquirrel::UI::JoinPrivateServerFromMenu); - Script_RegisterFunction(pSquirrelVM, "GetPrivateServerMessage", "Script_GetPrivateServerMessage", "Gets private server join status message", "string", "string", &VSquirrel::UI::GetPrivateServerMessage); - Script_RegisterFunction(pSquirrelVM, "ConnectToIPFromMenu", "Script_ConnectToIPFromMenu", "Joins server by ip address and encryption key", "void", "string, string", &VSquirrel::UI::ConnectToIPFromMenu); + Script_RegisterFunction(s, "CreateServer", "Script_CreateServer", "Start server with the specified settings", "void", "string, string, string, string, int", &VSquirrel::UI::CreateServerFromMenu); + Script_RegisterFunction(s, "SetEncKeyAndConnect", "Script_SetEncKeyAndConnect", "Set the encryption key to that of the specified server and connects to it", "void", "int", &VSquirrel::UI::SetEncKeyAndConnect); + Script_RegisterFunction(s, "JoinPrivateServerFromMenu", "Script_JoinPrivateServerFromMenu", "Joins private server by token", "void", "string", &VSquirrel::UI::JoinPrivateServerFromMenu); + Script_RegisterFunction(s, "GetPrivateServerMessage", "Script_GetPrivateServerMessage", "Gets private server join status message", "string", "string", &VSquirrel::UI::GetPrivateServerMessage); + Script_RegisterFunction(s, "ConnectToIPFromMenu", "Script_ConnectToIPFromMenu", "Joins server by ip address and encryption key", "void", "string, string", &VSquirrel::UI::ConnectToIPFromMenu); - Script_RegisterFunction(pSquirrelVM, "GetAvailableMaps", "Script_GetAvailableMaps", "Gets an array of all available maps", "array< string >", "", &VSquirrel::SHARED::GetAvailableMaps); - Script_RegisterFunction(pSquirrelVM, "GetAvailablePlaylists", "Script_GetAvailablePlaylists", "Gets an array of all available playlists", "array< string >", "", &VSquirrel::SHARED::GetAvailablePlaylists); + Script_RegisterFunction(s, "GetAvailableMaps", "Script_GetAvailableMaps", "Gets an array of all available maps", "array< string >", "", &VSquirrel::SHARED::GetAvailableMaps); + Script_RegisterFunction(s, "GetAvailablePlaylists", "Script_GetAvailablePlaylists", "Gets an array of all available playlists", "array< string >", "", &VSquirrel::SHARED::GetAvailablePlaylists); #ifndef CLIENT_DLL - Script_RegisterFunction(pSquirrelVM, "KickPlayerByName", "Script_KickPlayerByName", "Kicks a player from the server by name", "void", "string", &VSquirrel::SHARED::KickPlayerByName); - Script_RegisterFunction(pSquirrelVM, "KickPlayerById", "Script_KickPlayerById", "Kicks a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::KickPlayerById); + Script_RegisterFunction(s, "KickPlayerByName", "Script_KickPlayerByName", "Kicks a player from the server by name", "void", "string", &VSquirrel::SHARED::KickPlayerByName); + Script_RegisterFunction(s, "KickPlayerById", "Script_KickPlayerById", "Kicks a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::KickPlayerById); - Script_RegisterFunction(pSquirrelVM, "BanPlayerByName", "Script_BanPlayerByName", "Bans a player from the server by name", "void", "string", &VSquirrel::SHARED::BanPlayerByName); - Script_RegisterFunction(pSquirrelVM, "BanPlayerById", "Script_BanPlayerById", "Bans a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::BanPlayerById); + Script_RegisterFunction(s, "BanPlayerByName", "Script_BanPlayerByName", "Bans a player from the server by name", "void", "string", &VSquirrel::SHARED::BanPlayerByName); + Script_RegisterFunction(s, "BanPlayerById", "Script_BanPlayerById", "Bans a player from the server by handle or nucleus id", "void", "string", &VSquirrel::SHARED::BanPlayerById); - Script_RegisterFunction(pSquirrelVM, "UnbanPlayer", "Script_UnbanPlayer", "Unbans a player from the server by nucleus id or ip address", "void", "string", &VSquirrel::SHARED::UnbanPlayer); + Script_RegisterFunction(s, "UnbanPlayer", "Script_UnbanPlayer", "Unbans a player from the server by nucleus id or ip address", "void", "string", &VSquirrel::SHARED::UnbanPlayer); #endif // !CLIENT_DLL - Script_RegisterFunction(pSquirrelVM, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); + Script_RegisterFunction(s, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); } //--------------------------------------------------------------------------------- // Purpose: registers global constant for target context -// Input : *pSquirrelVM - +// Input : *v - // *name - -// val - +// value - //--------------------------------------------------------------------------------- -SQRESULT Script_RegisterConstant(CSquirrelVM* pSquirrelVM, const SQChar* name, SQInteger val) +SQRESULT Script_RegisterConstant(CSquirrelVM* s, const SQChar* name, SQInteger value) { - return v_Script_RegisterConstant(pSquirrelVM, name, val); + return v_Script_RegisterConstant(s, name, value); } //--------------------------------------------------------------------------------- // Purpose: Initialize all CLIENT/UI global structs and register SDK (CLIENT/UI) script functions -// Input : *pSquirrelVM - +// Input : *v - // context - (1 = CLIENT 2 = UI) //--------------------------------------------------------------------------------- SQRESULT Script_InitializeCLGlobalStructs(HSQUIRRELVM v, SQCONTEXT context) @@ -156,7 +156,7 @@ SQRESULT Script_InitializeCLGlobalStructs(HSQUIRRELVM v, SQCONTEXT context) #ifndef CLIENT_DLL //--------------------------------------------------------------------------------- // Purpose: Initialize all SERVER global structs and register SDK (SERVER) script functions -// Input : *pSquirrelVM - +// Input : *v - //--------------------------------------------------------------------------------- void Script_InitializeSVGlobalStructs(HSQUIRRELVM v) { @@ -182,12 +182,12 @@ SQBool Script_CreateServerVM() #ifndef DEDICATED //--------------------------------------------------------------------------------- // Purpose: Creates the CLIENT Squirrel VM -// Input : *pHlClient - +// Input : *hlClient - // Output : True on success, false on failure //--------------------------------------------------------------------------------- -SQBool Script_CreateClientVM(CHLClient* pHlClient) +SQBool Script_CreateClientVM(CHLClient* hlclient) { - SQBool results = v_Script_CreateClientVM(pHlClient); + SQBool results = v_Script_CreateClientVM(hlclient); if (results) DevMsg(eDLL_T::CLIENT, "Created CLIENT VM: '%p'\n", Script_GetContextObject(SQCONTEXT::CLIENT)); else @@ -252,31 +252,31 @@ SQBool Script_DestroySignalEntryListHead(CSquirrelVM* s, HSQUIRRELVM v, SQFloat // Purpose: prints the global include file the compiler loads for loading scripts // Input : *szRsonName - //--------------------------------------------------------------------------------- -SQInteger Script_LoadRson(const SQChar* szRsonName) +SQInteger Script_LoadRson(const SQChar* rsonfile) { if (sq_showrsonloading->GetBool()) { - DevMsg(eDLL_T::ENGINE, "Loading RSON: '%s'\n", szRsonName); + DevMsg(eDLL_T::ENGINE, "Loading RSON: '%s'\n", rsonfile); } - return v_Script_LoadRson(szRsonName); + return v_Script_LoadRson(rsonfile); } //--------------------------------------------------------------------------------- // Purpose: prints the scripts the compiler loads from global include to be compiled // Input : *v - -// *szScriptPath - -// *szScriptName - -// nFlag - +// *path - +// *name - +// flags - //--------------------------------------------------------------------------------- -SQBool Script_LoadScript(HSQUIRRELVM v, const SQChar* szScriptPath, const SQChar* szScriptName, SQInteger nFlag) +SQBool Script_LoadScript(HSQUIRRELVM v, const SQChar* path, const SQChar* name, SQInteger flags) { if (sq_showscriptloading->GetBool()) { - DevMsg(eDLL_T::ENGINE, "Loading script: '%s'\n", szScriptName); + DevMsg(eDLL_T::ENGINE, "Loading script: '%s'\n", name); } /////////////////////////////////////////////////////////////////////////////// - return v_Script_LoadScript(v, szScriptPath, szScriptName, nFlag); + return v_Script_LoadScript(v, path, name, flags); } //--------------------------------------------------------------------------------- @@ -297,14 +297,14 @@ void Script_Execute(const SQChar* code, const SQCONTEXT context) return; // Only run in main thread. } - CSquirrelVM* script = Script_GetContextObject(context); - if (!script) + CSquirrelVM* s = Script_GetContextObject(context); + if (!s) { Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script with no handle to VM\n", SQVM_GetContextName(context)); return; } - HSQUIRRELVM v = script->GetVM(); + HSQUIRRELVM v = s->GetVM(); if (!v) { Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script while VM isn't initialized\n", SQVM_GetContextName(context)); diff --git a/r5dev/squirrel/sqscript.h b/r5dev/squirrel/sqscript.h index 8e107502..3fadabcd 100644 --- a/r5dev/squirrel/sqscript.h +++ b/r5dev/squirrel/sqscript.h @@ -4,28 +4,28 @@ struct ScriptFunctionBinding_t { - const SQChar* m_szScriptName; // 00 - const SQChar* m_szNativeName; // 08 - const SQChar* m_szHelpString; // 10 - const SQChar* m_szRetValType; // 18 - const SQChar* m_szArgTypes; // 20 - std::int16_t unk28; // 28 - std::int16_t padding1; // 2A - std::int32_t unk2c; // 2C - std::int64_t unk30; // 30 - std::int32_t unk38; // 38 - std::int32_t padding2; // 3C - std::int64_t unk40; // 40 - std::int64_t unk48; // 48 - std::int64_t unk50; // 50 - std::int32_t unk58; // 58 - std::int32_t padding3; // 5C - void* m_pFunction; // 60 + const SQChar* _scriptname; // 00 + const SQChar* _nativename; // 08 + const SQChar* _helpstring; // 10 + const SQChar* _returntype; // 18 + const SQChar* _parameters; // 20 + std::int16_t unk28; // 28 + std::int16_t padding1; // 2A + std::int32_t unk2c; // 2C + std::int64_t unk30; // 30 + std::int32_t unk38; // 38 + SQInteger _nparamscheck; // 3C + std::int64_t unk40; // 40 + std::int64_t unk48; // 48 + std::int64_t unk50; // 50 + std::int32_t unk58; // 58 + std::int32_t padding3; // 5C + void* _functor; // 60 ScriptFunctionBinding_t() { memset(this, '\0', sizeof(ScriptFunctionBinding_t)); - this->padding2 = 6; + this->_nparamscheck = 6; } }; @@ -59,10 +59,10 @@ private: #pragma pack(pop) inline CMemory p_Script_RegisterFunction; -inline auto v_Script_RegisterFunction = p_Script_RegisterFunction.RCast(); +inline auto v_Script_RegisterFunction = p_Script_RegisterFunction.RCast(); inline CMemory p_Script_RegisterConstant; -inline auto v_Script_RegisterConstant = p_Script_RegisterConstant.RCast(); +inline auto v_Script_RegisterConstant = p_Script_RegisterConstant.RCast(); #if !defined (CLIENT_DLL) inline CMemory p_Script_InitializeSVGlobalStructs; inline auto v_Script_InitializeSVGlobalStructs = p_Script_InitializeSVGlobalStructs.RCast(); @@ -80,10 +80,10 @@ inline auto v_Script_CreateServerVM = p_Script_CreateServerVM.RCast(); +inline auto v_Script_CreateClientVM = p_Script_CreateClientVM.RCast(); #elif !defined (DEDICATED) && defined (GAMEDLL_S3) inline CMemory p_Script_CreateClientVM; -inline auto v_Script_CreateClientVM = p_Script_CreateClientVM.RCast(); +inline auto v_Script_CreateClientVM = p_Script_CreateClientVM.RCast(); #endif #if !defined (DEDICATED) inline CMemory p_Script_CreateUIVM; @@ -93,10 +93,10 @@ inline CMemory p_Script_DestroySignalEntryListHead; inline auto v_Script_DestroySignalEntryListHead = p_Script_DestroySignalEntryListHead.RCast(); inline CMemory p_Script_LoadRson; -inline auto v_Script_LoadRson = p_Script_LoadRson.RCast(); +inline auto v_Script_LoadRson = p_Script_LoadRson.RCast(); inline CMemory p_Script_LoadScript; -inline auto v_Script_LoadScript = p_Script_LoadScript.RCast(); +inline auto v_Script_LoadScript = p_Script_LoadScript.RCast(); #if !defined (CLIENT_DLL) inline CMemory g_pServerScript; @@ -106,12 +106,12 @@ inline CMemory g_pClientScript; inline CMemory g_pUIScript; #endif // !DEDICATED -SQRESULT Script_RegisterConstant(CSquirrelVM* pSquirrelVM, const SQChar* name, SQInteger val); -SQRESULT Script_RegisterFunction(CSquirrelVM* pSquirrelVM, const SQChar* szScriptName, const SQChar* szNativeName, - const SQChar* szHelpString, const SQChar* szRetValType, const SQChar* szArgTypes, void* pFunction); -void Script_RegisterServerFunctions(CSquirrelVM* pSquirrelVM); -void Script_RegisterClientFunctions(CSquirrelVM* pSquirrelVM); -void Script_RegisterUIFunctions(CSquirrelVM* pSquirrelVM); +SQRESULT Script_RegisterConstant(CSquirrelVM* s, const SQChar* name, SQInteger value); +SQRESULT Script_RegisterFunction(CSquirrelVM* s, const SQChar* scriptname, const SQChar* nativename, + const SQChar* helpstring, const SQChar* returntype, const SQChar* arguments, void* functor); +void Script_RegisterServerFunctions(CSquirrelVM* s); +void Script_RegisterClientFunctions(CSquirrelVM* s); +void Script_RegisterUIFunctions(CSquirrelVM* s); SQRESULT Script_InitializeCLGlobalStructs(HSQUIRRELVM v, SQCONTEXT context); void Script_InitializeSVGlobalStructs(HSQUIRRELVM v); @@ -123,8 +123,8 @@ SQBool Script_CreateClientVM(CHLClient* hlclient); SQBool Script_CreateUIVM(); CSquirrelVM* Script_GetContextObject(const SQCONTEXT context); -SQInteger Script_LoadRson(const SQChar* szRsonName); -SQBool Script_LoadScript(HSQUIRRELVM v, const SQChar* szScriptPath, const SQChar* szScriptName, SQInteger nFlag); +SQInteger Script_LoadRson(const SQChar* rsonfile); +SQBool Script_LoadScript(HSQUIRRELVM v, const SQChar* path, const SQChar* name, SQInteger flags); void Script_Execute(const SQChar* code, const SQCONTEXT context); From 4cda4371cb4f7a629cd7c36d4069bf0d381d5ba8 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 17:07:36 +0200 Subject: [PATCH 30/39] ScriptFunctionBinding_t: light cleanup and map out more fields --- r5dev/squirrel/sqscript.cpp | 5 ++++- r5dev/squirrel/sqscript.h | 23 +++++++++++++++++++---- r5dev/squirrel/sqtype.h | 1 + 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index 6d07cfbc..e492286e 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -21,15 +21,18 @@ // *functor - //--------------------------------------------------------------------------------- SQRESULT Script_RegisterFunction(CSquirrelVM* s, const SQChar* scriptname, const SQChar* nativename, - const SQChar* helpstring, const SQChar* returntype, const SQChar* parameters, void* functor) + const SQChar* helpstring, const SQChar* returntype, const SQChar* parameters, SQFunctor* functor) { ScriptFunctionBinding_t* binding = MemAllocSingleton()->Alloc(sizeof(ScriptFunctionBinding_t)); + memset(binding, '\0', sizeof(ScriptFunctionBinding_t)); + binding->_scriptname = scriptname; binding->_nativename = nativename; binding->_helpstring = helpstring; binding->_returntype = returntype; binding->_parameters = parameters; binding->_functor = functor; + binding->_nparamscheck = 5; SQRESULT results = v_Script_RegisterFunction(s, binding, 1); MemAllocSingleton()->Free(binding); diff --git a/r5dev/squirrel/sqscript.h b/r5dev/squirrel/sqscript.h index 3fadabcd..3204522f 100644 --- a/r5dev/squirrel/sqscript.h +++ b/r5dev/squirrel/sqscript.h @@ -12,7 +12,7 @@ struct ScriptFunctionBinding_t std::int16_t unk28; // 28 std::int16_t padding1; // 2A std::int32_t unk2c; // 2C - std::int64_t unk30; // 30 + const SQChar* _codehook; // 30 std::int32_t unk38; // 38 SQInteger _nparamscheck; // 3C std::int64_t unk40; // 40 @@ -20,12 +20,27 @@ struct ScriptFunctionBinding_t std::int64_t unk50; // 50 std::int32_t unk58; // 58 std::int32_t padding3; // 5C - void* _functor; // 60 + SQFunctor* _functor; // 60 ScriptFunctionBinding_t() { - memset(this, '\0', sizeof(ScriptFunctionBinding_t)); - this->_nparamscheck = 6; + _scriptname = nullptr; + _nativename = nullptr; + _helpstring = nullptr; + _returntype = nullptr; + _parameters = nullptr; + unk28 = 0; + padding1 = 0; + unk2c = 0; + _codehook = nullptr; + unk38 = 0; + _nparamscheck = 6; + unk40 = 0; + unk48 = 0; + unk50 = 0; + unk58 = 0; + padding3 = 0; + _functor = nullptr; } }; diff --git a/r5dev/squirrel/sqtype.h b/r5dev/squirrel/sqtype.h index dc580145..6a3f6291 100644 --- a/r5dev/squirrel/sqtype.h +++ b/r5dev/squirrel/sqtype.h @@ -18,6 +18,7 @@ typedef char SQChar; typedef float SQFloat; typedef long SQInteger; typedef unsigned long SQUnsignedInteger; +typedef void* SQFunctor; typedef SQUnsignedInteger SQBool; typedef SQInteger SQRESULT; From de2400f6a2de0ec2f0727649ad6f74fecfc5e700 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 17:08:20 +0200 Subject: [PATCH 31/39] Implement StrintCount utility Counts the number or delimiters found in a given string --- r5dev/public/utility/utility.cpp | 15 +++++++++++++++ r5dev/public/utility/utility.h | 1 + 2 files changed, 16 insertions(+) diff --git a/r5dev/public/utility/utility.cpp b/r5dev/public/utility/utility.cpp index 7fcf5683..6bfdde44 100644 --- a/r5dev/public/utility/utility.cpp +++ b/r5dev/public/utility/utility.cpp @@ -640,6 +640,21 @@ string StringUnescape(const string& svInput) return result; } +/////////////////////////////////////////////////////////////////////////////// +// For counting the number of delimiters in a given string. +size_t StringCount(const string& svInput, char cDelim) +{ + size_t result = 0; + for (size_t i = 0; i < svInput.size(); i++) + { + if (svInput[i] == cDelim) + { + result++; + } + } + return result; +} + /////////////////////////////////////////////////////////////////////////////// // For splitting a string into substrings by delimiter. vector StringSplit(string svInput, char cDelim, size_t nMax) diff --git a/r5dev/public/utility/utility.h b/r5dev/public/utility/utility.h index d6595544..24edebcd 100644 --- a/r5dev/public/utility/utility.h +++ b/r5dev/public/utility/utility.h @@ -48,6 +48,7 @@ bool StringReplace(string& svInput, const string& svFrom, const string& svTo); string StringReplaceC(const string& svInput, const string& svFrom, const string& svTo); string StringEscape(const string& svInput); string StringUnescape(const string& svInput); +size_t StringCount(const string& svInput, char cDelim); vector StringSplit(string svInput, char cDelim, size_t nMax = SIZE_MAX); ///////////////////////////////////////////////////////////////////////////// From 41083a732442b4c3deca676c979206a1d464242c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 17:13:05 +0200 Subject: [PATCH 32/39] Revert typedef --- r5dev/squirrel/sqscript.cpp | 2 +- r5dev/squirrel/sqscript.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index e492286e..b151d774 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -21,7 +21,7 @@ // *functor - //--------------------------------------------------------------------------------- SQRESULT Script_RegisterFunction(CSquirrelVM* s, const SQChar* scriptname, const SQChar* nativename, - const SQChar* helpstring, const SQChar* returntype, const SQChar* parameters, SQFunctor* functor) + const SQChar* helpstring, const SQChar* returntype, const SQChar* parameters, void* functor) { ScriptFunctionBinding_t* binding = MemAllocSingleton()->Alloc(sizeof(ScriptFunctionBinding_t)); memset(binding, '\0', sizeof(ScriptFunctionBinding_t)); diff --git a/r5dev/squirrel/sqscript.h b/r5dev/squirrel/sqscript.h index 3204522f..773d0637 100644 --- a/r5dev/squirrel/sqscript.h +++ b/r5dev/squirrel/sqscript.h @@ -20,7 +20,7 @@ struct ScriptFunctionBinding_t std::int64_t unk50; // 50 std::int32_t unk58; // 58 std::int32_t padding3; // 5C - SQFunctor* _functor; // 60 + void* _functor; // 60 ScriptFunctionBinding_t() { From d0b989be26ee70b1cf2ba1dfe2ade225d26a83a4 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 17:51:41 +0200 Subject: [PATCH 33/39] SQVM: fix undefined behavior when getting the error line Leave 1 byte for the null terminator. --- r5dev/squirrel/sqvm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/r5dev/squirrel/sqvm.cpp b/r5dev/squirrel/sqvm.cpp index 740db93d..8ff6fc08 100644 --- a/r5dev/squirrel/sqvm.cpp +++ b/r5dev/squirrel/sqvm.cpp @@ -319,7 +319,7 @@ void SQVM_CompileError(HSQUIRRELVM v, const SQChar* pszError, const SQChar* pszF context = SQVM_GetContextIndex(v); #endif - v_SQVM_GetErrorLine(pszFile, nLine, szContextBuf, sizeof(szContextBuf)); + v_SQVM_GetErrorLine(pszFile, nLine, szContextBuf, sizeof(szContextBuf) - 1); Error(static_cast(context), NO_ERROR, "%s SCRIPT COMPILE ERROR: %s\n", SQVM_GetContextName(context), pszError); Error(static_cast(context), NO_ERROR, " -> %s\n\n", szContextBuf); From bf16fc1a384a6775bde41745a0bd47a8aaa97d51 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 21:20:14 +0200 Subject: [PATCH 34/39] Fix dedicated.dll compile errors --- r5dev/squirrel/sqscript.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/r5dev/squirrel/sqscript.cpp b/r5dev/squirrel/sqscript.cpp index b151d774..5def95a8 100644 --- a/r5dev/squirrel/sqscript.cpp +++ b/r5dev/squirrel/sqscript.cpp @@ -10,6 +10,17 @@ #include "squirrel/sqinit.h" #include "squirrel/sqscript.h" +//--------------------------------------------------------------------------------- +// Purpose: registers global constant for target context +// Input : *v - +// *name - +// value - +//--------------------------------------------------------------------------------- +SQRESULT Script_RegisterConstant(CSquirrelVM* s, const SQChar* name, SQInteger value) +{ + return v_Script_RegisterConstant(s, name, value); +} + //--------------------------------------------------------------------------------- // Purpose: registers and exposes code functions to target context // Input : *s - @@ -128,17 +139,6 @@ void Script_RegisterUIFunctions(CSquirrelVM* s) Script_RegisterFunction(s, "ShutdownHostGame", "Script_ShutdownHostGame", "Shuts the local host game down", "void", "", &VSquirrel::SHARED::ShutdownHostGame); } -//--------------------------------------------------------------------------------- -// Purpose: registers global constant for target context -// Input : *v - -// *name - -// value - -//--------------------------------------------------------------------------------- -SQRESULT Script_RegisterConstant(CSquirrelVM* s, const SQChar* name, SQInteger value) -{ - return v_Script_RegisterConstant(s, name, value); -} - //--------------------------------------------------------------------------------- // Purpose: Initialize all CLIENT/UI global structs and register SDK (CLIENT/UI) script functions // Input : *v - From 484f3251d1cfa669d951e02a0b685a55925a10f6 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 21:20:37 +0200 Subject: [PATCH 35/39] Variable rename for readability --- r5dev/engine/client/client.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/r5dev/engine/client/client.cpp b/r5dev/engine/client/client.cpp index 0b76cdf5..a24c7192 100644 --- a/r5dev/engine/client/client.cpp +++ b/r5dev/engine/client/client.cpp @@ -307,9 +307,9 @@ bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg) #endif // !GAMEDLL_S0 || !GAMEDLL_S1 ServerPlayer_t* pSlot = &g_ServerPlayer[pClient_Adj->GetUserID()]; double flStartTime = Plat_FloatTime(); - int nCmdQuota = sv_quota_stringCmdsPerSecond->GetInt(); + int nCmdQuotaLimit = sv_quota_stringCmdsPerSecond->GetInt(); - if (!nCmdQuota) + if (!nCmdQuotaLimit) return true; if (flStartTime - pSlot->m_flStringCommandQuotaTimeStart >= 1.0) @@ -319,7 +319,7 @@ bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg) } ++pSlot->m_nStringCommandQuotaCount; - if (pSlot->m_nStringCommandQuotaCount > nCmdQuota) + if (pSlot->m_nStringCommandQuotaCount > nCmdQuotaLimit) { Warning(eDLL_T::SERVER, "Removing client '%s' from slot '%i' ('%llu' exceeded string command quota!)\n", pClient_Adj->GetNetChan()->GetAddress(), pClient_Adj->GetUserID(), pClient_Adj->GetNucleusID()); From 23eba316dfbd351b0be02eefcfe4e60b80c05845 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 21:37:58 +0200 Subject: [PATCH 36/39] Cmd: add rate limit logic for 'Cmd_ForwardToServer' If the client happens to exceed the quota by accident, the client will not be disconnected. This is a quality of life change. Client could still increase cl_quota_stringCmdsPerSecond to allow more submissions per second, or disabling the throttle entirely by setting cl_quota_stringCmdsPerSecond to 0. --- r5dev/tier1/IConVar.cpp | 1 + r5dev/tier1/cmd.cpp | 52 +++++++++++++++++++++++++++++++++++++++++ r5dev/tier1/cmd.h | 6 +++++ r5dev/tier1/cvar.cpp | 1 + r5dev/tier1/cvar.h | 1 + 5 files changed, 61 insertions(+) diff --git a/r5dev/tier1/IConVar.cpp b/r5dev/tier1/IConVar.cpp index cc685943..2d3c6093 100644 --- a/r5dev/tier1/IConVar.cpp +++ b/r5dev/tier1/IConVar.cpp @@ -123,6 +123,7 @@ void ConVar::Init(void) const // CLIENT | #ifndef DEDICATED cl_rcon_request_sendlogs = ConVar::Create("cl_rcon_request_sendlogs", "1" , FCVAR_RELEASE, "Request the rcon server to send console logs on connect.", false, 0.f, false, 0.f, nullptr, nullptr); + cl_quota_stringCmdsPerSecond = ConVar::Create("cl_quota_stringCmdsPerSecond", "16" , FCVAR_RELEASE, "How many string commands per second user is allowed to submit, 0 to allow all submissions.", true, 0.f, false, 0.f, nullptr, nullptr); cl_showhoststats = ConVar::Create("cl_showhoststats" , "0", FCVAR_DEVELOPMENTONLY, "Host speeds debug overlay.", false, 0.f, false, 0.f, nullptr, nullptr); cl_hoststats_invert_x = ConVar::Create("cl_hoststats_invert_x", "0", FCVAR_DEVELOPMENTONLY, "Inverts the X offset for host speeds debug overlay.", false, 0.f, false, 0.f, nullptr, nullptr); diff --git a/r5dev/tier1/cmd.cpp b/r5dev/tier1/cmd.cpp index 2b4d9c8a..6b6eb4f5 100644 --- a/r5dev/tier1/cmd.cpp +++ b/r5dev/tier1/cmd.cpp @@ -660,13 +660,65 @@ ECommandTarget_t Cbuf_GetCurrentPlayer(void) return ECommandTarget_t::CBUF_FIRST_PLAYER; } +//----------------------------------------------------------------------------- +// Purpose: Sends the entire command line over to the server +// Input : *args - +// Output : true on success, false otherwise +//----------------------------------------------------------------------------- +bool Cmd_ForwardToServer(const CCommand* args) +{ +#ifndef DEDICATED + // Client -> Server command throttling. + static double flForwardedCommandQuotaStartTime = -1; + static int nForwardedCommandQuotaCount = 0; + + // No command to forward. + if (args->ArgC() == 0) + return false; + + double flStartTime = Plat_FloatTime(); + int nCmdQuotaLimit = cl_quota_stringCmdsPerSecond->GetInt(); + const char* pszCmdString = nullptr; + + // Special case: "cmd whatever args..." is forwarded as "whatever args..."; + // in this case we strip "cmd" from the input. + if (Q_strcasecmp(args->Arg(0), "cmd") == 0) + pszCmdString = args->ArgS(); + else + pszCmdString = args->GetCommandString(); + + if (nCmdQuotaLimit) + { + if (flStartTime - flForwardedCommandQuotaStartTime >= 1.0) + { + flForwardedCommandQuotaStartTime = flStartTime; + nForwardedCommandQuotaCount = 0; + } + ++nForwardedCommandQuotaCount; + + if (nForwardedCommandQuotaCount > nCmdQuotaLimit) + { + // If we are over quota commands per second, dump this on the floor. + // If we spam the server with too many commands, it will kick us. + Warning(eDLL_T::CLIENT, "Command '%s' ignored (submission quota of '%d' per second exceeded!)\n", args->ArgS(), nCmdQuotaLimit); + return false; + } + } + return v_Cmd_ForwardToServer(args); +#else // !DEDICATED + return false; // Client only. +#endif // DEDICATED +} + /////////////////////////////////////////////////////////////////////////////// void ConCommand_Attach() { DetourAttach((LPVOID*)&ConCommandBase_IsFlagSet, &ConCommandBase::IsFlagSetInternal); + DetourAttach((LPVOID*)&v_Cmd_ForwardToServer, &Cmd_ForwardToServer); } void ConCommand_Detach() { DetourDetach((LPVOID*)&ConCommandBase_IsFlagSet, &ConCommandBase::IsFlagSetInternal); + DetourDetach((LPVOID*)&v_Cmd_ForwardToServer, &Cmd_ForwardToServer); } ConCommand* g_pConCommand = new ConCommand(); diff --git a/r5dev/tier1/cmd.h b/r5dev/tier1/cmd.h index dde9e316..c0041ae8 100644 --- a/r5dev/tier1/cmd.h +++ b/r5dev/tier1/cmd.h @@ -164,6 +164,9 @@ inline auto Cbuf_AddText = p_Cbuf_AddText.RCast(); +inline CMemory p_Cmd_ForwardToServer; +inline auto v_Cmd_ForwardToServer = p_Cmd_ForwardToServer.RCast(); + /* ==== CONCOMMAND ====================================================================================================================================================== */ inline CMemory p_ConCommandBase_IsFlagSet; inline auto ConCommandBase_IsFlagSet = p_ConCommandBase_IsFlagSet.RCast(); @@ -191,6 +194,7 @@ class VConCommand : public IDetour { spdlog::debug("| FUN: Cbuf_AddText : {:#18x} |\n", p_Cbuf_AddText.GetPtr()); spdlog::debug("| FUN: Cbuf_Execute : {:#18x} |\n", p_Cbuf_Execute.GetPtr()); + spdlog::debug("| FUN: Cmd_ForwardToServer : {:#18x} |\n", p_Cmd_ForwardToServer.GetPtr()); spdlog::debug("+----------------------------------------------------------------+\n"); spdlog::debug("| FUN: ConCommandBase::IsFlagSet : {:#18x} |\n", p_ConCommandBase_IsFlagSet.GetPtr()); spdlog::debug("+----------------------------------------------------------------+\n"); @@ -204,12 +208,14 @@ class VConCommand : public IDetour { p_Cbuf_AddText = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x20\x48\x63\xD9\x41\x8B\xF8\x48\x8D\x0D\x00\x00\x00\x00\x48\x8B\xF2\xFF\x15\x00\x00\x00\x00\x48\x8D\x05\x00\x00\x00\x00\x41\xB9\x00\x00\x00\x00"), "xxxx?xxxx?xxxxxxxxxxxxxx????xxxxx????xxx????xx????"); p_Cbuf_Execute = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x20\xFF\x15\x00\x00\x00\x00"), "xxxx?xxxx?xxxx?xxxxxxx????"); + p_Cmd_ForwardToServer = g_GameDll.FindPatternSIMD(reinterpret_cast("\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x81\xEC\x00\x00\x00\x00\x44\x8B\x59\x04"), "xxxx?xxxx?xxxx?xxxx????xxxx"); p_ConCommandBase_IsFlagSet = g_GameDll.FindPatternSIMD(reinterpret_cast("\x85\x51\x38\x0F\x95\xC0\xC3"), "xxxxxxx"); p_NullSub = g_GameDll.FindPatternSIMD(reinterpret_cast("\xC2\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x40\x53\x48\x83\xEC\x20\x48\x8D\x05\x00\x00\x00\x00"), "xxxxxxxxxxxxxxxxxxxxxxxxx????"); p_CallbackStub = g_GameDll.FindPatternSIMD(reinterpret_cast("\x33\xC0\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\x80\x49\x68\x08"), "xxxxxxxxxxxxxxxxxxxx"); 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_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*/ ConCommandBase_IsFlagSet = p_ConCommandBase_IsFlagSet.RCast(); /*85 51 38 0F 95 C0 C3*/ NullSub = p_NullSub.RCast(); /*C2 00 00 CC CC CC CC CC CC CC CC CC CC CC CC CC 40 53 48 83 EC 20 48 8D 05 ?? ?? ?? ??*/ CallbackStub = p_CallbackStub.RCast(); /*33 C0 C3 CC CC CC CC CC CC CC CC CC CC CC CC CC 80 49 68 08*/ /*UserMathErrorFunction*/ diff --git a/r5dev/tier1/cvar.cpp b/r5dev/tier1/cvar.cpp index 73921678..9c69c43a 100644 --- a/r5dev/tier1/cvar.cpp +++ b/r5dev/tier1/cvar.cpp @@ -93,6 +93,7 @@ ConVar* bhit_abs_origin = nullptr; // CLIENT | #ifndef DEDICATED ConVar* cl_rcon_request_sendlogs = nullptr; +ConVar* cl_quota_stringCmdsPerSecond = nullptr; ConVar* cl_showhoststats = nullptr; ConVar* cl_hoststats_invert_x = nullptr; diff --git a/r5dev/tier1/cvar.h b/r5dev/tier1/cvar.h index ae9be600..83a34c31 100644 --- a/r5dev/tier1/cvar.h +++ b/r5dev/tier1/cvar.h @@ -88,6 +88,7 @@ extern ConVar* bhit_abs_origin; // CLIENT | #ifndef DEDICATED extern ConVar* cl_rcon_request_sendlogs; +extern ConVar* cl_quota_stringCmdsPerSecond; extern ConVar* cl_showhoststats; extern ConVar* cl_hoststats_invert_x; From 5ce4af6ec6dbf38b770dd56284bbe46c77db2457 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 22:24:40 +0200 Subject: [PATCH 37/39] Update configuration files -dev is now removed from every prod cfg. -developer 1 is now removed from every prod cfg. --- r5dev/resource/cfg/autoexec.cfg | 1 - r5dev/resource/cfg/autoexec_client_dev.cfg | 1 + r5dev/resource/cfg/autoexec_dev.cfg | 2 +- r5dev/resource/cfg/startup_dedi_default.cfg | 1 - r5dev/resource/cfg/startup_dedi_dev.cfg | 2 +- r5dev/resource/cfg/startup_dedi_retail.cfg | 1 - r5dev/resource/cfg/startup_default.cfg | 1 - r5dev/resource/cfg/startup_launcher.cfg | 1 - r5dev/resource/cfg/startup_retail.cfg | 1 - 9 files changed, 3 insertions(+), 8 deletions(-) diff --git a/r5dev/resource/cfg/autoexec.cfg b/r5dev/resource/cfg/autoexec.cfg index f99c5a08..22a8f194 100644 --- a/r5dev/resource/cfg/autoexec.cfg +++ b/r5dev/resource/cfg/autoexec.cfg @@ -2,7 +2,6 @@ //// REPLICATED //// ////////////////////////// mp_allowed "1" // Whether multiplayer is allowed or not. -developer "1" // Required for certain script functionality. ////////////////////////// //// SQUIRREL //// diff --git a/r5dev/resource/cfg/autoexec_client_dev.cfg b/r5dev/resource/cfg/autoexec_client_dev.cfg index bd135be8..be9fa874 100644 --- a/r5dev/resource/cfg/autoexec_client_dev.cfg +++ b/r5dev/resource/cfg/autoexec_client_dev.cfg @@ -6,6 +6,7 @@ ////////////////////////// cl_noTimeoutLocalHost "1" // Do not time-out on local connections. cl_threaded_bone_setup "0" // Has to be disabled on the client to prevent deadlock. +cl_quota_stringCmdsPerSecond "256" // Max string commands submissions on the client. ////////////////////////// //// SIMULATION //// !!WARNING!!: CHANGING THESE CAN CAUSE SIMULATION ISSUES. DO NOT CHANGE FOR NON-DEBUG ACTIVITY! diff --git a/r5dev/resource/cfg/autoexec_dev.cfg b/r5dev/resource/cfg/autoexec_dev.cfg index 039d3a7e..f70e04ca 100644 --- a/r5dev/resource/cfg/autoexec_dev.cfg +++ b/r5dev/resource/cfg/autoexec_dev.cfg @@ -4,7 +4,7 @@ sv_cheats "1" // Allow cheats on the server. mp_allowed "1" // Whether multiplayer is allowed or not. bhit_enable "1" // Bullet trajectory debug. -developer "1" // Required for certain script functionality. +developer "1" // Required for DEVELOPER script. ////////////////////////// //// NETCHAN //// diff --git a/r5dev/resource/cfg/startup_dedi_default.cfg b/r5dev/resource/cfg/startup_dedi_default.cfg index 14137936..fe921edb 100644 --- a/r5dev/resource/cfg/startup_dedi_default.cfg +++ b/r5dev/resource/cfg/startup_dedi_default.cfg @@ -1,3 +1,2 @@ -ansiclr --dev -playlistfile "playlists_r5_patch.txt" diff --git a/r5dev/resource/cfg/startup_dedi_dev.cfg b/r5dev/resource/cfg/startup_dedi_dev.cfg index b9bd9826..6a3279ff 100644 --- a/r5dev/resource/cfg/startup_dedi_dev.cfg +++ b/r5dev/resource/cfg/startup_dedi_dev.cfg @@ -1,6 +1,6 @@ -ansiclr --notimeout -dev -devsdk +-notimeout -tools -playlistfile "playlists_r5_patch.txt" diff --git a/r5dev/resource/cfg/startup_dedi_retail.cfg b/r5dev/resource/cfg/startup_dedi_retail.cfg index 14137936..fe921edb 100644 --- a/r5dev/resource/cfg/startup_dedi_retail.cfg +++ b/r5dev/resource/cfg/startup_dedi_retail.cfg @@ -1,3 +1,2 @@ -ansiclr --dev -playlistfile "playlists_r5_patch.txt" diff --git a/r5dev/resource/cfg/startup_default.cfg b/r5dev/resource/cfg/startup_default.cfg index 17c52d3f..c38360ab 100644 --- a/r5dev/resource/cfg/startup_default.cfg +++ b/r5dev/resource/cfg/startup_default.cfg @@ -1,4 +1,3 @@ --dev -fnf -multiple -novid diff --git a/r5dev/resource/cfg/startup_launcher.cfg b/r5dev/resource/cfg/startup_launcher.cfg index 5ce162c4..49fd3d39 100644 --- a/r5dev/resource/cfg/startup_launcher.cfg +++ b/r5dev/resource/cfg/startup_launcher.cfg @@ -1,4 +1,3 @@ --dev -fnf -multiple -showdevmenu diff --git a/r5dev/resource/cfg/startup_retail.cfg b/r5dev/resource/cfg/startup_retail.cfg index f405522e..bcc89c5e 100644 --- a/r5dev/resource/cfg/startup_retail.cfg +++ b/r5dev/resource/cfg/startup_retail.cfg @@ -1,5 +1,4 @@ -ansiclr --dev -fnf -multiple -novid From 524962ac4472af6e36d70f638e9c454e85ba895f Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 22 Sep 2022 22:25:32 +0200 Subject: [PATCH 38/39] Pass -dev from the launcher Must be passed from the launcher, as this is removed from the configuration files for prod. Ticking the development box will pass '-dev' and '-devsdk'. --- r5dev/sdklauncher/basepanel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/r5dev/sdklauncher/basepanel.cpp b/r5dev/sdklauncher/basepanel.cpp index 11615640..22abf92a 100644 --- a/r5dev/sdklauncher/basepanel.cpp +++ b/r5dev/sdklauncher/basepanel.cpp @@ -739,6 +739,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters) } if (this->m_DevelopmentToggle->Checked()) { + svParameters.append("-dev\n"); svParameters.append("-devsdk\n"); results = eLaunchMode::LM_HOST_DEV; } @@ -864,6 +865,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters) } if (this->m_DevelopmentToggle->Checked()) { + svParameters.append("-dev\n"); svParameters.append("-devsdk\n"); results = eLaunchMode::LM_SERVER_DEV; } @@ -950,6 +952,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters) // GAME ############################################################### if (this->m_DevelopmentToggle->Checked()) { + svParameters.append("-dev\n"); svParameters.append("-devsdk\n"); results = eLaunchMode::LM_CLIENT_DEV; } From 422c9952d299cf7bc0174bc195e404fb194f10eb Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 23 Sep 2022 00:15:28 +0200 Subject: [PATCH 39/39] Force no net processing budget on development launch --- r5dev/resource/cfg/autoexec_dev.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/r5dev/resource/cfg/autoexec_dev.cfg b/r5dev/resource/cfg/autoexec_dev.cfg index f70e04ca..4e2e1d83 100644 --- a/r5dev/resource/cfg/autoexec_dev.cfg +++ b/r5dev/resource/cfg/autoexec_dev.cfg @@ -9,7 +9,8 @@ developer "1" // Required for DEVELOPER script. ////////////////////////// //// NETCHAN //// ////////////////////////// -net_userandomkey "0" // Whether to use the default netkey or a randomized key on launch. +net_useRandomKey "0" // Use a randomized netkey on launch. +net_processTimeBudget "0" // Net message process budget in milliseconds (removing netchannel if exceeded). net_usesocketsforloopback "1" // Whether to use network sockets layer for packets. //////////////////////////