diff options
-rw-r--r-- | NorthstarDLL/NorthstarDLL.vcxproj | 7 | ||||
-rw-r--r-- | NorthstarDLL/NorthstarDLL.vcxproj.filters | 9 | ||||
-rw-r--r-- | NorthstarDLL/client/audio.h | 2 | ||||
-rw-r--r-- | NorthstarDLL/client/clientvideooverrides.cpp | 10 | ||||
-rw-r--r-- | NorthstarDLL/client/modlocalisation.cpp | 4 | ||||
-rw-r--r-- | NorthstarDLL/core/filesystem/filesystem.cpp | 6 | ||||
-rw-r--r-- | NorthstarDLL/core/filesystem/rpakfilesystem.cpp | 21 | ||||
-rw-r--r-- | NorthstarDLL/logging/crashhandler.cpp | 4 | ||||
-rw-r--r-- | NorthstarDLL/mods/compiled/kb_act.cpp | 8 | ||||
-rw-r--r-- | NorthstarDLL/mods/compiled/modkeyvalues.cpp | 16 | ||||
-rw-r--r-- | NorthstarDLL/mods/compiled/modpdef.cpp | 118 | ||||
-rw-r--r-- | NorthstarDLL/mods/compiled/modscriptsrson.cpp | 8 | ||||
-rw-r--r-- | NorthstarDLL/mods/modmanager.cpp | 132 | ||||
-rw-r--r-- | NorthstarDLL/mods/modmanager.h | 35 | ||||
-rw-r--r-- | NorthstarDLL/pch.h | 2 | ||||
-rw-r--r-- | NorthstarDLL/scripts/client/scriptmodmenu.cpp | 18 | ||||
-rw-r--r-- | NorthstarDLL/squirrel/squirrel.cpp | 8 | ||||
-rw-r--r-- | NorthstarDLL/squirrel/squirrel.h | 8 | ||||
-rw-r--r-- | NorthstarDLL/util/printmaps.cpp | 2 |
19 files changed, 154 insertions, 264 deletions
diff --git a/NorthstarDLL/NorthstarDLL.vcxproj b/NorthstarDLL/NorthstarDLL.vcxproj index bb28d575..9bd3d6fa 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj +++ b/NorthstarDLL/NorthstarDLL.vcxproj @@ -449,7 +449,7 @@ <ClInclude Include="squirrel\squirreldatatypes.h" />
<ClInclude Include="util\utils.h" />
<ClInclude Include="util\version.h" />
- <ClInclude Include="util\wininfo.h" />
+ <ClInclude Include="util\wininfo.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\include\spdlog\fmt\bundled\LICENSE.rst" />
@@ -498,7 +498,6 @@ <ClCompile Include="masterserver\masterserver.cpp" />
<ClCompile Include="mods\compiled\kb_act.cpp" />
<ClCompile Include="mods\compiled\modkeyvalues.cpp" />
- <ClCompile Include="mods\compiled\modpdef.cpp" />
<ClCompile Include="mods\compiled\modscriptsrson.cpp" />
<ClCompile Include="mods\modmanager.cpp" />
<ClCompile Include="pch.cpp">
@@ -540,7 +539,7 @@ <ClCompile Include="util\printmaps.cpp" />
<ClCompile Include="util\utils.cpp" />
<ClCompile Include="util\version.cpp" />
- <ClCompile Include="util\wininfo.cpp" />
+ <ClCompile Include="util\wininfo.cpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="audio_asm.asm" />
@@ -549,4 +548,4 @@ <ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
-</Project>
+</Project>
\ No newline at end of file diff --git a/NorthstarDLL/NorthstarDLL.vcxproj.filters b/NorthstarDLL/NorthstarDLL.vcxproj.filters index d8437ba5..e149396f 100644 --- a/NorthstarDLL/NorthstarDLL.vcxproj.filters +++ b/NorthstarDLL/NorthstarDLL.vcxproj.filters @@ -1173,8 +1173,8 @@ <ClInclude Include="core\macros.h">
<Filter>Header Files\core</Filter>
</ClInclude>
- <ClInclude Include="util\wininfo.h">
- <Filter>Header Files</Filter>
+ <ClInclude Include="util\wininfo.h">
+ <Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="util\utils.h">
<Filter>Header Files\util</Filter>
@@ -1240,9 +1240,6 @@ <ClCompile Include="mods\compiled\modkeyvalues.cpp">
<Filter>Source Files\mods\compiled</Filter>
</ClCompile>
- <ClCompile Include="mods\compiled\modpdef.cpp">
- <Filter>Source Files\mods\compiled</Filter>
- </ClCompile>
<ClCompile Include="mods\compiled\modscriptsrson.cpp">
<Filter>Source Files\mods\compiled</Filter>
</ClCompile>
@@ -1435,4 +1432,4 @@ <Filter>Source Files</Filter>
</MASM>
</ItemGroup>
-</Project>
+</Project>
\ No newline at end of file diff --git a/NorthstarDLL/client/audio.h b/NorthstarDLL/client/audio.h index 26cda205..915d52ce 100644 --- a/NorthstarDLL/client/audio.h +++ b/NorthstarDLL/client/audio.h @@ -1,7 +1,5 @@ #pragma once -#include <vector> -#include <filesystem> #include <regex> #include <shared_mutex> diff --git a/NorthstarDLL/client/clientvideooverrides.cpp b/NorthstarDLL/client/clientvideooverrides.cpp index d8aa2754..d24dfa14 100644 --- a/NorthstarDLL/client/clientvideooverrides.cpp +++ b/NorthstarDLL/client/clientvideooverrides.cpp @@ -11,20 +11,20 @@ void*, __fastcall, (const char* path, uint32_t flags)) spdlog::info("BinkOpen {}", filename); // figure out which mod is handling the bink - Mod* fileOwner = nullptr; - for (Mod& mod : g_pModManager->m_LoadedMods) + Mod* pFileOwner = nullptr; + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; if (std::find(mod.BinkVideos.begin(), mod.BinkVideos.end(), filename) != mod.BinkVideos.end()) - fileOwner = &mod; + pFileOwner = &mod; } - if (fileOwner) + if (pFileOwner) { // create new path - fs::path binkPath(fileOwner->m_ModDirectory / "media" / filename); + fs::path binkPath(pFileOwner->m_ModDirectory / "media" / filename); return BinkOpen(binkPath.string().c_str(), flags); } else diff --git a/NorthstarDLL/client/modlocalisation.cpp b/NorthstarDLL/client/modlocalisation.cpp index 2b73876b..a2387e64 100644 --- a/NorthstarDLL/client/modlocalisation.cpp +++ b/NorthstarDLL/client/modlocalisation.cpp @@ -25,7 +25,7 @@ void, __fastcall, (void* pVguiLocalize)) // clang-format on { // load all mod localization manually, so we keep track of all files, not just previously loaded ones - for (Mod mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) if (mod.m_bEnabled) for (std::string& localisationFile : mod.LocalisationFiles) CLocalize__AddFile(g_pVguiLocalize, localisationFile.c_str(), nullptr, false); @@ -43,7 +43,7 @@ void, __fastcall, (void* self)) // previously we did this in CLocalize::AddFile, but for some reason it won't properly overwrite localization from // files loaded previously if done there, very weird but this works so whatever - for (Mod mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) if (mod.m_bEnabled) for (std::string& localisationFile : mod.LocalisationFiles) CLocalize__AddFile(g_pVguiLocalize, localisationFile.c_str(), nullptr, false); diff --git a/NorthstarDLL/core/filesystem/filesystem.cpp b/NorthstarDLL/core/filesystem/filesystem.cpp index 88622e5d..3cecc208 100644 --- a/NorthstarDLL/core/filesystem/filesystem.cpp +++ b/NorthstarDLL/core/filesystem/filesystem.cpp @@ -94,8 +94,8 @@ bool TryReplaceFile(const char* pPath, bool shouldCompile) // idk how efficient the lexically normal check is // can't just set all /s in path to \, since some paths aren't in writeable memory - auto file = g_pModManager->m_ModFiles.find(g_pModManager->NormaliseModFilePath(fs::path(pPath))); - if (file != g_pModManager->m_ModFiles.end()) + auto file = g_pModManager->GetModFiles().find(g_pModManager->NormaliseModFilePath(fs::path(pPath))); + if (file != g_pModManager->GetModFiles().end()) { SetNewModSearchPaths(file->second.m_pOwningMod); return true; @@ -146,7 +146,7 @@ HOOK(MountVPKHook, MountVPK, VPKData*, , (IFileSystem * fileSystem, const char* NS::log::fs->info("MountVPK {}", pVpkPath); VPKData* ret = MountVPK(fileSystem, pVpkPath); - for (Mod mod : g_pModManager->m_LoadedMods) + for (Mod mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; diff --git a/NorthstarDLL/core/filesystem/rpakfilesystem.cpp b/NorthstarDLL/core/filesystem/rpakfilesystem.cpp index c863463c..fa71c56f 100644 --- a/NorthstarDLL/core/filesystem/rpakfilesystem.cpp +++ b/NorthstarDLL/core/filesystem/rpakfilesystem.cpp @@ -89,15 +89,14 @@ void* PakLoadManager::LoadFile(const char* path) void HandlePakAliases(char** map) { // convert the pak being loaded to it's aliased one, e.g. aliasing mp_hub_timeshift => sp_hub_timeshift - for (int64_t i = g_pModManager->m_LoadedMods.size() - 1; i > -1; i--) + for (Mod& mod : g_pModManager->GetMods() | std::views::reverse) { - Mod* mod = &g_pModManager->m_LoadedMods[i]; - if (!mod->m_bEnabled) + if (!mod.m_bEnabled) continue; - if (mod->RpakAliases.find(*map) != mod->RpakAliases.end()) + if (mod.RpakAliases.find(*map) != mod.RpakAliases.end()) { - *map = &mod->RpakAliases[*map][0]; + *map = &mod.RpakAliases[*map][0]; return; } } @@ -106,7 +105,7 @@ void HandlePakAliases(char** map) void LoadPreloadPaks() { // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; @@ -123,7 +122,7 @@ void LoadPreloadPaks() void LoadPostloadPaks(const char* pPath) { // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; @@ -143,7 +142,7 @@ void LoadCustomMapPaks(char** pakName, bool* bNeedToFreePakName) bool bHasOriginalPak = fs::exists(fs::path("r2/paks/Win64/") / *pakName); // note, loading from ./ is necessary otherwise paks will load from gamedir/r2/paks - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; @@ -272,8 +271,8 @@ void*, __fastcall, (const char* pPath, void* pCallback)) NS::log::rpak->info("LoadStreamBsp: {}", filename.string()); // resolve modded stbsp path so we can load mod stbsps - auto modFile = g_pModManager->m_ModFiles.find(g_pModManager->NormaliseModFilePath(fs::path("maps" / filename))); - if (modFile != g_pModManager->m_ModFiles.end()) + auto modFile = g_pModManager->GetModFiles().find(g_pModManager->NormaliseModFilePath(fs::path("maps" / filename))); + if (modFile != g_pModManager->GetModFiles().end()) { newPath = (modFile->second.m_pOwningMod->m_ModDirectory / "mod" / modFile->second.m_Path).string(); pPath = newPath.c_str(); @@ -304,7 +303,7 @@ void*, __fastcall, (const char* pPath, void* pCallback)) size_t hashed = STR_HASH(starpakPath); // loop through all loaded mods - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { // ignore non-loaded mods if (!mod.m_bEnabled) diff --git a/NorthstarDLL/logging/crashhandler.cpp b/NorthstarDLL/logging/crashhandler.cpp index 5d120d1f..38d9312f 100644 --- a/NorthstarDLL/logging/crashhandler.cpp +++ b/NorthstarDLL/logging/crashhandler.cpp @@ -33,12 +33,10 @@ void PrintExceptionLog(ExceptionLog& exc) if (g_pModManager) { spdlog::error("Loaded mods: "); - for (const auto& mod : g_pModManager->m_LoadedMods) + for (const Mod& mod : g_pModManager->GetMods()) { if (mod.m_bEnabled) - { spdlog::error("{} {}", mod.Name, mod.Version); - } } } spdlog::error(exc.cause); diff --git a/NorthstarDLL/mods/compiled/kb_act.cpp b/NorthstarDLL/mods/compiled/kb_act.cpp index 3fc7ee30..109dc910 100644 --- a/NorthstarDLL/mods/compiled/kb_act.cpp +++ b/NorthstarDLL/mods/compiled/kb_act.cpp @@ -16,7 +16,7 @@ void ModManager::BuildKBActionsList() // write vanilla file's content to compiled file soCompiledKeys << R2::ReadVPKOriginalFile(KB_ACT_PATH); - for (Mod& mod : m_LoadedMods) + for (Mod& mod : GetMods()) { if (!mod.m_bEnabled) continue; @@ -37,8 +37,8 @@ void ModManager::BuildKBActionsList() overrideFile.m_pOwningMod = nullptr; overrideFile.m_Path = KB_ACT_PATH; - if (m_ModFiles.find(KB_ACT_PATH) == m_ModFiles.end()) - m_ModFiles.insert(std::make_pair(KB_ACT_PATH, overrideFile)); + if (GetModFiles().find(KB_ACT_PATH) == GetModFiles().end()) + GetModFiles().insert(std::make_pair(KB_ACT_PATH, overrideFile)); else - m_ModFiles[KB_ACT_PATH] = overrideFile; + GetModFiles()[KB_ACT_PATH] = overrideFile; } diff --git a/NorthstarDLL/mods/compiled/modkeyvalues.cpp b/NorthstarDLL/mods/compiled/modkeyvalues.cpp index fe262a60..ff2fafc1 100644 --- a/NorthstarDLL/mods/compiled/modkeyvalues.cpp +++ b/NorthstarDLL/mods/compiled/modkeyvalues.cpp @@ -24,14 +24,14 @@ void ModManager::TryBuildKeyValues(const char* filename) // copy over patch kv files, and add #bases to new file, last mods' patches should be applied first // note: #include should be identical but it's actually just broken, thanks respawn - for (int64_t i = m_LoadedMods.size() - 1; i > -1; i--) + for (Mod& mod : GetMods() | std::views::reverse) { - if (!m_LoadedMods[i].m_bEnabled) + if (mod.m_bEnabled) continue; size_t fileHash = STR_HASH(normalisedPath); - auto modKv = m_LoadedMods[i].KeyValues.find(fileHash); - if (modKv != m_LoadedMods[i].KeyValues.end()) + auto modKv = mod.KeyValues.find(fileHash); + if (modKv != mod.KeyValues.end()) { // should result in smth along the lines of #include "mod_patch_5_mp_weapon_car.txt" @@ -46,7 +46,7 @@ void ModManager::TryBuildKeyValues(const char* filename) fs::remove(compiledDir / patchFilePath); - fs::copy_file(m_LoadedMods[i].m_ModDirectory / "keyvalues" / filename, compiledDir / patchFilePath); + fs::copy_file(mod.m_ModDirectory / "keyvalues" / filename, compiledDir / patchFilePath); } } @@ -99,8 +99,8 @@ void ModManager::TryBuildKeyValues(const char* filename) overrideFile.m_pOwningMod = nullptr; overrideFile.m_Path = normalisedPath; - if (m_ModFiles.find(normalisedPath) == m_ModFiles.end()) - m_ModFiles.insert(std::make_pair(normalisedPath, overrideFile)); + if (GetModFiles().find(normalisedPath) == GetModFiles().end()) + GetModFiles().insert(std::make_pair(normalisedPath, overrideFile)); else - m_ModFiles[normalisedPath] = overrideFile; + GetModFiles()[normalisedPath] = overrideFile; } diff --git a/NorthstarDLL/mods/compiled/modpdef.cpp b/NorthstarDLL/mods/compiled/modpdef.cpp deleted file mode 100644 index 4b1b12b7..00000000 --- a/NorthstarDLL/mods/compiled/modpdef.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "mods/modmanager.h" -#include "core/filesystem/filesystem.h" - -#include <map> -#include <sstream> -#include <fstream> - -const fs::path MOD_PDEF_SUFFIX = "cfg/server/persistent_player_data_version_231.pdef"; -const char* VPK_PDEF_PATH = "cfg/server/persistent_player_data_version_231.pdef"; - -void ModManager::BuildPdef() -{ - spdlog::info("Building persistent_player_data_version_231.pdef..."); - - fs::path MOD_PDEF_PATH = fs::path(GetCompiledAssetsPath() / MOD_PDEF_SUFFIX); - - fs::remove(MOD_PDEF_PATH); - std::string pdef = R2::ReadVPKOriginalFile(VPK_PDEF_PATH); - - for (Mod& mod : m_LoadedMods) - { - if (!mod.m_bEnabled || !mod.Pdiff.size()) - continue; - - // this code probably isn't going to be pretty lol - // refer to shared/pjson.js for an actual okish parser of the pdiff format - // but pretty much, $ENUM_ADD blocks define members added to preexisting enums - // $PROP_START ends the custom stuff, and from there it's just normal props we append to the pdef - - std::map<std::string, std::vector<std::string>> enumAdds; - - // read pdiff - bool inEnum = false; - bool inProp = false; - std::string currentEnum; - std::string currentLine; - std::istringstream pdiffStream(mod.Pdiff); - - while (std::getline(pdiffStream, currentLine)) - { - if (inProp) - { - // just append to pdef here - pdef += currentLine; - pdef += '\n'; - continue; - } - - // trim leading whitespace - size_t start = currentLine.find_first_not_of(" \n\r\t\f\v"); - size_t end = currentLine.find("//"); - if (end == std::string::npos) - end = currentLine.size() - 1; // last char - - if (!currentLine.size() || !currentLine.compare(start, 2, "//")) - continue; - - if (inEnum) - { - if (!currentLine.compare(start, 9, "$ENUM_END")) - inEnum = false; - else - enumAdds[currentEnum].push_back(currentLine); // only need to push_back current line, if there's syntax errors then game - // pdef parser will handle them - } - else if (!currentLine.compare(start, 9, "$ENUM_ADD")) - { - inEnum = true; - currentEnum = currentLine.substr(start + 10 /*$ENUM_ADD + 1*/, currentLine.size() - end - (start + 10)); - enumAdds.insert(std::make_pair(currentEnum, std::vector<std::string>())); - } - else if (!currentLine.compare(start, 11, "$PROP_START")) - { - inProp = true; - pdef += "\n// $PROP_START "; - pdef += mod.Name; - pdef += "\n"; - } - } - - // add new members to preexisting enums - // note: this code could 100% be messed up if people put //$ENUM_START comments and the like - // could make it protect against this, but honestly not worth atm - for (auto enumAdd : enumAdds) - { - std::string addStr; - for (std::string enumMember : enumAdd.second) - { - addStr += enumMember; - addStr += '\n'; - } - - // start of enum we're adding to - std::string startStr = "$ENUM_START "; - startStr += enumAdd.first; - - // insert enum values into enum - size_t insertIdx = pdef.find("$ENUM_END", pdef.find(startStr)); - pdef.reserve(addStr.size()); - pdef.insert(insertIdx, addStr); - } - } - - fs::create_directories(MOD_PDEF_PATH.parent_path()); - - std::ofstream writeStream(MOD_PDEF_PATH, std::ios::binary); - writeStream << pdef; - writeStream.close(); - - ModOverrideFile overrideFile; - overrideFile.m_pOwningMod = nullptr; - overrideFile.m_Path = VPK_PDEF_PATH; - - if (m_ModFiles.find(VPK_PDEF_PATH) == m_ModFiles.end()) - m_ModFiles.insert(std::make_pair(VPK_PDEF_PATH, overrideFile)); - else - m_ModFiles[VPK_PDEF_PATH] = overrideFile; -} diff --git a/NorthstarDLL/mods/compiled/modscriptsrson.cpp b/NorthstarDLL/mods/compiled/modscriptsrson.cpp index cbe26651..292e9c99 100644 --- a/NorthstarDLL/mods/compiled/modscriptsrson.cpp +++ b/NorthstarDLL/mods/compiled/modscriptsrson.cpp @@ -16,7 +16,7 @@ void ModManager::BuildScriptsRson() std::string scriptsRson = R2::ReadVPKOriginalFile(VPK_SCRIPTS_RSON_PATH); scriptsRson += "\n\n// START MODDED SCRIPT CONTENT\n\n"; // newline before we start custom stuff - for (Mod& mod : m_LoadedMods) + for (Mod& mod : GetMods()) { if (!mod.m_bEnabled) continue; @@ -55,10 +55,10 @@ void ModManager::BuildScriptsRson() overrideFile.m_pOwningMod = nullptr; overrideFile.m_Path = VPK_SCRIPTS_RSON_PATH; - if (m_ModFiles.find(VPK_SCRIPTS_RSON_PATH) == m_ModFiles.end()) - m_ModFiles.insert(std::make_pair(VPK_SCRIPTS_RSON_PATH, overrideFile)); + if (GetModFiles().find(VPK_SCRIPTS_RSON_PATH) == GetModFiles().end()) + GetModFiles().insert(std::make_pair(VPK_SCRIPTS_RSON_PATH, overrideFile)); else - m_ModFiles[VPK_SCRIPTS_RSON_PATH] = overrideFile; + GetModFiles()[VPK_SCRIPTS_RSON_PATH] = overrideFile; // todo: for preventing dupe scripts in scripts.rson, we could actually parse when conditions with the squirrel vm, just need a way to // get a result out of squirrelmanager.ExecuteCode this would probably be the best way to do this, imo diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index 4e5380cf..04484fad 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -97,27 +97,27 @@ Mod::Mod(fs::path modDir, char* jsonBuf) // have to allocate this manually, otherwise convar registration will break // unfortunately this causes us to leak memory on reload, unsure of a way around this rn - ModConVar* convar = new ModConVar; - convar->Name = convarObj["Name"].GetString(); - convar->DefaultValue = convarObj["DefaultValue"].GetString(); + ModConVar convar; + convar.Name = convarObj["Name"].GetString(); + convar.DefaultValue = convarObj["DefaultValue"].GetString(); if (convarObj.HasMember("HelpString")) - convar->HelpString = convarObj["HelpString"].GetString(); + convar.HelpString = convarObj["HelpString"].GetString(); else - convar->HelpString = ""; + convar.HelpString = ""; - convar->Flags = FCVAR_NONE; + convar.Flags = FCVAR_NONE; if (convarObj.HasMember("Flags")) { // read raw integer flags if (convarObj["Flags"].IsInt()) - convar->Flags = convarObj["Flags"].GetInt(); + convar.Flags = convarObj["Flags"].GetInt(); else if (convarObj["Flags"].IsString()) { // parse cvar flags from string // example string: ARCHIVE_PLAYERPROFILE | GAMEDLL - convar->Flags |= ParseConVarFlagsString(convar->Name, convarObj["Flags"].GetString()); + convar.Flags |= ParseConVarFlagsString(convar.Name, convarObj["Flags"].GetString()); } } @@ -125,6 +125,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf) } } + // mod commands if (modJson.HasMember("ConCommands") && modJson["ConCommands"].IsArray()) { for (auto& concommandObj : modJson["ConCommands"].GetArray()) @@ -137,35 +138,35 @@ Mod::Mod(fs::path modDir, char* jsonBuf) // have to allocate this manually, otherwise concommand registration will break // unfortunately this causes us to leak memory on reload, unsure of a way around this rn - ModConCommand* concommand = new ModConCommand; - concommand->Name = concommandObj["Name"].GetString(); - concommand->Function = concommandObj["Function"].GetString(); - concommand->Context = ScriptContextFromString(concommandObj["Context"].GetString()); - if (concommand->Context == ScriptContext::INVALID) + ModConCommand concommand; + concommand.Name = concommandObj["Name"].GetString(); + concommand.Function = concommandObj["Function"].GetString(); + concommand.Context = ScriptContextFromString(concommandObj["Context"].GetString()); + if (concommand.Context == ScriptContext::INVALID) { - spdlog::warn("Mod ConCommand {} has invalid context {}", concommand->Name, concommandObj["Context"].GetString()); + spdlog::warn("Mod ConCommand {} has invalid context {}", concommand.Name, concommandObj["Context"].GetString()); continue; } if (concommandObj.HasMember("HelpString")) - concommand->HelpString = concommandObj["HelpString"].GetString(); + concommand.HelpString = concommandObj["HelpString"].GetString(); else - concommand->HelpString = ""; + concommand.HelpString = ""; - concommand->Flags = FCVAR_NONE; + concommand.Flags = FCVAR_NONE; if (concommandObj.HasMember("Flags")) { // read raw integer flags if (concommandObj["Flags"].IsInt()) { - concommand->Flags = concommandObj["Flags"].GetInt(); + concommand.Flags = concommandObj["Flags"].GetInt(); } else if (concommandObj["Flags"].IsString()) { // parse cvar flags from string // example string: ARCHIVE_PLAYERPROFILE | GAMEDLL - concommand->Flags |= ParseConVarFlagsString(concommand->Name, concommandObj["Flags"].GetString()); + concommand.Flags |= ParseConVarFlagsString(concommand.Name, concommandObj["Flags"].GetString()); } } @@ -288,66 +289,54 @@ ModManager::ModManager() LoadMods(); } -struct Test -{ - std::string funcName; - ScriptContext context; -}; - template <ScriptContext context> auto ModConCommandCallback_Internal(std::string name, const CCommand& command) { - if (g_pSquirrel<context>->m_pSQVM && g_pSquirrel<context>->m_pSQVM) + if (g_pSquirrel<context>->m_pSQVM && g_pSquirrel<context>->m_pSQVM->sqvm) { - std::vector<std::string> args; - args.reserve(command.ArgC()); + std::vector<std::string> vArgs; + vArgs.reserve(command.ArgC()); for (int i = 1; i < command.ArgC(); i++) - args.push_back(command.Arg(i)); - g_pSquirrel<context>->AsyncCall(name, args); + vArgs.push_back(command.Arg(i)); + + g_pSquirrel<context>->AsyncCall(name, vArgs); } else - { - spdlog::warn("ConCommand `{}` was called while the associated Squirrel VM `{}` was unloaded", name, GetContextName(context)); - } + spdlog::warn("ConCommand \"{}\" was called while the associated Squirrel VM \"{}\" was unloaded", name, GetContextName(context)); } auto ModConCommandCallback(const CCommand& command) { - ModConCommand* found = nullptr; - auto commandString = std::string(command.GetCommandString()); - - // Finding the first space to remove the command's name - auto firstSpace = commandString.find(' '); - if (firstSpace) - { - commandString = commandString.substr(0, firstSpace); - } + ModConCommand* pFoundCommand = nullptr; + std::string sCommandName = command.Arg(0); // Find the mod this command belongs to - for (auto& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { auto res = std::find_if( mod.ConCommands.begin(), mod.ConCommands.end(), - [&commandString](const ModConCommand* other) { return other->Name == commandString; }); + [&sCommandName](const ModConCommand* other) { return other->Name == sCommandName; }); + if (res != mod.ConCommands.end()) { - found = *res; + pFoundCommand = &*res; break; } } - if (!found) + + if (!pFoundCommand) return; - switch (found->Context) + switch (pFoundCommand->Context) { case ScriptContext::CLIENT: - ModConCommandCallback_Internal<ScriptContext::CLIENT>(found->Function, command); + ModConCommandCallback_Internal<ScriptContext::CLIENT>(pFoundCommand->Function, command); break; case ScriptContext::SERVER: - ModConCommandCallback_Internal<ScriptContext::SERVER>(found->Function, command); + ModConCommandCallback_Internal<ScriptContext::SERVER>(pFoundCommand->Function, command); break; case ScriptContext::UI: - ModConCommandCallback_Internal<ScriptContext::UI>(found->Function, command); + ModConCommandCallback_Internal<ScriptContext::UI>(pFoundCommand->Function, command); break; }; } @@ -443,7 +432,10 @@ void ModManager::LoadMods() } // sort by load prio, lowest-highest - std::sort(m_LoadedMods.begin(), m_LoadedMods.end(), [](Mod& a, Mod& b) { return a.LoadPriority < b.LoadPriority; }); + std::sort( + m_ModLoadState.m_LoadedMods.begin(), + m_ModLoadState.m_LoadedMods.end(), + [](Mod& a, Mod& b) { return a.LoadPriority < b.LoadPriority; }); for (Mod& mod : m_LoadedMods) { @@ -451,47 +443,47 @@ void ModManager::LoadMods() continue; // register convars - for (ModConVar* convar : mod.ConVars) + for (ModConVar convar : mod.ConVars) { - ConVar* pVar = R2::g_pCVar->FindVar(convar->Name.c_str()); + ConVar* pVar = R2::g_pCVar->FindVar(convar.Name.c_str()); // make sure convar isn't registered yet, if it is then modify its flags, helpstring etc if (!pVar) - new ConVar(convar->Name.c_str(), convar->DefaultValue.c_str(), convar->Flags, convar->HelpString.c_str()); + new ConVar(convar.Name.c_str(), convar.DefaultValue.c_str(), convar.Flags, convar.HelpString.c_str()); else { // TODO: should probably make sure this is actually a mod convar we're messing with - pVar->m_ConCommandBase.m_nFlags = convar->Flags; + pVar->m_ConCommandBase.m_nFlags = convar.Flags; // unfortunately this leaks memory and we can't really not leak memory because we don't know who allocated this // so we can't delete it without risking a crash - if (convar->HelpString.compare(pVar->GetHelpText())) + if (convar.HelpString.compare(pVar->GetHelpText())) { - int nHelpSize = convar->HelpString.size(); + int nHelpSize = convar.HelpString.size(); char* pNewHelpString = new char[nHelpSize + 1]; - strncpy_s(pNewHelpString, nHelpSize + 1, convar->HelpString.c_str(), convar->HelpString.size()); + strncpy_s(pNewHelpString, nHelpSize + 1, convar.HelpString.c_str(), convar.HelpString.size()); pVar->m_ConCommandBase.m_pszHelpString = pNewHelpString; } - if (convar->DefaultValue.compare(pVar->m_pszDefaultValue)) + if (convar.DefaultValue.compare(pVar->m_pszDefaultValue)) { - int nDefaultValueSize = convar->DefaultValue.size(); + int nDefaultValueSize = convar.DefaultValue.size(); char* pNewDefaultValueString = new char[nDefaultValueSize + 1]; - strncpy_s(pNewDefaultValueString, nDefaultValueSize + 1, convar->DefaultValue.c_str(), convar->DefaultValue.size()); + strncpy_s(pNewDefaultValueString, nDefaultValueSize + 1, convar.DefaultValue.c_str(), convar.DefaultValue.size()); pVar->m_pszDefaultValue = pNewDefaultValueString; pVar->SetValue(pNewDefaultValueString); } } } - for (ModConCommand* command : mod.ConCommands) + for (ModConCommand command : mod.ConCommands) { // make sure command isnt't registered multiple times. - if (!R2::g_pCVar->FindCommand(command->Name.c_str())) + if (!R2::g_pCVar->FindCommand(command.Name.c_str())) { - std::string funcName = command->Function; - RegisterConCommand(command->Name.c_str(), ModConCommandCallback, command->HelpString.c_str(), command->Flags); + std::string funcName = command.Function; + RegisterConCommand(command.Name.c_str(), ModConCommandCallback, command.HelpString.c_str(), command.Flags); } } @@ -754,6 +746,8 @@ void ModManager::LoadMods() void ModManager::UnloadMods() { + m_LastModLoadState = m_ModLoadState; + // clean up stuff from mods before we unload m_ModFiles.clear(); fs::remove_all(GetCompiledAssetsPath()); @@ -769,8 +763,6 @@ void ModManager::UnloadMods() for (std::pair<size_t, std::string> kvPaths : mod.KeyValues) fs::remove(GetCompiledAssetsPath() / fs::path(kvPaths.second).lexically_relative(mod.m_ModDirectory)); - mod.KeyValues.clear(); - // write to m_enabledModsCfg // should we be doing this here or should scripts be doing this manually? // main issue with doing this here is when we reload mods for connecting to a server, we write enabled mods, which isn't necessarily @@ -809,13 +801,15 @@ void ModManager::CompileAssetsForFile(const char* filename) if (fileHash == m_hScriptsRsonHash) BuildScriptsRson(); else if (fileHash == m_hPdefHash) - BuildPdef(); + { + // BuildPdef(); todo + } else if (fileHash == m_hKBActHash) BuildKBActionsList(); else { // check if we should build keyvalues, depending on whether any of our mods have patch kvs for this file - for (Mod& mod : m_LoadedMods) + for (Mod& mod : GetMods()) { if (!mod.m_bEnabled) continue; diff --git a/NorthstarDLL/mods/modmanager.h b/NorthstarDLL/mods/modmanager.h index 369eb07b..d44a202f 100644 --- a/NorthstarDLL/mods/modmanager.h +++ b/NorthstarDLL/mods/modmanager.h @@ -98,9 +98,9 @@ class Mod // custom scripts used by the mod std::vector<ModScript> Scripts; // convars created by the mod - std::vector<ModConVar*> ConVars; + std::vector<ModConVar> ConVars; // concommands created by the mod - std::vector<ModConCommand*> ConCommands; + std::vector<ModConCommand> ConCommands; // custom localisation files created by the mod std::vector<std::string> LocalisationFiles; @@ -127,10 +127,18 @@ class Mod struct ModOverrideFile { public: - Mod* m_pOwningMod; + Mod* m_pOwningMod; // don't need to explicitly clean this up fs::path m_Path; }; +class ModLoadState +{ + public: + std::vector<Mod> m_LoadedMods; + std::unordered_map<std::string, ModOverrideFile> m_ModFiles; + std::unordered_map<std::string, std::string> m_DependencyConstants; +}; + class ModManager { private: @@ -144,9 +152,8 @@ class ModManager size_t m_hKBActHash; public: - std::vector<Mod> m_LoadedMods; - std::unordered_map<std::string, ModOverrideFile> m_ModFiles; - std::unordered_map<std::string, std::string> m_DependencyConstants; + ModLoadState m_LastModLoadState; + ModLoadState m_ModLoadState; public: ModManager(); @@ -155,6 +162,22 @@ class ModManager std::string NormaliseModFilePath(const fs::path path); void CompileAssetsForFile(const char* filename); + // getters + inline std::vector<Mod>& GetMods() + { + return m_ModLoadState.m_LoadedMods; + }; + + inline std::unordered_map<std::string, ModOverrideFile>& GetModFiles() + { + return m_ModLoadState.m_ModFiles; + }; + + inline std::unordered_map<std::string, std::string>& GetDependencyConstants() + { + return m_ModLoadState.m_DependencyConstants; + }; + // compile asset type stuff, these are done in files under runtime/compiled/ void BuildScriptsRson(); void TryBuildKeyValues(const char* filename); diff --git a/NorthstarDLL/pch.h b/NorthstarDLL/pch.h index 55ebba8b..433030b6 100644 --- a/NorthstarDLL/pch.h +++ b/NorthstarDLL/pch.h @@ -17,6 +17,8 @@ #include <map> #include <filesystem> #include <sstream> +#include <ranges> +#include <vector> namespace fs = std::filesystem; diff --git a/NorthstarDLL/scripts/client/scriptmodmenu.cpp b/NorthstarDLL/scripts/client/scriptmodmenu.cpp index a88478fb..c6c53c7f 100644 --- a/NorthstarDLL/scripts/client/scriptmodmenu.cpp +++ b/NorthstarDLL/scripts/client/scriptmodmenu.cpp @@ -5,7 +5,7 @@ ADD_SQFUNC("array<string>", NSGetModNames, "", "", ScriptContext::SERVER | Scrip { g_pSquirrel<context>->newarray(sqvm, 0); - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { g_pSquirrel<context>->pushstring(sqvm, mod.Name.c_str()); g_pSquirrel<context>->arrayappend(sqvm, -2); @@ -19,7 +19,7 @@ ADD_SQFUNC("bool", NSIsModEnabled, "string modName", "", ScriptContext::SERVER | const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -37,7 +37,7 @@ ADD_SQFUNC("void", NSSetModEnabled, "string modName, bool enabled", "", ScriptCo const SQBool enabled = g_pSquirrel<context>->getbool(sqvm, 2); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -54,7 +54,7 @@ ADD_SQFUNC("string", NSGetModDescriptionByModName, "string modName", "", ScriptC const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -71,7 +71,7 @@ ADD_SQFUNC("string", NSGetModVersionByModName, "string modName", "", ScriptConte const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -88,7 +88,7 @@ ADD_SQFUNC("string", NSGetModDownloadLinkByModName, "string modName", "", Script const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -105,7 +105,7 @@ ADD_SQFUNC("int", NSGetModLoadPriority, "string modName", "", ScriptContext::SER const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -122,7 +122,7 @@ ADD_SQFUNC("bool", NSIsModRequiredOnClient, "string modName", "", ScriptContext: const SQChar* modName = g_pSquirrel<context>->getstring(sqvm, 1); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { @@ -141,7 +141,7 @@ ADD_SQFUNC( g_pSquirrel<context>->newarray(sqvm, 0); // manual lookup, not super performant but eh not a big deal - for (Mod& mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.Name.compare(modName)) { diff --git a/NorthstarDLL/squirrel/squirrel.cpp b/NorthstarDLL/squirrel/squirrel.cpp index 4cf342db..4e64aecc 100644 --- a/NorthstarDLL/squirrel/squirrel.cpp +++ b/NorthstarDLL/squirrel/squirrel.cpp @@ -189,11 +189,11 @@ template <ScriptContext context> void SquirrelManager<context>::VMCreated(CSquir RegisterSquirrelFunc(m_pSQVM, funcReg, 1); } - for (auto& pair : g_pModManager->m_DependencyConstants) + for (auto& pair : g_pModManager->GetDependencyConstants()) { bool bWasFound = false; - for (Mod& dependency : g_pModManager->m_LoadedMods) + for (Mod& dependency : g_pModManager->GetMods()) { if (!dependency.m_bEnabled) continue; @@ -471,7 +471,7 @@ template <ScriptContext context> bool __fastcall CallScriptInitCallbackHook(void if (bShouldCallCustomCallbacks) { - for (Mod mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; @@ -498,7 +498,7 @@ template <ScriptContext context> bool __fastcall CallScriptInitCallbackHook(void // run after callbacks if (bShouldCallCustomCallbacks) { - for (Mod mod : g_pModManager->m_LoadedMods) + for (Mod& mod : g_pModManager->GetMods()) { if (!mod.m_bEnabled) continue; diff --git a/NorthstarDLL/squirrel/squirrel.h b/NorthstarDLL/squirrel/squirrel.h index ce758d7c..65bda7e3 100644 --- a/NorthstarDLL/squirrel/squirrel.h +++ b/NorthstarDLL/squirrel/squirrel.h @@ -239,17 +239,15 @@ class SquirrelManagerBase { SQStackInfos stackInfo {}; if (1 + depth >= sqvm->_callstacksize) - { return nullptr; - } + sq_stackinfos(sqvm, 1 + depth, stackInfo); std::string sourceName = stackInfo._sourceName; std::replace(sourceName.begin(), sourceName.end(), '/', '\\'); std::string filename = "scripts\\vscripts\\" + sourceName; - if (auto res = g_pModManager->m_ModFiles.find(filename); res != g_pModManager->m_ModFiles.end()) - { + if (auto res = g_pModManager->GetModFiles().find(filename); res != g_pModManager->GetModFiles().end()) return res->second.m_pOwningMod; - } + return nullptr; } template <typename T> inline SQRESULT getuserdata(HSquirrelVM* sqvm, const SQInteger stackpos, T* data, uint64_t* typeId) diff --git a/NorthstarDLL/util/printmaps.cpp b/NorthstarDLL/util/printmaps.cpp index 99bda23c..449aa351 100644 --- a/NorthstarDLL/util/printmaps.cpp +++ b/NorthstarDLL/util/printmaps.cpp @@ -36,7 +36,7 @@ void RefreshMapList() // get modded maps // TODO: could probably check mod vpks to get mapnames from there too? - for (auto& modFilePair : g_pModManager->m_ModFiles) + for (auto& modFilePair : g_pModManager->GetModFiles()) { ModOverrideFile file = modFilePair.second; if (file.m_Path.extension() == ".bsp" && file.m_Path.parent_path().string() == "maps") // only allow mod maps actually in /maps atm |