Ver Fonte

Implemented validation of preset - removal of non-existing mods,
addition of newly installed mods

Ivan Savenko há 11 meses atrás
pai
commit
4945370fe3

+ 1 - 1
lib/json/JsonNode.h

@@ -187,7 +187,7 @@ void convert(std::map<std::string, Type> & value, const JsonNode & node)
 {
 {
 	value.clear();
 	value.clear();
 	for(const JsonMap::value_type & entry : node.Struct())
 	for(const JsonMap::value_type & entry : node.Struct())
-		value.insert(entry.first, entry.second.convertTo<Type>());
+		value.emplace(entry.first, entry.second.convertTo<Type>());
 }
 }
 
 
 template<typename Type>
 template<typename Type>

+ 16 - 1
lib/modding/ModDescription.cpp

@@ -106,9 +106,24 @@ ModVerificationInfo ModDescription::getVerificationInfo() const
 	return result;
 	return result;
 }
 }
 
 
+bool ModDescription::isCompatibility() const
+{
+	return getConfig()["modType"].String() == "Compatibility";
+}
+
+bool ModDescription::isTranslation() const
+{
+	return getConfig()["modType"].String() == "Translation";
+}
+
+bool ModDescription::keepDisabled() const
+{
+	return getConfig()["keepDisabled"].Bool();
+}
+
 bool ModDescription::affectsGameplay() const
 bool ModDescription::affectsGameplay() const
 {
 {
-	return false; // TODO
+	return true; // TODO
 }
 }
 
 
 VCMI_LIB_NAMESPACE_END
 VCMI_LIB_NAMESPACE_END

+ 3 - 0
lib/modding/ModDescription.h

@@ -51,6 +51,9 @@ public:
 	ModVerificationInfo getVerificationInfo() const;
 	ModVerificationInfo getVerificationInfo() const;
 
 
 	bool affectsGameplay() const;
 	bool affectsGameplay() const;
+	bool isCompatibility() const;
+	bool isTranslation() const;
+	bool keepDisabled() const;
 };
 };
 
 
 VCMI_LIB_NAMESPACE_END
 VCMI_LIB_NAMESPACE_END

+ 102 - 17
lib/modding/ModManager.cpp

@@ -15,6 +15,7 @@
 
 
 #include "../filesystem/Filesystem.h"
 #include "../filesystem/Filesystem.h"
 #include "../json/JsonNode.h"
 #include "../json/JsonNode.h"
+#include "../texts/CGeneralTextHandler.h"
 
 
 VCMI_LIB_NAMESPACE_BEGIN
 VCMI_LIB_NAMESPACE_BEGIN
 
 
@@ -153,25 +154,62 @@ void ModsPresetState::importInitialPreset()
 	modConfig["presets"]["default"] = preset;
 	modConfig["presets"]["default"] = preset;
 }
 }
 
 
-std::vector<TModID> ModsPresetState::getActiveMods() const
+const JsonNode & ModsPresetState::getActivePresetConfig() const
 {
 {
 	const std::string & currentPresetName = modConfig["activePreset"].String();
 	const std::string & currentPresetName = modConfig["activePreset"].String();
 	const JsonNode & currentPreset = modConfig["presets"][currentPresetName];
 	const JsonNode & currentPreset = modConfig["presets"][currentPresetName];
-	const JsonNode & modsToActivateJson = currentPreset["mods"];
-	std::vector<TModID> modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
+	return currentPreset;
+}
 
 
+TModList ModsPresetState::getActiveRootMods() const
+{
+	const JsonNode & modsToActivateJson = getActivePresetConfig()["mods"];
+	std::vector<TModID> modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
 	modsToActivate.push_back(ModScope::scopeBuiltin());
 	modsToActivate.push_back(ModScope::scopeBuiltin());
+	return modsToActivate;
+}
+
+std::map<TModID, bool> ModsPresetState::getModSettings(const TModID & modID) const
+{
+	const JsonNode & modSettingsJson = getActivePresetConfig()["settings"][modID];
+	std::map<TModID, bool> modSettings = modSettingsJson.convertTo<std::map<TModID, bool>>();
+	return modSettings;
+}
+
+void ModsPresetState::setSettingActiveInPreset(const TModID & modName, const TModID & settingName, bool isActive)
+{
+	const std::string & currentPresetName = modConfig["activePreset"].String();
+	JsonNode & currentPreset = modConfig["presets"][currentPresetName];
+
+	currentPreset["settings"][modName][settingName].Bool() = isActive;
+}
 
 
-	for(const auto & settings : currentPreset["settings"].Struct())
+void ModsPresetState::eraseModInAllPresets(const TModID & modName)
+{
+	for (auto & preset : modConfig["presets"].Struct())
+		vstd::erase(preset.second["mods"].Vector(), JsonNode(modName));
+}
+
+void ModsPresetState::eraseModSettingInAllPresets(const TModID & modName, const TModID & settingName)
+{
+	for (auto & preset : modConfig["presets"].Struct())
+		preset.second["settings"][modName].Struct().erase(modName);
+}
+
+std::vector<TModID> ModsPresetState::getActiveMods() const
+{
+	TModList activeRootMods = getActiveRootMods();
+	TModList allActiveMods;
+
+	for(const auto & activeMod : activeRootMods)
 	{
 	{
-		if(!vstd::contains(modsToActivate, settings.first))
-			continue; // settings for inactive mod
+		activeRootMods.push_back(activeMod);
 
 
-		for(const auto & submod : settings.second.Struct())
-			if(submod.second.Bool())
-				modsToActivate.push_back(settings.first + '.' + submod.first);
+		for(const auto & submod : getModSettings(activeMod))
+			if(submod.second)
+				allActiveMods.push_back(activeMod + '.' + submod.first);
 	}
 	}
-	return modsToActivate;
+	return allActiveMods;
 }
 }
 
 
 ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad)
 ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad)
