diff options
Diffstat (limited to 'NorthstarDLL/mods')
-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 | 119 | ||||
-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 |
6 files changed, 108 insertions, 210 deletions
diff --git a/NorthstarDLL/mods/compiled/kb_act.cpp b/NorthstarDLL/mods/compiled/kb_act.cpp index 4a011dc7..f3ad460f 100644 --- a/NorthstarDLL/mods/compiled/kb_act.cpp +++ b/NorthstarDLL/mods/compiled/kb_act.cpp @@ -17,7 +17,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; @@ -38,8 +38,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 774be0eb..051b193e 100644 --- a/NorthstarDLL/mods/compiled/modkeyvalues.cpp +++ b/NorthstarDLL/mods/compiled/modkeyvalues.cpp @@ -25,14 +25,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" @@ -47,7 +47,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); } } @@ -100,8 +100,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 219c744b..00000000 --- a/NorthstarDLL/mods/compiled/modpdef.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "pch.h" -#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 15fcdd13..b24aabe9 100644 --- a/NorthstarDLL/mods/compiled/modscriptsrson.cpp +++ b/NorthstarDLL/mods/compiled/modscriptsrson.cpp @@ -17,7 +17,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; @@ -56,10 +56,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 891ab978..754f648b 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -98,27 +98,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()); } } @@ -126,6 +126,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf) } } + // mod commands if (modJson.HasMember("ConCommands") && modJson["ConCommands"].IsArray()) { for (auto& concommandObj : modJson["ConCommands"].GetArray()) @@ -138,35 +139,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()); } } @@ -280,66 +281,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; }; } @@ -430,7 +419,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) { @@ -438,47 +430,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); } } @@ -741,6 +733,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()); @@ -756,8 +750,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 @@ -796,13 +788,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 ded6ff06..57ae8581 100644 --- a/NorthstarDLL/mods/modmanager.h +++ b/NorthstarDLL/mods/modmanager.h @@ -96,9 +96,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; @@ -125,10 +125,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: @@ -142,9 +150,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(); @@ -153,6 +160,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); |