Implement frame tasks

Run all Cbuf_Execute calls in the main thread. This should fix every problem related to (but not only):
* Connecting to server while RUI dialogue is still open.
* Connecting to server while in an active game.
* Running 'weapon_reparse'.
This commit is contained in:
Kawe Mazidjatari 2022-08-19 21:33:31 +02:00
parent b14f239971
commit 6764b5e56e
18 changed files with 222 additions and 21 deletions

View File

@ -137,7 +137,7 @@ void Systems_Init()
initTimer.Start();
WS_Init(); // Initialize Winsock.
WinSock_Init(); // Initialize Winsock.
MathLib_Init(); // Initialize Mathlib.
// Begin the detour transaction to hook the the process
@ -174,6 +174,7 @@ void Systems_Init()
CServer_Attach(); // S1 and S2 CServer functions require work.
#endif // !CLIENT_DLL && GAMEDLL_S3
Host_Attach();
CHostState_Attach();
CModelBsp_Attach();
@ -260,7 +261,7 @@ void Systems_Shutdown()
shutdownTimer.Start();
// Shutdown Winsock system.
WS_Shutdown();
WinSock_Shutdown();
// Begin the detour transaction to unhook the the process
DetourTransactionBegin();
@ -296,6 +297,7 @@ void Systems_Shutdown()
CServer_Detach(); // S1 and S2 CServer functions require work.
#endif // !CLIENT_DLL && GAMEDLL_S3
Host_Detach();
CHostState_Detach();
CModelBsp_Detach();
@ -361,7 +363,7 @@ void Systems_Shutdown()
//
/////////////////////////////////////////////////////
void WS_Init()
void WinSock_Init()
{
WSAData wsaData{};
int nError = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
@ -370,7 +372,7 @@ void WS_Init()
std::cerr << "Failed to start Winsock via WSAStartup: (" << NET_ErrorString(WSAGetLastError()) << ")" << std::endl;
}
}
void WS_Shutdown()
void WinSock_Shutdown()
{
int nError = ::WSACleanup();
if (nError != 0)

View File

@ -11,8 +11,8 @@ void R5Dev_Shutdown();
void Systems_Init();
void Systems_Shutdown();
void WS_Init();
void WS_Shutdown();
void WinSock_Init();
void WinSock_Shutdown();
void QuerySystemInfo();
void DetourInit();

43
r5dev/engine/host.cpp Normal file
View File

@ -0,0 +1,43 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ========//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "core/stdafx.h"
#include "tier0/frametask.h"
#include "engine/host.h"
/*
==================
_Host_RunFrame
Runs all active servers
==================
*/
void _Host_RunFrame(void* unused, float time)
{
for (const auto& task : g_FrameTasks)
{
task->RunFrame();
}
g_FrameTasks.erase(std::remove_if(g_FrameTasks.begin(), g_FrameTasks.end(), [](const IFrameTask* task)
{
return task->IsFinished();
}), g_FrameTasks.end());
return v_Host_RunFrame(unused, time);
}
///////////////////////////////////////////////////////////////////////////////
void Host_Attach()
{
DetourAttach((LPVOID*)&v_Host_RunFrame, &_Host_RunFrame);
}
void Host_Detach()
{
DetourDetach((LPVOID*)&v_Host_RunFrame, &_Host_RunFrame);
}

View File

@ -1,22 +1,25 @@
#pragma once
inline CMemory p_Host_RunFrame;
inline auto _Host_RunFrame = p_Host_RunFrame.RCast<void(*)(void* unused, float time)>();
inline auto v_Host_RunFrame = p_Host_RunFrame.RCast<void(*)(void* unused, float time)>();
inline CMemory p_Host_RunFrame_Render;
inline auto _Host_RunFrame_Render = p_Host_RunFrame_Render.RCast<void(*)(void)>();
inline auto v_Host_RunFrame_Render = p_Host_RunFrame_Render.RCast<void(*)(void)>();
inline CMemory p_Host_Error;
inline auto Host_Error = p_Host_Error.RCast<int(*)(char* error, ...)>();
inline auto v_Host_Error = p_Host_Error.RCast<int(*)(char* error, ...)>();
inline CMemory p_VCR_EnterPausedState;
inline auto VCR_EnterPausedState = p_VCR_EnterPausedState.RCast<void(*)(void)>();
inline auto v_VCR_EnterPausedState = p_VCR_EnterPausedState.RCast<void(*)(void)>();
inline bool* g_bAbortServerSet = nullptr;
inline jmp_buf* host_abortserver = nullptr;
inline float* interval_per_tick = nullptr;
void Host_Attach();
void Host_Detach();
///////////////////////////////////////////////////////////////////////////////
class VHost : public IDetour
{
@ -42,10 +45,10 @@ class VHost : public IDetour
p_Host_Error = g_GameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x48\x89\x4C\x24\x00\x48\x89\x54\x24\x00\x4C\x89\x44\x24\x00\x4C\x89\x4C\x24\x00\x53\x57\x48\x81\xEC\x00\x00\x00\x00"), "xxxx?xxxx?xxxx?xxxx?xxxxx????");
p_VCR_EnterPausedState = g_GameDll.FindPatternSIMD(reinterpret_cast<rsig_t>("\x40\x53\x48\x83\xEC\x20\x65\x48\x8B\x04\x25\x00\x00\x00\x00\xBB\x00\x00\x00\x00\xC6\x05\x00\x00\x00\x00\x00"), "xxxxxxxxxxx????x????xx?????");
_Host_RunFrame = p_Host_RunFrame.RCast<void(*)(void*, float)>();
_Host_RunFrame_Render = p_Host_Error.RCast<void(*)(void)>();
Host_Error = p_Host_Error.RCast<int(*)(char*, ...)>();
VCR_EnterPausedState = p_VCR_EnterPausedState.RCast<void(*)(void)>();
v_Host_RunFrame = p_Host_RunFrame.RCast<void(*)(void*, float)>();
v_Host_RunFrame_Render = p_Host_Error.RCast<void(*)(void)>();
v_Host_Error = p_Host_Error.RCast<int(*)(char*, ...)>();
v_VCR_EnterPausedState = p_VCR_EnterPausedState.RCast<void(*)(void)>();
}
virtual void GetVar(void) const
{

View File

@ -14,6 +14,7 @@ History:
#include "core/stdafx.h"
#include "core/init.h"
#include "core/resource.h"
#include "tier0/frametask.h"
#include "tier0/commandline.h"
#include "tier1/IConVar.h"
#include "tier1/cvar.h"
@ -624,8 +625,7 @@ void CBrowser::SendHostingPostRequest(void)
void CBrowser::ProcessCommand(const char* pszCommand) const
{
Cbuf_AddText(Cbuf_GetCurrentPlayer(), pszCommand, cmd_source_t::kCommandSrcCode);
std::thread t(Cbuf_Execute);
t.detach(); // Detatch from render thread.
g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); // Run in main thread.
}
//-----------------------------------------------------------------------------

View File

@ -15,6 +15,7 @@ History:
#include "core/stdafx.h"
#include "core/init.h"
#include "core/resource.h"
#include "tier0/frametask.h"
#include "tier0/commandline.h"
#include "tier1/cvar.h"
#include "windows/id3dx.h"
@ -534,8 +535,7 @@ void CConsole::ProcessCommand(const char* pszCommand)
DevMsg(eDLL_T::COMMON, "] %s\n", pszCommand);
Cbuf_AddText(Cbuf_GetCurrentPlayer(), pszCommand, cmd_source_t::kCommandSrcCode);
std::thread t(Cbuf_Execute);
t.detach(); // Detatch from render thread.
g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); // Run in main thread.
m_nHistoryPos = -1;
for (size_t i = m_vHistory.size(); i-- > 0; )

