diff --git a/r5dev/engine/server/server.cpp b/r5dev/engine/server/server.cpp index 2645da8d..d241972c 100644 --- a/r5dev/engine/server/server.cpp +++ b/r5dev/engine/server/server.cpp @@ -10,6 +10,7 @@ ///////////////////////////////////////////////////////////////////////////////// #include "core/stdafx.h" #include "common/protocol.h" +#include "tier0/frametask.h" #include "tier1/cvar.h" #include "tier1/strtools.h" #include "engine/server/sv_main.h" @@ -217,6 +218,17 @@ void CServer::BroadcastMessage(CNetMessage* const msg, const bool onlyActive, co //--------------------------------------------------------------------------------- void CServer::FrameJob(double flFrameTime, bool bRunOverlays, bool bUpdateFrame) { + for (IFrameTask* const& task : g_ServerTaskQueueList) + { + task->RunFrame(); + } + + g_ServerTaskQueueList.erase(std::remove_if(g_ServerTaskQueueList.begin(), + g_ServerTaskQueueList.end(), [](const IFrameTask* task) + { + return task->IsFinished(); + }), g_ServerTaskQueueList.end()); + CServer__FrameJob(flFrameTime, bRunOverlays, bUpdateFrame); LiveAPISystem()->RunFrame(); } @@ -242,3 +254,6 @@ void VServer::Detour(const bool bAttach) const /////////////////////////////////////////////////////////////////////////////// CServer* g_pServer = nullptr; CClientExtended CServer::sm_ClientsExtended[MAX_PLAYERS]; + +std::list g_ServerTaskQueueList; +CFrameTask g_ServerTaskQueue; diff --git a/r5dev/engine/server/server.h b/r5dev/engine/server/server.h index 3f976c6d..c549f8f7 100644 --- a/r5dev/engine/server/server.h +++ b/r5dev/engine/server/server.h @@ -1,4 +1,5 @@ #pragma once +#include "tier0/frametask.h" #include "tier1/NetAdr.h" #include "networksystem/pylon.h" #include "engine/client/client.h" @@ -111,6 +112,9 @@ static_assert(sizeof(CServer) == 0x25264C0); extern CServer* g_pServer; +extern std::list g_ServerTaskQueueList; +extern CFrameTask g_ServerTaskQueue; + extern ConVar sv_showconnecting; extern ConVar sv_pylonVisibility; diff --git a/r5dev/engine/sys_dll.cpp b/r5dev/engine/sys_dll.cpp index 5a3d21a2..5dc20100 100644 --- a/r5dev/engine/sys_dll.cpp +++ b/r5dev/engine/sys_dll.cpp @@ -20,6 +20,7 @@ #include "engine/host_cmd.h" #include "engine/enginetrace.h" #ifndef CLIENT_DLL +#include "engine/server/server.h" #include "engine/server/sv_main.h" #include "server/vengineserver_impl.h" #include "game/server/gameinterface.h" @@ -116,8 +117,11 @@ bool CModAppSystemGroup::StaticCreate(CModAppSystemGroup* pModAppSystemGroup) } g_TaskQueueList.push_back(&g_TaskQueue); - g_bAppSystemInit = true; +#ifndef CLIENT_DLL + g_ServerTaskQueueList.push_back(&g_ServerTaskQueue); +#endif // !CLIENT_DLL + g_bAppSystemInit = true; return CModAppSystemGroup__Create(pModAppSystemGroup); } diff --git a/r5dev/game/server/vscript_server.cpp b/r5dev/game/server/vscript_server.cpp index 0ca711d9..8e6cdb63 100644 --- a/r5dev/game/server/vscript_server.cpp +++ b/r5dev/game/server/vscript_server.cpp @@ -31,6 +31,18 @@ static void SQVM_ServerScript_f(const CCommand& args) { if (args.ArgC() >= 2) { + const char* code = args.ArgS(); + + if (!ThreadInServerFrameThread()) + { + const string scode(code); + g_ServerTaskQueue.Dispatch([scode]() + { + Script_Execute(scode.c_str(), SQCONTEXT::SERVER); + }, 0); + return; // Only run in server frame thread. + } + Script_Execute(args.ArgS(), SQCONTEXT::SERVER); } } diff --git a/r5dev/public/tier0/frametask.h b/r5dev/public/tier0/frametask.h index 01e7c2f9..9c4601a4 100644 --- a/r5dev/public/tier0/frametask.h +++ b/r5dev/public/tier0/frametask.h @@ -4,8 +4,8 @@ #include "public/iframetask.h" //=============================================================================// -// This class is set up to run before each frame (main thread). -// Committed tasks are scheduled to execute after 'i' frames. +// This class is set up to run before each frame, committed tasks are scheduled +// to execute after 'i' frames. // ---------------------------------------------------------------------------- // A use case for scheduling tasks in the main thread would be (for example) // performing a web request in a separate thread, and apply the results (such as diff --git a/r5dev/vscript/languages/squirrel_re/include/squirrel.h b/r5dev/vscript/languages/squirrel_re/include/squirrel.h index 1244ed98..5eee0377 100644 --- a/r5dev/vscript/languages/squirrel_re/include/squirrel.h +++ b/r5dev/vscript/languages/squirrel_re/include/squirrel.h @@ -187,7 +187,7 @@ void sq_newtable(HSQUIRRELVM v); SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx); SQRESULT sq_arrayappend(HSQUIRRELVM v, SQInteger idx); SQRESULT sq_pushstructure(HSQUIRRELVM v, const SQChar* name, const SQChar* member, const SQChar* codeclass1, const SQChar* codeclass2); -SQRESULT sq_compilebuffer(HSQUIRRELVM v, SQBufState* bufferState, const SQChar* buffer, SQInteger context); +SQRESULT sq_compilebuffer(HSQUIRRELVM v, SQBufState* bufferState, const SQChar* buffer, SQInteger context, SQBool raiseerror); SQRESULT sq_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror); SQRESULT sq_startconsttable(HSQUIRRELVM v); @@ -228,7 +228,7 @@ inline void(*v_sq_newtable)(HSQUIRRELVM v); inline SQRESULT(*v_sq_newslot)(HSQUIRRELVM v, SQInteger idx); inline SQRESULT(*v_sq_arrayappend)(HSQUIRRELVM v, SQInteger idx); inline SQRESULT(*v_sq_pushstructure)(HSQUIRRELVM v, const SQChar* name, const SQChar* member, const SQChar* codeclass1, const SQChar* codeclass2); -inline SQRESULT(*v_sq_compilebuffer)(HSQUIRRELVM v, SQBufState* bufferstate, const SQChar* buffer, SQInteger level); +inline SQRESULT(*v_sq_compilebuffer)(HSQUIRRELVM v, SQBufState* bufferstate, const SQChar* buffer, SQInteger level, SQBool raiseerror); inline SQRESULT(*v_sq_call)(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror); inline SQRESULT(*v_sq_get)(HSQUIRRELVM v, SQInteger idx); diff --git a/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp b/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp index b5e213af..b0ce42a1 100644 --- a/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp +++ b/r5dev/vscript/languages/squirrel_re/squirrel/sqapi.cpp @@ -177,9 +177,9 @@ SQRESULT sq_pushstructure(HSQUIRRELVM v, const SQChar* name, const SQChar* membe } //--------------------------------------------------------------------------------- -SQRESULT sq_compilebuffer(HSQUIRRELVM v, SQBufState* bufferState, const SQChar* buffer, SQInteger level) +SQRESULT sq_compilebuffer(HSQUIRRELVM v, SQBufState* bufferState, const SQChar* buffer, SQInteger level, SQBool raiseerror) { - return v_sq_compilebuffer(v, bufferState, buffer, level); + return v_sq_compilebuffer(v, bufferState, buffer, level, raiseerror); } //--------------------------------------------------------------------------------- diff --git a/r5dev/vscript/vscript.cpp b/r5dev/vscript/vscript.cpp index 8fcec3b4..11c7fced 100644 --- a/r5dev/vscript/vscript.cpp +++ b/r5dev/vscript/vscript.cpp @@ -133,7 +133,11 @@ SQBool Script_PrecompileClientScripts(CSquirrelVM* vm) void Script_Execute(const SQChar* code, const SQCONTEXT context) { Assert(context != SQCONTEXT::NONE); - Assert(ThreadInMainOrServerFrameThread()); + + if (context == SQCONTEXT::CLIENT || context == SQCONTEXT::UI) + Assert(ThreadInMainThread()); + else if (context == SQCONTEXT::SERVER) + Assert(ThreadInServerFrameThread()); CSquirrelVM* s = Script_GetScriptHandle(context); const char* const contextName = s_scriptContextNames[(int)context]; @@ -145,24 +149,29 @@ void Script_Execute(const SQChar* code, const SQCONTEXT context) } HSQUIRRELVM v = s->GetVM(); + if (!v) { Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script while VM isn't initialized\n", contextName); return; } - SQBufState bufState = SQBufState(code); - SQRESULT compileResult = sq_compilebuffer(v, &bufState, "console", -1); + SQBufState bufState(code); - if (SQ_SUCCEEDED(compileResult)) + if (SQ_SUCCEEDED(sq_compilebuffer(v, &bufState, "unnamed", -1, SQTrue))) { - sq_pushroottable(v); - SQRESULT callResult = sq_call(v, 1, false, false); + SQObject hScript; + sq_getstackobj(v, -1, &hScript); - if (!SQ_SUCCEEDED(callResult)) + sq_addref(v, &hScript); + sq_pop(v, 1); + + if (s->ExecuteFunction((HSCRIPT)&hScript, NULL, 0, NULL, NULL) == SCRIPT_ERROR) { Error(eDLL_T::ENGINE, NO_ERROR, "Failed to execute %s script \"%s\"\n", contextName, code); } + + sq_release(v, &hScript); } }