From 87a665fb7f5f20bb5b9bb80052c553b9e0c17ae1 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 14 Nov 2024 15:41:22 +0000 Subject: [PATCH] Restored all disabled mod functinality that was used by client --- client/mainmenu/CMainMenu.cpp | 11 -- launcher/modManager/cmodlistview_moc.cpp | 2 +- lib/modding/CModHandler.cpp | 118 ++++++++-------- lib/modding/CModHandler.h | 11 +- lib/modding/ContentTypeHandler.cpp | 69 ++-------- lib/modding/ContentTypeHandler.h | 11 +- lib/modding/ModDescription.cpp | 2 +- lib/modding/ModDescription.h | 3 +- lib/modding/ModManager.cpp | 168 ++++++++++++----------- lib/modding/ModManager.h | 15 +- vcmiqt/jsonutils.cpp | 2 +- 11 files changed, 180 insertions(+), 232 deletions(-) diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index 565d8bb9a..f3702101c 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -362,17 +362,6 @@ void CMainMenu::update() menu->switchToTab(menu->getActiveTab()); } - static bool warnedAboutModDependencies = false; - - if (!warnedAboutModDependencies) - { - warnedAboutModDependencies = true; - auto errorMessages = CGI->modh->getModLoadErrors(); - - if (!errorMessages.empty()) - CInfoWindow::showInfoDialog(errorMessages, std::vector>(), PlayerColor(1)); - } - // Handles mouse and key input GH.handleEvents(); GH.windows().simpleRedraw(); diff --git a/launcher/modManager/cmodlistview_moc.cpp b/launcher/modManager/cmodlistview_moc.cpp index a8fed0a8f..9f05d4265 100644 --- a/launcher/modManager/cmodlistview_moc.cpp +++ b/launcher/modManager/cmodlistview_moc.cpp @@ -809,7 +809,7 @@ void CModListView::installFiles(QStringList files) if(!modJsonUrl.isNull()) downloadFile(QString::fromStdString(modName + ".json"), QString::fromStdString(modJsonUrl.String()), tr("mods repository index")); - repository[modNameLower] = repoData; + repository[modNameLower] = modJson; } } else diff --git a/lib/modding/CModHandler.cpp b/lib/modding/CModHandler.cpp index 4fbb0f005..478c76196 100644 --- a/lib/modding/CModHandler.cpp +++ b/lib/modding/CModHandler.cpp @@ -38,19 +38,14 @@ CModHandler::~CModHandler() = default; std::vector CModHandler::getAllMods() const { - return modManager->getActiveMods();// TODO: currently identical to active + return modManager->getAllMods(); } -std::vector CModHandler::getActiveMods() const +const std::vector & CModHandler::getActiveMods() const { return modManager->getActiveMods(); } -std::string CModHandler::getModLoadErrors() const -{ - return ""; // TODO: modLoadErrors->toString(); -} - const ModDescription & CModHandler::getModInfo(const TModID & modId) const { return modManager->getModDescription(modId); @@ -86,35 +81,6 @@ static ISimpleResourceLoader * genModFilesystem(const std::string & modName, con return CResourceHandler::createFileSystem(getModDirectory(modName), defaultFS); } -//static ui32 calculateModChecksum(const std::string & modName, ISimpleResourceLoader * filesystem) -//{ -// boost::crc_32_type modChecksum; -// // first - add current VCMI version into checksum to force re-validation on VCMI updates -// modChecksum.process_bytes(reinterpret_cast(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size()); -// -// // second - add mod.json into checksum because filesystem does not contains this file -// // FIXME: remove workaround for core mod -// if (modName != ModScope::scopeBuiltin()) -// { -// auto modConfFile = CModInfo::getModFile(modName); -// ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32(); -// modChecksum.process_bytes(reinterpret_cast(&configChecksum), sizeof(configChecksum)); -// } -// // third - add all detected text files from this mod into checksum -// auto files = filesystem->getFilteredFiles([](const ResourcePath & resID) -// { -// return (resID.getType() == EResType::TEXT || resID.getType() == EResType::JSON) && -// ( boost::starts_with(resID.getName(), "DATA") || boost::starts_with(resID.getName(), "CONFIG")); -// }); -// -// for (const ResourcePath & file : files) -// { -// ui32 fileChecksum = filesystem->load(file)->calculateCRC32(); -// modChecksum.process_bytes(reinterpret_cast(&fileChecksum), sizeof(fileChecksum)); -// } -// return modChecksum.checksum(); -//} - void CModHandler::loadModFilesystems() { CGeneralTextHandler::detectInstallParameters(); @@ -250,7 +216,7 @@ std::set CModHandler::getModEnabledSoftDependencies(const TModID & modId { std::set softDependencies = getModSoftDependencies(modId); - vstd::erase_if(softDependencies, [&](const TModID & dependency){ return !modManager->isModActive(dependency);}); + vstd::erase_if(softDependencies, [this](const TModID & dependency){ return !modManager->isModActive(dependency);}); return softDependencies; } @@ -285,18 +251,41 @@ void CModHandler::load() content->init(); -// for(const TModID & modName : getActiveMods()) -// { -// logMod->trace("Generating checksum for %s", modName); -// allMods[modName].updateChecksum(calculateModChecksum(modName, CResourceHandler::get(modName))); -// } + const auto & activeMods = getActiveMods(); - for(const TModID & modName : getActiveMods()) - content->preloadData(getModInfo(modName)); + validationPassed.insert(activeMods.begin(), activeMods.end()); + + for(const TModID & modName : activeMods) + { + modChecksums[modName] = this->modManager->computeChecksum(modName); + } + + for(const TModID & modName : activeMods) + { + const auto & modInfo = getModInfo(modName); + bool isValid = content->preloadData(modInfo, isModValidationNeeded(modInfo)); + if (isValid) + logGlobal->info("\t\tParsing mod: OK (%s)", modInfo.getName()); + else + logGlobal->warn("\t\tParsing mod: Issues found! (%s)", modInfo.getName()); + + if (!isValid) + validationPassed.erase(modName); + } logMod->info("\tParsing mod data"); - for(const TModID & modName : getActiveMods()) - content->load(getModInfo(modName)); + for(const TModID & modName : activeMods) + { + const auto & modInfo = getModInfo(modName); + bool isValid = content->load(getModInfo(modName), isModValidationNeeded(getModInfo(modName))); + if (isValid) + logGlobal->info("\t\tLoading mod: OK (%s)", modInfo.getName()); + else + logGlobal->warn("\t\tLoading mod: Issues found! (%s)", modInfo.getName()); + + if (!isValid) + validationPassed.erase(modName); + } #if SCRIPTING_ENABLED VLC->scriptHandler->performRegistration(VLC);//todo: this should be done before any other handlers load @@ -304,7 +293,7 @@ void CModHandler::load() content->loadCustom(); - for(const TModID & modName : getActiveMods()) + for(const TModID & modName : activeMods) loadTranslation(modName); logMod->info("\tLoading mod data"); @@ -319,21 +308,30 @@ void CModHandler::load() void CModHandler::afterLoad(bool onlyEssential) { - //JsonNode modSettings; - //for (auto & modEntry : getActiveMods()) - //{ - // std::string pointer = "/" + boost::algorithm::replace_all_copy(modEntry.first, ".", "/mods/"); + JsonNode modSettings; + for (auto & modEntry : getActiveMods()) + { + if (validationPassed.count(modEntry)) + modManager->setValidatedChecksum(modEntry, modChecksums.at(modEntry)); + else + modManager->setValidatedChecksum(modEntry, std::nullopt); + } - // modSettings["activeMods"].resolvePointer(pointer) = modEntry.second.saveLocalData(); - //} - //modSettings[ModScope::scopeBuiltin()] = coreMod->saveLocalData(); - //modSettings[ModScope::scopeBuiltin()]["name"].String() = "Original game files"; + modManager->saveConfigurationState(); +} - //if(!onlyEssential) - //{ - // std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc); - // file << modSettings.toString(); - //} +bool CModHandler::isModValidationNeeded(const ModDescription & mod) const +{ + if (settings["mods"]["validation"].String() == "full") + return true; + + if (modManager->getValidatedChecksum(mod.getID()) == modChecksums.at(mod.getID())) + return false; + + if (settings["mods"]["validation"].String() == "off") + return false; + + return true; } VCMI_LIB_NAMESPACE_END diff --git a/lib/modding/CModHandler.h b/lib/modding/CModHandler.h index 1ea49daef..e991459c8 100644 --- a/lib/modding/CModHandler.h +++ b/lib/modding/CModHandler.h @@ -23,12 +23,16 @@ using TModID = std::string; class DLL_LINKAGE CModHandler final : boost::noncopyable { std::unique_ptr modManager; + std::map modChecksums; + std::set validationPassed; void loadTranslation(const TModID & modName); void checkModFilesystemsConflicts(const std::map & modFilesystems); + bool isModValidationNeeded(const ModDescription & mod) const; + public: - std::shared_ptr content; //FIXME: make private + std::shared_ptr content; /// receives list of available mods and trying to load mod.json from all of them void initializeConfig(); @@ -52,11 +56,8 @@ public: /// returns list of all (active) mods std::vector getAllMods() const; - std::vector getActiveMods() const; + const std::vector & getActiveMods() const; - /// Returns human-readable string that describes errors encounter during mod loading, such as missing dependencies - std::string getModLoadErrors() const; - const ModDescription & getModInfo(const TModID & modId) const; /// load content from all available mods diff --git a/lib/modding/ContentTypeHandler.cpp b/lib/modding/ContentTypeHandler.cpp index 44b925298..4a2779c54 100644 --- a/lib/modding/ContentTypeHandler.cpp +++ b/lib/modding/ContentTypeHandler.cpp @@ -55,7 +55,7 @@ ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, const std::string bool ContentTypeHandler::preloadModData(const std::string & modName, const JsonNode & fileList, bool validate) { - bool result = false; + bool result = true; JsonNode data = JsonUtils::assembleFromFiles(fileList, result); data.setModScope(modName); @@ -259,22 +259,28 @@ void CContentHandler::init() handlers.insert(std::make_pair("biomes", ContentTypeHandler(VLC->biomeHandler.get(), "biome"))); } -bool CContentHandler::preloadModData(const std::string & modName, JsonNode modConfig, bool validate) +bool CContentHandler::preloadData(const ModDescription & mod, bool validate) { bool result = true; + if (validate && mod.getID() != ModScope::scopeBuiltin()) // TODO: remove workaround + { + if (!JsonUtils::validate(mod.getLocalConfig(), "vcmi:mod", mod.getID())) + result = false; + } + for(auto & handler : handlers) { - result &= handler.second.preloadModData(modName, modConfig[handler.first], validate); + result &= handler.second.preloadModData(mod.getID(), mod.getLocalValue(handler.first), validate); } return result; } -bool CContentHandler::loadMod(const std::string & modName, bool validate) +bool CContentHandler::load(const ModDescription & mod, bool validate) { bool result = true; for(auto & handler : handlers) { - result &= handler.second.loadMod(modName, validate); + result &= handler.second.loadMod(mod.getID(), validate); } return result; } @@ -295,62 +301,9 @@ void CContentHandler::afterLoadFinalization() } } -void CContentHandler::preloadData(const ModDescription & mod) -{ - preloadModData(mod.getID(), mod.getLocalConfig(), false); - -// bool validate = validateMod(mod); -// -// // print message in format [<8-symbols checksum>] -// auto & info = mod.getVerificationInfo(); -// logMod->info("\t\t[%08x]%s", info.checksum, info.name); -// -// if (validate && mod.identifier != ModScope::scopeBuiltin()) -// { -// if (!JsonUtils::validate(mod.config, "vcmi:mod", mod.identifier)) -// mod.validation = CModInfo::FAILED; -// } -// if (!preloadModData(mod.identifier, mod.config, validate)) -// mod.validation = CModInfo::FAILED; -} - -void CContentHandler::load(const ModDescription & mod) -{ - loadMod(mod.getID(), false); - -// bool validate = validateMod(mod); -// -// if (!loadMod(mod.identifier, validate)) -// mod.validation = CModInfo::FAILED; -// -// if (validate) -// { -// if (mod.validation != CModInfo::FAILED) -// logMod->info("\t\t[DONE] %s", mod.getVerificationInfo().name); -// else -// logMod->error("\t\t[FAIL] %s", mod.getVerificationInfo().name); -// } -// else -// logMod->info("\t\t[SKIP] %s", mod.getVerificationInfo().name); -} - const ContentTypeHandler & CContentHandler::operator[](const std::string & name) const { return handlers.at(name); } -bool CContentHandler::validateMod(const ModDescription & mod) const -{ - if (settings["mods"]["validation"].String() == "full") - return true; - -// if (mod.validation == CModInfo::PASSED) -// return false; - - if (settings["mods"]["validation"].String() == "off") - return false; - - return true; -} - VCMI_LIB_NAMESPACE_END diff --git a/lib/modding/ContentTypeHandler.h b/lib/modding/ContentTypeHandler.h index 746552389..abcf7321e 100644 --- a/lib/modding/ContentTypeHandler.h +++ b/lib/modding/ContentTypeHandler.h @@ -50,23 +50,16 @@ public: /// class used to load all game data into handlers. Used only during loading class DLL_LINKAGE CContentHandler { - /// preloads all data from fileList as data from modName. - bool preloadModData(const std::string & modName, JsonNode modConfig, bool validate); - - /// actually loads data in mod - bool loadMod(const std::string & modName, bool validate); - std::map handlers; - bool validateMod(const ModDescription & mod) const; public: void init(); /// preloads all data from fileList as data from modName. - void preloadData(const ModDescription & mod); + bool preloadData(const ModDescription & mod, bool validateMod); /// actually loads data in mod - void load(const ModDescription & mod); + bool load(const ModDescription & mod, bool validateMod); void loadCustom(); diff --git a/lib/modding/ModDescription.cpp b/lib/modding/ModDescription.cpp index 98e4e4175..1ab841d2a 100644 --- a/lib/modding/ModDescription.cpp +++ b/lib/modding/ModDescription.cpp @@ -26,7 +26,7 @@ ModDescription::ModDescription(const TModID & fullID, const JsonNode & localConf , conflicts(loadModList(getValue("conflicts"))) { if(getID() != "core") - dependencies.insert("core"); + dependencies.emplace("core"); } ModDescription::~ModDescription() = default; diff --git a/lib/modding/ModDescription.h b/lib/modding/ModDescription.h index 52aa574e2..ae6adda80 100644 --- a/lib/modding/ModDescription.h +++ b/lib/modding/ModDescription.h @@ -21,10 +21,11 @@ using TModSet = std::set; class DLL_LINKAGE ModDescription : boost::noncopyable { + TModID identifier; + std::unique_ptr localConfig; std::unique_ptr repositoryConfig; - TModID identifier; TModSet dependencies; TModSet softDependencies; TModSet conflicts; diff --git a/lib/modding/ModManager.cpp b/lib/modding/ModManager.cpp index ce2e6bcb8..afd8cf236 100644 --- a/lib/modding/ModManager.cpp +++ b/lib/modding/ModManager.cpp @@ -13,6 +13,7 @@ #include "ModDescription.h" #include "ModScope.h" +#include "../constants/StringConstants.h" #include "../filesystem/Filesystem.h" #include "../json/JsonNode.h" #include "../texts/CGeneralTextHandler.h" @@ -49,17 +50,45 @@ ModsState::ModsState() for(const auto & submod : scanModsDirectory(getModSettingsDirectory(target))) testLocations.push_back(target + '.' + submod); - - // TODO: check that this is vcmi mod and not era mod? - // TODO: check that mod name is not reserved (ModScope::isScopeReserved(modFullName))) } } -TModList ModsState::getAllMods() const +TModList ModsState::getInstalledMods() const { return modList; } +uint32_t ModsState::computeChecksum(const TModID & modName) const +{ + boost::crc_32_type modChecksum; + // first - add current VCMI version into checksum to force re-validation on VCMI updates + modChecksum.process_bytes(reinterpret_cast(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size()); + + // second - add mod.json into checksum because filesystem does not contains this file + // FIXME: remove workaround for core mod + if (modName != ModScope::scopeBuiltin()) + { + auto modConfFile = getModDescriptionFile(modName); + ui32 configChecksum = CResourceHandler::get("initial")->load(modConfFile)->calculateCRC32(); + modChecksum.process_bytes(reinterpret_cast(&configChecksum), sizeof(configChecksum)); + } + + // third - add all detected text files from this mod into checksum + const auto & filesystem = CResourceHandler::get(modName); + + auto files = filesystem->getFilteredFiles([](const ResourcePath & resID) + { + return resID.getType() == EResType::JSON && boost::starts_with(resID.getName(), "CONFIG"); + }); + + for (const ResourcePath & file : files) + { + ui32 fileChecksum = filesystem->load(file)->calculateCRC32(); + modChecksum.process_bytes(reinterpret_cast(&fileChecksum), sizeof(fileChecksum)); + } + return modChecksum.checksum(); +} + std::vector ModsState::scanModsDirectory(const std::string & modDir) const { size_t depth = boost::range::count(modDir, '/'); @@ -90,6 +119,9 @@ std::vector ModsState::scanModsDirectory(const std::string & modDir) con if(name.find('.') != std::string::npos) continue; + if (ModScope::isScopeReserved(boost::to_lower_copy(name))) + continue; + if(!CResourceHandler::get("initial")->existsResource(JsonPath::builtin(entry.getName() + "/MOD"))) continue; @@ -123,20 +155,14 @@ ModsPresetState::ModsPresetState() else importInitialPreset(); // 1.5 format import - saveConfiguration(modConfig); + saveConfigurationState(); } } -void ModsPresetState::saveConfiguration(const JsonNode & modSettings) -{ - std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc); - file << modSettings.toString(); -} - void ModsPresetState::createInitialPreset() { // TODO: scan mods directory for all its content? Probably unnecessary since this looks like new install, but who knows? - modConfig["presets"]["default"]["mods"].Vector().push_back(JsonNode("vcmi")); + modConfig["presets"]["default"]["mods"].Vector().emplace_back("vcmi"); } void ModsPresetState::importInitialPreset() @@ -146,7 +172,7 @@ void ModsPresetState::importInitialPreset() for(const auto & mod : modConfig["activeMods"].Struct()) { if(mod.second["active"].Bool()) - preset["mods"].Vector().push_back(JsonNode(mod.first)); + preset["mods"].Vector().emplace_back(mod.first); for(const auto & submod : mod.second["mods"].Struct()) preset["settings"][mod.first][submod.first] = submod.second["active"]; @@ -176,6 +202,15 @@ std::map ModsPresetState::getModSettings(const TModID & modID) con return modSettings; } +std::optional ModsPresetState::getValidatedChecksum(const TModID & modName) const +{ + const JsonNode & node = modConfig["validatedMods"][modName]; + if (node.isNull()) + return std::nullopt; + else + return node.Integer(); +} + void ModsPresetState::setSettingActiveInPreset(const TModID & modName, const TModID & settingName, bool isActive) { const std::string & currentPresetName = modConfig["activePreset"].String(); @@ -212,6 +247,20 @@ std::vector ModsPresetState::getActiveMods() const return allActiveMods; } +void ModsPresetState::setValidatedChecksum(const TModID & modName, std::optional value) +{ + if (value.has_value()) + modConfig["validatedMods"][modName].Integer() = *value; + else + modConfig["validatedMods"].Struct().erase(modName); +} + +void ModsPresetState::saveConfigurationState() const +{ + std::fstream file(CResourceHandler::get()->getResourceName(ResourcePath("config/modSettings.json"))->c_str(), std::ofstream::out | std::ofstream::trunc); + file << modConfig.toCompactString(); +} + ModsStorage::ModsStorage(const std::vector & modsToLoad, const JsonNode & repositoryList) { JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json")); @@ -221,10 +270,7 @@ ModsStorage::ModsStorage(const std::vector & modsToLoad, const JsonNode for(auto modID : modsToLoad) { if(ModScope::isScopeReserved(modID)) - { - logMod->error("Can not load mod %s - this name is reserved for internal use!", modID); continue; - } JsonNode modConfig(getModDescriptionFile(modID)); modConfig.setModScope(modID); @@ -273,10 +319,10 @@ ModManager::ModManager(const JsonNode & repositoryList) : modsState(std::make_unique()) , modsPreset(std::make_unique()) { + //TODO: load only active mods & all their submods in game mode? + modsStorage = std::make_unique(modsState->getInstalledMods(), repositoryList); eraseMissingModsFromPreset(); - //TODO: load only active mods & all their submods in game mode - modsStorage = std::make_unique(modsState->getAllMods(), repositoryList); addNewModsToPreset(); std::vector desiredModList = modsPreset->getActiveMods(); @@ -301,6 +347,26 @@ const TModList & ModManager::getActiveMods() const return activeMods; } +uint32_t ModManager::computeChecksum(const TModID & modName) const +{ + return modsState->computeChecksum(modName); +} + +std::optional ModManager::getValidatedChecksum(const TModID & modName) const +{ + return modsPreset->getValidatedChecksum(modName); +} + +void ModManager::setValidatedChecksum(const TModID & modName, std::optional value) +{ + modsPreset->setValidatedChecksum(modName, value); +} + +void ModManager::saveConfigurationState() const +{ + modsPreset->saveConfigurationState(); +} + TModList ModManager::getAllMods() const { return modsStorage->getAllMods(); @@ -308,7 +374,7 @@ TModList ModManager::getAllMods() const void ModManager::eraseMissingModsFromPreset() { - const TModList & installedMods = modsState->getAllMods(); + const TModList & installedMods = modsState->getInstalledMods(); const TModList & rootMods = modsPreset->getActiveRootMods(); for(const auto & rootMod : rootMods) @@ -335,7 +401,7 @@ void ModManager::eraseMissingModsFromPreset() void ModManager::addNewModsToPreset() { - const TModList & installedMods = modsState->getAllMods(); + const TModList & installedMods = modsState->getInstalledMods(); for(const auto & modID : installedMods) { @@ -421,66 +487,4 @@ void ModManager::generateLoadOrder(std::vector modsToResolve) brokenMods = modsToResolve; } -// modLoadErrors = std::make_unique(); -// -// auto addErrorMessage = [this](const std::string & textID, const std::string & brokenModID, const std::string & missingModID) -// { -// modLoadErrors->appendTextID(textID); -// -// if (allMods.count(brokenModID)) -// modLoadErrors->replaceRawString(allMods.at(brokenModID).getVerificationInfo().name); -// else -// modLoadErrors->replaceRawString(brokenModID); -// -// if (allMods.count(missingModID)) -// modLoadErrors->replaceRawString(allMods.at(missingModID).getVerificationInfo().name); -// else -// modLoadErrors->replaceRawString(missingModID); -// -// }; -// -// // Left mods have unresolved dependencies, output all to log. -// for(const auto & brokenModID : modsToResolve) -// { -// const CModInfo & brokenMod = allMods.at(brokenModID); -// bool showErrorMessage = false; -// for(const TModID & dependency : brokenMod.dependencies) -// { -// if(!vstd::contains(resolvedModIDs, dependency) && brokenMod.config["modType"].String() != "Compatibility") -// { -// addErrorMessage("vcmi.server.errors.modNoDependency", brokenModID, dependency); -// showErrorMessage = true; -// } -// } -// for(const TModID & conflict : brokenMod.conflicts) -// { -// if(vstd::contains(resolvedModIDs, conflict)) -// { -// addErrorMessage("vcmi.server.errors.modConflict", brokenModID, conflict); -// showErrorMessage = true; -// } -// } -// for(const TModID & reverseConflict : resolvedModIDs) -// { -// if (vstd::contains(allMods.at(reverseConflict).conflicts, brokenModID)) -// { -// addErrorMessage("vcmi.server.errors.modConflict", brokenModID, reverseConflict); -// showErrorMessage = true; -// } -// } -// -// // some mods may in a (soft) dependency loop. -// if(!showErrorMessage && brokenMod.config["modType"].String() != "Compatibility") -// { -// modLoadErrors->appendTextID("vcmi.server.errors.modDependencyLoop"); -// if (allMods.count(brokenModID)) -// modLoadErrors->replaceRawString(allMods.at(brokenModID).getVerificationInfo().name); -// else -// modLoadErrors->replaceRawString(brokenModID); -// } -// -// } -// return sortedValidMods; -//} - VCMI_LIB_NAMESPACE_END diff --git a/lib/modding/ModManager.h b/lib/modding/ModManager.h index 4d38550e5..b74b1afba 100644 --- a/lib/modding/ModManager.h +++ b/lib/modding/ModManager.h @@ -31,7 +31,9 @@ class ModsState : boost::noncopyable public: ModsState(); - TModList getAllMods() const; + TModList getInstalledMods() const; + + uint32_t computeChecksum(const TModID & modName) const; }; /// Provides interface to access or change current mod preset @@ -39,8 +41,6 @@ class ModsPresetState : boost::noncopyable { JsonNode modConfig; - void saveConfiguration(const JsonNode & config); - void createInitialPreset(); void importInitialPreset(); @@ -61,6 +61,10 @@ public: /// Returns list of all known settings (submods) for a specified mod std::map getModSettings(const TModID & modID) const; + std::optional getValidatedChecksum(const TModID & modName) const; + void setValidatedChecksum(const TModID & modName, std::optional value); + + void saveConfigurationState() const; }; /// Provides access to mod properties @@ -101,7 +105,12 @@ public: const ModDescription & getModDescription(const TModID & modID) const; const TModList & getActiveMods() const; TModList getAllMods() const; + bool isModActive(const TModID & modID) const; + uint32_t computeChecksum(const TModID & modName) const; + std::optional getValidatedChecksum(const TModID & modName) const; + void setValidatedChecksum(const TModID & modName, std::optional value); + void saveConfigurationState() const; }; VCMI_LIB_NAMESPACE_END diff --git a/vcmiqt/jsonutils.cpp b/vcmiqt/jsonutils.cpp index 99112bea8..5815a46be 100644 --- a/vcmiqt/jsonutils.cpp +++ b/vcmiqt/jsonutils.cpp @@ -116,7 +116,7 @@ JsonNode toJson(QVariant object) void jsonToFile(QString filename, const JsonNode & object) { std::fstream file(qstringToPath(filename).c_str(), std::ios::out | std::ios_base::binary); - file << object.toString(); + file << object.toCompactString(); } }