diff options
author | Emma Miler <emma.pi@protonmail.com> | 2022-11-21 00:38:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-20 23:38:42 +0000 |
commit | 9e469ac28b610ecb8bce3e6c279660fae78861cf (patch) | |
tree | 57274f3be03cb160e42af7ed939274a2a028dbf0 | |
parent | 70b71ba3d3ad7121c6aabe55271542f55abe4008 (diff) | |
download | NorthstarLauncher-9e469ac28b610ecb8bce3e6c279660fae78861cf.tar.gz NorthstarLauncher-9e469ac28b610ecb8bce3e6c279660fae78861cf.zip |
Squirrel bridge v3 (#310)
* Initial
* Move squirrelmanager to virtual base class
* Implement changes from code review
* Formatting
* Update squirrel.cpp
* Formatting shit
* Fix filters
* Fix up
Use new squirrel autobind syntax
Move from `std::vector` to `std::queue` for message buffer
Add `NSTestMessageBuffer`
* Update squirrel.cpp
* Update squirrel.h
* Remove inline virtual final because this is stupid
I probably had a bit of a brain fart when this was written
* Moved to running ProcessMessages in-engine
* Remove TestMessageBuffer
* Formatting
* Rename pushSQObject -> pushobject
* Rename some stuff
* Update squirrel.h
* Formattting
* Remove unneeded global access
* Oops
-rw-r--r-- | NorthstarDLL/NorthstarDLL.vcxproj | 1 | ||||
-rw-r--r-- | NorthstarDLL/NorthstarDLL.vcxproj.filters | 3 | ||||
-rw-r--r-- | NorthstarDLL/clientchathooks.cpp | 35 | ||||
-rw-r--r-- | NorthstarDLL/hoststate.cpp | 11 | ||||
-rw-r--r-- | NorthstarDLL/scriptservertoclientstringcommand.cpp | 10 | ||||
-rw-r--r-- | NorthstarDLL/serverchathooks.cpp | 20 | ||||
-rw-r--r-- | NorthstarDLL/squirrel.cpp | 83 | ||||
-rw-r--r-- | NorthstarDLL/squirrel.h | 354 | ||||
-rw-r--r-- | NorthstarDLL/squirrelclasstypes.h | 239 | ||||
-rw-r--r-- | NorthstarDLL/squirreldatatypes.h | 19 |
10 files changed, 595 insertions, 180 deletions
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj b/NorthstarDLL/NorthstarDLL.vcxproj index c1532157..98e3e182 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj +++ b/NorthstarDLL/NorthstarDLL.vcxproj @@ -123,6 +123,7 @@ <ClInclude Include="crashhandler.h" />
<ClInclude Include="keyvalues.h" />
<ClInclude Include="loghooks.h" />
+ <ClInclude Include="squirrelclasstypes.h" />
<ClInclude Include="squirreldatatypes.h" />
<ClInclude Include="limits.h" />
<ClInclude Include="maxplayers.h" />
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj.filters b/NorthstarDLL/NorthstarDLL.vcxproj.filters index 8ff5f461..7e13234e 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj.filters +++ b/NorthstarDLL/NorthstarDLL.vcxproj.filters @@ -1499,6 +1499,9 @@ </ClInclude>
<ClInclude Include="loghooks.h">
<Filter>Header Files\Console</Filter>
+ </ClInclude>
+ <ClInclude Include="squirrelclasstypes.h">
+ <Filter>Header Files\Squirrel</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
diff --git a/NorthstarDLL/clientchathooks.cpp b/NorthstarDLL/clientchathooks.cpp index 1a25c897..847b5eb1 100644 --- a/NorthstarDLL/clientchathooks.cpp +++ b/NorthstarDLL/clientchathooks.cpp @@ -17,29 +17,22 @@ void, __fastcall, (void* self, const char* message, int inboxId, bool isTeam, bo if (self != *CHudChat::allHuds) return; - if (g_pSquirrel<ScriptContext::CLIENT>->setupfunc("CHudChat_ProcessMessageStartThread") != SQRESULT_ERROR) - { - int senderId = inboxId & CUSTOM_MESSAGE_INDEX_MASK; - bool isAnonymous = senderId == 0; - bool isCustom = isAnonymous || (inboxId & CUSTOM_MESSAGE_INDEX_BIT); - - // Type is set to 0 for non-custom messages, custom messages have a type encoded as the first byte - int type = 0; - const char* payload = message; - if (isCustom) - { - type = message[0]; - payload = message + 1; - } + int senderId = inboxId & CUSTOM_MESSAGE_INDEX_MASK; + bool isAnonymous = senderId == 0; + bool isCustom = isAnonymous || (inboxId & CUSTOM_MESSAGE_INDEX_BIT); - g_pSquirrel<ScriptContext::CLIENT>->pushinteger(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, (int)senderId - 1); - g_pSquirrel<ScriptContext::CLIENT>->pushstring(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, payload); - g_pSquirrel<ScriptContext::CLIENT>->pushbool(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, isTeam); - g_pSquirrel<ScriptContext::CLIENT>->pushbool(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, isDead); - g_pSquirrel<ScriptContext::CLIENT>->pushinteger(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, type); - g_pSquirrel<ScriptContext::CLIENT>->call(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, 5); + // Type is set to 0 for non-custom messages, custom messages have a type encoded as the first byte + int type = 0; + const char* payload = message; + if (isCustom) + { + type = message[0]; + payload = message + 1; } - else + + SQRESULT result = g_pSquirrel<ScriptContext::CLIENT>->Call( + "CHudChat_ProcessMessageStartThread", static_cast<int>(senderId) - 1, payload, isTeam, isDead, type); + if (result == SQRESULT_ERROR) for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) CHudChat__AddGameLine(hud, message, inboxId, isTeam, isDead); } diff --git a/NorthstarDLL/hoststate.cpp b/NorthstarDLL/hoststate.cpp index c36af20c..24e4bf63 100644 --- a/NorthstarDLL/hoststate.cpp +++ b/NorthstarDLL/hoststate.cpp @@ -7,6 +7,7 @@ #include "tier0.h" #include "r2engine.h" #include "limits.h" +#include "squirrel.h" AUTOHOOK_INIT() @@ -102,6 +103,16 @@ void, __fastcall, (CHostState* self, double flCurrentTime, float flFrameTime)) // update limits for frame g_pServerLimits->RunFrame(flCurrentTime, flFrameTime); } + + // Run Squirrel message buffer + if (g_pSquirrel<ScriptContext::UI>->m_pSQVM != nullptr && g_pSquirrel<ScriptContext::UI>->m_pSQVM->sqvm != nullptr) + g_pSquirrel<ScriptContext::UI>->ProcessMessageBuffer(); + + if (g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM != nullptr && g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm != nullptr) + g_pSquirrel<ScriptContext::CLIENT>->ProcessMessageBuffer(); + + if (g_pSquirrel<ScriptContext::SERVER>->m_pSQVM != nullptr && g_pSquirrel<ScriptContext::SERVER>->m_pSQVM->sqvm != nullptr) + g_pSquirrel<ScriptContext::SERVER>->ProcessMessageBuffer(); } ON_DLL_LOAD_RELIESON("engine.dll", HostState, ConVar, (CModule module)) diff --git a/NorthstarDLL/scriptservertoclientstringcommand.cpp b/NorthstarDLL/scriptservertoclientstringcommand.cpp index 5c116973..ac19c3af 100644 --- a/NorthstarDLL/scriptservertoclientstringcommand.cpp +++ b/NorthstarDLL/scriptservertoclientstringcommand.cpp @@ -5,14 +5,8 @@ void ConCommand_ns_script_servertoclientstringcommand(const CCommand& arg) { - if (g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM && - g_pSquirrel<ScriptContext::CLIENT>->setupfunc("NSClientCodeCallback_RecievedServerToClientStringCommand") != SQRESULT_ERROR) - { - g_pSquirrel<ScriptContext::CLIENT>->pushstring(g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, arg.ArgS()); - g_pSquirrel<ScriptContext::CLIENT>->call( - g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM->sqvm, - 1); // todo: doesn't throw or log errors from within this, probably not great behaviour - } + if (g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM) + g_pSquirrel<ScriptContext::CLIENT>->Call("NSClientCodeCallback_RecievedServerToClientStringCommand", arg.ArgS()); } ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ScriptServerToClientStringCommand, ClientSquirrel, (CModule module)) diff --git a/NorthstarDLL/serverchathooks.cpp b/NorthstarDLL/serverchathooks.cpp index d97f1ebf..e4e67e05 100644 --- a/NorthstarDLL/serverchathooks.cpp +++ b/NorthstarDLL/serverchathooks.cpp @@ -37,7 +37,7 @@ void(__fastcall* MessageWriteBool)(bool bValue); bool bShouldCallSayTextHook = false; // clang-format off AUTOHOOK(_CServerGameDLL__OnReceivedSayTextMessage, server.dll + 0x1595C0, -void, __fastcall, (CServerGameDLL* self, unsigned int nSenderPlayerIndex, const char* text, bool isTeam)) +void, __fastcall, (CServerGameDLL* self, unsigned int senderPlayerId, const char* text, bool isTeam)) // clang-format on { // MiniHook doesn't allow calling the base function outside of anywhere but the hook function. @@ -45,23 +45,19 @@ void, __fastcall, (CServerGameDLL* self, unsigned int nSenderPlayerIndex, const if (bShouldCallSayTextHook) { bShouldCallSayTextHook = false; - _CServerGameDLL__OnReceivedSayTextMessage(self, nSenderPlayerIndex, text, isTeam); + _CServerGameDLL__OnReceivedSayTextMessage(self, senderPlayerId, text, isTeam); return; } // check chat ratelimits - if (!g_pServerLimits->CheckChatLimits(&R2::g_pClientArray[nSenderPlayerIndex - 1])) + if (!g_pServerLimits->CheckChatLimits(&R2::g_pClientArray[senderPlayerId - 1])) return; - if (g_pSquirrel<ScriptContext::SERVER>->setupfunc("CServerGameDLL_ProcessMessageStartThread") != SQRESULT_ERROR) - { - g_pSquirrel<ScriptContext::SERVER>->pushinteger(g_pSquirrel<ScriptContext::SERVER>->m_pSQVM->sqvm, (int)nSenderPlayerIndex - 1); - g_pSquirrel<ScriptContext::SERVER>->pushstring(g_pSquirrel<ScriptContext::SERVER>->m_pSQVM->sqvm, text); - g_pSquirrel<ScriptContext::SERVER>->pushbool(g_pSquirrel<ScriptContext::SERVER>->m_pSQVM->sqvm, isTeam); - g_pSquirrel<ScriptContext::SERVER>->call(g_pSquirrel<ScriptContext::SERVER>->m_pSQVM->sqvm, 3); - } - else - _CServerGameDLL__OnReceivedSayTextMessage(self, nSenderPlayerIndex, text, isTeam); + SQRESULT result = g_pSquirrel<ScriptContext::SERVER>->Call( + "CServerGameDLL_ProcessMessageStartThread", static_cast<int>(senderPlayerId) - 1, text, isTeam); + + if (result == SQRESULT_ERROR) + _CServerGameDLL__OnReceivedSayTextMessage(self, senderPlayerId, text, isTeam); } void ChatSendMessage(unsigned int playerIndex, const char* text, bool isTeam) diff --git a/NorthstarDLL/squirrel.cpp b/NorthstarDLL/squirrel.cpp index c90b2d7f..673e2098 100644 --- a/NorthstarDLL/squirrel.cpp +++ b/NorthstarDLL/squirrel.cpp @@ -6,6 +6,8 @@ #include "r2engine.h" #include "tier0.h" +#include <any> + AUTOHOOK_INIT() std::shared_ptr<ColoredLogger> getSquirrelLoggerByContext(ScriptContext context) @@ -138,6 +140,25 @@ const char* SQTypeNameFromID(int type) return ""; } +// Allows for generating squirrelmessages from plugins. +// Not used in this version, but will be used later +void AsyncCall_External(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function) +{ + SquirrelMessage message {}; + message.functionName = func_name; + message.isExternal = true; + message.externalFunc = function; + switch (context) + { + case ScriptContext::CLIENT: + g_pSquirrel<ScriptContext::CLIENT>->messageBuffer->push(message); + case ScriptContext::SERVER: + g_pSquirrel<ScriptContext::SERVER>->messageBuffer->push(message); + case ScriptContext::UI: + g_pSquirrel<ScriptContext::UI>->messageBuffer->push(message); + } +} + // needed to define implementations for squirrelmanager outside of squirrel.h without compiler errors template class SquirrelManager<ScriptContext::SERVER>; template class SquirrelManager<ScriptContext::CLIENT>; @@ -156,6 +177,7 @@ template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquir for (auto& pair : g_pModManager->m_DependencyConstants) { bool bWasFound = false; + for (Mod& dependency : g_pModManager->m_LoadedMods) { if (!dependency.m_bEnabled) @@ -170,6 +192,7 @@ template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquir defconst(m_pSQVM, pair.first.c_str(), bWasFound); } + g_pSquirrel<context>->messageBuffer = new SquirrelMessageBuffer(); } template <ScriptContext context> void SquirrelManager<context>::VMDestroyed() @@ -196,7 +219,7 @@ template <ScriptContext context> void SquirrelManager<context>::ExecuteCode(cons if (compileResult != SQRESULT_ERROR) { pushroottable(m_pSQVM->sqvm); - SQRESULT callResult = call(m_pSQVM->sqvm, 0); + SQRESULT callResult = _call(m_pSQVM->sqvm, 0); spdlog::info("sq_call returned {}", PrintSQRESULT.at(callResult)); } } @@ -304,7 +327,10 @@ template <ScriptContext context> void __fastcall DestroyVMHook(void* a1, HSquirr g_pSquirrel<ScriptContext::UI>->VMDestroyed(); } else + { + g_pSquirrel<context>->m_pSQVM = nullptr; // Fixes a race-like bug DestroyVM<context>(a1, sqvm); + } spdlog::info("DestroyVM {} {}", GetContextName(realContext), (void*)sqvm); } @@ -482,6 +508,44 @@ template <ScriptContext context> void StubUnsafeSQFuncs() } } +template <ScriptContext context> void SquirrelManager<context>::ProcessMessageBuffer() +{ + auto maybeMessage = messageBuffer->pop(); + if (!maybeMessage) + { + return; + } + + SquirrelMessage message = maybeMessage.value(); + + SQObject functionobj {}; + int result = sq_getfunction(m_pSQVM->sqvm, message.functionName.c_str(), &functionobj, 0); + if (result != 0) // This func returns 0 on success for some reason + { + spdlog::error( + "ProcessMessageBuffer was unable to find function with name '{}' on {}. Is it global?", + message.functionName, + GetContextName(context)); + return; + } + pushobject(m_pSQVM->sqvm, &functionobj); // Push the function object + pushroottable(m_pSQVM->sqvm); + if (message.isExternal) + { + message.externalFunc(m_pSQVM->sqvm); + } + else + { + for (auto& v : message.args) + { + // Execute lambda to push arg to stack + v(); + } + } + + _call(m_pSQVM->sqvm, message.args.size()); +} + ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) { AUTOHOOK_DISPATCH_MODULE(client.dll) @@ -516,6 +580,7 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::CLIENT>->__sq_pushbool = module.Offset(0x3710).As<sq_pushboolType>(); g_pSquirrel<ScriptContext::CLIENT>->__sq_pushasset = module.Offset(0x3560).As<sq_pushassetType>(); g_pSquirrel<ScriptContext::CLIENT>->__sq_pushvector = module.Offset(0x3780).As<sq_pushvectorType>(); + g_pSquirrel<ScriptContext::CLIENT>->__sq_pushobject = module.Offset(0x83D0).As<sq_pushobjectType>(); g_pSquirrel<ScriptContext::CLIENT>->__sq_raiseerror = module.Offset(0x8470).As<sq_raiseerrorType>(); g_pSquirrel<ScriptContext::UI>->__sq_pushstring = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushstring; g_pSquirrel<ScriptContext::UI>->__sq_pushinteger = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushinteger; @@ -523,6 +588,7 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::UI>->__sq_pushbool = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushbool; g_pSquirrel<ScriptContext::UI>->__sq_pushvector = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushvector; g_pSquirrel<ScriptContext::UI>->__sq_pushasset = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushasset; + g_pSquirrel<ScriptContext::UI>->__sq_pushobject = g_pSquirrel<ScriptContext::CLIENT>->__sq_pushobject; g_pSquirrel<ScriptContext::UI>->__sq_raiseerror = g_pSquirrel<ScriptContext::CLIENT>->__sq_raiseerror; g_pSquirrel<ScriptContext::CLIENT>->__sq_getstring = module.Offset(0x60C0).As<sq_getstringType>(); @@ -533,8 +599,6 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::CLIENT>->__sq_getasset = module.Offset(0x6010).As<sq_getassetType>(); g_pSquirrel<ScriptContext::CLIENT>->__sq_getuserdata = module.Offset(0x63D0).As<sq_getuserdataType>(); g_pSquirrel<ScriptContext::CLIENT>->__sq_getvector = module.Offset(0x6140).As<sq_getvectorType>(); - g_pSquirrel<ScriptContext::CLIENT>->__sq_getthisentity = module.Offset(0x12F80).As<sq_getthisentityType>(); - g_pSquirrel<ScriptContext::CLIENT>->__sq_getobject = module.Offset(0x6160).As<sq_getobjectType>(); g_pSquirrel<ScriptContext::UI>->__sq_getstring = g_pSquirrel<ScriptContext::CLIENT>->__sq_getstring; g_pSquirrel<ScriptContext::UI>->__sq_getinteger = g_pSquirrel<ScriptContext::CLIENT>->__sq_getinteger; g_pSquirrel<ScriptContext::UI>->__sq_getfloat = g_pSquirrel<ScriptContext::CLIENT>->__sq_getfloat; @@ -557,6 +621,11 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::CLIENT>->__sq_GetEntityConstant_CBaseEntity; g_pSquirrel<ScriptContext::UI>->__sq_getentityfrominstance = g_pSquirrel<ScriptContext::CLIENT>->__sq_getentityfrominstance; + // Message buffer stuff + g_pSquirrel<ScriptContext::UI>->messageBuffer = g_pSquirrel<ScriptContext::CLIENT>->messageBuffer; + g_pSquirrel<ScriptContext::CLIENT>->__sq_getfunction = module.Offset(0x572FB0).As<sq_getfunctionType>(); + g_pSquirrel<ScriptContext::UI>->__sq_getfunction = g_pSquirrel<ScriptContext::CLIENT>->__sq_getfunction; + MAKEHOOK( module.Offset(0x108E0), &RegisterSquirrelFunctionHook<ScriptContext::CLIENT>, @@ -585,6 +654,9 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) StubUnsafeSQFuncs<ScriptContext::CLIENT>(); StubUnsafeSQFuncs<ScriptContext::UI>(); + + g_pSquirrel<ScriptContext::CLIENT>->__sq_getfunction = module.Offset(0x6CB0).As<sq_getfunctionType>(); + g_pSquirrel<ScriptContext::UI>->__sq_getfunction = g_pSquirrel<ScriptContext::CLIENT>->__sq_getfunction; } ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) @@ -611,6 +683,8 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::SERVER>->__sq_pushbool = module.Offset(0x3710).As<sq_pushboolType>(); g_pSquirrel<ScriptContext::SERVER>->__sq_pushasset = module.Offset(0x3560).As<sq_pushassetType>(); g_pSquirrel<ScriptContext::SERVER>->__sq_pushvector = module.Offset(0x3780).As<sq_pushvectorType>(); + g_pSquirrel<ScriptContext::SERVER>->__sq_pushobject = module.Offset(0x83A0).As<sq_pushobjectType>(); + g_pSquirrel<ScriptContext::SERVER>->__sq_raiseerror = module.Offset(0x8440).As<sq_raiseerrorType>(); g_pSquirrel<ScriptContext::SERVER>->__sq_getstring = module.Offset(0x60A0).As<sq_getstringType>(); @@ -621,6 +695,7 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::SERVER>->__sq_getuserdata = module.Offset(0x63B0).As<sq_getuserdataType>(); g_pSquirrel<ScriptContext::SERVER>->__sq_getvector = module.Offset(0x6120).As<sq_getvectorType>(); g_pSquirrel<ScriptContext::SERVER>->__sq_get = module.Offset(0x7C00).As<sq_getType>(); + g_pSquirrel<ScriptContext::SERVER>->__sq_getthisentity = module.Offset(0x203B0).As<sq_getthisentityType>(); g_pSquirrel<ScriptContext::SERVER>->__sq_getobject = module.Offset(0x6140).As<sq_getobjectType>(); @@ -631,6 +706,8 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) g_pSquirrel<ScriptContext::SERVER>->__sq_getentityfrominstance = module.Offset(0x1E920).As<sq_getentityfrominstanceType>(); g_pSquirrel<ScriptContext::SERVER>->logger = NS::log::SCRIPT_SV; + // Message buffer stuff + g_pSquirrel<ScriptContext::SERVER>->__sq_getfunction = module.Offset(0x6C85).As<sq_getfunctionType>(); MAKEHOOK( module.Offset(0x1DD10), diff --git a/NorthstarDLL/squirrel.h b/NorthstarDLL/squirrel.h index 6142b157..626d4f12 100644 --- a/NorthstarDLL/squirrel.h +++ b/NorthstarDLL/squirrel.h @@ -1,6 +1,6 @@ #pragma once -#include "squirreldatatypes.h" +#include "squirrelclasstypes.h" #include "squirrelautobind.h" #include "vector.h" @@ -11,78 +11,6 @@ typedef unsigned long SQUnsignedInteger; typedef char SQChar; typedef SQUnsignedInteger SQBool; -enum SQRESULT : SQInteger -{ - SQRESULT_ERROR = -1, - SQRESULT_NULL = 0, - SQRESULT_NOTNULL = 1, -}; - -typedef SQRESULT (*SQFunction)(HSquirrelVM* sqvm); - -enum class eSQReturnType -{ - Float = 0x1, - Vector = 0x3, - Integer = 0x5, - Boolean = 0x6, - Entity = 0xD, - String = 0x21, - Default = 0x20, - Arrays = 0x25, - Asset = 0x28, - Table = 0x26, -}; - -const std::map<SQRESULT, const char*> PrintSQRESULT = { - {SQRESULT_ERROR, "SQRESULT_ERROR"}, {SQRESULT_NULL, "SQRESULT_NULL"}, {SQRESULT_NOTNULL, "SQRESULT_NOTNULL"}}; - -struct CompileBufferState -{ - const SQChar* buffer; - const SQChar* bufferPlusLength; - const SQChar* bufferAgain; - - CompileBufferState(const std::string& code) - { - buffer = code.c_str(); - bufferPlusLength = code.c_str() + code.size(); - bufferAgain = code.c_str(); - } -}; - -struct SQFuncRegistration -{ - const char* squirrelFuncName; - const char* cppFuncName; - const char* helpText; - const char* returnTypeString; - const char* argTypes; - uint32_t unknown1; - uint32_t devLevel; - const char* shortNameMaybe; - uint32_t unknown2; - eSQReturnType returnType; - uint32_t* externalBufferPointer; - uint64_t externalBufferSize; - uint64_t unknown3; - uint64_t unknown4; - SQFunction funcPtr; - - SQFuncRegistration() - { - memset(this, 0, sizeof(SQFuncRegistration)); - this->returnType = eSQReturnType::Default; - } -}; - -enum class ScriptContext : int -{ - SERVER, - CLIENT, - UI, -}; - static constexpr int operator&(ScriptContext first, ScriptContext second) { return first == second; @@ -108,55 +36,13 @@ const char* GetContextName_Short(ScriptContext context); eSQReturnType SQReturnTypeFromString(const char* pReturnType); const char* SQTypeNameFromID(const int iTypeId); -// core sqvm funcs -typedef int64_t (*RegisterSquirrelFuncType)(CSquirrelVM* sqvm, SQFuncRegistration* funcReg, char unknown); -typedef void (*sq_defconstType)(CSquirrelVM* sqvm, const SQChar* name, int value); - -typedef SQRESULT (*sq_compilebufferType)( - HSquirrelVM* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, SQBool bShouldThrowError); -typedef SQRESULT (*sq_callType)(HSquirrelVM* sqvm, SQInteger iArgs, SQBool bShouldReturn, SQBool bThrowError); -typedef SQInteger (*sq_raiseerrorType)(HSquirrelVM* sqvm, const SQChar* pError); - -// sq stack array funcs -typedef void (*sq_newarrayType)(HSquirrelVM* sqvm, SQInteger iStackpos); -typedef SQRESULT (*sq_arrayappendType)(HSquirrelVM* sqvm, SQInteger iStackpos); - -// sq table funcs -typedef SQRESULT (*sq_newtableType)(HSquirrelVM* sqvm); -typedef SQRESULT (*sq_newslotType)(HSquirrelVM* sqvm, SQInteger idx, SQBool bStatic); - -// sq stack push funcs -typedef void (*sq_pushroottableType)(HSquirrelVM* sqvm); -typedef void (*sq_pushstringType)(HSquirrelVM* sqvm, const SQChar* pStr, SQInteger iLength); -typedef void (*sq_pushintegerType)(HSquirrelVM* sqvm, SQInteger i); -typedef void (*sq_pushfloatType)(HSquirrelVM* sqvm, SQFloat f); -typedef void (*sq_pushboolType)(HSquirrelVM* sqvm, SQBool b); -typedef void (*sq_pushassetType)(HSquirrelVM* sqvm, const SQChar* str, SQInteger iLength); -typedef void (*sq_pushvectorType)(HSquirrelVM* sqvm, const SQFloat* pVec); - -// sq stack get funcs -typedef const SQChar* (*sq_getstringType)(HSquirrelVM* sqvm, SQInteger iStackpos); -typedef SQInteger (*sq_getintegerType)(HSquirrelVM* sqvm, SQInteger iStackpos); -typedef SQFloat (*sq_getfloatType)(HSquirrelVM*, SQInteger iStackpos); -typedef SQBool (*sq_getboolType)(HSquirrelVM*, SQInteger iStackpos); -typedef SQRESULT (*sq_getType)(HSquirrelVM* sqvm, SQInteger iStackpos); -typedef SQRESULT (*sq_getassetType)(HSquirrelVM* sqvm, SQInteger iStackpos, const char** pResult); -typedef SQRESULT (*sq_getuserdataType)(HSquirrelVM* sqvm, SQInteger iStackpos, void** pData, uint64_t* pTypeId); -typedef SQFloat* (*sq_getvectorType)(HSquirrelVM* sqvm, SQInteger iStackpos); -typedef SQBool (*sq_getthisentityType)(HSquirrelVM*, void** ppEntity); -typedef void (*sq_getobjectType)(HSquirrelVM*, SQInteger iStackPos, SQObject* pOutObj); - -// sq stack userpointer funcs -typedef void* (*sq_createuserdataType)(HSquirrelVM* sqvm, SQInteger iSize); -typedef SQRESULT (*sq_setuserdatatypeidType)(HSquirrelVM* sqvm, SQInteger iStackpos, uint64_t iTypeId); - -// sq misc entity funcs -typedef void* (*sq_getentityfrominstanceType)(CSquirrelVM* sqvm, SQObject* pInstance, char** ppEntityConstant); -typedef char** (*sq_GetEntityConstantType)(); - -template <ScriptContext context> class SquirrelManager +void schedule_call_external(ScriptContext context, const char* func_name, SquirrelMessage_External_Pop function); + +// This base class means that only the templated functions have to be rebuilt for each template instance +// Cuts down on compile time by ~5 seconds +class SquirrelManagerBase { - private: + protected: std::vector<SQFuncRegistration*> m_funcRegistrations; public: @@ -189,6 +75,7 @@ template <ScriptContext context> class SquirrelManager sq_pushboolType __sq_pushbool; sq_pushassetType __sq_pushasset; sq_pushvectorType __sq_pushvector; + sq_pushobjectType __sq_pushobject; sq_getstringType __sq_getstring; sq_getintegerType __sq_getinteger; @@ -203,20 +90,12 @@ template <ScriptContext context> class SquirrelManager sq_createuserdataType __sq_createuserdata; sq_setuserdatatypeidType __sq_setuserdatatypeid; + sq_getfunctionType __sq_getfunction; sq_getentityfrominstanceType __sq_getentityfrominstance; sq_GetEntityConstantType __sq_GetEntityConstant_CBaseEntity; -#pragma endregion - public: - SquirrelManager() : m_pSQVM(nullptr) {} - - void VMCreated(CSquirrelVM* newSqvm); - void VMDestroyed(); - void ExecuteCode(const char* code); - void AddFuncRegistration(std::string returnType, std::string name, std::string argTypes, std::string helpText, SQFunction func); - SQRESULT setupfunc(const SQChar* funcname); - void AddFuncOverride(std::string name, SQFunction func); +#pragma endregion #pragma region SQVM func wrappers inline void defconst(CSquirrelVM* sqvm, const SQChar* pName, int nValue) @@ -230,7 +109,7 @@ template <ScriptContext context> class SquirrelManager return __sq_compilebuffer(m_pSQVM->sqvm, bufferState, bufferName, -1, bShouldThrowError); } - inline SQRESULT call(HSquirrelVM* sqvm, const SQInteger args) + inline SQRESULT _call(HSquirrelVM* sqvm, const SQInteger args) { return __sq_call(sqvm, args + 1, false, false); } @@ -295,6 +174,11 @@ template <ScriptContext context> class SquirrelManager __sq_pushvector(sqvm, *(float**)&pVal); } + inline void pushobject(HSquirrelVM* sqvm, SQObject* obj) + { + __sq_pushobject(sqvm, obj); + } + inline const SQChar* getstring(HSquirrelVM* sqvm, const SQInteger stackpos) { return __sq_getstring(sqvm, stackpos); @@ -326,6 +210,11 @@ template <ScriptContext context> class SquirrelManager return *(Vector3*)&pRet; } + inline int sq_getfunction(HSquirrelVM* sqvm, const char* name, SQObject* returnObj, const char* signature) + { + return __sq_getfunction(sqvm, name, returnObj, signature); + } + inline SQRESULT getasset(HSquirrelVM* sqvm, const SQInteger stackpos, const char** result) { return __sq_getasset(sqvm, stackpos, result); @@ -364,4 +253,205 @@ template <ScriptContext context> class SquirrelManager #pragma endregion }; +template <ScriptContext context> class SquirrelManager : public virtual SquirrelManagerBase +{ + public: +#pragma region MessageBuffer + SquirrelMessageBuffer* messageBuffer; + + template <typename... Args> SquirrelMessage AsyncCall(std::string funcname, Args... args) + { + // This function schedules a call to be executed on the next frame + // This is useful for things like threads and plugins, which do not run on the main thread + FunctionVector functionVector; + SqRecurseArgs<context>(functionVector, args...); + SquirrelMessage message = {funcname, functionVector}; + messageBuffer->push(message); + return message; + } + + SquirrelMessage AsyncCall(std::string funcname) + { + // This function schedules a call to be executed on the next frame + // This is useful for things like threads and plugins, which do not run on the main thread + FunctionVector functionVector = {}; + SquirrelMessage message = {funcname, functionVector}; + messageBuffer->push(message); + return message; + } + + SQRESULT Call(const char* funcname) + { + // Warning! + // This function assumes the squirrel VM is stopped/blocked at the moment of call + // Calling this function while the VM is running is likely to result in a crash due to stack destruction + // If you want to call into squirrel asynchronously, use `AsyncCall` instead + + if (!m_pSQVM || !m_pSQVM->sqvm) + { + spdlog::error( + "{} was called on context {} while VM was not initialized. This will crash", __FUNCTION__, GetContextName(context)); + } + + SQObject functionobj {}; + int result = sq_getfunction(m_pSQVM->sqvm, funcname, &functionobj, 0); + if (result != 0) // This func returns 0 on success for some reason + { + return SQRESULT_ERROR; + } + pushobject(m_pSQVM->sqvm, &functionobj); // Push the function object + pushroottable(m_pSQVM->sqvm); // Push root table + return _call(m_pSQVM->sqvm, 0); + } + + template <typename... Args> SQRESULT Call(const char* funcname, Args... args) + { + // Warning! + // This function assumes the squirrel VM is stopped/blocked at the moment of call + // Calling this function while the VM is running is likely to result in a crash due to stack destruction + // If you want to call into squirrel asynchronously, use `schedule_call` instead + if (!m_pSQVM || !m_pSQVM->sqvm) + { + spdlog::error( + "{} was called on context {} while VM was not initialized. This will crash", __FUNCTION__, GetContextName(context)); + } + SQObject functionobj {}; + int result = sq_getfunction(m_pSQVM->sqvm, funcname, &functionobj, 0); + if (result != 0) // This func returns 0 on success for some reason + { + return SQRESULT_ERROR; + } + pushobject(m_pSQVM->sqvm, &functionobj); // Push the function object + pushroottable(m_pSQVM->sqvm); // Push root table + + FunctionVector functionVector; + SqRecurseArgs<context>(functionVector, args...); + + for (auto& v : functionVector) + { + // Execute lambda to push arg to stack + v(); + } + + return _call(m_pSQVM->sqvm, functionVector.size()); + } + +#pragma endregion + + public: + SquirrelManager() + { + m_pSQVM = nullptr; + } + + void VMCreated(CSquirrelVM* newSqvm); + void VMDestroyed(); + void ExecuteCode(const char* code); + void AddFuncRegistration(std::string returnType, std::string name, std::string argTypes, std::string helpText, SQFunction func); + SQRESULT setupfunc(const SQChar* funcname); + void AddFuncOverride(std::string name, SQFunction func); + void ProcessMessageBuffer(); +}; + template <ScriptContext context> SquirrelManager<context>* g_pSquirrel; + +/* + Beware all ye who enter below. + This place is not a place of honor... no highly esteemed deed is commemorated here... nothing valued is here. + What is here was dangerous and repulsive to us. This message is a warning about danger. +*/ + +#pragma region MessageBuffer templates + +// Clang-formatting makes this whole thing unreadable +// clang-format off + +#ifndef MessageBufferFuncs +#define MessageBufferFuncs +// Bools +template <ScriptContext context, typename T> +requires std::convertible_to<T, bool> && (!std::is_floating_point_v<T>) && (!std::convertible_to<T, std::string>) && (!std::convertible_to<T, int>) +inline VoidFunction SQMessageBufferPushArg(T& arg) { + return [arg]{ g_pSquirrel<context>->pushbool(g_pSquirrel<context>->m_pSQVM->sqvm, static_cast<bool>(arg)); }; +} +// Vectors +template <ScriptContext context> +inline VoidFunction SQMessageBufferPushArg(Vector3& arg) { + return [arg]{ g_pSquirrel<context>->pushvector(g_pSquirrel<context>->m_pSQVM->sqvm, arg); }; +} +// Vectors +template <ScriptContext context> +inline VoidFunction SQMessageBufferPushArg(SQObject* arg) { + return [arg]{ g_pSquirrel<context>->pushSQObject(g_pSquirrel<context>->m_pSQVM->sqvm, arg); }; +} +// Ints +template <ScriptContext context, typename T> +requires std::convertible_to<T, int> && (!std::is_floating_point_v<T>) +inline VoidFunction SQMessageBufferPushArg(T& arg) { + return [arg]{ g_pSquirrel<context>->pushinteger(g_pSquirrel<context>->m_pSQVM->sqvm, static_cast<int>(arg)); }; +} +// Floats +template <ScriptContext context, typename T> +requires std::convertible_to<T, float> && (std::is_floating_point_v<T>) +inline VoidFunction SQMessageBufferPushArg(T& arg) { + return [arg]{ g_pSquirrel<context>->pushfloat(g_pSquirrel<context>->m_pSQVM->sqvm, static_cast<float>(arg)); }; +} +// Strings +template <ScriptContext context, typename T> +requires (std::convertible_to<T, std::string> || std::is_constructible_v<std::string, T>) +inline VoidFunction SQMessageBufferPushArg(T& arg) { + auto converted = std::string(arg); + return [converted]{ g_pSquirrel<context>->pushstring(g_pSquirrel<context>->m_pSQVM->sqvm, converted.c_str(), converted.length()); }; +} +// Assets +template <ScriptContext context> +inline VoidFunction SQMessageBufferPushArg(SquirrelAsset& arg) { + return [arg]{ g_pSquirrel<context>->pushasset(g_pSquirrel<context>->m_pSQVM->sqvm, arg.path.c_str(), arg.path.length()); }; +} +// Maps +template <ScriptContext context, typename T> +requires is_iterable<T> +inline VoidFunction SQMessageBufferPushArg(T& arg) { + FunctionVector localv = {}; + localv.push_back([]{g_pSquirrel<context>->newarray(g_pSquirrel<context>->m_pSQVM->sqvm, 0);}); + + for (const auto& item : arg) { + localv.push_back(SQMessageBufferPushArg<context>(item)); + localv.push_back([]{g_pSquirrel<context>->arrayappend(g_pSquirrel<context>->m_pSQVM->sqvm, -2);}); + } + + return [localv] { for (auto& func : localv) { func(); } }; +} +// Vectors +template <ScriptContext context, typename T> +requires is_map<T> +inline VoidFunction SQMessageBufferPushArg(T& map) { + FunctionVector localv = {}; + localv.push_back([]{g_pSquirrel<context>->newtable(g_pSquirrel<context>->m_pSQVM->sqvm);}); + + for (const auto& item : map) { + localv.push_back(SQMessageBufferPushArg<context>(item.first)); + localv.push_back(SQMessageBufferPushArg<context>(item.second)); + localv.push_back([]{g_pSquirrel<context>->newslot(g_pSquirrel<context>->m_pSQVM->sqvm, -3, false);}); + } + + return [localv]{ for (auto& func : localv) { func(); } }; +} + +template <ScriptContext context, typename T> +inline void SqRecurseArgs(FunctionVector& v, T& arg) { + v.push_back(SQMessageBufferPushArg<context>(arg)); +} + +// This function is separated from the PushArg function so as to not generate too many template instances +// This is the main function responsible for unrolling the argument pack +template <ScriptContext context, typename T, typename... Args> +inline void SqRecurseArgs(FunctionVector& v, T& arg, Args... args) { + v.push_back(SQMessageBufferPushArg<context>(arg)); + SqRecurseArgs<context>(v, args...); +} + +// clang-format on +#endif + +#pragma endregion diff --git a/NorthstarDLL/squirrelclasstypes.h b/NorthstarDLL/squirrelclasstypes.h new file mode 100644 index 00000000..e26bc8d0 --- /dev/null +++ b/NorthstarDLL/squirrelclasstypes.h @@ -0,0 +1,239 @@ +#pragma once +#include "pch.h" +#include "squirreldatatypes.h" + +#include <queue> + +enum SQRESULT : SQInteger +{ + SQRESULT_ERROR = -1, + SQRESULT_NULL = 0, + SQRESULT_NOTNULL = 1, +}; + +typedef SQRESULT (*SQFunction)(HSquirrelVM* sqvm); + +enum class eSQReturnType +{ + Float = 0x1, + Vector = 0x3, + Integer = 0x5, + Boolean = 0x6, + Entity = 0xD, + String = 0x21, + Default = 0x20, + Arrays = 0x25, + Asset = 0x28, + Table = 0x26, +}; + +const std::map<SQRESULT, const char*> PrintSQRESULT = { + {SQRESULT::SQRESULT_ERROR, "SQRESULT_ERROR"}, + {SQRESULT::SQRESULT_NULL, "SQRESULT_NULL"}, + {SQRESULT::SQRESULT_NOTNULL, "SQRESULT_NOTNULL"}}; + +struct CompileBufferState +{ + const SQChar* buffer; + const SQChar* bufferPlusLength; + const SQChar* bufferAgain; + + CompileBufferState(const std::string& code) + { + buffer = code.c_str(); + bufferPlusLength = code.c_str() + code.size(); + bufferAgain = code.c_str(); + } +}; + +struct SQFuncRegistration +{ + const char* squirrelFuncName; + const char* cppFuncName; + const char* helpText; + const char* returnTypeString; + const char* argTypes; + uint32_t unknown1; + uint32_t devLevel; + const char* shortNameMaybe; + uint32_t unknown2; + eSQReturnType returnType; + uint32_t* externalBufferPointer; + uint64_t externalBufferSize; + uint64_t unknown3; + uint64_t unknown4; + SQFunction funcPtr; + + SQFuncRegistration() + { + memset(this, 0, sizeof(SQFuncRegistration)); + this->returnType = eSQReturnType::Default; + } +}; + +enum class ScriptContext : int +{ + SERVER, + CLIENT, + UI, +}; + +typedef std::vector<std::function<void()>> FunctionVector; +typedef std::function<void()> VoidFunction; + +// clang-format off +template <typename T> +concept is_map = + // Simple maps + std::same_as<T, std::map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type>> || + std::same_as<T, std::unordered_map<typename T::key_type, typename T::mapped_type, typename T::hasher, typename T::key_equal, typename T::allocator_type>> || + + // Nested maps + std::same_as < + std::map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type>, + std::map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type> + > || + std::same_as < + std::unordered_map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type>, + std::unordered_map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type> + > || + std::same_as < + std::unordered_map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type>, + std::map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type> + > || + std::same_as < + std::map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type>, + std::unordered_map<typename T::key_type, typename T::mapped_type, typename T::key_compare, typename T::allocator_type> + > +; + +template<typename T> +concept is_iterable = requires(std::ranges::range_value_t<T> x) +{ + x.begin(); // must have `x.begin()` + x.end(); // and `x.end()` +}; + +// clang-format on + +typedef void (*SquirrelMessage_External_Pop)(HSquirrelVM* sqvm); +typedef void (*sq_schedule_call_externalType)(ScriptContext context, const char* funcname, SquirrelMessage_External_Pop function); + +class SquirrelMessage +{ + public: + std::string functionName; + FunctionVector args; + bool isExternal = false; + SquirrelMessage_External_Pop externalFunc = NULL; +}; + +class SquirrelMessageBuffer +{ + + private: + std::queue<SquirrelMessage> messages = {}; + + public: + std::mutex mutex; + std::optional<SquirrelMessage> pop() + { + std::lock_guard<std::mutex> guard(mutex); + if (!messages.empty()) + { + auto message = messages.front(); + messages.pop(); + return message; + } + else + { + return std::nullopt; + } + } + + void unwind() + { + auto maybeMessage = this->pop(); + if (!maybeMessage) + { + spdlog::error("Plugin tried consuming SquirrelMessage while buffer was empty"); + return; + } + auto message = maybeMessage.value(); + for (auto& v : message.args) + { + // Execute lambda to push arg to stack + v(); + } + } + + void push(SquirrelMessage message) + { + std::lock_guard<std::mutex> guard(mutex); + messages.push(message); + } +}; + +// Super simple wrapper class to allow pushing Assets via call +class SquirrelAsset +{ + public: + std::string path; + SquirrelAsset(std::string path) : path(path) {}; +}; + +#pragma region TypeDefs + +// core sqvm funcs +typedef int64_t (*RegisterSquirrelFuncType)(CSquirrelVM* sqvm, SQFuncRegistration* funcReg, char unknown); +typedef void (*sq_defconstType)(CSquirrelVM* sqvm, const SQChar* name, int value); + +typedef SQRESULT (*sq_compilebufferType)( + HSquirrelVM* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, SQBool bShouldThrowError); +typedef SQRESULT (*sq_callType)(HSquirrelVM* sqvm, SQInteger iArgs, SQBool bShouldReturn, SQBool bThrowError); +typedef SQInteger (*sq_raiseerrorType)(HSquirrelVM* sqvm, const SQChar* pError); + +// sq stack array funcs +typedef void (*sq_newarrayType)(HSquirrelVM* sqvm, SQInteger iStackpos); +typedef SQRESULT (*sq_arrayappendType)(HSquirrelVM* sqvm, SQInteger iStackpos); + +// sq table funcs +typedef SQRESULT (*sq_newtableType)(HSquirrelVM* sqvm); +typedef SQRESULT (*sq_newslotType)(HSquirrelVM* sqvm, SQInteger idx, SQBool bStatic); + +// sq stack push funcs +typedef void (*sq_pushroottableType)(HSquirrelVM* sqvm); +typedef void (*sq_pushstringType)(HSquirrelVM* sqvm, const SQChar* pStr, SQInteger iLength); +typedef void (*sq_pushintegerType)(HSquirrelVM* sqvm, SQInteger i); +typedef void (*sq_pushfloatType)(HSquirrelVM* sqvm, SQFloat f); +typedef void (*sq_pushboolType)(HSquirrelVM* sqvm, SQBool b); +typedef void (*sq_pushassetType)(HSquirrelVM* sqvm, const SQChar* str, SQInteger iLength); +typedef void (*sq_pushvectorType)(HSquirrelVM* sqvm, const SQFloat* pVec); +typedef void (*sq_pushobjectType)(HSquirrelVM* sqvm, SQObject* pVec); + +// sq stack get funcs +typedef const SQChar* (*sq_getstringType)(HSquirrelVM* sqvm, SQInteger iStackpos); +typedef SQInteger (*sq_getintegerType)(HSquirrelVM* sqvm, SQInteger iStackpos); +typedef SQFloat (*sq_getfloatType)(HSquirrelVM*, SQInteger iStackpos); +typedef SQBool (*sq_getboolType)(HSquirrelVM*, SQInteger iStackpos); +typedef SQRESULT (*sq_getType)(HSquirrelVM* sqvm, SQInteger iStackpos); +typedef SQRESULT (*sq_getassetType)(HSquirrelVM* sqvm, SQInteger iStackpos, const char** pResult); +typedef SQRESULT (*sq_getuserdataType)(HSquirrelVM* sqvm, SQInteger iStackpos, void** pData, uint64_t* pTypeId); +typedef SQFloat* (*sq_getvectorType)(HSquirrelVM* sqvm, SQInteger iStackpos); +typedef SQBool (*sq_getthisentityType)(HSquirrelVM*, void** ppEntity); +typedef void (*sq_getobjectType)(HSquirrelVM*, SQInteger iStackPos, SQObject* pOutObj); + +// sq stack userpointer funcs +typedef void* (*sq_createuserdataType)(HSquirrelVM* sqvm, SQInteger iSize); +typedef SQRESULT (*sq_setuserdatatypeidType)(HSquirrelVM* sqvm, SQInteger iStackpos, uint64_t iTypeId); + +// sq misc entity funcs +typedef void* (*sq_getentityfrominstanceType)(CSquirrelVM* sqvm, SQObject* pInstance, char** ppEntityConstant); +typedef char** (*sq_GetEntityConstantType)(); + +typedef int (*sq_getfunctionType)(HSquirrelVM* sqvm, const char* name, SQObject* returnObj, const char* signature); + +#pragma endregion + +// These "external" versions of the types are for plugins +typedef int64_t (*RegisterSquirrelFuncType_External)(ScriptContext context, SQFuncRegistration* funcReg, char unknown); diff --git a/NorthstarDLL/squirreldatatypes.h b/NorthstarDLL/squirreldatatypes.h index 818ce2a4..e9f88d08 100644 --- a/NorthstarDLL/squirreldatatypes.h +++ b/NorthstarDLL/squirreldatatypes.h @@ -22,6 +22,13 @@ struct SQUserData; typedef void (*releasehookType)(void* val, int size); +// stolen from ttf2sdk: sqvm types +typedef float SQFloat; +typedef long SQInteger; +typedef unsigned long SQUnsignedInteger; +typedef char SQChar; +typedef SQUnsignedInteger SQBool; + /* 127 */ enum SQObjectType : int { @@ -83,6 +90,7 @@ union SQObjectValue float asFloat; int asInteger; SQUserData* asUserdata; + SQStructInstance* asStructInstance; }; /* 160 */ @@ -279,12 +287,15 @@ struct alignas(8) HSquirrelVM struct SQStructInstance { void* vftable; - unsigned char gap_8[16]; + __int32 uiRef; + BYTE gap_C[4]; + __int64 unknown_10; void* pointer_18; - unsigned char gap_20[8]; + __int64 unknown_20; SQSharedState* _sharedState; - unsigned char gap[8]; - SQObject data[20]; + unsigned int size; + BYTE gap_34[4]; + SQObject data[1]; // This struct is dynamically sized, so this size is unknown }; /* 148 */ |