From 98fdf909e8824a93dc5ed90f9e97175ef2509ab3 Mon Sep 17 00:00:00 2001 From: Dmitry Orlov Date: Wed, 20 Jan 2021 11:23:58 +0300 Subject: [PATCH] Fix: Hanging on start up if mod dependency is not resolved' --- lib/CModHandler.cpp | 55 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 509ba4498..d3299c8ba 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -716,50 +716,41 @@ bool CModHandler::checkDependencies(const std::vector & input) const return true; } -std::vector CModHandler::resolveDependencies(std::vector input) const +std::vector CModHandler::resolveDependencies(std::vector modsToResolve) const { - // Topological sort algorithm - // May not be the fastest one but VCMI does not needs any speed here - // Unless user have dozens of mods with complex dependencies this code should be fine + std::vector brokenMods; - // first - sort input to have input strictly based on name (and not on hashmap or anything else) - boost::range::sort(input); - - std::vector output; - output.reserve(input.size()); - - std::set resolvedMods; - - // Check if all mod dependencies are resolved (moved to resolvedMods) - auto isResolved = [&](const CModInfo & mod) -> bool + auto looksValid = [&](const CModInfo & mod) -> bool { + auto res = true; for(const TModID & dependency : mod.dependencies) { - if (!vstd::contains(resolvedMods, dependency)) - return false; + if(!(res = vstd::contains(modsToResolve, dependency))) + logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", mod.name, dependency); } - return true; + return res; }; - while (!input.empty()) + while(true) { - std::set toResolve; // list of mods resolved on this iteration - - for (auto it = input.begin(); it != input.end();) + for(auto mod : modsToResolve) { - if (isResolved(allMods.at(*it))) - { - toResolve.insert(*it); - output.push_back(*it); - it = input.erase(it); - continue; - } - it++; + if(!looksValid(this->allMods.at(mod))) + brokenMods.push_back(mod); } - resolvedMods.insert(toResolve.begin(), toResolve.end()); + if(!brokenMods.empty()) + { + vstd::erase_if(modsToResolve, [&](TModID mid) + { + return brokenMods.end() != std::find(brokenMods.begin(), brokenMods.end(), mid); + }); + brokenMods.clear(); + continue; + } + break; } - - return output; + boost::range::sort(modsToResolve); + return modsToResolve; } std::vector CModHandler::getModList(std::string path)