mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
VScript: properly implement script command callback
Previously we did sq_pushroottable() and a subsequent sq_call() after compiling the text buffer, but this didn't work for code that was threaded, or using Get/SetNetVar* functions. The second issue was that the callback for the "script" command was ran in the main thread. Server script should always run in the server frame thread, the Set/GetNetVar* functions check thread id to retrieve the correct VM context, so running server script from the main thread ended up with Set/GetNetVar* functions retrieving the client VM context rather than server's, causing undefined behavior. Script commands are now queued to the server frame thread, ultimately fixing this bug. Also fixed a small bug with function 'sq_compilebuffer()'; it takes an extra argument but this wasn't taken into account in the SDK.
This commit is contained in:
parent
183a6e9c35
commit
1455017419
@ -10,6 +10,7 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
#include "core/stdafx.h"
|
#include "core/stdafx.h"
|
||||||
#include "common/protocol.h"
|
#include "common/protocol.h"
|
||||||
|
#include "tier0/frametask.h"
|
||||||
#include "tier1/cvar.h"
|
#include "tier1/cvar.h"
|
||||||
#include "tier1/strtools.h"
|
#include "tier1/strtools.h"
|
||||||
#include "engine/server/sv_main.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)
|
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);
|
CServer__FrameJob(flFrameTime, bRunOverlays, bUpdateFrame);
|
||||||
LiveAPISystem()->RunFrame();
|
LiveAPISystem()->RunFrame();
|
||||||
}
|
}
|
||||||
@ -242,3 +254,6 @@ void VServer::Detour(const bool bAttach) const
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
CServer* g_pServer = nullptr;
|
CServer* g_pServer = nullptr;
|
||||||
CClientExtended CServer::sm_ClientsExtended[MAX_PLAYERS];
|
CClientExtended CServer::sm_ClientsExtended[MAX_PLAYERS];
|
||||||
|
|
||||||
|
std::list<IFrameTask*> g_ServerTaskQueueList;
|
||||||
|
CFrameTask g_ServerTaskQueue;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "tier0/frametask.h"
|
||||||
#include "tier1/NetAdr.h"
|
#include "tier1/NetAdr.h"
|
||||||
#include "networksystem/pylon.h"
|
#include "networksystem/pylon.h"
|
||||||
#include "engine/client/client.h"
|
#include "engine/client/client.h"
|
||||||
@ -111,6 +112,9 @@ static_assert(sizeof(CServer) == 0x25264C0);
|
|||||||
|
|
||||||
extern CServer* g_pServer;
|
extern CServer* g_pServer;
|
||||||
|
|
||||||
|
extern std::list<IFrameTask*> g_ServerTaskQueueList;
|
||||||
|
extern CFrameTask g_ServerTaskQueue;
|
||||||
|
|
||||||
extern ConVar sv_showconnecting;
|
extern ConVar sv_showconnecting;
|
||||||
|
|
||||||
extern ConVar sv_pylonVisibility;
|
extern ConVar sv_pylonVisibility;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "engine/host_cmd.h"
|
#include "engine/host_cmd.h"
|
||||||
#include "engine/enginetrace.h"
|
#include "engine/enginetrace.h"
|
||||||
#ifndef CLIENT_DLL
|
#ifndef CLIENT_DLL
|
||||||
|
#include "engine/server/server.h"
|
||||||
#include "engine/server/sv_main.h"
|
#include "engine/server/sv_main.h"
|
||||||
#include "server/vengineserver_impl.h"
|
#include "server/vengineserver_impl.h"
|
||||||
#include "game/server/gameinterface.h"
|
#include "game/server/gameinterface.h"
|
||||||
@ -116,8 +117,11 @@ bool CModAppSystemGroup::StaticCreate(CModAppSystemGroup* pModAppSystemGroup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_TaskQueueList.push_back(&g_TaskQueue);
|
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);
|
return CModAppSystemGroup__Create(pModAppSystemGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,18 @@ static void SQVM_ServerScript_f(const CCommand& args)
|
|||||||
{
|
{
|
||||||
if (args.ArgC() >= 2)
|
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);
|
Script_Execute(args.ArgS(), SQCONTEXT::SERVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#include "public/iframetask.h"
|
#include "public/iframetask.h"
|
||||||
|
|
||||||
//=============================================================================//
|
//=============================================================================//
|
||||||
// This class is set up to run before each frame (main thread).
|
// This class is set up to run before each frame, committed tasks are scheduled
|
||||||
// Committed tasks are scheduled to execute after 'i' frames.
|
// to execute after 'i' frames.
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// A use case for scheduling tasks in the main thread would be (for example)
|
// 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
|
// performing a web request in a separate thread, and apply the results (such as
|
||||||
|
@ -187,7 +187,7 @@ void sq_newtable(HSQUIRRELVM v);
|
|||||||
SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx);
|
SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx);
|
||||||
SQRESULT sq_arrayappend(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_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_call(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror);
|
||||||
|
|
||||||
SQRESULT sq_startconsttable(HSQUIRRELVM v);
|
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_newslot)(HSQUIRRELVM v, SQInteger idx);
|
||||||
inline SQRESULT(*v_sq_arrayappend)(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_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_call)(HSQUIRRELVM v, SQInteger params, SQBool retval, SQBool raiseerror);
|
||||||
inline SQRESULT(*v_sq_get)(HSQUIRRELVM v, SQInteger idx);
|
inline SQRESULT(*v_sq_get)(HSQUIRRELVM v, SQInteger idx);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------
|
||||||
|
@ -133,7 +133,11 @@ SQBool Script_PrecompileClientScripts(CSquirrelVM* vm)
|
|||||||
void Script_Execute(const SQChar* code, const SQCONTEXT context)
|
void Script_Execute(const SQChar* code, const SQCONTEXT context)
|
||||||
{
|
{
|
||||||
Assert(context != SQCONTEXT::NONE);
|
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);
|
CSquirrelVM* s = Script_GetScriptHandle(context);
|
||||||
const char* const contextName = s_scriptContextNames[(int)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();
|
HSQUIRRELVM v = s->GetVM();
|
||||||
|
|
||||||
if (!v)
|
if (!v)
|
||||||
{
|
{
|
||||||
Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script while VM isn't initialized\n", contextName);
|
Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to run %s script while VM isn't initialized\n", contextName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SQBufState bufState = SQBufState(code);
|
SQBufState bufState(code);
|
||||||
SQRESULT compileResult = sq_compilebuffer(v, &bufState, "console", -1);
|
|
||||||
|
|
||||||
if (SQ_SUCCEEDED(compileResult))
|
if (SQ_SUCCEEDED(sq_compilebuffer(v, &bufState, "unnamed", -1, SQTrue)))
|
||||||
{
|
{
|
||||||
sq_pushroottable(v);
|
SQObject hScript;
|
||||||
SQRESULT callResult = sq_call(v, 1, false, false);
|
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);
|
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to execute %s script \"%s\"\n", contextName, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sq_release(v, &hScript);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user