From 900855c0036aa9a6a6305e3f17a41a55640bdfaf Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Wed, 6 Oct 2021 21:46:32 +0100 Subject: add mod enabling/disabling --- NorthstarDedicatedTest/dllmain.cpp | 1 + NorthstarDedicatedTest/keyvalues.cpp | 3 +++ NorthstarDedicatedTest/modmanager.cpp | 45 +++++++++++++++++++++++++++++++- NorthstarDedicatedTest/modmanager.h | 6 +++++ NorthstarDedicatedTest/scriptmodmenu.cpp | 39 +++++++++++++++++++++++++++ NorthstarDedicatedTest/scriptsrson.cpp | 3 +++ NorthstarDedicatedTest/squirrel.cpp | 18 ++++++++++++- NorthstarDedicatedTest/squirrel.h | 4 +++ 8 files changed, 117 insertions(+), 2 deletions(-) diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 684f968e..7bf1c091 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -2,6 +2,7 @@ #include "hooks.h" #include "main.h" #include "squirrel.h" +#include "tier0.h" #include "dedicated.h" #include "dedicatedmaterialsystem.h" #include "sourceconsole.h" diff --git a/NorthstarDedicatedTest/keyvalues.cpp b/NorthstarDedicatedTest/keyvalues.cpp index 3d527e62..3bf4ff48 100644 --- a/NorthstarDedicatedTest/keyvalues.cpp +++ b/NorthstarDedicatedTest/keyvalues.cpp @@ -52,6 +52,9 @@ void ModManager::TryBuildKeyValues(const char* filename) // note: #include should be identical but it's actually just broken, thanks respawn for (int i = m_loadedMods.size() - 1; i > -1; i--) { + if (!m_loadedMods[i]->Enabled) + continue; + size_t fileHash = std::hash{}(normalisedPath); for (int j = 0; j < m_loadedMods[i]->KeyValuesHash.size(); j++) { diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index f5deed1a..b561c03b 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -5,6 +5,8 @@ #include "rapidjson/error/en.h" #include "rapidjson/document.h" +#include "rapidjson/ostreamwrapper.h" +#include "rapidjson/writer.h" #include #include #include @@ -184,13 +186,32 @@ ModManager::ModManager() void ModManager::LoadMods() { - UnloadMods(); + if (m_hasLoadedMods) + UnloadMods(); + + m_hasLoadedMods = true; std::vector modDirs; // ensure dirs exist + fs::remove_all(COMPILED_ASSETS_PATH); fs::create_directories(MOD_FOLDER_PATH); + // read enabled mods cfg + std::ifstream enabledModsStream("R2Northstar/enabledmods.json"); + std::stringstream enabledModsStringStream; + + if (!enabledModsStream.fail()) + { + while (enabledModsStream.peek() != EOF) + enabledModsStringStream << (char)enabledModsStream.get(); + + enabledModsStream.close(); + m_enabledModsCfg.Parse(enabledModsStringStream.str().c_str()); + + m_hasEnabledModsCfg = m_enabledModsCfg.IsObject(); + } + // get mod directories for (fs::directory_entry dir : fs::directory_iterator(MOD_FOLDER_PATH)) if (fs::exists(dir.path() / "mod.json")) @@ -216,6 +237,11 @@ void ModManager::LoadMods() Mod* mod = new Mod(modDir, (char*)jsonStringStream.str().c_str()); + if (m_hasEnabledModsCfg && m_enabledModsCfg.HasMember(mod->Name.c_str())) + mod->Enabled = m_enabledModsCfg[mod->Name.c_str()].IsTrue(); + else + mod->Enabled = true; + if (mod->wasReadSuccessfully) { spdlog::info("Loaded mod {} successfully", mod->Name); @@ -311,6 +337,9 @@ void ModManager::UnloadMods() m_modFiles.clear(); fs::remove_all(COMPILED_ASSETS_PATH); + if (!m_hasEnabledModsCfg) + m_enabledModsCfg.SetObject(); + for (Mod* mod : m_loadedMods) { // remove all built kvs @@ -319,8 +348,19 @@ void ModManager::UnloadMods() mod->KeyValuesHash.clear(); mod->KeyValues.clear(); + + // write to m_enabledModsCfg + if (!m_enabledModsCfg.HasMember(mod->Name.c_str())) + m_enabledModsCfg.AddMember(rapidjson::StringRef(mod->Name.c_str()), rapidjson::Value(false), m_enabledModsCfg.GetAllocator()); + + m_enabledModsCfg[mod->Name.c_str()].SetBool(mod->Enabled); } + std::ofstream writeStream("R2Northstar/enabledmods.json"); + rapidjson::OStreamWrapper writeStreamWrapper(writeStream); + rapidjson::Writer writer(writeStreamWrapper); + m_enabledModsCfg.Accept(writer); + // do we need to dealloc individual entries in m_loadedMods? idk, rework m_loadedMods.clear(); } @@ -336,6 +376,9 @@ void ModManager::CompileAssetsForFile(const char* filename) // check if we should build keyvalues, depending on whether any of our mods have patch kvs for this file for (Mod* mod : m_loadedMods) { + if (!mod->Enabled) + continue; + size_t fileHash = std::hash{}(fs::path(filename).lexically_normal().string()); if (std::find(mod->KeyValuesHash.begin(), mod->KeyValuesHash.end(), fileHash) != mod->KeyValuesHash.end()) { diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h index 079e1613..03160dd8 100644 --- a/NorthstarDedicatedTest/modmanager.h +++ b/NorthstarDedicatedTest/modmanager.h @@ -3,6 +3,7 @@ #include #include #include +#include "rapidjson/document.h" namespace fs = std::filesystem; @@ -96,6 +97,11 @@ public: class ModManager { +private: + bool m_hasLoadedMods = false; + bool m_hasEnabledModsCfg; + rapidjson::Document m_enabledModsCfg; + public: std::vector m_loadedMods; std::unordered_map m_modFiles; diff --git a/NorthstarDedicatedTest/scriptmodmenu.cpp b/NorthstarDedicatedTest/scriptmodmenu.cpp index ca7d047d..74319f56 100644 --- a/NorthstarDedicatedTest/scriptmodmenu.cpp +++ b/NorthstarDedicatedTest/scriptmodmenu.cpp @@ -18,6 +18,43 @@ SQInteger SQ_GetModNames(void* sqvm) return 1; } +// bool NSIsModEnabled(string modName) +SQInteger SQ_IsModEnabled(void* sqvm) +{ + const SQChar* modName = ClientSq_getstring(sqvm, 1); + + // manual lookup, not super performant but eh not a big deal + for (Mod* mod : g_ModManager->m_loadedMods) + { + if (!mod->Name.compare(modName)) + { + ClientSq_pushbool(sqvm, mod->Enabled); + return 1; + } + } + + return 0; // return null +} + +// void NSSetModEnabled(string modName, bool enabled) +SQInteger SQ_SetModEnabled(void* sqvm) +{ + const SQChar* modName = ClientSq_getstring(sqvm, 1); + const SQBool enabled = ClientSq_getbool(sqvm, 2); + + // manual lookup, not super performant but eh not a big deal + for (Mod* mod : g_ModManager->m_loadedMods) + { + if (!mod->Name.compare(modName)) + { + mod->Enabled = enabled; + return 0; // return null + } + } + + return 0; // return null +} + // string NSGetModDescriptionByModName(string modName) SQInteger SQ_GetModDescription(void* sqvm) { @@ -127,6 +164,8 @@ void InitialiseScriptModMenu(HMODULE baseAddress) return; g_UISquirrelManager->AddFuncRegistration("array", "NSGetModNames", "", "Returns the names of all loaded mods", SQ_GetModNames); + g_UISquirrelManager->AddFuncRegistration("bool", "NSIsModEnabled", "string modName", "Returns whether a given mod is enabled", SQ_IsModEnabled); + g_UISquirrelManager->AddFuncRegistration("void", "NSSetModEnabled", "string modName, bool enabled", "Sets whether a given mod is enabled", SQ_SetModEnabled); g_UISquirrelManager->AddFuncRegistration("string", "NSGetModDescriptionByModName", "string modName", "Returns a given mod's description", SQ_GetModDescription); g_UISquirrelManager->AddFuncRegistration("string", "NSGetModVersionByModName", "string modName", "Returns a given mod's version", SQ_GetModVersion); g_UISquirrelManager->AddFuncRegistration("string", "NSGetModDownloadLinkByModName", "string modName", "Returns a given mod's download link", SQ_GetModDownloadLink); diff --git a/NorthstarDedicatedTest/scriptsrson.cpp b/NorthstarDedicatedTest/scriptsrson.cpp index bc49ed26..514d4f1c 100644 --- a/NorthstarDedicatedTest/scriptsrson.cpp +++ b/NorthstarDedicatedTest/scriptsrson.cpp @@ -19,6 +19,9 @@ void ModManager::BuildScriptsRson() for (Mod* mod : m_loadedMods) { + if (!mod->Enabled) + continue; + // this isn't needed at all, just nice to have imo scriptsRson += "// MOD: "; scriptsRson += mod->Name; diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index 85e26c45..dfeb1805 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -81,6 +81,9 @@ sq_getintegerType ServerSq_getinteger; sq_getfloatType ClientSq_getfloat; sq_getfloatType ServerSq_getfloat; +sq_getboolType ClientSq_getbool; +sq_getboolType ServerSq_getbool; + template void ExecuteCodeCommand(const CCommand& args); @@ -130,6 +133,7 @@ void InitialiseClientSquirrel(HMODULE baseAddress) ClientSq_getstring = (sq_getstringType)((char*)baseAddress + 0x60C0); ClientSq_getinteger = (sq_getintegerType)((char*)baseAddress + 0x60E0); ClientSq_getfloat = (sq_getfloatType)((char*)baseAddress + 0x6100); + ClientSq_getbool = (sq_getboolType)((char*)baseAddress + 0x6130); 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 @@ -140,7 +144,6 @@ void InitialiseClientSquirrel(HMODULE baseAddress) void InitialiseServerSquirrel(HMODULE baseAddress) { g_ServerSquirrelManager = new SquirrelManager(); - g_ServerSquirrelManager->AddFuncRegistration("void", "SavePdataForEntityIndex", "int i", "idk", NSTestFunc); HookEnabler hook; @@ -160,6 +163,7 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ServerSq_getstring = (sq_getstringType)((char*)baseAddress + 0x60A0); ServerSq_getinteger = (sq_getintegerType)((char*)baseAddress + 0x60C0); ServerSq_getfloat = (sq_getfloatType)((char*)baseAddress + 0x60E0); + ServerSq_getbool = (sq_getboolType)((char*)baseAddress + 0x6110); 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 @@ -280,6 +284,9 @@ template char CallScriptInitCallbackHook(void* sqvm, const char { for (Mod* mod : g_ModManager->m_loadedMods) { + if (!mod->Enabled) + continue; + for (ModScript* script : mod->Scripts) { for (ModScriptCallback* modCallback : script->Callbacks) @@ -304,6 +311,9 @@ template char CallScriptInitCallbackHook(void* sqvm, const char { for (Mod* mod : g_ModManager->m_loadedMods) { + if (!mod->Enabled) + continue; + for (ModScript* script : mod->Scripts) { for (ModScriptCallback* modCallback : script->Callbacks) @@ -329,6 +339,9 @@ template char CallScriptInitCallbackHook(void* sqvm, const char { for (Mod* mod : g_ModManager->m_loadedMods) { + if (!mod->Enabled) + continue; + for (ModScript* script : mod->Scripts) { for (ModScriptCallback* modCallback : script->Callbacks) @@ -353,6 +366,9 @@ template char CallScriptInitCallbackHook(void* sqvm, const char { for (Mod* mod : g_ModManager->m_loadedMods) { + if (!mod->Enabled) + continue; + for (ModScript* script : mod->Scripts) { for (ModScriptCallback* modCallback : script->Callbacks) diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h index 66abcd76..5ccab090 100644 --- a/NorthstarDedicatedTest/squirrel.h +++ b/NorthstarDedicatedTest/squirrel.h @@ -114,6 +114,10 @@ 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; + template class SquirrelManager { -- cgit v1.2.3