mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-29 23:07:48 +02:00
Merge remote-tracking branch 'vcmi/beta' into develop
This commit is contained in:
@@ -489,23 +489,49 @@ void CModHandler::afterLoad(bool onlyEssential)
|
||||
|
||||
}
|
||||
|
||||
void CModHandler::trySetActiveMods(const std::map<TModID, CModVersion> & modList)
|
||||
void CModHandler::trySetActiveMods(std::vector<TModID> saveActiveMods, const std::map<TModID, CModVersion> & modList)
|
||||
{
|
||||
std::vector<TModID> newActiveMods;
|
||||
|
||||
ModIncompatibility::ModList missingMods;
|
||||
|
||||
for(const auto & mod : modList)
|
||||
for(const auto & m : activeMods)
|
||||
{
|
||||
auto m = mod.first;
|
||||
auto mver = mod.second;
|
||||
if (vstd::contains(saveActiveMods, m))
|
||||
continue;
|
||||
|
||||
if(allMods.count(m) && (allMods[m].version.isNull() || mver.isNull() || allMods[m].version.compatible(mver)))
|
||||
allMods[m].setEnabled(true);
|
||||
else
|
||||
auto & modInfo = allMods.at(m);
|
||||
if(modInfo.checkModGameplayAffecting())
|
||||
missingMods.emplace_back(m, modInfo.version.toString());
|
||||
}
|
||||
|
||||
for(const auto & m : saveActiveMods)
|
||||
{
|
||||
const CModVersion & mver = modList.at(m);
|
||||
|
||||
if (allMods.count(m) == 0)
|
||||
{
|
||||
missingMods.emplace_back(m, mver.toString());
|
||||
continue;
|
||||
}
|
||||
|
||||
auto & modInfo = allMods.at(m);
|
||||
|
||||
bool modAffectsGameplay = modInfo.checkModGameplayAffecting();
|
||||
bool modVersionCompatible = modInfo.version.isNull() || mver.isNull() || modInfo.version.compatible(mver);
|
||||
bool modEnabledLocally = vstd::contains(activeMods, m);
|
||||
bool modCanBeEnabled = modEnabledLocally && modVersionCompatible;
|
||||
|
||||
allMods[m].setEnabled(modCanBeEnabled);
|
||||
|
||||
if (modCanBeEnabled)
|
||||
newActiveMods.push_back(m);
|
||||
|
||||
if (!modCanBeEnabled && modAffectsGameplay)
|
||||
missingMods.emplace_back(m, mver.toString());
|
||||
}
|
||||
|
||||
if(!missingMods.empty())
|
||||
throw ModIncompatibility(std::move(missingMods));
|
||||
std::swap(activeMods, newActiveMods);
|
||||
}
|
||||
|
||||
CIdentifierStorage & CModHandler::getIdentifiers()
|
||||
|
||||
@@ -52,7 +52,7 @@ class DLL_LINKAGE CModHandler : boost::noncopyable
|
||||
CModVersion getModVersion(TModID modName) const;
|
||||
|
||||
/// Attempt to set active mods according to provided list of mods from save, throws on failure
|
||||
void trySetActiveMods(const std::map<TModID, CModVersion> & modList);
|
||||
void trySetActiveMods(std::vector<TModID> saveActiveMods, const std::map<TModID, CModVersion> & modList);
|
||||
|
||||
std::unique_ptr<CIdentifierStorage> identifiers;
|
||||
|
||||
@@ -100,16 +100,14 @@ public:
|
||||
else
|
||||
{
|
||||
loadMods();
|
||||
std::vector<TModID> newActiveMods;
|
||||
std::vector<TModID> saveActiveMods;
|
||||
std::map<TModID, CModVersion> modVersions;
|
||||
h & newActiveMods;
|
||||
h & saveActiveMods;
|
||||
|
||||
for(const auto & m : newActiveMods)
|
||||
for(const auto & m : saveActiveMods)
|
||||
h & modVersions[m];
|
||||
|
||||
trySetActiveMods(modVersions);
|
||||
|
||||
std::swap(activeMods, newActiveMods);
|
||||
trySetActiveMods(saveActiveMods, modVersions);
|
||||
}
|
||||
|
||||
h & identifiers;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../filesystem/Filesystem.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@@ -128,6 +129,48 @@ void CModInfo::loadLocalData(const JsonNode & data)
|
||||
validation = validated ? PASSED : FAILED;
|
||||
}
|
||||
|
||||
bool CModInfo::checkModGameplayAffecting() const
|
||||
{
|
||||
if (modGameplayAffecting.has_value())
|
||||
return *modGameplayAffecting;
|
||||
|
||||
static const std::vector<std::string> keysToTest = {
|
||||
"heroClasses",
|
||||
"artifacts",
|
||||
"creatures",
|
||||
"factions",
|
||||
"objects",
|
||||
"heroes",
|
||||
"spells",
|
||||
"skills",
|
||||
"templates",
|
||||
"scripts",
|
||||
"battlefields",
|
||||
"terrains",
|
||||
"rivers",
|
||||
"roads",
|
||||
"obstacles"
|
||||
};
|
||||
|
||||
ResourceID modFileResource(CModInfo::getModFile(identifier));
|
||||
|
||||
if(CResourceHandler::get("initial")->existsResource(modFileResource))
|
||||
{
|
||||
const JsonNode modConfig(modFileResource);
|
||||
|
||||
for(const auto & key : keysToTest)
|
||||
{
|
||||
if (!modConfig[key].isNull())
|
||||
{
|
||||
modGameplayAffecting = true;
|
||||
return *modGameplayAffecting;
|
||||
}
|
||||
}
|
||||
}
|
||||
modGameplayAffecting = false;
|
||||
return *modGameplayAffecting;
|
||||
}
|
||||
|
||||
bool CModInfo::isEnabled() const
|
||||
{
|
||||
return implicitlyEnabled && explicitlyEnabled;
|
||||
|
||||
@@ -18,6 +18,10 @@ using TModID = std::string;
|
||||
|
||||
class DLL_LINKAGE CModInfo
|
||||
{
|
||||
/// cached result of checkModGameplayAffecting() call
|
||||
/// Do not serialize - depends on local mod version, not server/save mod version
|
||||
mutable std::optional<bool> modGameplayAffecting;
|
||||
|
||||
public:
|
||||
enum EValidationStatus
|
||||
{
|
||||
@@ -67,6 +71,9 @@ public:
|
||||
static std::string getModDir(const std::string & name);
|
||||
static std::string getModFile(const std::string & name);
|
||||
|
||||
/// return true if this mod can affect gameplay, e.g. adds or modifies any game objects
|
||||
bool checkModGameplayAffecting() const;
|
||||
|
||||
private:
|
||||
/// true if mod is enabled by user, e.g. in Launcher UI
|
||||
bool explicitlyEnabled;
|
||||
|
||||
Reference in New Issue
Block a user