diff options
Diffstat (limited to 'NorthstarDLL/squirrel.cpp')
-rw-r--r-- | NorthstarDLL/squirrel.cpp | 250 |
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 |