diff options
Diffstat (limited to 'NorthstarDLL/squirrel.h')
-rw-r--r-- | NorthstarDLL/squirrel.h | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/NorthstarDLL/squirrel.h b/NorthstarDLL/squirrel.h new file mode 100644 index 00000000..397fa9ed --- /dev/null +++ b/NorthstarDLL/squirrel.h @@ -0,0 +1,334 @@ +#include <../modmanager.h> +#pragma once + +void InitialiseClientSquirrel(HMODULE baseAddress); +void InitialiseServerSquirrel(HMODULE baseAddress); + +// stolen from ttf2sdk: sqvm types +typedef float SQFloat; +typedef long SQInteger; +typedef unsigned long SQUnsignedInteger; +typedef char SQChar; + +typedef SQUnsignedInteger SQBool; +typedef SQInteger SQRESULT; + +const SQRESULT SQRESULT_ERROR = -1; +const SQRESULT SQRESULT_NULL = 0; +const SQRESULT SQRESULT_NOTNULL = 1; + +typedef SQInteger (*SQFunction)(void* sqvm); + +enum SQReturnTypeEnum +{ + SqReturnFloat = 0x1, + SqReturnVector = 0x3, + SqReturnInteger = 0x5, + SqReturnBoolean = 0x6, + SqReturnEntity = 0xD, + SqReturnString = 0x21, + SqReturnDefault = 0x20, + SqReturnArrays = 0x25, + SqReturnAsset = 0x28, + SqReturnTable = 0x26, +}; + +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; + __int32 unknown1; + __int32 devLevel; + const char* shortNameMaybe; + __int32 unknown2; + SQReturnTypeEnum returnTypeEnum; + __int32* externalBufferPointer; + __int64 externalBufferSize; + __int64 unknown3; + __int64 unknown4; + void* funcPtr; + + SQFuncRegistration() + { + memset(this, 0, sizeof(SQFuncRegistration)); + this->returnTypeEnum = SqReturnDefault; + } +}; + +SQReturnTypeEnum GetReturnTypeEnumFromString(const char* returnTypeString); + +// core sqvm funcs +typedef SQRESULT (*sq_compilebufferType)(void* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, ScriptContext a2); +extern sq_compilebufferType ClientSq_compilebuffer; +extern sq_compilebufferType ServerSq_compilebuffer; + +typedef void (*sq_pushroottableType)(void* sqvm); +extern sq_pushroottableType ClientSq_pushroottable; +extern sq_pushroottableType ServerSq_pushroottable; + +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; + +// sq stack array funcs +typedef void (*sq_newarrayType)(void* sqvm, SQInteger stackpos); +extern sq_newarrayType ClientSq_newarray; +extern sq_newarrayType ServerSq_newarray; + +typedef SQRESULT (*sq_arrayappendType)(void* sqvm, SQInteger stackpos); +extern sq_arrayappendType ClientSq_arrayappend; +extern sq_arrayappendType ServerSq_arrayappend; + +// sq stack push funcs +typedef void (*sq_pushstringType)(void* sqvm, const SQChar* str, SQInteger stackpos); +extern sq_pushstringType ClientSq_pushstring; +extern sq_pushstringType ServerSq_pushstring; + +// weird how these don't take a stackpos arg? +typedef void (*sq_pushintegerType)(void* sqvm, SQInteger i); +extern sq_pushintegerType ClientSq_pushinteger; +extern sq_pushintegerType ServerSq_pushinteger; + +typedef void (*sq_pushfloatType)(void* sqvm, SQFloat f); +extern sq_pushfloatType ClientSq_pushfloat; +extern sq_pushfloatType ServerSq_pushfloat; + +typedef void (*sq_pushboolType)(void* sqvm, SQBool b); +extern sq_pushboolType ClientSq_pushbool; +extern sq_pushboolType ServerSq_pushbool; + +typedef SQInteger (*sq_pusherrorType)(void* sqvm, const SQChar* error); +extern sq_pusherrorType ClientSq_pusherror; +extern sq_pusherrorType ServerSq_pusherror; + +typedef void (*sq_defconst)(void* sqvm, const SQChar* name, int value); +extern sq_defconst ClientSq_defconst; +extern sq_defconst ServerSq_defconst; + +typedef SQRESULT (*sq_pushAssetType)(void* sqvm, const SQChar* assetName, SQInteger nameLength); +extern sq_pushAssetType ServerSq_pushAsset; +extern sq_pushAssetType ClientSq_pushAsset; + +// sq stack get funcs +typedef const SQChar* (*sq_getstringType)(void* sqvm, SQInteger stackpos); +extern sq_getstringType ClientSq_getstring; +extern sq_getstringType ServerSq_getstring; + +typedef SQInteger (*sq_getintegerType)(void* sqvm, SQInteger stackpos); +extern sq_getintegerType ClientSq_getinteger; +extern sq_getintegerType ServerSq_getinteger; + +typedef SQFloat (*sq_getfloatType)(void*, SQInteger stackpos); +extern sq_getfloatType ClientSq_getfloat; +extern sq_getfloatType ServerSq_getfloat; + +typedef SQBool (*sq_getboolType)(void*, SQInteger stackpos); +extern sq_getboolType ClientSq_getbool; +extern sq_getboolType ServerSq_getbool; + +typedef SQRESULT (*sq_getType)(void* sqvm, SQInteger idx); +extern sq_getType ServerSq_sq_get; +extern sq_getType ClientSq_sq_get; + +template <ScriptContext context> class SquirrelManager +{ + private: + std::vector<SQFuncRegistration*> m_funcRegistrations; + + public: + void* sqvm; + void* sqvm2; + + public: + SquirrelManager() : sqvm(nullptr) {} + + void VMCreated(void* newSqvm) + { + 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 == ScriptContext::CLIENT || context == ScriptContext::UI) + ClientRegisterSquirrelFunc(sqvm, funcReg, 1); + else + ServerRegisterSquirrelFunc(sqvm, funcReg, 1); + } + for (auto& pair : g_ModManager->DependencyConstants) + { + bool wasFound = false; + for (Mod& dependency : g_ModManager->m_loadedMods) + { + if (dependency.Name == pair.second) + { + wasFound = dependency.Enabled; + break; + } + } + if (context == ScriptContext::SERVER) + ServerSq_defconst(sqvm, pair.first.c_str(), wasFound); + else + ClientSq_defconst(sqvm, pair.first.c_str(), wasFound); + } + } + + void VMDestroyed() + { + sqvm = nullptr; + } + + void ExecuteCode(const char* code) + { + // ttf2sdk checks ThreadIsInMainThread here, might be good to do that? doesn't seem like an issue rn tho + + if (!sqvm) + { + spdlog::error("Cannot execute code, {} squirrel vm is not initialised", GetContextName(context)); + return; + } + + spdlog::info("Executing {} script code {} ", GetContextName(context), code); + + std::string strCode(code); + CompileBufferState bufferState = CompileBufferState(strCode); + + SQRESULT compileResult; + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + compileResult = ClientSq_compilebuffer(sqvm2, &bufferState, "console", -1, context); + else if (context == ScriptContext::SERVER) + compileResult = ServerSq_compilebuffer(sqvm2, &bufferState, "console", -1, context); + + spdlog::info("sq_compilebuffer returned {}", compileResult); + if (compileResult >= 0) + { + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + { + ClientSq_pushroottable(sqvm2); + SQRESULT callResult = ClientSq_call(sqvm2, 1, false, false); + spdlog::info("sq_call returned {}", callResult); + } + else if (context == ScriptContext::SERVER) + { + ServerSq_pushroottable(sqvm2); + SQRESULT callResult = ServerSq_call(sqvm2, 1, false, false); + spdlog::info("sq_call returned {}", callResult); + } + } + } + + int setupfunc(const char* funcname) + { + int result = -2; + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + { + ClientSq_pushroottable(sqvm2); + ClientSq_pushstring(sqvm2, funcname, -1); + result = ClientSq_sq_get(sqvm2, -2); + if (result != SQRESULT_ERROR) + { + ClientSq_pushroottable(sqvm2); + } + } + else if (context == ScriptContext::SERVER) + { + ServerSq_pushroottable(sqvm2); + ServerSq_pushstring(sqvm2, funcname, -1); + result = ServerSq_sq_get(sqvm2, -2); + if (result != SQRESULT_ERROR) + { + ServerSq_pushroottable(sqvm2); + } + } + return result; + } + + void pusharg(int arg) + { + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + ClientSq_pushinteger(sqvm2, arg); + else if (context == ScriptContext::SERVER) + ServerSq_pushinteger(sqvm2, arg); + } + void pusharg(const char* arg) + { + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + ClientSq_pushstring(sqvm2, arg, -1); + else if (context == ScriptContext::SERVER) + ServerSq_pushstring(sqvm2, arg, -1); + } + void pusharg(float arg) + { + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + ClientSq_pushfloat(sqvm2, arg); + else if (context == ScriptContext::SERVER) + ServerSq_pushfloat(sqvm2, arg); + } + void pusharg(bool arg) + { + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + ClientSq_pushbool(sqvm2, arg); + else if (context == ScriptContext::SERVER) + ServerSq_pushbool(sqvm2, arg); + } + + int call(int args) + { + int result = -2; + if (context == ScriptContext::CLIENT || context == ScriptContext::UI) + result = ClientSq_call(sqvm2, args + 1, false, false); + else if (context == ScriptContext::SERVER) + result = ServerSq_call(sqvm2, args + 1, false, false); + + return result; + } + + 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->returnTypeString = new char[returnType.size() + 1]; + strcpy((char*)reg->returnTypeString, returnType.c_str()); + reg->returnTypeEnum = GetReturnTypeEnumFromString(returnType.c_str()); + + reg->argTypes = new char[argTypes.size() + 1]; + strcpy((char*)reg->argTypes, argTypes.c_str()); + + reg->funcPtr = reinterpret_cast<void*>(func); + + m_funcRegistrations.push_back(reg); + } +}; + +extern SquirrelManager<ScriptContext::CLIENT>* g_ClientSquirrelManager; +extern SquirrelManager<ScriptContext::SERVER>* g_ServerSquirrelManager; +extern SquirrelManager<ScriptContext::UI>* g_UISquirrelManager; |