mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
fix bug: may load mod before dependeny
This commit is contained in:
parent
bc1d99431d
commit
3049c4b70e
@ -716,46 +716,67 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> modsToResolve) const
|
std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> input) const
|
||||||
{
|
{
|
||||||
std::vector<TModID> brokenMods;
|
// 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
|
||||||
|
|
||||||
auto looksValid = [&](const CModInfo & mod) -> bool
|
// first - sort input to have input strictly based on name (and not on hashmap or anything else)
|
||||||
|
boost::range::sort(input);
|
||||||
|
|
||||||
|
std::vector <TModID> output;
|
||||||
|
output.reserve(input.size());
|
||||||
|
|
||||||
|
std::set <TModID> resolvedMods;
|
||||||
|
|
||||||
|
// Check if all mod dependencies are resolved (moved to resolvedMods)
|
||||||
|
auto isResolved = [&](const CModInfo & mod) -> bool
|
||||||
{
|
{
|
||||||
auto res = true;
|
|
||||||
for(const TModID & dependency : mod.dependencies)
|
for(const TModID & dependency : mod.dependencies)
|
||||||
{
|
{
|
||||||
if(!vstd::contains(modsToResolve, dependency))
|
if (!vstd::contains(resolvedMods, dependency))
|
||||||
{
|
return false;
|
||||||
logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", mod.name, dependency);
|
|
||||||
res = false; //continue iterations, since we should show all errors for the current mod.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
while(true)
|
while (true)
|
||||||
{
|
{
|
||||||
for(auto mod : modsToResolve)
|
size_t lastResolvedCount = resolvedMods.size();
|
||||||
|
std::set <TModID> toResolve; // list of mods resolved on this iteration
|
||||||
|
|
||||||
|
for (auto it = input.begin(); it != input.end();)
|
||||||
{
|
{
|
||||||
if(!looksValid(this->allMods.at(mod)))
|
if (isResolved(allMods.at(*it)))
|
||||||
brokenMods.push_back(mod);
|
|
||||||
}
|
|
||||||
if(!brokenMods.empty())
|
|
||||||
{
|
|
||||||
vstd::erase_if(modsToResolve, [&](TModID mid)
|
|
||||||
{
|
{
|
||||||
return brokenMods.end() != std::find(brokenMods.begin(), brokenMods.end(), mid);
|
toResolve.insert(*it);
|
||||||
});
|
output.push_back(*it);
|
||||||
brokenMods.clear();
|
it = input.erase(it);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
}
|
}
|
||||||
break;
|
resolvedMods.insert(toResolve.begin(), toResolve.end());
|
||||||
|
|
||||||
|
if (lastResolvedCount == resolvedMods.size())
|
||||||
|
break; // No more mod can be resolved, should be end.
|
||||||
}
|
}
|
||||||
boost::range::sort(modsToResolve);
|
|
||||||
return modsToResolve;
|
|
||||||
|
// Left mods are broken, output all to log.
|
||||||
|
for (auto it = input.begin(); it != input.end(); it++)
|
||||||
|
{
|
||||||
|
const CModInfo & mod = allMods.at(*it);
|
||||||
|
for(const TModID & dependency : mod.dependencies)
|
||||||
|
if(!vstd::contains(resolvedMods, dependency))
|
||||||
|
logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", mod.name, dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> CModHandler::getModList(std::string path)
|
std::vector<std::string> CModHandler::getModList(std::string path)
|
||||||
{
|
{
|
||||||
std::string modDir = boost::to_upper_copy(path + "MODS/");
|
std::string modDir = boost::to_upper_copy(path + "MODS/");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user