diff options
Diffstat (limited to 'NorthstarDedicatedTest/modmanager.cpp')
-rw-r--r-- | NorthstarDedicatedTest/modmanager.cpp | 178 |
1 files changed, 175 insertions, 3 deletions
diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index d6ccfa6a..72998347 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -1,9 +1,136 @@ #include "pch.h" -#include "ModManager.h" -#include "rapidjson/rapidjson.h" +#include "modmanager.h" +#include "convar.h" + +#include "rapidjson/error/en.h" +#include "rapidjson/document.h" +#include <filesystem> +#include <fstream> +#include <string> +#include <sstream> +#include <vector> ModManager* g_ModManager; +Mod::Mod(fs::path modDir, char* jsonBuf) +{ + wasReadSuccessfully = false; + + rapidjson::Document modJson; + modJson.Parse<rapidjson::ParseFlag::kParseCommentsFlag | rapidjson::ParseFlag::kParseTrailingCommasFlag>(jsonBuf); + + // fail if parse error + if (modJson.HasParseError()) + { + spdlog::error("Failed reading mod file {}: encountered parse error \"{}\" at offset {}", (modDir / "mod.json").string(), GetParseError_En(modJson.GetParseError()), modJson.GetErrorOffset()); + return; + } + + // fail if it's not a json obj (could be an array, string, etc) + if (!modJson.IsObject()) + { + spdlog::error("Failed reading mod file {}: file is not a JSON object", (modDir / "mod.json").string()); + return; + } + + // basic mod info + // name is required + if (!modJson.HasMember("Name")) + { + spdlog::error("Failed reading mod file {}: missing required member \"Name\"", (modDir / "mod.json").string()); + return; + } + + Name = modJson["Name"].GetString(); + + if (modJson.HasMember("Description")) + Description = modJson["Description"].GetString(); + else + Description = ""; + + if (modJson.HasMember("Version")) + Version = modJson["Version"].GetString(); + else + { + Version = "0.0.0"; + spdlog::warn("Mod file {} is missing a version, consider adding a version", (modDir / "mod.json").string()); + } + + if (modJson.HasMember("DownloadLink")) + DownloadLink = modJson["DownloadLink"].GetString(); + else + DownloadLink = ""; + + if (modJson.HasMember("RequiredOnClient")) + RequiredOnClient = modJson["RequiredOnClient"].GetBool(); + else + RequiredOnClient = false; + + // mod convars + if (modJson.HasMember("ConVars") && modJson["ConVars"].IsArray()) + { + for (auto& convarObj : modJson["ConVars"].GetArray()) + { + if (!convarObj.IsObject() || !convarObj.HasMember("Name") || !convarObj.HasMember("DefaultValue")) + continue; + + ModConVar* convar = new ModConVar; + convar->Name = convarObj["Name"].GetString(); + convar->DefaultValue = convarObj["DefaultValue"].GetString(); + + if (convarObj.HasMember("HelpString")) + convar->HelpString = convarObj["HelpString"].GetString(); + else + convar->HelpString = ""; + + // todo: could possibly parse FCVAR names here instead + if (convarObj.HasMember("Flags")) + convar->Flags = convarObj["Flags"].GetInt(); + else + convar->Flags = FCVAR_NONE; + + ConVars.push_back(convar); + } + } + + // mod scripts + if (modJson.HasMember("Scripts") && modJson["Scripts"].IsArray()) + { + for (auto& scriptObj : modJson["Scripts"].GetArray()) + { + if (!scriptObj.IsObject() || !scriptObj.HasMember("Path") || !scriptObj.HasMember("RunOn")) + continue; + + ModScript* script = new ModScript; + + script->Path = scriptObj["Path"].GetString(); + script->RsonRunOn = scriptObj["RunOn"].GetString(); + + // callbacks + for (auto iterator = scriptObj.MemberBegin(); iterator != scriptObj.MemberEnd(); iterator++) + { + if (!iterator->name.IsString() || !iterator->value.IsObject()) + continue; + + ModScriptCallback* callback = new ModScriptCallback; + callback->HookedCodeCallback = iterator->name.GetString(); + + if (iterator->value.HasMember("Before") && iterator->value["Before"].IsString()) + callback->BeforeCallback = iterator->value["Before"].GetString(); + + if (iterator->value.HasMember("After") && iterator->value["After"].IsString()) + callback->AfterCallback = iterator->value["After"].GetString(); + + script->Callbacks.push_back(callback); + } + + Scripts.push_back(script); + } + } + + wasReadSuccessfully = true; +} + ModManager::ModManager() { LoadMods(); @@ -11,10 +138,55 @@ ModManager::ModManager() void ModManager::LoadMods() { + std::vector<fs::path> modDirs; + + // get mod directories + for (fs::directory_entry dir : fs::directory_iterator(MOD_FOLDER_PATH)) + if (fs::exists(dir.path() / "mod.json")) + modDirs.push_back(dir.path()); + + for (fs::path modDir : modDirs) + { + // read mod json file + std::ifstream jsonStream(modDir / "mod.json"); + std::stringstream jsonStringStream; + + // fail if no mod json + if (jsonStream.fail()) + { + spdlog::warn("Mod {} has a directory but no mod.json", modDir.string()); + continue; + } + + while (jsonStream.peek() != EOF) + jsonStringStream << (char)jsonStream.get(); + + jsonStream.close(); + + Mod* mod = new Mod(modDir, (char*)jsonStringStream.str().c_str()); + + if (mod->wasReadSuccessfully) + { + spdlog::info("Loaded mod {} successfully", mod->Name); + loadedMods.push_back(mod); + } + else + { + spdlog::warn("Skipping loading mod file {}", (modDir / "mod.json").string()); + delete mod; + } + } + + for (Mod* mod : loadedMods) + { + for (ModConVar* convar : mod->ConVars) + if (g_CustomConvars.find(convar->Name) == g_CustomConvars.end()) // make sure convar isn't registered yet + RegisterConVar(convar->Name.c_str(), convar->DefaultValue.c_str(), convar->Flags, convar->HelpString.c_str()); + } } void InitialiseModManager(HMODULE baseAddress) { - g_ModManager = new ModManager; + g_ModManager = new ModManager(); }
\ No newline at end of file |