Kawe Mazidjatari 6b7e0d574d VScript: fix method order
More logical order of newly added methods.
2024-06-01 11:49:14 +02:00

292 lines
8.8 KiB
C++

//===============================================================================//
//
// Purpose: VSquirrel VM
//
//===============================================================================//
#include "core/stdafx.h"
#include "vscript/vscript.h"
#include "pluginsystem/modsystem.h"
#include "vsquirrel.h"
// Callbacks for registering abstracted script functions.
void(*ServerScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
void(*ClientScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
void(*UiScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
// Callbacks for registering script enums.
void(*ServerScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
void(*ClientScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
void(*UIScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
// Admin panel functions, NULL on client only builds.
void(*CoreServerScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
void(*AdminPanelScriptRegister_Callback)(CSquirrelVM* s) = nullptr;
// Registering constants in scripts.
void(*ScriptConstantRegister_Callback)(CSquirrelVM* s) = nullptr;
//---------------------------------------------------------------------------------
// Purpose: Initialises a Squirrel VM instance
// Output : True on success, false on failure
//---------------------------------------------------------------------------------
bool CSquirrelVM::Init(CSquirrelVM* s, SQCONTEXT context, SQFloat curTime)
{
// original func always returns true, added check just in case.
if (!CSquirrelVM__Init(s, context, curTime))
{
return false;
}
Msg((eDLL_T)context, "Created %s VM: '0x%p'\n", s->GetVM()->_sharedstate->_contextname, s);
switch (context)
{
case SQCONTEXT::SERVER:
g_pServerScript = s;
if (ServerScriptRegister_Callback)
ServerScriptRegister_Callback(s);
break;
case SQCONTEXT::CLIENT:
g_pClientScript = s;
if (ClientScriptRegister_Callback)
ClientScriptRegister_Callback(s);
break;
case SQCONTEXT::UI:
g_pUIScript = s;
if (UiScriptRegister_Callback)
UiScriptRegister_Callback(s);
if (CoreServerScriptRegister_Callback)
CoreServerScriptRegister_Callback(s);
if (AdminPanelScriptRegister_Callback)
AdminPanelScriptRegister_Callback(s);
break;
}
return true;
}
//---------------------------------------------------------------------------------
// Purpose: destroys the signal entry list head
// Input : *s -
// v -
// f -
// Output : true on success, false otherwise
//---------------------------------------------------------------------------------
bool CSquirrelVM::DestroySignalEntryListHead(CSquirrelVM* s, HSQUIRRELVM v, SQFloat f)
{
SQBool result = CSquirrelVM__DestroySignalEntryListHead(s, v, f);
s->RegisterConstant("DEVELOPER", developer->GetInt());
// Must have one.
Assert(ScriptConstantRegister_Callback);
ScriptConstantRegister_Callback(s);
return result;
}
//---------------------------------------------------------------------------------
// Purpose: registers a global constant
// Input : *name -
// value -
//---------------------------------------------------------------------------------
SQRESULT CSquirrelVM::RegisterConstant(const SQChar* name, SQInteger value)
{
return CSquirrelVM__RegisterConstant(this, name, value);
}
//---------------------------------------------------------------------------------
// Purpose: runs text as script on the VM
// Input : *script -
// Output : true on success, false otherwise
//---------------------------------------------------------------------------------
bool CSquirrelVM::Run(const SQChar* const script)
{
Assert(m_hVM);
bool success = false;
SQBufState bufState(script);
if (SQ_SUCCEEDED(sq_compilebuffer(m_hVM, &bufState, "unnamed", -1, SQTrue)))
{
SQObject hScript;
sq_getstackobj(m_hVM, -1, &hScript);
sq_addref(m_hVM, &hScript);
sq_pop(m_hVM, 1);
if (ExecuteFunction((HSCRIPT)&hScript, NULL, 0, NULL, NULL) == SCRIPT_DONE)
success = true;
sq_release(m_hVM, &hScript);
}
return success;
}
//---------------------------------------------------------------------------------
// Purpose: executes a function by handle
// Input : hFunction -
// *pArgs -
// nArgs -
// *pReturn -
// hScope -
// Output : SCRIPT_DONE on success, SCRIPT_ERROR otherwise
//---------------------------------------------------------------------------------
ScriptStatus_t CSquirrelVM::ExecuteFunction(HSCRIPT hFunction, void** pArgs, unsigned int nArgs, void* pReturn, HSCRIPT hScope)
{
// NOTE: pArgs and pReturn are most likely of type 'ScriptVariant_t', needs to be reversed.
return CSquirrelVM__ExecuteFunction(this, hFunction, pArgs, nArgs, pReturn, hScope);
}
//---------------------------------------------------------------------------------
// Purpose: executes a code callback
// Input : *name -
// Output : true on success, false otherwise
//---------------------------------------------------------------------------------
bool CSquirrelVM::ExecuteCodeCallback(const SQChar* const name)
{
return CSquirrelVM__ExecuteCodeCallback(this, name);
}
//---------------------------------------------------------------------------------
// Purpose: registers a code function
// Input : *s -
// *scriptName -
// *nativeName -
// *helpString -
// *returnString -
// *parameters -
// *function -
//---------------------------------------------------------------------------------
SQRESULT CSquirrelVM::RegisterFunction(const SQChar* scriptName, const SQChar* nativeName,
const SQChar* helpString, const SQChar* returnString, const SQChar* parameters, void* function)
{
ScriptFunctionBinding_t binding;
binding.Init(scriptName, nativeName, helpString, returnString, parameters, 5, function);
SQRESULT results = CSquirrelVM__RegisterFunction(this, &binding, 1);
return results;
}
//---------------------------------------------------------------------------------
// Purpose: sets current VM as the global precompiler
// Input : *name -
// value -
//---------------------------------------------------------------------------------
void CSquirrelVM::SetAsCompiler(RSON::Node_t* rson)
{
const SQCONTEXT context = GetContext();
switch (context)
{
case SQCONTEXT::SERVER:
{
v_Script_SetServerPrecompiler(context, rson);
break;
}
case SQCONTEXT::CLIENT:
case SQCONTEXT::UI:
{
v_Script_SetClientPrecompiler(context, rson);
break;
}
}
}
//---------------------------------------------------------------------------------
// Purpose: Precompiles mod scripts
//---------------------------------------------------------------------------------
void CSquirrelVM::CompileModScripts()
{
FOR_EACH_VEC(ModSystem()->GetModList(), i)
{
const CModSystem::ModInstance_t* mod = ModSystem()->GetModList()[i];
if (!mod->IsEnabled())
continue;
if (!mod->m_bHasScriptCompileList)
continue;
// allocs parsed rson buffer
RSON::Node_t* rson = mod->LoadScriptCompileList();
if (!rson)
Error(GetNativeContext(), NO_ERROR,
"%s: Failed to load RSON file '%s'\n",
__FUNCTION__, mod->GetScriptCompileListPath().Get());
const char* scriptPathArray[MAX_PRECOMPILED_SCRIPTS];
int scriptCount = 0;
SetAsCompiler(rson);
if (Script_ParseScriptList(
GetContext(),
mod->GetScriptCompileListPath().Get(),
rson,
(char**)scriptPathArray, &scriptCount,
nullptr, 0))
{
std::vector<char*> newScriptPaths;
for (int j = 0; j < scriptCount; ++j)
{
// add "::MOD::" to the start of the script path so it can be
// identified from Script_LoadScript later, this is so we can
// avoid script naming conflicts by removing the engine's
// forced directory of "scripts/vscripts/" and adding the mod
// path to the start
CUtlString scriptPath;
scriptPath.Format("%s%s%s%s",
MOD_SCRIPT_PATH_IDENTIFIER, mod->GetBasePath().Get(),
GAME_SCRIPT_PATH, scriptPathArray[j]);
char* pszScriptPath = _strdup(scriptPath.Get());
// normalise slash direction
V_FixSlashes(pszScriptPath);
newScriptPaths.emplace_back(pszScriptPath);
scriptPathArray[j] = pszScriptPath;
}
switch (GetContext())
{
case SQCONTEXT::SERVER:
{
CSquirrelVM__PrecompileServerScripts(this, GetContext(), (char**)scriptPathArray, scriptCount);
break;
}
case SQCONTEXT::CLIENT:
case SQCONTEXT::UI:
{
CSquirrelVM__PrecompileClientScripts(this, GetContext(), (char**)scriptPathArray, scriptCount);
break;
}
}
// clean up our allocated script paths
for (char* path : newScriptPaths)
{
free(path);
}
}
RSON_Free(rson, AlignedMemAlloc());
AlignedMemAlloc()->Free(rson);
}
}
//---------------------------------------------------------------------------------
void VSquirrel::Detour(const bool bAttach) const
{
DetourSetup(&CSquirrelVM__Init, &CSquirrelVM::Init, bAttach);
DetourSetup(&CSquirrelVM__DestroySignalEntryListHead, &CSquirrelVM::DestroySignalEntryListHead, bAttach);
}