mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
refactor code: change code style and add some comments
This commit is contained in:
parent
3049c4b70e
commit
10dc6922de
@ -716,64 +716,65 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> input) const
|
// Returned vector affects the resource loaders call order (see CFilesystemList::load).
|
||||||
|
// The loaders call order matters when dependent mod overrides resources in its dependencies.
|
||||||
|
std::vector <TModID> CModHandler::validateAndSortDependencies(std::vector <TModID> modsToResolve) const
|
||||||
{
|
{
|
||||||
// Topological sort algorithm
|
// Topological sort algorithm.
|
||||||
// May not be the fastest one but VCMI does not needs any speed here
|
// TODO: Investigate possible ways to improve performance.
|
||||||
// Unless user have dozens of mods with complex dependencies this code should be fine
|
boost::range::sort(modsToResolve); // Sort mods per name
|
||||||
|
std::vector <TModID> sortedValidMods; // Vector keeps order of elements (LIFO)
|
||||||
|
sortedValidMods.reserve(modsToResolve.size()); // push_back calls won't cause memory reallocation
|
||||||
|
std::set <TModID> resolvedModIDs; // Use a set for validation for performance reason, but set does not keep order of elements
|
||||||
|
|
||||||
// first - sort input to have input strictly based on name (and not on hashmap or anything else)
|
// Mod is resolved if it has not dependencies or all its dependencies are already resolved
|
||||||
boost::range::sort(input);
|
auto isResolved = [&](const CModInfo & mod) -> CModInfo::EValidationStatus
|
||||||
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
|
if(mod.dependencies.size() > resolvedModIDs.size())
|
||||||
|
return CModInfo::PENDING;
|
||||||
|
|
||||||
for(const TModID & dependency : mod.dependencies)
|
for(const TModID & dependency : mod.dependencies)
|
||||||
{
|
{
|
||||||
if (!vstd::contains(resolvedMods, dependency))
|
if(!vstd::contains(resolvedModIDs, dependency))
|
||||||
return false;
|
return CModInfo::PENDING;
|
||||||
}
|
}
|
||||||
return true;
|
return CModInfo::PASSED;
|
||||||
};
|
};
|
||||||
|
|
||||||
while (true)
|
while(true)
|
||||||
{
|
{
|
||||||
size_t lastResolvedCount = resolvedMods.size();
|
std::set <TModID> resolvedOnCurrentTreeLevel;
|
||||||
std::set <TModID> toResolve; // list of mods resolved on this iteration
|
for(auto it = modsToResolve.begin(); it != modsToResolve.end();) // One iteration - one level of mods tree
|
||||||
|
|
||||||
for (auto it = input.begin(); it != input.end();)
|
|
||||||
{
|
{
|
||||||
if (isResolved(allMods.at(*it)))
|
if(isResolved(allMods.at(*it)) == CModInfo::PASSED)
|
||||||
{
|
{
|
||||||
toResolve.insert(*it);
|
resolvedOnCurrentTreeLevel.insert(*it); // Not to the resolvedModIDs, so current node childs will be resolved on the next iteration
|
||||||
output.push_back(*it);
|
sortedValidMods.push_back(*it);
|
||||||
it = input.erase(it);
|
it = modsToResolve.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
resolvedMods.insert(toResolve.begin(), toResolve.end());
|
if(resolvedOnCurrentTreeLevel.size())
|
||||||
|
{
|
||||||
if (lastResolvedCount == resolvedMods.size())
|
resolvedModIDs.insert(resolvedOnCurrentTreeLevel.begin(), resolvedOnCurrentTreeLevel.end());
|
||||||
break; // No more mod can be resolved, should be end.
|
continue;
|
||||||
|
}
|
||||||
|
// If there're no valid mods on the current mods tree level, no more mod can be resolved, should be end.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Left mods have unresolved dependencies, output all to log.
|
||||||
// Left mods are broken, output all to log.
|
for(const auto & brokenModID : modsToResolve)
|
||||||
for (auto it = input.begin(); it != input.end(); it++)
|
|
||||||
{
|
{
|
||||||
const CModInfo & mod = allMods.at(*it);
|
const CModInfo & brokenMod = allMods.at(brokenModID);
|
||||||
for(const TModID & dependency : mod.dependencies)
|
for(const TModID & dependency : brokenMod.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);
|
if(!vstd::contains(resolvedModIDs, dependency))
|
||||||
|
logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", brokenMod.name, dependency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return sortedValidMods;
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -916,7 +917,7 @@ static ui32 calculateModChecksum(const std::string modName, ISimpleResourceLoade
|
|||||||
|
|
||||||
void CModHandler::loadModFilesystems()
|
void CModHandler::loadModFilesystems()
|
||||||
{
|
{
|
||||||
activeMods = resolveDependencies(activeMods);
|
activeMods = validateAndSortDependencies(activeMods);
|
||||||
|
|
||||||
coreMod.updateChecksum(calculateModChecksum("core", CResourceHandler::get("core")));
|
coreMod.updateChecksum(calculateModChecksum("core", CResourceHandler::get("core")));
|
||||||
|
|
||||||
|
@ -242,9 +242,15 @@ class DLL_LINKAGE CModHandler
|
|||||||
// - circular dependencies
|
// - circular dependencies
|
||||||
bool checkDependencies(const std::vector <TModID> & input) const;
|
bool checkDependencies(const std::vector <TModID> & input) const;
|
||||||
|
|
||||||
// returns load order in which all dependencies are resolved, e.g. loaded after required mods
|
/**
|
||||||
// function assumes that input list is valid (checkDependencies returned true)
|
* 1. Set apart mods with resolved dependencies from mods which have unresolved dependencies
|
||||||
std::vector <TModID> resolveDependencies(std::vector<TModID> input) const;
|
* 2. Sort resolved mods using topological algorithm
|
||||||
|
* 3. Log all problem mods and their unresolved dependencies
|
||||||
|
*
|
||||||
|
* @param modsToResolve list of valid mod IDs (checkDependencies returned true - TODO: Clarify it.)
|
||||||
|
* @return a vector of the topologically sorted resolved mods: child nodes (dependent mods) have greater index than parents
|
||||||
|
*/
|
||||||
|
std::vector <TModID> validateAndSortDependencies(std::vector <TModID> modsToResolve) const;
|
||||||
|
|
||||||
std::vector<std::string> getModList(std::string path);
|
std::vector<std::string> getModList(std::string path);
|
||||||
void loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods);
|
void loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods);
|
||||||
|
Loading…
Reference in New Issue
Block a user