@@ -210,15 +248,11 @@ ModManager::ModManager()
 	: modsState(std::make_unique<ModsState>())
 	: modsState(std::make_unique<ModsState>())
 	, modsPreset(std::make_unique<ModsPresetState>())
 	, modsPreset(std::make_unique<ModsPresetState>())
 {
 {
-	std::vector<TModID> desiredModList = modsPreset->getActiveMods();
-	const std::vector<TModID> & installedModList = modsState->getAllMods();
-
-	vstd::erase_if(desiredModList, [&](const TModID & mod){
-		return !vstd::contains(installedModList, mod);
-	});
+	eraseMissingModsFromPreset();
+	addNewModsToPreset();
 
 
+	std::vector<TModID> desiredModList = modsPreset->getActiveMods();
 	modsStorage = std::make_unique<ModsStorage>(desiredModList);
 	modsStorage = std::make_unique<ModsStorage>(desiredModList);
-
 	generateLoadOrder(desiredModList);
 	generateLoadOrder(desiredModList);
 }
 }
 
 
@@ -239,6 +273,54 @@ const TModList & ModManager::getActiveMods() const
 	return activeMods;
 	return activeMods;
 }
 }
 
 
+void ModManager::eraseMissingModsFromPreset()
+{
+	const TModList & installedMods = modsState->getAllMods();
+	const TModList & rootMods = modsPreset->getActiveRootMods();
+
+	for(const auto & rootMod : rootMods)
+	{
+		if(!vstd::contains(installedMods, rootMod))
+		{
+			modsPreset->eraseModInAllPresets(rootMod);
+			continue;
+		}
+
+		const auto & modSettings = modsPreset->getModSettings(rootMod);
+
+		for(const auto & modSetting : modSettings)
+		{
+			TModID fullModID = rootMod + '.' + modSetting.first;
+			if(!vstd::contains(installedMods, fullModID))
+			{
+				modsPreset->eraseModSettingInAllPresets(rootMod, modSetting.first);
+				continue;
+			}
+		}
+	}
+}
+
+void ModManager::addNewModsToPreset()
+{
+	const TModList & installedMods = modsState->getAllMods();
+
+	for(const auto & modID : installedMods)
+	{
+		size_t dotPos = modID.find('.');
+
+		if(dotPos == std::string::npos)
+			continue; // only look up submods aka mod settings
+
+		std::string rootMod = modID.substr(0, dotPos);
+		std::string settingID = modID.substr(dotPos + 1);
+
+		const auto & modSettings = modsPreset->getModSettings(rootMod);
+
+		if (!modSettings.count(settingID))
+			modsPreset->setSettingActiveInPreset(rootMod, settingID, modsStorage->getMod(modID).keepDisabled());
+	}
+}
+
 void ModManager::generateLoadOrder(std::vector<TModID> modsToResolve)
 void ModManager::generateLoadOrder(std::vector<TModID> modsToResolve)
 {
 {
 	// Topological sort algorithm.
 	// Topological sort algorithm.
@@ -251,6 +333,9 @@ void ModManager::generateLoadOrder(std::vector<TModID> modsToResolve)
 	// Mod is resolved if it has no dependencies or all its dependencies are already resolved
 	// Mod is resolved if it has no dependencies or all its dependencies are already resolved
 	auto isResolved = [&](const ModDescription & mod) -> bool
 	auto isResolved = [&](const ModDescription & mod) -> bool
 	{
 	{
+		if (mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage())
+			return false;
+
 		if(mod.getDependencies().size() > resolvedModIDs.size())
 		if(mod.getDependencies().size() > resolvedModIDs.size())
 			return false;
 			return false;
 
 

+ 13 - 5
lib/modding/ModManager.h

@@ -44,17 +44,23 @@ class ModsPresetState : boost::noncopyable
 	void createInitialPreset();
 	void createInitialPreset();
 	void importInitialPreset();
 	void importInitialPreset();
 
 
+	const JsonNode & getActivePresetConfig() const;
+
 public:
 public:
 	ModsPresetState();
 	ModsPresetState();
 
 
-	/// Returns true if mod is active in current preset
-	bool isModActive(const TModID & modName) const;
-
-	void activateModInPreset(const TModID & modName);
-	void dectivateModInAllPresets(const TModID & modName);
+	void setSettingActiveInPreset(const TModID & modName, const TModID & settingName, bool isActive);
+	void eraseModInAllPresets(const TModID & modName);
+	void eraseModSettingInAllPresets(const TModID & modName, const TModID & settingName);
 
 
 	/// Returns list of all mods active in current preset. Mod order is unspecified
 	/// Returns list of all mods active in current preset. Mod order is unspecified
 	TModList getActiveMods() const;
 	TModList getActiveMods() const;
+
+	/// Returns list of currently active root mods (non-submod)
+	TModList getActiveRootMods() const;
+
+	/// Returns list of all known settings (submods) for a specified mod
+	std::map<TModID, bool> getModSettings(const TModID & modID) const;
 };
 };
 
 
 /// Provides access to mod properties
 /// Provides access to mod properties
@@ -82,6 +88,8 @@ class ModManager : boost::noncopyable
 	std::unique_ptr<ModsStorage> modsStorage;
 	std::unique_ptr<ModsStorage> modsStorage;
 
 
 	void generateLoadOrder(TModList desiredModList);
 	void generateLoadOrder(TModList desiredModList);
+	void eraseMissingModsFromPreset();
+	void addNewModsToPreset();
 
 
 public:
 public:
 	ModManager();
 	ModManager();