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:
parent
ba9e3dca9d
commit
4945370fe3
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user