View File

@ -5,6 +5,7 @@
//=============================================================================//
#include "core/stdafx.h"
#include "tier0/frametask.h"
#include "tier0/commandline.h"
#include "tier1/cvar.h"
#include "vpc/interfaces.h"
@ -80,7 +81,9 @@ bool CModAppSystemGroup::Create(CModAppSystemGroup* pModAppSystemGroup)
g_pHLClient = nullptr;
}
g_FrameTasks.push_back(std::move(g_DelayedCallTask));
g_bAppSystemInit = true;
return CModAppSystemGroup_Create(pModAppSystemGroup);
}

View File

@ -13,6 +13,7 @@
#include "vpc/keyvalues.h"
#include "pylon.h"
#include "listmanager.h"
#include <tier0/frametask.h>
//-----------------------------------------------------------------------------
// Purpose:
@ -89,8 +90,7 @@ void CServerListManager::ConnectToServer(const string& svServer, const string& s
void CServerListManager::ProcessCommand(const char* pszCommand) const
{
Cbuf_AddText(Cbuf_GetCurrentPlayer(), pszCommand, cmd_source_t::kCommandSrcCode);
std::thread t(Cbuf_Execute);
t.detach(); // Detatch from caller thread (would otherwise deadlock!).
g_DelayedCallTask->AddFunc(Cbuf_Execute, 0); // Run in main thread.
}
CServerListManager* g_pServerListManager = new CServerListManager();

23
r5dev/public/iframetask.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef TIER0_IFRAMETASK_H
#define TIER0_IFRAMETASK_H
struct DelayedCall_s
{
int m_nDelayedFrames;
std::function<void()> m_rFunctor;
DelayedCall_s(int frames, std::function<void()> functor)
{
m_nDelayedFrames = frames;
m_rFunctor = functor;
}
};
abstract_class IFrameTask
{
public:
virtual ~IFrameTask() {}
virtual void RunFrame() = 0;
virtual bool IsFinished() const = 0;
};
#endif // TIER0_IFRAMETASK_H

55
r5dev/tier0/frametask.cpp Normal file
View File

@ -0,0 +1,55 @@
//=============================================================================//
//
// Purpose:
//
//-----------------------------------------------------------------------------
//
//=============================================================================//
#include "core/stdafx.h"
#include "tier0/frametask.h"
//-----------------------------------------------------------------------------
// Purpose: run frame task and process queued calls
//-----------------------------------------------------------------------------
void CFrameTask::RunFrame()
{
std::lock_guard<std::mutex> l(m_Mutex);
for (auto& delay : m_DelayedCalls)
{
delay.m_nDelayedFrames = (std::max)(delay.m_nDelayedFrames - 1, 0);
if (delay.m_nDelayedFrames == 0)
{
delay.m_rFunctor();
}
}
auto newEnd = std::remove_if(m_DelayedCalls.begin(), m_DelayedCalls.end(), [](const DelayedCall_s& delay)
{
return delay.m_nDelayedFrames == 0;
});
m_DelayedCalls.erase(newEnd, m_DelayedCalls.end());
}
//-----------------------------------------------------------------------------
// Purpose: is the task finished
// Output : true if finished, false otherwise
//-----------------------------------------------------------------------------
bool CFrameTask::IsFinished() const
{
return false;
}
//-----------------------------------------------------------------------------
// Purpose: adds function to list, to be called after 'i' frames.
// Input : functor -
// frames -
//-----------------------------------------------------------------------------
void CFrameTask::AddFunc(std::function<void()> functor, int frames)
{
std::lock_guard<std::mutex> l(m_Mutex);
m_DelayedCalls.emplace_back(frames, functor);
}
//-----------------------------------------------------------------------------
std::list<IFrameTask*> g_FrameTasks;
CFrameTask* g_DelayedCallTask = new CFrameTask();

23
r5dev/tier0/frametask.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef TIER0_FRAMETASK_H
#define TIER0_FRAMETASK_H
#include "public/iframetask.h"
class CFrameTask : public IFrameTask
{
public:
virtual ~CFrameTask() {}
virtual void RunFrame();
virtual bool IsFinished() const;
void AddFunc(std::function<void()> functor, int frames);
private:
std::mutex m_Mutex;
std::list<DelayedCall_s> m_DelayedCalls;
};
extern std::list<IFrameTask*> g_FrameTasks;
extern CFrameTask* g_DelayedCallTask;
#endif // TIER0_FRAMETASK_H

View File

@ -36,6 +36,7 @@
<ClCompile Include="..\engine\debugoverlay.cpp" />
<ClCompile Include="..\engine\gl_rsurf.cpp" />
<ClCompile Include="..\engine\gl_screen.cpp" />
<ClCompile Include="..\engine\host.cpp" />
<ClCompile Include="..\engine\host_cmd.cpp" />
<ClCompile Include="..\engine\host_state.cpp" />
<ClCompile Include="..\engine\modelloader.cpp" />
@ -105,6 +106,7 @@
<ClCompile Include="..\tier0\cputopology.cpp" />
<ClCompile Include="..\tier0\dbg.cpp" />
<ClCompile Include="..\tier0\fasttimer.cpp" />
<ClCompile Include="..\tier0\frametask.cpp" />
<ClCompile Include="..\tier0\jobthread.cpp" />
<ClCompile Include="..\tier0\platform.cpp" />
<ClCompile Include="..\tier0\threadtools.cpp" />
@ -256,6 +258,7 @@
<ClInclude Include="..\public\idebugoverlay.h" />
<ClInclude Include="..\public\ifile.h" />
<ClInclude Include="..\public\ifilesystem.h" />
<ClInclude Include="..\public\iframetask.h" />
<ClInclude Include="..\public\ihandleentity.h" />
<ClInclude Include="..\public\inetchannel.h" />
<ClInclude Include="..\public\inetmessage.h" />
@ -472,6 +475,7 @@
<ClInclude Include="..\tier0\dbg.h" />
<ClInclude Include="..\tier0\dbgflag.h" />
<ClInclude Include="..\tier0\fasttimer.h" />
<ClInclude Include="..\tier0\frametask.h" />
<ClInclude Include="..\tier0\interface.h" />
<ClInclude Include="..\tier0\jobthread.h" />
<ClInclude Include="..\tier0\memalloc.h" />

View File

@ -579,6 +579,12 @@
<ClCompile Include="..\networksystem\listmanager.cpp">
<Filter>sdk\networksystem</Filter>
</ClCompile>
<ClCompile Include="..\engine\host.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
<ClCompile Include="..\tier0\frametask.cpp">
<Filter>sdk\tier0</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\cdll_engine_int.h">
@ -1727,6 +1733,12 @@
<ClInclude Include="..\public\isnapshotmgr.h">
<Filter>sdk\public</Filter>
</ClInclude>
<ClInclude Include="..\public\iframetask.h">
<Filter>sdk\public</Filter>
</ClInclude>
<ClInclude Include="..\tier0\frametask.h">
<Filter>sdk\tier0</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\shared\resource\lockedserver.png">

View File

@ -222,6 +222,7 @@
<ClInclude Include="..\public\icvar.h" />
<ClInclude Include="..\public\ifile.h" />
<ClInclude Include="..\public\ifilesystem.h" />
<ClInclude Include="..\public\iframetask.h" />
<ClInclude Include="..\public\inetchannel.h" />
<ClInclude Include="..\public\inetmessage.h" />
<ClInclude Include="..\public\inetmsghandler.h" />
@ -427,6 +428,7 @@
<ClInclude Include="..\tier0\dbg.h" />
<ClInclude Include="..\tier0\dbgflag.h" />
<ClInclude Include="..\tier0\fasttimer.h" />
<ClInclude Include="..\tier0\frametask.h" />
<ClInclude Include="..\tier0\interface.h" />
<ClInclude Include="..\tier0\jobthread.h" />
<ClInclude Include="..\tier0\memalloc.h" />
@ -487,6 +489,7 @@
<ClCompile Include="..\engine\clockdriftmgr.cpp" />
<ClCompile Include="..\engine\cmodel_bsp.cpp" />
<ClCompile Include="..\engine\common.cpp" />
<ClCompile Include="..\engine\host.cpp" />
<ClCompile Include="..\engine\host_cmd.cpp" />
<ClCompile Include="..\engine\host_state.cpp" />
<ClCompile Include="..\engine\modelloader.cpp" />
@ -555,6 +558,7 @@
<ClCompile Include="..\tier0\cputopology.cpp" />
<ClCompile Include="..\tier0\dbg.cpp" />
<ClCompile Include="..\tier0\fasttimer.cpp" />
<ClCompile Include="..\tier0\frametask.cpp" />
<ClCompile Include="..\tier0\jobthread.cpp" />
<ClCompile Include="..\tier0\platform.cpp" />
<ClCompile Include="..\tier0\threadtools.cpp" />

View File

@ -1233,6 +1233,12 @@
<ClInclude Include="..\public\isnapshotmgr.h">
<Filter>sdk\public</Filter>
</ClInclude>
<ClInclude Include="..\public\iframetask.h">
<Filter>sdk\public</Filter>
</ClInclude>
<ClInclude Include="..\tier0\frametask.h">
<Filter>sdk\tier0</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\common\opcodes.cpp">
@ -1538,6 +1544,12 @@
<ClCompile Include="..\tier1\generichash.cpp">
<Filter>sdk\tier1</Filter>
</ClCompile>
<ClCompile Include="..\engine\host.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
<ClCompile Include="..\tier0\frametask.cpp">
<Filter>sdk\tier0</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\Dedicated.def" />

View File

@ -36,6 +36,7 @@
<ClCompile Include="..\engine\debugoverlay.cpp" />
<ClCompile Include="..\engine\gl_rsurf.cpp" />
<ClCompile Include="..\engine\gl_screen.cpp" />
<ClCompile Include="..\engine\host.cpp" />
<ClCompile Include="..\engine\host_cmd.cpp" />
<ClCompile Include="..\engine\host_state.cpp" />
<ClCompile Include="..\engine\modelloader.cpp" />
@ -115,6 +116,7 @@
<ClCompile Include="..\tier0\cputopology.cpp" />
<ClCompile Include="..\tier0\dbg.cpp" />
<ClCompile Include="..\tier0\fasttimer.cpp" />
<ClCompile Include="..\tier0\frametask.cpp" />
<ClCompile Include="..\tier0\jobthread.cpp" />
<ClCompile Include="..\tier0\platform.cpp" />
<ClCompile Include="..\tier0\threadtools.cpp" />
@ -281,6 +283,7 @@
<ClInclude Include="..\public\idebugoverlay.h" />
<ClInclude Include="..\public\ifile.h" />
<ClInclude Include="..\public\ifilesystem.h" />
<ClInclude Include="..\public\iframetask.h" />
<ClInclude Include="..\public\ihandleentity.h" />
<ClInclude Include="..\public\inetchannel.h" />
<ClInclude Include="..\public\inetmessage.h" />
@ -499,6 +502,7 @@
<ClInclude Include="..\tier0\dbg.h" />
<ClInclude Include="..\tier0\dbgflag.h" />
<ClInclude Include="..\tier0\fasttimer.h" />
<ClInclude Include="..\tier0\frametask.h" />
<ClInclude Include="..\tier0\jobthread.h" />
<ClInclude Include="..\tier0\memalloc.h" />
<ClInclude Include="..\tier0\memstd.h" />

View File

@ -618,6 +618,12 @@
<ClCompile Include="..\networksystem\listmanager.cpp">
<Filter>sdk\networksystem</Filter>
</ClCompile>
<ClCompile Include="..\tier0\frametask.cpp">
<Filter>sdk\tier0</Filter>
</ClCompile>
<ClCompile Include="..\engine\host.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\cdll_engine_int.h">
@ -1814,6 +1820,12 @@
<ClInclude Include="..\public\isnapshotmgr.h">
<Filter>sdk\public</Filter>
</ClInclude>
<ClInclude Include="..\tier0\frametask.h">
<Filter>sdk\tier0</Filter>
</ClInclude>
<ClInclude Include="..\public\iframetask.h">
<Filter>sdk\public</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\shared\resource\lockedserver.png">

View File

@ -7,6 +7,7 @@
#include "core/stdafx.h"
#include "core/init.h"
#include "core/logdef.h"
#include "tier0/frametask.h"
#include "tier1/cmd.h"
#ifndef DEDICATED
#include "windows/id3dx.h"
@ -135,7 +136,7 @@ DWORD __stdcall ProcessConsoleWorker(LPVOID)
// Execute the command.
Cbuf_AddText(Cbuf_GetCurrentPlayer(), sCommand.c_str(), cmd_source_t::kCommandSrcCode);
Cbuf_Execute();
g_DelayedCallTask->AddFunc(Cbuf_Execute, 0);
sCommand.clear();