From 80428e6f62899162c036f2752edfbfd7d1adb80b Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sun, 25 Jul 2021 18:19:26 +0100 Subject: add custom native script function support --- NorthstarDedicatedTest/squirrel.cpp | 65 ++++++++++++++++++++++++++++++--- NorthstarDedicatedTest/squirrel.h | 72 +++++++++++++++++++++++++++++++++---- 2 files changed, 127 insertions(+), 10 deletions(-) diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index addb8862..15c144c5 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -43,6 +43,9 @@ sq_pushroottableType ServerSq_pushroottable; sq_callType ClientSq_call; sq_callType ServerSq_call; +RegisterSquirrelFuncType ClientRegisterSquirrelFunc; +RegisterSquirrelFuncType ServerRegisterSquirrelFunc; + template void ExecuteCodeCommand(const CCommand& args); // inits @@ -50,24 +53,32 @@ SquirrelManager* g_ClientSquirrelManager; SquirrelManager* g_ServerSquirrelManager; SquirrelManager* g_UISquirrelManager; +SQInteger NSTestFunc(void* sqvm) +{ + return 1; +} + void InitialiseClientSquirrel(HMODULE baseAddress) { HookEnabler hook; // client inits g_ClientSquirrelManager = new SquirrelManager(); + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x12B00, &SQPrintHook, reinterpret_cast(&ClientSQPrint)); // client print function - RegisterConCommand("script_client", ExecuteCodeCommand, "Executes script code in the client vm", FCVAR_CLIENTDLL); + RegisterConCommand("script_client", ExecuteCodeCommand, "Executes script code on the client vm", FCVAR_CLIENTDLL); // ui inits g_UISquirrelManager = new SquirrelManager(); + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x12BA0, &SQPrintHook, reinterpret_cast(&UISQPrint)); // ui print function - RegisterConCommand("script_ui", ExecuteCodeCommand, "Executes script code in the client vm", FCVAR_CLIENTDLL); + RegisterConCommand("script_ui", ExecuteCodeCommand, "Executes script code on the ui vm", FCVAR_CLIENTDLL); // inits for both client and ui, since they share some functions ClientSq_compilebuffer = (sq_compilebufferType)((char*)baseAddress + 0x3110); ClientSq_pushroottable = (sq_pushroottableType)((char*)baseAddress + 0x5860); ClientSq_call = (sq_callType)((char*)baseAddress + 0x8650); + ClientRegisterSquirrelFunc = (RegisterSquirrelFuncType)((char*)baseAddress + 0x108E0); ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26130, &CreateNewVMHook, reinterpret_cast(&ClientCreateNewVM)); // client createnewvm function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E70, &DestroyVMHook, reinterpret_cast(&ClientDestroyVM)); // client destroyvm function @@ -84,13 +95,14 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ServerSq_compilebuffer = (sq_compilebufferType)((char*)baseAddress + 0x3110); ServerSq_pushroottable = (sq_pushroottableType)((char*)baseAddress + 0x5840); ServerSq_call = (sq_callType)((char*)baseAddress + 0x8620); + ServerRegisterSquirrelFunc = (RegisterSquirrelFuncType)((char*)baseAddress + 0x1DDD10); ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FE90, &SQPrintHook, reinterpret_cast(&ServerSQPrint)); // server print function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x260E0, &CreateNewVMHook, reinterpret_cast(&ServerCreateNewVM)); // server createnewvm function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E20, &DestroyVMHook, reinterpret_cast(&ServerDestroyVM)); // server destroyvm function ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x799E0, &ScriptCompileErrorHook, reinterpret_cast(&ServerSQCompileError)); // server compileerror function - RegisterConCommand("script", ExecuteCodeCommand, "Executes script code in the server vm", FCVAR_GAMEDLL); + RegisterConCommand("script", ExecuteCodeCommand, "Executes script code on the server vm", FCVAR_GAMEDLL); } // hooks @@ -244,7 +256,52 @@ template char CallScriptInitCallbackHook(void* sqvm, const char } else if (context == SERVER) { - // todo lol + // since we don't hook arbitrary callbacks yet, make sure we're only doing callbacks on inits + bool shouldCallCustomCallbacks = !strcmp(callback, "CodeCallback_MapSpawn"); + + // run before callbacks + // todo: we need to verify if RunOn is valid for current state before calling callbacks + if (shouldCallCustomCallbacks) + { + for (Mod* mod : g_ModManager->m_loadedMods) + { + for (ModScript* script : mod->Scripts) + { + for (ModScriptCallback* modCallback : script->Callbacks) + { + if (modCallback->Context == SERVER && modCallback->BeforeCallback.length()) + { + spdlog::info("Running custom {} script callback \"{}\"", GetContextName(context), modCallback->BeforeCallback); + ServerCallScriptInitCallback(sqvm, modCallback->BeforeCallback.c_str()); + } + } + } + } + } + + spdlog::info("{} CodeCallback {} called", GetContextName(context), callback); + if (!shouldCallCustomCallbacks) + spdlog::info("Not executing custom callbacks for CodeCallback {}", callback); + ret = ServerCallScriptInitCallback(sqvm, callback); + + // run after callbacks + if (shouldCallCustomCallbacks) + { + for (Mod* mod : g_ModManager->m_loadedMods) + { + for (ModScript* script : mod->Scripts) + { + for (ModScriptCallback* modCallback : script->Callbacks) + { + if (modCallback->Context == SERVER && modCallback->AfterCallback.length()) + { + spdlog::info("Running custom {} script callback \"{}\"", GetContextName(context), modCallback->AfterCallback); + ClientCallScriptInitCallback(sqvm, modCallback->AfterCallback.c_str()); + } + } + } + } + } } return ret; diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h index 43f6cef8..2704dbc7 100644 --- a/NorthstarDedicatedTest/squirrel.h +++ b/NorthstarDedicatedTest/squirrel.h @@ -26,6 +26,33 @@ struct CompileBufferState } }; +struct SQFuncRegistration +{ + const char* squirrelFuncName; + const char* cppFuncName; + const char* helpText; + const char* returnValueType; + const char* argTypes; + int16_t somethingThatsZero; + int16_t padding1; + int32_t unknown1; + int64_t unknown2; + int32_t unknown3; + int32_t padding2; + int64_t unknown4; + int64_t unknown5; + int64_t unknown6; + int32_t unknown7; + int32_t padding3; + void* funcPtr; + + SQFuncRegistration() + { + memset(this, 0, sizeof(SQFuncRegistration)); + this->padding2 = 32; + } +}; + typedef SQRESULT(*sq_compilebufferType)(void* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, int a2); extern sq_compilebufferType ClientSq_compilebuffer; extern sq_compilebufferType ServerSq_compilebuffer; @@ -38,22 +65,41 @@ typedef SQRESULT(*sq_callType)(void* sqvm, SQInteger s1, SQBool a2, SQBool a3); extern sq_callType ClientSq_call; extern sq_callType ServerSq_call; +typedef int64_t(*RegisterSquirrelFuncType)(void* sqvm, SQFuncRegistration* funcReg, char unknown); +extern RegisterSquirrelFuncType ClientRegisterSquirrelFunc; +extern RegisterSquirrelFuncType ServerRegisterSquirrelFunc; + //template void ExecuteSQCode(SquirrelManager sqManager, const char* code); // need this because we can't do template class functions in the .cpp file typedef SQInteger(*SQFunction)(void* sqvm); template class SquirrelManager { +private: + std::vector m_funcRegistrations; + public: void* sqvm; + void* sqvm2; public: SquirrelManager() : sqvm(nullptr) {} - void VMCreated(void* sqvm) + void VMCreated(void* newSqvm) { - sqvm = sqvm; + sqvm = newSqvm; + sqvm2 = *((void**)((char*)sqvm + 8)); // honestly not 100% sure on what this is, but alot of functions take it + + for (SQFuncRegistration* funcReg : m_funcRegistrations) + { + spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName); + + if (context == CLIENT || context == UI) + ClientRegisterSquirrelFunc(sqvm, funcReg, 1); + else + ServerRegisterSquirrelFunc(sqvm, funcReg, 1); + } } void VMDestroyed() @@ -71,9 +117,6 @@ public: return; } - void* sqvm2 = *((void**)((char*)sqvm + 8)); // honestly not 100% sure on what this is, but it seems to be what this function is supposed to take - // potentially move to a property later if it's used alot - spdlog::info("Executing {} script code {} ", GetContextName(context), code); std::string strCode(code); @@ -105,7 +148,24 @@ public: void AddFuncRegistration(std::string returnType, std::string name, std::string argTypes, std::string helpText, SQFunction func) { - + SQFuncRegistration* reg = new SQFuncRegistration; + + reg->squirrelFuncName = new char[name.size() + 1]; + strcpy((char*)reg->squirrelFuncName, name.c_str()); + reg->cppFuncName = reg->squirrelFuncName; + + reg->helpText = new char[helpText.size() + 1]; + strcpy((char*)reg->helpText, helpText.c_str()); + + reg->returnValueType = new char[returnType.size() + 1]; + strcpy((char*)reg->returnValueType, returnType.c_str()); + + reg->argTypes = new char[argTypes.size() + 1]; + strcpy((char*)reg->argTypes, argTypes.c_str()); + + reg->funcPtr = func; + + m_funcRegistrations.push_back(reg); } }; -- cgit v1.2.3