1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-06 00:24:11 +02:00

Implemented validation of preset - removal of non-existing mods,

addition of newly installed mods
This commit is contained in:
Ivan Savenko 2024-11-11 11:19:14 +00:00
parent ba9e3dca9d
commit 4945370fe3
5 changed files with 138 additions and 27 deletions

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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,27 +154,64 @@ 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"]; return currentPreset;
std::vector<TModID> modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
modsToActivate.push_back(ModScope::scopeBuiltin());
for(const auto & settings : currentPreset["settings"].Struct())
{
if(!vstd::contains(modsToActivate, settings.first))
continue; // settings for inactive mod
for(const auto & submod : settings.second.Struct())
if(submod.second.Bool())
modsToActivate.push_back(settings.first + '.' + submod.first);
} }
TModList ModsPresetState::getActiveRootMods() const
{
const JsonNode & modsToActivateJson = getActivePresetConfig()["mods"];
std::vector<TModID> modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
modsToActivate.push_back(ModScope::scopeBuiltin());
return modsToActivate; 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;
}
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)
{
activeRootMods.push_back(activeMod);
for(const auto & submod : getModSettings(activeMod))
if(submod.second)
allActiveMods.push_back(activeMod + '.' + submod.first);
}
return allActiveMods;
}
ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad) ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad)
{ {
JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json")); JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json"));
@ -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>())
{ {
eraseMissingModsFromPreset();
addNewModsToPreset();
std::vector<TModID> desiredModList = modsPreset->getActiveMods(); 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);
});
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;

View File

@ -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 void setSettingActiveInPreset(const TModID & modName, const TModID & settingName, bool isActive);
bool isModActive(const TModID & modName) const; void eraseModInAllPresets(const TModID & modName);
void eraseModSettingInAllPresets(const TModID & modName, const TModID & settingName);
void activateModInPreset(const TModID & modName);
void dectivateModInAllPresets(const TModID & modName);
/// 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();