From 53788d5ba58f106a7d702487709a221f2a8d7fc0 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Tue, 16 May 2023 00:44:59 +0200 Subject: [PATCH] Potential fix for intermittent crash during playlists reload This should fix a rare crash that happens when the playlists file is reloaded during disconnect. The client fetches the playlists from the server on connect. On disconnect, we want to reload the one from the client so that if the player want's to create his own game, that he would have his own playlists. The fix is to delay the reload of the playlists file to the beginning of the next frame. --- r5dev/engine/net.cpp | 33 +++------------------------------ r5dev/engine/net.h | 7 ------- r5dev/engine/net_chan.cpp | 34 +++++++++++++++++++++++++++++++--- r5dev/engine/net_chan.h | 19 +++++++++++++++---- 4 files changed, 49 insertions(+), 44 deletions(-) diff --git a/r5dev/engine/net.cpp b/r5dev/engine/net.cpp index ad54d607..b483cd08 100644 --- a/r5dev/engine/net.cpp +++ b/r5dev/engine/net.cpp @@ -7,11 +7,8 @@ #include "core/stdafx.h" #include "engine/net.h" #ifndef NETCONSOLE -#include "tier0/frametask.h" #include "tier1/cvar.h" -#include "vpc/keyvalues.h" #include "mathlib/color.h" -#include "common/callback.h" #include "net.h" #include "net_chan.h" #ifndef CLIENT_DLL @@ -160,24 +157,6 @@ void NET_PrintFunc(const char* fmt, ...) DevMsg(context, "%s", result.c_str()); } -//----------------------------------------------------------------------------- -// Purpose: shutdown netchannel -// Input : *this - -// *szReason - -// bBadRep - -// bRemoveNow - -//----------------------------------------------------------------------------- -void NET_Shutdown(void* thisptr, const char* szReason, uint8_t bBadRep, bool bRemoveNow) -{ -#ifndef DEDICATED - // Re-load playlist from the disk to replace the one we received from the server. - _DownloadPlaylists_f(); - KeyValues::InitPlaylists(); -#endif // !DEDICATED - - v_NET_Shutdown(thisptr, szReason, bBadRep, bRemoveNow); -} - //----------------------------------------------------------------------------- // Purpose: disconnect the client and shutdown netchannel // Input : *pClient - @@ -194,9 +173,9 @@ void NET_RemoveChannel(CClient* pClient, int nIndex, const char* szReason, uint8 return; } - v_NET_Shutdown(pClient->GetNetChan(), szReason, bBadRep, bRemoveNow); // Shutdown NetChannel. - pClient->Clear(); // Reset CClient instance for client. - g_ServerPlayer[nIndex].Reset(); // Reset ServerPlayer slot. + pClient->GetNetChan()->Shutdown(szReason, bBadRep, bRemoveNow); // Shutdown NetChannel. + pClient->Clear(); // Reset CClient slot. + g_ServerPlayer[nIndex].Reset(); // Reset ServerPlayer slot. #endif // !CLIENT_DLL } #endif // !NETCONSOLE @@ -312,9 +291,6 @@ void VNet::Attach() const DetourAttach((LPVOID*)&v_NET_SendDatagram, &NET_SendDatagram); DetourAttach((LPVOID*)&v_NET_Decompress, &NET_Decompress); DetourAttach((LPVOID*)&v_NET_PrintFunc, &NET_PrintFunc); -#ifndef DEDICATED - DetourAttach((LPVOID*)&v_NET_Shutdown, &NET_Shutdown); -#endif } void VNet::Detach() const @@ -324,9 +300,6 @@ void VNet::Detach() const DetourDetach((LPVOID*)&v_NET_SendDatagram, &NET_SendDatagram); DetourDetach((LPVOID*)&v_NET_Decompress, &NET_Decompress); DetourDetach((LPVOID*)&v_NET_PrintFunc, &NET_PrintFunc); -#ifndef DEDICATED - DetourDetach((LPVOID*)&v_NET_Shutdown, &NET_Shutdown); -#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/engine/net.h b/r5dev/engine/net.h index 016c98cd..31b8ec5e 100644 --- a/r5dev/engine/net.h +++ b/r5dev/engine/net.h @@ -22,9 +22,6 @@ constexpr const char* DEFAULT_NET_ENCRYPTION_KEY = "WDNWLmJYQ2ZlM0VoTid3Yg=="; inline CMemory p_NET_Init; inline auto v_NET_Init = p_NET_Init.RCast(); -inline CMemory p_NET_Shutdown; -inline auto v_NET_Shutdown = p_NET_Shutdown.RCast(); - inline CMemory p_NET_SetKey; inline auto v_NET_SetKey = p_NET_SetKey.RCast(); @@ -64,7 +61,6 @@ class VNet : public IDetour virtual void GetAdr(void) const { LogFunAdr("NET_Init", p_NET_Init.GetPtr()); - LogFunAdr("NET_Shutdown", p_NET_Shutdown.GetPtr()); LogFunAdr("NET_Config", p_NET_Config.GetPtr()); LogFunAdr("NET_SetKey", p_NET_SetKey.GetPtr()); LogFunAdr("NET_ReceiveDatagram", p_NET_ReceiveDatagram.GetPtr()); @@ -79,10 +75,8 @@ class VNet : public IDetour { #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2) p_NET_Init = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 81 EC C0 01 ??"); - p_NET_Shutdown = g_GameDll.FindPatternSIMD("48 89 6C 24 18 56 57 41 56 48 83 EC 30 83 B9 D8"); #elif defined (GAMEDLL_S3) p_NET_Init = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 81 EC F0 01 ??"); - p_NET_Shutdown = g_GameDll.FindPatternSIMD("48 89 6C 24 18 56 57 41 56 48 83 EC 30 83 B9 D0"); #endif p_NET_Config = g_GameDll.FindPatternSIMD("48 81 EC ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 0F 57 C0"); p_NET_SetKey = g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 41 B8"); @@ -92,7 +86,6 @@ class VNet : public IDetour p_NET_PrintFunc = g_GameDll.FindPatternSIMD("48 89 54 24 10 4C 89 44 24 18 4C 89 4C 24 20 C3 48"); v_NET_Init = p_NET_Init.RCast(); /*48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 81 EC F0 01 00*/ - v_NET_Shutdown = p_NET_Shutdown.RCast(); /*48 89 6C 24 18 56 57 41 56 48 83 EC 30 83 B9 D0*/ v_NET_Config = p_NET_Config.RCast(); v_NET_SetKey = p_NET_SetKey.RCast(); /*48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 41 B8*/ v_NET_ReceiveDatagram = p_NET_ReceiveDatagram.RCast(); /*E8 ?? ?? ?? ?? 84 C0 75 35 48 8B D3*/ diff --git a/r5dev/engine/net_chan.cpp b/r5dev/engine/net_chan.cpp index 2a1da999..2610f90b 100644 --- a/r5dev/engine/net_chan.cpp +++ b/r5dev/engine/net_chan.cpp @@ -5,7 +5,10 @@ //=============================================================================// #include "core/stdafx.h" +#include "tier0/frametask.h" #include "tier1/cvar.h" +#include "vpc/keyvalues.h" +#include "common/callback.h" #include "engine/net.h" #include "engine/net_chan.h" #ifndef CLIENT_DLL @@ -220,13 +223,36 @@ void CNetChan::Clear(bool bStopProcessing) v_NetChan_Clear(this, bStopProcessing); } +//----------------------------------------------------------------------------- +// Purpose: shutdown netchannel +// Input : *this - +// *szReason - +// bBadRep - +// bRemoveNow - +//----------------------------------------------------------------------------- +void CNetChan::_Shutdown(CNetChan* pChan, const char* szReason, uint8_t bBadRep, bool bRemoveNow) +{ + v_NetChan_Shutdown(pChan, szReason, bBadRep, bRemoveNow); + +#ifndef DEDICATED + // Delay execution to the next frame; this is required to avoid a rare crash. + // Cannot reload playlists while still disconnecting. + g_TaskScheduler->Dispatch([]() + { + // Re-load and re-init playlists from the disk to replace the cached one we received from the server. + _DownloadPlaylists_f(); + KeyValues::InitPlaylists(); + }, 0); +#endif // !DEDICATED +} + //----------------------------------------------------------------------------- // Purpose: process message // Input : *pChan - // *pMsg - // Output : true on success, false on failure //----------------------------------------------------------------------------- -bool CNetChan::ProcessMessages(CNetChan* pChan, bf_read* pMsg) +bool CNetChan::_ProcessMessages(CNetChan* pChan, bf_read* pMsg) { #ifndef CLIENT_DLL if (!ThreadInServerFrameThread() || !net_processTimeBudget->GetInt()) @@ -289,9 +315,11 @@ void CNetChan::SetRemoteCPUStatistics(uint8_t nStats) /////////////////////////////////////////////////////////////////////////////// void VNetChan::Attach() const { - DetourAttach(&v_NetChan_ProcessMessages, &CNetChan::ProcessMessages); + DetourAttach((PVOID*)&v_NetChan_Shutdown, &CNetChan::_Shutdown); + DetourAttach((PVOID*)&v_NetChan_ProcessMessages, &CNetChan::_ProcessMessages); } void VNetChan::Detach() const { - DetourDetach(&v_NetChan_ProcessMessages, &CNetChan::ProcessMessages); + DetourDetach((PVOID*)&v_NetChan_Shutdown, &CNetChan::_Shutdown); + DetourDetach((PVOID*)&v_NetChan_ProcessMessages, &CNetChan::_ProcessMessages); } diff --git a/r5dev/engine/net_chan.h b/r5dev/engine/net_chan.h index 2983f411..77e8b4cb 100644 --- a/r5dev/engine/net_chan.h +++ b/r5dev/engine/net_chan.h @@ -105,9 +105,13 @@ public: const netadr_t& GetRemoteAddress(void) const; bool IsOverflowed(void) const; - void Clear(bool bStopProcessing); - static bool ProcessMessages(CNetChan* pChan, bf_read* pMsg); + void Clear(bool bStopProcessing); + inline void Shutdown(const char* szReason, uint8_t bBadRep, bool bRemoveNow) + { _Shutdown(this, szReason, bBadRep, bRemoveNow); } + + static void _Shutdown(CNetChan* pChan, const char* szReason, uint8_t bBadRep, bool bRemoveNow); + static bool _ProcessMessages(CNetChan* pChan, bf_read* pMsg); void SetRemoteFramerate(float flFrameTime, float flFrameTimeStdDeviation); void SetRemoteCPUStatistics(uint8_t nStats); @@ -185,6 +189,9 @@ static_assert(sizeof(CNetChan) == 0x1AC8); inline CMemory p_NetChan_Clear; inline auto v_NetChan_Clear = p_NetChan_Clear.RCast(); +inline CMemory p_NetChan_Shutdown; +inline auto v_NetChan_Shutdown = p_NetChan_Shutdown.RCast(); + inline CMemory p_NetChan_ProcessMessages; inline auto v_NetChan_ProcessMessages = p_NetChan_ProcessMessages.RCast(); /////////////////////////////////////////////////////////////////////////////// @@ -193,15 +200,19 @@ class VNetChan : public IDetour virtual void GetAdr(void) const { LogFunAdr("CNetChan::Clear", p_NetChan_Clear.GetPtr()); + LogFunAdr("CNetChan::Shutdown", p_NetChan_Shutdown.GetPtr()); LogFunAdr("CNetChan::ProcessMessages", p_NetChan_ProcessMessages.GetPtr()); } virtual void GetFun(void) const { p_NetChan_Clear = g_GameDll.FindPatternSIMD("88 54 24 10 53 55 57"); - v_NetChan_Clear = p_NetChan_Clear.RCast(); /*88 54 24 10 53 55 57*/ + v_NetChan_Clear = p_NetChan_Clear.RCast(); + + p_NetChan_Shutdown = g_GameDll.FindPatternSIMD("48 89 6C 24 18 56 57 41 56 48 83 EC 30 83 B9"); + v_NetChan_Shutdown = p_NetChan_Shutdown.RCast(); p_NetChan_ProcessMessages = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B FA"); - v_NetChan_ProcessMessages = p_NetChan_ProcessMessages.RCast();/*48 89 5C 24 ?? 48 89 6C 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B FA*/ + v_NetChan_ProcessMessages = p_NetChan_ProcessMessages.RCast(); } virtual void GetVar(void) const { } virtual void GetCon(void) const { }