/* * cmodlist.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 "cmodlist.h" #include "../../lib/JsonNode.h" #include "../../lib/filesystem/CFileInputStream.h" bool CModEntry::compareVersions(QString lesser, QString greater) { static const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch QStringList lesserList = lesser.split("."); QStringList greaterList = greater.split("."); assert(lesserList.size() <= maxSections); assert(greaterList.size() <= maxSections); for(int i = 0; i < maxSections; i++) { if(greaterList.size() <= i) // 1.1.1 > 1.1 return false; if(lesserList.size() <= i) // 1.1 < 1.1.1 return true; if(lesserList[i].toInt() != greaterList[i].toInt()) return lesserList[i].toInt() < greaterList[i].toInt(); // 1.1 < 1.2 } return false; } QString CModEntry::sizeToString(double size) { static const QString sizes[] = { /*"%1 B", */ "%1 KiB", "%1 MiB", "%1 GiB", "%1 TiB" }; size_t index = 0; while(size > 1024 && index < 4) { size /= 1024; index++; } return 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) { } bool CModEntry::isEnabled() const { if(!isInstalled()) return false; return modSettings["active"].toBool(); } bool CModEntry::isDisabled() const { if(!isInstalled()) return false; return !isEnabled(); } bool CModEntry::isAvailable() const { if(isInstalled()) return false; return !repository.isEmpty(); } bool CModEntry::isUpdateable() const { if(!isInstalled()) return false; QString installedVer = localData["installedVersion"].toString(); QString availableVer = repository["latestVersion"].toString(); if(compareVersions(installedVer, availableVer)) return true; return false; } bool CModEntry::isEssential() const { return getValue("storedLocaly").toBool(); } bool CModEntry::isInstalled() const { return !localData.isEmpty(); } int CModEntry::getModStatus() const { int status = 0; if(isEnabled()) status |= ModStatus::ENABLED; if(isInstalled()) status |= ModStatus::INSTALLED; if(isUpdateable()) status |= ModStatus::UPDATEABLE; return status; } QString CModEntry::getName() const { return modname; } QVariant CModEntry::getValue(QString value) const { if(repository.contains(value) && localData.contains(value)) { // value is present in both repo and locally installed. Select one from latest version QString installedVer = localData["installedVersion"].toString(); QString availableVer = repository["latestVersion"].toString(); if(compareVersions(installedVer, availableVer)) return repository[value]; else return localData[value]; } if(repository.contains(value)) return repository[value]; if(localData.contains(value)) return localData[value]; return QVariant(); } QVariantMap CModList::copyField(QVariantMap data, QString from, QString to) { QVariantMap renamed; for(auto it = data.begin(); it != data.end(); it++) { QVariantMap modConf = it.value().toMap(); modConf.insert(to, modConf.value(from)); renamed.insert(it.key(), modConf); } return renamed; } void CModList::reloadRepositories() { } void CModList::resetRepositories() { repositories.clear(); } void CModList::addRepository(QVariantMap data) { repositories.push_back(copyField(data, "version", "latestVersion")); } void CModList::setLocalModList(QVariantMap data) { localModList = copyField(data, "version", "installedVersion"); } void CModList::setModSettings(QVariant data) { modSettings = data.toMap(); } void CModList::modChanged(QString modID) { } static QVariant getValue(QVariant input, QString path) { if(path.size() > 1) { QString entryName = path.section('/', 0, 1); QString remainder = "/" + path.section('/', 2, -1); entryName.remove(0, 1); return getValue(input.toMap().value(entryName), remainder); } else { return input; } } CModEntry CModList::getMod(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()) { settings["active"] = true; // default } else { if(!conf.toMap().isEmpty()) { settings = conf.toMap(); if(settings.value("active").isNull()) settings["active"] = true; // default } 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; } } } for(auto entry : repositories) { QVariant repoVal = getValue(entry, path); if(repoVal.isValid()) { if(repo.empty()) { repo = repoVal.toMap(); } else { if(CModEntry::compareVersions(repo["version"].toString(), repoVal.toMap()["version"].toString())) repo = repoVal.toMap(); } } } return CModEntry(repo, local, settings, modname); } bool CModList::hasMod(QString modname) const { if(localModList.contains(modname)) return true; for(auto entry : repositories) if(entry.contains(modname)) return true; return false; } QStringList CModList::getRequirements(QString modname) { QStringList ret; if(hasMod(modname)) { auto mod = getMod(modname); for(auto entry : mod.getValue("depends").toStringList()) ret += getRequirements(entry); } ret += modname; return ret; } QVector CModList::getModList() const { QSet knownMods; QVector modList; for(auto repo : repositories) { for(auto it = repo.begin(); it != repo.end(); it++) { knownMods.insert(it.key()); } } for(auto it = localModList.begin(); it != localModList.end(); it++) { knownMods.insert(it.key()); } for(auto entry : knownMods) { modList.push_back(entry); } return modList; } QVector CModList::getChildren(QString parent) const { QVector children; int depth = parent.count('.') + 1; for(const QString & mod : getModList()) { if(mod.count('.') == depth && mod.startsWith(parent)) children.push_back(mod); } return children; }