From 85635ad99dbdfa909341e4138f6fdb0c9bf73bf1 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Sun, 10 Jul 2022 18:22:59 +0300 Subject: Add dependency constants (#156) * Fix duplicate script in scripts.rson when 2 mods add a custom script with the same path Allow mods to force a VPK to load through vpk.json * Remove unnecessary print * Fix match predicate using the value instead of the name * - Add a dependency constant system for use in compile flags - Remove the duplicate script engine error fix - Add ClientSq_defconst & ServerSq_defconst * Format fix * - Fix access violation - Separate dependency constants into mod and add checks for conflicts * - Remove unnecessary comment * Remove VPK loading for now and allow 2 mods to use the same constant if the mod names match * Fix bugs * fix mistake * fix keyvalues not working with modded files * simplify code * Fix formatting * Remove keyvalues fix --- NorthstarDedicatedTest/modmanager.cpp | 34 ++++++++++++++++++++++++++++++++++ NorthstarDedicatedTest/modmanager.h | 6 ++++++ NorthstarDedicatedTest/squirrel.cpp | 7 +++++++ NorthstarDedicatedTest/squirrel.h | 21 +++++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 9de1c7b1..de45bd23 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -186,6 +186,26 @@ Mod::Mod(fs::path modDir, char* jsonBuf) } } + if (modJson.HasMember("Dependencies") && modJson["Dependencies"].IsObject()) + { + for (auto v = modJson["Dependencies"].MemberBegin(); v != modJson["Dependencies"].MemberEnd(); v++) + { + if (!v->name.IsString() || !v->value.IsString()) + continue; + + spdlog::info("Constant {} defined by {} for mod {}", v->name.GetString(), Name, v->value.GetString()); + if (DependencyConstants.find(v->name.GetString()) != DependencyConstants.end() && + v->value.GetString() != DependencyConstants[v->name.GetString()]) + { + spdlog::error("A dependency constant with the same name already exists for another mod. Change the constant name."); + return; + } + + if (DependencyConstants.find(v->name.GetString()) == DependencyConstants.end()) + DependencyConstants.emplace(v->name.GetString(), v->value.GetString()); + } + } + wasReadSuccessfully = true; } @@ -212,6 +232,8 @@ void ModManager::LoadMods() fs::remove_all(GetCompiledAssetsPath()); fs::create_directories(GetModFolderPath()); + DependencyConstants.clear(); + // read enabled mods cfg std::ifstream enabledModsStream(GetNorthstarPrefix() + "/enabledmods.json"); std::stringstream enabledModsStringStream; @@ -253,6 +275,18 @@ void ModManager::LoadMods() Mod mod(modDir, (char*)jsonStringStream.str().c_str()); + for (auto& pair : mod.DependencyConstants) + { + if (DependencyConstants.find(pair.first) != DependencyConstants.end() && DependencyConstants[pair.first] != pair.second) + { + spdlog::error("Constant {} in mod {} already exists in another mod.", pair.first, mod.Name); + mod.wasReadSuccessfully = false; + break; + } + if (DependencyConstants.find(pair.first) == DependencyConstants.end()) + DependencyConstants.emplace(pair); + } + if (m_hasEnabledModsCfg && m_enabledModsCfg.HasMember(mod.Name.c_str())) mod.Enabled = m_enabledModsCfg[mod.Name.c_str()].IsTrue(); else diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h index 00c0384a..d605eec2 100644 --- a/NorthstarDedicatedTest/modmanager.h +++ b/NorthstarDedicatedTest/modmanager.h @@ -100,6 +100,9 @@ class Mod std::vector Rpaks; std::unordered_map RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite + // iterated over to create squirrel VM constants depending if a mod exists or not. + // this only exists because we cannot access g_ModManager whilst mods are being loaded for the first time for some reason. + std::unordered_map DependencyConstants; // other stuff @@ -130,6 +133,9 @@ class ModManager public: std::vector m_loadedMods; std::unordered_map m_modFiles; + // iterated over to create squirrel VM constants depending if a mod exists or not. + // here because constants are global anyways. + std::unordered_map DependencyConstants; public: ModManager(); diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index d0d54a3a..a0680d9a 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -72,6 +72,9 @@ sq_pushboolType ServerSq_pushbool; sq_pusherrorType ClientSq_pusherror; sq_pusherrorType ServerSq_pusherror; +sq_defconst ClientSq_defconst; +sq_defconst ServerSq_defconst; + sq_pushAssetType ClientSq_pushAsset; sq_pushAssetType ServerSq_pushAsset; @@ -148,6 +151,8 @@ void InitialiseClientSquirrel(HMODULE baseAddress) ClientSq_sq_get = (sq_getType)((char*)baseAddress + 0x7C30); + ClientSq_defconst = (sq_defconst)((char*)baseAddress + 0x12120); + ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x26130, @@ -203,6 +208,8 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ServerSq_sq_get = (sq_getType)((char*)baseAddress + 0x7C00); + ServerSq_defconst = (sq_defconst)((char*)baseAddress + 0x1F550); + ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x1FE90, diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h index cbdf0c8c..0e49c7f8 100644 --- a/NorthstarDedicatedTest/squirrel.h +++ b/NorthstarDedicatedTest/squirrel.h @@ -1,3 +1,4 @@ +#include <../modmanager.h> #pragma once void InitialiseClientSquirrel(HMODULE baseAddress); @@ -121,6 +122,10 @@ 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; @@ -172,6 +177,22 @@ template class SquirrelManager 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() -- cgit v1.2.3