mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Properly decouple squirrel and game code. This makes it easier to reverse engineer more of this squirrel system, and to compile them as individual libraries later on when moving to CMake to significantly decrease compile times.
209 lines
6.2 KiB
C++
209 lines
6.2 KiB
C++
//===============================================================================//
|
|
//
|
|
// Purpose: VSquirrel VM
|
|
//
|
|
//===============================================================================//
|
|
#include "core/stdafx.h"
|
|
#include "tier1/cvar.h"
|
|
#include "vscript/vscript.h"
|
|
#include "vsquirrel.h"
|
|
#include "pluginsystem/modsystem.h"
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Purpose: Initialises a Squirrel VM instance
|
|
// Output : True on success, false on failure
|
|
//---------------------------------------------------------------------------------
|
|
SQBool CSquirrelVM::Init(CSquirrelVM* s, SQCONTEXT context, SQFloat curTime)
|
|
{
|
|
// original func always returns true, added check just in case.
|
|
if (!v_CSquirrelVM_Init(s, context, curTime))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DevMsg((eDLL_T)context, "Created %s VM: '0x%p'\n", s->GetVM()->_sharedstate->_contextname, s);
|
|
|
|
switch (context)
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
case SQCONTEXT::SERVER:
|
|
g_pServerScript = s;
|
|
Script_RegisterServerFunctions(s);
|
|
break;
|
|
#endif
|
|
#ifndef DEDICATED
|
|
case SQCONTEXT::CLIENT:
|
|
g_pClientScript = s;
|
|
Script_RegisterClientFunctions(s);
|
|
break;
|
|
case SQCONTEXT::UI:
|
|
g_pUIScript = s;
|
|
Script_RegisterUIFunctions(s);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Purpose: destroys the signal entry list head
|
|
// Input : *s -
|
|
// v -
|
|
// f -
|
|
// Output : true on success, false otherwise
|
|
//---------------------------------------------------------------------------------
|
|
SQBool CSquirrelVM::DestroySignalEntryListHead(CSquirrelVM* s, HSQUIRRELVM v, SQFloat f)
|
|
{
|
|
SQBool result = v_CSquirrelVM_DestroySignalEntryListHead(s, v, f);
|
|
s->RegisterConstant("DEVELOPER", developer->GetInt());
|
|
return result;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Purpose: registers a global constant
|
|
// Input : *name -
|
|
// value -
|
|
//---------------------------------------------------------------------------------
|
|
SQRESULT CSquirrelVM::RegisterConstant(const SQChar* name, SQInteger value)
|
|
{
|
|
return v_CSquirrelVM_RegisterConstant(this, name, value);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// 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 = v_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)
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
case SQCONTEXT::SERVER:
|
|
{
|
|
v_Script_SetServerPrecompiler(context, rson);
|
|
break;
|
|
}
|
|
#endif
|
|
#ifndef DEDICATED
|
|
case SQCONTEXT::CLIENT:
|
|
case SQCONTEXT::UI:
|
|
{
|
|
v_Script_SetClientPrecompiler(context, rson);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------
|
|
// Purpose: Precompiles mod scripts
|
|
//---------------------------------------------------------------------------------
|
|
void CSquirrelVM::CompileModScripts()
|
|
{
|
|
for (auto& mod : g_pModSystem->GetModList())
|
|
{
|
|
if (!mod.IsEnabled())
|
|
continue;
|
|
|
|
if (!mod.m_bHasScriptCompileList)
|
|
continue;
|
|
|
|
RSON::Node_t* rson = mod.LoadScriptCompileList(); // allocs parsed rson buffer
|
|
|
|
if (!rson)
|
|
Error(GetVM()->GetNativePrintContext(), EXIT_FAILURE, "%s: Failed to load RSON file %s\n", __FUNCTION__, mod.GetScriptCompileListPath().string().c_str());
|
|
|
|
const char* scriptPathArray[MAX_PRECOMPILED_SCRIPTS];
|
|
int scriptCount = 0;
|
|
|
|
SetAsCompiler(rson);
|
|
|
|
if (Script_ParseScriptList(
|
|
GetContext(),
|
|
mod.GetScriptCompileListPath().string().c_str(),
|
|
rson,
|
|
(char**)scriptPathArray, &scriptCount,
|
|
nullptr, 0))
|
|
{
|
|
std::vector<char*> newScriptPaths;
|
|
for (int i = 0; i < scriptCount; ++i)
|
|
{
|
|
// 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
|
|
std::string scriptPath = MOD_SCRIPT_PATH_IDENTIFIER + (mod.GetBasePath() / "scripts/vscripts/" / scriptPathArray[i]).string();
|
|
char* pszScriptPath = _strdup(scriptPath.c_str());
|
|
|
|
// normalise slash direction
|
|
V_FixSlashes(pszScriptPath);
|
|
|
|
newScriptPaths.emplace_back(pszScriptPath);
|
|
scriptPathArray[i] = pszScriptPath;
|
|
}
|
|
|
|
switch (GetVM()->GetContext())
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
case SQCONTEXT::SERVER:
|
|
{
|
|
v_CSquirrelVM_PrecompileServerScripts(this, GetContext(), (char**)scriptPathArray, scriptCount);
|
|
break;
|
|
}
|
|
#endif
|
|
#ifndef DEDICATED
|
|
case SQCONTEXT::CLIENT:
|
|
case SQCONTEXT::UI:
|
|
{
|
|
v_CSquirrelVM_PrecompileClientScripts(this, GetContext(), (char**)scriptPathArray, scriptCount);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// clean up our allocated script paths
|
|
for (char* path : newScriptPaths)
|
|
{
|
|
delete path;
|
|
}
|
|
}
|
|
|
|
// TODO[rexx]: clean up allocated RSON memory. example @ 1408B18E2
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------
|
|
void VSquirrel::Attach() const
|
|
{
|
|
DetourAttach((LPVOID*)&v_CSquirrelVM_Init, &CSquirrelVM::Init);
|
|
DetourAttach((LPVOID*)&v_CSquirrelVM_DestroySignalEntryListHead, &CSquirrelVM::DestroySignalEntryListHead);
|
|
}
|
|
//---------------------------------------------------------------------------------
|
|
void VSquirrel::Detach() const
|
|
{
|
|
DetourDetach((LPVOID*)&v_CSquirrelVM_Init, &CSquirrelVM::Init);
|
|
DetourDetach((LPVOID*)&v_CSquirrelVM_DestroySignalEntryListHead, &CSquirrelVM::DestroySignalEntryListHead);
|
|
}
|