mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Initial support for mod presets system
This commit is contained in:
parent
7fdddee503
commit
c57120f0dd
@ -13,6 +13,7 @@ set(launcher_SRCS
|
||||
modManager/cmodmanager.cpp
|
||||
modManager/imageviewer_moc.cpp
|
||||
modManager/chroniclesextractor.cpp
|
||||
modManager/modsettingsstorage.cpp
|
||||
settingsView/csettingsview_moc.cpp
|
||||
firstLaunch/firstlaunch_moc.cpp
|
||||
main.cpp
|
||||
@ -43,6 +44,7 @@ set(launcher_HEADERS
|
||||
modManager/cmodmanager.h
|
||||
modManager/imageviewer_moc.h
|
||||
modManager/chroniclesextractor.h
|
||||
modManager/modsettingsstorage.h
|
||||
settingsView/csettingsview_moc.h
|
||||
firstLaunch/firstlaunch_moc.h
|
||||
mainwindow_moc.h
|
||||
|
@ -33,8 +33,8 @@ QString CModEntry::sizeToString(double size)
|
||||
return QCoreApplication::translate("File size", sizes[index]).arg(QString::number(size, 'f', 1));
|
||||
}
|
||||
|
||||
CModEntry::CModEntry(QVariantMap repository, QVariantMap localData, QVariantMap modSettings, QString modname)
|
||||
: repository(repository), localData(localData), modSettings(modSettings), modname(modname)
|
||||
CModEntry::CModEntry(QVariantMap repository, QVariantMap localData, bool modActive, QString modname)
|
||||
: repository(repository), localData(localData), modActive(modActive), modname(modname)
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ bool CModEntry::isEnabled() const
|
||||
if (!isVisible())
|
||||
return false;
|
||||
|
||||
return modSettings["active"].toBool();
|
||||
return modActive;
|
||||
}
|
||||
|
||||
bool CModEntry::isDisabled() const
|
||||
@ -250,9 +250,9 @@ void CModList::setLocalModList(QVariantMap data)
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
void CModList::setModSettings(QVariant data)
|
||||
void CModList::setModSettings(std::shared_ptr<ModSettingsStorage> data)
|
||||
{
|
||||
modSettings = data.toMap();
|
||||
modSettings = data;
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
@ -294,46 +294,23 @@ CModEntry CModList::getModUncached(QString modname) const
|
||||
{
|
||||
QVariantMap repo;
|
||||
QVariantMap local = localModList[modname].toMap();
|
||||
QVariantMap settings;
|
||||
|
||||
QString path = modname;
|
||||
path = "/" + path.replace(".", "/mods/");
|
||||
QVariant conf = getValue(modSettings, path);
|
||||
|
||||
if(conf.isNull())
|
||||
bool modActive = modSettings->isModActive(modname);
|
||||
|
||||
if(modActive)
|
||||
{
|
||||
settings["active"] = !local.value("keepDisabled").toBool();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!conf.toMap().isEmpty())
|
||||
{
|
||||
settings = conf.toMap();
|
||||
if(settings.value("active").isNull())
|
||||
settings["active"] = !local.value("keepDisabled").toBool();
|
||||
}
|
||||
else
|
||||
settings.insert("active", conf);
|
||||
}
|
||||
|
||||
if(settings["active"].toBool())
|
||||
{
|
||||
QString rootPath = path.section('/', 0, 1);
|
||||
if(path != rootPath)
|
||||
{
|
||||
conf = getValue(modSettings, rootPath);
|
||||
const auto confMap = conf.toMap();
|
||||
if(!conf.isNull() && !confMap["active"].isNull() && !confMap["active"].toBool())
|
||||
{
|
||||
settings = confMap;
|
||||
}
|
||||
}
|
||||
QString rootModName = modname.section('.', 0, 1);
|
||||
if (!modSettings->isModActive(rootModName))
|
||||
modActive = false; // parent mod is inactive -> submod is also inactive
|
||||
}
|
||||
|
||||
if(settings.value("active").toBool())
|
||||
if(modActive)
|
||||
{
|
||||
if(!::isCompatible(local.value("compatibility").toMap()))
|
||||
settings["active"] = false;
|
||||
modActive = false; // mod not compatible with our version of vcmi -> inactive
|
||||
}
|
||||
|
||||
for(auto entry : repositories)
|
||||
@ -366,7 +343,7 @@ CModEntry CModList::getModUncached(QString modname) const
|
||||
}
|
||||
}
|
||||
|
||||
return CModEntry(repo, local, settings, modname);
|
||||
return CModEntry(repo, local, modActive, modname);
|
||||
}
|
||||
|
||||
bool CModList::hasMod(QString modname) const
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include "modsettingsstorage.h"
|
||||
|
||||
namespace ModStatus
|
||||
{
|
||||
enum EModStatus
|
||||
@ -30,13 +32,13 @@ class CModEntry
|
||||
// repository contains newest version only (if multiple are available)
|
||||
QVariantMap repository;
|
||||
QVariantMap localData;
|
||||
QVariantMap modSettings;
|
||||
bool modActive;
|
||||
|
||||
QString modname;
|
||||
|
||||
QVariant getValueImpl(QString value, bool localized) const;
|
||||
public:
|
||||
CModEntry(QVariantMap repository, QVariantMap localData, QVariantMap modSettings, QString modname);
|
||||
CModEntry(QVariantMap repository, QVariantMap localData, bool modActive, QString modname);
|
||||
|
||||
// installed and enabled
|
||||
bool isEnabled() const;
|
||||
@ -80,7 +82,7 @@ class CModList
|
||||
{
|
||||
QVector<QVariantMap> repositories;
|
||||
QVariantMap localModList;
|
||||
QVariantMap modSettings;
|
||||
std::shared_ptr<ModSettingsStorage> modSettings;
|
||||
|
||||
mutable QMap<QString, CModEntry> cachedMods;
|
||||
|
||||
@ -92,7 +94,7 @@ public:
|
||||
virtual void reloadRepositories();
|
||||
virtual void addRepository(QVariantMap data);
|
||||
virtual void setLocalModList(QVariantMap data);
|
||||
virtual void setModSettings(QVariant data);
|
||||
virtual void setModSettings(std::shared_ptr<ModSettingsStorage> data);
|
||||
virtual void modChanged(QString modID);
|
||||
|
||||
// returns mod by name. Note: mod MUST exist
|
||||
|
@ -192,6 +192,8 @@ void CModListModel::resetRepositories()
|
||||
|
||||
void CModListModel::modChanged(QString modID)
|
||||
{
|
||||
CModList::modChanged(modID);
|
||||
|
||||
int index = modNameToID.indexOf(modID);
|
||||
QModelIndex parent = this->parent(createIndex(0, 0, index));
|
||||
int row = modIndex[modIndexToName(parent)].indexOf(modID);
|
||||
|
@ -69,15 +69,10 @@ CModManager::CModManager(CModList * modList)
|
||||
loadModSettings();
|
||||
}
|
||||
|
||||
QString CModManager::settingsPath()
|
||||
{
|
||||
return pathToQString(VCMIDirs::get().userConfigPath() / "modSettings.json");
|
||||
}
|
||||
|
||||
void CModManager::loadModSettings()
|
||||
{
|
||||
modSettings = JsonUtils::JsonFromFile(settingsPath()).toMap();
|
||||
modList->setModSettings(modSettings["activeMods"]);
|
||||
modSettings = std::make_shared<ModSettingsStorage>();
|
||||
modList->setModSettings(modSettings);
|
||||
}
|
||||
|
||||
void CModManager::resetRepositories()
|
||||
@ -248,35 +243,11 @@ bool CModManager::canDisableMod(QString modname)
|
||||
return true;
|
||||
}
|
||||
|
||||
static QVariant writeValue(QString path, QVariantMap input, QVariant value)
|
||||
{
|
||||
if(path.size() > 1)
|
||||
{
|
||||
|
||||
QString entryName = path.section('/', 0, 1);
|
||||
QString remainder = "/" + path.section('/', 2, -1);
|
||||
|
||||
entryName.remove(0, 1);
|
||||
input.insert(entryName, writeValue(remainder, input.value(entryName).toMap(), value));
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
bool CModManager::doEnableMod(QString mod, bool on)
|
||||
{
|
||||
QString path = mod;
|
||||
path = "/activeMods/" + path.replace(".", "/mods/") + "/active";
|
||||
|
||||
modSettings = writeValue(path, modSettings, QVariant(on)).toMap();
|
||||
modList->setModSettings(modSettings["activeMods"]);
|
||||
modSettings->setModActive(mod, on);
|
||||
modList->modChanged(mod);
|
||||
|
||||
JsonUtils::JsonToFile(settingsPath(), modSettings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "cmodlist.h"
|
||||
#include "modsettingsstorage.h"
|
||||
|
||||
class CModManager : public QObject
|
||||
{
|
||||
@ -17,14 +18,12 @@ class CModManager : public QObject
|
||||
|
||||
CModList * modList;
|
||||
|
||||
QString settingsPath();
|
||||
|
||||
// check-free version of public method
|
||||
bool doEnableMod(QString mod, bool on);
|
||||
bool doInstallMod(QString mod, QString archivePath);
|
||||
bool doUninstallMod(QString mod);
|
||||
|
||||
QVariantMap modSettings;
|
||||
std::shared_ptr<ModSettingsStorage> modSettings;
|
||||
QVariantMap localMods;
|
||||
|
||||
QStringList recentErrors;
|
||||
|
123
launcher/modManager/modsettingsstorage.cpp
Normal file
123
launcher/modManager/modsettingsstorage.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* modsettignsstorage.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "modsettingsstorage.h"
|
||||
|
||||
#include "../../lib/VCMIDirs.h"
|
||||
#include "../vcmiqt/jsonutils.h"
|
||||
|
||||
static QVariant writeValue(QString path, QVariantMap input, QVariant value)
|
||||
{
|
||||
if(path.size() > 1)
|
||||
{
|
||||
QString entryName = path.section('/', 0, 1);
|
||||
QString remainder = "/" + path.section('/', 2, -1);
|
||||
entryName.remove(0, 1);
|
||||
input.insert(entryName, writeValue(remainder, input.value(entryName).toMap(), value));
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
ModSettingsStorage::ModSettingsStorage()
|
||||
{
|
||||
config = JsonUtils::JsonFromFile(settingsPath()).toMap();
|
||||
|
||||
// TODO: import from 1.5 format
|
||||
}
|
||||
|
||||
QString ModSettingsStorage::settingsPath() const
|
||||
{
|
||||
return pathToQString(VCMIDirs::get().userConfigPath() / "modSettings.json");
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setRootModActive(const QString & modName, bool on)
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
QStringList activeMods = getActiveMods();
|
||||
|
||||
assert(modName.count('.') == 0); // this method should never be used for submods
|
||||
|
||||
if (on)
|
||||
activeMods.push_back(modName);
|
||||
else
|
||||
activeMods.removeAll(modName);
|
||||
|
||||
config = writeValue("/presets/" + presetName + "/mods", config, activeMods).toMap();
|
||||
|
||||
JsonUtils::JsonToFile(settingsPath(), config);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setModSettingActive(const QString & modName, bool on)
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
QString rootModName = modName.section('.', 0, 0);
|
||||
QString settingName = modName.section('.', 1);
|
||||
QVariantMap modSettings = getModSettings(rootModName);
|
||||
|
||||
assert(modName.count('.') != 0); // this method should only be used for submods
|
||||
|
||||
modSettings.insert(settingName, QVariant(on));
|
||||
|
||||
config = writeValue("/presets/" + presetName + "/settings/" + rootModName, config, modSettings).toMap();
|
||||
|
||||
JsonUtils::JsonToFile(settingsPath(), config);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setModActive(const QString & modName, bool on)
|
||||
{
|
||||
if (modName.contains('.'))
|
||||
setModSettingActive(modName, on);
|
||||
else
|
||||
setRootModActive(modName, on);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setActivePreset(const QString & presetName)
|
||||
{
|
||||
config.insert("activePreset", QVariant(presetName));
|
||||
}
|
||||
|
||||
QString ModSettingsStorage::getActivePreset() const
|
||||
{
|
||||
return config["activePreset"].toString();
|
||||
}
|
||||
|
||||
bool ModSettingsStorage::isModActive(const QString & modName) const
|
||||
{
|
||||
if (modName.contains('.'))
|
||||
{
|
||||
QString rootModName = modName.section('.', 0, 0);
|
||||
QString settingName = modName.section('.', 1);
|
||||
|
||||
return getModSettings(rootModName)[settingName].toBool();
|
||||
}
|
||||
else
|
||||
return getActiveMods().contains(modName);
|
||||
}
|
||||
|
||||
QStringList ModSettingsStorage::getActiveMods() const
|
||||
{
|
||||
return getActivePresetData()["mods"].toStringList();
|
||||
}
|
||||
|
||||
QVariantMap ModSettingsStorage::getActivePresetData() const
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
return config["presets"].toMap()[presetName].toMap();
|
||||
}
|
||||
|
||||
QVariantMap ModSettingsStorage::getModSettings(const QString & modName) const
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
return getActivePresetData()["settings"].toMap()[modName].toMap();
|
||||
}
|
37
launcher/modManager/modsettingsstorage.h
Normal file
37
launcher/modManager/modsettingsstorage.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* modsettignsstorage.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
class ModSettingsStorage
|
||||
{
|
||||
QVariantMap config;
|
||||
|
||||
QString settingsPath() const;
|
||||
|
||||
void setRootModActive(const QString & modName, bool on);
|
||||
void setModSettingActive(const QString & modName, bool on);
|
||||
|
||||
QVariantMap getActivePresetData() const;
|
||||
QStringList getActiveMods() const;
|
||||
QVariantMap getModSettings(const QString & modName) const;
|
||||
|
||||
public:
|
||||
ModSettingsStorage();
|
||||
|
||||
void setModActive(const QString & modName, bool on);
|
||||
void setActivePreset(const QString & presetName);
|
||||
|
||||
QString getActivePreset() const;
|
||||
bool isModActive(const QString & modName) const;
|
||||
//QStringList getPresetsList() const;
|
||||
};
|
||||
|
@ -238,13 +238,13 @@ std::vector<std::string> CModHandler::getModList(const std::string & path) const
|
||||
|
||||
|
||||
|
||||
void CModHandler::loadMods(const std::string & path, const std::string & parent, const JsonNode & modSettings, bool enableMods)
|
||||
void CModHandler::loadMods(const std::string & path, const std::string & parent, const JsonNode & modSettings, const std::vector<TModID> & modsToActivate, bool enableMods)
|
||||
{
|
||||
for(const std::string & modName : getModList(path))
|
||||
loadOneMod(modName, parent, modSettings, enableMods);
|
||||
loadOneMod(modName, parent, modSettings, modsToActivate, enableMods);
|
||||
}
|
||||
|
||||
void CModHandler::loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, bool enableMods)
|
||||
void CModHandler::loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, const std::vector<TModID> & modsToActivate, bool enableMods)
|
||||
{
|
||||
boost::to_lower(modName);
|
||||
std::string modFullName = parent.empty() ? modName : parent + '.' + modName;
|
||||
@ -257,7 +257,8 @@ void CModHandler::loadOneMod(std::string modName, const std::string & parent, co
|
||||
|
||||
if(CResourceHandler::get("initial")->existsResource(CModInfo::getModFile(modFullName)))
|
||||
{
|
||||
CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName)));
|
||||
bool thisModActive = vstd::contains(modsToActivate, modFullName);
|
||||
CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName)), thisModActive);
|
||||
if (!parent.empty()) // this is submod, add parent to dependencies
|
||||
mod.dependencies.insert(parent);
|
||||
|
||||
@ -265,7 +266,7 @@ void CModHandler::loadOneMod(std::string modName, const std::string & parent, co
|
||||
if (mod.isEnabled() && enableMods)
|
||||
activeMods.push_back(modFullName);
|
||||
|
||||
loadMods(CModInfo::getModDir(modFullName) + '/', modFullName, modSettings[modName]["mods"], enableMods && mod.isEnabled());
|
||||
loadMods(CModInfo::getModDir(modFullName) + '/', modFullName, modSettings[modName]["mods"], modsToActivate, enableMods && mod.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,9 +275,27 @@ void CModHandler::loadMods()
|
||||
JsonNode modConfig;
|
||||
|
||||
modConfig = loadModSettings(JsonPath::builtin("config/modSettings.json"));
|
||||
loadMods("", "", modConfig["activeMods"], true);
|
||||
const JsonNode & modSettings = modConfig["activeMods"];
|
||||
const std::string & currentPresetName = modConfig["activePreset"].String();
|
||||
const JsonNode & currentPreset = modConfig["presets"][currentPresetName];
|
||||
const JsonNode & modsToActivateJson = currentPreset["mods"];
|
||||
std::vector<TModID> modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
|
||||
|
||||
coreMod = std::make_unique<CModInfo>(ModScope::scopeBuiltin(), modConfig[ModScope::scopeBuiltin()], JsonNode(JsonPath::builtin("config/gameConfig.json")));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
loadMods("", "", modSettings, modsToActivate, true);
|
||||
|
||||
coreMod = std::make_unique<CModInfo>(ModScope::scopeBuiltin(), modConfig[ModScope::scopeBuiltin()], JsonNode(JsonPath::builtin("config/gameConfig.json")), true);
|
||||
}
|
||||
|
||||
std::vector<std::string> CModHandler::getAllMods() const
|
||||
|
@ -42,11 +42,11 @@ class DLL_LINKAGE CModHandler final : boost::noncopyable
|
||||
* @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<TModID> validateAndSortDependencies(std::vector <TModID> modsToResolve) const;
|
||||
|
||||
std::vector<std::string> getModList(const std::string & path) const;
|
||||
void loadMods(const std::string & path, const std::string & parent, const JsonNode & modSettings, bool enableMods);
|
||||
void loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, bool enableMods);
|
||||
void loadMods(const std::string & path, const std::string & parent, const JsonNode & modSettings, const std::vector<TModID> & modsToActivate, bool enableMods);
|
||||
void loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, const std::vector<TModID> & modsToActivate, bool enableMods);
|
||||
void loadTranslation(const TModID & modName);
|
||||
|
||||
CModVersion getModVersion(TModID modName) const;
|
||||
|
@ -40,12 +40,12 @@ CModInfo::CModInfo():
|
||||
|
||||
}
|
||||
|
||||
CModInfo::CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config):
|
||||
CModInfo::CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config, bool isActive):
|
||||
identifier(identifier),
|
||||
dependencies(readModList(config["depends"])),
|
||||
softDependencies(readModList(config["softDepends"])),
|
||||
conflicts(readModList(config["conflicts"])),
|
||||
explicitlyEnabled(false),
|
||||
explicitlyEnabled(isActive),
|
||||
implicitlyEnabled(true),
|
||||
validation(PENDING),
|
||||
config(addMeta(config, identifier))
|
||||
@ -110,11 +110,9 @@ void CModInfo::loadLocalData(const JsonNode & data)
|
||||
{
|
||||
bool validated = false;
|
||||
implicitlyEnabled = true;
|
||||
explicitlyEnabled = !config["keepDisabled"].Bool();
|
||||
verificationInfo.checksum = 0;
|
||||
if (data.isStruct())
|
||||
{
|
||||
explicitlyEnabled = data["active"].Bool();
|
||||
validated = data["validated"].Bool();
|
||||
updateChecksum(strtol(data["checksum"].String().c_str(), nullptr, 16));
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
JsonNode config;
|
||||
|
||||
CModInfo();
|
||||
CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config);
|
||||
CModInfo(const std::string & identifier, const JsonNode & local, const JsonNode & config, bool isActive);
|
||||
|
||||
JsonNode saveLocalData() const;
|
||||
void updateChecksum(ui32 newChecksum);
|
||||
|
Loading…
Reference in New Issue
Block a user