From 1ed1a968bc73ff8f4ffa235949f01c29173666d7 Mon Sep 17 00:00:00 2001 From: uniboi Date: Tue, 2 Apr 2024 00:15:50 +0200 Subject: [PATCH 1/5] push tables for semver of dependencies --- primedev/squirrel/squirrel.cpp | 94 +++++++++++++++++++++++++- primedev/squirrel/squirrel.h | 22 ++++++ primedev/squirrel/squirrelclasstypes.h | 4 ++ 3 files changed, 119 insertions(+), 1 deletion(-) diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index 41a6a782f..13483e067 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,82 @@ 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.find('.', major.length())); + 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; + // pushconsttable(m_pSQVM->sqvm); + 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 +252,24 @@ 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 mod is not loaded push null instead of a table with all versions + if (!bWasFound) + { + pushstring(m_pSQVM->sqvm, pair.first.c_str(), -1); + pushnull(m_pSQVM->sqvm); // this is coerced to SQInteger 0 for some reason in the const table + pushinteger(m_pSQVM->sqvm, 0); + newslot(m_pSQVM->sqvm, -3, false); + // 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 +289,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 +810,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 +903,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 From 7c7deb5b078634cff0c4fca6f3b12a926dc6088f Mon Sep 17 00:00:00 2001 From: uniboi Date: Tue, 2 Apr 2024 00:24:37 +0200 Subject: [PATCH 2/5] push 0 because null gets erased for some reason --- primedev/squirrel/squirrel.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index 13483e067..b53c9f436 100644 --- a/primedev/squirrel/squirrel.cpp +++ b/primedev/squirrel/squirrel.cpp @@ -260,11 +260,11 @@ template void SquirrelManager::VMCreated(CSquir // if mod is not loaded push null instead of a table with all versions if (!bWasFound) { - pushstring(m_pSQVM->sqvm, pair.first.c_str(), -1); - pushnull(m_pSQVM->sqvm); // this is coerced to SQInteger 0 for some reason in the const table - pushinteger(m_pSQVM->sqvm, 0); - newslot(m_pSQVM->sqvm, -3, false); - // defconst(m_pSQVM, pair.first.c_str(), 0); + // pushstring(m_pSQVM->sqvm, pair.first.c_str(), -1); + // pushnull(m_pSQVM->sqvm); // TODO null entries get erased for some reason + // pushinteger(m_pSQVM->sqvm, 0); + // newslot(m_pSQVM->sqvm, -3, false); + defconst(m_pSQVM, pair.first.c_str(), 0); } } From d24c96facb5ad337af4c5477c51a8deb00dfd2de Mon Sep 17 00:00:00 2001 From: uniboi Date: Tue, 2 Apr 2024 20:55:10 +0200 Subject: [PATCH 3/5] remove unused code --- primedev/squirrel/squirrel.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index b53c9f436..0c8852fac 100644 --- a/primedev/squirrel/squirrel.cpp +++ b/primedev/squirrel/squirrel.cpp @@ -257,13 +257,10 @@ template void SquirrelManager::VMCreated(CSquir } } - // if mod is not loaded push null instead of a table with all versions + // 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) { - // pushstring(m_pSQVM->sqvm, pair.first.c_str(), -1); - // pushnull(m_pSQVM->sqvm); // TODO null entries get erased for some reason - // pushinteger(m_pSQVM->sqvm, 0); - // newslot(m_pSQVM->sqvm, -3, false); defconst(m_pSQVM, pair.first.c_str(), 0); } } From 194caf729982a9f854f8a16f2db1ce714e31bab5 Mon Sep 17 00:00:00 2001 From: uniboi Date: Tue, 2 Apr 2024 21:01:23 +0200 Subject: [PATCH 4/5] forger --- primedev/squirrel/squirrel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index 0c8852fac..a68859df9 100644 --- a/primedev/squirrel/squirrel.cpp +++ b/primedev/squirrel/squirrel.cpp @@ -186,7 +186,6 @@ template void SquirrelManager::CreateDependency if (nDots >= 2) { std::string major = version.substr(0, version.find('.')); - // std::string minor = version.substr(major.length() + 1, version.find('.', major.length())); std::string minor = version.substr(major.length() + 1, version.length() - version.find('.', major.length() + 1)); size_t preRelease = version.find('-'); From 7b6456431dd4964aa10af55acbcec7c9a89372aa Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Wed, 3 Apr 2024 13:50:50 +0200 Subject: [PATCH 5/5] Update primedev/squirrel/squirrel.cpp Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> --- primedev/squirrel/squirrel.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index a68859df9..cfb36ea4a 100644 --- a/primedev/squirrel/squirrel.cpp +++ b/primedev/squirrel/squirrel.cpp @@ -228,9 +228,6 @@ template void SquirrelManager::CreateDependency template void SquirrelManager::VMCreated(CSquirrelVM* newSqvm) { m_pSQVM = newSqvm; - - // pushconsttable(m_pSQVM->sqvm); - for (SQFuncRegistration* funcReg : m_funcRegistrations) { spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName);