diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index 41a6a782f..cfb36ea4a 100644 --- a/primedev/squirrel/squirrel.cpp +++ b/primedev/squirrel/squirrel.cpp @@ -10,6 +10,8 @@ #include "plugins/pluginmanager.h" #include "ns_version.h" #include "core/vanilla.h" +#include "squirrelclasstypes.h" +#include "squirreldatatypes.h" #include @@ -162,16 +164,78 @@ template class SquirrelManager; template class SquirrelManager; template class SquirrelManager; +// create a string -> integer slot in table at index -1 +template SQRESULT SquirrelManager::CreateSlot(const char* key, SQInteger val) +{ + pushstring(m_pSQVM->sqvm, key, -1); + pushinteger(m_pSQVM->sqvm, val); + return newslot(m_pSQVM->sqvm, -3, false); +} + +// expects const table to be at stack index -1 +template void SquirrelManager::CreateDependencyConstantsForMod(Mod& mod, const char* dependencyName) +{ + std::string version = mod.Version; + auto nDots = std::count(version.begin(), version.end(), '.'); + + // push mod name as key + pushstring(m_pSQVM->sqvm, dependencyName, -1); + newtable(m_pSQVM->sqvm); + + // valid semver must at least include 2 dots to seperate versions + if (nDots >= 2) + { + std::string major = version.substr(0, version.find('.')); + std::string minor = version.substr(major.length() + 1, version.length() - version.find('.', major.length() + 1)); + + size_t preRelease = version.find('-'); + size_t build = version.find('+'); + + size_t patchEnd = version.length(); + + if (build != std::string::npos) + { + patchEnd = build; + } + + // pre-releases are always in front of build meta data + if (preRelease != std::string::npos) + { + patchEnd = preRelease; + } + + std::string patch = version.substr(major.length() + minor.length() + 2, patchEnd); + + if (std::all_of(major.begin(), major.end(), ::isdigit)) + { + CreateSlot("major", stoi(major)); + } + + if (std::all_of(minor.begin(), minor.end(), ::isdigit)) + { + CreateSlot("minor", stoi(minor)); + } + + if (std::all_of(patch.begin(), patch.end(), ::isdigit)) + { + CreateSlot("patch", stoi(patch)); + } + } + + newslot(m_pSQVM->sqvm, -3, false); +} + template void SquirrelManager::VMCreated(CSquirrelVM* newSqvm) { m_pSQVM = newSqvm; - for (SQFuncRegistration* funcReg : m_funcRegistrations) { spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName); RegisterSquirrelFunc(m_pSQVM, funcReg, 1); } + pushconsttable(m_pSQVM->sqvm); + for (auto& pair : g_pModManager->m_DependencyConstants) { bool bWasFound = false; @@ -184,13 +248,21 @@ template void SquirrelManager::VMCreated(CSquir if (dependency.Name == pair.second) { bWasFound = true; + CreateDependencyConstantsForMod(dependency, pair.first.c_str()); break; } } - defconst(m_pSQVM, pair.first.c_str(), bWasFound); + // if the dependency is not loaded, place a falsy value in the map + // null would've been cooler but pushing null in the table erased the slot for some reason + if (!bWasFound) + { + defconst(m_pSQVM, pair.first.c_str(), 0); + } } + poptop(m_pSQVM->sqvm); + std::vector loadedPlugins = g_pPluginManager->GetLoadedPlugins(); for (const auto& pluginName : g_pModManager->m_PluginDependencyConstants) { @@ -210,6 +282,8 @@ template void SquirrelManager::VMCreated(CSquir // define squirrel constant for if we are in vanilla-compatibility mode defconst(m_pSQVM, "VANILLA", g_pVanillaCompatibility->GetVanillaCompatibility()); + // poptop(m_pSQVM->sqvm); + g_pSquirrel->messageBuffer = new SquirrelMessageBuffer(); g_pPluginManager->InformSqvmCreated(newSqvm); } @@ -729,6 +803,13 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_pushnewstructinstance = g_pSquirrel->__sq_pushnewstructinstance; g_pSquirrel->__sq_sealstructslot = g_pSquirrel->__sq_sealstructslot; + g_pSquirrel->__sq_pushconsttable = module.Offset(0x5940).RCast(); + g_pSquirrel->__sq_pushconsttable = g_pSquirrel->__sq_pushconsttable; + g_pSquirrel->__sq_poptop = module.Offset(0x7030).RCast(); + g_pSquirrel->__sq_poptop = g_pSquirrel->__sq_poptop; + g_pSquirrel->__sq_pushnull = module.Offset(0x33d0).RCast(); + g_pSquirrel->__sq_pushnull = g_pSquirrel->__sq_pushnull; + MAKEHOOK( module.Offset(0x108E0), &RegisterSquirrelFunctionHook, @@ -815,6 +896,10 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_pushnewstructinstance = module.Offset(0x53e0).RCast(); g_pSquirrel->__sq_sealstructslot = module.Offset(0x5510).RCast(); + g_pSquirrel->__sq_pushconsttable = module.Offset(0x5920).RCast(); + g_pSquirrel->__sq_poptop = module.Offset(0x7000).RCast(); + g_pSquirrel->__sq_pushnull = module.Offset(0x33d0).RCast(); + MAKEHOOK( module.Offset(0x1DD10), &RegisterSquirrelFunctionHook, diff --git a/primedev/squirrel/squirrel.h b/primedev/squirrel/squirrel.h index 0c1f24d36..62bd9aa1f 100644 --- a/primedev/squirrel/squirrel.h +++ b/primedev/squirrel/squirrel.h @@ -4,6 +4,7 @@ #include "squirrelautobind.h" #include "core/math/vector.h" #include "mods/modmanager.h" +#include "squirreldatatypes.h" /* definitions from hell @@ -120,6 +121,10 @@ class SquirrelManagerBase sq_pushnewstructinstanceType __sq_pushnewstructinstance; sq_sealstructslotType __sq_sealstructslot; + sq_pushconsttableType __sq_pushconsttable; + sq_poptopType __sq_poptop; + sq_pushnullType __sq_pushnull; + #pragma endregion #pragma region SQVM func wrappers @@ -254,6 +259,21 @@ class SquirrelManagerBase return __sq_stackinfos(sqvm, level, &out, sqvm->_callstacksize); } + inline void pushconsttable(HSquirrelVM* sqvm) + { + return __sq_pushconsttable(sqvm); + } + + inline void poptop(HSquirrelVM* sqvm) + { + return __sq_poptop(sqvm); + } + + inline void pushnull(HSquirrelVM* sqvm) + { + return __sq_pushnull(sqvm); + } + inline Mod* getcallingmod(HSquirrelVM* sqvm, int depth = 0) { SQStackInfos stackInfo {}; @@ -407,6 +427,8 @@ template class SquirrelManager : public virtual Squirrel m_pSQVM = nullptr; } + SQRESULT CreateSlot(const char* key, SQInteger val); + void CreateDependencyConstantsForMod(Mod& mod, const char* dependencyName); void VMCreated(CSquirrelVM* newSqvm); void VMDestroyed(); void ExecuteCode(const char* code); diff --git a/primedev/squirrel/squirrelclasstypes.h b/primedev/squirrel/squirrelclasstypes.h index 91c3c4683..545d79021 100644 --- a/primedev/squirrel/squirrelclasstypes.h +++ b/primedev/squirrel/squirrelclasstypes.h @@ -235,4 +235,8 @@ typedef int (*sq_getfunctionType)(HSquirrelVM* sqvm, const char* name, SQObject* typedef SQRESULT (*sq_pushnewstructinstanceType)(HSquirrelVM* sqvm, int fieldCount); typedef SQRESULT (*sq_sealstructslotType)(HSquirrelVM* sqvm, int slotIndex); +typedef void (*sq_poptopType)(HSquirrelVM* sqvm); +typedef void (*sq_pushconsttableType)(HSquirrelVM* sqvm); +typedef void (*sq_pushnullType)(HSquirrelVM* sqvm); + #pragma endregion