aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/squirrel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDLL/squirrel.cpp')
-rw-r--r--NorthstarDLL/squirrel.cpp250
1 files changed, 131 insertions, 119 deletions
diff --git a/NorthstarDLL/squirrel.cpp b/NorthstarDLL/squirrel.cpp
index 056fe401..4bd4bca8 100644
--- a/NorthstarDLL/squirrel.cpp
+++ b/NorthstarDLL/squirrel.cpp
@@ -4,6 +4,7 @@
#include "modmanager.h"
#include "dedicated.h"
#include "r2engine.h"
+#include "tier0.h"
AUTOHOOK_INIT()
@@ -41,6 +42,58 @@ eSQReturnType SQReturnTypeFromString(const char* pReturnType)
return eSQReturnType::Default; // previous default value
}
+const char* SQTypeNameFromID(int type)
+{
+ switch (type)
+ {
+ case OT_ASSET:
+ return "asset";
+ case OT_INTEGER:
+ return "int";
+ case OT_BOOL:
+ return "bool";
+ case SQOBJECT_NUMERIC:
+ return "float or int";
+ case OT_NULL:
+ return "null";
+ case OT_VECTOR:
+ return "vector";
+ case 0:
+ return "var";
+ case OT_USERDATA:
+ return "userdata";
+ case OT_FLOAT:
+ return "float";
+ case OT_STRING:
+ return "string";
+ case OT_ARRAY:
+ return "array";
+ case 0x8000200:
+ return "function";
+ case 0x8100000:
+ return "structdef";
+ case OT_THREAD:
+ return "thread";
+ case OT_FUNCPROTO:
+ return "function";
+ case OT_CLAAS:
+ return "class";
+ case OT_WEAKREF:
+ return "weakref";
+ case 0x8080000:
+ return "unimplemented function";
+ case 0x8200000:
+ return "struct instance";
+ case OT_TABLE:
+ return "table";
+ case 0xA008000:
+ return "instance";
+ case OT_ENTITY:
+ return "entity";
+ }
+ return "";
+}
+
// needed to define implementations for squirrelmanager outside of squirrel.h without compiler errors
template class SquirrelManager<ScriptContext::SERVER>;
template class SquirrelManager<ScriptContext::CLIENT>;
@@ -48,13 +101,12 @@ template class SquirrelManager<ScriptContext::UI>;
template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquirrelVM* newSqvm)
{
- SquirrelVM = newSqvm;
- sqvm = SquirrelVM->sqvm; // honestly not 100% sure on what this is, but alot of functions take it
+ m_pSQVM = newSqvm;
for (SQFuncRegistration* funcReg : m_funcRegistrations)
{
spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName);
- RegisterSquirrelFunc(SquirrelVM, funcReg, 1);
+ RegisterSquirrelFunc(m_pSQVM, funcReg, 1);
}
for (auto& pair : g_pModManager->m_DependencyConstants)
@@ -72,18 +124,18 @@ template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquir
}
}
- defconst(SquirrelVM, pair.first.c_str(), bWasFound);
+ defconst(m_pSQVM, pair.first.c_str(), bWasFound);
}
}
template <ScriptContext context> void SquirrelManager<context>::VMDestroyed()
{
- SquirrelVM = nullptr;
+ m_pSQVM = nullptr;
}
template <ScriptContext context> void SquirrelManager<context>::ExecuteCode(const char* pCode)
{
- if (!SquirrelVM)
+ if (!m_pSQVM)
{
spdlog::error("Cannot execute code, {} squirrel vm is not initialised", GetContextName(context));
return;
@@ -99,8 +151,8 @@ template <ScriptContext context> void SquirrelManager<context>::ExecuteCode(cons
if (compileResult != SQRESULT_ERROR)
{
- pushroottable(sqvm);
- SQRESULT callResult = call(sqvm, 0);
+ pushroottable(m_pSQVM->sqvm);
+ SQRESULT callResult = call(m_pSQVM->sqvm, 0);
spdlog::info("sq_call returned {}", PrintSQRESULT.at(callResult));
}
}
@@ -131,29 +183,36 @@ template <ScriptContext context> void SquirrelManager<context>::AddFuncRegistrat
template <ScriptContext context> SQRESULT SquirrelManager<context>::setupfunc(const SQChar* funcname)
{
- pushroottable(sqvm);
- pushstring(sqvm, funcname, -1);
+ pushroottable(m_pSQVM->sqvm);
+ pushstring(m_pSQVM->sqvm, funcname, -1);
- SQRESULT result = get(sqvm, -2);
+ SQRESULT result = get(m_pSQVM->sqvm, -2);
if (result != SQRESULT_ERROR)
- pushroottable(sqvm);
+ pushroottable(m_pSQVM->sqvm);
return result;
}
+
template <ScriptContext context> void SquirrelManager<context>::AddFuncOverride(std::string name, SQFunction func)
{
m_funcOverrides[name] = func;
}
// hooks
+bool IsUIVM(ScriptContext context, HSquirrelVM* pSqvm)
+{
+ return context != ScriptContext::SERVER && g_pSquirrel<ScriptContext::UI>->m_pSQVM &&
+ g_pSquirrel<ScriptContext::UI>->m_pSQVM->sqvm == pSqvm;
+}
+
template <ScriptContext context> void* (*sq_compiler_create)(HSquirrelVM* sqvm, void* a2, void* a3, SQBool bShouldThrowError);
template <ScriptContext context> void* sq_compiler_createHook(HSquirrelVM* sqvm, void* a2, void* a3, SQBool bShouldThrowError)
{
// store whether errors generated from this compile should be fatal
- if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->sqvm)
- g_pSquirrel<ScriptContext::UI>->m_bCompilationErrorsFatal = bShouldThrowError;
+ if (IsUIVM(context, sqvm))
+ g_pSquirrel<ScriptContext::UI>->m_bFatalCompilationErrors = bShouldThrowError;
else
- g_pSquirrel<context>->m_bCompilationErrorsFatal = bShouldThrowError;
+ g_pSquirrel<context>->m_bFatalCompilationErrors = bShouldThrowError;
return sq_compiler_create<context>(sqvm, a2, a3, bShouldThrowError);
}
@@ -179,7 +238,7 @@ template <ScriptContext context> SQInteger SQPrintHook(HSquirrelVM* sqvm, const
return 0;
}
-template <ScriptContext context> CSquirrelVM* (*CreateNewVM)(void* a1, ScriptContext contextArg);
+template <ScriptContext context> CSquirrelVM* (*CreateNewVM)(void* a1, ScriptContext realContext);
template <ScriptContext context> CSquirrelVM* CreateNewVMHook(void* a1, ScriptContext realContext)
{
CSquirrelVM* sqvm = CreateNewVM<context>(a1, realContext);
@@ -192,11 +251,11 @@ template <ScriptContext context> CSquirrelVM* CreateNewVMHook(void* a1, ScriptCo
return sqvm;
}
-template <ScriptContext context> void (*DestroyVM)(void* a1, void* sqvm);
-template <ScriptContext context> void DestroyVMHook(void* a1, void* sqvm)
+template <ScriptContext context> void (*DestroyVM)(void* a1, HSquirrelVM* sqvm);
+template <ScriptContext context> void DestroyVMHook(void* a1, HSquirrelVM* sqvm)
{
ScriptContext realContext = context; // ui and client use the same function so we use this for prints
- if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->sqvm)
+ if (IsUIVM(context, sqvm))
{
realContext = ScriptContext::UI;
g_pSquirrel<ScriptContext::UI>->VMDestroyed();
@@ -204,18 +263,18 @@ template <ScriptContext context> void DestroyVMHook(void* a1, void* sqvm)
else
DestroyVM<context>(a1, sqvm);
- spdlog::info("DestroyVM {} {}", GetContextName(realContext), sqvm);
+ spdlog::info("DestroyVM {} {}", GetContextName(realContext), (void*)sqvm);
}
-template <ScriptContext context> void (*SQCompileError)(void* sqvm, const char* error, const char* file, int line, int column);
-template <ScriptContext context> void ScriptCompileErrorHook(void* sqvm, const char* error, const char* file, int line, int column)
+template <ScriptContext context> void (*SQCompileError)(HSquirrelVM* sqvm, const char* error, const char* file, int line, int column);
+template <ScriptContext context> void ScriptCompileErrorHook(HSquirrelVM* sqvm, const char* error, const char* file, int line, int column)
{
- bool bIsFatalError = g_pSquirrel<context>->m_bCompilationErrorsFatal;
+ bool bIsFatalError = g_pSquirrel<context>->m_bFatalCompilationErrors;
ScriptContext realContext = context; // ui and client use the same function so we use this for prints
- if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->sqvm)
+ if (IsUIVM(context, sqvm))
{
realContext = ScriptContext::UI;
- bIsFatalError = g_pSquirrel<ScriptContext::UI>->m_bCompilationErrorsFatal;
+ bIsFatalError = g_pSquirrel<ScriptContext::UI>->m_bFatalCompilationErrors;
}
spdlog::error("{} SCRIPT COMPILE ERROR {}", GetContextName(realContext), error);
@@ -247,11 +306,10 @@ template <ScriptContext context> void ScriptCompileErrorHook(void* sqvm, const c
// dont call the original function since it kills game lol
}
-template <ScriptContext context> int64_t (*RegisterSquirrelFunction)(CSquirrelVM* sqvm, SQFuncRegistration* funcReg, char unknown);
+template <ScriptContext context> int64_t(*RegisterSquirrelFunction)(CSquirrelVM* sqvm, SQFuncRegistration* funcReg, char unknown);
template <ScriptContext context> int64_t RegisterSquirrelFunctionHook(CSquirrelVM* sqvm, SQFuncRegistration* funcReg, char unknown)
{
-
- if (context == ScriptContext::CLIENT && sqvm == g_pSquirrel<ScriptContext::UI>->SquirrelVM)
+ if (IsUIVM(context, sqvm->sqvm))
{
if (g_pSquirrel<ScriptContext::UI>->m_funcOverrides.count(funcReg->squirrelFuncName))
{
@@ -263,7 +321,7 @@ template <ScriptContext context> int64_t RegisterSquirrelFunctionHook(CSquirrelV
return g_pSquirrel<ScriptContext::UI>->RegisterSquirrelFunc(sqvm, funcReg, unknown);
}
- if (g_pSquirrel<context>->m_funcOverrides.count(funcReg->squirrelFuncName))
+ if (g_pSquirrel<context>->m_funcOverrides.find(funcReg->squirrelFuncName) != g_pSquirrel<context>->m_funcOverrides.end())
{
g_pSquirrel<context>->m_funcOriginals[funcReg->squirrelFuncName] = funcReg->funcPtr;
funcReg->funcPtr = g_pSquirrel<context>->m_funcOverrides[funcReg->squirrelFuncName];
@@ -276,7 +334,6 @@ template <ScriptContext context> int64_t RegisterSquirrelFunctionHook(CSquirrelV
template <ScriptContext context> bool (*CallScriptInitCallback)(void* sqvm, const char* callback);
template <ScriptContext context> bool CallScriptInitCallbackHook(void* sqvm, const char* callback)
{
-
ScriptContext realContext = context;
bool bShouldCallCustomCallbacks = true;
@@ -346,21 +403,43 @@ template <ScriptContext context> void ConCommand_script(const CCommand& args)
g_pSquirrel<context>->ExecuteCode(args.ArgS());
}
-SQRESULT SQ_Stub(HSquirrelVM* sqvm)
+// literal class type that wraps a constant expression string
+template <size_t N> struct TemplateStringLiteral
+{
+ constexpr TemplateStringLiteral(const char (&str)[N])
+ {
+ std::copy_n(str, N, value);
+ }
+
+ char value[N];
+};
+
+template <ScriptContext context, TemplateStringLiteral funcName> SQRESULT SQ_StubbedFunc(HSquirrelVM* sqvm)
{
- spdlog::info("Stubbed Function called");
+ spdlog::info("Blocking call to stubbed function {} in {}", funcName.value, GetContextName(context));
return SQRESULT_NULL;
}
+template <ScriptContext context> void StubUnsafeSQFuncs()
+{
+ if (!Tier0::CommandLine()->CheckParm("-allowunsafesqfuncs"))
+ {
+ g_pSquirrel<context>->AddFuncOverride("DevTextBufferWrite", SQ_StubbedFunc<context, "DevTextBufferWrite">);
+ g_pSquirrel<context>->AddFuncOverride("DevTextBufferClear", SQ_StubbedFunc<context, "DevTextBufferClear">);
+ g_pSquirrel<context>->AddFuncOverride("DevTextBufferDumpToFile", SQ_StubbedFunc<context, "DevTextBufferDumpToFile">);
+ g_pSquirrel<context>->AddFuncOverride("Dev_CommandLineAddParam", SQ_StubbedFunc<context, "Dev_CommandLineAddParam">);
+ g_pSquirrel<context>->AddFuncOverride("DevP4Checkout", SQ_StubbedFunc<context, "DevP4Checkout">);
+ g_pSquirrel<context>->AddFuncOverride("DevP4Add", SQ_StubbedFunc<context, "DevP4Add">);
+ }
+}
+
ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module))
{
AUTOHOOK_DISPATCH_MODULE(client.dll)
g_pSquirrel<ScriptContext::CLIENT> = new SquirrelManager<ScriptContext::CLIENT>;
g_pSquirrel<ScriptContext::UI> = new SquirrelManager<ScriptContext::UI>;
-
- // g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc = module.Offset(0x108E0).As<RegisterSquirrelFuncType>();
- // g_pSquirrel<ScriptContext::UI>->RegisterSquirrelFunc = g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc;
+
g_pSquirrel<ScriptContext::CLIENT>->__sq_defconst = module.Offset(0x12120).As<sq_defconstType>();
g_pSquirrel<ScriptContext::UI>->__sq_defconst = g_pSquirrel<ScriptContext::CLIENT>->__sq_defconst;
@@ -419,6 +498,12 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::UI>->__sq_createuserdata = g_pSquirrel<ScriptContext::CLIENT>->__sq_createuserdata;
g_pSquirrel<ScriptContext::UI>->__sq_setuserdatatypeid = g_pSquirrel<ScriptContext::CLIENT>->__sq_setuserdatatypeid;
+ MAKEHOOK(
+ module.Offset(0x108E0),
+ &RegisterSquirrelFunctionHook<ScriptContext::CLIENT>,
+ &g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc);
+ g_pSquirrel<ScriptContext::UI>->RegisterSquirrelFunc = g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc;
+
// uiscript_reset concommand: don't loop forever if compilation fails
module.Offset(0x3C6E4C).NOP(6);
@@ -431,31 +516,16 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module))
MAKEHOOK(module.Offset(0x26E70), &DestroyVMHook<ScriptContext::CLIENT>, &DestroyVM<ScriptContext::CLIENT>);
MAKEHOOK(module.Offset(0x79A50), &ScriptCompileErrorHook<ScriptContext::CLIENT>, &SQCompileError<ScriptContext::CLIENT>);
- MAKEHOOK(module.Offset(0x10190), &CallScriptInitCallbackHook<ScriptContext::CLIENT>, &CallScriptInitCallback<ScriptContext::CLIENT>);
-
MAKEHOOK(
- module.Offset(0x108E0),
- &RegisterSquirrelFunctionHook<ScriptContext::CLIENT>,
- &g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc);
-
- g_pSquirrel<ScriptContext::UI>->RegisterSquirrelFunc = g_pSquirrel<ScriptContext::CLIENT>->RegisterSquirrelFunc;
+ module.Offset(0x10190),
+ &CallScriptInitCallbackHook<ScriptContext::CLIENT>,
+ &CallScriptInitCallback<ScriptContext::CLIENT>);
RegisterConCommand("script_client", ConCommand_script<ScriptContext::CLIENT>, "Executes script code on the client vm", FCVAR_CLIENTDLL);
RegisterConCommand("script_ui", ConCommand_script<ScriptContext::UI>, "Executes script code on the ui vm", FCVAR_CLIENTDLL);
- g_pSquirrel<ScriptContext::CLIENT>->AddFuncOverride("DevTextBufferWrite", SQ_Stub);
- g_pSquirrel<ScriptContext::CLIENT>->AddFuncOverride("DevTextBufferClear", SQ_Stub);
- g_pSquirrel<ScriptContext::CLIENT>->AddFuncOverride("DevTextBufferDumpToFile", SQ_Stub);
- g_pSquirrel<ScriptContext::CLIENT>->AddFuncOverride("Dev_CommandLineAddParam", SQ_Stub);
- g_pSquirrel<ScriptContext::CLIENT>->AddFuncOverride("DevP4Checkout", SQ_Stub);
- g_pSquirrel<ScriptContext::CLIENT>->AddFuncOverride("DevP4Add", SQ_Stub);
-
- g_pSquirrel<ScriptContext::UI>->AddFuncOverride("DevTextBufferWrite", SQ_Stub);
- g_pSquirrel<ScriptContext::UI>->AddFuncOverride("DevTextBufferClear", SQ_Stub);
- g_pSquirrel<ScriptContext::UI>->AddFuncOverride("DevTextBufferDumpToFile", SQ_Stub);
- g_pSquirrel<ScriptContext::UI>->AddFuncOverride("Dev_CommandLineAddParam", SQ_Stub);
- g_pSquirrel<ScriptContext::UI>->AddFuncOverride("DevP4Checkout", SQ_Stub);
- g_pSquirrel<ScriptContext::UI>->AddFuncOverride("DevP4Add", SQ_Stub);
+ StubUnsafeSQFuncs<ScriptContext::CLIENT>();
+ StubUnsafeSQFuncs<ScriptContext::UI>();
}
ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
@@ -464,7 +534,6 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::SERVER> = new SquirrelManager<ScriptContext::SERVER>;
- // g_pSquirrel<ScriptContext::SERVER>->RegisterSquirrelFunc = module.Offset(0x1DD10).As<RegisterSquirrelFuncType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_defconst = module.Offset(0x1F550).As<sq_defconstType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_compilebuffer = module.Offset(0x3110).As<sq_compilebufferType>();
@@ -497,6 +566,11 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
g_pSquirrel<ScriptContext::SERVER>->__sq_createuserdata = module.Offset(0x38D0).As<sq_createuserdataType>();
g_pSquirrel<ScriptContext::SERVER>->__sq_setuserdatatypeid = module.Offset(0x6470).As<sq_setuserdatatypeidType>();
+ MAKEHOOK(
+ module.Offset(0x1DD10),
+ &RegisterSquirrelFunctionHook<ScriptContext::SERVER>,
+ &g_pSquirrel<ScriptContext::SERVER>->RegisterSquirrelFunc);
+
MAKEHOOK(module.Offset(0x8AA0), &sq_compiler_createHook<ScriptContext::SERVER>, &sq_compiler_create<ScriptContext::SERVER>);
MAKEHOOK(module.Offset(0x1FE90), &SQPrintHook<ScriptContext::SERVER>, &SQPrint<ScriptContext::SERVER>);
@@ -505,11 +579,6 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
MAKEHOOK(module.Offset(0x799E0), &ScriptCompileErrorHook<ScriptContext::SERVER>, &SQCompileError<ScriptContext::SERVER>);
MAKEHOOK(module.Offset(0x1D5C0), &CallScriptInitCallbackHook<ScriptContext::SERVER>, &CallScriptInitCallback<ScriptContext::SERVER>);
- MAKEHOOK(
- module.Offset(0x1DD10),
- &RegisterSquirrelFunctionHook<ScriptContext::SERVER>,
- &g_pSquirrel<ScriptContext::SERVER>->RegisterSquirrelFunc);
-
// FCVAR_CHEAT and FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS allows clients to execute this, but since it's unsafe we only allow it when cheats
// are enabled for script_client and script_ui, we don't use cheats, so clients can execute them on themselves all they want
RegisterConCommand(
@@ -518,62 +587,5 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module))
"Executes script code on the server vm",
FCVAR_GAMEDLL | FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS | FCVAR_CHEAT);
- g_pSquirrel<ScriptContext::SERVER>->AddFuncOverride("DevTextBufferWrite", SQ_Stub);
- g_pSquirrel<ScriptContext::SERVER>->AddFuncOverride("DevTextBufferClear", SQ_Stub);
- g_pSquirrel<ScriptContext::SERVER>->AddFuncOverride("DevTextBufferDumpToFile", SQ_Stub);
- g_pSquirrel<ScriptContext::SERVER>->AddFuncOverride("Dev_CommandLineAddParam", SQ_Stub);
- g_pSquirrel<ScriptContext::SERVER>->AddFuncOverride("DevP4Checkout", SQ_Stub);
- g_pSquirrel<ScriptContext::SERVER>->AddFuncOverride("DevP4Add", SQ_Stub);
+ StubUnsafeSQFuncs<ScriptContext::SERVER>();
}
-
-const char* SQTypeNameFromID(int type)
-{
- switch (type)
- {
- case OT_ASSET:
- return "asset";
- case OT_INTEGER:
- return "int";
- case OT_BOOL:
- return "bool";
- case SQOBJECT_NUMERIC:
- return "float or int";
- case OT_NULL:
- return "null";
- case OT_VECTOR:
- return "vector";
- case 0:
- return "var";
- case OT_USERDATA:
- return "userdata";
- case OT_FLOAT:
- return "float";
- case OT_STRING:
- return "string";
- case OT_ARRAY:
- return "array";
- case 0x8000200:
- return "function";
- case 0x8100000:
- return "structdef";
- case OT_THREAD:
- return "thread";
- case OT_FUNCPROTO:
- return "function";
- case OT_CLAAS:
- return "class";
- case OT_WEAKREF:
- return "weakref";
- case 0x8080000:
- return "unimplemented function";
- case 0x8200000:
- return "struct instance";
- case OT_TABLE:
- return "table";
- case 0xA008000:
- return "instance";
- case OT_ENTITY:
- return "entity";
- }
- return "";
-} \ No newline at end of file