mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
292 lines
8.8 KiB
C++
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);
|
|
}
|